diff --git a/source/net/filebot/media/AutoDetection.java b/source/net/filebot/media/AutoDetection.java index 102383c9..bc05b102 100644 --- a/source/net/filebot/media/AutoDetection.java +++ b/source/net/filebot/media/AutoDetection.java @@ -7,7 +7,6 @@ import static java.util.stream.Collectors.*; import static net.filebot.Logging.*; import static net.filebot.MediaTypes.*; import static net.filebot.media.MediaDetection.*; -import static net.filebot.media.XattrMetaInfo.*; import static net.filebot.similarity.Normalization.*; import static net.filebot.util.FileUtilities.*; import static net.filebot.util.StringUtilities.*; @@ -16,10 +15,15 @@ import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.EnumMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.function.Predicate; import java.util.logging.Level; import java.util.regex.Pattern; @@ -62,7 +66,7 @@ public class AutoDetection { private static final Pattern MOVIE_PATTERN = Pattern.compile("[\\\\/]Movies[\\\\/]", CASE_INSENSITIVE); private static final Pattern SERIES_PATTERN = Pattern.compile("[\\\\/](?:TV.Shows|TV.Series)[\\\\/]|tv[sp]-|EP\\d{1,3}|Season\\D?\\d{1,2}|\\d{4}.S\\d{2}", CASE_INSENSITIVE); - private static final Pattern ANIME_PATTERN = Pattern.compile("[\\\\/]Anime[\\\\/]|[\\(\\[](\\p{XDigit}{8})[\\]\\)]|[\\[][A-Z]+Subs[\\]]", CASE_INSENSITIVE); + private static final Pattern ANIME_PATTERN = Pattern.compile("[\\\\/]Anime[\\\\/]|[\\(\\[]\\p{XDigit}{8}[\\]\\)]|[\\[][A-Z]+Subs[\\]]", CASE_INSENSITIVE); private Predicate forceIgnore = f -> false; private Predicate forceMusic = f -> AUDIO_FILES.accept(f) && !VIDEO_FILES.accept(f); @@ -70,8 +74,11 @@ public class AutoDetection { private Predicate forceSeries = f -> find(f.getPath(), SERIES_PATTERN) || isEpisode(f, true); private Predicate forceAnime = f -> find(f.getPath(), ANIME_PATTERN); - public Map> group() { - return stream(files).collect(groupingBy(f -> { + public Map> group() { + // sort keys and values + Map> groups = new TreeMap>(); + + stream(files).parallel().collect(groupingByConcurrent(f -> { Group group = new Group(); try { if (forceIgnore.test(f)) { @@ -81,44 +88,37 @@ public class AutoDetection { return group.music(f); } if (forceMovie.test(f)) { - return group.movie(detectMovie(f, false)); + return group.movie(getMovieMatches(f, false)); } if (forceSeries.test(f)) { - return group.series(detectSeries(f, false)); + return group.series(getSeriesMatches(f, false)); } if (forceAnime.test(f)) { - return group.anime(detectSeries(f, true)); + return group.anime(getSeriesMatches(f, true)); } return detectGroup(f); } catch (Exception e) { debug.log(Level.SEVERE, e.getMessage(), e); } return group; - })); + })).forEach((k, v) -> groups.put(k, new TreeSet(v))); + + return groups; } - private List detectSeries(File f, boolean anime) throws Exception { + private List getSeriesMatches(File f, boolean anime) throws Exception { List names = detectSeriesNames(singleton(f), anime, locale); - if (names.isEmpty()) { - names = detectSeriesNames(getVideoFiles(f.getParentFile()), anime, locale); + if (names.size() > 0) { + return names; } - return names; + List episodes = getVideoFiles(f.getParentFile()); + if (episodes.size() >= 5) { + return detectSeriesNames(episodes, anime, locale); + } + return emptyList(); } - private List detectMovie(File file, boolean strict) throws Exception { - // 1. xattr - Object metaObject = xattr.getMetaInfo(file); - if (metaObject instanceof Movie) { - return singletonList((Movie) metaObject); - } - - // 2. perfect filename match - Movie match = matchMovie(file, 4); - if (match != null) { - return singletonList(match); - } - - // 3. run full-fledged movie detection + private List getMovieMatches(File file, boolean strict) throws Exception { return MediaDetection.detectMovie(file, WebServices.TheMovieDB, locale, strict); } @@ -129,8 +129,8 @@ public class AutoDetection { private Group detectGroup(File f) throws Exception { Group group = new Group(); - List s = detectSeries(f, false); - List m = detectMovie(f, false); + List s = getSeriesMatches(f, false); + List m = getMovieMatches(f, false); if (m.isEmpty() && s.isEmpty()) return group; @@ -244,20 +244,18 @@ public class AutoDetection { return getChildren(f.getParentFile()).stream().filter(VIDEO_FILES::accept).filter(it -> { return find(dn, snm) || find(normalize(it.getName()), snm); }).map(it -> { - return streamMatches(it.getName(), EPISODE_NUMBERS).map(Integer::new).sorted().distinct().collect(toList()); + return streamMatches(it.getName(), EPISODE_NUMBERS).map(Integer::new).collect(toSet()); }).filter(it -> it.size() > 0).distinct().count() >= 10; } public boolean episodeWithoutNumbers() throws Exception { - return find(asn, DASH) && getMovieMatch().isEmpty(); + return find(asn, DASH) && getMovieMatches(f, true).isEmpty(); } public boolean episodeNumbers() throws Exception { - if (getMovieMatch().isEmpty()) { - String n = stripReleaseInfo(asn, false); - if (parseEpisodeNumber(n, false) != null || NUMBER_PAIR.matcher(n).find()) { - return Stream.of(dn, fn).anyMatch(it -> snm.matcher(it).find() && getMovieMatch().isEmpty()); - } + String n = stripReleaseInfo(asn, false); + if (parseEpisodeNumber(n, false) != null || NUMBER_PAIR.matcher(n).find()) { + return Stream.of(dn, fn).anyMatch(it -> snm.matcher(it).find()) && getMovieMatches(f, true).isEmpty(); } return false; } @@ -271,7 +269,7 @@ public class AutoDetection { } public boolean exactMovieMatch() throws Exception { - return detectMovie(f, true).size() > 0 && Stream.of(dn, fn).anyMatch(it -> find(it, YEAR)); + return getMovieMatches(f, true).size() > 0 && Stream.of(dn, fn).anyMatch(it -> find(it, YEAR)); } public boolean containsMovieName() { @@ -294,15 +292,6 @@ public class AutoDetection { return m.getEffectiveNamesWithoutYear().stream().map(this::normalize).anyMatch(fn::contains); } - private List m_match = null; - - private List getMovieMatch() { - if (m_match == null) { - m_match = MediaDetection.matchMovieName(asList(dn, fn), true, 0); - } - return m_match; - } - } @FunctionalInterface @@ -333,7 +322,7 @@ public class AutoDetection { Movie, Series, Anime, Music; } - public static class Group extends EnumMap { + public static class Group extends EnumMap implements Comparable { public Group() { super(Type.class); @@ -377,6 +366,17 @@ public class AutoDetection { return this; } + @Override + public int compareTo(Group other) { + if (size() != other.size()) { + return Integer.compare(size(), other.size()); + } + + return stream(Type.values()).mapToInt(t -> { + return Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER).compare(Objects.toString(get(t), null), Objects.toString(other.get(t), null)); + }).filter(i -> i != 0).findFirst().orElse(0); + } + } }