diff --git a/source/net/filebot/media/AutoDetection.java b/source/net/filebot/media/AutoDetection.java index 8abd8701..53660fe1 100644 --- a/source/net/filebot/media/AutoDetection.java +++ b/source/net/filebot/media/AutoDetection.java @@ -44,8 +44,8 @@ public class AutoDetection { private File[] files; private Locale locale; - public AutoDetection(Collection root, Locale locale) { - this.files = resolve(root.stream().map(FastFile::new), getSystemFilesFilter()).toArray(File[]::new); + public AutoDetection(Collection root, boolean resolve, Locale locale) { + this.files = (resolve ? resolve(root.stream().map(FastFile::new), getSystemFilesFilter()) : root.stream()).toArray(File[]::new); this.locale = locale; } @@ -135,10 +135,10 @@ public class AutoDetection { if (isMusic(f)) return group.music(f); - if (isEpisode(f)) - return group.series(getSeriesMatches(f, false)); // episode characteristics override movie characteristics (e.g. episodes in Movies folder) - if (isMovie(f)) + if (isMovie(f) && !isEpisode(f)) // episode characteristics override movie characteristics (e.g. episodes in Movies folder) return group.movie(getMovieMatches(f, false)); + if (isEpisode(f)) + return group.series(getSeriesMatches(f, false)); if (isAnime(f)) return group.anime(getSeriesMatches(f, true)); diff --git a/source/net/filebot/resources/action.auto.png b/source/net/filebot/resources/action.auto.png new file mode 100644 index 00000000..640f890d Binary files /dev/null and b/source/net/filebot/resources/action.auto.png differ diff --git a/source/net/filebot/resources/action.auto@2x.png b/source/net/filebot/resources/action.auto@2x.png new file mode 100644 index 00000000..162078a5 Binary files /dev/null and b/source/net/filebot/resources/action.auto@2x.png differ diff --git a/source/net/filebot/ui/rename/AutoDetectMatcher.java b/source/net/filebot/ui/rename/AutoDetectMatcher.java new file mode 100644 index 00000000..7bdcb352 --- /dev/null +++ b/source/net/filebot/ui/rename/AutoDetectMatcher.java @@ -0,0 +1,78 @@ + +package net.filebot.ui.rename; + +import static java.util.Collections.*; +import static java.util.stream.Collectors.*; +import static net.filebot.Logging.*; +import static net.filebot.WebServices.*; + +import java.awt.Component; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Level; + +import net.filebot.media.AutoDetection; +import net.filebot.media.AutoDetection.Group; +import net.filebot.media.AutoDetection.Type; +import net.filebot.similarity.Match; +import net.filebot.web.SortOrder; + +class AutoDetectMatcher implements AutoCompleteMatcher { + + private AutoCompleteMatcher movie = new MovieMatcher(TheMovieDB); + private AutoCompleteMatcher episode = new EpisodeListMatcher(TheTVDB, false); + private AutoCompleteMatcher anime = new EpisodeListMatcher(AniDB, false); + private AutoCompleteMatcher music = new MusicMatcher(MediaInfoID3, AcoustID); + + @Override + public List> match(Collection files, boolean strict, SortOrder order, Locale locale, boolean autodetection, Component parent) throws Exception { + Map> groups = new AutoDetection(files, false, locale).group(); + + // can't use parallel stream because default fork/join pool doesn't play well with the security manager + ExecutorService executor = Executors.newWorkStealingPool(); + List> result = new ArrayList>(); + + groups.entrySet().stream().collect(toMap(Entry::getKey, it -> { + return executor.submit(() -> match(it.getKey(), it.getValue(), strict, order, locale, autodetection, parent)); + })).forEach((group, matches) -> { + try { + result.addAll(matches.get()); + } catch (Exception e) { + log.log(Level.WARNING, "Failed to process group: " + group, e); + } + }); + + executor.shutdown(); + return result; + } + + private List> match(Group group, Collection files, boolean strict, SortOrder order, Locale locale, boolean autodetection, Component parent) throws Exception { + if (group.values().stream().filter(Objects::nonNull).count() == 1) { + for (Type key : group.keySet()) { + switch (key) { + case Movie: + return movie.match(files, strict, order, locale, autodetection, parent); + case Series: + return episode.match(files, strict, order, locale, autodetection, parent); + case Anime: + return anime.match(files, strict, order, locale, autodetection, parent); + case Music: + return music.match(files, strict, order, locale, autodetection, parent); + } + } + } + + debug.info(format("Ignore group: %s", group)); + return emptyList(); + } + +} diff --git a/source/net/filebot/ui/rename/RenamePanel.java b/source/net/filebot/ui/rename/RenamePanel.java index d610d380..21ca55b3 100644 --- a/source/net/filebot/ui/rename/RenamePanel.java +++ b/source/net/filebot/ui/rename/RenamePanel.java @@ -426,7 +426,7 @@ public class RenamePanel extends JComponent { } protected ActionPopup createFetchPopup() { - final ActionPopup actionPopup = new ActionPopup("Fetch & Match Data", ResourceManager.getIcon("action.fetch")); + ActionPopup actionPopup = new ActionPopup("Fetch & Match Data", ResourceManager.getIcon("action.fetch")); actionPopup.addDescription(new JLabel("Episode Mode:")); @@ -449,6 +449,9 @@ public class RenamePanel extends JComponent { actionPopup.add(new AutoCompleteAction(it.getName(), it.getIcon(), new MusicMatcher(it))); } + actionPopup.addDescription(new JLabel("Smart Mode:")); + actionPopup.add(new AutoCompleteAction("Autodetect", ResourceManager.getIcon("action.auto"), new AutoDetectMatcher())); + actionPopup.addSeparator(); actionPopup.addDescription(new JLabel("Options:"));