import org.serviio.library.metadata.*
import org.serviio.library.online.*
import groovy.json.JsonSlurper
import java.net.URLEncoder
import static org.apache.commons.lang.StringEscapeUtils.*
/********************************************************************
* Discovery.com plugin for Serviio (US ONLY)
*
*
* Version:
* V1: - Initial Release by nwalk7800
* V2: - Discovery starting listing the different quality streams right in the JSON
* V3: - EPISODE_LIST location changed from science.discovery.com to www.sciencechannel.com for some episodes
* V4: - Removed playlsit from the the episode list filter and handle empty video list
*
* Must be installed as a WebResource
* Only available in US
* Sample URLs:
* http://science.discovery.com/tv-shows/how-its-made
* http://dsc.discovery.com/tv-shows/mythbusters
* http://animal.discovery.com/tv-shows/my-cat-from-hell
********************************************************************/
class Discovery extends WebResourceUrlExtractor
{
final VALID_FEED_URL = '^(?:http:\\/\\/)?(?:.*?\\.)?discovery\\.com\\/tv-shows\\/(.*?)$'
final SHOW_TITLE = '
(.*?) ?:.*?'
final EPISODE_URL = 'http://%s.discovery.com/'
// final EPISODE_LIST = 'http://science.discovery.com/services/taxonomy/%s/?num=%d&page=0&filter=clip,playlist,fullepisode&tpl=dds/modules/video/all_assets_list.html&sort=date&order=desc&feedGroup=video'
final EPISODE_LIST = 'http://www.sciencechannel.com/services/taxonomy/%s/?num=%d&page=0&filter=clip,fullepisode&tpl=dds/modules/video/all_assets_list.html&sort=date&order=desc&feedGroup=video'
final SINGLE_EPISODE = '.*?.*?.*?>(.*?)<\\/a><\\/h4>.*?(.*?)<\\/div>'
final JSON_REGEX = 'var videoListJSON = (\\{.*?](?=\\};))'
int getVersion()
{
return 1
}
int getExtractItemsTimeout()
{
return 30
}
WebResourceContainer errorHandlerWRC(String e)
{
List items = []
println e
log(e)
items << new WebResourceItem(title: e, additionalInfo: ['url':'http://error','thumbnailUrl':'http://fake.jpg'])
WebResourceContainer wrc = new WebResourceContainer(title: "Error", items: items)
return wrc
}
void errorHandler(String e)
{
println e
log(e)
return
}
String getExtractorName()
{
return 'discovery.com'
}
boolean extractorMatches(URL feedUrl)
{
return feedUrl ==~ VALID_FEED_URL
}
WebResourceContainer extractItems(URL resourceUrl, int maxItemsToRetrieve)
{
List items = []
Date releaseDate
URL urlEpisodeList
String pageContent
String strShowName
String strEpisodeURL
String strSubDomain
def jsMatcher
//Get the subdomain
jsMatcher = resourceUrl =~ 'https?:\\/\\/(.*?)\\.discovery\\.com'
strSubDomain = jsMatcher[0][1]
//Get the show title
pageContent = resourceUrl.getText()
jsMatcher = pageContent =~ SHOW_TITLE
strShowName = unescapeHtml(jsMatcher[0][1])
//Make sure there is a valid max number
if (maxItemsToRetrieve <= -1)
{
maxItemsToRetrieve=100
}
//Get the full episode list URL
urlEpisodeList = new URL(String.format(EPISODE_LIST, java.net.URLEncoder.encode(strShowName), maxItemsToRetrieve))
//println urlEpisodeList
pageContent = urlEpisodeList.getText().replaceAll("\n", "")
jsMatcher = pageContent =~ SINGLE_EPISODE
if (jsMatcher.count <= 0)
{
return errorHandlerWRC("Discovery.com: No Episodes found")
}
try
{
for (def i = 0; i < jsMatcher.count; i++)
{
Map additionalInfo = new HashMap();
strEpisodeURL = jsMatcher[i][1]
strEpisodeURL = strEpisodeURL.replaceAll('^\\/', String.format(EPISODE_URL, strSubDomain))
additionalInfo.put("url", strEpisodeURL)
additionalInfo.put("thumbnailUrl", jsMatcher[i][2])
releaseDate = Date.parse("MM/dd/yyyy", jsMatcher[i][4])
items << new WebResourceItem(title: unescapeHtml(jsMatcher[i][3]).replaceAll(".*?: ", ""), releaseDate: releaseDate, additionalInfo: additionalInfo)
}
}
catch(e)
{
errorHandlerWRC("Discovery.com: Error parsing episodes")
}
return new WebResourceContainer(title: strShowName, items: items)
}
ContentURLContainer extractUrl(WebResourceItem item, PreferredQuality requestedQuality)
{
List items = []
String pageContent
String url, concat
int intMP4
def jsMatcher
def json
def cc
def cacheKey
//Get episode page
pageContent = new URL(item.additionalInfo.url).getText().replaceAll("\n", "").replaceAll("\r", "")
//Get the chunk of json with the video info
jsMatcher = pageContent =~ JSON_REGEX
json = new JsonSlurper().parseText(jsMatcher[0][1].replaceAll(" \\/\\/.*?\"", "\"") + "}")
//Get the first clip from the JSON
//The rest are for other videos
if (Integer.valueOf(json.clips.size) >= 0)
{
intMP4 = json.clips[0].mp4.size() - 1
if (intMP4 < 0) { intMP4 = 0 }
//Get the URL for the requested quality
if (requestedQuality == PreferredQuality.HIGH)
url = json.clips[0].mp4.src[intMP4]
else if (requestedQuality == PreferredQuality.MEDIUM)
url = json.clips[0].mp4.src[(int) Math.round((double) intMP4 / 2)]
else if (requestedQuality == PreferredQuality.LOW)
url = json.clips[0].mp4.src[0]
cacheKey = "Discovery_${json.clips[0].uuid}_${requestedQuality}"
}
return new ContentURLContainer(contentUrl: url, thumbnailUrl: item.additionalInfo.thumbnailUrl, expiresImmediately: true, cacheKey: cacheKey)
}
static void main(args)
{
Discovery extractor = new Discovery()
//for testing
//println extractor.extractorMatches(new URL("http://science.discovery.com/tv-shows/how-its-made"))
//WebResourceContainer container = extractor.extractItems( new URL("http://animal.discovery.com/tv-shows/my-cat-from-hell"), 1)
//WebResourceContainer container = extractor.extractItems( new URL("http://dsc.discovery.com/tv-shows/mythbusters"), 1)
WebResourceContainer container = extractor.extractItems( new URL("http://science.discovery.com/tv-shows/how-its-made"), 5)
if (container)
{
container.getItems().each
{
ContentURLContainer result = extractor.extractUrl(it, PreferredQuality.HIGH)
println it
println ""
println result
println ""
}
}
}
} |