+ 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.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);

View File

@ -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()) {

View File

@ -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()) {

View File

@ -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:

View File

@ -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();
}

View File

@ -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, Comparable<FileInfo> {
public class SimpleFileInfo implements 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) {
@ -47,20 +44,23 @@ public class SimpleFileInfo implements FileInfo {
FileInfo other = (FileInfo) obj;
return other.getLength() == getLength() && other.getPath().equals(getPath());
}
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);
}
}

View File

@ -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,62 +15,19 @@ import java.util.zip.ZipException;
import net.sourceforge.tuned.ByteBufferOutputStream;
import net.sourceforge.tuned.FileUtilities;
/**
* Describes a subtitle on OpenSubtitles.
*
* @see OpenSubtitlesXmlRpc
*/
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);
// copy entry set to enum map
for (Entry<String, V> entry : stringMap.entrySet()) {
try {
@ -80,109 +36,101 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor, Seri
// illegal enum constant, just ignore
}
}
return enumMap;
}
}
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));
InputStream stream = resource.openStream();
try {
ByteBufferOutputStream buffer = new ByteBufferOutputStream(getLength());
// extract gzipped subtitle on-the-fly
try {
stream = new GZIPInputStream(stream);
} catch (ZipException e) {
throw new IOException(String.format("%s: anti-leech limit may have been reached", e.getMessage()));
}
// fully download
buffer.transferFully(stream);
return buffer.getByteBuffer();
} finally {
stream.close();
}
}
@Override
public int hashCode() {
return getProperty(Property.IDSubtitle).hashCode();
}
@Override
public boolean equals(Object object) {
if (object instanceof OpenSubtitlesSubtitleDescriptor) {
OpenSubtitlesSubtitleDescriptor other = (OpenSubtitlesSubtitleDescriptor) object;
return getProperty(Property.IDSubtitle).equals(other.getProperty(Property.IDSubtitle));
}
return false;
}
@Override
public String toString() {
return String.format("%s [%s]", getName(), getLanguageName());
}
@Override
public File toFile() {
return new File(getPath());
}
}