From 07037b34ce43ccc6b0defbbead4564be4c231502 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Fri, 26 Feb 2016 16:35:59 +0000 Subject: [PATCH] Support multi-episode objects where each episode member has the same SxE numbers @see https://www.filebot.net/forums/viewtopic.php?f=8&t=3456 --- .../filebot/similarity/EpisodeMatcher.java | 48 ++++++-------- source/net/filebot/web/Episode.java | 6 +- source/net/filebot/web/EpisodeFormat.java | 31 ++++----- source/net/filebot/web/EpisodeUtilities.java | 66 +++++++++---------- 4 files changed, 67 insertions(+), 84 deletions(-) diff --git a/source/net/filebot/similarity/EpisodeMatcher.java b/source/net/filebot/similarity/EpisodeMatcher.java index 2abe381f..b34770db 100644 --- a/source/net/filebot/similarity/EpisodeMatcher.java +++ b/source/net/filebot/similarity/EpisodeMatcher.java @@ -1,6 +1,8 @@ package net.filebot.similarity; +import static java.util.Arrays.*; import static java.util.Collections.*; +import static net.filebot.web.EpisodeUtilities.*; import java.io.File; import java.util.ArrayList; @@ -12,6 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Predicate; import net.filebot.media.SmartSeasonEpisodeMatcher; import net.filebot.similarity.SeasonEpisodeMatcher.SxE; @@ -55,20 +58,19 @@ public class EpisodeMatcher extends Matcher { File file = it.getValue(); Set uniqueFiles = normalizeIdentifierSet(parseEpisodeIdentifer(file)); - if (uniqueFiles.size() < 2) - continue; - Set uniqueEpisodes = normalizeIdentifierSet(episodeIdentifierSets.get(file)); - if (uniqueEpisodes.size() < 2) - continue; if (uniqueFiles.equals(uniqueEpisodes)) { List episodes = episodeSets.get(file); - if (isMultiEpisode(episodes)) { - MultiEpisode episode = new MultiEpisode(episodes.toArray(new Episode[0])); - disjointMatchCollection.add(new Match(file, episode)); - modified = true; + if (episodes.size() > 1) { + Episode[] episodeSequence = episodes.stream().sorted(episodeComparator()).distinct().toArray(Episode[]::new); + + if (isMultiEpisode(episodeSequence)) { + MultiEpisode episode = new MultiEpisode(episodeSequence); + disjointMatchCollection.add(new Match(file, episode)); + modified = true; + } } } } @@ -123,40 +125,30 @@ public class EpisodeMatcher extends Matcher { return identifier; } - private boolean isMultiEpisode(List episodes) { - // sanity check that there is valid episode data for at least two episodes - if (episodes.size() < 2) + private boolean isMultiEpisode(Episode[] episodes) { + if (episodes.length < 2) return false; // check episode sequence integrity Integer seqIndex = null; for (Episode it : episodes) { // any illegal episode object breaks the chain - if (it == null) - return false; - if (it.getEpisode() == null && it.getSpecial() == null) + Integer num = it != null ? it.getEpisode() != null ? it.getEpisode() : it.getSpecial() : null; + if (num == null) return false; - // non-sequential episode index breaks the chain + // non-sequential next episode index breaks the chain (same episode is OK since DVD numbering allows for multiple episodes to share the same SxE numbers) if (seqIndex != null) { - Integer num = it.getEpisode() != null ? it.getEpisode() : it.getSpecial(); - if (!num.equals(seqIndex + 1)) { + if (!(num.equals(seqIndex + 1) || num.equals(seqIndex))) { return false; } } - seqIndex = it.getEpisode() != null ? it.getEpisode() : it.getSpecial(); + seqIndex = num; } // check drill-down integrity - String seriesName = null; - for (Episode ep : episodes) { - if (seriesName != null && !seriesName.equals(ep.getSeriesName())) - return false; - - seriesName = ep.getSeriesName(); - } - - return true; + return stream(episodes).map(Episode::getSeriesName).allMatch(Predicate.isEqual(episodes[0].getSeriesName())); } + } diff --git a/source/net/filebot/web/Episode.java b/source/net/filebot/web/Episode.java index 9e67127e..acea85b6 100644 --- a/source/net/filebot/web/Episode.java +++ b/source/net/filebot/web/Episode.java @@ -82,7 +82,7 @@ public class Episode implements Serializable { } public List getNumbers() { - return Arrays.asList(season, episode, special); + return Arrays.asList(season, episode, special, absolute); } public List getSeriesNames() { @@ -107,7 +107,7 @@ public class Episode implements Serializable { public boolean equals(Object obj) { if (obj instanceof Episode) { Episode other = (Episode) obj; - return equals(season, other.season) && equals(episode, other.episode) && equals(seriesName, other.seriesName) && equals(title, other.title) && equals(special, other.special); + return equals(season, other.season) && equals(episode, other.episode) && equals(absolute, other.absolute) && equals(special, other.special) && equals(seriesName, other.seriesName) && equals(title, other.title); } return false; @@ -122,7 +122,7 @@ public class Episode implements Serializable { @Override public int hashCode() { - return Arrays.hashCode(new Object[] { seriesName, season, episode, title, special }); + return Arrays.hashCode(new Object[] { season, episode, absolute, special, seriesName, title }); } @Override diff --git a/source/net/filebot/web/EpisodeFormat.java b/source/net/filebot/web/EpisodeFormat.java index 279430c2..3ab01481 100644 --- a/source/net/filebot/web/EpisodeFormat.java +++ b/source/net/filebot/web/EpisodeFormat.java @@ -1,5 +1,6 @@ package net.filebot.web; +import static java.util.stream.Collectors.*; import static net.filebot.similarity.Normalization.*; import static net.filebot.util.StringUtilities.*; @@ -16,7 +17,7 @@ import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import java.util.stream.IntStream; public class EpisodeFormat extends Format { @@ -101,31 +102,23 @@ public class EpisodeFormat extends Format { } public String formatMultiTitle(List episodes) { - return episodes.stream().map(e -> removeTrailingBrackets(e.getTitle())).distinct().collect(Collectors.joining(" & ")); + return episodes.stream().map(e -> removeTrailingBrackets(e.getTitle())).distinct().collect(joining(" & ")); } public String formatMultiRangeSxE(List episodes) { - return getSeasonEpisodeNumbers(episodes).entrySet().stream().map(it -> { - if (it.getKey() >= 0) { - // season episode format - return String.format("%01dx%02d-%02d", it.getKey(), it.getValue().first(), it.getValue().last()); - } else { - // absolute episode format - return String.format("%02d-%02d", it.getValue().first(), it.getValue().last()); - } - }).collect(Collectors.joining("-")); + return formatMultiRangeNumbers(episodes, "%01dx", "%02d"); } public String formatMultiRangeS00E00(List episodes) { + return formatMultiRangeNumbers(episodes, "S%02d", "E%02d"); + } + + public String formatMultiRangeNumbers(List episodes, String seasonFormat, String episodeFormat) { return getSeasonEpisodeNumbers(episodes).entrySet().stream().map(it -> { - if (it.getKey() >= 0) { - // season episode format - return String.format("S%02dE%02d-E%02d", it.getKey(), it.getValue().first(), it.getValue().last()); - } else { - // absolute episode format - return String.format("E%02d-E%02d", it.getValue().first(), it.getValue().last()); - } - }).collect(Collectors.joining("-")); + String s = it.getKey() >= 0 ? String.format(seasonFormat, it.getKey()) : ""; + String e = IntStream.of(it.getValue().first(), it.getValue().last()).distinct().mapToObj(i -> String.format(episodeFormat, i)).collect(joining("-")); + return s + e; + }).collect(joining(" - ")); } private SortedMap> getSeasonEpisodeNumbers(Iterable episodes) { diff --git a/source/net/filebot/web/EpisodeUtilities.java b/source/net/filebot/web/EpisodeUtilities.java index c876f3fc..f49422f2 100644 --- a/source/net/filebot/web/EpisodeUtilities.java +++ b/source/net/filebot/web/EpisodeUtilities.java @@ -33,42 +33,40 @@ public final class EpisodeUtilities { } public static Comparator episodeComparator() { - return new Comparator() { - - @Override - public int compare(Episode a, Episode b) { - int diff = compareValue(a.getSeriesName(), b.getSeriesName()); - if (diff != 0) - return diff; - - diff = compareValue(a.getSeason(), b.getSeason()); - if (diff != 0) - return diff; - - diff = compareValue(a.getEpisode(), b.getEpisode()); - if (diff != 0) - return diff; - - diff = compareValue(a.getSpecial(), b.getSpecial()); - if (diff != 0) - return diff; - - return compareValue(a.getTitle(), b.getTitle()); - } - - private int compareValue(Comparable o1, T o2) { - if (o1 == null && o2 == null) - return 0; - if (o1 == null && o2 != null) - return Integer.MAX_VALUE; - if (o1 != null && o2 == null) - return Integer.MIN_VALUE; - - return o1.compareTo(o2); - } - }; + return NUMBERS_COMPARATOR; } + public static final Comparator NUMBERS_COMPARATOR = new Comparator() { + + @Override + public int compare(Episode a, Episode b) { + int diff = compareValue(a.getSeason(), b.getSeason()); + if (diff != 0) + return diff; + + diff = compareValue(a.getEpisode(), b.getEpisode()); + if (diff != 0) + return diff; + + diff = compareValue(a.getSpecial(), b.getSpecial()); + if (diff != 0) + return diff; + + return compareValue(a.getAbsolute(), b.getAbsolute()); + } + + private int compareValue(Comparable o1, T o2) { + if (o1 == null && o2 == null) + return 0; + if (o1 == null && o2 != null) + return Integer.MAX_VALUE; + if (o1 != null && o2 == null) + return Integer.MIN_VALUE; + + return o1.compareTo(o2); + } + }; + private EpisodeUtilities() { throw new UnsupportedOperationException(); }