--- remove Subscene/Sublight from codebase

This commit is contained in:
Reinhard Pointner 2013-08-04 13:09:06 +00:00
parent d66fd0f141
commit 1804d12def
11 changed files with 3 additions and 1243 deletions

Binary file not shown.

View File

@ -20,6 +20,4 @@ themoviedb.apikey: 5a6edae568130bf10617b6d45be99f13
serienjunkies.apikey: 9fbhw9uebfiwvbefzuwv serienjunkies.apikey: 9fbhw9uebfiwvbefzuwv
fanart.tv.apikey: 780b986b22c35e6f7a134a2f392c2deb fanart.tv.apikey: 780b986b22c35e6f7a134a2f392c2deb
acoustid.apikey: 0B3qZnQc acoustid.apikey: 0B3qZnQc
pushover.apikey: wcckDz3oygHSU2SdIptvnHxJ92SQKK pushover.apikey: wcckDz3oygHSU2SdIptvnHxJ92SQKK
sublight.clientid: FileBot2
sublight.apikey: 79f7a868-c28c-446f-a58e-3637ca24c87a

View File

@ -61,7 +61,6 @@ public final class WebServices {
// subtitle dbs // subtitle dbs
public static final OpenSubtitlesClient OpenSubtitles = new OpenSubtitlesClient(String.format("%s %s", getApplicationName(), getApplicationVersion())); public static final OpenSubtitlesClient OpenSubtitles = new OpenSubtitlesClient(String.format("%s %s", getApplicationName(), getApplicationVersion()));
//TODO remove Subscene/Sublight from codebase
// misc // misc
public static final FanartTV FanartTV = new FanartTV(Settings.getApplicationProperty("fanart.tv.apikey")); public static final FanartTV FanartTV = new FanartTV(Settings.getApplicationProperty("fanart.tv.apikey"));

View File

@ -1,449 +0,0 @@
package net.sourceforge.filebot.web;
import static java.lang.Math.*;
import static java.util.Collections.*;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.tuned.Timer;
import net.sublight.webservice.ArrayOfGenre;
import net.sublight.webservice.ArrayOfIMDB;
import net.sublight.webservice.ArrayOfRelease;
import net.sublight.webservice.ArrayOfString;
import net.sublight.webservice.ArrayOfSubtitle;
import net.sublight.webservice.ArrayOfSubtitleLanguage;
import net.sublight.webservice.ClientInfo;
import net.sublight.webservice.Genre;
import net.sublight.webservice.IMDB;
import net.sublight.webservice.Release;
import net.sublight.webservice.Sublight;
import net.sublight.webservice.SublightSoap;
import net.sublight.webservice.Subtitle;
import net.sublight.webservice.SubtitleLanguage;
public class SublightSubtitleClient implements SubtitleProvider, VideoHashSubtitleService {
private static final String iid = "25f30171-518c-463b-a310-b9f8e1eddb40";
private final ClientInfo clientInfo = new ClientInfo();
private String username;
private String passwordHash;
private SublightSoap webservice;
private String session;
@Override
public String getName() {
return "Sublight";
}
@Override
public URI getLink() {
return URI.create("http://www.sublight.si");
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.sublight");
}
@Override
public List<SearchResult> search(String query) throws WebServiceException {
// require login
login();
Holder<ArrayOfIMDB> response = new Holder<ArrayOfIMDB>();
Holder<String> error = new Holder<String>();
webservice.findIMDB(query, null, null, response, error);
// abort if something went wrong
checkError(error);
List<SearchResult> results = new ArrayList<SearchResult>();
if (response.value != null) {
for (IMDB imdb : response.value.getIMDB()) {
// remove classifier (e.g. tt0436992 -> 0436992)
int id = Integer.parseInt(imdb.getId().substring(2));
results.add(new Movie(imdb.getTitle(), imdb.getYear(), id, -1));
}
}
return results;
}
@Override
public List<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, String languageName) throws WebServiceException {
Movie movie = (Movie) searchResult;
List<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>();
// retrieve subtitles by name and year
for (Subtitle subtitle : getSubtitleList(null, movie.getName(), movie.getYear(), languageName)) {
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
}
return subtitles;
}
@Override
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] files, final String languageName) throws Exception {
Map<File, List<SubtitleDescriptor>> subtitles = new HashMap<File, List<SubtitleDescriptor>>(files.length);
ExecutorService executor = Executors.newFixedThreadPool(min(files.length, 10));
List<Future<List<SubtitleDescriptor>>> requests = new ArrayList<Future<List<SubtitleDescriptor>>>();
try {
// queue and execute requests
for (int i = 0; i < files.length; i++) {
Future<List<SubtitleDescriptor>> request = null;
try {
// make call interruptible
if (Thread.interrupted())
throw new InterruptedException();
// compute video hash and execute query in parallel
final String videoHash = SublightVideoHasher.computeHash(files[i]);
request = executor.submit(new Callable<List<SubtitleDescriptor>>() {
@Override
public List<SubtitleDescriptor> call() throws Exception {
return getSubtitleList(videoHash, languageName);
}
});
} catch (IOException e) {
Logger.getLogger(SublightSubtitleClient.class.getName()).log(Level.WARNING, "Error computing video hash: " + e.getMessage());
}
requests.add(i, request);
}
// collect results
for (int i = 0; i < files.length; i++) {
List<SubtitleDescriptor> response = emptyList();
if (requests.get(i) != null) {
response = requests.get(i).get();
}
subtitles.put(files[i], response);
}
return subtitles;
} finally {
// shutdown after all tasks are done or an exception was thrown
executor.shutdownNow();
}
}
public List<SubtitleDescriptor> getSubtitleList(String videoHash, String languageName) throws WebServiceException {
List<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>();
// retrieve subtitles by video hash
for (Subtitle subtitle : getSubtitleList(videoHash, null, null, languageName)) {
// only keep linked subtitles
if (subtitle.isIsLinked()) {
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
}
}
return subtitles;
}
public List<Subtitle> getSubtitleList(String videoHash, String name, Integer year, String languageName) throws WebServiceException {
// require login
login();
// given language or all languages
ArrayOfSubtitleLanguage languages = new ArrayOfSubtitleLanguage();
if (languageName != null) {
// given language
languages.getSubtitleLanguage().add(getSubtitleLanguage(languageName));
} else {
// all languages
Collections.addAll(languages.getSubtitleLanguage(), SubtitleLanguage.values());
}
// hash singleton array
ArrayOfString videoHashes = new ArrayOfString();
videoHashes.getString().add(videoHash);
// all genres
ArrayOfGenre genres = new ArrayOfGenre();
Collections.addAll(genres.getGenre(), Genre.values());
// response holders
Holder<ArrayOfSubtitle> subtitles = new Holder<ArrayOfSubtitle>();
Holder<ArrayOfRelease> releases = new Holder<ArrayOfRelease>();
Holder<String> error = new Holder<String>();
webservice.searchSubtitles4(session, videoHashes, name, year, null, null, languages, genres, null, null, null, subtitles, releases, null, error);
// abort if something went wrong
checkError(error);
// return empty list if response is empty
if (subtitles.value == null) {
return Collections.emptyList();
}
// map all release names by subtitle id
if (releases.value != null) {
Map<String, String> releaseNameBySubtitleID = new HashMap<String, String>();
// map release names by subtitle id
for (Release release : releases.value.getRelease()) {
releaseNameBySubtitleID.put(release.getSubtitleID(), release.getName());
}
// set release names
for (Subtitle subtitle : subtitles.value.getSubtitle()) {
subtitle.setRelease(releaseNameBySubtitleID.get(subtitle.getSubtitleID()));
}
}
return subtitles.value.getSubtitle();
}
@Override
public boolean publishSubtitle(int imdbid, String languageName, File[] videoFile, File[] subtitleFile) throws Exception {
//TODO implement upload feature
return false;
}
public void publishSubtitle(int imdbid, String videoHash, String languageName, String releaseName, byte[] data) {
// require login
login();
Subtitle subtitle = new Subtitle();
subtitle.setIMDB(String.format("http://www.imdb.com/title/tt%07d", imdbid));
subtitle.setLanguage(getSubtitleLanguage(languageName));
subtitle.setRelease(releaseName);
Holder<Boolean> result = new Holder<Boolean>();
Holder<String> subid = new Holder<String>();
Holder<String> error = new Holder<String>();
// upload subtitle
webservice.publishSubtitle2(session, subtitle, data, result, subid, null, error);
// abort if something went wrong
checkError(error);
// link subtitle to video file
webservice.addHashLink3(session, subid.value, videoHash, null, null, error);
// abort if something went wrong
checkError(error);
}
protected Map<String, SubtitleLanguage> getLanguageAliasMap() {
Map<String, SubtitleLanguage> languages = new HashMap<String, SubtitleLanguage>(4);
// insert special some additional special handling
languages.put("Brazilian", SubtitleLanguage.PORTUGUESE_BRAZIL);
languages.put("Bosnian", SubtitleLanguage.BOSNIAN_LATIN);
languages.put("Serbian", SubtitleLanguage.SERBIAN_LATIN);
return languages;
}
protected SubtitleLanguage getSubtitleLanguage(String languageName) {
// check subtitle language enum
for (SubtitleLanguage language : SubtitleLanguage.values()) {
if (language.value().equalsIgnoreCase(languageName))
return language;
}
// check alias list
for (Entry<String, SubtitleLanguage> alias : getLanguageAliasMap().entrySet()) {
if (alias.getKey().equalsIgnoreCase(languageName))
return alias.getValue();
}
// illegal language name
throw new IllegalArgumentException("Illegal language: " + languageName);
}
protected String getLanguageName(SubtitleLanguage language) {
// check alias list first
for (Entry<String, SubtitleLanguage> alias : getLanguageAliasMap().entrySet()) {
if (language == alias.getValue())
return alias.getKey();
}
// use language value by default
return language.value();
}
protected synchronized byte[] getZipArchive(Subtitle subtitle) throws WebServiceException, InterruptedException {
// require login
login();
Holder<String> ticket = new Holder<String>();
Holder<Short> que = new Holder<Short>();
Holder<byte[]> data = new Holder<byte[]>();
Holder<String> error = new Holder<String>();
webservice.getDownloadTicket2(session, null, subtitle.getSubtitleID(), null, ticket, que, null, error);
// abort if something went wrong
checkError(error);
// wait x seconds as specified by the download ticket response, download ticket is not valid until then
Thread.sleep(que.value * 1000);
webservice.downloadByID4(session, subtitle.getSubtitleID(), -1, false, ticket.value, null, data, null, error);
// abort if something went wrong
checkError(error);
// return zip file bytes
return data.value;
}
@Override
public URI getSubtitleListLink(SearchResult searchResult, String languageName) {
// note that sublight can only be accessed via the soap API
return URI.create("http://www.sublight.si/SearchSubtitles.aspx");
}
public synchronized void setClient(String id, String key) {
clientInfo.setClientId(id);
clientInfo.setApiKey(key);
}
public synchronized void setUser(String username, String password) {
this.username = username;
this.passwordHash = password != null && password.length() > 0 ? getPasswordHash(password) : null;
}
public String getPasswordHash(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(password.getBytes("UTF-16LE"));
return String.format("%032x", new BigInteger(1, digest.digest()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public synchronized void login() throws WebServiceException {
if (clientInfo.getClientId() == null || clientInfo.getClientId().isEmpty()) {
throw new IllegalStateException("Sublight login has not been configured");
}
if (webservice == null) {
// lazy initialize because all the JAX-WS class loading can take quite some time
webservice = new Sublight().getSublightSoap();
}
if (session == null) {
// args contains only iid
ArrayOfString args = new ArrayOfString();
args.getString().add(iid);
Holder<String> session = new Holder<String>();
Holder<String> error = new Holder<String>();
if (username == null || username.isEmpty()) {
webservice.logInAnonymous4(clientInfo, args, session, null, error);
} else {
webservice.logIn6(username, passwordHash, clientInfo, args, session, null, null, null, null, error);
}
// abort if something went wrong
checkError(error);
// start session
this.session = session.value;
}
// reset timer
logoutTimer.set(10, TimeUnit.MINUTES, true);
}
protected synchronized void logout() throws WebServiceException {
if (session != null) {
Holder<String> error = new Holder<String>();
webservice.logOut(session, null, error);
// abort if something went wrong
checkError(error);
// stop session
this.session = null;
// cancel timer
logoutTimer.cancel();
}
}
protected void checkError(Holder<?> error) throws WebServiceException {
if (error.value != null) {
throw new WebServiceException("Response indicates error: " + error.value);
}
}
protected final Timer logoutTimer = new Timer() {
@Override
public void run() {
logout();
}
};
}

View File

@ -1,144 +0,0 @@
package net.sourceforge.filebot.web;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.util.Formatter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import net.sourceforge.tuned.ByteBufferOutputStream;
import net.sublight.webservice.Subtitle;
public class SublightSubtitleDescriptor implements SubtitleDescriptor {
private final Subtitle subtitle;
private final SublightSubtitleClient source;
private final String name;
private final String languageName;
public SublightSubtitleDescriptor(Subtitle subtitle, SublightSubtitleClient source) {
this.subtitle = subtitle;
this.source = source;
this.name = getName(subtitle);
this.languageName = source.getLanguageName(subtitle.getLanguage());
}
private String getName(Subtitle subtitle) {
String releaseName = subtitle.getRelease();
// check if release name contains sufficient information to be used as display name
if (releaseName != null && !releaseName.isEmpty()) {
boolean isValid = true;
if (subtitle.getSeason() != null) {
isValid &= releaseName.contains(subtitle.getSeason().toString());
}
if (subtitle.getEpisode() != null) {
isValid &= releaseName.contains(subtitle.getEpisode().toString());
}
if (isValid) {
return releaseName;
}
}
// format proper display name
Formatter builder = new Formatter(new StringBuilder(subtitle.getTitle()));
if (subtitle.getSeason() != null || subtitle.getEpisode() != null) {
builder.format(" - S%02dE%02d", subtitle.getSeason(), subtitle.getEpisode());
}
if (subtitle.getRelease() != null && !subtitle.getRelease().isEmpty()) {
builder.format(" (%s)", subtitle.getRelease());
}
return builder.out().toString();
}
@Override
public String getName() {
return name;
}
@Override
public String getLanguageName() {
return languageName;
}
@Override
public String getType() {
return subtitle.getSubtitleType().value().toLowerCase();
}
@Override
public long getLength() {
return subtitle.getSize();
}
@Override
public ByteBuffer fetch() throws Exception {
byte[] archive = source.getZipArchive(subtitle);
// the zip archive will contain exactly one subtitle
ZipInputStream stream = new ZipInputStream(new ByteArrayInputStream(archive));
try {
// move to subtitle entry
ZipEntry entry = stream.getNextEntry();
ByteBufferOutputStream buffer = new ByteBufferOutputStream(entry.getSize());
// read subtitle data
buffer.transferFully(stream);
// return plain subtitle data
return buffer.getByteBuffer();
} finally {
stream.close();
}
}
@Override
public String getPath() {
return String.format("%s.%s", getName(), getType());
}
@Override
public int hashCode() {
return subtitle.getSubtitleID().hashCode();
}
@Override
public boolean equals(Object object) {
if (object instanceof SublightSubtitleDescriptor) {
SublightSubtitleDescriptor other = (SublightSubtitleDescriptor) object;
return subtitle.getSubtitleID().equals(other.subtitle.getSubtitleID());
}
return false;
}
@Override
public String toString() {
return String.format("%s [%s]", getName(), getLanguageName());
}
}

View File

@ -1,124 +0,0 @@
package net.sourceforge.filebot.web;
import static java.lang.Math.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.concurrent.TimeUnit;
import net.sourceforge.filebot.mediainfo.MediaInfo;
import net.sourceforge.filebot.mediainfo.MediaInfoException;
import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
/**
* Compute special hash used by <a href="http://www.subtitles-on.net">Sublight</a> to identify video files.
*
* <pre>
* The hash is divided into 5 sections:
* 1 byte : reserved
* 2 bytes: video duration in seconds
* 6 bytes: file size in bytes
* 16 bytes: MD5 hash of the first 5 MB
* 1 byte: control byte, sum of all other bytes
* </pre>
*/
public final class SublightVideoHasher {
public static String computeHash(File file) throws IOException, MediaInfoException {
byte[][] hash = new byte[4][];
// 1 byte = 0 (reserved)
hash[0] = new byte[] { 0 };
// 2 bytes (video duration in seconds)
hash[1] = getTrailingBytes(getDuration(file, TimeUnit.SECONDS), 2);
// 6 bytes (file size in bytes)
hash[2] = getTrailingBytes(file.length(), 6);
// 16 bytes (md5 hash of the first 5 MB)
hash[3] = getHeadMD5(file, 5 * 1024 * 1024);
// format and sum
Formatter hex = new Formatter(new StringBuilder(52));
byte sum = 0;
for (byte[] group : hash) {
for (byte b : group) {
hex.format("%02x", b);
sum += b;
}
}
// 1 byte (control byte)
hex.format("%02x", sum);
// done
return hex.out().toString();
}
protected static byte[] getTrailingBytes(long value, int n) {
byte[] bytes = BigInteger.valueOf(value).toByteArray();
// bytes will be initialized with 0
byte[] trailingBytes = new byte[n];
// copy the least significant n bytes to the new array
System.arraycopy(bytes, max(0, bytes.length - n), trailingBytes, max(0, n - bytes.length), min(n, bytes.length));
return trailingBytes;
}
protected static long getDuration(File file, TimeUnit unit) throws IOException, MediaInfoException {
MediaInfo mediaInfo = new MediaInfo();
if (!mediaInfo.open(file))
throw new IOException("Failed to open file: " + file);
// get media info
String duration = mediaInfo.get(StreamKind.General, 0, "Duration");
// close handle
mediaInfo.close();
// sanity check
if (duration.isEmpty())
throw new IOException("Failed to read video duration");
// convert from milliseconds to given unit
return unit.convert(Long.parseLong(duration), TimeUnit.MILLISECONDS);
}
protected static byte[] getHeadMD5(File file, long chunkSize) throws IOException {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
FileChannel channel = new FileInputStream(file).getChannel();
try {
// calculate md5
md5.update(channel.map(MapMode.READ_ONLY, 0, min(channel.size(), chunkSize)));
} finally {
// close channel
channel.close();
}
return md5.digest();
} catch (Exception e) {
throw new IOException("Failed to calculate md5 hash", e);
}
}
}

View File

@ -1,199 +0,0 @@
package net.sourceforge.filebot.web;
import static net.sourceforge.filebot.web.WebRequest.*;
import static net.sourceforge.tuned.XPathUtilities.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.Icon;
import net.sourceforge.filebot.Cache;
import net.sourceforge.filebot.ResourceManager;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class SubsceneSubtitleClient implements SubtitleProvider {
private static final String host = "subscene.com";
@Override
public String getName() {
return "Subscene";
}
@Override
public URI getLink() {
return URI.create("http://subscene.com");
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.subscene");
}
@Override
public List<SearchResult> search(String query) throws IOException, SAXException {
URL searchUrl = new URL("http", host, "/subtitles/title.aspx?q=" + encode(query, true));
Document dom = getHtmlDocument(searchUrl);
List<Node> nodes = selectNodes("//H2[text()='Close']//following::DIV[@class='title']//A", dom);
List<SearchResult> searchResults = new ArrayList<SearchResult>(nodes.size());
Pattern titleSuffixPattern = Pattern.compile("\\s-\\s([^-]+)[(](\\d{4})[)]$");
for (Node node : nodes) {
String title = getTextContent(node);
String href = getAttribute("href", node);
// simplified name for easy matching
String shortName = titleSuffixPattern.matcher(title).replaceFirst("");
try {
searchResults.add(new SubsceneSearchResult(shortName, title, new URL("http", host, href)));
} catch (MalformedURLException e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Invalid href: " + href, e);
}
}
return searchResults;
}
@Override
public List<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, String languageName) throws Exception {
URL subtitleListUrl = getSubtitleListLink(searchResult, languageName).toURL();
String filter = getLanguageFilter(languageName);
Document dom = getSubtitleListDocument(subtitleListUrl, filter);
List<Node> rows = selectNodes("//TD[@class='a1']", dom);
List<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>();
for (Node row : rows) {
try {
List<Node> fields = selectNodes(".//SPAN", row);
String language = getTextContent(fields.get(0));
if (languageName == null || language.equalsIgnoreCase(languageName)) {
String name = getTextContent(fields.get(1));
String href = selectString(".//A/@href", row);
URL subtitlePage = new URL(subtitleListUrl.getProtocol(), subtitleListUrl.getHost(), href);
subtitles.add(new SubsceneSubtitleDescriptor(name, language, subtitlePage));
}
} catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Cannot parse subtitle node", e);
}
}
return subtitles;
}
protected Document getSubtitleListDocument(URL subtitleListUrl, String languageFilter) throws IOException, SAXException {
URLConnection connection = subtitleListUrl.openConnection();
if (languageFilter != null) {
connection.addRequestProperty("Cookie", "Filter=" + languageFilter);
}
return getHtmlDocument(connection);
}
@SuppressWarnings("unchecked")
protected String getLanguageFilter(String languageName) throws IOException, SAXException {
if (languageName == null || languageName.isEmpty()) {
return null;
}
// try cache first
Cache cache = Cache.getCache("web-datasource-lv2");
String cacheKey = getClass().getName() + ".languageFilter";
Map<String, String> filters = cache.get(cacheKey, Map.class);
if (filters != null) {
return filters.get(languageName.toLowerCase());
}
// fetch new language filter data
filters = getLanguageFilterMap();
// update cache after sanity check
if (filters.size() > 42) {
cache.put(cacheKey, filters);
} else {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to scrape language filters: " + filters);
}
return filters.get(languageName.toLowerCase());
}
protected Map<String, String> getLanguageFilterMap() throws IOException, SAXException {
Map<String, String> filters = new HashMap<String, String>(50);
Document dom = getHtmlDocument(new URL("http://subscene.com/filter"));
List<Node> checkboxes = selectNodes("//INPUT[@type='checkbox']", dom);
for (Node checkbox : checkboxes) {
String filter = getAttribute("value", checkbox);
if (filter != null) {
String name = selectString("./following::LABEL", checkbox);
filters.put(name.toLowerCase(), filter);
}
}
return filters;
}
@Override
public URI getSubtitleListLink(SearchResult searchResult, String languageName) {
return ((HyperLink) searchResult).getURI();
}
public static class SubsceneSearchResult extends HyperLink {
private String shortName;
public SubsceneSearchResult(String shortName, String title, URL url) {
super(title, url);
this.shortName = shortName;
}
@Override
public String getName() {
return shortName;
}
@Override
public String toString() {
return super.getName();
}
}
}

View File

@ -1,96 +0,0 @@
package net.sourceforge.filebot.web;
import static java.util.Collections.*;
import static net.sourceforge.tuned.XPathUtilities.*;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class SubsceneSubtitleDescriptor implements SubtitleDescriptor {
private String title;
private String language;
private URL subtitlePage;
public SubsceneSubtitleDescriptor(String title, String language, URL subtitlePage) {
this.title = title;
this.language = language;
this.subtitlePage = subtitlePage;
}
@Override
public String getName() {
return title;
}
@Override
public String getLanguageName() {
return language;
}
@Override
public String getType() {
return null;
}
@Override
public ByteBuffer fetch() throws Exception {
return WebRequest.fetch(getDownloadLink(), 0, singletonMap("Referer", subtitlePage.toString()));
}
private URL getDownloadLink() throws IOException, SAXException {
Document page = WebRequest.getHtmlDocument(subtitlePage);
String file = selectString("id('downloadButton')/@href", page);
return new URL(subtitlePage.getProtocol(), subtitlePage.getHost(), file);
}
@Override
public String getPath() {
return getName();
}
@Override
public long getLength() {
return -1;
}
@Override
public int hashCode() {
return subtitlePage.getPath().hashCode();
}
@Override
public boolean equals(Object object) {
if (object instanceof SubsceneSubtitleDescriptor) {
SubsceneSubtitleDescriptor other = (SubsceneSubtitleDescriptor) object;
return subtitlePage.getPath().equals(other.getPath());
}
return false;
}
@Override
public String toString() {
return String.format("%s [%s]", getName(), getLanguageName());
}
}

View File

@ -1,108 +0,0 @@
package net.sourceforge.filebot.web;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import net.sublight.webservice.Subtitle;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SublightSubtitleClientTest {
private static SublightSubtitleClient client = new SublightSubtitleClient();
@BeforeClass
public static void login() {
client.setClient("SublightCmd", "12c72276-b95f-4144-bb2a-879775c71437");
client.setUser("filebot-test", "correcthorsebatterystaple");
client.login();
}
@Test
public void search() {
List<SearchResult> list = client.search("babylon 5");
Movie sample = (Movie) list.get(0);
// check sample entry
assertEquals("Babylon 5", sample.getName());
assertEquals(105946, sample.getImdbId());
// check size
assertEquals(8, list.size());
}
@Test
public void getSubtitleListEnglish() {
List<SubtitleDescriptor> list = client.getSubtitleList(new Movie("Heroes", 2006, 813715, -1), "English");
SubtitleDescriptor sample = list.get(0);
assertEquals("English", sample.getLanguageName());
// check size
assertTrue(list.size() > 45);
}
@Test
public void getSubtitleListAllLanguages() {
List<SubtitleDescriptor> list = client.getSubtitleList(new Movie("Terminator 2", 1991, 103064, -1), "Croatian");
SubtitleDescriptor sample = list.get(0);
assertEquals("Terminator.2-Judgment.Day[1991]DvDrip-aXXo", sample.getName());
assertEquals("Croatian", sample.getLanguageName());
}
@Test
public void getSubtitleListVideoHash() throws Exception {
List<Subtitle> list = client.getSubtitleList("001c6e0000320458004ee6f6859e5b7844767d44336e5624edbb", null, null, "English");
Subtitle sample = list.get(0);
assertEquals("Jurassic Park", sample.getTitle());
assertEquals("Jurassic.Park[1993]DvDrip-aXXo", sample.getRelease());
assertEquals(true, sample.isIsLinked());
}
@Test
public void getZipArchive() throws Exception {
Subtitle subtitle = new Subtitle();
subtitle.setSubtitleID("1b4e9868-dded-49d0-b6e2-2d145328f6d4");
byte[] zip = client.getZipArchive(subtitle);
// read first zip entry
ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(zip));
try {
ZipEntry entry = zipInputStream.getNextEntry();
assertEquals("Terminator The Sarah Connor Chronicles.srt", entry.getName());
assertEquals(38959, entry.getSize(), 0);
} finally {
zipInputStream.close();
}
}
@AfterClass
public static void logout() {
// logout manually
client.logout();
}
}

View File

@ -1,113 +0,0 @@
package net.sourceforge.filebot.web;
import static org.junit.Assert.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import net.sourceforge.filebot.vfs.ArchiveType;
import net.sourceforge.filebot.vfs.MemoryFile;
import net.sourceforge.filebot.web.SubsceneSubtitleClient.SubsceneSearchResult;
import org.junit.BeforeClass;
import org.junit.Test;
public class SubsceneSubtitleClientTest {
/**
* Twin Peaks - First Season, ~ 15 subtitles
*/
private static HyperLink twinpeaksSearchResult;
/**
* Lost - Fourth Season, ~ 430 subtitles
*/
private static HyperLink lostSearchResult;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
twinpeaksSearchResult = new SubsceneSearchResult("Twin Peaks", "Twin Peaks - First Season (1990)", new URL("http://subscene.com/subtitles/twin-peaks-first-season"));
lostSearchResult = new SubsceneSearchResult("Lost", "Lost - Fourth Season (2008)", new URL("http://subscene.com/subtitles/lost-fourth-season"));
}
private SubsceneSubtitleClient subscene = new SubsceneSubtitleClient();
@Test
public void search() throws Exception {
List<SearchResult> results = subscene.search("twin peaks");
SubsceneSearchResult result = (SubsceneSearchResult) results.get(0);
assertEquals(twinpeaksSearchResult.toString(), result.toString());
assertEquals(twinpeaksSearchResult.getURL().toString(), result.getURL().toString());
assertEquals(twinpeaksSearchResult.getName(), result.getName());
}
@Test
public void search2() throws Exception {
List<SearchResult> results = subscene.search("firefly");
SubsceneSearchResult result = (SubsceneSearchResult) results.get(0);
assertEquals("Firefly - The Complete Series (2002)", result.toString());
assertEquals("Firefly", result.getName());
assertEquals("http://subscene.com/subtitles/firefly-the-complete-series", result.getURL().toString());
}
@Test
public void getSubtitleListSearchResult() throws Exception {
List<SubtitleDescriptor> subtitleList = subscene.getSubtitleList(twinpeaksSearchResult, "Italian");
assertEquals(10, subtitleList.size());
SubtitleDescriptor subtitle = subtitleList.get(0);
assertEquals("Twin-Peaks-S01E00-Pilot-eAlternate-ita sub by IScrew [www.ITALIANSHARE.net]", subtitle.getName());
assertEquals("Italian", subtitle.getLanguageName());
}
@Test
public void getSubtitleListSearchResultMany() throws Exception {
List<SubtitleDescriptor> subtitleList = subscene.getSubtitleList(lostSearchResult, "Japanese");
// lots of subtitles, but only a few Japanese ones
assertEquals(16, subtitleList.size());
}
@Test
public void getLanguageFilterMap() throws Exception {
Map<String, String> filters = subscene.getLanguageFilterMap();
assertEquals("1", filters.get("albanian"));
assertEquals("13", filters.get("english"));
assertEquals("17", filters.get("finnish"));
assertEquals("45", filters.get("vietnamese"));
}
@Test
public void getSubtitleListLink() throws Exception {
assertEquals(twinpeaksSearchResult.getURL().toString(), subscene.getSubtitleListLink(twinpeaksSearchResult, null).toURL().toString());
}
@Test
public void downloadSubtitleArchive() throws Exception {
SearchResult selectedResult = subscene.search("firefly").get(0);
SubtitleDescriptor subtitleDescriptor = subscene.getSubtitleList(selectedResult, "English").get(0);
assertEquals("Firefly The Complete Series", subtitleDescriptor.getName());
ByteBuffer data = subtitleDescriptor.fetch();
Iterable<MemoryFile> archive = ArchiveType.RAR.fromData(data);
MemoryFile file = archive.iterator().next();
assertEquals("Firefly - 1x01 - Serenity.srt", file.getName());
}
}

View File

@ -1,15 +1,11 @@
package net.sourceforge.filebot.web; package net.sourceforge.filebot.web;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses( { AnidbClientTest.class, TVRageClientTest.class, TheTVDBClientTest.class, SerienjunkiesClientTest.class, TMDbClientTest.class, IMDbClientTest.class, SubsceneSubtitleClientTest.class, SublightSubtitleClientTest.class, @SuiteClasses({ AnidbClientTest.class, TVRageClientTest.class, TheTVDBClientTest.class, SerienjunkiesClientTest.class, TMDbClientTest.class, IMDbClientTest.class, OpenSubtitlesXmlRpcTest.class })
OpenSubtitlesXmlRpcTest.class })
public class WebTestSuite { public class WebTestSuite {
} }