import java.awt.PageAttributes.MediaType; import java.lang.reflect.Method; import java.util.HashMap; import java.text.*; import org.restlet.* import groovy.json.* import org.restlet.resource.ClientResource import org.restlet.data.* import org.restlet.representation.* import org.serviio.library.metadata.* import org.serviio.library.online.* import org.serviio.util.* import org.apache.commons.lang.StringEscapeUtils /** * WebResource extractor plugin for http://www.ceskatelevize.cz/ivysilani * * @author mv * @version * * Plugin supports following query parameters * max_items= overwrite maximum number of items/movie in category provided by serviio setting * order=desc revers order of items. * log_level= not implemented via request. it can be change in source code. See bellow for line * private int log_level=1 * Set log level 1-10, 1 less log message, 10 maximum log message. Default log setting has to have DEBUG. * ` Curetly use only 1 basic, 5 midle , 10 full detail * addDdate=title Add relaase date to title of media. Some DLNA client does not display Release date. * example *http://www.ceskatelevize.cz/ivysilani/902567-bob-a-bobek-kralici-z-klobouku/200350950010013-na-ostrove?max_items=30&order=desc */ class CzechTV extends WebResourceUrlExtractor { final VALID_FEED_URL = '^http://www.ceskatelevize.cz/ivysilani/.*' final BASE_URL = "http://www.ceskatelevize.cz/ivysilani/" final AJAX_HTTP ="http://www.ceskatelevize.cz/ajax/getPlaylistURI.php" private String useragent private ClientResource client private int log_level=1 CzechTV() { useragent=getFFmpegUserAgent() log( "Init CzechTV user agent for http is -" + useragent); client=new ClientResource(org.restlet.data.Method.POST , AJAX_HTTP) Form requestHeaders = new Form() requestHeaders.add('x-addr','127.0.0.1') requestHeaders.add('X-Requested-With','XMLHttpRequest') client.getRequest().getAttributes().put("org.restlet.http.headers", requestHeaders) } void finalize() { client.release() } String getExtractorName() { return getClass().getName() } boolean extractorMatches(URL feedUrl) { return feedUrl ==~ VALID_FEED_URL } int getVersion() { return 4 } private void my_log(int message_level,String s ) { if(log_level>=message_level) { my_log(s) } } private void my_log(String s) { //println s log(s) } WebResourceContainer extractItems(URL resourceUrl, int maxItems) { my_log( "Start extractItems procedure Czech TV " + resourceUrl) List items = [] def maxcount= resourceUrl.query=~ /(?i).*MAX_ITEMS=([0-9]+).*/ if(maxcount.getCount()>0) { maxItems=maxcount[0][1].toInteger() } boolean doreverse=resourceUrl.query==~/(?i).*ORDER=DESC.*/ boolean addreleasedate=resourceUrl.query==~/(?i).*AddDate=.*/ def page_hmlt=openURL(resourceUrl,useragent) def title = page_hmlt =~ '(.*):' assert title.getCount() > 0, "Error not find media Title" my_log( "Title of Page: " + title[0][1]) String hosturl=resourceUrl.protocol + '://' + resourceUrl.host def itemscount=0 if( maxItems==-1) maxItems=Integer.MAX_VALUE //max value mean no limit itemscount=Add_episod_page(page_hmlt,hosturl, items, maxItems, addreleasedate) if(itemscount<maxItems) { def nextpage=page_hmlt =~ '<a.*class="detailProgrammePaging next".*href="(.*)"' def lastpage=page_hmlt =~ '<a.*class="detailProgrammePaging last".*href="(.*)"' if (lastpage.getCount()>0 && nextpage.getCount()>0) { def pagenavi= nextpage[0][1]=~/.*\/([0-9]+)\/$/ assert pagenavi.getCount() > 0, "Wrong parser /(.*)\\/([0-9]+)\\/\$/ for string" + nextpage[0][1] def nextpage_num=pagenavi[0][1].toInteger() pagenavi= lastpage[0][1]=~/(.*)\/([0-9]+)\/$/ assert pagenavi.getCount() > 0, "Wrong parser /(.*)\\/([0-9]+)\\/\$/ for string" + lastpage[0][1] String baseref=pagenavi[0][1] def lastpage_num=pagenavi[0][2].toInteger() for(int i=nextpage_num ; i<=lastpage_num & itemscount<maxItems;i++ ) { my_log( "next page url " + hosturl+baseref+"/"+i+"/") resourceUrl = new URL(hosturl+baseref+"/"+i+"/") page_hmlt=openURL(resourceUrl,useragent) itemscount=Add_episod_page(page_hmlt,hosturl, items, maxItems,addreleasedate) } } } my_log( "count video files" + itemscount) if(doreverse) { items.reverse(true) } my_log( items.toString()) return new WebResourceContainer(title: title[0][1], thumbnailUrl: items[0].getAdditionalInfo()['WebResourceItemThumbnailUrl'], items: items) } private int Add_episod_page(String page_hmlt,String hosturl,List items, int maxItems,boolean addreleasedate) { String WebResourceTitle = "CZECH TV" //println page_hmlt def media_list = page_hmlt =~ '<li class="itemBlock clearfix.*>.*\\s*.*<a.*href="(.*)">.*\\s*.*<img src="(.*)" alt="(.*)" width="(\\d*)" height="(\\d*)".*>' def media_dat = page_hmlt =~ '</h3>[.\\s]*<p>(.*)</p>' def ItemsAdded = items.size(); if( media_list.getCount() < 1) { my_log( "Error not find media link") return ItemsAdded } for( int i = 0; i < media_list.getCount() && ItemsAdded<maxItems ; i++ ) { Date releasedate String title= media_list[i][3] //for(int j=0;j<media_list.getCount();j++){println media_list[i][j]} try {//simply use cureent time like relase date if relase date cannot be parsed if(media_dat.getCount()>0) { try{releasedate=new SimpleDateFormat("d. M. yyyy").parse(media_dat[i][1])} catch(ee) { releasedate=new SimpleDateFormat("d. M. yyyy").parse(media_list[i][3]) title= media_dat[i][1] } } else { //If it is not date format siple use current time like release date releasedate=new SimpleDateFormat("d. M. yyyy").parse(media_list[i][3]) } } catch(e) { releasedate=new Date() } title=StringEscapeUtils.unescapeHtml(title) if(addreleasedate) { title=releasedate.getDateString() + " - " + title } my_log( "title: " + title+ "\t" + hosturl + media_list[i][1] + "\ttext date: " + releasedate +"\tdate format: "+ releasedate.getDateString() ) WebResourceItem item = new WebResourceItem(title: title, releaseDate: releasedate, additionalInfo: ['WebResourceItemUrl': hosturl + media_list[i][1], 'WebResourceItemThumbnailUrl': media_list[i][2] ] ) items << item ItemsAdded++ } return ItemsAdded } ContentURLContainer extractUrl(WebResourceItem item, PreferredQuality requestedQuality) { my_log( "-----Start extractUrl " + item.getAdditionalInfo()['WebResourceItemUrl']) def pageURL =new URL(item.getAdditionalInfo()['WebResourceItemUrl']) def page_hmlt=openURL(pageURL,useragent) String ItemVideoUrl //find string for request of lint to xlm play link def objectJSON = page_hmlt =~ 'callSOAP\\((.*)\\)' assert objectJSON.getCount() > 0, "Error not find media dat" def json = new JsonSlurper().parseText(objectJSON[0][1]) my_log( "json"+ json) String str=objectJSON[0][1].toString() Form f=new Form() // fillform(f,"","options",json ) def options=json.options f.add("options[userIP]", options.userIP) f.add("options[playerType]", options.playerType) for(int j=0; j<options.playlistItems.size; j++) { def playlist=options.playlistItems[j] f.add("options[playlistItems][" + j + "][Type]", playlist.Type) f.add("options[playlistItems][" + j + "][Format]", playlist.Format) f.add("options[playlistItems][" + j + "][Identifier]", playlist.Identifier) f.add("options[playlistItems][" + j + "][Title]", playlist.Title) def skip=playlist.Skip if (skip!=null) { f.add("options[playlistItems][" + j + "][Skip][Enable]", skip.Enable.toString()) f.add("options[playlistItems][" + j + "][Skip][Delay]", skip.Delay) f.add("options[playlistItems][" + j + "][ClickThruURL]", playlist.ClickThruURL) } else { f.add("options[playlistItems][" + j + "][Region]", playlist.Region) f.add("options[playlistItems][" + j + "][SubtitlesUrl]", playlist.SubtitlesUrl) f.add("options[playlistItems][" + j + "][Indexes]", playlist.Indexes) } for(int i=0; i<playlist.Gemius.Param.size; i++) { def Param=playlist.Gemius.Param[i] f.add("options[playlistItems][" + j + "][Gemius][Param][" + i + "][Name]", Param.Name) f.add("options[playlistItems][" + j + "][Gemius][Param][" + i + "][Value]", Param.Value) } } f.add("options[previewImageURL]", options.previewImageURL) f.add("options[audio]", options.audio.toString()) f.add("options[defaultStreamQuality]", options.defaultStreamQuality) f.add("options[hash]", options.hash) my_log ( f.getQueryString()) def res=client.post(f.getWebRepresentation(),org.restlet.data.MediaType.APPLICATION_WWW_FORM) my_log( "Status AJAX request: " + client.getStatus()) String s=client.responseEntity.getText() s=s.replaceAll("%26", "&") my_log( s) pageURL =new URL(s) String page_hmlt2=openURL(pageURL,useragent) my_log (10,page_hmlt2) //println page_hmlt2.replace("\"", "\\\"").replace("\r\n", "\"+\r\n\"") Node xml = new XmlParser().parseText(page_hmlt2) def swichItem String ContentUrl String baseurl String Playpath for(int i=0;i<xml.smilRoot.body.switchItem.size();i++) { swichItem=xml.smilRoot.body.switchItem[i] if( ! swichItem.@'id'.contains("-AD-") ) { baseurl=xml.smilRoot.body.switchItem[i].@'base' ContentUrl=baseurl def tmp= baseurl =~ /rtmp:\/\/.*\.cz\/(.*)/ String app=tmp[0][1] def videos=swichItem.video.findAll{it.'@label'==~/[0-9]{3,4}p/} Integer max_index=videos.size()-1 Integer medium_index=Math.round(max_index/2.0) switch (requestedQuality) { case PreferredQuality.HIGH : Playpath= videos.max{a,b-> (a.'@label'=~ /([0-9]{3,4})p/)[0][1].toInteger() <=> (b.'@label'=~ /([0-9]{3,4})p/)[0][1].toInteger()}.'@src' ;break; case PreferredQuality.MEDIUM : Playpath= videos[medium_index].@'src' ;break; case PreferredQuality.LOW : Playpath= videos.min{a,b-> (a.'@label'=~ /([0-9]{3,4})p/)[0][1].toInteger() <=> (b.'@label'=~ /([0-9]{3,4})p/)[0][1].toInteger()}.'@src';break; default : Playpath= videos[medium_index].@'src' ;break; } ContentUrl= baseurl+ " app=" + app + " playpath=" + Playpath + " swfUrl=http://img9.ceskatelevize.cz/libraries/JWPlayer/player.swf swfVfy=1 live=1" my_log( "WebResourceItemTitle : "+item.getTitle()) //println "WebResourceItemId : "+item.getAdditionalInfo()['WebResourceItemId'] my_log(5, "WebResourceItemThumbnailUrl : "+item.getAdditionalInfo()['WebResourceItemThumbnailUrl']) my_log( "ContentUrl : "+ContentUrl) my_log( 10,"ffmpeg.exe -i \"" + ContentUrl + "\" out"+ (new Random().nextInt() % 600 + 1) + ".avi") my_log( 10,"rtmpdump -v -R -r \""+baseurl+ "\" -a \"" + app + "\" -y \"" + Playpath + "\" -s \"http://img9.ceskatelevize.cz/libraries/JWPlayer/player.swf\" -o out" + (new Random().nextInt() % 600 + 1) + ".avi") my_log("------ end extractUrl") } } return new ContentURLContainer(fileType: MediaFileType.VIDEO, contentUrl: ContentUrl, thumbnailUrl: item.getAdditionalInfo()['WebResourceItemThumbnailUrl'],cacheKey:item.getAdditionalInfo()['WebResourceItemUrl']+requestedQuality,expiresImmediately:true) } void fillform(Form f,String prefix,aaa,HashMap<String,Object> json) { def zz= json.get(aaa) if( zz.getClass() != java.util.HashMap.class & zz.getClass()!=java.util.ArrayList.class) { println prefix + "[" + aaa + "]=" + zz.toString() f.add(prefix + "[" + aaa + "]",zz.toString() ) } else { println zz.getClass() if(prefix=="") { prefix=aaa } else { prefix+= "["+ aaa + "]" } def keys=null int max=0 if (zz.getClass()==java.util.ArrayList.class) { for(int i=0;i<zz.size;i++) { if(zz[i].getClass()== java.util.HashMap.class) { def a=zz[i].keySet() def aa=a.toArray() for(int j=0; j<aa.length; j++) { fillform(f,prefix+"["+i+"]",aa[j],zz[i]) } } } } else { keys=zz.keySet().toArray() for(int j=0;j<keys.length;j++) { fillform(f,prefix,keys[j],zz) } } } } /********************************************* * MAIN *********************************************/ static void main(args) { WebResourceContainer container //def TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/10437569498-hospoda-u-druhe-sance/") //def TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/10361564316-sanitka-2/") def TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/10225075918-zdivocela-zeme-iv/?addDate=title") //def TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/10354229723-pripady-1-oddeleni/") //def TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/902567-bob-a-bobek-kralici-z-klobouku/200350950010013-na-ostrove/") CzechTV extractor = new CzechTV() println "PluginName : " + extractor.getExtractorName(); println "TestMatch : " + extractor.extractorMatches(TestUrl); container = extractor.extractItems(TestUrl, 5); println "**** HIGH ****" ;extractor.extractUrl(container.getItems()[0], PreferredQuality.HIGH) //println "**** MEDIUM ****";extractor.extractUrl(container.getItems()[0], PreferredQuality.MEDIUM) //println "**** LOW ****" ;extractor.extractUrl(container.getItems()[0], PreferredQuality.LOW) //println "Druhu URL ******************************************************************************\n\n\n" //TestUrl = new URL("http://www.ceskatelevize.cz/ivysilani/10225075918-zdivocela-zeme-iv/") //container = extractor.extractItems(TestUrl, 5); //println "**** HIGH ****" ;extractor.extractUrl(container.getItems()[0], PreferredQuality.HIGH) } }