org.tinymediamanager.thirdparty.MediaInfoXMLParser Maven / Gradle / Ivy
The newest version!
package org.tinymediamanager.thirdparty;
import java.io.FileInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tinymediamanager.core.entities.MediaFile;
import org.tinymediamanager.scraper.util.StrgUtils;
import org.tinymediamanager.thirdparty.MediaInfo.StreamKind;
public class MediaInfoXMLParser {
private final List files = new ArrayList<>();
private static final Logger LOGGER = LoggerFactory.getLogger(MediaInfoXMLParser.class);
private static Pattern DURATION_HOUR_PATTERN = Pattern.compile("(\\d*?) h");
private static Pattern DURATION_MINUTE_PATTERN = Pattern.compile("(\\d*?) min");
private static Pattern DURATION_SECOND_PATTERN = Pattern.compile("(\\d*?) s");
public static MediaInfoXMLParser parseXML(Path path) throws Exception {
return new MediaInfoXMLParser(Jsoup.parse(new FileInputStream(path.toFile()), "UTF-8", "", Parser.xmlParser()));
}
private MediaInfoXMLParser(Document document) throws Exception {
// first check if there is a valid root object (old and new format)
Elements rootElements = document.select("MediaInfo");
if (rootElements.isEmpty()) {
throw new InvalidXmlException("Invalid/unparseable XML");
}
Element root = rootElements.get(0);
// get root element
Elements fileElements = root.select("media"); // new style
if (fileElements.isEmpty()) {
fileElements = root.select("file"); // old style
}
// process every file in the ISO
for (Element file : fileElements) {
MiFile miFile = new MiFile();
miFile.filename = "/tmp/dummy.bdmv";
if (StringUtils.isNotBlank(file.attr("ref")) && file.attr("ref").length() > 5) {
miFile.filename = file.attr("ref");
}
// and add all tracks
for (Element track : file.select("track")) {
MiTrack miTrack = new MiTrack();
miTrack.type = track.attr("type");
// all tags in that track
miTrack.elements.addAll(track.children());
miFile.tracks.add(miTrack);
}
// do the magic - create same wird map as MediaInfoLib will do, so we can parse with our impl...
miFile.createSnapshot();
// dummy MF to get the type (now the filename should be always set)
MediaFile mf = new MediaFile(Paths.get(miFile.filename));
if (mf.isVideo() || mf.getExtension().equalsIgnoreCase("mpls")) {
miFile.filename = mf.getFilename(); // so we have it w/o path
files.add(miFile);
}
}
}
/**
* find the biggest file (prob just right for MI as main movie file)
*/
public MiFile getMainFile() {
long biggest = 0L;
long longest = 0L;
MiFile mainFile = null;
// for (MiFile f : files) {
// if (f.getFilesize() > biggest) {
// mainFile = f;
// biggest = f.getFilesize();
// }
// }
// no filesize? try parsing by duration
if (mainFile == null) {
for (MiFile f : files) {
if (f.getFilename().toLowerCase(Locale.ROOT).endsWith("ifo")) {
// IFO files have the accumulated duration, but unusable as MI snapshot ;)
// continue;
}
if (f.getDuration() > longest) {
mainFile = f;
longest = f.getDuration();
}
}
}
// prevent NPE
if (mainFile == null) {
mainFile = new MiFile();
}
LOGGER.trace("Returning main video file: {}", mainFile.getFilename());
return mainFile;
}
public int getRuntimeFromDvdFiles() {
int rtifo = 0;
MiFile ifo = null;
if (files.size() <= 1) {
// this method is for DVDs with multiple files...
return 0;
}
// loop over all IFOs, and find the one with longest runtime == main video file?
for (MiFile mf : files) {
if (mf.getFilename().toLowerCase(Locale.ROOT).endsWith("ifo")) {
if (mf.getDuration() > rtifo) {
rtifo = mf.getDuration();
ifo = mf; // need the prefix
}
}
}
if (ifo != null) {
LOGGER.trace("Found longest IFO:{} duration:{}", ifo.getFilename(), rtifo);
// check DVD VOBs
String prefix = StrgUtils.substr(ifo.getFilename(), "(?i)^(VTS_\\d+).*");
if (prefix.isEmpty()) {
// check HD-DVD
prefix = StrgUtils.substr(ifo.getFilename(), "(?i)^(HV\\d+)I.*");
}
if (!prefix.isEmpty()) {
int rtvob = 0;
for (MiFile mf : files) {
if (mf.getFilename().startsWith(prefix) && !ifo.getFilename().equals(mf.getFilename())) {
rtvob += mf.getDuration();
LOGGER.trace("VOB:{} duration:{} accumulated:{}", mf.getFilename(), mf.getDuration(), rtvob);
}
}
if (rtvob > rtifo) {
rtifo = rtvob;
}
}
else {
// no IFO? must be bluray
LOGGER.trace("TODO: bluray");
}
}
return rtifo;
}
/**
* File record (1:N)
*/
public static class MiFile {
public final Map>> snapshot;
private final List tracks;
private int duration = 0;
private long filesize = 0;
private String filename = "";
private MiFile() {
tracks = new ArrayList<>();
snapshot = new EnumMap<>(StreamKind.class);
}
public String getFilename() {
return filename;
}
public long getFilesize() {
return filesize;
}
public int getDuration() {
return duration;
}
// kinda same snapshot map like from originating MediaInfo (TagNames differ!)
// Map>>
private void createSnapshot() {
StreamKind currentKind = null;
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy