+ support for smart-skip/override for keeping the higher-quality video via --conflict auto

This commit is contained in:
Reinhard Pointner 2014-01-22 11:31:55 +00:00
parent 66a6278611
commit c45abb7291
7 changed files with 132 additions and 120 deletions

View File

@ -60,6 +60,7 @@ import net.sourceforge.filebot.subtitle.SubtitleFormat;
import net.sourceforge.filebot.subtitle.SubtitleNaming; import net.sourceforge.filebot.subtitle.SubtitleNaming;
import net.sourceforge.filebot.vfs.FileInfo; import net.sourceforge.filebot.vfs.FileInfo;
import net.sourceforge.filebot.vfs.MemoryFile; import net.sourceforge.filebot.vfs.MemoryFile;
import net.sourceforge.filebot.vfs.SimpleFileInfo;
import net.sourceforge.filebot.web.AudioTrack; import net.sourceforge.filebot.web.AudioTrack;
import net.sourceforge.filebot.web.Episode; import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.EpisodeFormat; import net.sourceforge.filebot.web.EpisodeFormat;
@ -574,7 +575,7 @@ public class CmdlineOperations implements CmdlineInterface {
throw new Exception("File already exists: " + destination); throw new Exception("File already exists: " + destination);
} }
if (conflictAction == ConflictAction.OVERRIDE) { if (conflictAction == ConflictAction.OVERRIDE || (conflictAction == ConflictAction.AUTO && VIDEO_SIZE_ORDER.compare(source, destination) > 0)) {
if (!destination.delete()) { if (!destination.delete()) {
CLILogger.log(Level.SEVERE, "Failed to override file: " + destination); CLILogger.log(Level.SEVERE, "Failed to override file: " + destination);
} }
@ -1085,14 +1086,15 @@ public class CmdlineOperations implements CmdlineInterface {
CLILogger.info(String.format("Read archive [%s] and extract to [%s]", file.getName(), outputFolder)); CLILogger.info(String.format("Read archive [%s] and extract to [%s]", file.getName(), outputFolder));
final FileMapper outputMapper = new FileMapper(outputFolder, false); final FileMapper outputMapper = new FileMapper(outputFolder, false);
final List<File> outputMapping = new ArrayList<File>(); final List<FileInfo> outputMapping = new ArrayList<FileInfo>();
for (FileInfo entry : archive.listFiles()) { for (FileInfo it : archive.listFiles()) {
outputMapping.add(outputMapper.getOutputFile(new File(entry.getPath()))); File outputPath = outputMapper.getOutputFile(it.toFile());
outputMapping.add(new SimpleFileInfo(outputPath.getPath(), it.getLength()));
} }
final Set<File> selection = new TreeSet<File>(); final Set<FileInfo> selection = new TreeSet<FileInfo>();
for (File future : outputMapping) { for (FileInfo future : outputMapping) {
if (filter == null || filter.accept(future)) { if (filter == null || filter.accept(future.toFile())) {
selection.add(future); selection.add(future);
} }
} }
@ -1103,18 +1105,27 @@ public class CmdlineOperations implements CmdlineInterface {
} }
boolean skip = true; boolean skip = true;
for (File future : filter == null || forceExtractAll ? outputMapping : selection) { for (FileInfo future : filter == null || forceExtractAll ? outputMapping : selection) {
skip &= future.exists(); if (conflictAction == ConflictAction.AUTO) {
skip &= (future.toFile().exists() && future.getLength() == future.toFile().length());
} else {
skip &= (future.toFile().exists());
}
} }
if (!skip || conflictAction == ConflictAction.OVERRIDE) { if (!skip || conflictAction == ConflictAction.OVERRIDE) {
if (filter == null || forceExtractAll) { if (filter == null || forceExtractAll) {
CLILogger.finest("Extracting files " + outputMapping); CLILogger.finest("Extracting files " + outputMapping);
// extract all files // extract all files
archive.extract(outputMapper); archive.extract(outputMapper);
extractedFiles.addAll(outputMapping);
for (FileInfo it : outputMapping) {
extractedFiles.add(it.toFile());
}
} else { } else {
CLILogger.finest("Extracting files " + selection); CLILogger.finest("Extracting files " + selection);
// extract files selected by the given filter // extract files selected by the given filter
archive.extract(outputMapper, new FileFilter() { archive.extract(outputMapper, new FileFilter() {
@ -1123,7 +1134,10 @@ public class CmdlineOperations implements CmdlineInterface {
return selection.contains(outputMapper.getOutputFile(entry)); return selection.contains(outputMapper.getOutputFile(entry));
} }
}); });
extractedFiles.addAll(selection);
for (FileInfo it : selection) {
extractedFiles.add(it.toFile());
}
} }
} else { } else {
CLILogger.finest("Skipped extracting files " + selection); CLILogger.finest("Skipped extracting files " + selection);

View File

@ -707,7 +707,7 @@ public class MediaBindingBean {
return JsonWriter.objectToJson(infoObject); return JsonWriter.objectToJson(infoObject);
} }
private File getInferredMediaFile() { public File getInferredMediaFile() {
// make sure media file is defined // make sure media file is defined
checkMediaFile(); checkMediaFile();
@ -717,7 +717,7 @@ public class MediaBindingBean {
if (videos.size() > 0) { if (videos.size() > 0) {
return videos.iterator().next(); return videos.iterator().next();
} }
} else if ((infoObject instanceof Episode || infoObject instanceof Movie) && !VIDEO_FILES.accept(mediaFile)) { } else if (SUBTITLE_FILES.accept(mediaFile) || ((infoObject instanceof Episode || infoObject instanceof Movie) && !VIDEO_FILES.accept(mediaFile))) {
// prefer equal match from current context if possible // prefer equal match from current context if possible
if (getContext() != null) { if (getContext() != null) {
for (Entry<File, Object> it : getContext().entrySet()) { for (Entry<File, Object> it : getContext().entrySet()) {

View File

@ -17,6 +17,7 @@ import java.net.URL;
import java.text.CollationKey; import java.text.CollationKey;
import java.text.Collator; import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -40,6 +41,7 @@ import java.util.regex.Pattern;
import net.sourceforge.filebot.WebServices; import net.sourceforge.filebot.WebServices;
import net.sourceforge.filebot.archive.Archive; import net.sourceforge.filebot.archive.Archive;
import net.sourceforge.filebot.format.MediaBindingBean;
import net.sourceforge.filebot.similarity.CommonSequenceMatcher; import net.sourceforge.filebot.similarity.CommonSequenceMatcher;
import net.sourceforge.filebot.similarity.DateMatcher; import net.sourceforge.filebot.similarity.DateMatcher;
import net.sourceforge.filebot.similarity.DateMetric; import net.sourceforge.filebot.similarity.DateMetric;
@ -97,7 +99,7 @@ public class MediaDetection {
Archive iso = new Archive(file); Archive iso = new Archive(file);
try { try {
for (FileInfo it : iso.listFiles()) { for (FileInfo it : iso.listFiles()) {
for (File entry : listPath(new File(it.getPath()))) { for (File entry : listPath(it.toFile())) {
if (diskFolderEntryFilter.accept(entry)) { if (diskFolderEntryFilter.accept(entry)) {
return true; return true;
} }
@ -1251,6 +1253,55 @@ public class MediaDetection {
} }
} }
public static Comparator<File> VIDEO_SIZE_ORDER = new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
long[] v1 = getSizeValues(f1);
long[] v2 = getSizeValues(f2);
for (int i = 0; i < v1.length; i++) {
// best to worst
int d = new Long(v1[i]).compareTo(new Long(v2[i]));
if (d != 0) {
return d;
}
}
return 0;
}
public long[] getSizeValues(File f) {
long[] v = new long[] { 0, 0 };
try {
if (VIDEO_FILES.accept(f) || SUBTITLE_FILES.accept(f)) {
MediaBindingBean media = new MediaBindingBean(null, f, null);
// 1. Video Resolution
List<Integer> dim = media.getDimension();
v[0] = dim.get(0).longValue() * dim.get(1).longValue();
// 2. File Size
v[1] = media.getInferredMediaFile().length();
} else if (AUDIO_FILES.accept(f)) {
// 1. Audio BitRate
v[0] = 0;
// 2. File Size
v[1] = f.length();
}
} catch (Exception e) {
// negative values for invalid files
Logger.getLogger(MediaDetection.class.getClass().getName()).warning(String.format("Unable to read media info: %s [%s]", e.getMessage(), f.getName()));
Arrays.fill(v, -1);
return v;
}
return v;
}
};
public static void storeMetaInfo(File file, Object model, String original) { public static void storeMetaInfo(File file, Object model, String original) {
// only for Episode / Movie objects // only for Episode / Movie objects
if ((model instanceof Episode || model instanceof Movie) && file.exists()) { if ((model instanceof Episode || model instanceof Movie) && file.exists()) {

View File

@ -217,7 +217,7 @@ class ExtractTool extends Tool<TableModel> {
return data[row].entry.getName(); return data[row].entry.getName();
case 1: case 1:
File root = new File(data[row].archive.getName()); File root = new File(data[row].archive.getName());
File prefix = new File(data[row].entry.getPath()).getParentFile(); File prefix = data[row].entry.toFile().getParentFile();
File path = (prefix == null) ? root : new File(root, prefix.getPath()); File path = (prefix == null) ? root : new File(root, prefix.getPath());
return normalizePathSeparators(path.getPath()); return normalizePathSeparators(path.getPath());
case 2: case 2:

View File

@ -1,18 +1,17 @@
package net.sourceforge.filebot.vfs; package net.sourceforge.filebot.vfs;
import java.io.File;
public interface FileInfo { public interface FileInfo {
public String getPath(); public String getPath();
public String getName(); public String getName();
public String getType(); public String getType();
public long getLength(); public long getLength();
public File toFile();
} }

View File

@ -1,45 +1,42 @@
package net.sourceforge.filebot.vfs; package net.sourceforge.filebot.vfs;
import static net.sourceforge.tuned.FileUtilities.*; import static net.sourceforge.tuned.FileUtilities.*;
import java.io.File;
import java.util.Arrays; import java.util.Arrays;
public class SimpleFileInfo implements FileInfo, Comparable<FileInfo> {
public class SimpleFileInfo implements FileInfo {
private final String path; private final String path;
private final long length; private final long length;
public SimpleFileInfo(String path, long length) { public SimpleFileInfo(String path, long length) {
this.path = path; this.path = path;
this.length = length; this.length = length;
} }
@Override @Override
public String getPath() { public String getPath() {
return path; return path;
} }
public String getName() { public String getName() {
return getNameWithoutExtension(path); return getNameWithoutExtension(path);
} }
@Override @Override
public String getType() { public String getType() {
return getExtension(path); return getExtension(path);
} }
public long getLength() { public long getLength() {
return length; return length;
} }
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] { getPath(), getLength() });
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -51,16 +48,19 @@ public class SimpleFileInfo implements FileInfo {
return false; return false;
} }
@Override @Override
public int hashCode() { public int compareTo(FileInfo other) {
return Arrays.hashCode(new Object[] { getPath(), getLength() }); return getPath().compareTo(other.getPath());
} }
@Override @Override
public String toString() { public String toString() {
return getPath(); return getPath();
} }
@Override
public File toFile() {
return new File(path);
}
} }

View File

@ -1,7 +1,6 @@
package net.sourceforge.filebot.web; package net.sourceforge.filebot.web;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
@ -16,7 +15,6 @@ import java.util.zip.ZipException;
import net.sourceforge.tuned.ByteBufferOutputStream; import net.sourceforge.tuned.ByteBufferOutputStream;
import net.sourceforge.tuned.FileUtilities; import net.sourceforge.tuned.FileUtilities;
/** /**
* Describes a subtitle on OpenSubtitles. * Describes a subtitle on OpenSubtitles.
* *
@ -25,49 +23,7 @@ import net.sourceforge.tuned.FileUtilities;
public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Serializable { public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Serializable {
public static enum Property { public static enum Property {
IDSubtitle, IDSubtitle, IDSubtitleFile, IDSubMovieFile, IDMovie, IDMovieImdb, SubFileName, SubFormat, SubHash, SubSize, MovieHash, MovieByteSize, MovieName, MovieNameEng, MovieYear, MovieReleaseName, MovieTimeMS, MovieFPS, MovieImdbRating, MovieKind, SeriesSeason, SeriesEpisode, SeriesIMDBParent, SubLanguageID, ISO639, LanguageName, UserID, UserRank, UserNickName, SubAddDate, SubAuthorComment, SubFeatured, SubComments, SubDownloadsCnt, SubHearingImpaired, SubRating, SubHD, SubBad, SubActualCD, SubSumCD, MatchedBy, SubtitlesLink, SubDownloadLink, ZipDownloadLink;
IDSubtitleFile,
IDSubMovieFile,
IDMovie,
IDMovieImdb,
SubFileName,
SubFormat,
SubHash,
SubSize,
MovieHash,
MovieByteSize,
MovieName,
MovieNameEng,
MovieYear,
MovieReleaseName,
MovieTimeMS,
MovieFPS,
MovieImdbRating,
MovieKind,
SeriesSeason,
SeriesEpisode,
SeriesIMDBParent,
SubLanguageID,
ISO639,
LanguageName,
UserID,
UserRank,
UserNickName,
SubAddDate,
SubAuthorComment,
SubFeatured,
SubComments,
SubDownloadsCnt,
SubHearingImpaired,
SubRating,
SubHD,
SubBad,
SubActualCD,
SubSumCD,
MatchedBy,
SubtitlesLink,
SubDownloadLink,
ZipDownloadLink;
public static <V> EnumMap<Property, V> asEnumMap(Map<String, V> stringMap) { public static <V> EnumMap<Property, V> asEnumMap(Map<String, V> stringMap) {
EnumMap<Property, V> enumMap = new EnumMap<Property, V>(Property.class); EnumMap<Property, V> enumMap = new EnumMap<Property, V>(Property.class);
@ -87,57 +43,47 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
private final Map<Property, String> properties; private final Map<Property, String> properties;
public OpenSubtitlesSubtitleDescriptor(Map<Property, String> properties) { public OpenSubtitlesSubtitleDescriptor(Map<Property, String> properties) {
this.properties = properties; this.properties = properties;
} }
public String getProperty(Property key) { public String getProperty(Property key) {
return properties.get(key); return properties.get(key);
} }
@Override @Override
public String getPath() { public String getPath() {
return getProperty(Property.SubFileName); return getProperty(Property.SubFileName);
} }
@Override @Override
public String getName() { public String getName() {
return FileUtilities.getNameWithoutExtension(getProperty(Property.SubFileName)); return FileUtilities.getNameWithoutExtension(getProperty(Property.SubFileName));
} }
@Override @Override
public String getLanguageName() { public String getLanguageName() {
return getProperty(Property.LanguageName); return getProperty(Property.LanguageName);
} }
@Override @Override
public String getType() { public String getType() {
return getProperty(Property.SubFormat); return getProperty(Property.SubFormat);
} }
@Override @Override
public long getLength() { public long getLength() {
return Long.parseLong(getProperty(Property.SubSize)); return Long.parseLong(getProperty(Property.SubSize));
} }
public String getMovieHash() { public String getMovieHash() {
return getProperty(Property.MovieHash); return getProperty(Property.MovieHash);
} }
public long getMovieByteSize() { public long getMovieByteSize() {
return Long.parseLong(getProperty(Property.MovieByteSize)); return Long.parseLong(getProperty(Property.MovieByteSize));
} }
@Override @Override
public ByteBuffer fetch() throws Exception { public ByteBuffer fetch() throws Exception {
URL resource = new URL(getProperty(Property.SubDownloadLink)); URL resource = new URL(getProperty(Property.SubDownloadLink));
@ -162,13 +108,11 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
} }
} }
@Override @Override
public int hashCode() { public int hashCode() {
return getProperty(Property.IDSubtitle).hashCode(); return getProperty(Property.IDSubtitle).hashCode();
} }
@Override @Override
public boolean equals(Object object) { public boolean equals(Object object) {
if (object instanceof OpenSubtitlesSubtitleDescriptor) { if (object instanceof OpenSubtitlesSubtitleDescriptor) {
@ -179,10 +123,14 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
return false; return false;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("%s [%s]", getName(), getLanguageName()); return String.format("%s [%s]", getName(), getLanguageName());
} }
@Override
public File toFile() {
return new File(getPath());
}
} }