From 70adfa0b0f2517456fbd54a7693fe051501d174b Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Tue, 20 Dec 2011 02:37:36 +0000 Subject: [PATCH] * api support for thetvdb banners --- .../filebot/cli/ScriptShell.lib.groovy | 7 ++ .../filebot/web/TheTVDBClient.java | 96 +++++++++++++++++++ .../net/sourceforge/tuned/FileUtilities.java | 22 +++++ .../filebot/web/TheTVDBClientTest.java | 46 +++++++-- 4 files changed, 161 insertions(+), 10 deletions(-) diff --git a/source/net/sourceforge/filebot/cli/ScriptShell.lib.groovy b/source/net/sourceforge/filebot/cli/ScriptShell.lib.groovy index d757b47a..822a868e 100644 --- a/source/net/sourceforge/filebot/cli/ScriptShell.lib.groovy +++ b/source/net/sourceforge/filebot/cli/ScriptShell.lib.groovy @@ -40,6 +40,13 @@ List.metaClass.mapByFolder = { mapByFolder(delegate) } List.metaClass.mapByExtension = { mapByExtension(delegate) } +// WebRequest utility methods +import static net.sourceforge.filebot.web.WebRequest.* + +URL.metaClass.parseHtml = { new XmlParser(false, false).parseText(getXmlString(getHtmlDocument(delegate))) }; +URL.metaClass.saveAs = { f -> writeFile(fetch(delegate), f) } + + // Shell helper import static com.sun.jna.Platform.*; diff --git a/source/net/sourceforge/filebot/web/TheTVDBClient.java b/source/net/sourceforge/filebot/web/TheTVDBClient.java index 751143ea..cec2aa92 100644 --- a/source/net/sourceforge/filebot/web/TheTVDBClient.java +++ b/source/net/sourceforge/filebot/web/TheTVDBClient.java @@ -361,4 +361,100 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { } + + /** + * Search for a series banner matching the given parameters + * + * @see http://thetvdb.com/wiki/index.php/API:banners.xml + */ + public Map getBanner(TheTVDBSearchResult series, String bannerType, String bannerType2, Integer season, String language) throws Exception { + // build selector + Map selector = new EnumMap(BannerProperty.class); + if (bannerType != null) + selector.put(BannerProperty.BannerType, bannerType); + if (bannerType2 != null) + selector.put(BannerProperty.BannerType2, bannerType2); + if (season != null) + selector.put(BannerProperty.Season, new Double(season)); + if (language != null) + selector.put(BannerProperty.Language, language); + + // search for a banner matching the selector + for (Map it : getBannerDescriptor(series.seriesId)) { + if (it.entrySet().containsAll(selector.entrySet())) { + return it; + } + } + + return null; + } + + + public List> getBannerDescriptor(int seriesid) throws Exception { + Document dom = getDocument(getResource(MirrorType.XML, "/api/" + apikey + "/series/" + seriesid + "/banners.xml")); + + List nodes = selectNodes("//Banner", dom); + List> banners = new ArrayList>(); + + for (Node node : nodes) { + try { + EnumMap item = new EnumMap(BannerProperty.class); + + // copy values from xml + for (BannerProperty key : BannerProperty.values()) { + String value = getTextContent(key.name(), node); + if (value != null && value.length() > 0) { + item.put(key, getTextContent(key.name(), node)); + } + } + + // parse numbers + for (BannerProperty key : BannerProperty.numbers()) { + if (item.get(key) != null) { + item.put(key, new Double(item.get(key).toString())); + } + } + + // resolve relative urls + for (BannerProperty key : BannerProperty.urls()) { + if (item.get(key) != null) { + item.put(key, getResource(MirrorType.BANNER, "/banners/" + item.get(key))); + } + } + + banners.add(item); + } catch (Exception e) { + // log and ignore + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Invalid banner descriptor", e); + } + } + + return banners; + } + + + public static enum BannerProperty { + id, + BannerPath, + BannerType, + BannerType2, + Season, + Colors, + Language, + Rating, + RatingCount, + SeriesName, + ThumbnailPath, + VignettePath; + + public static BannerProperty[] numbers() { + return new BannerProperty[] { id, Season, Rating, RatingCount }; + } + + + public static BannerProperty[] urls() { + return new BannerProperty[] { BannerPath, ThumbnailPath, VignettePath }; + } + } + } diff --git a/source/net/sourceforge/tuned/FileUtilities.java b/source/net/sourceforge/tuned/FileUtilities.java index 300774cb..3934fd06 100644 --- a/source/net/sourceforge/tuned/FileUtilities.java +++ b/source/net/sourceforge/tuned/FileUtilities.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; @@ -27,6 +28,15 @@ import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; + import com.ibm.icu.text.CharsetDetector; import com.ibm.icu.text.CharsetMatch; @@ -461,6 +471,18 @@ public final class FileUtilities { } + public static String getXmlString(Document dom) throws TransformerException { + Transformer tr = TransformerFactory.newInstance().newTransformer(); + tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + tr.setOutputProperty(OutputKeys.INDENT, "yes"); + + //create string from dom + StringWriter buffer = new StringWriter(); + tr.transform(new DOMSource(dom), new StreamResult(buffer)); + return buffer.toString(); + } + + public static final long KILO = 1024; public static final long MEGA = KILO * 1024; public static final long GIGA = MEGA * 1024; diff --git a/test/net/sourceforge/filebot/web/TheTVDBClientTest.java b/test/net/sourceforge/filebot/web/TheTVDBClientTest.java index 3a6856e6..9b0f5e74 100644 --- a/test/net/sourceforge/filebot/web/TheTVDBClientTest.java +++ b/test/net/sourceforge/filebot/web/TheTVDBClientTest.java @@ -4,15 +4,18 @@ package net.sourceforge.filebot.web; import static org.junit.Assert.*; +import java.net.URL; import java.util.EnumSet; import java.util.List; import java.util.Locale; +import java.util.Map; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import net.sf.ehcache.CacheManager; +import net.sourceforge.filebot.web.TheTVDBClient.BannerProperty; import net.sourceforge.filebot.web.TheTVDBClient.MirrorType; import net.sourceforge.filebot.web.TheTVDBClient.TheTVDBSearchResult; @@ -21,7 +24,7 @@ public class TheTVDBClientTest { private TheTVDBClient thetvdb = new TheTVDBClient("BA864DEE427E384A"); - + @Test public void search() throws Exception { // test default language and query escaping (blanks) @@ -35,7 +38,7 @@ public class TheTVDBClientTest { assertEquals(70726, first.getSeriesId()); } - + @Test public void searchGerman() throws Exception { List results = thetvdb.search("Buffy the Vampire Slayer", Locale.GERMAN); @@ -48,7 +51,7 @@ public class TheTVDBClientTest { assertEquals(70327, first.getSeriesId()); } - + @Test public void getEpisodeListAll() throws Exception { List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327)); @@ -76,7 +79,7 @@ public class TheTVDBClientTest { assertEquals(null, last.airdate()); } - + @Test public void getEpisodeListSingleSeason() throws Exception { List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Wonderfalls", 78845), 1); @@ -94,7 +97,7 @@ public class TheTVDBClientTest { assertEquals("2004-03-12", first.airdate().toString()); } - + @Test public void getEpisodeListNumbering() throws Exception { List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Firefly", 78874), 1); @@ -111,19 +114,19 @@ public class TheTVDBClientTest { assertEquals("2002-12-20", first.airdate().toString()); } - + @Test public void getEpisodeListLink() { assertEquals("http://www.thetvdb.com/?tab=seasonall&id=78874", thetvdb.getEpisodeListLink(new TheTVDBSearchResult("Firefly", 78874)).toString()); } - + @Test public void getEpisodeListLinkSingleSeason() { assertEquals("http://www.thetvdb.com/?tab=season&seriesid=73965&seasonid=6749", thetvdb.getEpisodeListLink(new TheTVDBSearchResult("Roswell", 73965), 3).toString()); } - + @Test public void getMirror() throws Exception { assertNotNull(thetvdb.getMirror(MirrorType.XML)); @@ -131,7 +134,7 @@ public class TheTVDBClientTest { assertNotNull(thetvdb.getMirror(MirrorType.ZIP)); } - + @Test public void resolveTypeMask() { // no flags set @@ -144,7 +147,30 @@ public class TheTVDBClientTest { assertEquals(EnumSet.allOf(MirrorType.class), MirrorType.fromTypeMask(7)); } - + + @Test + public void getBanner() throws Exception { + Map banner = thetvdb.getBanner(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327), "season", "seasonwide", 7, "en"); + + assertEquals(857660, (Double) banner.get(BannerProperty.id), 0); + assertEquals("season", banner.get(BannerProperty.BannerType)); + assertEquals("seasonwide", banner.get(BannerProperty.BannerType2)); + assertEquals("http://thetvdb.com/banners/seasonswide/70327-7.jpg", banner.get(BannerProperty.BannerPath).toString()); + assertEquals(99712, WebRequest.fetch((URL) banner.get(BannerProperty.BannerPath)).remaining(), 0); + } + + + @Test + public void getBannerDescriptor() throws Exception { + List> banners = thetvdb.getBannerDescriptor(70327); + + assertEquals(106, banners.size()); + assertEquals("fanart", banners.get(0).get(BannerProperty.BannerType)); + assertEquals("1280x720", banners.get(0).get(BannerProperty.BannerType2)); + assertEquals(486993, WebRequest.fetch((URL) banners.get(0).get(BannerProperty.BannerPath)).remaining(), 0); + } + + @BeforeClass @AfterClass public static void clearCache() {