Full support for "TheMovieDB::TV" and "TheMovieDB" datasources
This commit is contained in:
parent
e4817e9de8
commit
16d2459365
|
@ -35,6 +35,7 @@ import net.filebot.web.ShooterSubtitles;
|
|||
import net.filebot.web.SubtitleProvider;
|
||||
import net.filebot.web.SubtitleSearchResult;
|
||||
import net.filebot.web.TMDbClient;
|
||||
import net.filebot.web.TMDbTVClient;
|
||||
import net.filebot.web.TVMazeClient;
|
||||
import net.filebot.web.TheTVDBClient;
|
||||
import net.filebot.web.VideoHashSubtitleService;
|
||||
|
@ -45,28 +46,30 @@ import one.util.streamex.StreamEx;
|
|||
*/
|
||||
public final class WebServices {
|
||||
|
||||
// episode dbs
|
||||
// movie sources
|
||||
public static final OMDbClient OMDb = new OMDbClient();
|
||||
public static final TMDbClient TheMovieDB = new TMDbClient(getApiKey("themoviedb"));
|
||||
|
||||
// episode sources
|
||||
public static final TVMazeClient TVmaze = new TVMazeClient();
|
||||
public static final AnidbClient AniDB = new AnidbClientWithLocalSearch(getApiKey("anidb"), 6);
|
||||
|
||||
// extended TheTVDB module with local search
|
||||
public static final TheTVDBClientWithLocalSearch TheTVDB = new TheTVDBClientWithLocalSearch(getApiKey("thetvdb"));
|
||||
public static final TMDbTVClient TheMovieDB_TV = new TMDbTVClient(TheMovieDB);
|
||||
|
||||
// movie dbs
|
||||
public static final OMDbClient OMDb = new OMDbClient();
|
||||
public static final TMDbClient TheMovieDB = new TMDbClient(getApiKey("themoviedb"));
|
||||
|
||||
// subtitle dbs
|
||||
// subtitle sources
|
||||
public static final OpenSubtitlesClient OpenSubtitles = new OpenSubtitlesClientWithLocalSearch(getApiKey("opensubtitles"), getApplicationVersion());
|
||||
public static final ShooterSubtitles Shooter = new ShooterSubtitles();
|
||||
|
||||
// misc
|
||||
// other sources
|
||||
public static final FanartTVClient FanartTV = new FanartTVClient(Settings.getApiKey("fanart.tv"));
|
||||
public static final AcoustIDClient AcoustID = new AcoustIDClient(Settings.getApiKey("acoustid"));
|
||||
public static final XattrMetaInfoProvider XattrMetaData = new XattrMetaInfoProvider();
|
||||
public static final ID3Lookup MediaInfoID3 = new ID3Lookup();
|
||||
|
||||
public static EpisodeListProvider[] getEpisodeListProviders() {
|
||||
return new EpisodeListProvider[] { TheTVDB, TheMovieDB, AniDB, TVmaze };
|
||||
return new EpisodeListProvider[] { TheTVDB, TheMovieDB_TV, AniDB, TVmaze };
|
||||
}
|
||||
|
||||
public static MovieIdentificationService[] getMovieIdentificationServices() {
|
||||
|
@ -85,16 +88,10 @@ public final class WebServices {
|
|||
}
|
||||
|
||||
public static MusicIdentificationService[] getMusicIdentificationServices() {
|
||||
return new MusicIdentificationService[] { AcoustID, new ID3Lookup() };
|
||||
return new MusicIdentificationService[] { AcoustID, MediaInfoID3 };
|
||||
}
|
||||
|
||||
public static EpisodeListProvider getEpisodeListProvider(String name) {
|
||||
// special handling for TheMovieDB which is the only datasource that supports both series and movie mode
|
||||
if (name.equalsIgnoreCase(TheMovieDB.getName()))
|
||||
return null;
|
||||
if (name.equalsIgnoreCase(TheMovieDB.getName() + "::TV"))
|
||||
return TheMovieDB;
|
||||
|
||||
return getService(name, getEpisodeListProviders());
|
||||
}
|
||||
|
||||
|
@ -107,7 +104,7 @@ public final class WebServices {
|
|||
}
|
||||
|
||||
private static <T extends Datasource> T getService(String name, T[] services) {
|
||||
return StreamEx.of(services).findFirst(it -> it.getName().equalsIgnoreCase(name)).orElse(null);
|
||||
return StreamEx.of(services).findFirst(it -> it.getIdentifier().equalsIgnoreCase(name)).orElse(null);
|
||||
}
|
||||
|
||||
public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool();
|
||||
|
|
|
@ -94,16 +94,16 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
Locale locale = getLanguage(lang).getLocale();
|
||||
ConflictAction conflictAction = ConflictAction.forName(conflict);
|
||||
|
||||
if (getEpisodeListProvider(db) != null) {
|
||||
// tv series mode
|
||||
return renameSeries(files, action, conflictAction, outputDir, format, getEpisodeListProvider(db), query, SortOrder.forName(sortOrder), filter, locale, strict);
|
||||
}
|
||||
|
||||
if (getMovieIdentificationService(db) != null) {
|
||||
// movie mode
|
||||
return renameMovie(files, action, conflictAction, outputDir, format, getMovieIdentificationService(db), query, filter, locale, strict);
|
||||
}
|
||||
|
||||
if (getEpisodeListProvider(db) != null) {
|
||||
// tv series mode
|
||||
return renameSeries(files, action, conflictAction, outputDir, format, getEpisodeListProvider(db), query, SortOrder.forName(sortOrder), filter, locale, strict);
|
||||
}
|
||||
|
||||
if (getMusicIdentificationService(db) != null || containsOnly(files, AUDIO_FILES)) {
|
||||
// music mode
|
||||
return renameMusic(files, action, conflictAction, outputDir, format, getMusicIdentificationService(db) == null ? AcoustID : getMusicIdentificationService(db));
|
||||
|
|
|
@ -245,7 +245,7 @@ public class MediaBindingBean {
|
|||
|
||||
if (infoObject instanceof Episode) {
|
||||
// force English series name for TheTVDB data
|
||||
if (WebServices.TheTVDB.getName().equals(getSeriesInfo().getDatabase())) {
|
||||
if (WebServices.TheTVDB.getIdentifier().equals(getSeriesInfo().getDatabase())) {
|
||||
return WebServices.TheTVDB.getSeriesInfo(getSeriesInfo().getId(), Locale.ENGLISH).getName();
|
||||
}
|
||||
|
||||
|
@ -628,7 +628,7 @@ public class MediaBindingBean {
|
|||
|
||||
try {
|
||||
if (infoObject instanceof Episode) {
|
||||
if (WebServices.TheTVDB.getName().equals(getSeriesInfo().getDatabase())) {
|
||||
if (WebServices.TheTVDB.getIdentifier().equals(getSeriesInfo().getDatabase())) {
|
||||
TheTVDBSeriesInfo extendedSeriesInfo = (TheTVDBSeriesInfo) WebServices.TheTVDB.getSeriesInfo(getSeriesInfo().getId(), Locale.ENGLISH);
|
||||
if (extendedSeriesInfo.getImdbId() != null) {
|
||||
metaInfo = WebServices.OMDb.getMovieInfo(new Movie(null, -1, grepImdbId(extendedSeriesInfo.getImdbId()).iterator().next(), -1));
|
||||
|
|
|
@ -15,7 +15,9 @@ import net.filebot.web.SortOrder;
|
|||
|
||||
public class PlainFileMatcher implements Datasource, AutoCompleteMatcher {
|
||||
|
||||
public static final PlainFileMatcher INSTANCE = new PlainFileMatcher();
|
||||
public static PlainFileMatcher getInstance() {
|
||||
return new PlainFileMatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
|
|
@ -39,7 +39,7 @@ public class Preset {
|
|||
this.path = path == null ? null : path.getPath();
|
||||
this.includes = includes == null ? null : includes.getExpression();
|
||||
this.format = format == null ? null : format.getExpression();
|
||||
this.database = database == null ? null : database.getName();
|
||||
this.database = database == null ? null : database.getIdentifier();
|
||||
this.sortOrder = sortOrder == null ? null : sortOrder.name();
|
||||
this.matchMode = matchMode == null ? null : matchMode;
|
||||
this.language = language == null ? null : language.getCode();
|
||||
|
@ -104,8 +104,8 @@ public class Preset {
|
|||
if (adb != null) {
|
||||
return new AudioFingerprintMatcher(adb);
|
||||
}
|
||||
if (PlainFileMatcher.INSTANCE.getName().equals(database)) {
|
||||
return PlainFileMatcher.INSTANCE;
|
||||
if (PlainFileMatcher.getInstance().getIdentifier().equals(database)) {
|
||||
return PlainFileMatcher.getInstance();
|
||||
}
|
||||
throw new IllegalStateException(database);
|
||||
}
|
||||
|
@ -114,20 +114,20 @@ public class Preset {
|
|||
if (database == null || database.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
EpisodeListProvider sdb = WebServices.getEpisodeListProvider(database);
|
||||
if (sdb != null) {
|
||||
return sdb;
|
||||
}
|
||||
MovieIdentificationService mdb = WebServices.getMovieIdentificationService(database);
|
||||
if (mdb != null) {
|
||||
return mdb;
|
||||
}
|
||||
EpisodeListProvider sdb = WebServices.getEpisodeListProvider(database);
|
||||
if (sdb != null) {
|
||||
return sdb;
|
||||
}
|
||||
MusicIdentificationService adb = WebServices.getMusicIdentificationService(database);
|
||||
if (adb != null) {
|
||||
return adb;
|
||||
}
|
||||
if (PlainFileMatcher.INSTANCE.getName().equals(database)) {
|
||||
return PlainFileMatcher.INSTANCE;
|
||||
if (PlainFileMatcher.getInstance().getIdentifier().equals(database)) {
|
||||
return PlainFileMatcher.getInstance();
|
||||
}
|
||||
throw new IllegalStateException(database);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,11 @@ import javax.swing.ListCellRenderer;
|
|||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
|
||||
import net.filebot.Language;
|
||||
import net.filebot.RenameAction;
|
||||
import net.filebot.ResourceManager;
|
||||
|
@ -50,11 +55,6 @@ import net.filebot.web.MovieIdentificationService;
|
|||
import net.filebot.web.SortOrder;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
|
||||
public class PresetEditor extends JDialog {
|
||||
|
||||
enum Result {
|
||||
|
@ -154,7 +154,7 @@ public class PresetEditor extends JDialog {
|
|||
boolean input = selectRadio.isSelected();
|
||||
|
||||
inputPanel.setVisible(input);
|
||||
sortOrderCombo.setEnabled(ds instanceof EpisodeListProvider && ((EpisodeListProvider) ds).hasSeasonSupport());
|
||||
sortOrderCombo.setEnabled(ds instanceof EpisodeListProvider);
|
||||
languageCombo.setEnabled(ds instanceof EpisodeListProvider || ds instanceof MovieIdentificationService);
|
||||
matchModeCombo.setEnabled(ds instanceof EpisodeListProvider || ds instanceof MovieIdentificationService);
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ public class PresetEditor extends JDialog {
|
|||
providers.addElement(it);
|
||||
}
|
||||
}
|
||||
providers.addElement(PlainFileMatcher.INSTANCE);
|
||||
providers.addElement(PlainFileMatcher.getInstance());
|
||||
|
||||
JComboBox<Datasource> combo = new JComboBox<Datasource>(providers);
|
||||
combo.setRenderer(new ListCellRenderer<Object>() {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class AnidbClient extends AbstractEpisodeListProvider {
|
|||
Document dom = getDocument(url);
|
||||
|
||||
// parse series info
|
||||
SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, anime.getId());
|
||||
SeriesInfo seriesInfo = new SeriesInfo(this, sortOrder, locale, anime.getId());
|
||||
seriesInfo.setAliasNames(anime.getAliasNames());
|
||||
|
||||
// AniDB types: Movie, Music Video, Other, OVA, TV Series, TV Special, Web, unknown
|
||||
|
|
|
@ -8,4 +8,8 @@ public interface Datasource {
|
|||
|
||||
Icon getIcon();
|
||||
|
||||
default String getIdentifier() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ public class SeriesInfo implements Serializable {
|
|||
this.status = other.status;
|
||||
}
|
||||
|
||||
public SeriesInfo(String database, SortOrder order, Locale language, Integer id) {
|
||||
this.database = database;
|
||||
public SeriesInfo(Datasource database, SortOrder order, Locale language, Integer id) {
|
||||
this.database = database.getIdentifier();
|
||||
this.order = order.name();
|
||||
this.language = language.getLanguage();
|
||||
this.id = id;
|
||||
|
|
|
@ -7,7 +7,6 @@ import static net.filebot.CachedResource.*;
|
|||
import static net.filebot.Logging.*;
|
||||
import static net.filebot.util.JsonUtilities.*;
|
||||
import static net.filebot.util.StringUtilities.*;
|
||||
import static net.filebot.web.EpisodeUtilities.*;
|
||||
import static net.filebot.web.WebRequest.*;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -41,13 +40,13 @@ import net.filebot.ResourceManager;
|
|||
import net.filebot.web.TMDbClient.MovieInfo.MovieProperty;
|
||||
import net.filebot.web.TMDbClient.Person.PersonProperty;
|
||||
|
||||
public class TMDbClient extends AbstractEpisodeListProvider implements MovieIdentificationService {
|
||||
public class TMDbClient implements MovieIdentificationService {
|
||||
|
||||
private static final String host = "api.themoviedb.org";
|
||||
private static final String version = "3";
|
||||
|
||||
private static final FloodLimit SEARCH_LIMIT = new FloodLimit(10, 10, TimeUnit.SECONDS);
|
||||
private static final FloodLimit REQUEST_LIMIT = new FloodLimit(20, 10, TimeUnit.SECONDS);
|
||||
protected static final FloodLimit SEARCH_LIMIT = new FloodLimit(10, 10, TimeUnit.SECONDS);
|
||||
protected static final FloodLimit REQUEST_LIMIT = new FloodLimit(20, 10, TimeUnit.SECONDS);
|
||||
|
||||
private final String apikey;
|
||||
|
||||
|
@ -65,7 +64,7 @@ public class TMDbClient extends AbstractEpisodeListProvider implements MovieIden
|
|||
return ResourceManager.getIcon("search.themoviedb");
|
||||
}
|
||||
|
||||
private Matcher getNameYearMatcher(String query) {
|
||||
protected Matcher getNameYearMatcher(String query) {
|
||||
return Pattern.compile("(.+)\\b[(]?((?:19|20)\\d{2})[)]?$").matcher(query.trim());
|
||||
}
|
||||
|
||||
|
@ -116,7 +115,7 @@ public class TMDbClient extends AbstractEpisodeListProvider implements MovieIden
|
|||
}).filter(Objects::nonNull).collect(toList());
|
||||
}
|
||||
|
||||
private Set<String> getAlternativeTitles(String path, String key, String title, String originalTitle, boolean extendedInfo) {
|
||||
protected Set<String> getAlternativeTitles(String path, String key, String title, String originalTitle, boolean extendedInfo) {
|
||||
Set<String> alternativeTitles = new LinkedHashSet<String>();
|
||||
if (originalTitle != null) {
|
||||
alternativeTitles.add(originalTitle);
|
||||
|
@ -301,7 +300,7 @@ public class TMDbClient extends AbstractEpisodeListProvider implements MovieIden
|
|||
}).collect(toList());
|
||||
}
|
||||
|
||||
public Object request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws Exception {
|
||||
protected Object request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws Exception {
|
||||
// default parameters
|
||||
String key = parameters.isEmpty() ? resource : resource + '?' + encodeParameters(parameters, true);
|
||||
String cacheName = locale.getLanguage().isEmpty() ? getName() : getName() + "_" + locale;
|
||||
|
@ -726,107 +725,4 @@ public class TMDbClient extends AbstractEpisodeListProvider implements MovieIden
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SortOrder vetoRequestParameter(SortOrder order) {
|
||||
return SortOrder.Airdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getEpisodeListLink(SearchResult searchResult) {
|
||||
return URI.create("https://www.themoviedb.org/tv/" + searchResult.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
|
||||
// query by name with year filter if possible
|
||||
Matcher nameYear = getNameYearMatcher(query);
|
||||
if (nameYear.matches()) {
|
||||
return searchTV(nameYear.group(1).trim(), Integer.parseInt(nameYear.group(2)), locale, true);
|
||||
} else {
|
||||
return searchTV(query.trim(), -1, locale, true);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SearchResult> searchTV(String seriesName, int startYear, Locale locale, boolean extendedInfo) throws Exception {
|
||||
Map<String, Object> query = new LinkedHashMap<String, Object>(2);
|
||||
query.put("query", seriesName);
|
||||
if (startYear > 0) {
|
||||
query.put("first_air_date_year", startYear);
|
||||
}
|
||||
Object response = request("search/tv", query, locale, SEARCH_LIMIT);
|
||||
|
||||
return streamJsonObjects(response, "results").map(it -> {
|
||||
Integer id = getInteger(it, "id");
|
||||
String name = getString(it, "name");
|
||||
String originalName = getString(it, "original_name");
|
||||
|
||||
if (name == null) {
|
||||
name = originalName;
|
||||
}
|
||||
|
||||
if (id == null || name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> alternativeTitles = getAlternativeTitles("tv/" + id, "results", name, originalName, extendedInfo);
|
||||
|
||||
return new SearchResult(id, name, alternativeTitles);
|
||||
}).filter(Objects::nonNull).collect(toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SeriesData fetchSeriesData(SearchResult series, SortOrder sortOrder, Locale locale) throws Exception {
|
||||
// http://api.themoviedb.org/3/tv/id
|
||||
Object tv = request("tv/" + series.getId(), emptyMap(), locale, REQUEST_LIMIT);
|
||||
|
||||
SeriesInfo info = new SeriesInfo(getName(), sortOrder, locale, series.getId());
|
||||
info.setName(Stream.of("original_name", "name").map(key -> getString(tv, key)).filter(Objects::nonNull).findFirst().orElse(series.getName()));
|
||||
info.setAliasNames(series.getAliasNames());
|
||||
info.setStatus(getString(tv, "status"));
|
||||
info.setLanguage(getString(tv, "original_language"));
|
||||
info.setStartDate(getStringValue(tv, "first_air_date", SimpleDate::parse));
|
||||
info.setRating(getStringValue(tv, "vote_average", Double::new));
|
||||
info.setRatingCount(getStringValue(tv, "vote_count", Integer::new));
|
||||
info.setRuntime(stream(getArray(tv, "episode_run_time")).map(Object::toString).map(Integer::new).findFirst().orElse(null));
|
||||
info.setGenres(streamJsonObjects(tv, "genres").map(it -> getString(it, "name")).collect(toList()));
|
||||
info.setNetwork(streamJsonObjects(tv, "networks").map(it -> getString(it, "name")).findFirst().orElse(null));
|
||||
|
||||
int[] seasons = streamJsonObjects(tv, "seasons").mapToInt(it -> getInteger(it, "season_number")).toArray();
|
||||
List<Episode> episodes = new ArrayList<Episode>();
|
||||
List<Episode> specials = new ArrayList<Episode>();
|
||||
|
||||
for (int s : seasons) {
|
||||
// http://api.themoviedb.org/3/tv/id/season/season_number
|
||||
Object season = request("tv/" + series.getId() + "/season/" + s, emptyMap(), locale, REQUEST_LIMIT);
|
||||
|
||||
streamJsonObjects(season, "episodes").forEach(episode -> {
|
||||
Integer episodeNumber = getInteger(episode, "episode_number");
|
||||
Integer seasonNumber = getInteger(episode, "season_number");
|
||||
String episodeTitle = getString(episode, "name");
|
||||
SimpleDate airdate = getStringValue(episode, "air_date", SimpleDate::parse);
|
||||
|
||||
Integer absoluteNumber = episodes.size() + 1;
|
||||
|
||||
if (s > 0) {
|
||||
episodes.add(new Episode(series.getName(), seasonNumber, episodeNumber, episodeTitle, absoluteNumber, null, airdate, info));
|
||||
} else {
|
||||
specials.add(new Episode(series.getName(), null, null, episodeTitle, null, episodeNumber, airdate, info));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// episodes my not be ordered by DVD episode number
|
||||
episodes.sort(episodeComparator());
|
||||
|
||||
// add specials at the end
|
||||
episodes.addAll(specials);
|
||||
|
||||
return new SeriesData(info, episodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package net.filebot.web;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.util.JsonUtilities.*;
|
||||
import static net.filebot.web.EpisodeUtilities.*;
|
||||
import static net.filebot.web.TMDbClient.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
public class TMDbTVClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private final TMDbClient tmdb;
|
||||
|
||||
public TMDbTVClient(TMDbClient tmdb) {
|
||||
this.tmdb = tmdb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return tmdb.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "TheMovieDB::TV";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return tmdb.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SortOrder vetoRequestParameter(SortOrder order) {
|
||||
return SortOrder.Airdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getEpisodeListLink(SearchResult searchResult) {
|
||||
return URI.create("https://www.themoviedb.org/tv/" + searchResult.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
|
||||
// query by name with year filter if possible
|
||||
Matcher nameYear = tmdb.getNameYearMatcher(query);
|
||||
if (nameYear.matches()) {
|
||||
return searchTV(nameYear.group(1).trim(), Integer.parseInt(nameYear.group(2)), locale, true);
|
||||
} else {
|
||||
return searchTV(query.trim(), -1, locale, true);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SearchResult> searchTV(String seriesName, int startYear, Locale locale, boolean extendedInfo) throws Exception {
|
||||
Map<String, Object> query = new LinkedHashMap<String, Object>(2);
|
||||
query.put("query", seriesName);
|
||||
if (startYear > 0) {
|
||||
query.put("first_air_date_year", startYear);
|
||||
}
|
||||
Object response = tmdb.request("search/tv", query, locale, SEARCH_LIMIT);
|
||||
|
||||
return streamJsonObjects(response, "results").map(it -> {
|
||||
Integer id = getInteger(it, "id");
|
||||
String name = getString(it, "name");
|
||||
String originalName = getString(it, "original_name");
|
||||
|
||||
if (name == null) {
|
||||
name = originalName;
|
||||
}
|
||||
|
||||
if (id == null || name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> alternativeTitles = tmdb.getAlternativeTitles("tv/" + id, "results", name, originalName, extendedInfo);
|
||||
|
||||
return new SearchResult(id, name, alternativeTitles);
|
||||
}).filter(Objects::nonNull).collect(toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SeriesData fetchSeriesData(SearchResult series, SortOrder sortOrder, Locale locale) throws Exception {
|
||||
// http://api.themoviedb.org/3/tv/id
|
||||
Object tv = tmdb.request("tv/" + series.getId(), emptyMap(), locale, REQUEST_LIMIT);
|
||||
|
||||
SeriesInfo info = new SeriesInfo(this, sortOrder, locale, series.getId());
|
||||
info.setName(Stream.of("original_name", "name").map(key -> getString(tv, key)).filter(Objects::nonNull).findFirst().orElse(series.getName()));
|
||||
info.setAliasNames(series.getAliasNames());
|
||||
info.setStatus(getString(tv, "status"));
|
||||
info.setLanguage(getString(tv, "original_language"));
|
||||
info.setStartDate(getStringValue(tv, "first_air_date", SimpleDate::parse));
|
||||
info.setRating(getStringValue(tv, "vote_average", Double::new));
|
||||
info.setRatingCount(getStringValue(tv, "vote_count", Integer::new));
|
||||
info.setRuntime(stream(getArray(tv, "episode_run_time")).map(Object::toString).map(Integer::new).findFirst().orElse(null));
|
||||
info.setGenres(streamJsonObjects(tv, "genres").map(it -> getString(it, "name")).collect(toList()));
|
||||
info.setNetwork(streamJsonObjects(tv, "networks").map(it -> getString(it, "name")).findFirst().orElse(null));
|
||||
|
||||
int[] seasons = streamJsonObjects(tv, "seasons").mapToInt(it -> getInteger(it, "season_number")).toArray();
|
||||
List<Episode> episodes = new ArrayList<Episode>();
|
||||
List<Episode> specials = new ArrayList<Episode>();
|
||||
|
||||
for (int s : seasons) {
|
||||
// http://api.themoviedb.org/3/tv/id/season/season_number
|
||||
Object season = tmdb.request("tv/" + series.getId() + "/season/" + s, emptyMap(), locale, REQUEST_LIMIT);
|
||||
|
||||
streamJsonObjects(season, "episodes").forEach(episode -> {
|
||||
Integer episodeNumber = getInteger(episode, "episode_number");
|
||||
Integer seasonNumber = getInteger(episode, "season_number");
|
||||
String episodeTitle = getString(episode, "name");
|
||||
SimpleDate airdate = getStringValue(episode, "air_date", SimpleDate::parse);
|
||||
|
||||
Integer absoluteNumber = episodes.size() + 1;
|
||||
|
||||
if (s > 0) {
|
||||
episodes.add(new Episode(series.getName(), seasonNumber, episodeNumber, episodeTitle, absoluteNumber, null, airdate, info));
|
||||
} else {
|
||||
specials.add(new Episode(series.getName(), null, null, episodeTitle, null, episodeNumber, airdate, info));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// episodes my not be ordered by DVD episode number
|
||||
episodes.sort(episodeComparator());
|
||||
|
||||
// add specials at the end
|
||||
episodes.addAll(specials);
|
||||
|
||||
return new SeriesData(info, episodes);
|
||||
}
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ public class TVMazeClient extends AbstractEpisodeListProvider {
|
|||
Object[] genres = getArray(response, "genres");
|
||||
Double rating = getStringValue(getMap(response, "rating"), "average", Double::new);
|
||||
|
||||
SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, show.getId());
|
||||
SeriesInfo seriesInfo = new SeriesInfo(this, sortOrder, locale, show.getId());
|
||||
seriesInfo.setName(show.getName());
|
||||
seriesInfo.setAliasNames(show.getAliasNames());
|
||||
seriesInfo.setStatus(status);
|
||||
|
|
|
@ -121,7 +121,7 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
|
|||
|
||||
// parse series info
|
||||
Node seriesNode = selectNode("Data/Series", dom);
|
||||
TheTVDBSeriesInfo seriesInfo = new TheTVDBSeriesInfo(getName(), sortOrder, locale, series.getId());
|
||||
TheTVDBSeriesInfo seriesInfo = new TheTVDBSeriesInfo(this, sortOrder, locale, series.getId());
|
||||
seriesInfo.setAliasNames(series.getAliasNames());
|
||||
|
||||
seriesInfo.setName(getTextContent("SeriesName", seriesNode));
|
||||
|
|
|
@ -17,7 +17,7 @@ public class TheTVDBSeriesInfo extends SeriesInfo implements Serializable {
|
|||
protected String posterUrl;
|
||||
|
||||
protected TheTVDBSeriesInfo() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
public TheTVDBSeriesInfo(TheTVDBSeriesInfo other) {
|
||||
|
@ -31,7 +31,7 @@ public class TheTVDBSeriesInfo extends SeriesInfo implements Serializable {
|
|||
this.posterUrl = other.posterUrl;
|
||||
}
|
||||
|
||||
public TheTVDBSeriesInfo(String database, SortOrder order, Locale language, Integer id) {
|
||||
public TheTVDBSeriesInfo(Datasource database, SortOrder order, Locale language, Integer id) {
|
||||
super(database, order, language, id);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import net.filebot.web.TMDbClient.MovieInfo;
|
|||
|
||||
public class TMDbClientTest {
|
||||
|
||||
static TMDbClient tmdb = new TMDbClient("66308fb6e3fd850dde4c7d21df2e8306");
|
||||
TMDbClient tmdb = new TMDbClient("66308fb6e3fd850dde4c7d21df2e8306");
|
||||
|
||||
@Test
|
||||
public void searchByName() throws Exception {
|
||||
|
@ -94,62 +94,6 @@ public class TMDbClientTest {
|
|||
assertEquals("https://image.tmdb.org/t/p/original/ac0HwGJIU3GxjjGujlIjLJmAGPR.jpg", artwork.get(0).getUrl().toString());
|
||||
}
|
||||
|
||||
SearchResult buffy = new SearchResult(95, "Buffy the Vampire Slayer");
|
||||
SearchResult wonderfalls = new SearchResult(1982, "Wonderfalls");
|
||||
SearchResult firefly = new SearchResult(1437, "Firefly");
|
||||
|
||||
@Test
|
||||
public void search() throws Exception {
|
||||
// test default language and query escaping (blanks)
|
||||
List<SearchResult> results = tmdb.search("babylon 5", Locale.ENGLISH);
|
||||
|
||||
assertEquals(1, results.size());
|
||||
|
||||
assertEquals("Babylon 5", results.get(0).getName());
|
||||
assertEquals(3137, results.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListAll() throws Exception {
|
||||
List<Episode> list = tmdb.getEpisodeList(buffy, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
assertTrue(list.size() >= 144);
|
||||
|
||||
// check ordinary episode
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Buffy the Vampire Slayer", first.getSeriesName());
|
||||
assertEquals("1997-03-10", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("1997-03-10", first.getAirdate().toString());
|
||||
|
||||
// check special episode
|
||||
Episode last = list.get(list.size() - 1);
|
||||
assertEquals("Buffy the Vampire Slayer", last.getSeriesName());
|
||||
assertEquals("Unaired Buffy the Vampire Slayer pilot", last.getTitle());
|
||||
assertEquals(null, last.getSeason());
|
||||
assertEquals(null, last.getEpisode());
|
||||
assertEquals(null, last.getAbsolute());
|
||||
assertEquals("1", last.getSpecial().toString());
|
||||
assertEquals(null, last.getAirdate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListSingleSeason() throws Exception {
|
||||
List<Episode> list = tmdb.getEpisodeList(wonderfalls, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Wonderfalls", first.getSeriesName());
|
||||
assertEquals("2004-03-12", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Wax Lion", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("2004-03-12", first.getAirdate().toString());
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void floodLimit() throws Exception {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package net.filebot.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TMDbTVClientTest {
|
||||
|
||||
TMDbTVClient tmdb = new TMDbTVClient(new TMDbClient("66308fb6e3fd850dde4c7d21df2e8306"));
|
||||
|
||||
SearchResult buffy = new SearchResult(95, "Buffy the Vampire Slayer");
|
||||
SearchResult wonderfalls = new SearchResult(1982, "Wonderfalls");
|
||||
SearchResult firefly = new SearchResult(1437, "Firefly");
|
||||
|
||||
@Test
|
||||
public void search() throws Exception {
|
||||
// test default language and query escaping (blanks)
|
||||
List<SearchResult> results = tmdb.search("babylon 5", Locale.ENGLISH);
|
||||
|
||||
assertEquals(1, results.size());
|
||||
|
||||
assertEquals("Babylon 5", results.get(0).getName());
|
||||
assertEquals(3137, results.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListAll() throws Exception {
|
||||
List<Episode> list = tmdb.getEpisodeList(buffy, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
assertTrue(list.size() >= 144);
|
||||
|
||||
// check ordinary episode
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Buffy the Vampire Slayer", first.getSeriesName());
|
||||
assertEquals("1997-03-10", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("1997-03-10", first.getAirdate().toString());
|
||||
|
||||
// check special episode
|
||||
Episode last = list.get(list.size() - 1);
|
||||
assertEquals("Buffy the Vampire Slayer", last.getSeriesName());
|
||||
assertEquals("Unaired Buffy the Vampire Slayer pilot", last.getTitle());
|
||||
assertEquals(null, last.getSeason());
|
||||
assertEquals(null, last.getEpisode());
|
||||
assertEquals(null, last.getAbsolute());
|
||||
assertEquals("1", last.getSpecial().toString());
|
||||
assertEquals(null, last.getAirdate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListSingleSeason() throws Exception {
|
||||
List<Episode> list = tmdb.getEpisodeList(wonderfalls, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Wonderfalls", first.getSeriesName());
|
||||
assertEquals("2004-03-12", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Wax Lion", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("2004-03-12", first.getAirdate().toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@ import org.junit.runners.Suite;
|
|||
import org.junit.runners.Suite.SuiteClasses;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ SimpleDateTest.class, AnidbClientTest.class, TheTVDBClientTest.class, TVMazeClientTest.class, TMDbClientTest.class, OMDbClientTest.class, OpenSubtitlesXmlRpcTest.class, AcoustIDClientTest.class })
|
||||
@SuiteClasses({ SimpleDateTest.class, AnidbClientTest.class, TheTVDBClientTest.class, TVMazeClientTest.class, TMDbClientTest.class, TMDbTVClientTest.class, OMDbClientTest.class, OpenSubtitlesXmlRpcTest.class, AcoustIDClientTest.class })
|
||||
public class WebTestSuite {
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue