import groovy.util.XmlParser
import groovy.json.JsonSlurper
import org.serviio.library.metadata.*
import org.serviio.library.online.*
import org.serviio.util.*

/********************************************************************
 * desistreams.tv plugin for Serviio
 * 
 * @author X S Inattar
 *
 * URL to use as video webresource: http://www.desistreams.tv/
 * 
 * Version:
 *    V1: August 05, 2012 - Initial Release
 *    V2: August 09, 2012 - Bug Fix: Set live=true for content
 *    V3: August 21, 2012 - Added support for: wcast.tv
 *    V4: September 27, 2012 - Updated based on changes made to the source website
 * 
 ********************************************************************/
 
 class DesiStreams extends WebResourceUrlExtractor {
 
    final VALID_RESOURCE_URL = '^(?:http://)?(?:www\\.)?desistreams.tv/'
    final BASE_URL = 'http://www.desistreams.tv/'
    final TITLE = 'DESISTREAMS.TV'
    final CHANNEL_LIST_EXTRACTOR = '<td><a href="(.*?)" Target=.*?><center><img src="(.*?)" width="100" height="70" alt="" /></a><br />(.*?)</center>'
    
    
    String getExtractorName() {
        return 'desistreams.tv'
    }
    
    boolean extractorMatches(URL resourceURL) {
        return resourceURL ==~ VALID_RESOURCE_URL
    }
   
    /**/
    void write_to_log(
        String text
    ) {
        log(TITLE + ' - ' + text)
    }
    /**/
    
    Boolean URLExists(URL fileURL){
        if(((HttpURLConnection) fileURL.openConnection()).getResponseCode() == 404){
            return false
        }
        return true
    }
    
    Boolean channelOffline(
        String htmlText, 
        String offlineChecker
    ) {        
        def offline_check = htmlText =~ offlineChecker
        if (offline_check.count > 0) {
            return true
        }
        return false
    }         
    
    Boolean streamNotSupported(
        String htmlText, 
        String streamNotSupportedChecker
    ) {        
        def notsupported_check = htmlText =~ streamNotSupportedChecker
        if (notsupported_check.count > 0) {
            return true
        }
        return false
    }
    
    final PLAYPATH_MAPS = 
        [
            "9xmlow":"",
            "aagatv":"aag",
            "aasthatv":"",
            "abcuu":"abcu.stream",
            "aetvu":"",
            "animalplanetlow":"",
            "animalplanetu":"",
            "arylive":"111206",
            "aryn":"arynews",
            "aryuklive":"aryuk",
            "bbcworldnews":"",
            "bravou":"",
            "cartoonnetlow":"",
            "cartoonnetu":"",
            "cbsu":"",
            "channelufx":"",
            "cnbcu":"",
            "cnnlow":"",
            "colorslive":"colors12.stream",
            "comedycentu":"",
            "cwu":"",
            "ddsports7":"ddsports7.stream",
            "discoveryhindi":"115521",
            "discoverylow":"",
            "discoveryscience":"",
            "discoveryturbo":"",
            "discoveryuu":"",
            "disneyenglishlow":"",
            "espnusahq":"espnusa.stream",
            "etnow":"",
            "etv":"",
            "etv_bihar":"",
            "etv_rajasthan":"",
            "etv2":"",
            "etvbangla":"",
            "etvmarathi":"",
            "etvurdu":"",
            "expressentx":"",
            "expressnewslive":"expressnewsx.stream",
            "foodnetuu":"",
            "fox_movies":"",
            "foxnewsu":"",
            "foxu1":"foxu.stream",
            "fxu":"",
            "geoents4":"geouk",
            "geonewslive":"geonews212.stream",
            "Geosuper":"13246540114814",
            "GeoTv":"ent1",
            "hbou":"",
            "historylow":"",
            "HumTv":"115520",
            "indiatv":"",
            "jaihindtv":"",
            "kairalitv5":"kairalitv.stream",
            "lifeoklow":"",
            "lifetimeu":"",
            "maa_gold":"",
            "maa_movies":"",
            "maamusic":"",
            "maatv":"",
            "makkaltv":"",
            "Masalatv":"MasalaTv",
            "Movies":"115518",
            "mtv_india":"",
            "mtvusa":"",
            "my9u":"",
            "natgeou":"",
            "nbcu":"",
            "news24":"",
            "nicku":"",
            "otv_bangla":"",
            "pbsu":"",
            "pogo":"",
            "primetv6":"primetv",
            "rajtv":"",
            "sablow1":"",
            "sakshitv":"",
            "setmax87":"setmax",
            "sony_mix":"",
            "sonylow1":"",
            "spikeu":"",
            "starcricket_hq":"starcricket_hq.stream",
            "starmovies":"starmovies",
            "starnews":"",
            "starplus78":"starplus",
            "starplushd11":"strarplus1",
            "starplushigh":"",
            "starpluslow":"",
            "starutsavlow":"",
            "starvijayhigh":"",
            "stgold":"gold",
            "syfyu":"",
            "tarang_bangla":"",
            "tarangmusic_bangla":"",
            "tbsu":"",
            "TenSportsLive":"1155200",
            "tlclow":"",
            "tntusa":"",
            "umpmoviez":"upmov",
            "usa":"",
            "utv_stars":"",
            "wwe":"wwe.stream",
            "zeecafei":"zeecafe",
            "zeecinema11":"cinema",
            "zeepunjabi11":"zeepunjabi",
            "zeetv11":"zeetv",
            "zeetvhq":""
        ]
    final STREAM_MAPS =
        [
            "9xmlow":"live",
            "aagatv":"app",
            "aasthatv":"stream",
            "abcuu":"broadcast",
            "aetvu":"broadcast",
            "animalplanetlow":"live",
            "animalplanetu":"live",
            "arylive":"broadcast",
            "aryn":"app",
            "aryuklive":"app",
            "bbcworldnews":"live",
            "bravou":"live",
            "cartoonnetlow":"live",
            "cartoonnetu":"live",
            "cbsu":"broadcast",
            "channelufx":"live",
            "cnbcu":"live",
            "cnnlow":"live",
            "colorslive":"broadcast",
            "comedycentu":"broadcast",
            "cwu":"live",
            "ddsports7":"stream",
            "discoveryhindi":"broadcast",
            "discoverylow":"live",
            "discoveryscience":"live",
            "discoveryturbo":"live",
            "discoveryuu":"broadcast",
            "disneyenglishlow":"live",
            "espnusahq":"live",
            "etnow":"live",
            "etv":"live",
            "etv_bihar":"stream",
            "etv_rajasthan":"stream",
            "etv2":"live",
            "etvbangla":"live",
            "etvmarathi":"live",
            "etvurdu":"live",
            "expressentx":"live",
            "expressnewslive":"live",
            "foodnetuu":"broadcast",
            "fox_movies":"stream",
            "foxnewsu":"broadcast",
            "foxu1":"live",
            "fxu":"live",
            "geoents4":"app",
            "geonewslive":"broadcast",
            "Geosuper":"broadcast",
            "GeoTv":"broadcast",
            "hbou":"broadcast",
            "historylow":"live",
            "HumTv":"broadcast",
            "indiatv":"live",
            "jaihindtv":"live",
            "kairalitv5":"live",
            "lifeoklow":"live",
            "lifetimeu":"live",
            "maa_gold":"stream",
            "maa_movies":"stream",
            "maamusic":"live",
            "maatv":"live",
            "makkaltv":"live",
            "Masalatv":"broadcast",
            "Movies":"broadcast",
            "mtv_india":"stream",
            "mtvusa":"stream",
            "my9u":"broadcast",
            "natgeou":"live",
            "nbcu":"live",
            "news24":"live",
            "nicku":"live",
            "otv_bangla":"stream",
            "pbsu":"broadcast",
            "pogo":"live",
            "primetv6":"app",
            "rajtv":"live",
            "sablow1":"stream",
            "sakshitv":"live",
            "setmax87":"app",
            "sony_mix":"stream",
            "sonylow1":"stream",
            "spikeu":"broadcast",
            "starcricket_hq":"broadcast",
            "starmovies":"broadcast",
            "starnews":"live",
            "starplus78":"app",
            "starplushd11":"app",
            "starplushigh":"live",
            "starpluslow":"live",
            "starutsavlow":"live",
            "starvijayhigh":"live",
            "stgold":"app",
            "syfyu":"live",
            "tarang_bangla":"stream",
            "tarangmusic_bangla":"stream",
            "tbsu":"broadcast",
            "TenSportsLive":"broadcast",
            "tlclow":"live",
            "tntusa":"live",
            "umpmoviez":"app",
            "usa":"live",
            "utv_stars":"stream",
            "wwe":"stream",
            "zeecafei":"app",
            "zeecinema11":"app",
            "zeepunjabi11":"app",
            "zeetv11":"app",
            "zeetvhq":"live"
        ]
    String modify_playpath_based_on_page_url(String playpath, String pageURL) {
        def actual_playpath = playpath
        
        actual_playpath = PLAYPATH_MAPS.get(actual_playpath)
        if (actual_playpath == "") {
            actual_playpath = playpath + ".stream"
        }
        
        return actual_playpath
    }
    
    String modify_playpath_based_on_swf_url(String playpath, String swfURL) {
        def actual_playpath = playpath
        
        return actual_playpath
    }
    
    String fix_playpath(String playpath) {
        def actual_playpath = playpath
        
        actual_playpath = actual_playpath.replaceAll(".flv", "")
        actual_playpath = java.net.URLDecoder.decode(actual_playpath)
        
        return actual_playpath
    } 
    
    final ILIVE_STREAMS = [
        'rtmp://46.105.109.122/edge',
        'rtmp://176.31.231.50/edge',
        'rtmp://46.105.115.183/edge',
        'rtmp://176.31.231.124/edge'
    ]
    final CASTALBA_STREAMS = [
        'rtmp://173.192.105.215/live',
        'rtmp://173.192.48.117/live',
        'rtmp://159.253.149.16/live'
    ]
    String redirect_to_actual_stream(String stream) {
        def actual_stream = stream
        def streamURLs = null
        if (stream.contains('ilive.to')) {            
            streamURLs = ILIVE_STREAMS
        }
        else if (stream.contains('castalba.tv')) {            
            streamURLs = CASTALBA_STREAMS
        }        
        
        if (streamURLs != null) {
            actual_stream = streamURLs[ (int)(System.currentTimeMillis() % streamURLs.size()) ]
        }
        
        return actual_stream
    }
    
    String modify_stream_based_on_page_and_playpath(String stream, String pageURL, String playpath) {
        def actual_stream = stream
        
        if (pageURL.contains("video.virginradioitaly.it") 
            || pageURL.contains("video.radiomontecarlo.net")
        ) {
            actual_stream = actual_stream.replaceFirst("auto\\|","rtmp://")
            actual_stream = actual_stream.replaceFirst("\\|",":1935/")
            actual_stream = actual_stream.replaceAll("\\|","/")
        }        
        else
        {
            actual_stream = actual_stream + STREAM_MAPS.get(playpath)            
        }
                
        return actual_stream
    }
    
    String modify_stream_based_on_swf_url(String stream, String swfURL) {
        def actual_stream = stream
        
        if (swfURL.contains('awooze.com')) {
            actual_stream = actual_stream + '/'
        }
        else if (swfURL.contains('vitalstreamcdn.com')) {
            actual_stream = actual_stream + '/'
        }
        else if (swfURL.contains('myfoxtampabay.com')) {
            actual_stream = actual_stream + '/live'
        }
        
        return actual_stream
    }  
    
    String process_for_URL(        
        String htmlText,
        String rgxMatcher,
        String baseURL
    ) {       
        def return_val = '-NOTFOUND-'        
        def matcher = htmlText =~ rgxMatcher
        if (matcher.count > 0) {
            return_val = '-URL-' + baseURL + matcher[0][1]
        }        
        return return_val
    }
    
    String process_for_PLAYPATH(
        String htmlText,
        String rgxMatcher,
        String[] streamURLs,
        String baseURL,
        String swfURL        
    ) {        
        def return_val = '-NOTFOUND-'        
        def matcher = htmlText =~ rgxMatcher
        if (matcher.count > 0) {
            
            def pageURL = baseURL + matcher[0][1]
            
            def playpath = fix_playpath(matcher[0][1])            
            
            def stream = streamURLs[ (int)(System.currentTimeMillis() % streamURLs.size()) ]
            stream = modify_stream_based_on_page_and_playpath(stream, pageURL, playpath)
            
            playpath = modify_playpath_based_on_page_url(playpath, pageURL)
            playpath = modify_playpath_based_on_swf_url(playpath, swfURL)
            
            return_val = '-STREAM-' + stream
            return_val = return_val + ' playpath=' + playpath
            return_val = return_val + ' pageUrl=' + pageURL
            return_val = return_val + ' swfUrl=' + swfURL
            return_val = return_val + ' live=1'
        }        
        return return_val
    }
    
    String process_for_SWF_PLAYPATH_STREAMER(
        String htmlText,
        String rgxMatcher,
        String pageUrl
    ) {        
        def return_val = '-NOTFOUND-'        
        def matcher = htmlText =~ rgxMatcher
        if (matcher.count > 0) {
            
            def swfUrl = matcher[0][1] + '.swf'
            def playpath = fix_playpath(matcher[0][2])
            def stream = matcher[0][3]
            stream = modify_stream_based_on_page_and_playpath(stream, pageUrl, playpath)
            stream = modify_stream_based_on_swf_url(stream, swfUrl)
            stream = redirect_to_actual_stream(stream)
            
            playpath = modify_playpath_based_on_page_url(playpath, pageUrl)
            playpath = modify_playpath_based_on_swf_url(playpath, swfUrl)
            
            return_val = '-STREAM-' + stream
            return_val = return_val + ' playpath=' + playpath
            return_val = return_val + ' pageUrl=' + pageUrl
            return_val = return_val + ' swfUrl=' + swfUrl
            return_val = return_val + ' live=1'
        }        
        return return_val
    }
    
    String processChannel(
        String channel_url
    )
    {
        def log_text = ''
        def error = ''   
        
        if (!URLExists(new URL(channel_url))) {
            error = '-DEADLINK-'
            log_text = log_text + error
            print error
            write_to_log(log_text)
            return error
        }
        
        def channel_src_text = new URL(channel_url).getText()        
        channel_src_text = channel_src_text.replaceAll('%3A',':')
        channel_src_text = channel_src_text.replaceAll('%2F','/')
        channel_src_text = channel_src_text.replaceAll('&amp;','&')                                         
        channel_src_text = channel_src_text.replaceAll('&quot;','"')                                         
        channel_src_text = channel_src_text.replaceAll('&lt;','<')                                         
        channel_src_text = channel_src_text.replaceAll('&gt;','>')                                                                 
        channel_src_text = channel_src_text.replaceAll('%2D','-')
        
        def channel_stream_url_text = channel_src_text            
        def url_found = 0          
        def loop = 0  
        def base_url = ''
        def current_url = channel_url //channel_src
        def rtmp_url = ''            
        while (url_found == 0) {
        
            if (channelOffline(channel_stream_url_text, '<h1 class="center">This channel is offline\\.</h1>')
                || channelOffline(channel_stream_url_text, '<h4 class=.*?THIS CHANNEL IS CURRENTLY OFFLINE</h4>')
                ) {
                error = '-OFFLINE-'
                log_text = log_text + error
                print error
                write_to_log(log_text)
                return error
            }
            
            if (streamNotSupported(channel_stream_url_text, '<media url="rtmfp://.*?/>')
                || streamNotSupported(channel_stream_url_text, '<script.*?src=".*?player\\.ooyala\\.com.*?"></script>')                    
                ) {
                error = '-NOTSUPPORTED-'
                log_text = log_text + error
                print error
                write_to_log(log_text)
                return error
            }
            
            def returned_url = '-NOTFOUND-'
            
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    "<script.*?fid='(.*?)';.*?src='.*?wcast\\.tv.*?'></script>",
                    (String[])[    
                        'rtmp://live.wcast.tv/'
                    ],
                    'http://www.wcast.tv/embed.php?u=',
                    'http://www.wcast.tv/player/player.swf'
                )
            }
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    '<script.*?fid="(.*?)";.*?src=".*?wcast\\.tv.*?"></script>',
                    (String[])[    
                        'rtmp://live.wcast.tv/'
                    ],
                    'http://www.wcast.tv/embed.php?u=',
                    'http://www.wcast.tv/player/player.swf'
                )
            }
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    "<script.*?fid='(.*?)';.*?src='.*?livecaster\\.tv.*?'></script>",
                    (String[])[    
                        'rtmp://cdn.livecaster.tv/'
                    ],
                    'http://www.livecaster.tv/embed.php?u=',
                    'http://www.livecaster.tv/player/player.swf'
                )
            }
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    "<script.*?fid='(.*?)';.*?src='.*?fcast\\.tv",
                    (String[])[    
                        'rtmp://37.221.166.68/',
                        'rtmp://37.221.166.69/',
                        'rtmp://37.221.166.70/'
                    ],
                    'http://www.fcast.tv/embed.php?live=',
                    'http://www.fcast.tv/player/player-licensed.swf'
                )
            }
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    '<script.*?fid="(.*?)";.*?src=".*?blive\\.me',
                    (String[])[    
                        'rtmp://67.215.244.178/',
                        'rtmp://67.215.243.218/'
                    ],
                    'http://www.blive.me/embed.php?v=',
                    'http://static.blive.me/player/player.swf'
                )
            } 
            if (returned_url == '-NOTFOUND-') {
                returned_url = process_for_PLAYPATH(
                    channel_stream_url_text,
                    "<script.*?fid='(.*?)';.*?src='.*?110cast\\.com",
                    (String[])[    
                        'rtmp://fms1.110cast.com/'
                    ],
                    'http://www.110cast.com/embed.php?u=',
                    'http://www.110cast.com/player/player-licensed.swf'
                )
            }
            if (returned_url == '-NOTFOUND-' ) {
                returned_url = process_for_SWF_PLAYPATH_STREAMER(
                    channel_stream_url_text,
                    '<embed.*?src="(.*?)\\.swf".*?flashvars="file=(.*?).flv&streamer=(.*?)&',
                    current_url
                )
            }
            if (returned_url == '-NOTFOUND-') { 
                returned_url = process_for_URL(
                    channel_stream_url_text, 
                    '<iframe.*?src=".*?dmastiers\\.com/videos/(.*?)" width=.*?></iframe>',
                    'http://www.dmastiers.com/videos/'
                )                 
            }        
            
            if (returned_url == '-NOTFOUND-') { 
                returned_url = process_for_URL(
                    channel_stream_url_text, 
                    '<meta http-equiv="REFRESH" content="0;url=http://desistreams\\.tv/embed/(.*?)">',
                    'http://desistreams.tv/embed/'
                )                 
            }
            
            log_text = log_text + returned_url    
            log_text = log_text + ' '
            print returned_url + ' '
            
            if (returned_url == '-NOTFOUND-') {
                error = '-NOTFOUND-'
                write_to_log(log_text)
                return error
            }            
            else if (returned_url.contains("-URL-")) {
                returned_url = returned_url.replaceFirst("-URL-","")
                current_url = returned_url
                if (!URLExists(new URL(current_url))) {
                    error = '-DEADLINK-'
                    log_text = log_text + error
                    print error
                    write_to_log(log_text)
                    return error
                }
                channel_stream_url_text = new URL(current_url).getText()
//                channel_stream_url_text = channel_stream_url_text.replaceAll("\n","")
//                channel_stream_url_text = channel_stream_url_text.replaceAll("\r","")
                channel_stream_url_text = channel_stream_url_text.replaceAll('%3A',':')
                channel_stream_url_text = channel_stream_url_text.replaceAll('%2F','/')
                channel_stream_url_text = channel_stream_url_text.replaceAll('&amp;','&')                                         
                channel_stream_url_text = channel_stream_url_text.replaceAll('&quot;','"')                                                         
                channel_stream_url_text = channel_stream_url_text.replaceAll('%2D','-')
                channel_stream_url_text = channel_stream_url_text.replaceAll('&lt;','<')                                         
                channel_stream_url_text = channel_stream_url_text.replaceAll('&gt;','>')                                                                 
                
                
                /**                
                    println channel_stream_url_text
                    println ''
                    println ''                        
                    println ''
                    println ''
                    println ''                                                                                        
                /**/
            }
            else if (returned_url.contains("-STREAM-")) {
                rtmp_url = returned_url
                url_found = 1
            }         
        }             
        
        write_to_log(log_text)
        
        return rtmp_url   
    }
    
    WebResourceContainer extractItems(URL resourceURL, int maxItemsToRetrieve) {
    
        List<WebResourceItem> items = []
        
        if (URLExists(resourceURL) == false) {
            write_to_log("Invalid Resource URL")
            return null
        }        
        
        def resource_text = resourceURL.getText()
        
        def channel_list_matcher = resource_text =~ CHANNEL_LIST_EXTRACTOR
        def channel_count = channel_list_matcher.count
        for (channel_number in 0..<channel_count) {
        //for (channel_number in 0..<10) {
            def channel_url = channel_list_matcher[channel_number][1]
            def channel_image = channel_list_matcher[channel_number][2]
            def channel_title = channel_list_matcher[channel_number][3]           
            def channel_cache_key = (channel_url =~ '.*?/(.*?)\\.')[0][1]
            
            print channel_title
            //processChannel(BASE_URL + channel_url)
            println ''
            
            items << new WebResourceItem(title: channel_title, 
                additionalInfo: [channelURL: BASE_URL + channel_url, 
                    thumbnailURL: BASE_URL + channel_image, 
                    cacheKey: TITLE + '_' + channel_cache_key
                ]
            )
        }                
        
        return new WebResourceContainer(title: TITLE, items: items)
    }
    
    ContentURLContainer extractUrl(WebResourceItem item, PreferredQuality requestedQuality) {
    
        def rtmp_url = processChannel(item.additionalInfo.channelURL)
        if (rtmp_url.contains('-STREAM-')) {
            rtmp_url = rtmp_url.replaceFirst("-STREAM-", "")
        }
        else {
            return null
        }
                
        return new ContentURLContainer(contentUrl: rtmp_url, 
            thumbnailUrl: item.additionalInfo.thumbnailURL, 
            expiresImmediately: true, 
            cacheKey : item.additionalInfo.cacheKey,
            live: true
            )    
    }
    
    static void main(args) {
        
        DesiStreams extractor = new DesiStreams()
        
        WebResourceContainer container = extractor.extractItems( new URL("http://desistreams.tv/"), 5)
        /**/
        container.getItems().each {
            ContentURLContainer result = extractor.extractUrl(it, PreferredQuality.MEDIUM)
            println result 
            println ''
        }
       /**/                  
    }
 }