+ add addtional metadata (order, language) to episode and movie objects

This commit is contained in:
Reinhard Pointner 2014-07-24 11:31:03 +00:00
parent 8e80a02498
commit a5398cc5e1
12 changed files with 130 additions and 124 deletions

View File

@ -50,7 +50,6 @@ import net.filebot.web.MoviePart;
import net.filebot.web.MultiEpisode;
import net.filebot.web.SearchResult;
import net.filebot.web.SimpleDate;
import net.filebot.web.SortOrder;
import net.filebot.web.TheTVDBSearchResult;
import com.cedarsoftware.util.io.JsonWriter;
@ -556,14 +555,13 @@ public class MediaBindingBean {
if (metaInfo == null) {
try {
if (infoObject instanceof Episode)
metaInfo = WebServices.TheTVDB.getSeriesInfoByName(((Episode) infoObject).getSeriesName(), Locale.ENGLISH);
metaInfo = WebServices.TheTVDB.getSeriesInfoByName(getEpisode().getSeriesName(), getEpisode().getLanguage());
if (infoObject instanceof Movie)
metaInfo = WebServices.TheMovieDB.getMovieInfo(getMovie(), Locale.ENGLISH, true);
metaInfo = WebServices.TheMovieDB.getMovieInfo(getMovie(), getMovie().getLanguage(), true);
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve metadata: " + infoObject, e);
}
}
return createMapBindings(new PropertyBindings(metaInfo, null));
}
@ -588,7 +586,7 @@ public class MediaBindingBean {
@Define("episodelist")
public Object getEpisodeList() throws Exception {
return ((EpisodeListProvider) getDatabase()).getEpisodeList(getSeriesObject(), SortOrder.Airdate, Locale.ENGLISH);
return ((EpisodeListProvider) getDatabase()).getEpisodeList(getSeriesObject(), getEpisode().getOrder(), getEpisode().getLanguage());
}
@Define("database")

View File

@ -92,7 +92,7 @@ public class AnidbClient extends AbstractEpisodeListProvider {
}
@Override
public List<Episode> fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale language) throws Exception {
public List<Episode> fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception {
AnidbSearchResult anime = (AnidbSearchResult) searchResult;
// e.g. http://api.anidb.net:9001/httpapi?request=anime&client=filebot&clientver=1&protover=1&aid=4521
@ -112,7 +112,7 @@ public class AnidbClient extends AbstractEpisodeListProvider {
// select main title and anime start date
SimpleDate seriesStartDate = SimpleDate.parse(selectString("//startdate", dom), "yyyy-MM-dd");
String animeTitle = selectString("//titles/title[@type='official' and @lang='" + language.getLanguage() + "']", dom);
String animeTitle = selectString("//titles/title[@type='official' and @lang='" + locale.getLanguage() + "']", dom);
if (animeTitle.isEmpty()) {
animeTitle = selectString("//titles/title[@type='main']", dom);
}
@ -126,15 +126,15 @@ public class AnidbClient extends AbstractEpisodeListProvider {
if (type == 1 || type == 2) {
SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node), "yyyy-MM-dd");
String title = selectString(".//title[@lang='" + language.getLanguage() + "']", node);
String title = selectString(".//title[@lang='" + locale.getLanguage() + "']", node);
if (title.isEmpty()) { // English language fall-back
title = selectString(".//title[@lang='en']", node);
}
if (type == 1) {
episodes.add(new Episode(animeTitle, seriesStartDate, null, number, title, number, null, airdate, searchResult)); // normal episode, no seasons for anime
episodes.add(new Episode(animeTitle, seriesStartDate, null, number, title, number, null, SortOrder.Absolute, locale, airdate, searchResult)); // normal episode, no seasons for anime
} else {
episodes.add(new Episode(animeTitle, seriesStartDate, null, null, title, null, number, airdate, searchResult)); // special episode
episodes.add(new Episode(animeTitle, seriesStartDate, null, null, title, null, number, SortOrder.Absolute, locale, airdate, searchResult)); // special episode
}
}
}

View File

@ -3,41 +3,46 @@ package net.filebot.web;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class Episode implements Serializable {
private String seriesName;
private SimpleDate seriesStartDate;
protected String seriesName;
protected SimpleDate seriesStartDate;
private Integer season;
private Integer episode;
private String title;
protected Integer season;
protected Integer episode;
protected String title;
// absolute episode number
private Integer absolute;
protected Integer absolute;
// special number
private Integer special;
protected Integer special;
// optional episode number order hint & episode name / title language hint
protected String order;
protected String language;
// episode airdate
private SimpleDate airdate;
protected SimpleDate airdate;
// original series descriptor
private SearchResult series;
protected SearchResult series;
protected Episode() {
// used by serializer
}
public Episode(Episode obj) {
this(obj.seriesName, obj.seriesStartDate, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.airdate, obj.series);
this(obj.seriesName, obj.seriesStartDate, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.getOrder(), obj.getLanguage(), obj.airdate, obj.series);
}
public Episode(String seriesName, SimpleDate seriesStartDate, Integer season, Integer episode, String title, SearchResult series) {
this(seriesName, seriesStartDate, season, episode, title, null, null, null, series);
this(seriesName, seriesStartDate, season, episode, title, null, null, null, null, null, series);
}
public Episode(String seriesName, SimpleDate seriesStartDate, Integer season, Integer episode, String title, Integer absolute, Integer special, SimpleDate airdate, SearchResult series) {
public Episode(String seriesName, SimpleDate seriesStartDate, Integer season, Integer episode, String title, Integer absolute, Integer special, SortOrder order, Locale locale, SimpleDate airdate, SearchResult series) {
this.seriesName = seriesName;
this.seriesStartDate = (seriesStartDate == null ? null : seriesStartDate.clone());
this.season = season;
@ -45,6 +50,8 @@ public class Episode implements Serializable {
this.title = title;
this.absolute = absolute;
this.special = special;
this.order = (order == null ? null : order.name());
this.language = (locale == null ? null : locale.getLanguage());
this.airdate = (airdate == null ? null : airdate.clone());
this.series = (series == null ? null : series.clone());
}
@ -77,6 +84,14 @@ public class Episode implements Serializable {
return special;
}
public SortOrder getOrder() {
return order == null ? null : SortOrder.forName(order);
}
public Locale getLanguage() {
return language == null ? null : new Locale(language);
}
public SimpleDate getAirdate() {
return airdate;
}

View File

@ -187,7 +187,7 @@ public class EpisodeFormat extends Format {
// did parse input
pos.setIndex(source.length());
return new Episode(name, null, season, episode, title, season == null ? episode : null, special, airdate, null);
return new Episode(name, null, season, episode, title, season == null ? episode : null, special, null, null, airdate, null);
}
// failed to parse input

View File

@ -1,73 +1,66 @@
package net.filebot.web;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public final class EpisodeUtilities {
public static List<Episode> filterBySeason(Iterable<Episode> episodes, int season) {
List<Episode> results = new ArrayList<Episode>(25);
// filter given season from all seasons
for (Episode episode : episodes) {
if (episode.getSeason() != null && season == episode.getSeason()) {
results.add(episode);
}
}
return results;
}
public static int getLastSeason(Iterable<Episode> episodes) {
int lastSeason = 0;
// filter given season from all seasons
for (Episode episode : episodes) {
if (episode.getSeason() != null && episode.getSeason() > lastSeason) {
lastSeason = episode.getSeason();
}
}
return lastSeason;
}
public static void sortEpisodes(List<Episode> episodes) {
Collections.sort(episodes, episodeComparator());
}
public static Comparator<Episode> episodeComparator() {
return new Comparator<Episode>() {
@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 <T> int compareValue(Comparable<T> o1, T o2) {
if (o1 == null && o2 == null)
return 0;
@ -75,13 +68,12 @@ public final class EpisodeUtilities {
return Integer.MAX_VALUE;
if (o1 != null && o2 == null)
return Integer.MIN_VALUE;
return o1.compareTo(o2);
}
};
}
private EpisodeUtilities() {
throw new UnsupportedOperationException();
}

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class Movie extends SearchResult {
@ -12,19 +13,27 @@ public class Movie extends SearchResult {
protected int imdbId;
protected int tmdbId;
// optional movie name language hint
protected String language;
protected Movie() {
// used by serializer
}
public Movie(String name, int year, int imdbId, int tmdbId) {
this(name, new String[0], year, imdbId, tmdbId);
public Movie(Movie obj) {
this(obj.name, obj.aliasNames, obj.year, obj.imdbId, obj.tmdbId, obj.getLanguage());
}
public Movie(String name, String[] aliasNames, int year, int imdbId, int tmdbId) {
public Movie(String name, int year, int imdbId, int tmdbId) {
this(name, new String[0], year, imdbId, tmdbId, null);
}
public Movie(String name, String[] aliasNames, int year, int imdbId, int tmdbId, Locale locale) {
super(name, aliasNames);
this.year = year;
this.imdbId = imdbId;
this.tmdbId = tmdbId;
this.language = (locale == null ? null : locale.getLanguage());
}
public int getYear() {
@ -39,6 +48,10 @@ public class Movie extends SearchResult {
return tmdbId;
}
public Locale getLanguage() {
return language == null ? null : new Locale(language);
}
public String getNameWithYear() {
return toString(name, year);
}
@ -86,7 +99,7 @@ public class Movie extends SearchResult {
@Override
public Movie clone() {
return new Movie(name, aliasNames, year, imdbId, tmdbId);
return new Movie(this);
}
@Override

View File

@ -1,60 +1,46 @@
package net.filebot.web;
public class MoviePart extends Movie {
protected final int partIndex;
protected final int partCount;
public MoviePart(MoviePart obj) {
this(obj.name, obj.year, obj.imdbId, obj.tmdbId, obj.partIndex, obj.partCount);
this(obj, obj.partIndex, obj.partCount);
}
public MoviePart(Movie movie, int partIndex, int partCount) {
this(movie.name, movie.year, movie.imdbId, movie.tmdbId, partIndex, partCount);
}
public MoviePart(String name, int year, int imdbId, int tmdbId, int partIndex, int partCount) {
super(name, year, imdbId, tmdbId);
super(movie);
this.partIndex = partIndex;
this.partCount = partCount;
}
public int getPartIndex() {
return partIndex;
}
public int getPartCount() {
return partCount;
}
@Override
public boolean equals(Object object) {
if (object instanceof MoviePart && super.equals(object)) {
MoviePart other = (MoviePart) object;
return partIndex == other.partIndex && partCount == other.partCount;
}
return super.equals(object);
}
@Override
public MoviePart clone() {
return new MoviePart(this);
}
@Override
public String toString() {
return String.format("%s (%d) [%d]", name, year, partIndex);
}
}

View File

@ -141,7 +141,11 @@ public class SerienjunkiesClient extends AbstractEpisodeListProvider {
title = "";
}
episodes.add(new Episode(seriesName, series.getStartDate(), season, episode, title, i + 1, null, airdate, searchResult));
// additional metadata
SortOrder order = SortOrder.Airdate;
Locale language = Locale.GERMAN.equals(locale) ? Locale.GERMAN : Locale.ENGLISH;
episodes.add(new Episode(seriesName, series.getStartDate(), season, episode, title, i + 1, null, order, language, airdate, searchResult));
}
// make sure episodes are in ordered correctly

View File

@ -1,23 +1,19 @@
package net.filebot.web;
public enum SortOrder {
Airdate,
DVD,
Absolute;
Airdate, DVD, Absolute;
public static SortOrder forName(String name) {
for (SortOrder order : SortOrder.values()) {
if (order.name().equalsIgnoreCase(name)) {
return order;
}
}
throw new IllegalArgumentException("Invalid SortOrder: " + name);
}
@Override
public String toString() {
return String.format("%s Order", name());

View File

@ -129,7 +129,7 @@ public class TMDbClient implements MovieIdentificationService {
// make sure main title is not in the set of alternative titles
alternativeTitles.remove(title);
result.add(new Movie(title, alternativeTitles.toArray(new String[0]), year, -1, id));
result.add(new Movie(title, alternativeTitles.toArray(new String[0]), year, -1, id, locale));
} catch (Exception e) {
// only print 'missing release date' warnings for matching movie titles
if (query.equalsIgnoreCase(title) || query.equalsIgnoreCase(originalTitle)) {
@ -157,7 +157,7 @@ public class TMDbClient implements MovieIdentificationService {
String id = byIMDB ? String.format("tt%07d", imdbtmdbid) : String.valueOf(imdbtmdbid);
try {
MovieInfo info = getMovieInfo(id, locale, false, false);
return new Movie(info.getName(), info.getReleased().getYear(), info.getImdbId(), info.getId());
return new Movie(info.getName(), new String[0], info.getReleased().getYear(), info.getImdbId(), info.getId(), locale);
} catch (FileNotFoundException e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Movie not found: " + id);
return null;

View File

@ -1,7 +1,5 @@
package net.filebot.web;
import static net.filebot.util.XPathUtilities.*;
import static net.filebot.web.EpisodeUtilities.*;
import static net.filebot.web.WebRequest.*;
@ -22,63 +20,58 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TVRageClient extends AbstractEpisodeListProvider {
private final String host = "services.tvrage.com";
@Override
public String getName() {
return "TVRage";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.tvrage");
}
@Override
public ResultCache getCache() {
return new ResultCache(host, Cache.getCache("web-datasource"));
}
@Override
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws IOException, SAXException {
URL searchUrl = new URL("http", host, "/feeds/full_search.php?show=" + encode(query, true));
Document dom = getDocument(searchUrl);
List<Node> nodes = selectNodes("Results/show", dom);
List<SearchResult> searchResults = new ArrayList<SearchResult>(nodes.size());
for (Node node : nodes) {
int showid = Integer.parseInt(getTextContent("showid", node));
String name = getTextContent("name", node);
String link = getTextContent("link", node);
searchResults.add(new TVRageSearchResult(name, showid, link));
}
return searchResults;
}
@Override
public List<Episode> fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws IOException, SAXException {
TVRageSearchResult series = (TVRageSearchResult) searchResult;
URL episodeListUrl = new URL("http", host, "/feeds/full_show_info.php?sid=" + series.getSeriesId());
Document dom = getDocument(episodeListUrl);
String seriesName = selectString("Show/name", dom);
SimpleDate seriesStartDate = SimpleDate.parse(selectString("Show/started", dom), "MMM/dd/yyyy");
Locale language = Locale.ENGLISH;
List<Episode> episodes = new ArrayList<Episode>(25);
List<Episode> specials = new ArrayList<Episode>(5);
// episodes and specials
for (Node node : selectNodes("//episode", dom)) {
String title = getTextContent("title", node);
@ -86,34 +79,36 @@ public class TVRageClient extends AbstractEpisodeListProvider {
String seasonIdentifier = getAttribute("no", node.getParentNode());
Integer seasonNumber = seasonIdentifier == null ? null : new Integer(seasonIdentifier);
SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node), "yyyy-MM-dd");
SortOrder order = SortOrder.Airdate; // default order
// check if we have season and episode number, if not it must be a special episode
if (episodeNumber == null || seasonNumber == null) {
// handle as special episode
seasonNumber = getIntegerContent("season", node);
int specialNumber = filterBySeason(specials, seasonNumber).size() + 1;
specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, title, null, specialNumber, airdate, searchResult));
specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, title, null, specialNumber, order, language, airdate, searchResult));
} else {
// handle as normal episode
if (sortOrder == SortOrder.Absolute) {
episodeNumber = getIntegerContent("epnum", node);
seasonNumber = null;
order = SortOrder.Absolute;
}
episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, title, null, null, airdate, searchResult));
episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, title, null, null, order, language, airdate, searchResult));
}
}
// add specials at the end
episodes.addAll(specials);
return episodes;
}
@Override
public URI getEpisodeListLink(SearchResult searchResult) {
return URI.create(((TVRageSearchResult) searchResult).getLink() + "/episode_list/all");
}
}

View File

@ -139,6 +139,7 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
// default numbering
Integer episodeNumber = getIntegerContent("EpisodeNumber", node);
Integer seasonNumber = getIntegerContent("SeasonNumber", node);
SortOrder order = SortOrder.Airdate;
if (seasonNumber == null || seasonNumber == 0) {
// handle as special episode
@ -149,24 +150,30 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
// use given episode number as special number or count specials by ourselves
Integer specialNumber = (episodeNumber != null) ? episodeNumber : filterBySeason(specials, seasonNumber).size() + 1;
specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, episodeName, null, specialNumber, airdate, searchResult));
specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, episodeName, null, specialNumber, order, locale, airdate, searchResult));
} else {
// handle as normal episode
if (sortOrder == SortOrder.Absolute) {
if (absoluteNumber != null) {
episodeNumber = absoluteNumber;
seasonNumber = null;
order = SortOrder.Absolute;
}
} else if (sortOrder == SortOrder.DVD) {
try {
episodeNumber = new Float(dvdEpisodeNumber).intValue();
seasonNumber = new Integer(dvdSeasonNumber);
int eno = new Float(dvdEpisodeNumber).intValue();
int sno = new Float(dvdSeasonNumber).intValue();
// require both values to be successfully read
episodeNumber = eno;
seasonNumber = sno;
order = SortOrder.DVD;
} catch (Exception e) {
// ignore, fallback to default numbering
}
}
episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, searchResult));
episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, episodeName, absoluteNumber, null, order, locale, airdate, searchResult));
}
}