Skip to content
This repository was archived by the owner on Oct 21, 2024. It is now read-only.

Commit 94a80ce

Browse files
committed
Play advertisements
1 parent 121ea88 commit 94a80ce

File tree

4 files changed

+95
-2
lines changed

4 files changed

+95
-2
lines changed

resources/lib/kodiutils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True
190190
def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None):
191191
"""Play the given stream"""
192192
from resources.lib.addon import routing
193+
playlist = None
194+
if isinstance(stream, list):
195+
playlist = stream[1:]
196+
stream = stream[0]
193197

194198
play_item = xbmcgui.ListItem(label=title, path=stream)
195199
if art_dict:
@@ -210,6 +214,10 @@ def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None):
210214

211215
xbmcplugin.setResolvedUrl(routing.handle, True, listitem=play_item)
212216

217+
if playlist:
218+
for item in playlist:
219+
xbmc.PlayList(1).add(item, listitem=play_item)
220+
213221

214222
def get_search_string(heading='', message=''):
215223
"""Ask the user for a search string"""

resources/lib/modules/player.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ def play_from_page(self, channel, path):
3434
episode = self._api.get_episode(channel, path)
3535
resolved_stream = None
3636

37+
# Get advertisements
38+
ad_streams = self._api.get_ad_streams(episode.channel, episode.program_title, path, episode.uuid, episode.video_type)
39+
_LOGGER.info('Advertisements: %s', ad_streams)
40+
3741
if episode.stream:
3842
# We already have a resolved stream. Nice!
3943
# We don't need credentials for these streams.
@@ -46,6 +50,8 @@ def play_from_page(self, channel, path):
4650
_LOGGER.info('Resolved stream: %s', resolved_stream)
4751

4852
if resolved_stream:
53+
ad_streams.append(resolved_stream)
54+
resolved_stream = ad_streams
4955
titleitem = Menu.generate_titleitem(episode)
5056
kodiutils.play(resolved_stream, info_dict=titleitem.info_dict, art_dict=titleitem.art_dict, prop_dict=titleitem.prop_dict)
5157

resources/lib/viervijfzes/content.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@ def __repr__(self):
9797
class Episode:
9898
""" Defines an Episode. """
9999

100-
def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None, background=None,
101-
duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None):
100+
def __init__(self, uuid=None, video_type=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None,
101+
background=None, duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None):
102102
"""
103103
:type uuid: str
104+
:type video_type: str
104105
:type nodeid: str
105106
:type path: str
106107
:type channel: str
@@ -119,6 +120,7 @@ def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_titl
119120
:type stream: string
120121
"""
121122
self.uuid = uuid
123+
self.video_type = video_type
122124
self.nodeid = nodeid
123125
self.path = path
124126
self.channel = channel
@@ -375,6 +377,65 @@ def get_categories(self, channel):
375377

376378
return categories
377379

380+
def get_weather(self, channel):
381+
""" Get a weather dictionary.
382+
:type channel: str
383+
:rtype dict
384+
"""
385+
response = self._get_url(self.SITE_APIS[channel] + '/weather', authentication=True)
386+
weather = json.loads(response)
387+
return weather
388+
389+
def get_ad_streams(self, channel, program, path, uuid, video_type):
390+
""" Get a list of advertisement stream URLs to use for this video.
391+
:type channel: str
392+
:type path: str
393+
:rtype list
394+
"""
395+
ad_streams = []
396+
ad_url = 'https://pubads.g.doubleclick.net/gampad/ads'
397+
weather = self.get_weather(channel)
398+
channel_info = dict(
399+
vier=dict(cmsid='2493239', network_id='21797861328'),
400+
vijf=dict(cmsid='2493512', network_id='21797861328'),
401+
zes=dict(cmsid='2496240', network_id='21797861328')
402+
)
403+
network_id = channel_info.get(channel).get('network_id')
404+
from unicodedata import normalize
405+
program = normalize('NFD', program).replace(' ', '-')
406+
program = re.sub(r'[^A-Za-z0-9-]+', '', program).lower()
407+
if program:
408+
iu_id = '/{}/{}/{}/{}'.format(network_id, channel, 'programmas', program)
409+
else:
410+
iu_id = '/{}/{}/'.format(network_id, channel)
411+
params = dict(ad_rule=1,
412+
cmsid=channel_info.get(channel).get('cmsid'),
413+
correlator=int(round(time.time() * 1000)),
414+
sbs_weather_cond=weather.get('summary'),
415+
sbs_weather_temp=weather.get('temperature'),
416+
description_url=path,
417+
env='vp',
418+
gdfp_req=1,
419+
impl='s',
420+
iu=iu_id,
421+
output='vast',
422+
sz='640x360',
423+
unviewed_position_start=1,
424+
url=path,
425+
vid=uuid,
426+
video_type=video_type)
427+
428+
xml = self._get_url(ad_url, params)
429+
from lxml import etree as ET
430+
tree = ET.fromstring(xml)
431+
for item in tree:
432+
if item.tag == 'Preroll':
433+
url = item.find('Ad').text
434+
xml = self._get_url(url).encode('utf-8')
435+
tree = ET.fromstring(xml)
436+
ad_streams = tree.xpath('/VAST/Ad/InLine/Creatives/Creative/Linear/MediaFiles/MediaFile[@delivery="streaming"]/text()')
437+
return ad_streams
438+
378439
@staticmethod
379440
def _extract_programs(html, channel):
380441
""" Extract Programs from HTML code """
@@ -535,6 +596,7 @@ def _parse_episode_data(data, season_uuid=None):
535596

536597
episode = Episode(
537598
uuid=data.get('videoUuid'),
599+
video_type=data.get('type', {}),
538600
nodeid=data.get('pageInfo', {}).get('nodeId'),
539601
path=data.get('link').lstrip('/'),
540602
channel=data.get('pageInfo', {}).get('site'),

tests/xbmc.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ def getPlayingFile(self):
135135
return ''
136136

137137

138+
class PlayList(object): # pylint: disable=useless-object-inheritance
139+
""" A stub implementation of the xbmc PlayList class """
140+
141+
def __init__(self, playList):
142+
""" A stub constructor for the xbmc PlayList class """
143+
144+
def getposition(self):
145+
""" A stub implementation for the xbmc PlayList class getposition() method """
146+
return 0
147+
148+
def add(self, url, listitem=None, index=-1):
149+
""" A stub implementation for the xbmc PlayList class add() method """
150+
151+
def size(self):
152+
""" A stub implementation for the xbmc PlayList class size() method """
153+
154+
138155
class VideoInfoTag:
139156
""" A stub implementation of the xbmc VideoInfoTag class """
140157

0 commit comments

Comments
 (0)