import org.serviio.library.metadata.*
import org.serviio.library.online.*


/********************************************************************
 * USTREAM plugin for Serviio
 *
 * Logic by forum member: piscui - http://piscui.webear.net/ustream.php
 * 
 * @author X S Inattar
 *
 * Must be installed as a Video WebResource
 * Sample URLs: 
 *    http://www.ustream.tv/nasahdtv
 *    http://www.ustream.tv/opensea
 *    http://www.ustream.tv/discovery/live/sports?order=most-views-all
 *    http://www.ustream.tv/discovery/live/sports?order=most-views-all&page=2
 *    http://www.ustream.tv/discovery/live/entertainment
 *	  http://www.ustream.tv/new#new/spotlight/underthesea
 * 
 * Version:
 *    V1: July 28, 2012 - Initial Release
 *    V2: July 29, 2012 - Pages and Categories Support 
 *    V3: August 06, 2012 - Fix for new# links for new USTREAM in IE
 *    V4: August 25, 2012 - USTREAM made some changes to the stream urls
 *    V5: August 27, 2012 - Added support for new categories. (provided by jhb50)
 *
 ********************************************************************/

class USTREAM extends WebResourceUrlExtractor {
    
    final VALID_FEED_URL = '^(?:http://)?(?:www\\.)?ustream\\.tv/(.*?)(?:/)?$'
    final BASE_URL = 'http://www.ustream.tv'
    final CHANNEL_ID_EXTRACTOR = 'cid=(.*?)&'
    final THUMBNAIL_EXTRACTOR_1 = '<img class="image" alt="(.*?)" width="66" height="66" src="(.*)" rel="(.*)" />'
    final THUMBNAIL_EXTRACTOR_2 = '<img src="(.*)" alt="(.*?)" title="(.*?)" />'
    final TITLE_EXTRACTOR = '<meta property="og:title" content="(.*)" />'
    final PLAYPATH_EXTRACTOR_1 = "cdnStreamName\\W\\W\\W(.+?)\\x00"
    final PLAYPATH_EXTRACTOR_2 = "streamName\\W\\W\\W(.+?)\\x00"
    final TCURL_EXTRACTOR_1 = "cdnStreamUrl\\W\\W\\S(.*?)\\x00"
    final TCURL_EXTRACTOR_2 = "cdnUrl\\W\\W\\S(.*?)\\x00"
    final TCURL_EXTRACTOR_3 = "fmsUrl\\W\\W\\S(.*?)\\x00"
    final SWF_URL = 'http://static-cdn1.ustream.tv/swf/live/viewer.rsl:96.swf'
    final AMF_URL = 'http://cgw.ustream.tv/Viewer/getStream/1/<!--ChannelID-->.amf';
    final CHANNEL_ITEMS_EXTRACTOR = '<a href="(.*?)" class="shadowbox">\n\t\t\t\t\t<strong class="livebadgeLeft">LIVE</strong>\n\t\t\t\t\t\t\t<span class="img">\n\t\t\t\t<img src=".*?" alt="(.*?)" width="192" height="108".*?/>'

    String getExtractorName() {
        return 'ustream.tv'
    }
    
    boolean extractorMatches(URL feedUrl) {
        return feedUrl ==~ VALID_FEED_URL
    }
       
    WebResourceContainer extractItems(URL resourceUrl, int maxItemsToRetrieve) {
            
        List<WebResourceItem> items = []
        
        def ustreamURL = resourceUrl.toString()
        ustreamURL = ustreamURL.replaceFirst("/new#\\./", "/")
        ustreamURL = ustreamURL.replaceFirst("/new#", "/")

        def channelCodeMatcher = ustreamURL =~ VALID_FEED_URL
        if (channelCodeMatcher.count <= 0 ) {
            return null
        }        
        
        def channelText = new URL(ustreamURL).getText()
        channelText = channelText.replaceAll('&amp;', '&')
        def channelTitle  = channelCodeMatcher        
        def channelTitleMatcher = channelText =~ TITLE_EXTRACTOR
        if (channelTitleMatcher.count > 0) {
            channelTitle = channelTitleMatcher[0][1]
        }
        println channelTitle
        
		// NEW CODE FOR NEW CATEGORIES ******************************************
		
		if (ustreamURL.contains('/new/')) { 
		    def jsonMatcher = channelText =~ '(?s)<div class="active">.*?<a href="/' + channelCodeMatcher[0][1] + '".*?data-listUrl="(.*?)".*?class="state active">(.*?)<.*?</a>'
			def catTitle = "UStream " + jsonMatcher[0][2].trim()
			def jsonUrl = BASE_URL + jsonMatcher[0][1]
			def jsonText = new URL(jsonUrl).getText()
			jsonText = jsonText.replace("\\t", "")
			jsonText = jsonText.replace("\\n", "")
			jsonText = jsonText.replace("\\", "")
			//# get ID#, thumbnail, title
			def allLinks = jsonText =~ '(?s)<li.data-mediaType.*?data-mediaId="(.*?)".*?<div class="img">.*?<img src="(.*?)".*?<span class="badge badge.*?">(.*?)<.*?<div class="titleOwner">.*?<h3>(.*?)<.*?<a href="(.*?)".*?</li>'
			int itemsAdded = 0
			for( int i = 0; i < allLinks.size() && (maxItemsToRetrieve == -1 || itemsAdded < maxItemsToRetrieve); i++ ) {
				if (allLinks[i][3] == "Live"){
					items << new WebResourceItem(title: allLinks[i][4], additionalInfo: [channelURL: BASE_URL + allLinks[i][5]])
					itemsAdded++
					println "Live Item #" + itemsAdded + " " + allLinks[i][4] + " (" + BASE_URL + allLinks[i][5] + ")"
					log ("Live Item #" + itemsAdded + " " + allLinks[i][4] + " (" + BASE_URL + allLinks[i][5] + ")")
				}
			}
			return new WebResourceContainer(title: catTitle, items: items)
		}
        // END OF NEW CODE ******************************************************
 
		else if (ustreamURL.contains('/discovery/live/')) {        
              
            def channel_items_matcher = channelText =~ CHANNEL_ITEMS_EXTRACTOR
            if (channel_items_matcher.count <= 0) {
                return null
            }
            
            def loopRun = (maxItemsToRetrieve != -1 && maxItemsToRetrieve <= channel_items_matcher.count) ? maxItemsToRetrieve : channel_items_matcher.count
            int count = 0
			for (i in 0..<loopRun) {                
                items << new WebResourceItem(title: channel_items_matcher[i][2], additionalInfo: [channelURL: BASE_URL + channel_items_matcher[i][1]] )
 				// ADDED ITEM LOGGING **************************
				count++
				println "Live Item #" + count + " " + channel_items_matcher[i][2] + " (" + BASE_URL + channel_items_matcher[i][1] + ")"
				log ("Live Item #" + count + " " + channel_items_matcher[i][2] + " (" + BASE_URL + channel_items_matcher[i][1] + ")")
				//END ADD LOGGING *******************************
           }
        }        
        else {                                                            
            items << new WebResourceItem(title: channelTitle, additionalInfo: [channelURL: ustreamURL] )                        
        }
        
        return new WebResourceContainer(title: channelTitle, items: items)
    }

    ContentURLContainer extractUrl(WebResourceItem item, PreferredQuality requestedQuality) {
        
        println item.additionalInfo.channelURL
        def channelText = new URL(item.additionalInfo.channelURL).getText()
        
        def channelIdMatcher = channelText =~ CHANNEL_ID_EXTRACTOR
        if (channelIdMatcher.count <= 0) {
            return null
        }
        def channelId = channelIdMatcher[0][1]
        println channelId      
        
        def channelThumb = null
        def channelThumbMatcher_1 = channelText =~ THUMBNAIL_EXTRACTOR_1
        if (channelThumbMatcher_1.count > 0) {
            channelThumb = channelThumbMatcher_1[0][2]
        }
        else {
            def channelThumbMatcher_2 = channelText =~ THUMBNAIL_EXTRACTOR_2
            if (channelThumbMatcher_2.count > 0) {
                channelThumb = channelThumbMatcher_2[0][1]
            }
        }
        println channelThumb                  
        
        def dataurl = AMF_URL
        dataurl = dataurl.replaceAll("<!--.*?-->", channelId)
        println dataurl           
        def data = new URL(dataurl).getText()
        
        def cdnStreamUrlFound = 0
        def playpath = ''        
        def playpath_matcher_1 = data =~ PLAYPATH_EXTRACTOR_1
        if (playpath_matcher_1.count > 0) {
            cdnStreamUrlFound = 1
            playpath = playpath_matcher_1[0][1]
        }
        else {        
            def playpath_matcher_2 = data =~ PLAYPATH_EXTRACTOR_2
            if (playpath_matcher_2.count <= 0) {
                return null
            }
            playpath = playpath_matcher_2[0][1]
        }
        
        def rtmpurl = ''
        if (cdnStreamUrlFound == 1) 
        {
            def tcurl_matcher_1 = data =~ TCURL_EXTRACTOR_1
            if (tcurl_matcher_1.count > 0) {
                rtmpurl = tcurl_matcher_1[0][1]
            }
            else 
            {
                return null
            }
        } 
        else 
        {
            def tcurl_matcher_2 = data =~ TCURL_EXTRACTOR_2
            if (tcurl_matcher_2.count > 0) {
                rtmpurl = tcurl_matcher_2[0][1]
            }
            else {
                def tcurl_matcher_3 = data =~ TCURL_EXTRACTOR_3
                if (tcurl_matcher_3.count > 0) {
                    rtmpurl = tcurl_matcher_3[0][1]
                    rtmpurl = rtmpurl.replaceAll('/ustreamVideo', ':1935/ustreamVideo')
                    rtmpurl = rtmpurl + '/'
                }
                else {
                    return null
                }
            }
        }
        
        def contentUrl = rtmpurl + ' playpath=' + playpath + ' swfUrl=' + SWF_URL + ' swfVfy=1 live=1'  
        
        def cacheKey = 'USTREAM_' + channelId
       
        return new ContentURLContainer(contentUrl: contentUrl, thumbnailUrl: channelThumb, expiresImmediately: true, cacheKey : cacheKey, live: true)    
    }
        
    static void main(args) {
    
        USTREAM extractor = new  USTREAM()
        
        //WebResourceContainer container = extractor.extractItems( new URL("http://www.ustream.tv/new#./creativelive"), 5)
        WebResourceContainer container = extractor.extractItems( new URL("http://www.ustream.tv/new#new/spotlight/underthesea"), 5)
		//WebResourceContainer container = extractor.extractItems( new URL("http://www.ustream.tv/discovery/live/entertainment"), 5)
        //WebResourceContainer container = extractor.extractItems( new URL("http://www.ustream.tv/new#channel/live-iss-stream"), 5)
        container.getItems().each {
            ContentURLContainer result = extractor.extractUrl(it, PreferredQuality.MEDIUM)
            println result 
        }   
        
        /**
        container = extractor.extractItems( new URL("http://www.ustream.tv/discovery/live/entertainment"), 20)
        container.getItems().each {
            ContentURLContainer result = extractor.extractUrl(it, PreferredQuality.MEDIUM)
            println result 
        }  
        /**/ 
    }
}