import org.serviio.library.online.WebResourceUrlExtractor
import org.serviio.library.online.WebResourceContainer
import org.serviio.library.online.PreferredQuality
import groovy.json.JsonSlurper
import org.serviio.library.online.WebResourceItem
import org.serviio.library.online.ContentURLContainer
import org.serviio.library.metadata.MediaFileType
import java.text.SimpleDateFormat
/**
 * WebResource extractor plugin for SBSonDemand (Australia only) 
 *
 * @author ttguy
 * @version 0.1.5
   0.1 This version working for featured programs - 10 on 22/9/2012. No thumbnails are sent
   0.1.1 This version working for featured programs - 1-19 on 22/9/2012. No thumbnails are sent
   0.1.2 This version working for feeds listed below 23/9/2012. Thumbnails are sent
   0.1.3 Fixes a bug made apparent by an XML structure not previously seen
   0.1.4 Branch from 0.1.3 and different to 0.2.1 which is also a branch from 0.1.3. Made it work with SBS changes of 6/10/2012
   0.1.5  Fix issue with prefered quality not working and making some videos not play at all. 

	In for eg the html in a video page like 
		http://www.sbs.com.au/ondemand/video/2285470848
		There is a json formated data section vod.cache.video and a item in that plfile$url":"http://link.theplatform.com/s/dYtmxB/dWQ_e6_x_hjMT_ISLDJ330awEgcZavEk?feed=Video%20-%20Single
		And when you pull that file it gives you a smil xml format file with links like 
		<video src="http://sbsauvod-f.akamaihd.net/SBS_Production/managed/2012/09/2012-10-01_283096_512K.mp4" and if I whack the famous "?v=&fp=&r=&g=" on to the end of that url
		 ffmpeg can download the file. 


* According to http://whirlpool.net.au/wiki/sbs_downloader  the following feeds should be valid for this plug in.
* Events have lots of cycling bits. Clips are short bits of news stories and other short "clips".
* Programs are full episodes. 
*          URL                                                                  desc                        tested
* http://feed.theplatform.com/f/dYtmxB/featured-programs-prod/?form=json   contains featured programs         Y  about 19 items
* http://feed.theplatform.com/f/dYtmxB/section-programs/?form=json         contains all programs videos       Y maxes out at 100 items - but see note below
* http://feed.theplatform.com/f/dYtmxB/section-clips/?form=json            contains all clips                 Y
* http://feed.theplatform.com/f/dYtmxB/section-events/?form=json           contains all events videos         Y
* http://feed.theplatform.com/f/dYtmxB/videos-lastchance/?form=json        contains last chance videos     Feed Not working - BadParameterException
* http://feed.theplatform.com/f/dYtmxB/featured-clips/?form=json           contains featured clips            Y
* http://feed.theplatform.com/f/dYtmxB/e16qKzBBHt4R/?form=json             Full Eps and Clips combined        Y maxes out at 100 items  - but see note below
* http://feed.theplatform.com/f/dYtmxB/CxeOeDELXKEv/?form=json             All videos on the site            Feed not working - AuthorizationException
                           

*  - I pulled this feed link by running wireshark while browsing on the SBS site
*     http://feed.theplatform.com/f/dYtmxB/section-programs?form=json&byCategories=Film%7CFilm%2FAction+Adventure%7CFilm%2FBiography%7CFilm%2FAnimation%7CFilm%2FClassic%7CFilm%2FComedy%7CFilm%2FCult%7CFilm%2FDance%7CFilm%2FDrama%7CFilm%2FEpi
*      The  &byCategories= translates to "Film|Film/Action Adventure|Film/Biography|Film/Animation|Film/Classic|Film/Comedy|Film/Cult|Film/Dance|Film/Drama|Film/Epi"
  http://feed.theplatform.com/f/dYtmxB/section-sbstv?form=json&byCategories=Film%7CFilm%2FAction+Adventure%7CFilm%2FAnimation%7CFilm%2FWestern%7CShort+Film%2CSection%2FPrograms
      Film|Film/Action Adventure|Film/Animation|Film/Western|Short Film,Section/Programs
*  You can also use the Search for program API to generate a play list using a search?form=json&q=<search term> syntax
*  Eg Mythbusters search:
* http://feed.theplatform.com/f/dYtmxB/search?form=json&q=mythbusters

* 
	http://feed.theplatform.com/f/dYtmxB/section-sbstv?form=json&byCategories=Documentary%2CSection%2FPrograms    - Documentary programs 

* These URLs should be added as a Web Resource under the Library > Online Sources Tab in the Serviio console
*
*   You can encode a range of clips you want to retrieve in the URLs by adding "&range=1-9" to the end of the URL
*  eg http://feed.theplatform.com/f/dYtmxB/featured-programs-prod/?form=json&range=1-9
*  Will return the first 9 programs in the featured-progams feed
*
*  You can limit the number items retrieved from the serviio console too - "Max number of feed items to retreive" setting
*
*  The URLs without a range listed appear to max out at 100 items. But you can get the next 100 items by adding a &range101-200
*  to the end of them.  There do not appear to be more than 200 items in a feed.  eg  &range190-210 only returns 10 videos
*  
*
*  SBS seems to offer 4 video qualities. Which makes us have to make a decision about what is medium quality when 
*  the user specifies medium quality. 
*  If the user says high quality this plugin serves up the highest quality available.
*  If the user says medium quality this plugin serves up the first video with a resolution higher than the value specified in the
*   MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE variable below. (Currently this is set to 1000K ) 
*   If the user says low quality this plugin serves up the lowest resolution available if the LOW_QUAL_IS_THIS_INDEX variable below is set = 0
*   Or if the user says low quality and the LOW_QUAL_IS_THIS_INDEX variable below is set = 1 then the plugin serves up the second lowest resolution
*   available
* 
* It seems when running this with  PreferredQuality.LOW [and LOW_QUAL_IS_THIS_INDEX =0 setting  ] (on Xbox at least) that the device tries repeatedly to load the file and
*  then only plays the audio. Might be something to do with how Xbox treats very low bit rate sources? Or how Serviio transcodes low
*  bitrate sources.
*
* To Test outside of Serviio cd to the serviio install folder and execute the groovy file
*  cd /usr/bin/serviio-0.6.2/
*  groovy -cp lib/serviio.jar:lib/slf4j-api.jar:lib/slf4j-log4j12.jar:lib/log4j.jar:lib/org.restlet.jar plugins/SBSonDemand.groovy
*
*/
class SBSonDemand extends WebResourceUrlExtractor {
    /////////////////////////////////////////////////////[CONSTANTS]/////////////////////////////////////////////////////

   final static Integer MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE = 1000000 // This var controls what the plugin considers medium quality
                                                    // The sample SBS video I played with had bit rates offered of 
							//128000, 512000, 1063443, 1497066
							// Under this scenario with this var set to 500000 the medium qual video would be
							// The  512000 bitrate one
   							// With this var at 1000000 medium qual would be the 1063443 bitrate one
  
    final static Integer LOW_QUAL_IS_THIS_INDEX =1 //  Set this to 1 to make the plugin return the second lowest resolution video for Prefered Quality Low
						  // Set this to 0 to make the plugin return the  lowest resolution video for Prefered Quality Low
                                                // This is a case of computers counting and they start from zero. The first number is zero !!!
						// With this set to 1 and  MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE = 1000000 means that generally
						// you will get the prefered quality Low, Medium and High settings serve up the 512000, 1063443, 1497066 resolution videos respecively. 
						// You would not get the lowest resolution SBS has video served up.
    final static version='0.1.5'
    final static VALID_WEB_RESOURCE_URL = '^http(s)*://feed.theplatform.com/f/dYtmxB/.*$'  
    final static USER_AGENT = 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1'
    final static AKAMAIHD_URL_SUFIX                       = "?v=&fp=&r=&g="
    //////////////////////////////////////////////////////[METHODS]//////////////////////////////////////////////////////
    @Override
    protected org.serviio.library.online.WebResourceContainer extractItems(URL url, int  maxItemsToRetrieve) {
        String pageSource = openURL(url, USER_AGENT)
	//println pageSource
	JsonSlurper slurper = new JsonSlurper()
	Object result = slurper.parseText(pageSource)
	String title =result.title
//	println "Feed Title: $title"
//	println result.size
//	println result
	def  entries = result.entries

	//def mediaContent = entries[1].media$content
	//def id = entries[1].id
	//def id ="http://www.sbs.com.au/ondemand/video/2131508325"
	// http://www.sbs.com.au/ondemand/video/2131508325
	//  The above URL has a  player.releaseUrl
	// http://link.theplatform.com/s/dYtmxB/Y3CLxrVGKU24HiXKlkdr0_JGl6omFlbI?feed=Video%20-%20Single&switch=hd&mbr=true&policy=11064&dfptag=video.film.sbs.com.au%2Fsec30%3Btype%3Dpreroll%3Bsz%3D530x298&dfptagmid=video.film.sbs.com.au%2Fsec30%3Btype%3Dmidroll%3Bsz%3D530x298&ord=6923883
	// dowlloading the player.releaseUrl gives you XML from which you can extract the video urls from




/*

ffmpeg -report -i "http://sbsauvod-f.akamaihd.net/SBS_Production/managed/2012/09/2012-09-17_440873_512K.mp4?v=&fp=&r=&g="
	208.79.64.146  - theplatform
	4
	[[plfile$format:MPEG4, plfile$duration:1510.0, plfile$downloadUrl:, plfile$assetTypes:[RTMP secured]], [plfile$format:MPEG4, plfile$duration:1510.0, plfile$downloadUrl:, plfile$assetTypes:[RTMP secured]], [plfile$format:MPEG4, plfile$duration:1510.48, plfile$downloadUrl:, plfile$assetTypes:[RTMP secured]], [plfile$format:MPEG4, plfile$duration:1510.48, plfile$downloadUrl:, plfile$assetTypes:[RTMP secured]]]

	id = http://mps.theplatform.com/data/Media/2275387616
	
	browse to 

	http://www.sbs.com.au/ondemand/video/2275387616


*/

        List<WebResourceItem> items = []

	items = CreateWebResourceItems(entries,maxItemsToRetrieve)

//	println "items $items"
 	
        return new WebResourceContainer(title: title, items: items)


  
    }

    /**
     * Creates List of WebResourceItems
     */
    private List<WebResourceItem> CreateWebResourceItems(entries, int  maxItemsToRetrieve){
	List<WebResourceItem> ReturnItems = []
 	//println "maxItemsToRetrieve $maxItemsToRetrieve"
        Map<String,String> additionalInfo = new HashMap<String, String>();
	//println "entries.size $entries.size"
	if (!(entries==null))
	{	
	def size=entries.size -1	
	for ( count in  0..size )
           {
	     def ent=entries[count]
	     if ( count > maxItemsToRetrieve - 1 && maxItemsToRetrieve>0)
		break;
		
	
	 //       println ent.id
	//	println "ent $ent"
		def title = ent.title
	//	println "Vid title: $title"
		//println ent.keySet() // lists the keys
		//println ent.media$content[0].plfile$downloadUrl
		//println "ent.pubDate $ent.pubDate"
		
		// ent.pubDate is a java.lang.Long   1347348600000
		Date releaseDate = new Date(ent.pubDate)
		

		//println "releaseDate $releaseDate"
	   	ReturnItems << new WebResourceItem(title: title,releaseDate: releaseDate, additionalInfo: createAdditionalInfo(ent))
             // additionalInfo.put(it.bitrate,it.file.substring(4))
           }
	}
        return ReturnItems
    }
  
 /**
     * Creates additional info map for web resource item
     * @param entry  ArrayList contains data about video
     * The returned map contains a VideoId which is the URL for the Video as
     * as it would be viewed on the web site.
     *  It also contains a Thumbnail which is the URL for the videos thumb nail
     */
    private Map createAdditionalInfo(entry){
        Map<String,String> additionalInfo = new HashMap<String, String>();
	def VideoId = entry.id.replaceAll("http://mps.theplatform.com/data/Media/","")
	//VideoId = "http://www.sbs.com.au/ondemand/video/" + VideoId 
	//println "VideoId $VideoId"
	additionalInfo.put("VideoId", VideoId)
	
	if (!(entry.media$thumbnails==null))
	{
		//println entry.media$thumbnails.size()


		if (entry.media$thumbnails.size()==2)
		{
			additionalInfo.put("Thumbnail", entry.media$thumbnails[1].plfile$downloadUrl)
		}
		else
		{
			additionalInfo.put("Thumbnail", entry.media$thumbnails[0].plfile$downloadUrl)
		}
	}	
	else
	{	
		additionalInfo.put("Thumbnail", entry.plmedia$defaultThumbnailUrl)
		//println entry.plmedia$defaultThumbnailUrl
	}

	
    return additionalInfo
    }

	/*
	extractUrl
	*/
    @Override
    protected org.serviio.library.online.ContentURLContainer extractUrl(org.serviio.library.online.WebResourceItem webResourceItem, org.serviio.library.online.PreferredQuality preferredQuality) {
	String VideoUrl = "http://www.sbs.com.au/ondemand/video/" + webResourceItem.additionalInfo.get("VideoId") 	
	String PageData =   openURL(new URL(VideoUrl ), USER_AGENT)
	String contentUrl
	def ResolutionMap= [:] 
	Integer Bitrate
//	println "PageData $PageData"	
     //   “=~” – Creates a Matcher out of the String on the left hand side and the Pattern on the right.
	//def matcher = PageData =~ /player\.releaseUrl = "(.+)";/   
// This matcher is matching on     vod.cache.video['id_2285470848'] = <blah blah>"};   // and it captures the <blah blah>"}
	def matcher = PageData =~ /vod\.cache\.video\['id_/ + webResourceItem.additionalInfo.get("VideoId") + /'] = /  + /(.+"});/ 
	String releaseJsonStr= matcher[0][1] 
	//println "releaseJsonStr $releaseJsonStr"
	JsonSlurper slurper = new JsonSlurper()
	Object result = slurper.parseText(releaseJsonStr)
	def mediacontent = result.media$content
	if (mediacontent.size() == 0 )
	{
		log("No media content found VideoUrl  $VideoUrl ")
		println "No media content found VideoUrl  $VideoUrl "
	}
	else
	{	
		for ( contentitem in mediacontent )
		{
			Bitrate = contentitem.plfile$bitrate
			ResolutionMap [(Bitrate)] = contentitem.plfile$url
			//println "Bitrate $Bitrate "
		}
	

	//	println ResolutionMap
	
		ResolutionMap=ResolutionMap.sort()

	//	println  " -  after sort - last key "	
	//	println ResolutionMap
		//println ResolutionMap.lastKey()
	//	println ResolutionMap.keySet()
	//	println ResolutionMap [(ResolutionMap.firstKey())]

		//println "releaseUrlNodes $releaseUrlNodes"
	      
	
		String xmlUrl
		switch (preferredQuality){
		    case PreferredQuality.HIGH:
		        xmlUrl= ResolutionMap [(ResolutionMap.lastKey())]
		        break
		    case PreferredQuality.MEDIUM:
		//	println ResolutionMap.keySet()
			for (br in ResolutionMap.keySet())
			{
				if (br > MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE)
				{
					xmlUrl = ResolutionMap [(br)]
					break;
				}
			}
		        if (xmlUrl == null)
			{
			  log("No resolution avail above $MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE. Using highest resolution available - " + (ResolutionMap.lastKey()).toString())
			  println "No resolution avail above $MEDIUM_QUAL_IS_FIRST_RESOLUTION_ABOVE. Using highest resolution available - " + (ResolutionMap.lastKey()).toString()
 			  xmlUrl= ResolutionMap [( ResolutionMap.lastKey() )]
			}
		        break
		    case PreferredQuality.LOW:
		      
	 		xmlUrl = ResolutionMap [(ResolutionMap.keySet().toArray())[LOW_QUAL_IS_THIS_INDEX]]
		
		        break
		}

		//println "xmlUrl $xmlUrl"
		def VidNodes = new XmlParser().parse(xmlUrl )
		def VidElements
		if ( VidNodes.body[0].seq.size()==0)
		{
			VidElements =VidNodes.body[0].video[0]
		}
		else
		{
			if ( VidNodes.body[0].seq[0].par.size()==0)
			{
				VidElements =VidNodes.body[0].seq[0].video[0]
			}
			else
			{	
		 		VidElements =VidNodes.body[0].seq[0].par[0].video[0]
			}
		}

	
	
		contentUrl = VidElements.@src
 		return new ContentURLContainer(fileType: MediaFileType.VIDEO, contentUrl: contentUrl + AKAMAIHD_URL_SUFIX,thumbnailUrl: webResourceItem.additionalInfo.get("Thumbnail")  )
	}
	//println "VidNodes $VidNodes"

       
    }

    @Override
    boolean extractorMatches(URL url) {
	def result =url ==~ VALID_WEB_RESOURCE_URL
	if (result)
	{
		log("version $version")
		
	}
        return result
    }

    @Override
    String getExtractorName() {
         return 'SBSonDemand (Australia only)'
    }
    static void main(args) {
// Serviio never executes main.
//  Just use main to test the plugin from outside serviio
//   cd /usr/bin/<pc5dczc_install folder>/ 
// eg 
//  cd /usr/bin/serviio-0.6.2/
// and 
// groovy -cp lib/serviio.jar:lib/slf4j-api.jar:lib/slf4j-log4j12.jar:lib/log4j.jar:lib/org.restlet.jar plugins/SBSonDemand.groovy


     // def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/section-programs/")
	//def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/video-lastchance/?range=1-8&form=json")
	//def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/featured-programs-prod/?range=1-8&form=json")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/featured-programs-prod/?form=json")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/section-programs?form=json&byCategories=Film%7CFilm%2FAction+Adventure%7CFilm%2FBiography%7CFilm%2FAnimation%7CFilm%2FClassic%7CFilm%2FComedy%7CFilm%2FCult%7CFilm%2FDance%7CFilm%2FDrama%7CFilm%2FEpi")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/section-sbstv?form=json&byCategories=Film%7CFilm%2FAction+Adventure%7CFilm%2FAnimation%7CFilm%2FWestern%7CShort+Film%2CSection%2FPrograms")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/search?form=json&q=mythbusters")
      def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/section-sbstv?form=json&byCategories=Documentary%2CSection%2FPrograms")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/section-programs/?form=json")
//	def TestUrl = new URL("http://feed.theplatform.com/f/dYtmxB/CxeOeDELXKEv/?form=json&range=190-220")





        SBSonDemand extractor = new SBSonDemand()
        println "PluginName               : " + extractor.getExtractorName();
        println "TestMatch                : " + extractor.extractorMatches(TestUrl);
	println "TestUrl $TestUrl"
	println new URLDecoder().decode(TestUrl.toString())
        WebResourceContainer container = extractor.extractItems(TestUrl, 10);
	def items =container.getItems()
	int count=0
	println "URL " + count + ": " + extractor.extractUrl(items[8], PreferredQuality.MEDIUM)
	println "URL " + count + ": " + extractor.extractUrl(items[9], PreferredQuality.MEDIUM)
	//println  items.size()

//	for (item in items)
//		{
 //       	println "URL " + count + ": " + extractor.extractUrl(item, PreferredQuality.MEDIUM)
//		println "- - - - - - - - - - - - - - - - - - - - - - - - - - - "
//		count++
//		}

	
    }
}
