* use TV Series index only for TV-mode and Anime index only for Anime-mode
This commit is contained in:
parent
c4ab4e8382
commit
ef2a64003b
|
@ -41,7 +41,6 @@ import net.sourceforge.filebot.HistorySpooler;
|
||||||
import net.sourceforge.filebot.Language;
|
import net.sourceforge.filebot.Language;
|
||||||
import net.sourceforge.filebot.MediaTypes;
|
import net.sourceforge.filebot.MediaTypes;
|
||||||
import net.sourceforge.filebot.RenameAction;
|
import net.sourceforge.filebot.RenameAction;
|
||||||
import net.sourceforge.filebot.WebServices;
|
|
||||||
import net.sourceforge.filebot.archive.Archive;
|
import net.sourceforge.filebot.archive.Archive;
|
||||||
import net.sourceforge.filebot.archive.FileMapper;
|
import net.sourceforge.filebot.archive.FileMapper;
|
||||||
import net.sourceforge.filebot.format.ExpressionFilter;
|
import net.sourceforge.filebot.format.ExpressionFilter;
|
||||||
|
@ -130,9 +129,9 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
|
|
||||||
CLILogger.finest(format("Filename pattern: [%.02f] SxE, [%.02f] CWS", sxe / max, cws / max));
|
CLILogger.finest(format("Filename pattern: [%.02f] SxE, [%.02f] CWS", sxe / max, cws / max));
|
||||||
if (sxe > (max * 0.65) || cws > (max * 0.65)) {
|
if (sxe > (max * 0.65) || cws > (max * 0.65)) {
|
||||||
return renameSeries(files, action, conflictAction, outputDir, format, WebServices.TheTVDB, query, SortOrder.forName(sortOrder), filter, locale, strict); // use default episode db
|
return renameSeries(files, action, conflictAction, outputDir, format, TheTVDB, query, SortOrder.forName(sortOrder), filter, locale, strict); // use default episode db
|
||||||
} else {
|
} else {
|
||||||
return renameMovie(files, action, conflictAction, outputDir, format, WebServices.TMDb, query, filter, locale, strict); // use default movie db
|
return renameMovie(files, action, conflictAction, outputDir, format, TMDb, query, filter, locale, strict); // use default movie db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +150,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
|
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
|
||||||
|
|
||||||
// auto-determine optimal batch sets
|
// auto-determine optimal batch sets
|
||||||
for (Entry<Set<File>, Set<String>> sameSeriesGroup : mapSeriesNamesByFiles(mediaFiles, locale).entrySet()) {
|
for (Entry<Set<File>, Set<String>> sameSeriesGroup : mapSeriesNamesByFiles(mediaFiles, locale, db != AniDB, db == AniDB).entrySet()) {
|
||||||
List<List<File>> batchSets = new ArrayList<List<File>>();
|
List<List<File>> batchSets = new ArrayList<List<File>>();
|
||||||
|
|
||||||
if (sameSeriesGroup.getValue() != null && sameSeriesGroup.getValue().size() > 0) {
|
if (sameSeriesGroup.getValue() != null && sameSeriesGroup.getValue().size() > 0) {
|
||||||
|
@ -168,7 +167,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
// auto-detect series name if not given
|
// auto-detect series name if not given
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
// detect series name by common word sequence
|
// detect series name by common word sequence
|
||||||
seriesNames = detectSeriesNames(batch, locale);
|
seriesNames = detectSeriesNames(batch, locale, db != AniDB, db == AniDB);
|
||||||
CLILogger.config("Auto-detected query: " + seriesNames);
|
CLILogger.config("Auto-detected query: " + seriesNames);
|
||||||
} else {
|
} else {
|
||||||
// use --q option
|
// use --q option
|
||||||
|
@ -663,7 +662,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup subtitles by hash
|
// lookup subtitles by hash
|
||||||
for (VideoHashSubtitleService service : WebServices.getVideoHashSubtitleServices()) {
|
for (VideoHashSubtitleService service : getVideoHashSubtitleServices()) {
|
||||||
if (remainingVideos.isEmpty() || (databaseFilter != null && !databaseFilter.matcher(service.getName()).matches())) {
|
if (remainingVideos.isEmpty() || (databaseFilter != null && !databaseFilter.matcher(service.getName()).matches())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -687,7 +686,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
try {
|
try {
|
||||||
List<File> videoFiles = filter(files, VIDEO_FILES);
|
List<File> videoFiles = filter(files, VIDEO_FILES);
|
||||||
querySet.addAll(detectSeriesNames(videoFiles, language.getLocale()));
|
querySet.addAll(detectSeriesNames(videoFiles, language.getLocale(), true, false));
|
||||||
|
|
||||||
// auto-detect movie names
|
// auto-detect movie names
|
||||||
for (File f : videoFiles) {
|
for (File f : videoFiles) {
|
||||||
|
@ -708,7 +707,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
||||||
querySet.add(query);
|
querySet.add(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SubtitleProvider service : WebServices.getSubtitleProviders()) {
|
for (SubtitleProvider service : getSubtitleProviders()) {
|
||||||
if (remainingVideos.isEmpty() || (databaseFilter != null && !databaseFilter.matcher(service.getName()).matches())) {
|
if (remainingVideos.isEmpty() || (databaseFilter != null && !databaseFilter.matcher(service.getName()).matches())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,14 +134,14 @@ public class MediaDetection {
|
||||||
return new DateMetric().parse(object);
|
return new DateMetric().parse(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Set<File>, Set<String>> mapSeriesNamesByFiles(Collection<File> files, Locale locale) throws Exception {
|
public static Map<Set<File>, Set<String>> mapSeriesNamesByFiles(Collection<File> files, Locale locale, boolean useSeriesIndex, boolean useAnimeIndex) throws Exception {
|
||||||
// map series names by folder
|
// map series names by folder
|
||||||
Map<File, Set<String>> seriesNamesByFolder = new HashMap<File, Set<String>>();
|
Map<File, Set<String>> seriesNamesByFolder = new HashMap<File, Set<String>>();
|
||||||
Map<File, List<File>> filesByFolder = mapByFolder(files);
|
Map<File, List<File>> filesByFolder = mapByFolder(files);
|
||||||
|
|
||||||
for (Entry<File, List<File>> it : filesByFolder.entrySet()) {
|
for (Entry<File, List<File>> it : filesByFolder.entrySet()) {
|
||||||
Set<String> namesForFolder = new TreeSet<String>(getLenientCollator(locale));
|
Set<String> namesForFolder = new TreeSet<String>(getLenientCollator(locale));
|
||||||
namesForFolder.addAll(detectSeriesNames(it.getValue(), locale));
|
namesForFolder.addAll(detectSeriesNames(it.getValue(), locale, useSeriesIndex, useAnimeIndex));
|
||||||
|
|
||||||
seriesNamesByFolder.put(it.getKey(), namesForFolder);
|
seriesNamesByFolder.put(it.getKey(), namesForFolder);
|
||||||
}
|
}
|
||||||
|
@ -271,6 +271,20 @@ public class MediaDetection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> detectSeriesNames(Collection<File> files, Locale locale) throws Exception {
|
public static List<String> detectSeriesNames(Collection<File> files, Locale locale) throws Exception {
|
||||||
|
return detectSeriesNames(files, locale, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> detectSeriesNames(Collection<File> files, Locale locale, boolean useSeriesIndex, boolean useAnimeIndex) throws Exception {
|
||||||
|
List<IndexEntry<SearchResult>> index = new ArrayList<IndexEntry<SearchResult>>();
|
||||||
|
if (useSeriesIndex)
|
||||||
|
index.addAll(getSeriesIndex());
|
||||||
|
if (useAnimeIndex)
|
||||||
|
index.addAll(getAnimeIndex());
|
||||||
|
|
||||||
|
return detectSeriesNames(files, locale, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> detectSeriesNames(Collection<File> files, Locale locale, List<IndexEntry<SearchResult>> seriesIndex) throws Exception {
|
||||||
List<String> names = new ArrayList<String>();
|
List<String> names = new ArrayList<String>();
|
||||||
|
|
||||||
// try xattr metadata if enabled
|
// try xattr metadata if enabled
|
||||||
|
@ -400,16 +414,15 @@ public class MediaDetection {
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<IndexEntry<SearchResult>> seriesIndex = new ArrayList<IndexEntry<SearchResult>>(100000);
|
private static final ArrayList<IndexEntry<SearchResult>> seriesIndex = new ArrayList<IndexEntry<SearchResult>>(0);
|
||||||
|
|
||||||
public static List<IndexEntry<SearchResult>> getSeriesIndex() throws IOException {
|
public static List<IndexEntry<SearchResult>> getSeriesIndex() throws IOException {
|
||||||
synchronized (seriesIndex) {
|
synchronized (seriesIndex) {
|
||||||
if (seriesIndex.isEmpty()) {
|
if (seriesIndex.isEmpty()) {
|
||||||
|
seriesIndex.ensureCapacity(100000);
|
||||||
try {
|
try {
|
||||||
for (SearchResult[] index : new SearchResult[][] { releaseInfo.getTheTVDBIndex(), releaseInfo.getAnidbIndex() }) {
|
for (SearchResult it : releaseInfo.getTheTVDBIndex()) {
|
||||||
for (SearchResult it : index) {
|
seriesIndex.addAll(HighPerformanceMatcher.prepare(it));
|
||||||
seriesIndex.addAll(HighPerformanceMatcher.prepare(it));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// can't load movie index, just try again next time
|
// can't load movie index, just try again next time
|
||||||
|
@ -423,6 +436,28 @@ public class MediaDetection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final ArrayList<IndexEntry<SearchResult>> animeIndex = new ArrayList<IndexEntry<SearchResult>>(0);
|
||||||
|
|
||||||
|
public static List<IndexEntry<SearchResult>> getAnimeIndex() throws IOException {
|
||||||
|
synchronized (animeIndex) {
|
||||||
|
if (animeIndex.isEmpty()) {
|
||||||
|
animeIndex.ensureCapacity(50000);
|
||||||
|
try {
|
||||||
|
for (SearchResult it : releaseInfo.getAnidbIndex()) {
|
||||||
|
animeIndex.addAll(HighPerformanceMatcher.prepare(it));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// can't load movie index, just try again next time
|
||||||
|
Logger.getLogger(MediaDetection.class.getClass().getName()).log(Level.SEVERE, "Failed to load anime index: " + e.getMessage(), e);
|
||||||
|
|
||||||
|
// rely on online search
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static List<String> matchSeriesByName(Collection<String> files, int maxStartIndex) throws Exception {
|
public static List<String> matchSeriesByName(Collection<String> files, int maxStartIndex) throws Exception {
|
||||||
HighPerformanceMatcher nameMatcher = new HighPerformanceMatcher(maxStartIndex);
|
HighPerformanceMatcher nameMatcher = new HighPerformanceMatcher(maxStartIndex);
|
||||||
List<String> matches = new ArrayList<String>();
|
List<String> matches = new ArrayList<String>();
|
||||||
|
@ -755,11 +790,12 @@ public class MediaDetection {
|
||||||
return matches != null && matches.size() > 0 ? matches.get(0) : null;
|
return matches != null && matches.size() > 0 ? matches.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<IndexEntry<Movie>> movieIndex = new ArrayList<IndexEntry<Movie>>(100000);
|
private static final ArrayList<IndexEntry<Movie>> movieIndex = new ArrayList<IndexEntry<Movie>>(0);
|
||||||
|
|
||||||
public static List<IndexEntry<Movie>> getMovieIndex() throws IOException {
|
public static List<IndexEntry<Movie>> getMovieIndex() throws IOException {
|
||||||
synchronized (movieIndex) {
|
synchronized (movieIndex) {
|
||||||
if (movieIndex.isEmpty()) {
|
if (movieIndex.isEmpty()) {
|
||||||
|
movieIndex.ensureCapacity(100000);
|
||||||
try {
|
try {
|
||||||
for (Movie it : releaseInfo.getMovieList()) {
|
for (Movie it : releaseInfo.getMovieList()) {
|
||||||
movieIndex.addAll(HighPerformanceMatcher.prepare(it));
|
movieIndex.addAll(HighPerformanceMatcher.prepare(it));
|
||||||
|
|
|
@ -50,11 +50,16 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
||||||
|
|
||||||
private final EpisodeListProvider provider;
|
private final EpisodeListProvider provider;
|
||||||
|
|
||||||
|
private boolean useAnimeIndex;
|
||||||
|
private boolean useSeriesIndex;
|
||||||
|
|
||||||
// only allow one fetch session at a time so later requests can make use of cached results
|
// only allow one fetch session at a time so later requests can make use of cached results
|
||||||
private final Object providerLock = new Object();
|
private final Object providerLock = new Object();
|
||||||
|
|
||||||
public EpisodeListMatcher(EpisodeListProvider provider) {
|
public EpisodeListMatcher(EpisodeListProvider provider, boolean useSeriesIndex, boolean useAnimeIndex) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
|
this.useSeriesIndex = useSeriesIndex;
|
||||||
|
this.useAnimeIndex = useAnimeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, Map<String, SearchResult> selectionMemory, final Component parent) throws Exception {
|
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, Map<String, SearchResult> selectionMemory, final Component parent) throws Exception {
|
||||||
|
@ -180,7 +185,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
||||||
final Map<String, List<String>> inputMemory = new TreeMap<String, List<String>>(CommonSequenceMatcher.getLenientCollator(Locale.ROOT));
|
final Map<String, List<String>> inputMemory = new TreeMap<String, List<String>>(CommonSequenceMatcher.getLenientCollator(Locale.ROOT));
|
||||||
|
|
||||||
// detect series names and create episode list fetch tasks
|
// detect series names and create episode list fetch tasks
|
||||||
for (Entry<Set<File>, Set<String>> sameSeriesGroup : mapSeriesNamesByFiles(mediaFiles, locale).entrySet()) {
|
for (Entry<Set<File>, Set<String>> sameSeriesGroup : mapSeriesNamesByFiles(mediaFiles, locale, useSeriesIndex, useAnimeIndex).entrySet()) {
|
||||||
final List<List<File>> batchSets = new ArrayList<List<File>>();
|
final List<List<File>> batchSets = new ArrayList<List<File>>();
|
||||||
final Collection<String> queries = sameSeriesGroup.getValue();
|
final Collection<String> queries = sameSeriesGroup.getValue();
|
||||||
|
|
||||||
|
@ -265,7 +270,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
||||||
|
|
||||||
// require user input if auto-detection has failed or has been disabled
|
// require user input if auto-detection has failed or has been disabled
|
||||||
if (episodes.isEmpty()) {
|
if (episodes.isEmpty()) {
|
||||||
List<String> detectedSeriesNames = detectSeriesNames(files, locale);
|
List<String> detectedSeriesNames = detectSeriesNames(files, locale, useSeriesIndex, useAnimeIndex);
|
||||||
String parentPathHint = normalizePathSeparators(getRelativePathTail(files.get(0).getParentFile(), 2).getPath());
|
String parentPathHint = normalizePathSeparators(getRelativePathTail(files.get(0).getParentFile(), 2).getPath());
|
||||||
String suggestion = detectedSeriesNames.size() > 0 ? join(detectedSeriesNames, ", ") : parentPathHint;
|
String suggestion = detectedSeriesNames.size() > 0 ? join(detectedSeriesNames, ", ") : parentPathHint;
|
||||||
|
|
||||||
|
|
|
@ -288,8 +288,8 @@ public class RenamePanel extends JComponent {
|
||||||
actionPopup.addDescription(new JLabel("Episode Mode:"));
|
actionPopup.addDescription(new JLabel("Episode Mode:"));
|
||||||
|
|
||||||
// create actions for match popup episode list completion
|
// create actions for match popup episode list completion
|
||||||
for (EpisodeListProvider provider : WebServices.getEpisodeListProviders()) {
|
for (EpisodeListProvider db : WebServices.getEpisodeListProviders()) {
|
||||||
actionPopup.add(new AutoCompleteAction(provider.getName(), provider.getIcon(), new EpisodeListMatcher(provider)));
|
actionPopup.add(new AutoCompleteAction(db.getName(), db.getIcon(), new EpisodeListMatcher(db, db != WebServices.AniDB, db == WebServices.AniDB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
actionPopup.addSeparator();
|
actionPopup.addSeparator();
|
||||||
|
|
|
@ -935,7 +935,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
Collection<String> querySet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
Collection<String> querySet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
|
||||||
// auto-detect series names
|
// auto-detect series names
|
||||||
querySet.addAll(detectSeriesNames(files, Locale.ROOT));
|
querySet.addAll(detectSeriesNames(files, Locale.ROOT, true, false));
|
||||||
|
|
||||||
// auto-detect movie names
|
// auto-detect movie names
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
|
|
Loading…
Reference in New Issue