+ support for smart-skip/override for keeping the higher-quality video via --conflict auto
This commit is contained in:
parent
66a6278611
commit
c45abb7291
|
@ -60,6 +60,7 @@ import net.sourceforge.filebot.subtitle.SubtitleFormat;
|
|||
import net.sourceforge.filebot.subtitle.SubtitleNaming;
|
||||
import net.sourceforge.filebot.vfs.FileInfo;
|
||||
import net.sourceforge.filebot.vfs.MemoryFile;
|
||||
import net.sourceforge.filebot.vfs.SimpleFileInfo;
|
||||
import net.sourceforge.filebot.web.AudioTrack;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
import net.sourceforge.filebot.web.EpisodeFormat;
|
||||
|
@ -574,7 +575,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
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()) {
|
||||
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));
|
||||
final FileMapper outputMapper = new FileMapper(outputFolder, false);
|
||||
|
||||
final List<File> outputMapping = new ArrayList<File>();
|
||||
for (FileInfo entry : archive.listFiles()) {
|
||||
outputMapping.add(outputMapper.getOutputFile(new File(entry.getPath())));
|
||||
final List<FileInfo> outputMapping = new ArrayList<FileInfo>();
|
||||
for (FileInfo it : archive.listFiles()) {
|
||||
File outputPath = outputMapper.getOutputFile(it.toFile());
|
||||
outputMapping.add(new SimpleFileInfo(outputPath.getPath(), it.getLength()));
|
||||
}
|
||||
|
||||
final Set<File> selection = new TreeSet<File>();
|
||||
for (File future : outputMapping) {
|
||||
if (filter == null || filter.accept(future)) {
|
||||
final Set<FileInfo> selection = new TreeSet<FileInfo>();
|
||||
for (FileInfo future : outputMapping) {
|
||||
if (filter == null || filter.accept(future.toFile())) {
|
||||
selection.add(future);
|
||||
}
|
||||
}
|
||||
|
@ -1103,18 +1105,27 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
}
|
||||
|
||||
boolean skip = true;
|
||||
for (File future : filter == null || forceExtractAll ? outputMapping : selection) {
|
||||
skip &= future.exists();
|
||||
for (FileInfo future : filter == null || forceExtractAll ? outputMapping : selection) {
|
||||
if (conflictAction == ConflictAction.AUTO) {
|
||||
skip &= (future.toFile().exists() && future.getLength() == future.toFile().length());
|
||||
} else {
|
||||
skip &= (future.toFile().exists());
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip || conflictAction == ConflictAction.OVERRIDE) {
|
||||
if (filter == null || forceExtractAll) {
|
||||
CLILogger.finest("Extracting files " + outputMapping);
|
||||
|
||||
// extract all files
|
||||
archive.extract(outputMapper);
|
||||
extractedFiles.addAll(outputMapping);
|
||||
|
||||
for (FileInfo it : outputMapping) {
|
||||
extractedFiles.add(it.toFile());
|
||||
}
|
||||
} else {
|
||||
CLILogger.finest("Extracting files " + selection);
|
||||
|
||||
// extract files selected by the given filter
|
||||
archive.extract(outputMapper, new FileFilter() {
|
||||
|
||||
|
@ -1123,7 +1134,10 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
return selection.contains(outputMapper.getOutputFile(entry));
|
||||
}
|
||||
});
|
||||
extractedFiles.addAll(selection);
|
||||
|
||||
for (FileInfo it : selection) {
|
||||
extractedFiles.add(it.toFile());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CLILogger.finest("Skipped extracting files " + selection);
|
||||
|
|
|
@ -707,7 +707,7 @@ public class MediaBindingBean {
|
|||
return JsonWriter.objectToJson(infoObject);
|
||||
}
|
||||
|
||||
private File getInferredMediaFile() {
|
||||
public File getInferredMediaFile() {
|
||||
// make sure media file is defined
|
||||
checkMediaFile();
|
||||
|
||||
|
@ -717,7 +717,7 @@ public class MediaBindingBean {
|
|||
if (videos.size() > 0) {
|
||||
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
|
||||
if (getContext() != null) {
|
||||
for (Entry<File, Object> it : getContext().entrySet()) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.net.URL;
|
|||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -40,6 +41,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
import net.sourceforge.filebot.WebServices;
|
||||
import net.sourceforge.filebot.archive.Archive;
|
||||
import net.sourceforge.filebot.format.MediaBindingBean;
|
||||
import net.sourceforge.filebot.similarity.CommonSequenceMatcher;
|
||||
import net.sourceforge.filebot.similarity.DateMatcher;
|
||||
import net.sourceforge.filebot.similarity.DateMetric;
|
||||
|
@ -97,7 +99,7 @@ public class MediaDetection {
|
|||
Archive iso = new Archive(file);
|
||||
try {
|
||||
for (FileInfo it : iso.listFiles()) {
|
||||
for (File entry : listPath(new File(it.getPath()))) {
|
||||
for (File entry : listPath(it.toFile())) {
|
||||
if (diskFolderEntryFilter.accept(entry)) {
|
||||
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) {
|
||||
// only for Episode / Movie objects
|
||||
if ((model instanceof Episode || model instanceof Movie) && file.exists()) {
|
||||
|
|
|
@ -217,7 +217,7 @@ class ExtractTool extends Tool<TableModel> {
|
|||
return data[row].entry.getName();
|
||||
case 1:
|
||||
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());
|
||||
return normalizePathSeparators(path.getPath());
|
||||
case 2:
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
package net.sourceforge.filebot.vfs;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface FileInfo {
|
||||
|
||||
public String getPath();
|
||||
|
||||
|
||||
public String getName();
|
||||
|
||||
|
||||
public String getType();
|
||||
|
||||
|
||||
public long getLength();
|
||||
|
||||
public File toFile();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,45 +1,42 @@
|
|||
|
||||
package net.sourceforge.filebot.vfs;
|
||||
|
||||
|
||||
import static net.sourceforge.tuned.FileUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
public class SimpleFileInfo implements FileInfo {
|
||||
public class SimpleFileInfo implements FileInfo, Comparable<FileInfo> {
|
||||
|
||||
private final String path;
|
||||
private final long length;
|
||||
|
||||
|
||||
public SimpleFileInfo(String path, long length) {
|
||||
this.path = path;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return getNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return getExtension(path);
|
||||
}
|
||||
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(new Object[] { getPath(), getLength() });
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
@ -51,16 +48,19 @@ public class SimpleFileInfo implements FileInfo {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(new Object[] { getPath(), getLength() });
|
||||
public int compareTo(FileInfo other) {
|
||||
return getPath().compareTo(other.getPath());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File toFile() {
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package net.sourceforge.filebot.web;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
|
@ -16,7 +15,6 @@ import java.util.zip.ZipException;
|
|||
import net.sourceforge.tuned.ByteBufferOutputStream;
|
||||
import net.sourceforge.tuned.FileUtilities;
|
||||
|
||||
|
||||
/**
|
||||
* Describes a subtitle on OpenSubtitles.
|
||||
*
|
||||
|
@ -25,49 +23,7 @@ import net.sourceforge.tuned.FileUtilities;
|
|||
public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Serializable {
|
||||
|
||||
public static enum Property {
|
||||
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;
|
||||
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;
|
||||
|
||||
public static <V> EnumMap<Property, V> asEnumMap(Map<String, V> stringMap) {
|
||||
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;
|
||||
|
||||
|
||||
public OpenSubtitlesSubtitleDescriptor(Map<Property, String> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
public String getProperty(Property key) {
|
||||
return properties.get(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return getProperty(Property.SubFileName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return FileUtilities.getNameWithoutExtension(getProperty(Property.SubFileName));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getLanguageName() {
|
||||
return getProperty(Property.LanguageName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return getProperty(Property.SubFormat);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return Long.parseLong(getProperty(Property.SubSize));
|
||||
}
|
||||
|
||||
|
||||
public String getMovieHash() {
|
||||
return getProperty(Property.MovieHash);
|
||||
}
|
||||
|
||||
|
||||
public long getMovieByteSize() {
|
||||
return Long.parseLong(getProperty(Property.MovieByteSize));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ByteBuffer fetch() throws Exception {
|
||||
URL resource = new URL(getProperty(Property.SubDownloadLink));
|
||||
|
@ -162,13 +108,11 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getProperty(Property.IDSubtitle).hashCode();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (object instanceof OpenSubtitlesSubtitleDescriptor) {
|
||||
|
@ -179,10 +123,14 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s [%s]", getName(), getLanguageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File toFile() {
|
||||
return new File(getPath());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue