mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-21 23:38:50 -05:00
Refactor Episode / MultiEpisode / EpisodeUtilities
This commit is contained in:
parent
b10ed1fdd9
commit
265eef6200
@ -72,7 +72,6 @@ import net.filebot.web.EpisodeFormat;
|
||||
import net.filebot.web.Movie;
|
||||
import net.filebot.web.MovieInfo;
|
||||
import net.filebot.web.MoviePart;
|
||||
import net.filebot.web.MultiEpisode;
|
||||
import net.filebot.web.SeriesInfo;
|
||||
import net.filebot.web.SimpleDate;
|
||||
import net.filebot.web.SortOrder;
|
||||
@ -151,13 +150,9 @@ public class MediaBindingBean {
|
||||
@Define("s")
|
||||
public Integer getSeasonNumber() {
|
||||
// look up season numbers via TheTVDB for AniDB episode data
|
||||
if (isAnime(getEpisode())) {
|
||||
return trySeasonEpisodeForAnime(getEpisode()).getSeason();
|
||||
}
|
||||
|
||||
return getEpisode().getSeason();
|
||||
}
|
||||
|
||||
@Define("e")
|
||||
public Integer getEpisodeNumber() {
|
||||
return getEpisode().getEpisode();
|
||||
@ -194,7 +189,7 @@ public class MediaBindingBean {
|
||||
String t = null;
|
||||
|
||||
if (infoObject instanceof Episode) {
|
||||
t = infoObject instanceof MultiEpisode ? EpisodeFormat.SeasonEpisode.formatMultiTitle(getEpisodes()) : getEpisode().getTitle(); // implicit support for multi-episode title formatting
|
||||
t = getEpisode().getTitle();
|
||||
} else if (infoObject instanceof Movie) {
|
||||
t = getMovieInfo().getTagline();
|
||||
} else if (infoObject instanceof AudioTrack) {
|
||||
@ -270,7 +265,7 @@ public class MediaBindingBean {
|
||||
}
|
||||
|
||||
// access episode list and find minimum airdate if necessary
|
||||
return getEpisodeList().stream().filter(e -> isRegular(e)).map(Episode::getAirdate).filter(Objects::nonNull).min(SimpleDate::compareTo).get();
|
||||
return getEpisodeList().stream().filter(Episode::isRegular).map(Episode::getAirdate).filter(Objects::nonNull).min(SimpleDate::compareTo).get();
|
||||
}
|
||||
|
||||
@Define("absolute")
|
||||
@ -804,12 +799,12 @@ public class MediaBindingBean {
|
||||
|
||||
@Define("anime")
|
||||
public boolean isAnimeEpisode() {
|
||||
return getEpisodes().stream().anyMatch(it -> isAnime(it));
|
||||
return getEpisode().isAnime();
|
||||
}
|
||||
|
||||
@Define("regular")
|
||||
public boolean isRegularEpisode() {
|
||||
return getEpisodes().stream().anyMatch(it -> isRegular(it));
|
||||
return getEpisode().isRegular();
|
||||
}
|
||||
|
||||
@Define("episodelist")
|
||||
@ -819,12 +814,12 @@ public class MediaBindingBean {
|
||||
|
||||
@Define("sy")
|
||||
public List<Integer> getSeasonYears() throws Exception {
|
||||
return getEpisodeList().stream().filter(e -> isRegular(e) && e.getSeason().equals(getSeasonNumber()) && e.getAirdate() != null).map(e -> e.getAirdate().getYear()).sorted().distinct().collect(toList());
|
||||
return getEpisodeList().stream().filter(e -> e.isRegular() && e.getSeason().equals(getSeasonNumber()) && e.getAirdate() != null).map(e -> e.getAirdate().getYear()).sorted().distinct().collect(toList());
|
||||
}
|
||||
|
||||
@Define("sc")
|
||||
public Integer getSeasonCount() throws Exception {
|
||||
return getEpisodeList().stream().filter(e -> isRegular(e) && e.getSeason() != null).map(Episode::getSeason).max(Integer::compare).get();
|
||||
return getEpisodeList().stream().filter(e -> e.isRegular() && e.getSeason() != null).map(Episode::getSeason).max(Integer::compare).get();
|
||||
}
|
||||
|
||||
@Define("mediaTitle")
|
||||
@ -960,7 +955,7 @@ public class MediaBindingBean {
|
||||
|
||||
@Define("episodes")
|
||||
public List<Episode> getEpisodes() {
|
||||
return getMultiEpisodeList(getEpisode());
|
||||
return streamMultiEpisode(getEpisode()).collect(toList());
|
||||
}
|
||||
|
||||
@Define("movie")
|
||||
|
@ -4,7 +4,6 @@ import static java.util.Arrays.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.similarity.Normalization.*;
|
||||
import static net.filebot.util.FileUtilities.*;
|
||||
import static net.filebot.web.EpisodeUtilities.*;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -52,7 +51,7 @@ public class NamingStandard {
|
||||
}
|
||||
|
||||
public String getPath(Episode e) {
|
||||
if (isAnime(e)) {
|
||||
if (e.isAnime()) {
|
||||
// Anime
|
||||
return path(getAnimeFolder(), getSeriesFolder(e), getEpisodeName(e));
|
||||
} else {
|
||||
@ -140,7 +139,7 @@ public class NamingStandard {
|
||||
}
|
||||
|
||||
public String formatSeriesName(Episode e) {
|
||||
if (isAnime(e)) {
|
||||
if (e.isAnime()) {
|
||||
// Anime
|
||||
return e.getSeriesInfo().getName(); // series info name is the primary Anime name
|
||||
} else {
|
||||
@ -150,7 +149,7 @@ public class NamingStandard {
|
||||
}
|
||||
|
||||
public String formatEpisodeNumbers(Episode e) {
|
||||
if (isAnime(e)) {
|
||||
if (e.isAnime()) {
|
||||
// Anime
|
||||
return EpisodeFormat.SeasonEpisode.formatSxE(e);
|
||||
} else {
|
||||
@ -161,7 +160,7 @@ public class NamingStandard {
|
||||
|
||||
public String formatEpisodeTitle(Episode e) {
|
||||
// enforce title length limit by default
|
||||
return truncateText(EpisodeFormat.SeasonEpisode.formatMultiTitle(getMultiEpisodeList(e)), TITLE_MAX_LENGTH);
|
||||
return truncateText(EpisodeFormat.SeasonEpisode.formatMultiTitle(e), TITLE_MAX_LENGTH);
|
||||
}
|
||||
|
||||
public static final int TITLE_MAX_LENGTH = 150;
|
||||
|
@ -74,11 +74,7 @@ public enum AnimeLists {
|
||||
}
|
||||
|
||||
private Episode derive(Episode episode, int s, int e) {
|
||||
if (s == 0) {
|
||||
return episode.derive(null, null, e); // special episode
|
||||
} else {
|
||||
return episode.derive(s, e, null); // regular episode
|
||||
}
|
||||
return s == 0 ? episode.deriveSpecial(e) : episode.derive(s, e);
|
||||
}
|
||||
|
||||
public Optional<Integer> map(int id, AnimeLists destination) throws Exception {
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.filebot.web;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@ -90,10 +88,6 @@ public class Episode implements Serializable {
|
||||
return seriesInfo;
|
||||
}
|
||||
|
||||
public List<Integer> getNumbers() {
|
||||
return Arrays.asList(season, episode, special, absolute);
|
||||
}
|
||||
|
||||
public Set<String> getSeriesNames() {
|
||||
Set<String> names = new LinkedHashSet<String>();
|
||||
if (seriesName != null) {
|
||||
@ -112,6 +106,18 @@ public class Episode implements Serializable {
|
||||
return names;
|
||||
}
|
||||
|
||||
public boolean isAnime() {
|
||||
return seriesInfo != null && (Objects.equals(seriesInfo.getType(), SeriesInfo.TYPE_ANIME) || Objects.equals(seriesInfo.getDatabase(), "AniDB")); // HACK: check database == AniDB for backward compatibility
|
||||
}
|
||||
|
||||
public boolean isRegular() {
|
||||
return episode != null;
|
||||
}
|
||||
|
||||
public boolean isSpecial() {
|
||||
return special != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Episode) {
|
||||
@ -139,8 +145,16 @@ public class Episode implements Serializable {
|
||||
return new Episode(this);
|
||||
}
|
||||
|
||||
public Episode derive(Integer season, Integer episode, Integer special) {
|
||||
return new Episode(getSeriesName(), season, episode, getTitle(), getAbsolute(), special, getAirdate(), getId(), getSeriesInfo());
|
||||
public Episode derive(Integer season, Integer episode) {
|
||||
return derive(getSeriesName(), season, episode, getAbsolute(), null);
|
||||
}
|
||||
|
||||
public Episode deriveSpecial(Integer special) {
|
||||
return derive(getSeriesName(), getSeason(), null, getAbsolute(), special);
|
||||
}
|
||||
|
||||
public Episode derive(String seriesName, Integer season, Integer episode, Integer absolute) {
|
||||
return derive(seriesName, season, episode, absolute, null);
|
||||
}
|
||||
|
||||
public Episode derive(String seriesName, Integer season, Integer episode, Integer absolute, Integer special) {
|
||||
|
@ -1,13 +1,12 @@
|
||||
package net.filebot.web;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.similarity.Normalization.*;
|
||||
import static net.filebot.web.EpisodeUtilities.*;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
@ -27,7 +26,7 @@ public class EpisodeFormat extends Format {
|
||||
@Override
|
||||
public StringBuffer format(Object obj, StringBuffer sb, FieldPosition pos) {
|
||||
if (obj instanceof MultiEpisode) {
|
||||
return sb.append(formatMultiEpisode(((MultiEpisode) obj).getEpisodes()));
|
||||
return sb.append(formatMultiEpisode(((MultiEpisode) obj)));
|
||||
}
|
||||
|
||||
// format episode object, e.g. Dark Angel - 3x01 - Labyrinth [2009-06-01]
|
||||
@ -60,19 +59,19 @@ public class EpisodeFormat extends Format {
|
||||
return sb;
|
||||
}
|
||||
|
||||
public String formatMultiEpisode(Collection<Episode> episodes) {
|
||||
Function<Episode, String> seriesName = it -> it.getSeriesName();
|
||||
Function<Episode, String> episodeNumber = it -> formatSxE(it);
|
||||
Function<Episode, String> episodeTitle = it -> it.getTitle() == null ? "" : removeTrailingBrackets(it.getTitle());
|
||||
public String formatMultiEpisode(Episode... episodes) {
|
||||
Function<Episode, String> seriesName = Episode::getSeriesName;
|
||||
Function<Episode, String> episodeNumber = this::formatSxE;
|
||||
Function<Episode, String> episodeTitle = this::formatMultiTitle;
|
||||
|
||||
return Stream.of(seriesName, episodeNumber, episodeTitle).map(f -> {
|
||||
return episodes.stream().map(f::apply).filter(s -> s.length() > 0).distinct().collect(joining(" & "));
|
||||
return streamMultiEpisode(episodes).map(f).filter(s -> s.length() > 0).distinct().collect(joining(" & "));
|
||||
}).collect(joining(" - "));
|
||||
}
|
||||
|
||||
public String formatSxE(Episode episode) {
|
||||
if (episode instanceof MultiEpisode) {
|
||||
return formatMultiRangeSxE(((MultiEpisode) episode).getEpisodes());
|
||||
return formatMultiRangeSxE(((MultiEpisode) episode));
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -87,7 +86,7 @@ public class EpisodeFormat extends Format {
|
||||
|
||||
public String formatS00E00(Episode episode) {
|
||||
if (episode instanceof MultiEpisode) {
|
||||
return formatMultiRangeS00E00(((MultiEpisode) episode).getEpisodes());
|
||||
return formatMultiRangeS00E00(((MultiEpisode) episode));
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -100,8 +99,8 @@ public class EpisodeFormat extends Format {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String formatMultiTitle(Collection<Episode> episodes) {
|
||||
return episodes.stream().map(Episode::getTitle).filter(Objects::nonNull).map(Normalization::removeTrailingBrackets).distinct().collect(joining(" & "));
|
||||
public String formatMultiTitle(Episode... episodes) {
|
||||
return streamMultiEpisode(episodes).map(Episode::getTitle).filter(Objects::nonNull).map(Normalization::removeTrailingBrackets).distinct().collect(joining(" & "));
|
||||
}
|
||||
|
||||
public String formatMultiRangeSxE(Iterable<Episode> episodes) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.filebot.web;
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.Logging.*;
|
||||
import static net.filebot.WebServices.*;
|
||||
@ -11,34 +11,27 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class EpisodeUtilities {
|
||||
|
||||
public static Episode mapEpisode(Episode episode, Function<Episode, Episode> mapper) {
|
||||
return createEpisode(getMultiEpisodeList(episode).stream().map(mapper).sorted(EPISODE_NUMBERS_COMPARATOR).collect(toList()));
|
||||
return createEpisode(streamMultiEpisode(episode).map(mapper).sorted(EPISODE_NUMBERS_COMPARATOR).toArray(Episode[]::new));
|
||||
}
|
||||
|
||||
public static Episode selectEpisode(List<Episode> episodelist, Episode selection) {
|
||||
return createEpisode(episodelist.stream().filter(getMultiEpisodeList(selection)::contains).sorted(EPISODE_NUMBERS_COMPARATOR).collect(toList()));
|
||||
return createEpisode(episodelist.stream().filter(streamMultiEpisode(selection).collect(toSet())::contains).sorted(EPISODE_NUMBERS_COMPARATOR).toArray(Episode[]::new));
|
||||
}
|
||||
|
||||
private static Episode createEpisode(List<Episode> episode) {
|
||||
if (episode.isEmpty()) {
|
||||
private static Episode createEpisode(Episode... episode) {
|
||||
if (episode.length == 0) {
|
||||
throw new IllegalArgumentException("Invalid Episode: Empty");
|
||||
}
|
||||
return episode.size() == 1 ? episode.get(0) : new MultiEpisode(episode);
|
||||
return episode.length == 1 ? episode[0] : new MultiEpisode(episode);
|
||||
}
|
||||
|
||||
public static List<Episode> getMultiEpisodeList(Episode e) {
|
||||
return e instanceof MultiEpisode ? ((MultiEpisode) e).getEpisodes() : singletonList(e);
|
||||
}
|
||||
|
||||
public static boolean isAnime(Episode e) {
|
||||
return AniDB.getIdentifier().equals(e.getSeriesInfo().getDatabase());
|
||||
}
|
||||
|
||||
public static boolean isRegular(Episode e) {
|
||||
return e.getEpisode() != null && e.getSpecial() == null;
|
||||
public static Stream<Episode> streamMultiEpisode(Episode... episodes) {
|
||||
return stream(episodes).flatMap(e -> e instanceof MultiEpisode ? ((MultiEpisode) e).stream() : Stream.of(e));
|
||||
}
|
||||
|
||||
public static List<Episode> fetchEpisodeList(Episode episode) throws Exception {
|
||||
@ -59,7 +52,7 @@ public final class EpisodeUtilities {
|
||||
}
|
||||
|
||||
public static Episode trySeasonEpisodeForAnime(Episode episode) {
|
||||
if (isAnime(episode) && isRegular(episode)) {
|
||||
if (episode.isAnime() && episode.isRegular()) {
|
||||
return mapEpisode(episode, e -> {
|
||||
try {
|
||||
return AnimeLists.forName(e.getSeriesInfo().getDatabase()).map(e, AnimeLists.TheTVDB).orElse(e);
|
||||
|
@ -1,12 +1,10 @@
|
||||
package net.filebot.web;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MultiEpisode extends Episode implements Iterable<Episode> {
|
||||
|
||||
@ -24,53 +22,86 @@ public class MultiEpisode extends Episode implements Iterable<Episode> {
|
||||
this.episodes = episodes.toArray(new Episode[0]);
|
||||
}
|
||||
|
||||
public Episode[] getEpisodes() {
|
||||
return episodes.clone();
|
||||
}
|
||||
|
||||
public Episode getFirst() {
|
||||
return episodes[0];
|
||||
}
|
||||
|
||||
public Stream<Episode> stream() {
|
||||
return Arrays.stream(episodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Episode> iterator() {
|
||||
return stream(episodes).iterator();
|
||||
}
|
||||
|
||||
public List<Episode> getEpisodes() {
|
||||
return unmodifiableList(asList(episodes));
|
||||
return stream().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSeriesName() {
|
||||
return episodes[0].getSeriesName();
|
||||
return getFirst().getSeriesName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEpisode() {
|
||||
return episodes[0].getEpisode();
|
||||
return getFirst().getEpisode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSeason() {
|
||||
return episodes[0].getSeason();
|
||||
return getFirst().getSeason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return EpisodeFormat.SeasonEpisode.formatMultiTitle(getEpisodes());
|
||||
return EpisodeFormat.SeasonEpisode.formatMultiTitle(episodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAbsolute() {
|
||||
return episodes[0].getAbsolute();
|
||||
return getFirst().getAbsolute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSpecial() {
|
||||
return episodes[0].getSpecial();
|
||||
return getFirst().getSpecial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDate getAirdate() {
|
||||
return episodes[0].getAirdate();
|
||||
return getFirst().getAirdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getId() {
|
||||
return episodes[0].getId();
|
||||
return getFirst().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeriesInfo getSeriesInfo() {
|
||||
return episodes[0].getSeriesInfo();
|
||||
return getFirst().getSeriesInfo();
|
||||
}
|
||||
|
||||
public List<Integer> getNumbers() {
|
||||
return stream(episodes).flatMap(e -> e.getNumbers().stream()).collect(toList());
|
||||
@Override
|
||||
public Set<String> getSeriesNames() {
|
||||
return getFirst().getSeriesNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnime() {
|
||||
return getFirst().isAnime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegular() {
|
||||
return getFirst().isRegular();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpecial() {
|
||||
return getFirst().isSpecial();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,9 +123,22 @@ public class MultiEpisode extends Episode implements Iterable<Episode> {
|
||||
return new MultiEpisode(episodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiEpisode derive(String seriesName, Integer season, Integer episode, Integer absolute, Integer special) {
|
||||
Episode[] m = new Episode[episodes.length];
|
||||
for (int i = 0; i < episodes.length; i++) {
|
||||
m[i] = episodes[i].derive(seriesName, season, up(episode, i), up(absolute, i), up(special, i));
|
||||
}
|
||||
return new MultiEpisode(m);
|
||||
}
|
||||
|
||||
private Integer up(Integer i, int delta) {
|
||||
return i == null ? null : i + delta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return EpisodeFormat.SeasonEpisode.formatMultiEpisode(getEpisodes());
|
||||
return EpisodeFormat.SeasonEpisode.formatMultiEpisode(episodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,9 +73,8 @@ public enum XEM {
|
||||
Map<String, Number> mappedNumbers = it.getValue();
|
||||
Integer e = getInteger(mappedNumbers, "episode");
|
||||
Integer a = getInteger(mappedNumbers, "absolute");
|
||||
Integer special = null;
|
||||
|
||||
return episode.derive(mappedSeriesName, mappedSeason, e, a, special);
|
||||
return episode.derive(mappedSeriesName, mappedSeason, e, a);
|
||||
}).collect(toList());
|
||||
|
||||
if (mappedEpisode.size() == 1) {
|
||||
|
Loading…
Reference in New Issue
Block a user