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 = '<title>(.*?) ?:.*?</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 = '<td>.*?<a href="(.*?)".*?<img src="(.*?)" \\/>.*?<h4>.*?>(.*?)<\\/a><\\/h4>.*?<div class="date">(.*?)<\\/div>'
    final JSON_REGEX = 'var videoListJSON = (\\{.*?](?=\\};))'
    
    int getVersion()
    {
        return 1
    }
    
    int getExtractItemsTimeout()
    {
        return 30
    }
    
    WebResourceContainer errorHandlerWRC(String e)
    {
        List<WebResourceItem> 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<WebResourceItem> 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<String,String> additionalInfo = new HashMap<String, String>();
            
                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<ContentURLContainer> 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 ""
            }
        }   
    }
}