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
*
* 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 SINGLE_EPISODE = '<td>.*?<a href="(.*?)".*?<img src="(.*?)" \\/>.*?<h4>.*?>(.*?)<\\/a><\\/h4>.*?<div class="date">(.*?)<\\/div>'
    final JSON_REGEX = 'var videoListJSON = (\\{.*?])'
    final QUALITY = '(?<=-)(?=,).*?(?=\\.mp4\\.csmil)'
    
    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, urlTemp
        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)
        {
            url = json.clips[0].m3u8
            url = url.replaceAll("/master.m3u8", "")
            url = url.replaceAll("\\/i\\/", "\\/")

            println url
            
            urlTemp = url
            
            //Try to get the requested quality
            if (requestedQuality == PreferredQuality.HIGH)
                url = url.replaceAll(QUALITY, ',80,150,350,0k')
            else if (requestedQuality == PreferredQuality.MEDIUM)
                url = url.replaceAll(QUALITY, ',400k,110k,200k,600k,800k,1500k,3500k,')
            else if (requestedQuality == PreferredQuality.LOW)
                url = url.replaceAll(QUALITY, ',400k,110k,200k,600k,800k,1500k,')

            //If the requested quality doesn't exist just use the original
            if (!testURL(url))
                url = urlTemp
            
            cacheKey = "Discovery_${json.clips[0].uuid}_${requestedQuality}"
        }
        return new ContentURLContainer(contentUrl: url, thumbnailUrl: item.additionalInfo.thumbnailUrl, expiresImmediately: true, cacheKey: cacheKey)
    }
    
    boolean testURL(String strURL)
    {
        try
        {
            def test = new java.net.URL(strURL).openStream()
            test.close()
        }
        catch(Exception e)
        {
            return false
        }
        return true
    }
    
    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"), 20)
        //WebResourceContainer container = extractor.extractItems( new URL("http://science.discovery.com/tv-shows/how-its-made"), 20)
        
        if (container)
        {
            container.getItems().each
            {
                ContentURLContainer result = extractor.extractUrl(it, PreferredQuality.HIGH)
                println it
                println result 
                println ""
            }
        }   
    }
}