def parse_json_video(video_data): """Parse JSON stream data Parse the JSON data and construct a video object from it for a list of videos """ attrs = video_data.get('customAttributes') if not attrs: return video = classes.Video() video.title = utils.ensure_ascii(video_data.get('title')) video.description = utils.ensure_ascii(video_data.get('description')) video.thumbnail = video_data.get('thumbnailPath') try: timestamp = time.mktime( time.strptime(video_data['customPublishDate'], '%Y-%m-%dT%H:%M:%S.%f+0000')) video.date = datetime.date.fromtimestamp(timestamp) except Exception: pass if video_data.get('entitlement'): video.subscription_required = True # Look for 'national' stream (e.g. Foxtel) video.video_id = get_attr(attrs, 'brightcove video id') if video.video_id: video.type = 'B' else: video.video_id = 'ref:{0}'.format(get_attr(attrs, 'ooyala embed code')) video.type = 'O' video.live = False return video
def list_matches(params): """ go through our xml file and retrive all we need to pass to kodi""" data = fetch_url(config.VIDEO_URL) tree = ET.fromstring(data) listing = [] for elem in tree.findall("MediaSection"): for gm in elem.findall('Item'): # remove items with no video eg. news articles if not gm.attrib['Type'] == 'V': continue g = classes.Video() g.title = utils.ensure_ascii(gm.find('Title').text) desc = gm.find('Description') if desc is not None: if desc.text is not None: g.desc = gm.find('Description').text.encode( 'ascii', 'replace') # remove PSA videos if g.title.startswith('Better Choices'): continue g.video_id = gm.find('Video').attrib['Id'] # keep live videos out of other submenus and vice versa if not gm.find('LiveNow').text: continue g.thumb = gm.find('FullImageUrl').text game_date = utils.ensure_ascii(gm.find('Date').text) g.time = game_date[game_date.find(' ') + 2:] listing.append(g) return listing
def get_videos(params): category = params.get('category') if category in ['Match Highlights', 'Match Replays']: data_url = config.TOPICS_URL.format( quote(config.CATEGORY_LOOKUP[category])) else: data_url = config.VIDEO_URL tree = ET.fromstring(fetch_url(data_url)) listing = [] for section in tree.findall('MediaSection'): for item in section: if not item.attrib['Type'] == 'V': continue v = classes.Video() v.desc = item.find('Description').text v.title = item.find('Title').text v.time = item.find('Timestamp').text video_id = item.find('Video') if video_id is not None: v.video_id = video_id.attrib.get('Id') v.policy_key = video_id.attrib.get('PolicyKey') v.account_id = video_id.attrib.get('AccountId') v.thumb = item.find('FullImageUrl').text v.link_id = item.find('Id').text listing.append(v) return listing
def play_video(params): """ Play a video by the provided path. :param path: str """ if 'dummy' in params: if params['dummy'] == 'True': return v = classes.Video() v.parse_params(params) try: # ticket = stream_auth.get_user_ticket() media_auth_token = None # if v.live == 'true': # media_auth_token = stream_auth.get_media_auth_token( # ticket, v.video_id) playlist = comm.get_stream_url(v, media_auth_token) play_item = xbmcgui.ListItem(path=playlist) xbmcplugin.setResolvedUrl(_handle, True, listitem=play_item) except Exception: utils.handle_error('Unable to play video') raise
def get_upcoming(): """Make a dummy file list for users to see upcoming matches/times""" season_data = json.loads(fetch_url(config.SEASONS_URL, request_token=True)) current_season = season_data.get('currentSeasonId') current_round = None for s in season_data.get('seasons'): if s.get('id') == current_season: current_round = s.get('currentRoundId') break if not current_round: return None fixture_url = config.FIXTURE_URL.format(current_season, current_round) fixture_data = json.loads(fetch_url(fixture_url, request_token=True)) listing = [] for match in fixture_data.get('fixtures'): if match.get('status') in [ 'SCHEDULED', 'UNCONFIRMED_TEAMS', 'CONFIRMED_TEAMS' ]: v = classes.Video() try: home = match['homeTeam'].get('teamName') away = match['awayTeam'].get('teamName') except KeyError: continue match_time = get_airtime(match.get('utcStartTime')) title = '{home} vs {away} - {time}' v.title = title.format(home=home, away=away, time=match_time) v.isdummy = True v.url = 'null' listing.append(v) return listing
def test_make_kodi_url(self): video = classes.Video() attrs = OrderedDict( sorted(fakes.FAKE_VIDEO_ATTRS.items(), key=lambda x: x[0])) for k, v in attrs.items(): setattr(video, k, v) self.assertEqual(fakes.FAKE_VIDEO_URL, video.make_kodi_url())
def get_upcoming(): """ similar to get_score but this time we are searching for upcoming live match info """ listing = [] for mode in ['SUPER_NETBALL', 'INTERNATIONAL']: data = fetch_url(config.SCORE_URL.format(mode=mode)) tree = ET.fromstring(data) for elem in tree.findall("Day"): for subelem in elem.findall("Game"): if subelem.find('GameState').text == 'Full Time': continue v = classes.Video() home = subelem.find('HomeTeam').attrib['FullName'] away = subelem.find('AwayTeam').attrib['FullName'] timestamp = subelem.find('Timestamp').text # convert zulu to local time airtime = get_airtime(timestamp) title = ('[COLOR red]Upcoming:[/COLOR] ' '{0} v {1} - [COLOR yellow]{2}[/COLOR]') v.title = title.format(home, away, airtime) v.dummy = True listing.append(v) return listing
def test_make_kodi_url(self, mock_version): mock_version.return_value = '1.0.0' video = classes.Video() attrs = OrderedDict( sorted(fakes.FAKE_VIDEO_ATTRS.items(), key=lambda x: x[0])) for k, v in attrs.items(): setattr(video, k, v) self.assertEqual(fakes.FAKE_VIDEO_URL, video.make_kodi_url())
def get_aflw_videos(): data = fetch_url(config.AFLW_LONG_URL) tree = ET.fromstring(data) listing = [] for elem in tree.findall('MediaSection'): for video in elem.findall('Item'): if video.attrib['Type'] == 'V': v = classes.Video() v.title = video.find('Title').text v.thumbnail = video.find('FullImageUrl').text v.type = video.find('Video').attrib['Type'] v.video_id = video.find('Video').attrib['Id'] v.policy_key = video.find('Video').attrib['PolicyKey'] v.account_id = video.find('Video').attrib['AccountId'] listing.append(v) return listing
def parse_json_live(video_data): """Parse JSON live stream data Parse the JSON data for live match and construct a video object from it for a list of videos """ streams = video_data.get('videoStreams') video_stream = None for stream in streams: for attrib in stream.get('customAttributes'): if attrib.get('attrName') in [ 'brightcove_videoid', 'brightcove_videoid_VIC' ]: video_stream = stream break if video_stream: break if not video_stream: return attrs = video_stream.get('customAttributes') video = classes.Video() title = utils.ensure_ascii(video_data.get('title')) video.title = '[COLOR green][LIVE NOW][/COLOR] {0}'.format(title) video.thumbnail = get_attr(attrs, 'imageURL') if get_attr(attrs, 'entitlement') == 'true': video.subscription_required = True # Look for 'national' stream (e.g. Foxtel) video_id = get_attr(attrs, 'brightcove_videoid') if not video_id: video_id = get_attr(attrs, 'brightcove_videoid_VIC') if not video_id: utils.log( 'Unable to find video ID from stream data: {0}'.format(video_data)) raise exceptions.AussieAddonsException('Unable to find video ' 'ID from stream data.') video.video_id = video_id video.live = True video.type = 'B' return video
def get_live_matches(): listing = [] for box in get_box_numbers(): tree = ET.fromstring(fetch_url(config.BOX_URL.format(box))) if tree.find('LiveVideo') is not None: for item in tree.find('LiveVideo').findall('Item'): v = classes.Video() v.title = item.find('Title').text v.time = item.find('Timestamp').text v.video_id = item.find('Video').attrib.get('Id') v.account_id = item.find('Video').attrib.get('AccountId') v.policy_key = item.find('Video').attrib.get('PolicyKey') v.type = item.find('Video').attrib.get('Type') v.p_code = item.find('Video').attrib.get('PCode') v.thumb = item.find('FullImageUrl').text v.link_id = item.find('Id').text v.live = 'true' listing.append(v) return listing
def get_upcoming(): """ similar to get_score but this time we are searching for upcoming live match info""" tree = ET.fromstring(fetch_url(config.SCORE_URL)) listing = [] for elem in tree.findall("Day"): for subelem in elem.findall("Game"): if subelem.find('PercentComplete').text == '0': g = classes.Video() home = subelem.find('HomeTeam').attrib['Name'] away = subelem.find('AwayTeam').attrib['Name'] timestamp = subelem.find('Timestamp').text # convert zulu to local time airtime = get_airtime(timestamp) title = ('[COLOR red]Upcoming:[/COLOR] ' '{0} v {1} - [COLOR yellow]{2}[/COLOR]') g.title = title.format(home, away, airtime) g.dummy = True listing.append(g) return listing
def list_matches(params): """ go through our xml file and retrive all we need to pass to kodi """ category = params['category'] if category == 'livematches': return list_live_matches() if category == 'Match Replays': url = config.TAGGEDLIST_REPLAY_URL else: url = config.LONGLIST_URL listing = [] for mode in ['SUPER_NETBALL', 'INTERNATIONAL']: data = fetch_url(url.format(mode=mode)) tree = ET.fromstring(data) for elem in tree.findall("MediaSection"): for gm in elem.findall('Item'): # remove items with no video eg. news articles if not gm.attrib['Type'] == 'V': continue # filter videos by category for metadata in gm.find('Metadata').findall('Data'): key = metadata.attrib['Key'] if key == 'contentType': content_type = metadata.attrib['Value'] if content_type != category: continue v = classes.Video() v.title = utils.ensure_ascii(gm.find('Title').text) v.video_id = gm.find('Video').attrib['Id'] v.account_id = gm.find('Video').attrib['AccountId'] v.policy_key = gm.find('Video').attrib['PolicyKey'] v.live = gm.find('LiveNow').text v.thumb = gm.find('FullImageUrl').text v.time = utils.ensure_ascii(gm.find('Date').text) v.date = gm.find('Timestamp').text listing.append(v) listing = sorted(listing, key=lambda x: x.date, reverse=True) return listing
def list_live_matches(): """ go through list of xml objects and return listing of game objects """ tree_list = find_live_matches() listing = [] for tree in tree_list: v = classes.Video() home = tree.find('HomeTeam').attrib['FullName'] away = tree.find('AwayTeam').attrib['FullName'] match_id = tree.find('Id').text score = get_score(match_id) title = '[COLOR green][LIVE NOW][/COLOR] {0} v {1} {2}' v.title = title.format(home, away, score) media_url = tree.find('WatchButton').find('URL').text video_id = media_url[media_url.find('Id=') + 3:] media_tree = get_media_tree(video_id) v.video_id = media_tree.find('Video').attrib['Id'] v.account_id = media_tree.find('Video').attrib['AccountId'] v.policy_key = media_tree.find('Video').attrib['PolicyKey'] v.live = 'true' listing.append(v) return listing
def get_aflw_upcoming(): """ similar to get_score but this time we are searching for upcoming live match info """ data = fetch_url(config.AFLW_SCORE_URL) tree = ET.fromstring(data) listing = [] for elem in tree.findall("Day"): for subelem in elem.findall("Game"): if subelem.find('GameState').text == 'COMPLETE': continue v = classes.Video() home = subelem.find('HomeTeam').attrib['FullName'] away = subelem.find('AwayTeam').attrib['FullName'] timestamp = subelem.find('Timestamp').text # convert zulu to local time airtime = get_airtime(timestamp, aflw=True) title = ('[COLOR red]AFLW:[/COLOR] ' '{0} vs {1} - {2}') v.title = title.format(home, away, airtime) v.dummy = True listing.append(v) return listing
def test_get_airtime(self): video = classes.Video() video.parse_kodi_url(fakes.FAKE_VIDEO_URL) expected = 'Saturday 2 May @ 4:00 PM' self.assertEqual(expected, video.get_airtime())
def test_parse_kodi_url(self): video = classes.Video() video.parse_kodi_url(fakes.FAKE_VIDEO_URL) observed = video.make_kodi_url() self.assertEqual(fakes.FAKE_VIDEO_URL, observed)
def test_parse_kodi_url(self, mock_version): mock_version.return_value = '1.0.0' video = classes.Video() video.parse_kodi_url(fakes.FAKE_VIDEO_URL) observed = video.make_kodi_url() self.assertEqual(fakes.FAKE_VIDEO_URL, observed)
def play(url): try: params = utils.get_url(url) v = classes.Video() v.parse_kodi_url(url) live = v.live == 'True' if params.get('isdummy'): xbmcgui.Dialog().ok( 'Dummy item', 'This item is not playable, it is used only to display ' 'the upcoming schedule. Please check back once the match ' 'has started. Playable matches will have "LIVE NOW" in ' 'green next to the title.') return if live: media_auth_token = None if params.get('subscription_required') == 'True': media_auth_token = stream_auth.get_media_auth_token( stream_auth.get_user_token(), v.video_id) stream_url = comm.get_stream_url(v, media_auth_token) stream_data = {'stream_url': str(stream_url)} else: stream_url = comm.get_bc_url(v) stream_data = {'stream_url': str(stream_url)} thumb = v.get_thumbnail() listitem = xbmcgui.ListItem(label=v.get_title(), path=stream_data.get('stream_url')) listitem.setArt({'icon': thumb, 'thumb': thumb}) if not live: listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'hls') listitem.setProperty('inputstream.adaptive.license_key', stream_data.get('stream_url')) else: drm_helper = drmhelper.helper.DRMHelper() addon = drm_helper.get_addon() if addon: ia_ver = addon.getAddonInfo('version') kodi_ver = utils.get_kodi_major_version() ia_capable = False if kodi_ver == 18: if LooseVersion(ia_ver) >= LooseVersion('2.4.3'): ia_capable = True elif kodi_ver == 19: if LooseVersion(ia_ver) >= LooseVersion('2.5.4'): ia_capable = True if ia_capable: listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'hls') listitem.setProperty('inputstream.adaptive.license_key', stream_data.get('stream_url')) listitem.addStreamInfo('video', v.get_kodi_stream_info()) listitem.setInfo('video', v.get_kodi_list_item()) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=listitem) except Exception: utils.handle_error('Unable to play video')