mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-24 00:38:52 -05:00
Refactor CmdlineInterface with proper types for all parameters
This commit is contained in:
parent
b42149e927
commit
7a0a36b528
@ -15,6 +15,7 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import net.filebot.media.XattrMetaInfoProvider;
|
import net.filebot.media.XattrMetaInfoProvider;
|
||||||
import net.filebot.similarity.MetricAvg;
|
import net.filebot.similarity.MetricAvg;
|
||||||
@ -40,7 +41,6 @@ import net.filebot.web.TVMazeClient;
|
|||||||
import net.filebot.web.TheTVDBClient;
|
import net.filebot.web.TheTVDBClient;
|
||||||
import net.filebot.web.TheTVDBClientV1;
|
import net.filebot.web.TheTVDBClientV1;
|
||||||
import net.filebot.web.VideoHashSubtitleService;
|
import net.filebot.web.VideoHashSubtitleService;
|
||||||
import one.util.streamex.StreamEx;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reuse the same web service client so login, cache, etc. can be shared.
|
* Reuse the same web service client so login, cache, etc. can be shared.
|
||||||
@ -72,29 +72,39 @@ public final class WebServices {
|
|||||||
public static final XattrMetaInfoProvider XattrMetaData = new XattrMetaInfoProvider();
|
public static final XattrMetaInfoProvider XattrMetaData = new XattrMetaInfoProvider();
|
||||||
public static final ID3Lookup MediaInfoID3 = new ID3Lookup();
|
public static final ID3Lookup MediaInfoID3 = new ID3Lookup();
|
||||||
|
|
||||||
public static EpisodeListProvider[] getEpisodeListProviders() {
|
public static Datasource[] getServices() {
|
||||||
return new EpisodeListProvider[] { TheTVDB, AniDB, TheMovieDB_TV, TVmaze };
|
return new Datasource[] { TheMovieDB, OMDb, TheTVDB, AniDB, TheMovieDB_TV, TVmaze, AcoustID, MediaInfoID3, XattrMetaData, OpenSubtitles, Shooter, TheTVDBv2, FanartTV };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MovieIdentificationService[] getMovieIdentificationServices() {
|
public static MovieIdentificationService[] getMovieIdentificationServices() {
|
||||||
return new MovieIdentificationService[] { TheMovieDB, OMDb };
|
return new MovieIdentificationService[] { TheMovieDB, OMDb };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SubtitleProvider[] getSubtitleProviders() {
|
public static EpisodeListProvider[] getEpisodeListProviders() {
|
||||||
return new SubtitleProvider[] { OpenSubtitles };
|
return new EpisodeListProvider[] { TheTVDB, AniDB, TheMovieDB_TV, TVmaze };
|
||||||
}
|
|
||||||
|
|
||||||
public static VideoHashSubtitleService[] getVideoHashSubtitleServices(Locale locale) {
|
|
||||||
if (locale.equals(Locale.CHINESE))
|
|
||||||
return new VideoHashSubtitleService[] { OpenSubtitles, Shooter };
|
|
||||||
else
|
|
||||||
return new VideoHashSubtitleService[] { OpenSubtitles };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MusicIdentificationService[] getMusicIdentificationServices() {
|
public static MusicIdentificationService[] getMusicIdentificationServices() {
|
||||||
return new MusicIdentificationService[] { AcoustID, MediaInfoID3 };
|
return new MusicIdentificationService[] { AcoustID, MediaInfoID3 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SubtitleProvider[] getSubtitleProviders(Locale locale) {
|
||||||
|
return new SubtitleProvider[] { OpenSubtitles };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VideoHashSubtitleService[] getVideoHashSubtitleServices(Locale locale) {
|
||||||
|
// special support for 射手网 for Chinese language subtitles
|
||||||
|
if (locale.equals(Locale.CHINESE)) {
|
||||||
|
return new VideoHashSubtitleService[] { OpenSubtitles, Shooter };
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VideoHashSubtitleService[] { OpenSubtitles };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Datasource getService(String name) {
|
||||||
|
return getService(name, getServices());
|
||||||
|
}
|
||||||
|
|
||||||
public static EpisodeListProvider getEpisodeListProvider(String name) {
|
public static EpisodeListProvider getEpisodeListProvider(String name) {
|
||||||
return getService(name, getEpisodeListProviders());
|
return getService(name, getEpisodeListProviders());
|
||||||
}
|
}
|
||||||
@ -107,8 +117,10 @@ public final class WebServices {
|
|||||||
return getService(name, getMusicIdentificationServices());
|
return getService(name, getMusicIdentificationServices());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Datasource> T getService(String name, T[] services) {
|
public static <T extends Datasource> T getService(String name, T... services) {
|
||||||
return StreamEx.of(services).findFirst(it -> it.getIdentifier().equalsIgnoreCase(name) || it.getName().equalsIgnoreCase(name)).orElse(null);
|
return stream(services).filter(it -> {
|
||||||
|
return it.getIdentifier().equalsIgnoreCase(name) || it.getName().equalsIgnoreCase(name);
|
||||||
|
}).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool();
|
public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool();
|
||||||
@ -127,7 +139,8 @@ public final class WebServices {
|
|||||||
private SearchResult merge(SearchResult prime, List<SearchResult> group) {
|
private SearchResult merge(SearchResult prime, List<SearchResult> group) {
|
||||||
int id = prime.getId();
|
int id = prime.getId();
|
||||||
String name = prime.getName();
|
String name = prime.getName();
|
||||||
String[] aliasNames = StreamEx.of(group).flatMap(it -> stream(it.getAliasNames())).remove(name::equals).distinct().toArray(String[]::new);
|
|
||||||
|
String[] aliasNames = group.stream().flatMap(it -> stream(it.getAliasNames())).filter(n -> !n.equals(name)).distinct().toArray(String[]::new);
|
||||||
return new SearchResult(id, name, aliasNames);
|
return new SearchResult(id, name, aliasNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +151,7 @@ public final class WebServices {
|
|||||||
Future<List<SearchResult>> localSearch = requestThreadPool.submit(() -> localIndex.get().search(query));
|
Future<List<SearchResult>> localSearch = requestThreadPool.submit(() -> localIndex.get().search(query));
|
||||||
|
|
||||||
// combine alias names into a single search results, and keep API search name as primary name
|
// combine alias names into a single search results, and keep API search name as primary name
|
||||||
Map<Integer, SearchResult> results = StreamEx.of(apiSearch.get()).append(localSearch.get()).groupingBy(SearchResult::getId, collectingAndThen(toList(), group -> merge(group.get(0), group)));
|
Map<Integer, SearchResult> results = Stream.concat(apiSearch.get().stream(), localSearch.get().stream()).collect(groupingBy(SearchResult::getId, collectingAndThen(toList(), group -> merge(group.get(0), group))));
|
||||||
|
|
||||||
return sortBySimilarity(results.values(), singleton(query), getSeriesMatchMetric());
|
return sortBySimilarity(results.values(), singleton(query), getSeriesMatchMetric());
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,20 @@ package net.filebot.cli;
|
|||||||
|
|
||||||
import static java.util.Collections.*;
|
import static java.util.Collections.*;
|
||||||
import static net.filebot.Logging.*;
|
import static net.filebot.Logging.*;
|
||||||
|
import static net.filebot.hash.VerificationUtilities.*;
|
||||||
|
import static net.filebot.subtitle.SubtitleUtilities.*;
|
||||||
import static net.filebot.util.FileUtilities.*;
|
import static net.filebot.util.FileUtilities.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
@ -22,6 +27,14 @@ import org.kohsuke.args4j.spi.ExplicitBooleanOptionHandler;
|
|||||||
|
|
||||||
import net.filebot.Language;
|
import net.filebot.Language;
|
||||||
import net.filebot.StandardRenameAction;
|
import net.filebot.StandardRenameAction;
|
||||||
|
import net.filebot.WebServices;
|
||||||
|
import net.filebot.format.ExpressionFileFilter;
|
||||||
|
import net.filebot.format.ExpressionFilter;
|
||||||
|
import net.filebot.format.ExpressionFormat;
|
||||||
|
import net.filebot.hash.HashType;
|
||||||
|
import net.filebot.subtitle.SubtitleFormat;
|
||||||
|
import net.filebot.subtitle.SubtitleNaming;
|
||||||
|
import net.filebot.web.Datasource;
|
||||||
import net.filebot.web.SortOrder;
|
import net.filebot.web.SortOrder;
|
||||||
|
|
||||||
public class ArgumentBean {
|
public class ArgumentBean {
|
||||||
@ -194,12 +207,61 @@ public class ArgumentBean {
|
|||||||
return SortOrder.forName(order);
|
return SortOrder.forName(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Locale getLocale() {
|
public ExpressionFormat getExpressionFormat() throws Exception {
|
||||||
return new Locale(lang);
|
return format == null ? null : new ExpressionFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionFilter getExpressionFilter() throws Exception {
|
||||||
|
return filter == null ? null : new ExpressionFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileFilter getExpressionFileFilter() throws Exception {
|
||||||
|
return filter == null ? null : new ExpressionFileFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Datasource getDatasource() {
|
||||||
|
return db == null ? null : WebServices.getService(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSearchQuery() {
|
||||||
|
return query == null || query.isEmpty() ? null : query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getOutputPath() {
|
||||||
|
return output == null ? null : new File(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getAbsoluteOutputFolder() throws Exception {
|
||||||
|
return output == null ? null : new File(output).getCanonicalFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubtitleFormat getSubtitleOutputFormat() {
|
||||||
|
return output == null ? null : getSubtitleFormatByName(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubtitleNaming getSubtitleNamingFormat() {
|
||||||
|
return optional(format).map(SubtitleNaming::forName).orElse(SubtitleNaming.MATCH_VIDEO_ADD_LANGUAGE_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashType getOutputHashType() {
|
||||||
|
// support --output checksum.sfv
|
||||||
|
return optional(output).map(File::new).map(f -> getHashType(f)).orElseGet(() -> {
|
||||||
|
// support --format SFV
|
||||||
|
return optional(format).map(k -> getHashTypeByExtension(k)).orElse(HashType.SFV);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charset getEncoding() {
|
||||||
|
return encoding == null ? null : Charset.forName(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Language getLanguage() {
|
public Language getLanguage() {
|
||||||
return Language.findLanguage(lang);
|
// find language code for any input (en, eng, English, etc)
|
||||||
|
return optional(lang).map(Language::findLanguage).orElseThrow(error("Illegal language code", lang));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStrict() {
|
||||||
|
return !nonStrict;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Level getLogLevel() {
|
public Level getLogLevel() {
|
||||||
@ -226,4 +288,12 @@ public class ArgumentBean {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> Optional<T> optional(T value) {
|
||||||
|
return Optional.ofNullable(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Supplier<CmdlineException> error(String message, Object value) {
|
||||||
|
return () -> new CmdlineException(message + ": " + value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,15 @@ import static net.filebot.util.ExceptionUtilities.*;
|
|||||||
import static net.filebot.util.FileUtilities.*;
|
import static net.filebot.util.FileUtilities.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
import javax.script.SimpleBindings;
|
import javax.script.SimpleBindings;
|
||||||
|
|
||||||
import net.filebot.MediaTypes;
|
import net.filebot.MediaTypes;
|
||||||
import net.filebot.StandardRenameAction;
|
|
||||||
|
|
||||||
public class ArgumentProcessor {
|
public class ArgumentProcessor {
|
||||||
|
|
||||||
@ -57,47 +56,47 @@ public class ArgumentProcessor {
|
|||||||
|
|
||||||
// print episode info
|
// print episode info
|
||||||
if (args.list) {
|
if (args.list) {
|
||||||
List<String> lines = cli.fetchEpisodeList(args.query, args.format, args.db, args.order, args.filter, args.lang);
|
List<String> lines = cli.fetchEpisodeList(args.getDatasource(), args.getSearchQuery(), args.getExpressionFormat(), args.getExpressionFilter(), args.getSortOrder(), args.getLanguage().getLocale());
|
||||||
lines.forEach(System.out::println);
|
lines.forEach(System.out::println);
|
||||||
return lines.isEmpty() ? 1 : 0;
|
return lines.isEmpty() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print media info
|
// print media info
|
||||||
if (args.mediaInfo) {
|
if (args.mediaInfo) {
|
||||||
List<String> lines = cli.getMediaInfo(args.getFiles(true), args.format, args.filter);
|
List<String> lines = cli.getMediaInfo(args.getFiles(true), args.getExpressionFileFilter(), args.getExpressionFormat());
|
||||||
lines.forEach(System.out::println);
|
lines.forEach(System.out::println);
|
||||||
return lines.isEmpty() ? 1 : 0;
|
return lines.isEmpty() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert files
|
// revert files
|
||||||
if (args.revert) {
|
if (args.revert) {
|
||||||
List<File> files = cli.revert(args.getFiles(false), args.filter, "TEST".equalsIgnoreCase(args.action));
|
List<File> files = cli.revert(args.getFiles(false), args.getExpressionFileFilter(), args.getRenameAction());
|
||||||
return files.isEmpty() ? 1 : 0;
|
return files.isEmpty() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// file operations
|
// file operations
|
||||||
Collection<File> files = new LinkedHashSet<File>(args.getFiles(true));
|
Set<File> files = new LinkedHashSet<File>(args.getFiles(true));
|
||||||
|
|
||||||
if (args.extract) {
|
if (args.extract) {
|
||||||
files.addAll(cli.extract(files, args.output, args.conflict, null, true));
|
files.addAll(cli.extract(files, args.getOutputPath(), args.getConflictAction(), null, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.getSubtitles) {
|
if (args.getSubtitles) {
|
||||||
files.addAll(cli.getMissingSubtitles(files, args.db, args.query, args.lang, args.output, args.encoding, args.format, !args.nonStrict));
|
files.addAll(cli.getMissingSubtitles(files, args.getSearchQuery(), args.getLanguage(), args.getSubtitleOutputFormat(), args.getEncoding(), args.getSubtitleNamingFormat(), args.isStrict()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.rename) {
|
if (args.rename) {
|
||||||
cli.rename(files, StandardRenameAction.forName(args.action), args.conflict, args.output, args.format, args.db, args.query, args.order, args.filter, args.lang, !args.nonStrict);
|
cli.rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.check) {
|
if (args.check) {
|
||||||
// check verification file
|
// check verification file
|
||||||
if (containsOnly(files, MediaTypes.getDefaultFilter("verification"))) {
|
if (containsOnly(files, MediaTypes.getDefaultFilter("verification"))) {
|
||||||
if (!cli.check(files)) {
|
if (!cli.check(files)) {
|
||||||
throw new Exception("Data corruption detected"); // one or more hashes mismatch
|
throw new Exception("Data corruption detected"); // one or more hashes do not match
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cli.compute(files, args.output, args.encoding);
|
cli.compute(files, args.getOutputPath(), args.getOutputHashType(), args.getEncoding());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,32 +2,42 @@ package net.filebot.cli;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.filebot.Language;
|
||||||
import net.filebot.RenameAction;
|
import net.filebot.RenameAction;
|
||||||
|
import net.filebot.format.ExpressionFilter;
|
||||||
|
import net.filebot.format.ExpressionFormat;
|
||||||
|
import net.filebot.hash.HashType;
|
||||||
|
import net.filebot.subtitle.SubtitleFormat;
|
||||||
|
import net.filebot.subtitle.SubtitleNaming;
|
||||||
|
import net.filebot.web.Datasource;
|
||||||
|
import net.filebot.web.SortOrder;
|
||||||
|
|
||||||
public interface CmdlineInterface {
|
public interface CmdlineInterface {
|
||||||
|
|
||||||
List<File> rename(Collection<File> files, RenameAction action, String conflict, String output, String format, String db, String query, String sortOrder, String filter, String lang, boolean strict) throws Exception;
|
List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception;
|
||||||
|
|
||||||
List<File> rename(Map<File, File> renameMap, RenameAction renameAction, String conflict) throws Exception;
|
List<File> rename(Map<File, File> rename, RenameAction action, ConflictAction conflict) throws Exception;
|
||||||
|
|
||||||
List<File> revert(Collection<File> files, String filter, boolean test) throws Exception;
|
List<File> revert(Collection<File> files, FileFilter filter, RenameAction action) throws Exception;
|
||||||
|
|
||||||
List<File> getSubtitles(Collection<File> files, String db, String query, String lang, String output, String encoding, String format, boolean strict) throws Exception;
|
List<File> getSubtitles(Collection<File> files, String query, Language language, SubtitleFormat output, Charset encoding, SubtitleNaming format, boolean strict) throws Exception;
|
||||||
|
|
||||||
List<File> getMissingSubtitles(Collection<File> files, String db, String query, String lang, String output, String encoding, String format, boolean strict) throws Exception;
|
List<File> getMissingSubtitles(Collection<File> files, String query, Language language, SubtitleFormat output, Charset encoding, SubtitleNaming format, boolean strict) throws Exception;
|
||||||
|
|
||||||
boolean check(Collection<File> files) throws Exception;
|
boolean check(Collection<File> files) throws Exception;
|
||||||
|
|
||||||
File compute(Collection<File> files, String output, String encoding) throws Exception;
|
File compute(Collection<File> files, File output, HashType hash, Charset encoding) throws Exception;
|
||||||
|
|
||||||
List<String> fetchEpisodeList(String query, String format, String db, String sortOrder, String filter, String lang) throws Exception;
|
List<String> fetchEpisodeList(Datasource db, String query, ExpressionFormat format, ExpressionFilter filter, SortOrder order, Locale locale) throws Exception;
|
||||||
|
|
||||||
List<String> getMediaInfo(Collection<File> files, String format, String filter) throws Exception;
|
List<String> getMediaInfo(Collection<File> files, FileFilter filter, ExpressionFormat format) throws Exception;
|
||||||
|
|
||||||
List<File> extract(Collection<File> files, String output, String conflict, FileFilter filter, boolean forceExtractAll) throws Exception;
|
List<File> extract(Collection<File> files, File output, ConflictAction conflict, FileFilter filter, boolean forceExtractAll) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import static net.filebot.util.RegularExpressions.*;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@ -37,7 +36,6 @@ import java.util.Set;
|
|||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -49,7 +47,6 @@ import net.filebot.RenameAction;
|
|||||||
import net.filebot.StandardRenameAction;
|
import net.filebot.StandardRenameAction;
|
||||||
import net.filebot.archive.Archive;
|
import net.filebot.archive.Archive;
|
||||||
import net.filebot.archive.FileMapper;
|
import net.filebot.archive.FileMapper;
|
||||||
import net.filebot.format.ExpressionFileFilter;
|
|
||||||
import net.filebot.format.ExpressionFilter;
|
import net.filebot.format.ExpressionFilter;
|
||||||
import net.filebot.format.ExpressionFormat;
|
import net.filebot.format.ExpressionFormat;
|
||||||
import net.filebot.format.MediaBindingBean;
|
import net.filebot.format.MediaBindingBean;
|
||||||
@ -59,7 +56,6 @@ import net.filebot.hash.VerificationFileWriter;
|
|||||||
import net.filebot.media.AutoDetection;
|
import net.filebot.media.AutoDetection;
|
||||||
import net.filebot.media.AutoDetection.Group;
|
import net.filebot.media.AutoDetection.Group;
|
||||||
import net.filebot.media.AutoDetection.Type;
|
import net.filebot.media.AutoDetection.Type;
|
||||||
import net.filebot.media.MediaDetection;
|
|
||||||
import net.filebot.media.VideoQuality;
|
import net.filebot.media.VideoQuality;
|
||||||
import net.filebot.media.XattrMetaInfoProvider;
|
import net.filebot.media.XattrMetaInfoProvider;
|
||||||
import net.filebot.similarity.CommonSequenceMatcher;
|
import net.filebot.similarity.CommonSequenceMatcher;
|
||||||
@ -93,30 +89,25 @@ import net.filebot.web.VideoHashSubtitleService;
|
|||||||
public class CmdlineOperations implements CmdlineInterface {
|
public class CmdlineOperations implements CmdlineInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> rename(Collection<File> files, RenameAction action, String conflict, String output, String formatExpression, String db, String query, String sortOrder, String filterExpression, String lang, boolean strict) throws Exception {
|
public List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception {
|
||||||
ExpressionFormat format = (formatExpression != null) ? new ExpressionFormat(formatExpression) : null;
|
// movie mode
|
||||||
ExpressionFilter filter = (filterExpression != null) ? new ExpressionFilter(filterExpression) : null;
|
if (db instanceof MovieIdentificationService) {
|
||||||
File outputDir = (output != null && output.length() > 0) ? new File(output).getAbsoluteFile() : null;
|
return renameMovie(files, action, conflict, output, format, (MovieIdentificationService) db, query, filter, locale, strict);
|
||||||
Locale locale = getLanguage(lang).getLocale();
|
|
||||||
ConflictAction conflictAction = ConflictAction.forName(conflict);
|
|
||||||
|
|
||||||
if (getMovieIdentificationService(db) != null) {
|
|
||||||
// movie mode
|
|
||||||
return renameMovie(files, action, conflictAction, outputDir, format, getMovieIdentificationService(db), query, filter, locale, strict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getEpisodeListProvider(db) != null) {
|
// series mode
|
||||||
// tv series mode
|
if (db instanceof EpisodeListProvider) {
|
||||||
return renameSeries(files, action, conflictAction, outputDir, format, getEpisodeListProvider(db), query, SortOrder.forName(sortOrder), filter, locale, strict);
|
return renameSeries(files, action, conflict, output, format, (EpisodeListProvider) db, query, order, filter, locale, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getMusicIdentificationService(db) != null) {
|
// music mode
|
||||||
// music mode
|
if (db instanceof MusicIdentificationService) {
|
||||||
return renameMusic(files, action, conflictAction, outputDir, format, getMusicIdentificationService(db));
|
return renameMusic(files, action, conflict, output, format, (MusicIdentificationService) db);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (XattrMetaData.getIdentifier().equalsIgnoreCase(db)) {
|
// generic file / xattr mode
|
||||||
return renameFiles(files, action, conflictAction, outputDir, format, XattrMetaData, filter, strict);
|
if (db instanceof XattrMetaInfoProvider) {
|
||||||
|
return renameFiles(files, action, conflict, output, format, (XattrMetaInfoProvider) db, filter, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto-detect mode for each fileset
|
// auto-detect mode for each fileset
|
||||||
@ -128,16 +119,16 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
for (Type key : it.getKey().types()) {
|
for (Type key : it.getKey().types()) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case Movie:
|
case Movie:
|
||||||
results.addAll(renameMovie(it.getValue(), action, conflictAction, outputDir, format, TheMovieDB, query, filter, locale, strict));
|
results.addAll(renameMovie(it.getValue(), action, conflict, output, format, TheMovieDB, query, filter, locale, strict));
|
||||||
break;
|
break;
|
||||||
case Series:
|
case Series:
|
||||||
results.addAll(renameSeries(it.getValue(), action, conflictAction, outputDir, format, TheTVDB, query, SortOrder.forName(sortOrder), filter, locale, strict));
|
results.addAll(renameSeries(it.getValue(), action, conflict, output, format, TheTVDB, query, order, filter, locale, strict));
|
||||||
break;
|
break;
|
||||||
case Anime:
|
case Anime:
|
||||||
results.addAll(renameSeries(it.getValue(), action, conflictAction, outputDir, format, AniDB, query, SortOrder.forName(sortOrder), filter, locale, strict));
|
results.addAll(renameSeries(it.getValue(), action, conflict, output, format, AniDB, query, order, filter, locale, strict));
|
||||||
break;
|
break;
|
||||||
case Music:
|
case Music:
|
||||||
results.addAll(renameMusic(it.getValue(), action, conflictAction, outputDir, format, MediaInfoID3, AcoustID));
|
results.addAll(renameMusic(it.getValue(), action, conflict, output, format, MediaInfoID3, AcoustID));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,13 +137,17 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (results.isEmpty()) {
|
||||||
|
throw new CmdlineException("Failed to identify or process any files");
|
||||||
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> rename(Map<File, File> renameMap, RenameAction renameAction, String conflict) throws Exception {
|
public List<File> rename(Map<File, File> renameMap, RenameAction renameAction, ConflictAction conflict) throws Exception {
|
||||||
// generic rename function that can be passed any set of files
|
// generic rename function that can be passed any set of files
|
||||||
return renameAll(renameMap, renameAction, ConflictAction.forName(conflict), null);
|
return renameAll(renameMap, renameAction, conflict, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<File> renameSeries(Collection<File> files, RenameAction renameAction, ConflictAction conflictAction, File outputDir, ExpressionFormat format, EpisodeListProvider db, String query, SortOrder sortOrder, ExpressionFilter filter, Locale locale, boolean strict) throws Exception {
|
public List<File> renameSeries(Collection<File> files, RenameAction renameAction, ConflictAction conflictAction, File outputDir, ExpressionFormat format, EpisodeListProvider db, String query, SortOrder sortOrder, ExpressionFilter filter, Locale locale, boolean strict) throws Exception {
|
||||||
@ -658,7 +653,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
return new ArrayList<File>(renameLog.values());
|
return new ArrayList<File>(renameLog.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File nextAvailableIndexedName(File file) {
|
protected static File nextAvailableIndexedName(File file) {
|
||||||
File parent = file.getParentFile();
|
File parent = file.getParentFile();
|
||||||
String name = getName(file);
|
String name = getName(file);
|
||||||
String ext = getExtension(file);
|
String ext = getExtension(file);
|
||||||
@ -666,17 +661,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> getSubtitles(Collection<File> files, String db, String query, String languageName, String output, String csn, String format, boolean strict) throws Exception {
|
public List<File> getSubtitles(Collection<File> files, String query, Language language, SubtitleFormat output, Charset encoding, SubtitleNaming format, boolean strict) throws Exception {
|
||||||
Language language = getLanguage(languageName);
|
|
||||||
SubtitleNaming naming = getSubtitleNaming(format);
|
|
||||||
|
|
||||||
// use all or only selected subtitle services
|
|
||||||
Predicate<Datasource> serviceFilter = service -> db == null ? true : db.contains(service.getName()) || db.contains(service.getIdentifier());
|
|
||||||
|
|
||||||
// when rewriting subtitles to target format an encoding must be defined, default to UTF-8
|
|
||||||
Charset outputEncoding = csn != null ? Charset.forName(csn) : output != null ? UTF_8 : null;
|
|
||||||
SubtitleFormat outputFormat = output != null ? getSubtitleFormatByName(output) : null;
|
|
||||||
|
|
||||||
// ignore anything that is not a video
|
// ignore anything that is not a video
|
||||||
files = filter(files, VIDEO_FILES);
|
files = filter(files, VIDEO_FILES);
|
||||||
|
|
||||||
@ -696,14 +681,14 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
|
|
||||||
// lookup subtitles by hash
|
// lookup subtitles by hash
|
||||||
for (VideoHashSubtitleService service : getVideoHashSubtitleServices(language.getLocale())) {
|
for (VideoHashSubtitleService service : getVideoHashSubtitleServices(language.getLocale())) {
|
||||||
if (remainingVideos.isEmpty() || !serviceFilter.test(service) || !requireLogin(service)) {
|
if (remainingVideos.isEmpty() || !requireLogin(service)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.fine("Looking up subtitles by hash via " + service.getName());
|
log.fine("Looking up subtitles by hash via " + service.getName());
|
||||||
Map<File, List<SubtitleDescriptor>> options = lookupSubtitlesByHash(service, remainingVideos, language.getName(), false, strict);
|
Map<File, List<SubtitleDescriptor>> options = lookupSubtitlesByHash(service, remainingVideos, language.getName(), false, strict);
|
||||||
Map<File, File> downloads = downloadSubtitleBatch(service, options, outputFormat, outputEncoding, naming);
|
Map<File, File> downloads = downloadSubtitleBatch(service, options, output, encoding, format);
|
||||||
remainingVideos.removeAll(downloads.keySet());
|
remainingVideos.removeAll(downloads.keySet());
|
||||||
subtitleFiles.addAll(downloads.values());
|
subtitleFiles.addAll(downloads.values());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -711,15 +696,15 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SubtitleProvider service : getSubtitleProviders()) {
|
for (SubtitleProvider service : getSubtitleProviders(language.getLocale())) {
|
||||||
if (strict || remainingVideos.isEmpty() || !serviceFilter.test(service) || !requireLogin(service)) {
|
if (strict || remainingVideos.isEmpty() || !requireLogin(service)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.fine(format("Looking up subtitles by name via %s", service.getName()));
|
log.fine(format("Looking up subtitles by name via %s", service.getName()));
|
||||||
Map<File, List<SubtitleDescriptor>> options = findSubtitlesByName(service, remainingVideos, language.getName(), query, false, strict);
|
Map<File, List<SubtitleDescriptor>> options = findSubtitlesByName(service, remainingVideos, language.getName(), query, false, strict);
|
||||||
Map<File, File> downloads = downloadSubtitleBatch(service, options, outputFormat, outputEncoding, naming);
|
Map<File, File> downloads = downloadSubtitleBatch(service, options, output, encoding, format);
|
||||||
remainingVideos.removeAll(downloads.keySet());
|
remainingVideos.removeAll(downloads.keySet());
|
||||||
subtitleFiles.addAll(downloads.values());
|
subtitleFiles.addAll(downloads.values());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -735,7 +720,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
return subtitleFiles;
|
return subtitleFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean requireLogin(Object service) {
|
protected static boolean requireLogin(Object service) {
|
||||||
if (service instanceof OpenSubtitlesClient) {
|
if (service instanceof OpenSubtitlesClient) {
|
||||||
OpenSubtitlesClient osdb = (OpenSubtitlesClient) service;
|
OpenSubtitlesClient osdb = (OpenSubtitlesClient) service;
|
||||||
if (osdb.isAnonymous()) {
|
if (osdb.isAnonymous()) {
|
||||||
@ -746,47 +731,38 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> getMissingSubtitles(Collection<File> files, String db, String query, String languageName, String output, String csn, String format, boolean strict) throws Exception {
|
public List<File> getMissingSubtitles(Collection<File> files, String query, Language language, SubtitleFormat output, Charset encoding, SubtitleNaming format, boolean strict) throws Exception {
|
||||||
// sanity check
|
|
||||||
for (File f : files) {
|
|
||||||
if (!f.exists()) {
|
|
||||||
throw new FileNotFoundException(f.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<File> videoFiles = filter(filter(files, VIDEO_FILES), new FileFilter() {
|
List<File> videoFiles = filter(filter(files, VIDEO_FILES), new FileFilter() {
|
||||||
|
|
||||||
// save time on repeating filesystem calls
|
// save time on repeating filesystem calls
|
||||||
private Map<File, List<File>> cache = new HashMap<File, List<File>>();
|
private Map<File, List<File>> cache = new HashMap<File, List<File>>();
|
||||||
|
|
||||||
private SubtitleNaming naming = getSubtitleNaming(format);
|
|
||||||
|
|
||||||
// get language code suffix for given language (.eng)
|
|
||||||
private String languageCode = Language.getStandardLanguageCode(getLanguage(languageName).getName());
|
|
||||||
|
|
||||||
public boolean matchesLanguageCode(File f) {
|
public boolean matchesLanguageCode(File f) {
|
||||||
Locale languageSuffix = MediaDetection.releaseInfo.getSubtitleLanguageTag(getName(f));
|
Language languageSuffix = Language.getLanguage(releaseInfo.getSubtitleLanguageTag(getName(f)));
|
||||||
Language language = Language.getLanguage(languageSuffix);
|
if (languageSuffix != null) {
|
||||||
if (language != null) {
|
return languageSuffix.getCode().equals(language.getCode());
|
||||||
return language.getISO3().equalsIgnoreCase(languageCode);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File video) {
|
public boolean accept(File video) {
|
||||||
|
if (!video.isFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
List<File> subtitleFiles = cache.computeIfAbsent(video.getParentFile(), parent -> {
|
List<File> subtitleFiles = cache.computeIfAbsent(video.getParentFile(), parent -> {
|
||||||
return getChildren(parent, SUBTITLE_FILES);
|
return getChildren(parent, SUBTITLE_FILES);
|
||||||
});
|
});
|
||||||
|
|
||||||
// can't tell which subtitle belongs to which file -> if any subtitles exist skip the whole folder
|
// can't tell which subtitle belongs to which file -> if any subtitles exist skip the whole folder
|
||||||
if (naming == SubtitleNaming.ORIGINAL) {
|
if (format == SubtitleNaming.ORIGINAL) {
|
||||||
return subtitleFiles.size() == 0;
|
return subtitleFiles.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return subtitleFiles.stream().allMatch(f -> {
|
return subtitleFiles.stream().allMatch(f -> {
|
||||||
if (isDerived(f, video)) {
|
if (isDerived(f, video)) {
|
||||||
return naming != SubtitleNaming.MATCH_VIDEO && !matchesLanguageCode(f);
|
return format != SubtitleNaming.MATCH_VIDEO && !matchesLanguageCode(f);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -798,16 +774,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
return emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSubtitles(videoFiles, db, query, languageName, output, csn, format, strict);
|
return getSubtitles(videoFiles, query, language, output, encoding, format, strict);
|
||||||
}
|
|
||||||
|
|
||||||
private SubtitleNaming getSubtitleNaming(String format) {
|
|
||||||
SubtitleNaming naming = SubtitleNaming.forName(format);
|
|
||||||
if (naming != null) {
|
|
||||||
return naming;
|
|
||||||
} else {
|
|
||||||
return SubtitleNaming.MATCH_VIDEO_ADD_LANGUAGE_TAG;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<File, File> downloadSubtitleBatch(Datasource service, Map<File, List<SubtitleDescriptor>> subtitles, SubtitleFormat outputFormat, Charset outputEncoding, SubtitleNaming naming) {
|
private Map<File, File> downloadSubtitleBatch(Datasource service, Map<File, List<SubtitleDescriptor>> subtitles, SubtitleFormat outputFormat, Charset outputEncoding, SubtitleNaming naming) {
|
||||||
@ -834,19 +801,25 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
MemoryFile subtitleFile = fetchSubtitle(descriptor);
|
MemoryFile subtitleFile = fetchSubtitle(descriptor);
|
||||||
|
|
||||||
// subtitle filename is based on movie filename
|
// subtitle filename is based on movie filename
|
||||||
String ext = getExtension(subtitleFile.getName());
|
String extension = getExtension(subtitleFile.getName());
|
||||||
ByteBuffer data = subtitleFile.getData();
|
ByteBuffer data = subtitleFile.getData();
|
||||||
|
|
||||||
if (outputFormat != null || outputEncoding != null) {
|
if (outputFormat != null || outputEncoding != null) {
|
||||||
|
// adjust extension of the output file
|
||||||
if (outputFormat != null) {
|
if (outputFormat != null) {
|
||||||
ext = outputFormat.getFilter().extension(); // adjust extension of the output file
|
extension = outputFormat.getFilter().extension();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.finest(format("Export [%s] as [%s / %s]", subtitleFile.getName(), outputFormat, outputEncoding.displayName(Locale.ROOT)));
|
// default to UTF-8 if no other encoding is given
|
||||||
|
if (outputEncoding == null) {
|
||||||
|
outputEncoding = UTF_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.finest(format("Export [%s] as [%s / %s]", subtitleFile.getName(), outputFormat, outputEncoding));
|
||||||
data = exportSubtitles(subtitleFile, outputFormat, 0, outputEncoding);
|
data = exportSubtitles(subtitleFile, outputFormat, 0, outputEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
File destination = new File(movieFile.getParentFile(), naming.format(movieFile, descriptor, ext));
|
File destination = new File(movieFile.getParentFile(), naming.format(movieFile, descriptor, extension));
|
||||||
log.info(format("Writing [%s] to [%s]", subtitleFile.getName(), destination.getName()));
|
log.info(format("Writing [%s] to [%s]", subtitleFile.getName(), destination.getName()));
|
||||||
|
|
||||||
writeFile(data, destination);
|
writeFile(data, destination);
|
||||||
@ -893,18 +866,6 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
return probableMatches.size() <= 5 ? probableMatches : probableMatches.subList(0, 5); // trust that the correct match is in the Top 3
|
return probableMatches.size() <= 5 ? probableMatches : probableMatches.subList(0, 5); // trust that the correct match is in the Top 3
|
||||||
}
|
}
|
||||||
|
|
||||||
private Language getLanguage(String lang) throws Exception {
|
|
||||||
// try to look up by language code
|
|
||||||
Language language = Language.findLanguage(lang);
|
|
||||||
|
|
||||||
if (language == null) {
|
|
||||||
// unable to lookup language
|
|
||||||
throw new CmdlineException("Illegal language code: " + lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
return language;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(Collection<File> files) throws Exception {
|
public boolean check(Collection<File> files) throws Exception {
|
||||||
// only check existing hashes
|
// only check existing hashes
|
||||||
@ -918,10 +879,14 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File compute(Collection<File> files, String output, String csn) throws Exception {
|
public File compute(Collection<File> files, File output, HashType hash, Charset encoding) throws Exception {
|
||||||
// ignore folders and any sort of special files
|
// ignore folders and any sort of special files
|
||||||
files = filter(files, FILES);
|
files = filter(files, FILES);
|
||||||
|
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
throw new CmdlineException("No files: " + files);
|
||||||
|
}
|
||||||
|
|
||||||
// find common parent folder of all files
|
// find common parent folder of all files
|
||||||
File[] fileList = files.toArray(new File[0]);
|
File[] fileList = files.toArray(new File[0]);
|
||||||
File[][] pathArray = new File[fileList.length][];
|
File[][] pathArray = new File[fileList.length][];
|
||||||
@ -933,38 +898,22 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
File[] common = csm.matchFirstCommonSequence(pathArray);
|
File[] common = csm.matchFirstCommonSequence(pathArray);
|
||||||
|
|
||||||
if (common == null) {
|
if (common == null) {
|
||||||
throw new CmdlineException("Paths must be on the same filesystem: " + files);
|
throw new CmdlineException("All paths must be on the same filesystem: " + files);
|
||||||
}
|
}
|
||||||
|
|
||||||
// last element in the common sequence must be the root folder
|
// last element in the common sequence must be the root folder
|
||||||
File root = common[common.length - 1];
|
File root = common[common.length - 1];
|
||||||
|
|
||||||
// create verification file
|
if (output == null) {
|
||||||
File outputFile;
|
output = new File(root, root.getName() + '.' + hash.getFilter().extension());
|
||||||
HashType hashType;
|
} else if (!output.isAbsolute()) {
|
||||||
|
output = new File(root, output.getPath());
|
||||||
if (output != null && getExtension(output) != null) {
|
|
||||||
// use given filename
|
|
||||||
hashType = getHashTypeByExtension(getExtension(output));
|
|
||||||
outputFile = new File(root, output);
|
|
||||||
} else {
|
|
||||||
// auto-select the filename based on folder and type
|
|
||||||
hashType = (output != null) ? getHashTypeByExtension(output) : HashType.SFV;
|
|
||||||
outputFile = new File(root, root.getName() + "." + hashType.getFilter().extension());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashType == null) {
|
log.info(format("Compute %s hash for %s files [%s]", hash, files.size(), output));
|
||||||
throw new CmdlineException("Illegal output type: " + output);
|
compute(root, files, output, hash, encoding);
|
||||||
}
|
|
||||||
|
|
||||||
if (files.isEmpty()) {
|
return output;
|
||||||
throw new CmdlineException("No files: " + files);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(format("Compute %s hash for %s files [%s]", hashType, files.size(), outputFile));
|
|
||||||
compute(root.getPath(), files, outputFile, hashType, csn);
|
|
||||||
|
|
||||||
return outputFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean check(File verificationFile, File root) throws Exception {
|
private boolean check(File verificationFile, File root) throws Exception {
|
||||||
@ -1004,16 +953,16 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compute(String root, Collection<File> files, File outputFile, HashType hashType, String csn) throws IOException, Exception {
|
private void compute(File root, Collection<File> files, File outputFile, HashType hashType, Charset encoding) throws IOException, Exception {
|
||||||
// compute hashes recursively and write to file
|
// compute hashes recursively and write to file
|
||||||
VerificationFileWriter out = new VerificationFileWriter(outputFile, hashType.getFormat(), csn != null ? csn : "UTF-8");
|
VerificationFileWriter out = new VerificationFileWriter(outputFile, hashType.getFormat(), encoding != null ? encoding : UTF_8);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (File it : files) {
|
for (File it : files) {
|
||||||
if (it.isHidden() || MediaTypes.getDefaultFilter("verification").accept(it))
|
if (it.isHidden() || MediaTypes.getDefaultFilter("verification").accept(it))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
String relativePath = normalizePathSeparators(it.getPath().replace(root, "")).substring(1);
|
String relativePath = normalizePathSeparators(it.getPath().substring(root.getPath().length() + 1)); // skip root and first slash
|
||||||
String hash = computeHash(it, hashType);
|
String hash = computeHash(it, hashType);
|
||||||
log.info(format("%s %s", hash, relativePath));
|
log.info(format("%s %s", hash, relativePath));
|
||||||
|
|
||||||
@ -1028,17 +977,13 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> fetchEpisodeList(String query, String expression, String db, String sortOrderName, String filterExpression, String languageName) throws Exception {
|
public List<String> fetchEpisodeList(Datasource db, String query, ExpressionFormat format, ExpressionFilter filter, SortOrder order, Locale locale) throws Exception {
|
||||||
if (query == null || query.isEmpty()) {
|
if (query == null) {
|
||||||
throw new IllegalArgumentException("query is not defined");
|
throw new IllegalArgumentException("query is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
// find series on the web and fetch episode list
|
// find series on the web and fetch episode list
|
||||||
ExpressionFormat format = expression == null ? null : new ExpressionFormat(expression);
|
EpisodeListProvider service = db instanceof EpisodeListProvider ? (EpisodeListProvider) db : TheTVDB;
|
||||||
ExpressionFilter filter = filterExpression == null ? null : new ExpressionFilter(filterExpression);
|
|
||||||
EpisodeListProvider service = db == null ? TheTVDB : getEpisodeListProvider(db);
|
|
||||||
SortOrder sortOrder = SortOrder.forName(sortOrderName);
|
|
||||||
Locale locale = getLanguage(languageName).getLocale();
|
|
||||||
|
|
||||||
// search and select search result
|
// search and select search result
|
||||||
List<SearchResult> options = selectSearchResult(query, service.search(query, locale), false, false);
|
List<SearchResult> options = selectSearchResult(query, service.search(query, locale), false, false);
|
||||||
@ -1047,7 +992,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetch episodes and apply filter
|
// fetch episodes and apply filter
|
||||||
List<Episode> episodes = applyExpressionFilter(service.getEpisodeList(options.get(0), sortOrder, locale), filter);
|
List<Episode> episodes = applyExpressionFilter(service.getEpisodeList(options.get(0), order, locale), filter);
|
||||||
Map<File, Episode> context = new EntryList<File, Episode>(null, episodes);
|
Map<File, Episode> context = new EntryList<File, Episode>(null, episodes);
|
||||||
|
|
||||||
return episodes.stream().map(episode -> {
|
return episodes.stream().map(episode -> {
|
||||||
@ -1056,49 +1001,52 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getMediaInfo(Collection<File> files, String format, String filter) throws Exception {
|
public List<String> getMediaInfo(Collection<File> files, FileFilter filter, ExpressionFormat format) throws Exception {
|
||||||
ExpressionFormat formatter = new ExpressionFormat(format != null && format.length() > 0 ? format : "{fn} [{resolution} {vc} {channels} {ac} {minutes}m]");
|
List<File> selection = filter(files, FILES);
|
||||||
List<File> selection = filter(files, filter == null || filter.isEmpty() ? f -> true : new ExpressionFileFilter(new ExpressionFilter(filter), false));
|
|
||||||
|
|
||||||
|
// apply custom filter
|
||||||
|
if (filter != null) {
|
||||||
|
selection = filter(selection, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default expression format if not set
|
||||||
|
ExpressionFormat formatter = format != null ? format : new ExpressionFormat("{fn} [{resolution} {vc} {channels} {ac} {minutes}m]");
|
||||||
|
|
||||||
|
// lazy format
|
||||||
return new FunctionList<File, String>(selection, f -> formatter.format(new MediaBindingBean(xattr.getMetaInfo(f), f, null)));
|
return new FunctionList<File, String>(selection, f -> formatter.format(new MediaBindingBean(xattr.getMetaInfo(f), f, null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> revert(Collection<File> files, String filter, boolean test) throws Exception {
|
public List<File> revert(Collection<File> files, FileFilter filter, RenameAction action) throws Exception {
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
throw new CmdlineException("Expecting at least one input path");
|
throw new CmdlineException("Expecting at least one input path");
|
||||||
}
|
}
|
||||||
|
|
||||||
FileFilter fileFilter = filter == null || filter.isEmpty() ? f -> true : new ExpressionFileFilter(new ExpressionFilter(filter), false);
|
|
||||||
Set<File> whitelist = new HashSet<File>(files);
|
Set<File> whitelist = new HashSet<File>(files);
|
||||||
Map<File, File> history = HistorySpooler.getInstance().getCompleteHistory().getRenameMap();
|
Map<File, File> history = HistorySpooler.getInstance().getCompleteHistory().getRenameMap();
|
||||||
|
|
||||||
return history.entrySet().stream().filter(it -> {
|
return history.entrySet().stream().filter(it -> {
|
||||||
File original = it.getKey();
|
File original = it.getKey();
|
||||||
File current = it.getValue();
|
File current = it.getValue();
|
||||||
return Stream.of(current, original).flatMap(f -> listPath(f).stream()).anyMatch(whitelist::contains) && current.exists() && fileFilter.accept(current);
|
return Stream.of(current, original).flatMap(f -> listPath(f).stream()).anyMatch(whitelist::contains) && current.exists() && (filter == null || filter.accept(current));
|
||||||
}).map(it -> {
|
}).map(it -> {
|
||||||
File original = it.getKey();
|
File original = it.getKey();
|
||||||
File current = it.getValue();
|
File current = it.getValue();
|
||||||
|
|
||||||
log.info(format("Revert [%s] to [%s]", current, original));
|
log.info(format("Revert [%s] to [%s]", current, original));
|
||||||
if (test) {
|
if (action.canRevert()) {
|
||||||
return original;
|
try {
|
||||||
}
|
return StandardRenameAction.revert(current, original);
|
||||||
|
} catch (Exception e) {
|
||||||
try {
|
log.warning("Failed to revert file: " + e);
|
||||||
return StandardRenameAction.revert(current, original);
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
log.warning(format("Failed to revert file: %s", e.getMessage()));
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).filter(Objects::nonNull).collect(toList());
|
}).filter(Objects::nonNull).collect(toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<File> extract(Collection<File> files, String output, String conflict, FileFilter filter, boolean forceExtractAll) throws Exception {
|
public List<File> extract(Collection<File> files, File output, ConflictAction conflict, FileFilter filter, boolean forceExtractAll) throws Exception {
|
||||||
ConflictAction conflictAction = ConflictAction.forName(conflict);
|
|
||||||
|
|
||||||
// only keep single-volume archives or first part of multi-volume archives
|
// only keep single-volume archives or first part of multi-volume archives
|
||||||
List<File> archiveFiles = filter(files, Archive.VOLUME_ONE_FILTER);
|
List<File> archiveFiles = filter(files, Archive.VOLUME_ONE_FILTER);
|
||||||
List<File> extractedFiles = new ArrayList<File>();
|
List<File> extractedFiles = new ArrayList<File>();
|
||||||
@ -1106,11 +1054,11 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
for (File file : archiveFiles) {
|
for (File file : archiveFiles) {
|
||||||
Archive archive = Archive.open(file);
|
Archive archive = Archive.open(file);
|
||||||
try {
|
try {
|
||||||
File outputFolder = new File(output != null ? output : getName(file));
|
File outputFolder = output;
|
||||||
if (!outputFolder.isAbsolute()) {
|
|
||||||
outputFolder = new File(file.getParentFile(), outputFolder.getPath());
|
if (outputFolder == null || !outputFolder.isAbsolute()) {
|
||||||
|
outputFolder = new File(file.getParentFile(), outputFolder == null ? getName(file) : outputFolder.getPath()).getCanonicalFile();
|
||||||
}
|
}
|
||||||
outputFolder = outputFolder.getCanonicalFile(); // normalize weird paths
|
|
||||||
|
|
||||||
log.info(format("Read archive [%s] and extract to [%s]", file.getName(), outputFolder));
|
log.info(format("Read archive [%s] and extract to [%s]", file.getName(), outputFolder));
|
||||||
FileMapper outputMapper = new FileMapper(outputFolder);
|
FileMapper outputMapper = new FileMapper(outputFolder);
|
||||||
@ -1135,14 +1083,14 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
|
|
||||||
boolean skip = true;
|
boolean skip = true;
|
||||||
for (FileInfo future : filter == null || forceExtractAll ? outputMapping : selection) {
|
for (FileInfo future : filter == null || forceExtractAll ? outputMapping : selection) {
|
||||||
if (conflictAction == ConflictAction.AUTO) {
|
if (conflict == ConflictAction.AUTO) {
|
||||||
skip &= (future.toFile().exists() && future.getLength() == future.toFile().length());
|
skip &= (future.toFile().exists() && future.getLength() == future.toFile().length());
|
||||||
} else {
|
} else {
|
||||||
skip &= (future.toFile().exists());
|
skip &= (future.toFile().exists());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip || conflictAction == ConflictAction.OVERRIDE) {
|
if (!skip || conflict == ConflictAction.OVERRIDE) {
|
||||||
if (filter == null || forceExtractAll) {
|
if (filter == null || forceExtractAll) {
|
||||||
log.finest("Extracting files " + outputMapping);
|
log.finest("Extracting files " + outputMapping);
|
||||||
|
|
||||||
|
@ -6,14 +6,14 @@ import static net.filebot.media.XattrMetaInfo.*;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
public class ExpressionFileFilter implements FileFilter {
|
public class ExpressionFileFilter implements FileFilter {
|
||||||
|
|
||||||
private final ExpressionFilter filter;
|
private ExpressionFilter filter;
|
||||||
private final boolean error;
|
|
||||||
|
|
||||||
public ExpressionFileFilter(ExpressionFilter filter, boolean error) {
|
public ExpressionFileFilter(String expression) throws ScriptException {
|
||||||
this.filter = filter;
|
this.filter = new ExpressionFilter(expression);
|
||||||
this.error = error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionFilter getExpressionFilter() {
|
public ExpressionFilter getExpressionFilter() {
|
||||||
@ -25,9 +25,9 @@ public class ExpressionFileFilter implements FileFilter {
|
|||||||
try {
|
try {
|
||||||
return filter.matches(new MediaBindingBean(xattr.getMetaInfo(f), f, null));
|
return filter.matches(new MediaBindingBean(xattr.getMetaInfo(f), f, null));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
debug.warning(format("Expression failed: %s", e));
|
debug.warning("Filter expression failed: " + e);
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ public enum HashType {
|
|||||||
public ExtensionFileFilter getFilter() {
|
public ExtensionFileFilter getFilter() {
|
||||||
return MediaTypes.getDefaultFilter("verification/sfv");
|
return MediaTypes.getDefaultFilter("verification/sfv");
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
MD5 {
|
MD5 {
|
||||||
@ -44,7 +43,6 @@ public enum HashType {
|
|||||||
public ExtensionFileFilter getFilter() {
|
public ExtensionFileFilter getFilter() {
|
||||||
return MediaTypes.getDefaultFilter("verification/md5sum");
|
return MediaTypes.getDefaultFilter("verification/md5sum");
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
SHA1 {
|
SHA1 {
|
||||||
@ -69,7 +67,6 @@ public enum HashType {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "SHA1";
|
return "SHA1";
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
SHA256 {
|
SHA256 {
|
||||||
@ -94,7 +91,6 @@ public enum HashType {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "SHA2";
|
return "SHA2";
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ED2K {
|
ED2K {
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
|
|
||||||
package net.filebot.hash;
|
package net.filebot.hash;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import net.filebot.Settings;
|
import net.filebot.Settings;
|
||||||
|
|
||||||
|
|
||||||
public class VerificationFileWriter implements Closeable {
|
public class VerificationFileWriter implements Closeable {
|
||||||
|
|
||||||
protected PrintWriter out;
|
protected PrintWriter out;
|
||||||
protected VerificationFormat format;
|
protected VerificationFormat format;
|
||||||
|
|
||||||
|
public VerificationFileWriter(File file, VerificationFormat format, Charset charset) throws IOException {
|
||||||
public VerificationFileWriter(File file, VerificationFormat format, String charset) throws IOException {
|
this(new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)), false), format, charset);
|
||||||
this(new PrintWriter(file, charset), format, charset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VerificationFileWriter(PrintWriter out, VerificationFormat format, Charset charset) {
|
||||||
public VerificationFileWriter(PrintWriter out, VerificationFormat format, String charset) {
|
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
|
||||||
@ -30,19 +30,16 @@ public class VerificationFileWriter implements Closeable {
|
|||||||
writeHeader(charset);
|
writeHeader(charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void writeHeader(Charset charset) {
|
||||||
protected void writeHeader(String charset) {
|
|
||||||
out.format("; Generated by %s %s on %tF at %<tT%n", Settings.getApplicationName(), Settings.getApplicationVersion(), new Date());
|
out.format("; Generated by %s %s on %tF at %<tT%n", Settings.getApplicationName(), Settings.getApplicationVersion(), new Date());
|
||||||
out.format("; charset=%s%n", charset);
|
out.format("; charset=%s%n", charset);
|
||||||
out.format(";%n");
|
out.format(";%n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void write(String path, String hash) {
|
public void write(String path, String hash) {
|
||||||
out.format("%s%n", format.format(path, hash));
|
out.format("%s%n", format.format(path, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
out.close();
|
out.close();
|
||||||
|
@ -57,7 +57,7 @@ public class Preset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionFileFilter getIncludeFilter() {
|
public ExpressionFileFilter getIncludeFilter() {
|
||||||
return getInputFolder() == null ? null : getValue(includes, expression -> new ExpressionFileFilter(new ExpressionFilter(expression), false));
|
return getInputFolder() == null ? null : getValue(includes, expression -> new ExpressionFileFilter(expression));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionFormat getFormat() {
|
public ExpressionFormat getFormat() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
package net.filebot.ui.sfv;
|
package net.filebot.ui.sfv;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -11,35 +12,29 @@ import net.filebot.hash.VerificationFileWriter;
|
|||||||
import net.filebot.ui.transfer.TextFileExportHandler;
|
import net.filebot.ui.transfer.TextFileExportHandler;
|
||||||
import net.filebot.util.FileUtilities;
|
import net.filebot.util.FileUtilities;
|
||||||
|
|
||||||
|
|
||||||
class ChecksumTableExportHandler extends TextFileExportHandler {
|
class ChecksumTableExportHandler extends TextFileExportHandler {
|
||||||
|
|
||||||
private final ChecksumTableModel model;
|
private final ChecksumTableModel model;
|
||||||
|
|
||||||
|
|
||||||
public ChecksumTableExportHandler(ChecksumTableModel model) {
|
public ChecksumTableExportHandler(ChecksumTableModel model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canExport() {
|
public boolean canExport() {
|
||||||
return model.getRowCount() > 0 && defaultColumn() != null;
|
return model.getRowCount() > 0 && defaultColumn() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void export(PrintWriter out) {
|
public void export(PrintWriter out) {
|
||||||
export(new VerificationFileWriter(out, model.getHashType().getFormat(), "UTF-8"), defaultColumn(), model.getHashType());
|
export(new VerificationFileWriter(out, model.getHashType().getFormat(), UTF_8), defaultColumn(), model.getHashType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultFileName() {
|
public String getDefaultFileName() {
|
||||||
return getDefaultFileName(defaultColumn());
|
return getDefaultFileName(defaultColumn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected File defaultColumn() {
|
protected File defaultColumn() {
|
||||||
// select first column that is not a verification file column
|
// select first column that is not a verification file column
|
||||||
for (File root : model.getChecksumColumns()) {
|
for (File root : model.getChecksumColumns()) {
|
||||||
@ -50,9 +45,8 @@ class ChecksumTableExportHandler extends TextFileExportHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void export(File file, File column) throws IOException {
|
public void export(File file, File column) throws IOException {
|
||||||
VerificationFileWriter writer = new VerificationFileWriter(file, model.getHashType().getFormat(), "UTF-8");
|
VerificationFileWriter writer = new VerificationFileWriter(file, model.getHashType().getFormat(), UTF_8);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
export(writer, column, model.getHashType());
|
export(writer, column, model.getHashType());
|
||||||
@ -61,7 +55,6 @@ class ChecksumTableExportHandler extends TextFileExportHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void export(VerificationFileWriter out, File column, HashType type) {
|
public void export(VerificationFileWriter out, File column, HashType type) {
|
||||||
for (ChecksumRow row : model.rows()) {
|
for (ChecksumRow row : model.rows()) {
|
||||||
ChecksumCell cell = row.getChecksum(column);
|
ChecksumCell cell = row.getChecksum(column);
|
||||||
@ -76,7 +69,6 @@ class ChecksumTableExportHandler extends TextFileExportHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getDefaultFileName(File column) {
|
public String getDefaultFileName(File column) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
@ -124,15 +124,18 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||||||
|
|
||||||
private final SubtitleDropTarget downloadDropTarget = new SubtitleDropTarget.Download() {
|
private final SubtitleDropTarget downloadDropTarget = new SubtitleDropTarget.Download() {
|
||||||
|
|
||||||
|
public Locale getLocale() {
|
||||||
|
return languageComboBox.getModel().getSelectedItem() == ALL_LANGUAGES ? Locale.ROOT : languageComboBox.getModel().getSelectedItem().getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VideoHashSubtitleService[] getVideoHashSubtitleServices() {
|
public VideoHashSubtitleService[] getVideoHashSubtitleServices() {
|
||||||
Locale locale = languageComboBox.getModel().getSelectedItem() == ALL_LANGUAGES ? Locale.ROOT : languageComboBox.getModel().getSelectedItem().getLocale();
|
return WebServices.getVideoHashSubtitleServices(getLocale());
|
||||||
return WebServices.getVideoHashSubtitleServices(locale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubtitleProvider[] getSubtitleProviders() {
|
public SubtitleProvider[] getSubtitleProviders() {
|
||||||
return WebServices.getSubtitleProviders();
|
return WebServices.getSubtitleProviders(getLocale());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -182,7 +185,7 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SubtitleProvider[] getSearchEngines() {
|
protected SubtitleProvider[] getSearchEngines() {
|
||||||
return WebServices.getSubtitleProviders();
|
return WebServices.getSubtitleProviders(getLocale());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user