+ added initial support for episode formatting language preferences
(preferred language will be ignored if data-source doesn't support multiple languages)
This commit is contained in:
parent
38bbaaf5d8
commit
949b1ce864
Binary file not shown.
After Width: | Height: | Size: 947 B |
|
@ -1,5 +1,5 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import java.util.Comparator;
|
|
@ -4,11 +4,12 @@ package net.sourceforge.filebot.ui.panel.rename;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.sourceforge.filebot.similarity.Match;
|
||||
|
||||
|
||||
interface AutoCompleteMatcher {
|
||||
|
||||
List<Match<File, ?>> match(List<File> files) throws Exception;
|
||||
List<Match<File, ?>> match(List<File> files, Locale locale) throws Exception;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Comparator;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
@ -91,6 +92,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
|
||||
selectDialog.getHeaderLabel().setText(String.format("Shows matching '%s':", query));
|
||||
selectDialog.getCancelAction().putValue(Action.NAME, "Ignore");
|
||||
selectDialog.pack();
|
||||
|
||||
// show dialog
|
||||
selectDialog.setLocation(getOffsetLocation(selectDialog.getOwner()));
|
||||
|
@ -111,7 +113,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
}
|
||||
|
||||
|
||||
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames) throws Exception {
|
||||
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames, final Locale locale) throws Exception {
|
||||
List<Callable<List<Episode>>> tasks = new ArrayList<Callable<List<Episode>>>();
|
||||
|
||||
// detect series names and create episode list fetch tasks
|
||||
|
@ -120,14 +122,14 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
|
||||
@Override
|
||||
public List<Episode> call() throws Exception {
|
||||
List<SearchResult> results = provider.search(query);
|
||||
List<SearchResult> results = provider.search(query, locale);
|
||||
|
||||
// select search result
|
||||
if (results.size() > 0) {
|
||||
SearchResult selectedSearchResult = selectSearchResult(query, results);
|
||||
|
||||
if (selectedSearchResult != null) {
|
||||
return provider.getEpisodeList(selectedSearchResult);
|
||||
return provider.getEpisodeList(selectedSearchResult, locale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,12 +159,12 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Match<File, ?>> match(final List<File> files) throws Exception {
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale) throws Exception {
|
||||
// focus on movie and subtitle files
|
||||
List<File> mediaFiles = FileUtilities.filter(files, VIDEO_FILES, SUBTITLE_FILES);
|
||||
|
||||
// detect series name and fetch episode list
|
||||
Set<Episode> episodes = fetchEpisodeSet(detectSeriesNames(mediaFiles));
|
||||
Set<Episode> episodes = fetchEpisodeSet(detectSeriesNames(mediaFiles), locale);
|
||||
|
||||
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Comparator;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
@ -44,7 +45,7 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Match<File, ?>> match(final List<File> files) throws Exception {
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale) throws Exception {
|
||||
// handle movie files
|
||||
File[] movieFiles = filter(files, VIDEO_FILES).toArray(new File[0]);
|
||||
MovieDescriptor[] movieDescriptors = service.getMovieDescriptors(movieFiles);
|
||||
|
|
|
@ -2,29 +2,38 @@
|
|||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static javax.swing.JOptionPane.*;
|
||||
import static javax.swing.SwingUtilities.*;
|
||||
import static net.sourceforge.filebot.Settings.*;
|
||||
import static net.sourceforge.tuned.ui.LoadingOverlayPane.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import ca.odell.glazedlists.ListSelection;
|
||||
|
@ -35,6 +44,7 @@ import net.sourceforge.filebot.ResourceManager;
|
|||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.WebServices;
|
||||
import net.sourceforge.filebot.similarity.Match;
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
import net.sourceforge.filebot.ui.panel.rename.RenameModel.FormattedFuture;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
import net.sourceforge.filebot.web.EpisodeListProvider;
|
||||
|
@ -61,6 +71,7 @@ public class RenamePanel extends JComponent {
|
|||
|
||||
private static final PreferencesEntry<String> persistentPreserveExtension = Settings.forPackage(RenamePanel.class).entry("rename.extension.preserve").defaultValue("true");
|
||||
private static final PreferencesEntry<String> persistentFormatExpression = Settings.forPackage(RenamePanel.class).entry("rename.format");
|
||||
private static final PreferencesEntry<String> persistentPreferredLanguage = Settings.forPackage(RenamePanel.class).entry("rename.language").defaultValue("en");
|
||||
|
||||
|
||||
public RenamePanel() {
|
||||
|
@ -161,7 +172,7 @@ public class RenamePanel extends JComponent {
|
|||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
EpisodeFormatDialog dialog = new EpisodeFormatDialog(SwingUtilities.getWindowAncestor(RenamePanel.this));
|
||||
EpisodeFormatDialog dialog = new EpisodeFormatDialog(getWindowAncestor(RenamePanel.this));
|
||||
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
|
||||
dialog.setVisible(true);
|
||||
|
||||
|
@ -178,6 +189,51 @@ public class RenamePanel extends JComponent {
|
|||
}
|
||||
});
|
||||
|
||||
actionPopup.add(new AbstractAction("Preferences", ResourceManager.getIcon("action.preferences")) {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
List<Language> languages = new LinkedList<Language>();
|
||||
|
||||
// all languages
|
||||
Language[] availableLanguages = Language.availableLanguages();
|
||||
Arrays.sort(availableLanguages, Language.ALPHABETIC_ORDER);
|
||||
Collections.addAll(languages, availableLanguages);
|
||||
|
||||
// guess preferred language
|
||||
if (!Locale.getDefault().equals(Locale.ENGLISH)) {
|
||||
languages.add(0, Language.getLanguage(Locale.getDefault().getLanguage()));
|
||||
}
|
||||
languages.add(0, Language.getLanguage("en"));
|
||||
|
||||
JList message = new JList(languages.toArray());
|
||||
message.setCellRenderer(new DefaultListCellRenderer() {
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
setIcon(ResourceManager.getFlagIcon(((Language) value).getCode()));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
// pre-select current language preferences
|
||||
for (Language language : languages) {
|
||||
if (language.getCode().equals(persistentPreferredLanguage.getValue())) {
|
||||
message.setSelectedValue(language, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JOptionPane pane = new JOptionPane(new JScrollPane(message), PLAIN_MESSAGE, OK_CANCEL_OPTION);
|
||||
pane.createDialog(getWindowAncestor(RenamePanel.this), "Language Preference").setVisible(true);
|
||||
|
||||
if (pane.getValue() != null && pane.getValue().equals(OK_OPTION)) {
|
||||
persistentPreferredLanguage.setValue(((Language) message.getSelectedValue()).getCode());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return actionPopup;
|
||||
}
|
||||
|
||||
|
@ -292,11 +348,12 @@ public class RenamePanel extends JComponent {
|
|||
SwingWorker<List<Match<File, ?>>, Void> worker = new SwingWorker<List<Match<File, ?>>, Void>() {
|
||||
|
||||
private final List<File> remainingFiles = new LinkedList<File>(renameModel.files());
|
||||
private final Locale locale = new Locale(persistentPreferredLanguage.getValue());
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Match<File, ?>> doInBackground() throws Exception {
|
||||
List<Match<File, ?>> matches = matcher.match(remainingFiles);
|
||||
List<Match<File, ?>> matches = matcher.match(remainingFiles, locale);
|
||||
|
||||
// remove matched files
|
||||
for (Match<File, ?> match : matches) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import javax.swing.border.CompoundBorder;
|
|||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import net.sourceforge.filebot.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
|
||||
|
||||
class LanguageComboBoxCellRenderer implements ListCellRenderer {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import static net.sourceforge.filebot.ui.panel.subtitle.Language.*;
|
||||
import static net.sourceforge.filebot.ui.Language.*;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
|
@ -14,6 +14,8 @@ import java.util.Set;
|
|||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
|
||||
|
||||
class LanguageComboBoxModel extends AbstractListModel implements ComboBoxModel {
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.ResourceBundle;
|
|||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.SwingPropertyChangeSupport;
|
||||
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
import net.sourceforge.tuned.FileUtilities;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.swing.JComboBox;
|
|||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.WebServices;
|
||||
import net.sourceforge.filebot.ui.AbstractSearchPanel;
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
import net.sourceforge.filebot.ui.SelectDialog;
|
||||
import net.sourceforge.filebot.web.SearchResult;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
package net.sourceforge.filebot.web;
|
||||
|
||||
|
||||
import static net.sourceforge.filebot.web.EpisodeListUtilities.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public abstract class AbstractEpisodeListProvider implements EpisodeListProvider {
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasLocaleSupport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws Exception {
|
||||
return search(query, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws Exception {
|
||||
return getEpisodeList(searchResult, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception {
|
||||
return getEpisodeList(searchResult, season, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season, Locale locale) throws Exception {
|
||||
List<Episode> all = getEpisodeList(searchResult, locale);
|
||||
List<Episode> eps = filterBySeason(all, season);
|
||||
|
||||
if (eps.isEmpty()) {
|
||||
throw new SeasonOutOfBoundsException(searchResult.getName(), season, getLastSeason(all));
|
||||
}
|
||||
|
||||
return eps;
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,7 @@ import net.sf.ehcache.Element;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class AnidbClient implements EpisodeListProvider {
|
||||
public class AnidbClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "anidb.net";
|
||||
private static final AnidbCache cache = new AnidbCache(CacheManager.getInstance().getCache("web-persistent-datasource"));
|
||||
|
@ -70,7 +70,19 @@ public class AnidbClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws Exception {
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasLocaleSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query, Locale locale) throws Exception {
|
||||
// normalize
|
||||
query = query.toLowerCase();
|
||||
|
||||
|
@ -123,12 +135,9 @@ public class AnidbClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws Exception {
|
||||
return getEpisodeList((AnidbSearchResult) searchResult, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(AnidbSearchResult anime, Locale language) throws Exception {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale language) throws Exception {
|
||||
AnidbSearchResult anime = (AnidbSearchResult) searchResult;
|
||||
|
||||
// e.g. http://api.anidb.net:9001/httpapi?request=anime&client=filebot&clientver=1&protover=1&aid=4521
|
||||
URL url = new URL("http", "api." + host, 9001, "/httpapi?request=anime&client=" + client + "&clientver=" + clientver + "&protover=1&aid=" + anime.getAnimeId());
|
||||
|
||||
|
@ -141,7 +150,10 @@ public class AnidbClient implements EpisodeListProvider {
|
|||
Document dom = getDocument(url);
|
||||
|
||||
// select main title
|
||||
String animeTitle = selectString("//titles/title[@type='main']", dom);
|
||||
String animeTitle = selectString("//titles/title[@type='official' and @lang='" + language.getLanguage() + "']", dom);
|
||||
if (animeTitle.isEmpty()) {
|
||||
animeTitle = selectString("//titles/title[@type='main']", dom);
|
||||
}
|
||||
|
||||
episodes = new ArrayList<Episode>(25);
|
||||
|
||||
|
@ -151,6 +163,10 @@ public class AnidbClient implements EpisodeListProvider {
|
|||
// ignore special episodes
|
||||
if (number != null) {
|
||||
String title = selectString(".//title[@lang='" + language.getLanguage() + "']", node);
|
||||
if (title.isEmpty()) { // English language fall-back
|
||||
title = selectString(".//title[@lang='en']", node);
|
||||
}
|
||||
|
||||
String airdate = getTextContent("airdate", node);
|
||||
|
||||
// no seasons for anime
|
||||
|
@ -187,13 +203,7 @@ public class AnidbClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season, Locale locale) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,9 @@ public class Date implements Serializable {
|
|||
|
||||
|
||||
public static Date parse(String string, String pattern) {
|
||||
if (string == null || string.isEmpty())
|
||||
return null;
|
||||
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.ROOT);
|
||||
formatter.setLenient(false); // enable strict mode (e.g. fail on invalid dates like 0000-00-00)
|
||||
|
||||
|
|
|
@ -4,33 +4,46 @@ package net.sourceforge.filebot.web;
|
|||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
|
||||
public interface EpisodeListProvider {
|
||||
|
||||
public List<SearchResult> search(String query) throws Exception;
|
||||
public String getName();
|
||||
|
||||
|
||||
public Icon getIcon();
|
||||
|
||||
|
||||
public boolean hasSingleSeasonSupport();
|
||||
|
||||
|
||||
public boolean hasLocaleSupport();
|
||||
|
||||
|
||||
public List<SearchResult> search(String query) throws Exception;
|
||||
|
||||
|
||||
public List<SearchResult> search(String query, Locale locale) throws Exception;
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws Exception;
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception;
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale locale) throws Exception;
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season, Locale locale) throws Exception;
|
||||
|
||||
|
||||
public URI getEpisodeListLink(SearchResult searchResult);
|
||||
|
||||
|
||||
public URI getEpisodeListLink(SearchResult searchResult, int season);
|
||||
|
||||
|
||||
public String getName();
|
||||
|
||||
|
||||
public Icon getIcon();
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
package net.sourceforge.filebot.web;
|
||||
|
||||
|
||||
import static net.sourceforge.filebot.web.EpisodeListUtilities.*;
|
||||
import static net.sourceforge.filebot.web.WebRequest.*;
|
||||
import static net.sourceforge.tuned.XPathUtilities.*;
|
||||
|
||||
|
@ -14,6 +13,7 @@ import java.net.URLConnection;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -27,7 +27,7 @@ import org.xml.sax.SAXException;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class IMDbClient implements EpisodeListProvider {
|
||||
public class IMDbClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "www.imdb.com";
|
||||
|
||||
|
@ -45,13 +45,7 @@ public class IMDbClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws IOException, SAXException {
|
||||
public List<SearchResult> search(String query, Locale locale) throws IOException, SAXException {
|
||||
|
||||
URL searchUrl = new URL("http", host, "/find?s=tt&q=" + URLEncoder.encode(query, "UTF-8"));
|
||||
|
||||
|
@ -87,7 +81,7 @@ public class IMDbClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws IOException, SAXException {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale locale) throws IOException, SAXException {
|
||||
Document dom = getHtmlDocument(openConnection(getEpisodeListLink(searchResult).toURL()));
|
||||
|
||||
String seriesName = normalizeName(selectString("//H1/A", dom));
|
||||
|
@ -113,19 +107,6 @@ public class IMDbClient implements EpisodeListProvider {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception {
|
||||
List<Episode> all = getEpisodeList(searchResult);
|
||||
List<Episode> eps = filterBySeason(all, season);
|
||||
|
||||
if (eps.isEmpty()) {
|
||||
throw new SeasonOutOfBoundsException(searchResult.getName(), season, getLastSeason(all));
|
||||
}
|
||||
|
||||
return eps;
|
||||
}
|
||||
|
||||
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
@ -36,7 +37,7 @@ import net.sf.ehcache.Element;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class SerienjunkiesClient implements EpisodeListProvider {
|
||||
public class SerienjunkiesClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "api.serienjunkies.de";
|
||||
private static final SerienjunkiesCache cache = new SerienjunkiesCache(CacheManager.getInstance().getCache("web-persistent-datasource"));
|
||||
|
@ -62,13 +63,7 @@ public class SerienjunkiesClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws IOException {
|
||||
public List<SearchResult> search(String query, Locale locale) throws IOException {
|
||||
// normalize
|
||||
query = query.toLowerCase();
|
||||
|
||||
|
@ -151,7 +146,7 @@ public class SerienjunkiesClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws IOException {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale locale) throws IOException {
|
||||
SerienjunkiesSearchResult series = (SerienjunkiesSearchResult) searchResult;
|
||||
|
||||
// try cache first
|
||||
|
@ -186,19 +181,6 @@ public class SerienjunkiesClient implements EpisodeListProvider {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException {
|
||||
List<Episode> all = getEpisodeList(searchResult);
|
||||
List<Episode> eps = filterBySeason(all, season);
|
||||
|
||||
if (eps.isEmpty()) {
|
||||
throw new SeasonOutOfBoundsException(searchResult.getName(), season, getLastSeason(all));
|
||||
}
|
||||
|
||||
return eps;
|
||||
}
|
||||
|
||||
|
||||
protected Object request(String resource) throws IOException {
|
||||
URL url = new URL("https", host, resource);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.net.URLEncoder;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -31,7 +32,7 @@ import org.xml.sax.SAXException;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class TVDotComClient implements EpisodeListProvider {
|
||||
public class TVDotComClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "www.tv.com";
|
||||
|
||||
|
@ -49,14 +50,7 @@ public class TVDotComClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws IOException, SAXException {
|
||||
|
||||
public List<SearchResult> search(String query, Locale locale) throws IOException, SAXException {
|
||||
// use ajax search request, because we don't need the whole search result page
|
||||
URL searchUrl = new URL("http", host, "/search.php?type=Search&stype=ajax_search&search_type=program&qs=" + URLEncoder.encode(query, "UTF-8"));
|
||||
|
||||
|
@ -81,8 +75,7 @@ public class TVDotComClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(final SearchResult searchResult) throws Exception {
|
||||
|
||||
public List<Episode> getEpisodeList(final SearchResult searchResult, final Locale locale) throws Exception {
|
||||
// get document for season 1
|
||||
Document dom = getHtmlDocument(getEpisodeListLink(searchResult, 1).toURL());
|
||||
|
||||
|
@ -113,7 +106,7 @@ public class TVDotComClient implements EpisodeListProvider {
|
|||
|
||||
@Override
|
||||
public List<Episode> call() throws Exception {
|
||||
return getEpisodeList(searchResult, season);
|
||||
return getEpisodeList(searchResult, season, locale);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -137,9 +130,8 @@ public class TVDotComClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season, Locale locale) throws IOException, SAXException {
|
||||
Document dom = getHtmlDocument(getEpisodeListLink(searchResult, season).toURL());
|
||||
|
||||
return getEpisodeList(searchResult, dom);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ import java.net.URL;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
@ -23,7 +23,7 @@ import org.xml.sax.SAXException;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class TVRageClient implements EpisodeListProvider {
|
||||
public class TVRageClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "services.tvrage.com";
|
||||
|
||||
|
@ -41,13 +41,7 @@ public class TVRageClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean hasSingleSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws SAXException, IOException, ParserConfigurationException {
|
||||
public List<SearchResult> search(String query, Locale locale) throws IOException, SAXException {
|
||||
|
||||
URL searchUrl = new URL("http", host, "/feeds/full_search.php?show=" + URLEncoder.encode(query, "UTF-8"));
|
||||
|
||||
|
@ -70,7 +64,7 @@ public class TVRageClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws IOException, SAXException, ParserConfigurationException {
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale locale) throws IOException, SAXException {
|
||||
int showId = ((TVRageSearchResult) searchResult).getShowId();
|
||||
|
||||
URL episodeListUrl = new URL("http", host, "/feeds/episode_list.php?sid=" + showId);
|
||||
|
@ -110,19 +104,6 @@ public class TVRageClient implements EpisodeListProvider {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException {
|
||||
List<Episode> all = getEpisodeList(searchResult);
|
||||
List<Episode> eps = filterBySeason(all, season);
|
||||
|
||||
if (eps.isEmpty()) {
|
||||
throw new SeasonOutOfBoundsException(searchResult.getName(), season, getLastSeason(all));
|
||||
}
|
||||
|
||||
return eps;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public URI getEpisodeListLink(SearchResult searchResult) {
|
||||
return getEpisodeListLink(searchResult, "all");
|
||||
|
|
|
@ -35,7 +35,7 @@ import net.sf.ehcache.Element;
|
|||
import net.sourceforge.filebot.ResourceManager;
|
||||
|
||||
|
||||
public class TheTVDBClient implements EpisodeListProvider {
|
||||
public class TheTVDBClient extends AbstractEpisodeListProvider {
|
||||
|
||||
private static final String host = "www.thetvdb.com";
|
||||
|
||||
|
@ -73,11 +73,12 @@ public class TheTVDBClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query) throws Exception {
|
||||
return search(query, Locale.ENGLISH);
|
||||
public boolean hasLocaleSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(String query, Locale language) throws Exception {
|
||||
// check if the exact series name is already cached
|
||||
Integer cachedResult = cache.getSeriesId(query, language);
|
||||
|
@ -105,31 +106,14 @@ public class TheTVDBClient implements EpisodeListProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult) throws Exception {
|
||||
return getEpisodeList((TheTVDBSearchResult) searchResult, Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception {
|
||||
List<Episode> all = getEpisodeList(searchResult);
|
||||
List<Episode> eps = filterBySeason(all, season);
|
||||
|
||||
if (eps.isEmpty()) {
|
||||
throw new SeasonOutOfBoundsException(searchResult.getName(), season, getLastSeason(all));
|
||||
}
|
||||
|
||||
return eps;
|
||||
}
|
||||
|
||||
|
||||
public List<Episode> getEpisodeList(TheTVDBSearchResult searchResult, Locale language) throws Exception {
|
||||
List<Episode> episodes = cache.getEpisodeList(searchResult.getSeriesId(), language);
|
||||
public List<Episode> getEpisodeList(SearchResult searchResult, Locale language) throws Exception {
|
||||
TheTVDBSearchResult series = (TheTVDBSearchResult) searchResult;
|
||||
List<Episode> episodes = cache.getEpisodeList(series.getSeriesId(), language);
|
||||
|
||||
if (episodes != null)
|
||||
return episodes;
|
||||
|
||||
Document seriesRecord = getSeriesRecord(searchResult, language);
|
||||
Document seriesRecord = getSeriesRecord(series, language);
|
||||
|
||||
// we could get the series name from the search result, but the language may not match the given parameter
|
||||
String seriesName = selectString("Data/Series/SeriesName", seriesRecord);
|
||||
|
@ -176,7 +160,7 @@ public class TheTVDBClient implements EpisodeListProvider {
|
|||
try {
|
||||
// cache seasonId for each season (always when we are at the first episode)
|
||||
// because it might be required by getEpisodeListLink
|
||||
cache.putSeasonId(searchResult.getSeriesId(), seasonNumber, getIntegerContent("seasonid", node));
|
||||
cache.putSeasonId(series.getSeriesId(), seasonNumber, getIntegerContent("seasonid", node));
|
||||
} catch (NumberFormatException e) {
|
||||
// season/episode is not a number, just ignore
|
||||
}
|
||||
|
@ -189,7 +173,7 @@ public class TheTVDBClient implements EpisodeListProvider {
|
|||
// add specials at the end
|
||||
episodes.addAll(specials);
|
||||
|
||||
cache.putEpisodeList(searchResult.getSeriesId(), language, episodes);
|
||||
cache.putEpisodeList(series.getSeriesId(), language, episodes);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class AnidbClientTest {
|
|||
|
||||
Episode first = list.get(0);
|
||||
|
||||
assertEquals("Juuni Kokki", first.getSeriesName());
|
||||
assertEquals("The Twelve Kingdoms", first.getSeriesName());
|
||||
assertEquals("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
|
@ -119,7 +119,7 @@ public class AnidbClientTest {
|
|||
List<Episode> list = anidb.getEpisodeList(monsterSearchResult, Locale.JAPANESE);
|
||||
|
||||
Episode last = list.get(73);
|
||||
assertEquals("Monster", last.getSeriesName());
|
||||
assertEquals("モンスター", last.getSeriesName());
|
||||
assertEquals("本当の怪物", last.getTitle());
|
||||
assertEquals("74", last.getEpisode().toString());
|
||||
assertEquals("74", last.getAbsolute().toString());
|
||||
|
|
|
@ -64,7 +64,7 @@ public class OpenSubtitlesXmlRpcTest {
|
|||
|
||||
OpenSubtitlesSubtitleDescriptor sample = list.get(75);
|
||||
|
||||
assertEquals("\"Wonderfalls\"", sample.getProperty(Property.MovieName));
|
||||
assertEquals("Wonderfalls", sample.getProperty(Property.MovieName));
|
||||
assertEquals("Hungarian", sample.getProperty(Property.LanguageName));
|
||||
assertEquals("imdbid", sample.getProperty(Property.MatchedBy));
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public class TheTVDBClientTest {
|
|||
assertEquals("Unaired Pilot", last.getTitle());
|
||||
assertEquals("1", last.getSeason().toString());
|
||||
assertEquals(null, last.getEpisode());
|
||||
assertEquals("1", last.getAbsolute().toString());
|
||||
assertEquals(null, last.getAbsolute());
|
||||
assertEquals("1", last.getSpecial().toString());
|
||||
assertEquals(null, last.airdate());
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ public class TheTVDBClientTest {
|
|||
public void getEpisodeListSingleSeason() throws Exception {
|
||||
List<Episode> list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Wonderfalls", 78845), 1);
|
||||
|
||||
assertEquals(13, list.size());
|
||||
assertEquals(14, list.size());
|
||||
|
||||
Episode first = list.get(0);
|
||||
|
||||
|
|
Loading…
Reference in New Issue