From d3d05f9c90b7b8e6c5cb50d06f3c6fe4354c5db9 Mon Sep 17 00:00:00 2001 From: mediaminister Date: Fri, 8 May 2020 12:11:50 +0200 Subject: [PATCH] Play advertisements --- resources/lib/kodiutils.py | 8 ++++ resources/lib/modules/player.py | 6 +++ resources/lib/viervijfzes/content.py | 66 +++++++++++++++++++++++++++- tests/xbmc.py | 17 +++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/resources/lib/kodiutils.py b/resources/lib/kodiutils.py index b694a8d..532854b 100644 --- a/resources/lib/kodiutils.py +++ b/resources/lib/kodiutils.py @@ -190,6 +190,10 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None): """Play the given stream""" from resources.lib.addon import routing + playlist = None + if isinstance(stream, list): + playlist = stream[1:] + stream = stream[0] play_item = xbmcgui.ListItem(label=title, path=stream) if art_dict: @@ -210,6 +214,10 @@ def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None): xbmcplugin.setResolvedUrl(routing.handle, True, listitem=play_item) + if playlist: + for item in playlist: + xbmc.PlayList(1).add(item, listitem=play_item) + def get_search_string(heading='', message=''): """Ask the user for a search string""" diff --git a/resources/lib/modules/player.py b/resources/lib/modules/player.py index 571c711..fc0068d 100644 --- a/resources/lib/modules/player.py +++ b/resources/lib/modules/player.py @@ -34,6 +34,10 @@ def play_from_page(self, channel, path): episode = self._api.get_episode(channel, path) resolved_stream = None + # Get advertisements + ad_streams = self._api.get_ad_streams(episode.channel, episode.program_title, path, episode.uuid, episode.video_type) + _LOGGER.info('Advertisements: %s', ad_streams) + if episode.stream: # We already have a resolved stream. Nice! # We don't need credentials for these streams. @@ -46,6 +50,8 @@ def play_from_page(self, channel, path): _LOGGER.info('Resolved stream: %s', resolved_stream) if resolved_stream: + ad_streams.append(resolved_stream) + resolved_stream = ad_streams titleitem = Menu.generate_titleitem(episode) kodiutils.play(resolved_stream, info_dict=titleitem.info_dict, art_dict=titleitem.art_dict, prop_dict=titleitem.prop_dict) diff --git a/resources/lib/viervijfzes/content.py b/resources/lib/viervijfzes/content.py index 7a135ed..32df3c0 100644 --- a/resources/lib/viervijfzes/content.py +++ b/resources/lib/viervijfzes/content.py @@ -97,10 +97,11 @@ def __repr__(self): class Episode: """ Defines an Episode. """ - def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None, background=None, - duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None): + def __init__(self, uuid=None, video_type=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None, + background=None, duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None): """ :type uuid: str + :type video_type: str :type nodeid: str :type path: str :type channel: str @@ -119,6 +120,7 @@ def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_titl :type stream: string """ self.uuid = uuid + self.video_type = video_type self.nodeid = nodeid self.path = path self.channel = channel @@ -375,6 +377,65 @@ def get_categories(self, channel): return categories + def get_weather(self, channel): + """ Get a weather dictionary. + :type channel: str + :rtype dict + """ + response = self._get_url(self.SITE_APIS[channel] + '/weather', authentication=True) + weather = json.loads(response) + return weather + + def get_ad_streams(self, channel, program, path, uuid, video_type): + """ Get a list of advertisement stream URLs to use for this video. + :type channel: str + :type path: str + :rtype list + """ + ad_streams = [] + ad_url = 'https://pubads.g.doubleclick.net/gampad/ads' + weather = self.get_weather(channel) + channel_info = dict( + vier=dict(cmsid='2493239', network_id='21797861328'), + vijf=dict(cmsid='2493512', network_id='21797861328'), + zes=dict(cmsid='2496240', network_id='21797861328') + ) + network_id = channel_info.get(channel).get('network_id') + from unicodedata import normalize + program = normalize('NFD', program).replace(' ', '-') + program = re.sub(r'[^A-Za-z0-9-]+', '', program).lower() + if program: + iu_id = '/{}/{}/{}/{}'.format(network_id, channel, 'programmas', program) + else: + iu_id = '/{}/{}/'.format(network_id, channel) + params = dict(ad_rule=1, + cmsid=channel_info.get(channel).get('cmsid'), + correlator=int(round(time.time() * 1000)), + sbs_weather_cond=weather.get('summary'), + sbs_weather_temp=weather.get('temperature'), + description_url=path, + env='vp', + gdfp_req=1, + impl='s', + iu=iu_id, + output='vast', + sz='640x360', + unviewed_position_start=1, + url=path, + vid=uuid, + video_type=video_type) + + xml = self._get_url(ad_url, params) + from lxml import etree as ET + tree = ET.fromstring(xml) + for item in tree: + if item.tag == 'Preroll': + url = item.find('Ad').text + xml = self._get_url(url).encode('utf-8') + tree = ET.fromstring(xml) + ad_streams = tree.xpath('/VAST/Ad/InLine/Creatives/Creative/Linear/MediaFiles/MediaFile[@delivery="streaming"]/text()') + return ad_streams + @staticmethod def _extract_programs(html, channel): """ Extract Programs from HTML code """ @@ -535,6 +596,7 @@ def _parse_episode_data(data, season_uuid=None): episode = Episode( uuid=data.get('videoUuid'), + video_type=data.get('type', {}), nodeid=data.get('pageInfo', {}).get('nodeId'), path=data.get('link').lstrip('/'), channel=data.get('pageInfo', {}).get('site'), diff --git a/tests/xbmc.py b/tests/xbmc.py index 88e31d5..e6237c0 100644 --- a/tests/xbmc.py +++ b/tests/xbmc.py @@ -135,6 +135,23 @@ def getPlayingFile(self): return '' +class PlayList(object): # pylint: disable=useless-object-inheritance + """ A stub implementation of the xbmc PlayList class """ + + def __init__(self, playList): + """ A stub constructor for the xbmc PlayList class """ + + def getposition(self): + """ A stub implementation for the xbmc PlayList class getposition() method """ + return 0 + + def add(self, url, listitem=None, index=-1): + """ A stub implementation for the xbmc PlayList class add() method """ + + def size(self): + """ A stub implementation for the xbmc PlayList class size() method """ + + class VideoInfoTag: """ A stub implementation of the xbmc VideoInfoTag class """