* switched back to using List as return value for EpisodeList- and SubtitleClients (lazy XPath evaluation not needed anymore, because we are fast enough anyway)
This commit is contained in:
parent
d1775cf1b4
commit
ea6a839aa8
|
@ -8,6 +8,7 @@ import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -30,7 +31,6 @@ import javax.swing.SwingWorker;
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.filebot.web.SearchResult;
|
import net.sourceforge.filebot.web.SearchResult;
|
||||||
import net.sourceforge.tuned.ExceptionUtil;
|
import net.sourceforge.tuned.ExceptionUtil;
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.ui.SelectButtonTextField;
|
import net.sourceforge.tuned.ui.SelectButtonTextField;
|
||||||
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
||||||
import net.sourceforge.tuned.ui.TunedUtil;
|
import net.sourceforge.tuned.ui.TunedUtil;
|
||||||
|
@ -137,7 +137,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
protected abstract class SearchTask extends SwingWorker<List<SearchResult>, Void> {
|
protected abstract class SearchTask extends SwingWorker<Collection<SearchResult>, Void> {
|
||||||
|
|
||||||
private final String searchText;
|
private final String searchText;
|
||||||
private final S client;
|
private final S client;
|
||||||
|
@ -153,7 +153,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected abstract List<SearchResult> doInBackground() throws Exception;
|
protected abstract Collection<SearchResult> doInBackground() throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public String getSearchText() {
|
public String getSearchText() {
|
||||||
|
@ -240,13 +240,13 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
||||||
|
|
||||||
|
|
||||||
private SearchResult selectSearchResult(SearchTask task) throws Exception {
|
private SearchResult selectSearchResult(SearchTask task) throws Exception {
|
||||||
List<SearchResult> searchResults = task.get();
|
Collection<SearchResult> searchResults = task.get();
|
||||||
|
|
||||||
switch (searchResults.size()) {
|
switch (searchResults.size()) {
|
||||||
case 0:
|
case 0:
|
||||||
return null;
|
return null;
|
||||||
case 1:
|
case 1:
|
||||||
return searchResults.get(0);
|
return searchResults.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple results have been found, user must selected one
|
// multiple results have been found, user must selected one
|
||||||
|
@ -288,17 +288,10 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
||||||
protected final Void doInBackground() throws Exception {
|
protected final Void doInBackground() throws Exception {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
ProgressIterator<E> iterator = fetch();
|
Collection<E> results = fetch();
|
||||||
|
|
||||||
while (!isCancelled() && iterator.hasNext()) {
|
for (E result : results) {
|
||||||
|
publish(result);
|
||||||
try {
|
|
||||||
publish(iterator.next());
|
|
||||||
} catch (Exception e) {
|
|
||||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
setProgress((iterator.getPosition() * 100) / iterator.getLength());
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +301,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected abstract ProgressIterator<E> fetch() throws Exception;
|
protected abstract Collection<E> fetch() throws Exception;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,7 @@ class FetchEpisodeListTask extends SwingWorker<List<Episode>, Void> {
|
||||||
protected List<Episode> doInBackground() throws Exception {
|
protected List<Episode> doInBackground() throws Exception {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
Iterator<Episode> itr = searchEngine.getEpisodeList(searchResult, numberOfSeason);
|
Iterator<Episode> itr = searchEngine.getEpisodeList(searchResult, numberOfSeason).iterator();
|
||||||
|
|
||||||
ArrayList<Episode> list = new ArrayList<Episode>();
|
ArrayList<Episode> list = new ArrayList<Episode>();
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import java.beans.PropertyChangeListener;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -185,7 +184,7 @@ public class SearchPanel extends FileBotPanel {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private class SearchTask extends SwingWorker<List<SearchResult>, Void> {
|
private class SearchTask extends SwingWorker<Collection<SearchResult>, Void> {
|
||||||
|
|
||||||
private final String query;
|
private final String query;
|
||||||
private final EpisodeListClient client;
|
private final EpisodeListClient client;
|
||||||
|
@ -200,7 +199,7 @@ public class SearchPanel extends FileBotPanel {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SearchResult> doInBackground() throws Exception {
|
protected Collection<SearchResult> doInBackground() throws Exception {
|
||||||
return client.search(query);
|
return client.search(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +241,7 @@ public class SearchPanel extends FileBotPanel {
|
||||||
|
|
||||||
SearchTask task = (SearchTask) evt.getSource();
|
SearchTask task = (SearchTask) evt.getSource();
|
||||||
|
|
||||||
List<SearchResult> searchResults;
|
Collection<SearchResult> searchResults;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
searchResults = task.get();
|
searchResults = task.get();
|
||||||
|
@ -268,7 +267,7 @@ public class SearchPanel extends FileBotPanel {
|
||||||
|
|
||||||
if (searchResults.size() == 1) {
|
if (searchResults.size() == 1) {
|
||||||
// only one show found, select this one
|
// only one show found, select this one
|
||||||
selectedResult = searchResults.get(0);
|
selectedResult = searchResults.iterator().next();
|
||||||
} else if (searchResults.size() > 1) {
|
} else if (searchResults.size() > 1) {
|
||||||
// multiple shows found, let user selected one
|
// multiple shows found, let user selected one
|
||||||
Window window = SwingUtilities.getWindowAncestor(SearchPanel.this);
|
Window window = SwingUtilities.getWindowAncestor(SearchPanel.this);
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class LanguageResolver {
|
||||||
return defaultInstance;
|
return defaultInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, Locale> localeMap = new HashMap<String, Locale>();
|
private final Map<String, Locale> cache = new HashMap<String, Locale>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,11 +28,11 @@ public class LanguageResolver {
|
||||||
public synchronized Locale getLocale(String languageName) {
|
public synchronized Locale getLocale(String languageName) {
|
||||||
languageName = languageName.toLowerCase();
|
languageName = languageName.toLowerCase();
|
||||||
|
|
||||||
Locale locale = localeMap.get(languageName);
|
Locale locale = cache.get(languageName);
|
||||||
|
|
||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
locale = findLocale(languageName);
|
locale = findLocale(languageName);
|
||||||
localeMap.put(languageName, locale);
|
cache.put(languageName, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
return locale;
|
return locale;
|
||||||
|
|
|
@ -3,7 +3,10 @@ package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import net.sourceforge.filebot.ListChangeSynchronizer;
|
import net.sourceforge.filebot.ListChangeSynchronizer;
|
||||||
import net.sourceforge.filebot.Settings;
|
import net.sourceforge.filebot.Settings;
|
||||||
|
@ -13,9 +16,6 @@ import net.sourceforge.filebot.ui.SelectDialog;
|
||||||
import net.sourceforge.filebot.web.SearchResult;
|
import net.sourceforge.filebot.web.SearchResult;
|
||||||
import net.sourceforge.filebot.web.SubtitleClient;
|
import net.sourceforge.filebot.web.SubtitleClient;
|
||||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||||
import net.sourceforge.tuned.FunctionIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
import net.sourceforge.tuned.ui.SimpleIconProvider;
|
import net.sourceforge.tuned.ui.SimpleIconProvider;
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SearchResult> doInBackground() throws Exception {
|
protected Collection<SearchResult> doInBackground() throws Exception {
|
||||||
return getClient().search(getSearchText());
|
return getClient().search(getSearchText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +87,16 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ProgressIterator<SubtitlePackage> fetch() throws Exception {
|
protected Collection<SubtitlePackage> fetch() throws Exception {
|
||||||
ProgressIterator<SubtitleDescriptor> descriptors = getClient().getSubtitleList(getSearchResult());
|
//TODO language combobox
|
||||||
|
Collection<SubtitleDescriptor> descriptors = getClient().getSubtitleList(getSearchResult(), Locale.ENGLISH);
|
||||||
|
ArrayList<SubtitlePackage> packages = new ArrayList<SubtitlePackage>();
|
||||||
|
|
||||||
return new FunctionIterator<SubtitleDescriptor, SubtitlePackage>(descriptors, new SubtitlePackageFunction());
|
for (SubtitleDescriptor descriptor : descriptors) {
|
||||||
|
packages.add(new SubtitlePackage(descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,14 +115,4 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitlePackageFunction implements Function<SubtitleDescriptor, SubtitlePackage> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubtitlePackage evaluate(SubtitleDescriptor sourceValue) {
|
|
||||||
return new SubtitlePackage(sourceValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,7 @@ import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.tuned.FunctionIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.XPathUtil;
|
import net.sourceforge.tuned.XPathUtil;
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
@ -88,33 +85,19 @@ public class AnidbClient extends EpisodeListClient {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
||||||
|
|
||||||
Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season));
|
Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season));
|
||||||
|
|
||||||
List<Node> nodes = XPathUtil.selectNodes("id('eplist')//TR/TD/SPAN/ancestor::TR", dom);
|
List<Node> nodes = XPathUtil.selectNodes("id('eplist')//TR/TD/SPAN/ancestor::TR", dom);
|
||||||
|
|
||||||
return new FunctionIterator<Node, Episode>(nodes, new EpisodeFunction(searchResult, nodes.size()));
|
NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
|
||||||
}
|
numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodes.size()).length(), 2));
|
||||||
|
numberFormat.setGroupingUsed(false);
|
||||||
|
|
||||||
private static class EpisodeFunction implements Function<Node, Episode> {
|
|
||||||
|
|
||||||
private final SearchResult searchResult;
|
ArrayList<Episode> episodes = new ArrayList<Episode>(nodes.size());
|
||||||
private final NumberFormat numberFormat;
|
|
||||||
|
|
||||||
|
for (Node node : nodes) {
|
||||||
public EpisodeFunction(SearchResult searchResult, int nodeCount) {
|
|
||||||
this.searchResult = searchResult;
|
|
||||||
|
|
||||||
numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
|
|
||||||
numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodeCount).length(), 2));
|
|
||||||
numberFormat.setGroupingUsed(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Episode evaluate(Node node) {
|
|
||||||
String number = XPathUtil.selectString("./TD[contains(@class,'id')]/A", node);
|
String number = XPathUtil.selectString("./TD[contains(@class,'id')]/A", node);
|
||||||
String title = XPathUtil.selectString("./TD[@class='title']/LABEL/text()", node);
|
String title = XPathUtil.selectString("./TD[@class='title']/LABEL/text()", node);
|
||||||
|
|
||||||
|
@ -129,15 +112,16 @@ public class AnidbClient extends EpisodeListClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
// no seasons for anime
|
// no seasons for anime
|
||||||
return new Episode(searchResult.getName(), null, number, title);
|
episodes.add(new Episode(searchResult.getName(), null, number, title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
||||||
return ((HyperLink) searchResult).getUri();
|
return ((HyperLink) searchResult).toUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,12 @@ package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class EpisodeListClient {
|
public abstract class EpisodeListClient {
|
||||||
|
|
||||||
|
@ -41,10 +40,10 @@ public abstract class EpisodeListClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract List<SearchResult> search(String searchterm) throws Exception;
|
public abstract Collection<SearchResult> search(String searchterm) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public abstract ProgressIterator<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception;
|
public abstract Collection<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public abstract URI getEpisodeListLink(SearchResult searchResult, int season);
|
public abstract URI getEpisodeListLink(SearchResult searchResult, int season);
|
||||||
|
|
|
@ -52,8 +52,11 @@ public class HtmlUtil {
|
||||||
|
|
||||||
|
|
||||||
public static Document getHtmlDocument(URL url) throws IOException, SAXException {
|
public static Document getHtmlDocument(URL url) throws IOException, SAXException {
|
||||||
URLConnection connection = url.openConnection();
|
return getHtmlDocument(url.openConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Document getHtmlDocument(URLConnection connection) throws IOException, SAXException {
|
||||||
Charset charset = getCharset(connection.getContentType());
|
Charset charset = getCharset(connection.getContentType());
|
||||||
String encoding = connection.getContentEncoding();
|
String encoding = connection.getContentEncoding();
|
||||||
InputStream inputStream = connection.getInputStream();
|
InputStream inputStream = connection.getInputStream();
|
||||||
|
|
|
@ -8,23 +8,22 @@ import java.net.URL;
|
||||||
|
|
||||||
public class HyperLink extends SearchResult {
|
public class HyperLink extends SearchResult {
|
||||||
|
|
||||||
private final URI uri;
|
private final URL url;
|
||||||
|
|
||||||
|
|
||||||
public HyperLink(String name, URI uri) {
|
|
||||||
super(name);
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public HyperLink(String name, URL url) {
|
public HyperLink(String name, URL url) {
|
||||||
super(name);
|
super(name);
|
||||||
this.uri = URI.create(url.toString());
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public URI getUri() {
|
public URL getUrl() {
|
||||||
return uri;
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public URI toUri() {
|
||||||
|
return URI.create(url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,10 @@ package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -155,20 +157,18 @@ public class OpenSubtitlesClient {
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<OpenSubtitlesSubtitleDescriptor> searchSubtitles(int... imdbidArray) throws XmlRpcFault {
|
public List<OpenSubtitlesSubtitleDescriptor> searchSubtitles(int imdbid, Locale language) throws XmlRpcFault {
|
||||||
|
|
||||||
List<Map<String, String>> imdbidList = new ArrayList<Map<String, String>>(imdbidArray.length);
|
Map<String, String> searchListEntry = new HashMap<String, String>(2);
|
||||||
|
|
||||||
for (int imdbid : imdbidArray) {
|
// pad imdbId with zeros
|
||||||
Map<String, String> map = new HashMap<String, String>(1);
|
//TODO needed???
|
||||||
|
searchListEntry.put("imdbid", String.format("%07d", imdbid));
|
||||||
// pad id with zeros
|
searchListEntry.put("sublanguageid", getSubLanguageID(language));
|
||||||
map.put("imdbid", String.format("%07d", imdbid));
|
|
||||||
|
|
||||||
imdbidList.add(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, List<Map<String, String>>> response = (Map<String, List<Map<String, String>>>) invoke("SearchSubtitles", token, imdbidList);
|
List<Map<String, String>> searchList = Collections.singletonList(searchListEntry);
|
||||||
|
|
||||||
|
Map<String, List<Map<String, String>>> response = (Map<String, List<Map<String, String>>>) invoke("SearchSubtitles", token, searchList);
|
||||||
|
|
||||||
ArrayList<OpenSubtitlesSubtitleDescriptor> subs = new ArrayList<OpenSubtitlesSubtitleDescriptor>();
|
ArrayList<OpenSubtitlesSubtitleDescriptor> subs = new ArrayList<OpenSubtitlesSubtitleDescriptor>();
|
||||||
|
|
||||||
|
@ -184,6 +184,12 @@ public class OpenSubtitlesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String getSubLanguageID(Locale locale) {
|
||||||
|
//TODO test if sublanguageid is really ISO3 language code
|
||||||
|
return locale.getISO3Language();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<MovieDescriptor> searchMoviesOnIMDB(String query) throws XmlRpcFault {
|
public List<MovieDescriptor> searchMoviesOnIMDB(String query) throws XmlRpcFault {
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -11,9 +13,6 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sourceforge.filebot.Settings;
|
import net.sourceforge.filebot.Settings;
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.tuned.FunctionIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,15 +43,14 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<SubtitleDescriptor> getSubtitleList(SearchResult searchResult) throws Exception {
|
public Collection<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, Locale language) throws Exception {
|
||||||
login();
|
login();
|
||||||
|
|
||||||
int imdbId = ((MovieDescriptor) searchResult).getImdbId();
|
int imdbId = ((MovieDescriptor) searchResult).getImdbId();
|
||||||
|
|
||||||
List<OpenSubtitlesSubtitleDescriptor> subtitles = client.searchSubtitles(imdbId);
|
return (Collection) client.searchSubtitles(imdbId, language);
|
||||||
|
|
||||||
return new FunctionIterator<OpenSubtitlesSubtitleDescriptor, SubtitleDescriptor>(subtitles, new SubtitleFunction());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,13 +133,4 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleFunction implements Function<OpenSubtitlesSubtitleDescriptor, SubtitleDescriptor> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubtitleDescriptor evaluate(OpenSubtitlesSubtitleDescriptor sourceValue) {
|
|
||||||
return sourceValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,28 +2,26 @@
|
||||||
package net.sourceforge.filebot.web;
|
package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
|
|
||||||
public class SearchResultCache {
|
public class SearchResultCache {
|
||||||
|
|
||||||
private final Map<String, SearchResult> cache = Collections.synchronizedMap(new TreeMap<String, SearchResult>(String.CASE_INSENSITIVE_ORDER));
|
private final ConcurrentHashMap<String, SearchResult> cache = new ConcurrentHashMap<String, SearchResult>();
|
||||||
|
|
||||||
|
|
||||||
public boolean containsKey(String name) {
|
public boolean containsKey(String name) {
|
||||||
return cache.containsKey(name);
|
return cache.containsKey(key(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SearchResult get(String name) {
|
public SearchResult get(String name) {
|
||||||
return cache.get(name);
|
return cache.get(key(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void add(SearchResult searchResult) {
|
public void add(SearchResult searchResult) {
|
||||||
cache.put(searchResult.getName(), searchResult);
|
cache.putIfAbsent(key(searchResult.getName()), searchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,4 +30,10 @@ public class SearchResultCache {
|
||||||
add(searchResult);
|
add(searchResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String key(String name) {
|
||||||
|
return name.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -18,10 +21,7 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.tuned.FileUtil;
|
import net.sourceforge.tuned.FileUtil;
|
||||||
import net.sourceforge.tuned.FunctionIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.XPathUtil;
|
import net.sourceforge.tuned.XPathUtil;
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
@ -70,69 +70,105 @@ public class SubsceneSubtitleClient extends SubtitleClient {
|
||||||
return searchResults;
|
return searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashMap<String, String> languageIdCache;
|
||||||
|
|
||||||
|
|
||||||
|
public String getLanguageID(Locale language) {
|
||||||
|
return languageIdCache.get(language.getDisplayLanguage(Locale.ENGLISH).toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<SubtitleDescriptor> getSubtitleList(SearchResult searchResult) throws Exception {
|
public List<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, Locale language) throws Exception {
|
||||||
|
|
||||||
URL url = getSubtitleListLink(searchResult).toURL();
|
URL url = getSubtitleListLink(searchResult).toURL();
|
||||||
|
|
||||||
Document dom = HtmlUtil.getHtmlDocument(url);
|
Document dom = null;
|
||||||
|
|
||||||
|
if (languageIdCache != null) {
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
|
||||||
|
if (language != null && language != Locale.ROOT) {
|
||||||
|
System.out.println(getLanguageID(language));
|
||||||
|
connection.addRequestProperty("Cookie", "subscene_sLanguageIds=" + getLanguageID(language));
|
||||||
|
}
|
||||||
|
|
||||||
|
dom = HtmlUtil.getHtmlDocument(connection);
|
||||||
|
} else {
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
|
||||||
|
dom = HtmlUtil.getHtmlDocument(connection);
|
||||||
|
|
||||||
|
List<Node> nodes = XPathUtil.selectNodes("//DIV[@class='languageList']/DIV", dom);
|
||||||
|
|
||||||
|
Pattern onClickPattern = Pattern.compile("selectLanguage\\((\\d+)\\);");
|
||||||
|
|
||||||
|
languageIdCache = new HashMap<String, String>();
|
||||||
|
|
||||||
|
for (Node node : nodes) {
|
||||||
|
Matcher matcher = onClickPattern.matcher(XPathUtil.selectString("./INPUT/@onclick", node));
|
||||||
|
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String name = XPathUtil.selectString("./LABEL/text()", node);
|
||||||
|
String id = matcher.group(1);
|
||||||
|
|
||||||
|
//TODO sysout
|
||||||
|
System.out.println(name + " = " + id);
|
||||||
|
|
||||||
|
languageIdCache.put(name.toLowerCase(), id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<Node> nodes = XPathUtil.selectNodes("//TABLE[@class='filmSubtitleList']//A[@id]//ancestor::TR", dom);
|
List<Node> nodes = XPathUtil.selectNodes("//TABLE[@class='filmSubtitleList']//A[@id]//ancestor::TR", dom);
|
||||||
|
|
||||||
return new FunctionIterator<Node, SubtitleDescriptor>(nodes, new SubtitleFunction(url));
|
Pattern hrefPattern = Pattern.compile("javascript:Subtitle\\((\\d+), '(\\w+)', '\\d+', '(\\d+)'\\);");
|
||||||
|
|
||||||
|
ArrayList<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>(nodes.size());
|
||||||
|
|
||||||
|
for (Node node : nodes) {
|
||||||
|
try {
|
||||||
|
Node linkNode = XPathUtil.selectFirstNode("./TD[1]/A", node);
|
||||||
|
|
||||||
|
String lang = XPathUtil.selectString("./SPAN[1]", linkNode);
|
||||||
|
|
||||||
|
String href = XPathUtil.selectString("@href", linkNode);
|
||||||
|
|
||||||
|
String name = XPathUtil.selectString("./SPAN[2]", linkNode);
|
||||||
|
|
||||||
|
String author = XPathUtil.selectString("./TD[4]", node);
|
||||||
|
|
||||||
|
Matcher matcher = hrefPattern.matcher(href);
|
||||||
|
|
||||||
|
if (!matcher.matches())
|
||||||
|
throw new IllegalArgumentException("Cannot extract download parameters: " + href);
|
||||||
|
|
||||||
|
String subtitleId = matcher.group(1);
|
||||||
|
String typeId = matcher.group(2);
|
||||||
|
|
||||||
|
URL downloadUrl = getDownloadUrl(url, subtitleId, typeId);
|
||||||
|
|
||||||
|
subtitles.add(new SubsceneSubtitleDescriptor(name, lang, author, typeId, downloadUrl, url));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot parse subtitle node", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtitles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleFunction implements Function<Node, SubtitleDescriptor> {
|
|
||||||
|
|
||||||
private final Pattern hrefPattern = Pattern.compile("javascript:Subtitle\\((\\d+), '(\\w+)', '0', '(\\d+)'\\);");
|
|
||||||
|
|
||||||
private final URL url;
|
|
||||||
|
|
||||||
|
|
||||||
public SubtitleFunction(URL url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
private URL getDownloadUrl(URL referer, String subtitleId, String typeId) throws MalformedURLException {
|
||||||
public SubtitleDescriptor evaluate(Node node) throws Exception {
|
String basePath = FileUtil.getNameWithoutExtension(referer.getFile());
|
||||||
Node linkNode = XPathUtil.selectFirstNode("./TD[1]/A", node);
|
String path = String.format("%s-dlpath-%s/%s.zipx", basePath, subtitleId, typeId);
|
||||||
|
|
||||||
String href = XPathUtil.selectString("@href", linkNode);
|
|
||||||
|
|
||||||
String lang = XPathUtil.selectString("./SPAN[1]", linkNode);
|
|
||||||
String name = XPathUtil.selectString("./SPAN[2]", linkNode);
|
|
||||||
|
|
||||||
String author = XPathUtil.selectString("./TD[4]", node);
|
|
||||||
|
|
||||||
Matcher matcher = hrefPattern.matcher(href);
|
|
||||||
|
|
||||||
if (!matcher.matches())
|
|
||||||
throw new IllegalArgumentException("Cannot extract download parameters: " + href);
|
|
||||||
|
|
||||||
String subtitleId = matcher.group(1);
|
|
||||||
String typeId = matcher.group(2);
|
|
||||||
|
|
||||||
URL downloadUrl = getDownloadUrl(url, subtitleId, typeId);
|
|
||||||
|
|
||||||
return new SubsceneSubtitleDescriptor(name, lang, author, typeId, downloadUrl, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private URL getDownloadUrl(URL referer, String subtitleId, String typeId) throws MalformedURLException {
|
|
||||||
String basePath = FileUtil.getNameWithoutExtension(referer.getFile());
|
|
||||||
String path = String.format("%s-dlpath-%s/%s.zipx", basePath, subtitleId, typeId);
|
|
||||||
|
|
||||||
return new URL(referer.getProtocol(), referer.getHost(), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return new URL(referer.getProtocol(), referer.getHost(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getSubtitleListLink(SearchResult searchResult) {
|
public URI getSubtitleListLink(SearchResult searchResult) {
|
||||||
return ((HyperLink) searchResult).getUri();
|
return ((HyperLink) searchResult).toUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@ package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class SubtitleClient {
|
public abstract class SubtitleClient {
|
||||||
|
@ -28,20 +28,20 @@ public abstract class SubtitleClient {
|
||||||
return Collections.unmodifiableList(registry);
|
return Collections.unmodifiableList(registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String name;
|
private final String name;
|
||||||
private ImageIcon icon;
|
private final Icon icon;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleClient(String name, ImageIcon icon) {
|
public SubtitleClient(String name, Icon icon) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract List<SearchResult> search(String searchterm) throws Exception;
|
public abstract Collection<SearchResult> search(String searchterm) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public abstract ProgressIterator<SubtitleDescriptor> getSubtitleList(SearchResult searchResult) throws Exception;
|
public abstract Collection<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, Locale language) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public abstract URI getSubtitleListLink(SearchResult searchResult);
|
public abstract URI getSubtitleListLink(SearchResult searchResult);
|
||||||
|
@ -52,7 +52,7 @@ public abstract class SubtitleClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ImageIcon getIcon() {
|
public Icon getIcon() {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,6 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.tuned.DefaultProgressIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.XPathUtil;
|
import net.sourceforge.tuned.XPathUtil;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
@ -63,7 +61,7 @@ public class TVRageClient extends EpisodeListClient {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException {
|
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException {
|
||||||
|
|
||||||
int showId = ((TVRageSearchResult) searchResult).getShowId();
|
int showId = ((TVRageSearchResult) searchResult).getShowId();
|
||||||
String episodeListUri = String.format("http://" + host + "/feeds/episode_list.php?sid=" + showId);
|
String episodeListUri = String.format("http://" + host + "/feeds/episode_list.php?sid=" + showId);
|
||||||
|
@ -95,7 +93,7 @@ public class TVRageClient extends EpisodeListClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultProgressIterator<Episode>(episodes);
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,7 @@ import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
import net.sourceforge.filebot.resources.ResourceManager;
|
||||||
import net.sourceforge.tuned.FunctionIterator;
|
|
||||||
import net.sourceforge.tuned.ProgressIterator;
|
|
||||||
import net.sourceforge.tuned.XPathUtil;
|
import net.sourceforge.tuned.XPathUtil;
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
@ -77,39 +74,22 @@ public class TvdotcomClient extends EpisodeListClient {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
||||||
|
|
||||||
Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season));
|
Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season));
|
||||||
|
|
||||||
List<Node> nodes = XPathUtil.selectNodes("id('episode-listing')/DIV/TABLE/TR/TD/ancestor::TR", dom);
|
List<Node> nodes = XPathUtil.selectNodes("id('episode-listing')/DIV/TABLE/TR/TD/ancestor::TR", dom);
|
||||||
|
|
||||||
return new FunctionIterator<Node, Episode>(nodes, new EpisodeFunction(searchResult, season, nodes.size()));
|
NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
|
||||||
}
|
numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodes.size()).length(), 2));
|
||||||
|
numberFormat.setGroupingUsed(false);
|
||||||
|
|
||||||
private static class EpisodeFunction implements Function<Node, Episode> {
|
|
||||||
|
|
||||||
private final SearchResult searchResult;
|
Integer episodeOffset = null;
|
||||||
private final NumberFormat numberFormat;
|
String seasonString = (season >= 1) ? Integer.toString(season) : null;
|
||||||
|
|
||||||
private Integer episodeOffset = null;
|
ArrayList<Episode> episodes = new ArrayList<Episode>(nodes.size());
|
||||||
private String seasonString = null;
|
|
||||||
|
|
||||||
|
for (Node node : nodes) {
|
||||||
public EpisodeFunction(SearchResult searchResult, int season, int nodeCount) {
|
|
||||||
this.searchResult = searchResult;
|
|
||||||
|
|
||||||
numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
|
|
||||||
numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodeCount).length(), 2));
|
|
||||||
numberFormat.setGroupingUsed(false);
|
|
||||||
|
|
||||||
if (season >= 1)
|
|
||||||
seasonString = Integer.toString(season);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Episode evaluate(Node node) {
|
|
||||||
String episodeNumber = XPathUtil.selectString("./TD[1]", node);
|
String episodeNumber = XPathUtil.selectString("./TD[1]", node);
|
||||||
String title = XPathUtil.selectString("./TD[2]/A", node);
|
String title = XPathUtil.selectString("./TD[2]/A", node);
|
||||||
|
|
||||||
|
@ -125,16 +105,17 @@ public class TvdotcomClient extends EpisodeListClient {
|
||||||
// episode number may be "Pilot", "Special", ...
|
// episode number may be "Pilot", "Special", ...
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Episode(searchResult.getName(), seasonString, episodeNumber, title);
|
episodes.add(new Episode(searchResult.getName(), seasonString, episodeNumber, title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
||||||
String summaryFile = null;
|
|
||||||
|
|
||||||
summaryFile = ((HyperLink) searchResult).getUri().getPath();
|
String summaryFile = ((HyperLink) searchResult).getUrl().getPath();
|
||||||
|
|
||||||
String base = summaryFile.substring(0, summaryFile.indexOf("summary.html"));
|
String base = summaryFile.substring(0, summaryFile.indexOf("summary.html"));
|
||||||
String file = base + "episode_listings.html";
|
String file = base + "episode_listings.html";
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
|
|
||||||
package net.sourceforge.tuned;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
|
|
||||||
public class DefaultProgressIterator<E> implements ProgressIterator<E> {
|
|
||||||
|
|
||||||
private final Iterator<E> sourceIterator;
|
|
||||||
private final int length;
|
|
||||||
|
|
||||||
private int position = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public DefaultProgressIterator(Collection<E> source) {
|
|
||||||
this.sourceIterator = source.iterator();
|
|
||||||
this.length = source.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return sourceIterator.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public E next() {
|
|
||||||
position++;
|
|
||||||
return sourceIterator.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,6 +15,11 @@ public class DefaultThreadFactory implements ThreadFactory {
|
||||||
private final boolean daemon;
|
private final boolean daemon;
|
||||||
|
|
||||||
|
|
||||||
|
public DefaultThreadFactory(String name) {
|
||||||
|
this(name, Thread.NORM_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public DefaultThreadFactory(String name, int priority) {
|
public DefaultThreadFactory(String name, int priority) {
|
||||||
this(name, priority, false);
|
this(name, priority, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
|
|
||||||
package net.sourceforge.tuned;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
|
|
||||||
public class FunctionIterator<S, T> implements ProgressIterator<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Function transforms one Object into another.
|
|
||||||
*
|
|
||||||
* @param <S> type of source Objects
|
|
||||||
* @param <T> type Objects are transformed into
|
|
||||||
*/
|
|
||||||
public static interface Function<S, T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform the given sourceValue into any kind of Object.
|
|
||||||
*
|
|
||||||
* @param sourceValue - the Object to transform
|
|
||||||
* @return the transformed version of the object
|
|
||||||
*/
|
|
||||||
public T evaluate(S sourceValue) throws Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Iterator<S> sourceIterator;
|
|
||||||
private final Function<S, T> function;
|
|
||||||
private final int length;
|
|
||||||
|
|
||||||
private int position = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public FunctionIterator(Collection<S> source, Function<S, T> function) {
|
|
||||||
this(source.iterator(), source.size(), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//TODO TEST case!!! for piped functions -> correct progress
|
|
||||||
public FunctionIterator(ProgressIterator<S> iterator, Function<S, T> function) {
|
|
||||||
this(iterator, iterator.getLength(), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public FunctionIterator(Iterator<S> iterator, int length, Function<S, T> function) {
|
|
||||||
this.sourceIterator = iterator;
|
|
||||||
this.length = length;
|
|
||||||
this.function = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
try {
|
|
||||||
return peekNext() != null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T next() {
|
|
||||||
if (!hasNext())
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
|
|
||||||
try {
|
|
||||||
return peekNext();
|
|
||||||
} finally {
|
|
||||||
cache = null;
|
|
||||||
currentException = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private T cache = null;
|
|
||||||
private RuntimeException currentException = null;
|
|
||||||
|
|
||||||
|
|
||||||
private T peekNext() {
|
|
||||||
while (cache == null && (sourceIterator.hasNext() || currentException != null)) {
|
|
||||||
if (currentException != null)
|
|
||||||
throw currentException;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cache = transform(sourceIterator.next());
|
|
||||||
} catch (Exception e) {
|
|
||||||
currentException = ExceptionUtil.asRuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private T transform(S sourceValue) throws Exception {
|
|
||||||
return function.evaluate(sourceValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPosition() {
|
|
||||||
if (sourceIterator instanceof FunctionIterator) {
|
|
||||||
return ((ProgressIterator<?>) sourceIterator).getPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The remove operation is not supported by this implementation of <code>Iterator</code>.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException if this method is invoked.
|
|
||||||
* @see java.util.Iterator
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
package net.sourceforge.tuned;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
|
|
||||||
public interface ProgressIterator<E> extends Iterator<E> {
|
|
||||||
|
|
||||||
public int getPosition();
|
|
||||||
|
|
||||||
|
|
||||||
public int getLength();
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.sourceforge.filebot.web.TVRageClient.TVRageSearchResult;
|
import net.sourceforge.filebot.web.TVRageClient.TVRageSearchResult;
|
||||||
import net.sourceforge.tuned.TestUtil;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ public class TVRageClientTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getEpisodeList() throws Exception {
|
public void getEpisodeList() throws Exception {
|
||||||
List<Episode> list = TestUtil.asList(tvrage.getEpisodeList(testResult, 7));
|
List<Episode> list = tvrage.getEpisodeList(testResult, 7);
|
||||||
|
|
||||||
Episode chosen = list.get(21);
|
Episode chosen = list.get(21);
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ public class TVRageClientTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getEpisodeListAll() throws Exception {
|
public void getEpisodeListAll() throws Exception {
|
||||||
List<Episode> list = TestUtil.asList(tvrage.getEpisodeList(testResult, 0));
|
List<Episode> list = tvrage.getEpisodeList(testResult, 0);
|
||||||
|
|
||||||
assertEquals(145, list.size());
|
assertEquals(145, list.size());
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||||
|
|
||||||
|
|
||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@SuiteClasses( { FunctionIteratorTest.class, PreferencesMapTest.class, PreferencesListTest.class })
|
@SuiteClasses( { PreferencesMapTest.class, PreferencesListTest.class })
|
||||||
public class TunedTestSuite {
|
public class TunedTestSuite {
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
|
|
Loading…
Reference in New Issue