* foundation for subtitle support

* added/updated libs
This commit is contained in:
Reinhard Pointner 2008-02-13 20:08:06 +00:00
parent 61fbd6a4e9
commit 3edd879d7e
22 changed files with 812 additions and 82 deletions

View File

@ -11,9 +11,11 @@
<property name="executable" location="${build}/${title}.jar" />
<property name="lib.nekohtml" value="nekohtml.jar" />
<property name="lib.xerces" value="xercesImpl.jar" />
<property name="lib.simmetrics" value="simmetrics.jar" />
<property name="lib.nekohtml" value="nekohtml-1.9.6.1.jar" />
<property name="lib.simmetrics" value="simmetrics_jar_v1_6_2_d07_02_07.jar" />
<property name="lib.xmlrpc" value="xmlrpc-client-1.1.jar" />
<target name="jar" depends="build">
@ -27,17 +29,26 @@
</manifest>
<!-- include libs if fatjar is set -->
<zipfileset src="${lib}/${lib.xerces}">
<include if="fatjar" name="**/*.class" />
<include if="fatjar" name="**/*.properties" />
<exclude if="fatjar" name="**/*Test*" />
</zipfileset>
<zipfileset src="${lib}/${lib.nekohtml}">
<include if="fatjar" name="**/*.class" />
<include if="fatjar" name="**/*.properties" />
<exclude if="fatjar" name="**/*Test*" />
</zipfileset>
<zipfileset src="${lib}/${lib.xerces}">
<include if="fatjar" name="**/*.class" />
</zipfileset>
<zipfileset src="${lib}/${lib.simmetrics}">
<include if="fatjar" name="**/*.class" />
<include if="fatjar" name="**/*.properties" />
<exclude if="fatjar" name="**/*Test*" />
</zipfileset>
</zipfileset>
<zipfileset src="${lib}/${lib.xmlrpc}">
<include if="fatjar" name="**/*.class" />
<include if="fatjar" name="**/*.properties" />
<exclude if="fatjar" name="**/*Test*" />
</zipfileset>
</jar>
</target>

BIN
lib/xmlrpc-client-1.1.jar Normal file

Binary file not shown.

View File

@ -1,3 +1,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
@ -10,6 +13,8 @@ public class Main {
* @param args
*/
public static void main(String[] args) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).setLevel(Level.ALL);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {

View File

@ -7,7 +7,7 @@ import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
@ -70,7 +70,7 @@ public class AnalyzePanel extends FileBotPanel {
}
};
private LinkedList<ToolPanel> toolPanels = new LinkedList<ToolPanel>();
private List<ToolPanel> toolPanels = new ArrayList<ToolPanel>();
public void addTool(ToolPanel toolPanel) {

View File

@ -4,9 +4,9 @@ package net.sourceforge.filebot.ui.panel.analyze.tools;
import java.awt.BorderLayout;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.TreeMap;
import javax.swing.BorderFactory;
@ -84,7 +84,7 @@ public class TypePanel extends ToolPanel {
if (list != null)
list.add(f);
else {
list = new LinkedList<File>();
list = new ArrayList<File>();
list.add(f);
map.put(suffix, list);
}

View File

@ -2,7 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
@ -21,7 +21,7 @@ public class FilesRenameList extends RenameList {
public List<FileEntry> getListEntries() {
DefaultListModel model = getModel();
List<FileEntry> files = new LinkedList<FileEntry>();
List<FileEntry> files = new ArrayList<FileEntry>();
for (int i = 0; i < model.getSize(); ++i)
files.add((FileEntry) model.get(i));

View File

@ -2,7 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
@ -21,7 +21,7 @@ public class NamesRenameList extends RenameList {
public List<ListEntry<?>> getListEntries() {
DefaultListModel model = getModel();
List<ListEntry<?>> entries = new LinkedList<ListEntry<?>>();
List<ListEntry<?>> entries = new ArrayList<ListEntry<?>>();
for (int i = 0; i < model.getSize(); i++)
entries.add((ListEntry<?>) model.get(i));

View File

@ -2,7 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename.match;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
@ -12,7 +12,7 @@ import net.sourceforge.filebot.ui.panel.rename.similarity.SimilarityMetric;
public class Matcher {
public List<Match> match(List<? extends ListEntry<?>> listA, List<? extends ListEntry<?>> listB, SimilarityMetric similarityMetric) {
LinkedList<Match> matches = new LinkedList<Match>();
ArrayList<Match> matches = new ArrayList<Match>();
for (ListEntry<?> entryA : listA) {
float maxSimilarity = -1;

View File

@ -12,7 +12,7 @@ import javax.swing.SwingWorker;
public class ChecksumComputationTask extends SwingWorker<Long, Object> {
private static final int CHUNK_SIZE = 32 * 1024;
private static final int BUFFER_SIZE = 32 * 1024;
private File file;
@ -31,9 +31,7 @@ public class ChecksumComputationTask extends SwingWorker<Long, Object> {
if (length > 0) {
long done = 0;
int bufferLength = (int) Math.min(length, CHUNK_SIZE);
byte[] buffer = new byte[bufferLength];
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = 0;

View File

@ -10,7 +10,6 @@ import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@ -39,9 +38,8 @@ public class AnidbClient extends EpisodeListClient {
@Override
public List<String> search(String searchterm) throws IOException, SAXException {
if (cache.containsKey(searchterm)) {
if (cache.containsKey(searchterm))
return Arrays.asList(searchterm);
}
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
@ -97,7 +95,7 @@ public class AnidbClient extends EpisodeListClient {
List<Node> nodes = XPathUtil.selectNodes("//TABLE[@id='eplist']//TR/TD/SPAN/ancestor::TR", dom);
LinkedList<Episode> list = new LinkedList<Episode>();
ArrayList<Episode> list = new ArrayList<Episode>(nodes.size());
NumberFormat f = NumberFormat.getInstance();
f.setMinimumIntegerDigits(Math.max(Integer.toString(nodes.size()).length(), 2));

View File

@ -0,0 +1,159 @@
package net.sourceforge.filebot.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;
public class DownloadTask extends SwingWorker<ByteBuffer, Object> {
public static final String DOWNLOAD_STATE = "download state";
public static final String BYTES_READ = "bytes read";
public static enum DownloadState {
PENDING, CONNECTING, DOWNLOADING, DONE;
}
private static final int BUFFER_SIZE = 4 * 1024;
private URL url;
private ByteBuffer postdata = null;
private long size = -1;
private long bytesRead = 0;
private DownloadState state = DownloadState.PENDING;
public DownloadTask(URL url) {
this.url = url;
}
public DownloadTask(URL url, ByteBuffer postdata) {
this.url = url;
this.postdata = postdata;
}
public DownloadTask(URL url, Map<String, String> postdata) {
this.url = url;
this.postdata = encodeParameters(postdata);
}
@Override
protected ByteBuffer doInBackground() throws Exception {
setDownloadState(DownloadState.CONNECTING);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (postdata != null) {
connection.setRequestMethod("POST");
connection.setDoOutput(true);
WritableByteChannel out = Channels.newChannel(connection.getOutputStream());
out.write(postdata);
out.close();
}
size = connection.getContentLength();
setDownloadState(DownloadState.DOWNLOADING);
InputStream in = connection.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
byte[] buffer = new byte[BUFFER_SIZE];
int len = 0;
try {
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
bytesRead += len;
getPropertyChangeSupport().firePropertyChange(BYTES_READ, null, bytesRead);
}
} catch (IOException e) {
// IOException (Premature EOF) is always thrown when the size of
// the response body is not known in advance, so we ignore it
if (isSizeKnown())
throw e;
} finally {
in.close();
out.close();
connection.disconnect();
}
setDownloadState(DownloadState.DONE);
return ByteBuffer.wrap(out.toByteArray());
}
private void setDownloadState(DownloadState state) {
this.state = state;
getPropertyChangeSupport().firePropertyChange(DOWNLOAD_STATE, null, state);
}
public DownloadState getDownloadState() {
return state;
}
public long getBytesRead() {
return bytesRead;
}
public boolean isSizeKnown() {
return size >= 0;
}
public long getSize() {
return size;
}
private static ByteBuffer encodeParameters(Map<String, String> parameters) {
StringBuffer sb = new StringBuffer();
int i = 0;
for (String key : parameters.keySet()) {
if (i > 0)
sb.append("&");
sb.append(key);
sb.append("=");
try {
sb.append(URLEncoder.encode(parameters.get(key), "UTF-8"));
} catch (UnsupportedEncodingException e) {
// will never happen
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.getMessage(), e);
}
i++;
}
return Charset.forName("UTF-8").encode(sb.toString());
}
}

View File

@ -29,19 +29,19 @@ public class ImdbSearchEngine {
private String host = "www.imdb.com";
public List<Movie> search(String searchterm) throws IOException, SAXException {
public List<MovieDescriptor> search(String searchterm) throws IOException, SAXException {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("id('outerbody')//TABLE//P[position() >= 2 and position() <=3 ]//A[count(child::IMG) <= 0]/..", dom);
ArrayList<Movie> movies = new ArrayList<Movie>();
ArrayList<MovieDescriptor> movies = new ArrayList<MovieDescriptor>();
for (Node node : nodes) {
try {
movies.add(parseMovie(node));
movies.add(parseMovieNode(node));
} catch (Exception e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid movie node", e);
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot parse movie node", e);
}
}
@ -49,7 +49,7 @@ public class ImdbSearchEngine {
}
private Movie parseMovie(Node node) {
private MovieDescriptor parseMovieNode(Node node) throws MalformedURLException {
// ignore javascript links
Node linkNode = XPathUtil.selectFirstNode("./A[count(@onclick) <= 0]", node);
@ -58,13 +58,12 @@ public class ImdbSearchEngine {
// match /title/tt0379786/
Matcher idMatcher = Pattern.compile(".*/tt(\\d+)/.*").matcher(href);
Integer imdbID = null;
int imdbId;
if (idMatcher.matches()) {
imdbID = new Integer(idMatcher.group(1));
} else {
imdbId = new Integer(idMatcher.group(1));
} else
throw new IllegalArgumentException("Cannot match imdb id: " + href);
}
String yearString = XPathUtil.selectString("text()[1]", node);
@ -73,12 +72,13 @@ public class ImdbSearchEngine {
Integer year = null;
if (yearMatcher.matches()) {
year = new Integer(yearMatcher.group(1));
} else {
year = Integer.parseInt(yearMatcher.group(1));
} else
throw new IllegalArgumentException("Cannot match year: " + yearString);
}
return new Movie(title, year, imdbID);
URL imdbUrl = new URL("http", host, href);
return new MovieDescriptor(title, year, imdbId, imdbUrl);
}

View File

@ -1,43 +0,0 @@
package net.sourceforge.filebot.web;
public class Movie {
private String title;
private Integer year;
private Integer imdbID;
public Movie(String title, Integer year, Integer imdbID) {
this.title = title;
this.imdbID = imdbID;
this.year = year;
}
public String getTitle() {
return title;
}
public Integer getImdbID() {
return imdbID;
}
public Integer getYear() {
return year;
}
@Override
public String toString() {
if (year == null)
return title;
return String.format("%s (%d)", title, year);
}
}

View File

@ -0,0 +1,48 @@
package net.sourceforge.filebot.web;
import java.net.URL;
public class MovieDescriptor {
private String title;
private int year;
private int imdbId;
private URL imdbUrl;
public MovieDescriptor(String title, int year, int imdbId, URL imdbUrl) {
this.title = title;
this.imdbId = imdbId;
this.year = year;
this.imdbUrl = imdbUrl;
}
public String getTitle() {
return title;
}
public int getYear() {
return year;
}
public int getImdbId() {
return imdbId;
}
public URL getImdbUrl() {
return imdbUrl;
}
@Override
public String toString() {
return String.format("%s (%d)", title, year);
}
}

View File

@ -0,0 +1,64 @@
package net.sourceforge.filebot.web;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Describes a subtitle on OpenSubtitles.
*
* @see OpenSubtitlesClient
*/
public class OpenSubtitleDescriptor {
private Map<String, String> properties;
public static enum Properties {
IDSubMovieFile, MovieHash, MovieByteSize, MovieTimeMS, MovieFrames, IDSubtitleFile, SubFileName, SubActualCD, SubSize, SubHash, IDSubtitle, UserID, SubLanguageID, SubFormat, SubSumCD, SubAuthorComment, SubAddDate, SubBad, SubRating, SubDownloadsCnt, MovieReleaseName, IDMovie, IDMovieImdb, MovieName, MovieNameEng, MovieYear, MovieImdbRating, UserNickName, ISO639, LanguageName, SubDownloadLink, ZipDownloadLink,
}
public OpenSubtitleDescriptor(Map<String, String> properties) {
this.properties = properties;
}
public Map<String, String> getPropertyMap() {
return properties;
}
public String getProperty(Properties property) {
return properties.get(property.name());
}
public long getSize() {
return Long.parseLong(getProperty(Properties.SubSize));
}
public URL getDownloadLink() {
String link = getProperty(Properties.SubDownloadLink);
try {
return new URL(link);
} catch (MalformedURLException e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid download link: " + link, e);
return null;
}
}
@Override
public String toString() {
return String.format("%s [%s]", getProperty(Properties.SubFileName), getProperty(Properties.LanguageName));
}
}

View File

@ -0,0 +1,257 @@
package net.sourceforge.filebot.web;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import redstone.xmlrpc.XmlRpcClient;
import redstone.xmlrpc.XmlRpcException;
import redstone.xmlrpc.XmlRpcFault;
/**
* Client for the OpenSubtitles XML-RPC API.
*
*/
public class OpenSubtitlesClient {
/**
* <table>
* <tr>
* <td>Main server:</td>
* <td>http://www.opensubtitles.org/xml-rpc</td>
* </tr>
* <tr>
* <td>Developing tests:</td>
* <td>http://dev.opensubtitles.org/xml-rpc</td>
* </tr>
* </table>
*/
private String url = "http://dev.opensubtitles.org/xml-rpc";
private String username;
private String password;
private String language;
private String useragent;
private String token = null;
private Timer keepAliveDaemon = null;
/**
* Interval to call NoOperation to keep the session from expiring
*/
public static final int KEEP_ALIVE_INTERVAL = 12 * 60 * 1000; // 12 minutes
public OpenSubtitlesClient(String useragent) {
this.useragent = useragent;
}
public boolean isLoggedOn() {
return username != null;
}
/**
* login as anonymous user
*/
public synchronized void login() throws XmlRpcFault {
this.login("", "", "en");
}
/**
* This will login user. This method should be called always when starting talking with
* server.
*
* @param username blank for anonymous user.
* @param password blank for anonymous user.
* @param language <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes">ISO639</a>
* 2 letter codes as language and later communication will be done in this
* language if applicable (error codes and so on).
*/
public synchronized void login(String username, String password, String language) throws XmlRpcFault {
if (isLoggedOn())
throw new IllegalStateException("User is already logged on");
if ((username == null) || (password == null) || (language == null))
throw new IllegalArgumentException("Username, password and language must not be null");
this.username = username;
this.password = password;
this.language = language;
activate();
}
public synchronized void logout() {
if (!isLoggedOn())
throw new IllegalStateException("User is not logged on");
deactivate();
username = null;
password = null;
language = null;
}
@SuppressWarnings("unchecked")
private synchronized void activate() throws XmlRpcFault {
if (isActive())
return;
if (!isLoggedOn())
throw new IllegalStateException("User is not logged on");
Map<String, String> response = (Map<String, String>) invoke("LogIn", username, password, language, useragent);
checkStatus(response.get("status"));
token = response.get("token");
keepAliveDaemon = new Timer(getClass().getSimpleName() + " Keepalive", true);
keepAliveDaemon.schedule(new KeepAliveTimerTask(), KEEP_ALIVE_INTERVAL, KEEP_ALIVE_INTERVAL);
}
@SuppressWarnings("unchecked")
private synchronized void deactivate() {
if (!isActive())
return;
// anonymous users will always get a 401 Unauthorized when trying to logout
if (!username.isEmpty()) {
try {
Map<String, String> response = (Map<String, String>) invoke("LogOut", token);
checkStatus(response.get("status"));
} catch (Exception e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Exception while deactivating connection", e);
}
}
token = null;
keepAliveDaemon.cancel();
keepAliveDaemon = null;
}
private boolean isActive() {
return token != null;
}
/**
* Check status whether it is OK or not
*
* @param status status code and message (e.g. 200 OK, 401 Unauthorized, ...)
* @throws XmlRpcFault thrown if status code is not OK
*/
private void checkStatus(String status) throws XmlRpcFault {
if (status.equals("200 OK"))
return;
Matcher m = Pattern.compile("(\\d+).*").matcher(status);
if (!m.matches())
throw new XmlRpcException("Illegal status code: " + status);
throw new XmlRpcFault(Integer.parseInt(m.group(1)), status);
}
private Object invoke(String method, Object... arguments) throws XmlRpcFault {
try {
XmlRpcClient rpc = new XmlRpcClient(url, false);
return rpc.invoke(method, arguments);
} catch (MalformedURLException e) {
// will never happen
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid xml-rpc url: " + url, e);
return null;
}
}
/**
* This simple function returns basic server info.
*/
@SuppressWarnings("unchecked")
public Map<String, String> getServerInfo() throws XmlRpcFault {
activate();
return (Map<String, String>) invoke("ServerInfo", token);
}
@SuppressWarnings("unchecked")
public List<OpenSubtitleDescriptor> searchSubtitles(int... imdbidArray) throws XmlRpcFault {
activate();
List<Map<String, String>> imdbidList = new ArrayList<Map<String, String>>(imdbidArray.length);
for (int imdbid : imdbidArray) {
Map<String, String> map = new HashMap<String, String>(1);
// pad id with zeros
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);
ArrayList<OpenSubtitleDescriptor> subs = new ArrayList<OpenSubtitleDescriptor>();
for (Map<String, String> subtitle : response.get("data"))
subs.add(new OpenSubtitleDescriptor(subtitle));
return subs;
}
@SuppressWarnings("unchecked")
public boolean noOperation() {
try {
activate();
Map<String, String> response = (Map<String, String>) invoke("NoOperation", token);
checkStatus(response.get("status"));
return true;
} catch (Exception e) {
deactivate();
return false;
}
}
private class KeepAliveTimerTask extends TimerTask {
@Override
public void run() {
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
if (!noOperation()) {
logger.log(Level.INFO, "Connection lost");
deactivate();
} else {
logger.log(Level.INFO, "Connection is OK");
}
};
};
}

View File

@ -0,0 +1,125 @@
package net.sourceforge.filebot.web;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.tuned.XPathUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class SubsceneClient {
private Map<String, URL> cache = Collections.synchronizedMap(new TreeMap<String, URL>());
private String host = "subscene.com";
public List<String> search(String searchterm) throws IOException, SAXException {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("id('filmSearch')/A", dom);
ArrayList<String> titles = new ArrayList<String>();
for (Node node : nodes) {
String title = XPathUtil.selectString("text()", node);
String href = XPathUtil.selectString("@href", node);
try {
URL url = new URL("http", host, href);
cache.put(title, url);
titles.add(title);
} catch (MalformedURLException e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid href: " + href, e);
}
}
return titles;
}
public List<SubsceneSubtitleDescriptor> getSubtitleList(String title) throws IOException, SAXException {
URL url = cache.get(title);
if (url == null)
throw new IllegalArgumentException("Unknown title: " + title);
Document dom = HtmlUtil.getHtmlDocument(url);
String downloadPath = XPathUtil.selectString("id('aspnetForm')/@action", dom);
String viewstate = XPathUtil.selectString("id('__VIEWSTATE')/@value", dom);
List<Node> nodes = XPathUtil.selectNodes("//TABLE[@class='filmSubtitleList']//A[@id]//ancestor::TR", dom);
ArrayList<SubsceneSubtitleDescriptor> list = new ArrayList<SubsceneSubtitleDescriptor>();
for (Node node : nodes) {
try {
Node linkNode = XPathUtil.selectFirstNode("./TD[1]/A", node);
String href = XPathUtil.selectString("@href", linkNode);
String name = XPathUtil.selectString("./SPAN[2]", linkNode);
String lang = XPathUtil.selectString("./SPAN[1]", linkNode);
int numberOfCDs = Integer.parseInt(XPathUtil.selectString("./TD[2]", node));
String author = XPathUtil.selectString("./TD[4]", node);
URL downloadUrl = new URL("http", host, downloadPath);
Map<String, String> downloadParameters = parseParameters(href);
downloadParameters.put("__VIEWSTATE", viewstate);
list.add(new SubsceneSubtitleDescriptor(name, lang, numberOfCDs, author, downloadUrl, downloadParameters));
} catch (Exception e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot parse subtitle node", e);
}
}
return list;
}
private Map<String, String> parseParameters(String href) {
Matcher matcher = Pattern.compile("javascript:Subtitle\\((\\d+), '(\\w+)', '0', '(\\d+)'\\);").matcher(href);
if (!matcher.matches())
throw new IllegalArgumentException("Cannot extract download parameters: " + href);
Map<String, String> map = new HashMap<String, String>();
map.put("subtitleId", matcher.group(1));
map.put("typeId", matcher.group(2));
map.put("filmId", matcher.group(3));
return map;
}
private URL getSearchUrl(String searchterm) throws UnsupportedEncodingException, MalformedURLException {
String qs = URLEncoder.encode(searchterm, "UTF-8");
String file = "/filmsearch.aspx?q=" + qs;
return new URL("http", host, file);
}
}

View File

@ -0,0 +1,67 @@
package net.sourceforge.filebot.web;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Map;
public class SubsceneSubtitleDescriptor {
private String title;
private String language;
private int numberOfCDs;
private String author;
private Map<String, String> downloadParameters;
private URL downloadUrl;
public SubsceneSubtitleDescriptor(String title, String language, int numberOfCDs, String author, URL downloadUrl, Map<String, String> downloadParameters) {
this.title = title;
this.language = language;
this.numberOfCDs = numberOfCDs;
this.author = author;
this.downloadUrl = downloadUrl;
this.downloadParameters = downloadParameters;
}
public String getTitle() {
return title;
}
public String getLanguage() {
return language;
}
public int getNumberOfCDs() {
return numberOfCDs;
}
public String getAuthor() {
return author;
}
public String getArchiveType() {
return downloadParameters.get("typeId");
}
public DownloadTask createDownloadTask() throws UnsupportedEncodingException {
return new DownloadTask(downloadUrl, downloadParameters);
}
@Override
public String toString() {
return String.format("%s [%s]", title, language);
}
}

View File

@ -0,0 +1,41 @@
package net.sourceforge.tuned;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
public class ByteBufferInputStream extends InputStream {
private ByteBuffer buffer;
public ByteBufferInputStream(ByteBuffer buffer) {
this.buffer = buffer;
}
@Override
public synchronized int read() throws IOException {
return buffer.getInt();
}
@Override
public synchronized int read(byte[] b, int off, int len) throws IOException {
int length = Math.min(len, buffer.remaining());
buffer.get(b, off, length);
return length;
}
@Override
public synchronized int available() throws IOException {
return buffer.remaining();
}
}

View File

@ -11,7 +11,7 @@ import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.ListIterator;
import javax.swing.SwingConstants;
@ -23,7 +23,7 @@ import javax.swing.SwingConstants;
*/
public class QueueNotificationLayout implements NotificationLayout, SwingConstants {
private LinkedList<NotificationWindow> notificationList = new LinkedList<NotificationWindow>();
private ArrayList<NotificationWindow> notificationList = new ArrayList<NotificationWindow>();
private int orientation;
private int direction;