diff --git a/ABCiView.bundle/Contents/Code/__init__.py b/ABCiView.bundle/Contents/Code/__init__.py index df4fc0b..a2021a7 100644 --- a/ABCiView.bundle/Contents/Code/__init__.py +++ b/ABCiView.bundle/Contents/Code/__init__.py @@ -3,19 +3,15 @@ ART = 'art-default.jpg' ICON = 'icon-default.jpg' - def Start(): + HTTP.RandomizeUserAgent(browser='Safari') Plugin.AddViewGroup('List', viewMode='List', mediaType='items') Plugin.AddViewGroup('InfoList', viewMode='InfoList', mediaType='items') - -@handler('/video/aubciview', 'Australian ABC iView', art=ART, thumb=ICON) +@handler('/video/iview', 'ABC iView', art=ART, thumb=ICON) def MainMenu(): + oc = ObjectContainer(view_group='List', title2='ABC iView') - - - #oc.add(VideoClipObject(key = RTMPVideoURL(url = 'rtmp://203.18.195.10/ondemand' + '?auth=7B8F0402DD370FF9299E', clip = 'mp4:comedy/madashell_02_08', swf_url = 'http://www.abc.net.au/iview/images/iview.jpg'), rating_key = '123',title = 'TEST')) - cats = iView_Config.List_Categories() for key in cats: @@ -25,88 +21,61 @@ def MainMenu(): )) oc.objects.sort(key=lambda obj: obj.title) - return oc -@route('/video/aubciview/category/{category}') +@route('/video/iview/category/{category}') def GetSeriesByCaegory(category): + cat = iView_Category(category) - oc = ObjectContainer(view_group='List', title2=cat.title) - series = cat.series_list for item in series: oc.add(DirectoryObject( key=Callback(GetEpisodesBySeries, series=item[0]), - title=item[1] + title=item[1], + thumb=Callback(GetSeriesThumb, seriesID=item[0]) )) + oc.objects.sort(key=lambda obj: obj.title) - return oc -@route('/video/aubciview/series/{series}') +def GetSeriesThumb(seriesID): + show = iView_Series(seriesID) + return show.img + +@route('/video/iview/series/{series}') def GetEpisodesBySeries(series): show = iView_Series(series) oc = ObjectContainer(view_group='InfoList', title2=show.title, no_cache=True) - episodes = show.episodes - - rtmp_url = iView_Config.RTMP_URL() - + for item in episodes: - dur = item[5] * 1000 - oc.add(Play_iView(item[1], item[2], item[3], item[4], dur, rtmp_url, item[6])) + oc.add(Play_iView(item['id'], item['title'], item['description'], item['url'], item['thumb'], item['duration'] )) oc.objects.sort(key=lambda obj: obj.title) return oc -@route('/video/aubciview/episode/play') -def Play_iView(iView_Title, iView_Summary, iView_Path, iView_Thumb, iView_Duration, video_url, iView_live=0, - include_container=False): +@route('/video/iview/episode/play') +def Play_iView(video_id, iView_Title, iView_Summary, iView_Path, iView_Thumb, iView_Duration): + HTTP.ClearCache() - - iView_live = int(iView_live) - - call_args = { - "iView_Title": iView_Title, - "iView_Summary": iView_Summary, - "iView_Path": iView_Path, - "iView_Thumb": iView_Thumb, - "iView_Duration": int(iView_Duration), - "video_url": video_url, - "iView_live": iView_live, - "include_container": True, - } - - if iView_live == 1: - rtmpVid = RTMPVideoURL(url=video_url, clip=iView_Path, swf_url=iView_Config.SWF_URL, live=True) - else: - rtmpVid = RTMPVideoURL(url=video_url, clip=iView_Config.CLIP_PATH() + iView_Path, swf_url=iView_Config.SWF_URL) - + Log('==== Video ====') + Log('Title: ' + iView_Title) + Log('Video Path: ' + iView_Path) + Log('==== End Video ====') + vco = VideoClipObject( - key=Callback(Play_iView, **call_args), + url= 'http://abc.net.au/iview/#/view/' + video_id, rating_key=iView_Path, title=iView_Title, summary=iView_Summary, thumb=iView_Thumb, - duration=int(iView_Duration), - items=[ - MediaObject( - parts=[ - PartObject( - key=rtmpVid - ) - ] - ) - ] + duration=iView_Duration, ) - if include_container: - return ObjectContainer(objects=[vco]) - else: - return vco + return vco diff --git a/ABCiView.bundle/Contents/Code/iview_class.py b/ABCiView.bundle/Contents/Code/iview_class.py index e271c4c..6546888 100644 --- a/ABCiView.bundle/Contents/Code/iview_class.py +++ b/ABCiView.bundle/Contents/Code/iview_class.py @@ -16,19 +16,27 @@ class iView_Config(): SERIES_URL = API_URL + 'seriesIndex' SERIES_JSON = JSON.ObjectFromURL(SERIES_URL) category_list = {} + + FALLBACK_PATH = 'rtmp://cp53909.edgefcs.net/ondemand' @classmethod def RTMP_URL(self): - xml = XML.ElementFromURL(url=self.AUTH_URL) - token = xml.xpath('//a:token/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[ - 0] - return xml.xpath('//a:server/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[ - 0] + '?auth=' + token - + xml = XML.ElementFromURL(url=self.AUTH_URL) + token = xml.xpath('//a:token/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[0] + server = xml.xpath('//a:server/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[0] + + if 'http' in server: + return self.FALLBACK_PATH + '?auth=' + token + else: + return server + '?auth=' + token + + @classmethod def CLIP_PATH(self): - xml = XML.ElementFromURL(self.AUTH_URL) + return 'mp4:flash/playback/_definst_/' + + xml = XML.ElementFromURL(self.AUTH_URL) path = xml.xpath('//a:path/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'}) if not path: return 'mp4:' @@ -51,45 +59,44 @@ def List_Categories(self): class iView_Series(object): def __init__(self, key): self.id = key - json = JSON.ObjectFromURL(iView_Config.API_URL + 'series=' + key) - - self.title = json[0]['b'] - self.description = json[0]['c'] - self.category = json[0]['e'] - self.img = json[0]['d'] - self.episode_count = len(json[0]['f']) - self.episodes = self.Episodes(json[0]['f']) + Log('Getting iView series info for:' + iView_Config.API_URL + 'series=' + key) + json = JSON.ObjectFromURL(iView_Config.API_URL + 'series=' + key) + for result in json: + Log('Checking series ID ' + str(key) + ' against results ' + str(result['a']) ) + if str(result['a']) == str(key): + Log('Got match for series ID') + self.title = result['b'] + self.description = result['c'] + self.category = result['e'] + self.img = result['d'] + self.episode_count = len(result['f']) + self.episodes = self.Episodes(result['f']) + else: + Log('rejected series ID match') def Episodes(self, json): eps = [] for ep in json: - id = ep['a'] - title = ep['b'] - description = ep['d'] + episode = {} + episode['id'] = ep['a'] + episode['title'] = ep['b'] + episode['description'] = ep['d'] - live = 0 + episode['live'] = 0 if 'n' in ep: - url = ep['n'][:-4] + episode['url'] = ep['n'][:-4] else: - url = ep['r'] - live = 1 + episode['url'] = ep['r'] + episode['live'] = 1 - thumb = ep['s'] + episode['thumb'] = ep['s'] if 'j' in ep: - duration = int(ep['j']) + episode['duration'] = int(ep['j']) * 1000 else: - duration = 0 - - tmp = [] - tmp.append(id) - tmp.append(title) - tmp.append(description) - tmp.append(url) - tmp.append(thumb) - tmp.append(duration) - tmp.append(live) - eps.append(tmp) + episode['duration'] = 0 + + eps.append(episode) return eps diff --git a/ABCiView.bundle/Contents/Info.plist b/ABCiView.bundle/Contents/Info.plist index 76a0a73..dfa823e 100644 --- a/ABCiView.bundle/Contents/Info.plist +++ b/ABCiView.bundle/Contents/Info.plist @@ -3,7 +3,7 @@ CFBundleIdentifier - com.plexapp.plugins.aubciview + com.plexapp.plugins.iview PlexClientPlatforms * PlexFrameworkVersion diff --git a/ABCiView.bundle/Contents/Services/ServiceInfo.plist b/ABCiView.bundle/Contents/Services/ServiceInfo.plist new file mode 100644 index 0000000..918fd52 --- /dev/null +++ b/ABCiView.bundle/Contents/Services/ServiceInfo.plist @@ -0,0 +1,22 @@ + + + + + URL + + iview + + Identifier + com.plexapp.plugins.iview + URLPatterns + + http://abc.net.au/iview/.+ + + + + PlexFrameworkFlags + + UseRealRTMP + + + \ No newline at end of file diff --git a/ABCiView.bundle/Contents/Services/URL/iview/ServiceCode.pys b/ABCiView.bundle/Contents/Services/URL/iview/ServiceCode.pys new file mode 100644 index 0000000..0f94041 --- /dev/null +++ b/ABCiView.bundle/Contents/Services/URL/iview/ServiceCode.pys @@ -0,0 +1,107 @@ +# getSeries: http://iview.abc.net.au/api/legacy/flash/?series=$ID +# getAllSeries: http://iview.abc.net.au/api/legacy/flash/?series=all + +def MetadataObjectForURL(url): + + #TODO get normalised url + RE_PLAYLIST = Regex('([0-9]+)$', Regex.DOTALL) + ID = RE_PLAYLIST.search(url).group(0) + data = JSON.ObjectFromURL('http://iview.abc.net.au/api/legacy/flash/?series='+ID) + + for result in data: + Log('Checking for ID:' + str(ID) + ' and got ' + str(result['a']) ) + Log('matched ID so getting episodes data') + episodes = result['f'] + show = result['b'] + RE_EPISODE = Regex('^'+show+' (.*)$') + + for episode in episodes: + if episode['a'] == ID: + title = RE_EPISODE.search(episode['b']).group(1) + summary = episode['d'] + thumb = episode['s'] + duration = int(episode['j'])*1000 + content_rating = episode['m'] + try: + season = int(episode['u']) + except: + season = None + + try: + absolute_index = int(episode['v']) + except: + absolute_index = None + expires_on = episode['g'] + aired = Datetime.ParseDate(episode['f']) + summary = summary + '\n\nExpires: ' + expires_on + + return EpisodeObject( + title=title, + summary=summary, + thumb=thumb, + duration=duration, + show = show, + season = season, + absolute_index = absolute_index, + originally_available_at = aired + ) + +def MediaObjectsForURL(url): + + container = Container.MP4 + video_codec = VideoCodec.H264 + audio_codec = AudioCodec.AAC + audio_channels = 2 + + return [ + MediaObject( + protocol='rtmp', + video_resolution='576', + audio_channels=2, + parts=[PartObject(key=Callback(PlayVideo, url=url))], + ), + ] + +@indirect +def PlayVideo(url): + BASE_URL = 'http://www.abc.net.au/iview/' + CFG_URL = BASE_URL + 'xml/config.xml' + CFG_XML = XML.ElementFromURL(CFG_URL) + AUTH_URL = CFG_XML.xpath('/config/param[@name="auth"]')[0].get("value") + FALLBACK_PATH = 'rtmp://cp53909.edgefcs.net/ondemand' + xml = XML.ElementFromURL(url=AUTH_URL) + token = xml.xpath('//a:token/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[0] + server = xml.xpath('//a:server/text()', namespaces={'a': 'http://www.abc.net.au/iView/Services/iViewHandshaker'})[0] + + if 'http' in server: + rtmpURL = FALLBACK_PATH + '?auth=' + token + else: + rtmpURL = server + '?auth=' + token + + RE_ID = Regex('([0-9]+)$', Regex.DOTALL) + ID = RE_ID.search(url).group(0) + #TODO: handle if URL is of different format (ie .scrape page and get same share liknk) + API_URL = CFG_XML.xpath('/config/param[@name="api"]')[0].get("value") + + #API returns series even if querying with episode ID + data = JSON.ObjectFromURL(API_URL + 'series=' + str(ID)) + + for results in data: + episodes = results['f'] + for episode in episodes: + if episode['a'] == ID: + live = 0 + if 'n' in episode: + video_url = episode['n'][:-4] + else: + video_url = episode['r'] + live = 1 + + SWF_URL = 'http://www.abc.net.au/iview/images/iview.jpg' + CLIP = 'mp4:flash/playback/_definst_/' + if live == 1: + rtmpVid = RTMPVideoURL(url=rtmpURL, clip=video_url, swf_url=SWF_URL, live=True) + else: + rtmpVid = RTMPVideoURL(url=rtmpURL, clip=CLIP + video_url, swf_url=SWF_URL) + + return IndirectResponse(VideoClipObject, key=rtmpVid) \ No newline at end of file