From 39dd413eec022efa7a5f07cdf727942df5de24eb Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Tue, 20 Oct 2009 21:16:34 +0000 Subject: [PATCH] * improved subtitle api and video hash support --- lib/sublight-ws.jar | Bin 141003 -> 141077 bytes .../ui/panel/subtitle/SubtitleUtilities.java | 41 ------- .../web/MovieIdentificationService.java | 11 ++ .../filebot/web/OpenSubtitlesClient.java | 105 +++++++++++++++++- .../filebot/web/OpenSubtitlesHasher.java | 2 - .../filebot/web/OpenSubtitlesXmlRpc.java | 40 ++++--- .../filebot/web/SublightSubtitleClient.java | 93 ++++++++++++---- .../web/SubsceneSubtitleDescriptor.java | 13 ++- .../web/SubtitleSourceSubtitleDescriptor.java | 8 +- .../filebot/web/VideoHashSubtitleService.java | 17 +++ .../net/sourceforge/tuned/FileUtilities.java | 23 ++++ .../filebot/web/OpenSubtitlesXmlRpcTest.java | 16 +-- 12 files changed, 269 insertions(+), 100 deletions(-) create mode 100644 source/net/sourceforge/filebot/web/MovieIdentificationService.java create mode 100644 source/net/sourceforge/filebot/web/VideoHashSubtitleService.java diff --git a/lib/sublight-ws.jar b/lib/sublight-ws.jar index 6efce7fbac7bff8068ad85dde431e4a005657aaf..6e668239ce0e13176956ee6cceafaf3f7b350c85 100644 GIT binary patch delta 13306 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
kTO}{nbwcuJnHu4ClgrVKZS=v1Qx87n zul2p3tIu!ZY8+D^VlceXAhtc$TR1PNq|U`}meSAOZ9D#0n9HwB;8%p8pWc$hb3}N} zb*o{{>Lj9J&HmlGH^LpY?m1fAh3i|j8$a&eTAk}Q*d9@K7MQ(WTCzs0$(WPS40xxV z?{|~PgV0tlZYfb|@^?+~o4kp}Cc0}4Kg(}Yzc`@U#$xrQ``ME6w?d-u@7HWe?Aedh zM!FJVrv^8)(lr;nRs-bgGJEo`Os<589(gm?_t?$-MBS772W-t_80t(+@6{_ihcr#E zeB2*6t@N}drp2$e<=Be%@W%3>?^n7L-cx%&&1T>$^nNNnQf;TbQYo@KP85Cq<%&lF z{l)mNQbUzZ)@52z)dzcsV#ndvzPbwN+}(OSzE_zz7?{Bw@@9N6kAuVN2ydAsu|dyw z!@qL6)z%vmtx(#eZnmi#>#;t8I@yu$7(V6XP+D4cS8W{?Ixc&TX-2NmF3Nra_x80{ zwk@i;pX0hauV?I9>XV6&4420C7=7Y&T6}yW#)4p6IYl?Ss4+$x(lD*Sn4otF@q0*A z_TB4oU!N?N7H-tHUw#Rt_{Zsh4oqOUY9<}%=cDXcjfKFwU6g(5kn3{bQ*bNdycsBt z*OdZyi?_`{1GHNtwft}A|JDkuL)diN|MtYK4q!L5w_mv8_mF(=Ck4D9B#wV74HK>M zeFyYG8*zx`Zq9a4*-F{?x!M5+{4N<7N7a@00CWqa%CQ&Vhqhn(w8rSKAh#B}f`q5A z`($8TRptG_cPN2J9{}hUP*w9F5Cd&orX#>SBxy|mJdk8L33?@80ITwz2IMKWc-#!2 z`R6VgzJCTdL?+;Qz5;tF!qKmQCb>R%Fbe|;^7<>_L=h0*05^(|_zke8_y{c+jlk#6 z0{r;j->8nXW`WZbQuZuhLlM6J53!n~st9v{GeyNa54cl=$ayL<@;}6A0XRodl`c@j zb1VX`6eM^NKv9H&MZlXPAeX4f<0UG>PXfFss;eZxiXwa<0jDT}`Z86xwG5o4AnVJ3 z14Xd?P7U$mI~C#o0i2Xj&RR-%+f~2*6Mj zVK)p06(Jr5J4ZnlU@)i^NLs2@0WAzF?p;qDJn5oVB%1n)L zn1vc4j|FB;xzO;BYgGU%OkV=5hSuQh%Ng=&a0$HVAoGtap7*Xq_TXLFVB+|ztS}x5 zweter1-iyTL!-2VdZUj*#d7v@;jufxLzLF%vcZI5kA|VF2H9Xd6m*GI% zVLamGR+BH4uz!>1fUe8`<2rcu50x3aJAj<)azq2dvkjN|v?Cxa_N>@@U zxt9x!S^OP)1Q5d3tuW&Kxu{M4bA{$V?a*DJvibhH86mqdTcar2*EsQQ!Z2v4{Jm*I zL!-E((&C#GcJ3w*J`zr4|Gj_nZ}y{YG8?>+!=v=CvT4Qj=9$QXHMt7*xay7&A9?WI z{4gQ%yEP;J9Y4T<-z7qA9^e{yR1P$X1&t2uFtX&|X~c*37o?_lGlgV!3^eKijkI?d zwF&Mt;>3sZ!h|Rta=9e5jR`a|0*(H8)B4^Of8l=^S@6K*C_NIv1D3K&^pA@3Z_>UZ zjK-XxD_hW&%8vMQ5`XyofAjrUx%zJnhl^@q=e2TvWK5kbi}_5|Jz1_qG^gY29@ zyAXejIPv)isu3mWU%X(_{<37fFdoAPW5sLp!MG_ZOFmGQC;vxOpaCU;PQ+!GCU69w14rJ@R?aE^;Y(1wxPswe8+#x$iytOHSpxo?fBa_(Sc9Vg zrbRL35CBcD9w3{_k#CIuV@?E;RXOTpl?1+6047LD>#b#$>~k=!Q~&Y$>JUUdtOa@z z7oiT8zvn3bUSpcI|L~dc9)i@>E>aMTs-X7|)l)s-A8XziS-*DpANnZpXy)&t{O1$~ z%y0jW&L--UjleP+0D}LSJxQ>kdh+>5F=%#ZhgmoBj~O?9eiuxLQa2VMFpX71JRl18 zbf6Ky_aBeHq8^^R01hA_hJTN`S(86zocLlPs>iovj|4MFrDP6p{dZv$1{upI{xDdu z{c8W{uV}KG;UuI+p9FX)%MT^nL9%MU4Ot~cnMV{&ebIjCkoT2aQ>b#{dwF;8MhwPJLH)_-h987hh{43f$^RJf_c-d`6T=Em5`*bbO!tX{rpys!Qz`P16x6mv zGRhhG2W7yI+7ksjy>g6kdU-idO-a zztzr{0KEjoK`Qbg7XFI_byDv*<=WxODd8V{9Z49Rl8~h&=*qkBk4l(=mXJ}MW-=;* zKP&|PhbF9k+TZG%*sQZR8!E@ILk`k(_sl{&$x>Mcz*2q&w$y8ft`@%7Tw!9GM* z&39A7$WZr)&rw(STEL7jU`9K4BidewiUD8T{?7HkFK_=I2_pSuz5;$!1_q5^R?fzh zR?u}i=z8ZKV2S5Kz>ZQX@}S|Ao*_txXQH8z+EEezL9#z#d@2IQN1?)MaLYv?6$w7K z?A}5BF$_`15Y$1p2^zw_jFVRpA$%hE0*gPqo7!78_fhNQ|8t1}J?-qR^)G+;vJ&J` fA38U_J^==j1L->lA= 0) { - position += read; - } - - return data; - } finally { - in.close(); - } - } - - /** * Write {@link ByteBuffer} to {@link File}. */ diff --git a/source/net/sourceforge/filebot/web/MovieIdentificationService.java b/source/net/sourceforge/filebot/web/MovieIdentificationService.java new file mode 100644 index 00000000..4523d60d --- /dev/null +++ b/source/net/sourceforge/filebot/web/MovieIdentificationService.java @@ -0,0 +1,11 @@ + +package net.sourceforge.filebot.web; + + +import java.io.File; + + +public interface MovieIdentificationService { + + public MovieDescriptor[] getMovieDescriptors(File[] movieFiles) throws Exception; +} diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java index 6d0ab388..9e95a8a0 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java @@ -2,7 +2,14 @@ package net.sourceforge.filebot.web; +import java.io.File; +import java.math.BigInteger; import java.net.URI; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -14,13 +21,14 @@ import java.util.logging.Logger; import javax.swing.Icon; import net.sourceforge.filebot.ResourceManager; +import net.sourceforge.filebot.web.OpenSubtitlesXmlRpc.Query; import net.sourceforge.tuned.Timer; /** * SubtitleClient for OpenSubtitles. */ -public class OpenSubtitlesClient implements SubtitleProvider { +public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleService, MovieIdentificationService { private final OpenSubtitlesXmlRpc xmlrpc; @@ -56,12 +64,12 @@ public class OpenSubtitlesClient implements SubtitleProvider { @Override public List getSubtitleList(SearchResult searchResult, String languageName) throws Exception { - // require login - login(); - // singleton array with or empty array String[] languageFilter = languageName != null ? new String[] { getSubLanguageID(languageName) } : new String[0]; + // require login + login(); + @SuppressWarnings("unchecked") List subtitles = (List) xmlrpc.searchSubtitles(((MovieDescriptor) searchResult).getImdbId(), languageFilter); @@ -69,6 +77,95 @@ public class OpenSubtitlesClient implements SubtitleProvider { } + public Map> getSubtitleList(File[] files, String languageName) throws Exception { + // singleton array with or empty array + String[] languageFilter = languageName != null ? new String[] { getSubLanguageID(languageName) } : new String[0]; + + // remember hash for each file + Map hashMap = new HashMap(files.length); + Map> resultMap = new HashMap>(files.length); + + // create hash query for each file + List queryList = new ArrayList(files.length); + + for (File file : files) { + String movieHash = OpenSubtitlesHasher.computeHash(file); + + // add query + queryList.add(Query.forHash(movieHash, file.length(), languageFilter)); + + // prepare result map + hashMap.put(movieHash, file); + resultMap.put(file, new LinkedList()); + } + + // require login + login(); + + // submit query and map results to given files + for (OpenSubtitlesSubtitleDescriptor subtitle : xmlrpc.searchSubtitles(queryList)) { + // get file for hash + File file = hashMap.get(subtitle.getMovieHash()); + + // add subtitle + resultMap.get(file).add(subtitle); + } + + return resultMap; + } + + + @Override + public boolean publishSubtitle(int imdbid, String languageName, File videoFile, File subtitleFile) throws Exception { + //TODO implement upload feature + return false; + } + + + /** + * Calculate MD5 hash. + */ + private String md5(byte[] data) { + try { + MessageDigest hash = MessageDigest.getInstance("MD5"); + hash.update(data); + + // return hex string + return String.format("%032x", new BigInteger(1, hash.digest())); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + + @Override + public MovieDescriptor[] getMovieDescriptors(File[] movieFiles) throws Exception { + // create result array + MovieDescriptor[] result = new MovieDescriptor[movieFiles.length]; + + // compute movie hashes + Map indexMap = new HashMap(movieFiles.length); + + for (int i = 0; i < movieFiles.length; i++) { + String hash = OpenSubtitlesHasher.computeHash(movieFiles[i]); + + // remember original index + indexMap.put(hash, i); + } + + // require login + login(); + + // dispatch single query for all hashes + for (Entry entry : xmlrpc.checkMovieHash(indexMap.keySet()).entrySet()) { + int index = indexMap.get(entry.getKey()); + result[index] = entry.getValue(); + } + + return result; + } + + @Override public URI getSubtitleListLink(SearchResult searchResult, String languageName) { MovieDescriptor movie = (MovieDescriptor) searchResult; diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java b/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java index 3655c002..43192789 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java @@ -45,7 +45,6 @@ public final class OpenSubtitlesHasher { public static String computeHash(InputStream stream, long length) throws IOException { - int chunkSizeForFile = (int) Math.min(HASH_CHUNK_SIZE, length); // buffer that will contain the head and the tail chunk, chunks will overlap if length is smaller than two chunks @@ -73,7 +72,6 @@ public final class OpenSubtitlesHasher { private static long computeHashForChunk(ByteBuffer buffer) { - LongBuffer longBuffer = buffer.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer(); long hash = 0; diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java b/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java index 9746ba37..58471f5b 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java @@ -5,11 +5,11 @@ package net.sourceforge.filebot.web; import static java.util.Collections.*; import static net.sourceforge.tuned.StringUtilities.*; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -26,7 +26,6 @@ import redstone.xmlrpc.XmlRpcFault; import redstone.xmlrpc.util.Base64; import net.sourceforge.filebot.web.OpenSubtitlesSubtitleDescriptor.Property; -import net.sourceforge.tuned.ByteBufferInputStream; import net.sourceforge.tuned.ByteBufferOutputStream; @@ -111,13 +110,17 @@ public class OpenSubtitlesXmlRpc { @SuppressWarnings("unchecked") public List searchSubtitles(Collection queryList) throws XmlRpcFault { + List subtitles = new ArrayList(); Map response = invoke("SearchSubtitles", token, queryList); - List> subtitleData = (List>) response.get("data"); - List subtitles = new ArrayList(); - - for (Map propertyMap : subtitleData) { - subtitles.add(new OpenSubtitlesSubtitleDescriptor(Property.asEnumMap(propertyMap))); + try { + List> subtitleData = (List>) response.get("data"); + + for (Map propertyMap : subtitleData) { + subtitles.add(new OpenSubtitlesSubtitleDescriptor(Property.asEnumMap(propertyMap))); + } + } catch (ClassCastException e) { + // no subtitle have been found } return subtitles; @@ -179,7 +182,7 @@ public class OpenSubtitlesXmlRpc { @SuppressWarnings("unchecked") - public List detectLanguage(ByteBuffer data) throws XmlRpcFault { + public List detectLanguage(byte[] data) throws XmlRpcFault { // compress and base64 encode String parameter = encodeData(data); @@ -211,16 +214,23 @@ public class OpenSubtitlesXmlRpc { @SuppressWarnings("unchecked") - public Map> checkMovieHash(Collection hashes) throws XmlRpcFault { + public Map checkMovieHash(Collection hashes) throws XmlRpcFault { Map response = invoke("CheckMovieHash", token, hashes); Map movieHashData = (Map) response.get("data"); - Map> movieHashMap = new HashMap>(); + Map movieHashMap = new HashMap(); for (Entry entry : movieHashData.entrySet()) { // empty associative arrays are deserialized as array, not as map if (entry.getValue() instanceof Map) { - movieHashMap.put(entry.getKey(), Property.asEnumMap((Map) entry.getValue())); + Map info = (Map) entry.getValue(); + + String hash = info.get("MovieHash"); + String name = info.get("MovieName"); + int year = Integer.parseInt(info.get("MovieYear")); + int imdb = Integer.parseInt(info.get("MovieImdbID")); + + movieHashMap.put(hash, new MovieDescriptor(name, year, imdb)); } } @@ -281,12 +291,12 @@ public class OpenSubtitlesXmlRpc { } - protected static String encodeData(ByteBuffer data) { + protected static String encodeData(byte[] data) { try { - DeflaterInputStream compressedDataStream = new DeflaterInputStream(new ByteBufferInputStream(data)); + DeflaterInputStream compressedDataStream = new DeflaterInputStream(new ByteArrayInputStream(data)); // compress data - ByteBufferOutputStream buffer = new ByteBufferOutputStream(data.remaining()); + ByteBufferOutputStream buffer = new ByteBufferOutputStream(data.length); buffer.transferFully(compressedDataStream); // base64 encode @@ -416,7 +426,7 @@ public class OpenSubtitlesXmlRpc { } - public void setSubContent(ByteBuffer data) { + public void setSubContent(byte[] data) { put("subcontent", encodeData(data)); } } diff --git a/source/net/sourceforge/filebot/web/SublightSubtitleClient.java b/source/net/sourceforge/filebot/web/SublightSubtitleClient.java index c6ae0cb4..3140c599 100644 --- a/source/net/sourceforge/filebot/web/SublightSubtitleClient.java +++ b/source/net/sourceforge/filebot/web/SublightSubtitleClient.java @@ -10,7 +10,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.AbstractMap.SimpleEntry; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; @@ -36,7 +35,7 @@ import net.sublight.webservice.SubtitlesAPI2; import net.sublight.webservice.SubtitlesAPI2Soap; -public class SublightSubtitleClient implements SubtitleProvider { +public class SublightSubtitleClient implements SubtitleProvider, VideoHashSubtitleService { private static final String iid = "42cc1701-3752-49e2-a148-332960073452"; @@ -108,15 +107,31 @@ public class SublightSubtitleClient implements SubtitleProvider { } + public Map> getSubtitleList(File[] files, final String languageName) throws Exception { + Map> subtitles = new HashMap>(files.length); + + for (final File file : files) { + subtitles.put(file, getSubtitleList(file, languageName)); + } + + return subtitles; + } + + public List getSubtitleList(File videoFile, String languageName) throws WebServiceException, IOException { List subtitles = new ArrayList(); - // retrieve subtitles by video hash - for (Subtitle subtitle : getSubtitleList(SublightVideoHasher.computeHash(videoFile), null, null, languageName)) { - // only keep linked subtitles - if (subtitle.isIsLinked()) { - subtitles.add(new SublightSubtitleDescriptor(subtitle, this)); + try { + // retrieve subtitles by video hash + for (Subtitle subtitle : getSubtitleList(SublightVideoHasher.computeHash(videoFile), null, null, languageName)) { + // only keep linked subtitles + if (subtitle.isIsLinked()) { + subtitles.add(new SublightSubtitleDescriptor(subtitle, this)); + } } + } catch (LinkageError e) { + // MediaInfo native lib not available + throw new UnsupportedOperationException(e); } return subtitles; @@ -176,12 +191,50 @@ public class SublightSubtitleClient implements SubtitleProvider { } - @SuppressWarnings("unchecked") - private static final Entry[] aliasList = new Entry[] { - new SimpleEntry(SubtitleLanguage.PORTUGUESE_BRAZIL, "Brazilian"), - new SimpleEntry(SubtitleLanguage.BOSNIAN_LATIN, "Bosnian"), - new SimpleEntry(SubtitleLanguage.SERBIAN_LATIN, "Serbian") - }; + @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 result = new Holder(); + Holder subid = new Holder(); + Holder error = new Holder(); + + // 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 getLanguageAliasMap() { + Map languages = new HashMap(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) { @@ -192,9 +245,9 @@ public class SublightSubtitleClient implements SubtitleProvider { } // check alias list - for (Entry alias : aliasList) { - if (alias.getValue().equalsIgnoreCase(languageName)) - return alias.getKey(); + for (Entry alias : getLanguageAliasMap().entrySet()) { + if (alias.getKey().equalsIgnoreCase(languageName)) + return alias.getValue(); } // illegal language name @@ -203,10 +256,10 @@ public class SublightSubtitleClient implements SubtitleProvider { protected String getLanguageName(SubtitleLanguage language) { - // check alias list - for (Entry alias : aliasList) { - if (language == alias.getKey()) - return alias.getValue(); + // check alias list first + for (Entry alias : getLanguageAliasMap().entrySet()) { + if (language == alias.getValue()) + return alias.getKey(); } // use language value by default diff --git a/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java index 1ec58002..d6624ff2 100644 --- a/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java @@ -36,23 +36,24 @@ public class SubsceneSubtitleDescriptor implements SubtitleDescriptor { } + @Override public String getLanguageName() { return language; } - @Override - public ByteBuffer fetch() throws Exception { - return WebRequest.fetch(downloadLink, singletonMap("Referer", referer.toString())); - } - - @Override public String getType() { return archiveType; } + @Override + public ByteBuffer fetch() throws Exception { + return WebRequest.fetch(downloadLink, singletonMap("Referer", referer.toString())); + } + + @Override public String toString() { return String.format("%s [%s]", getName(), getLanguageName()); diff --git a/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java index 50523b62..8cc93526 100644 --- a/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java @@ -62,14 +62,14 @@ public class SubtitleSourceSubtitleDescriptor implements SubtitleDescriptor { @Override - public ByteBuffer fetch() throws Exception { - return WebRequest.fetch(downloadLink); + public String getType() { + return "zip"; } @Override - public String getType() { - return "zip"; + public ByteBuffer fetch() throws Exception { + return WebRequest.fetch(downloadLink); } diff --git a/source/net/sourceforge/filebot/web/VideoHashSubtitleService.java b/source/net/sourceforge/filebot/web/VideoHashSubtitleService.java new file mode 100644 index 00000000..98402cea --- /dev/null +++ b/source/net/sourceforge/filebot/web/VideoHashSubtitleService.java @@ -0,0 +1,17 @@ + +package net.sourceforge.filebot.web; + + +import java.io.File; +import java.util.List; +import java.util.Map; + + +public interface VideoHashSubtitleService { + + public Map> getSubtitleList(File[] videoFiles, String languageName) throws Exception; + + + public boolean publishSubtitle(int imdbid, String languageName, File videoFile, File subtitleFile) throws Exception; + +} diff --git a/source/net/sourceforge/tuned/FileUtilities.java b/source/net/sourceforge/tuned/FileUtilities.java index 8ed95ad2..4c2ec31f 100644 --- a/source/net/sourceforge/tuned/FileUtilities.java +++ b/source/net/sourceforge/tuned/FileUtilities.java @@ -4,6 +4,9 @@ package net.sourceforge.tuned; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -13,6 +16,26 @@ import java.util.regex.Pattern; public final class FileUtilities { + public static byte[] readAll(File source) throws IOException { + InputStream in = new FileInputStream(source); + + try { + byte[] data = new byte[(int) source.length()]; + + int position = 0; + int read = 0; + + while (position < data.length && (read = in.read(data, position, data.length - position)) >= 0) { + position += read; + } + + return data; + } finally { + in.close(); + } + } + + /** * Pattern used for matching file extensions. * diff --git a/test/net/sourceforge/filebot/web/OpenSubtitlesXmlRpcTest.java b/test/net/sourceforge/filebot/web/OpenSubtitlesXmlRpcTest.java index c8e6d63c..1973b98e 100644 --- a/test/net/sourceforge/filebot/web/OpenSubtitlesXmlRpcTest.java +++ b/test/net/sourceforge/filebot/web/OpenSubtitlesXmlRpcTest.java @@ -6,7 +6,6 @@ import static java.util.Collections.*; import static org.junit.Assert.*; import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.util.List; import java.util.Map; @@ -122,20 +121,21 @@ public class OpenSubtitlesXmlRpcTest { @Test public void checkMovieHash() throws Exception { - Map> movieHashMap = xmlrpc.checkMovieHash(singleton("2bba5c34b007153b")); - Map movie = movieHashMap.values().iterator().next(); + Map results = xmlrpc.checkMovieHash(singleton("d7aa0275cace4410")); + MovieDescriptor movie = results.get("d7aa0275cace4410"); - assertEquals("\"Firefly\"", movie.get(Property.MovieName)); - assertEquals("2002", movie.get(Property.MovieYear)); + assertEquals("Iron Man", movie.getName()); + assertEquals(2008, movie.getYear()); + assertEquals(371746, movie.getImdbId()); } @Test public void checkMovieHashInvalid() throws Exception { - Map> movieHashMap = xmlrpc.checkMovieHash(singleton("0123456789abcdef")); + Map results = xmlrpc.checkMovieHash(singleton("0123456789abcdef")); // no movie info - assertTrue(movieHashMap.isEmpty()); + assertTrue(results.isEmpty()); } @@ -143,7 +143,7 @@ public class OpenSubtitlesXmlRpcTest { public void detectLanguage() throws Exception { String text = "Only those that are prepared to fire should be fired at."; - List languages = xmlrpc.detectLanguage(Charset.forName("utf-8").encode(text)); + List languages = xmlrpc.detectLanguage(text.getBytes("UTF-8")); assertEquals("eng", languages.get(0)); assertTrue(1 == languages.size());