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

Commit 82e1dc2

Browse files
committed
Play advertisements
1 parent 591cd91 commit 82e1dc2

File tree

3 files changed

+129
-38
lines changed

3 files changed

+129
-38
lines changed

resources/lib/kodiutils.py

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -193,43 +193,59 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True
193193
xbmcplugin.endOfDirectory(routing.handle, succeeded, cacheToDisc=cache)
194194

195195

196-
def play(stream, stream_type=STREAM_HLS, license_key=None, title=None, art_dict=None, info_dict=None, prop_dict=None, stream_dict=None):
196+
def play(stream, stream_type=STREAM_HLS, license_key=None, title=None, art_dict=None, info_dict=None, prop_dict=None, stream_dict=None, ads_list=None):
197197
"""Play the given stream"""
198198
from resources.lib.addon import routing
199-
200-
play_item = xbmcgui.ListItem(label=title, path=stream)
201-
if art_dict:
202-
play_item.setArt(art_dict)
203-
if info_dict:
204-
play_item.setInfo(type='video', infoLabels=info_dict)
205-
if prop_dict:
206-
play_item.setProperties(prop_dict)
207-
if stream_dict:
208-
play_item.addStreamInfo('video', stream_dict)
209-
210-
# Setup Inputstream Adaptive
211-
if kodi_version_major() >= 19:
212-
play_item.setProperty('inputstream', 'inputstream.adaptive')
213-
else:
214-
play_item.setProperty('inputstreamaddon', 'inputstream.adaptive')
215-
216-
if stream_type == STREAM_HLS:
217-
play_item.setProperty('inputstream.adaptive.manifest_type', 'hls')
218-
play_item.setMimeType('application/vnd.apple.mpegurl')
219-
220-
elif stream_type == STREAM_DASH:
221-
play_item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
222-
play_item.setMimeType('application/dash+xml')
223-
if license_key is not None:
224-
import inputstreamhelper
225-
is_helper = inputstreamhelper.Helper('mpd', drm='com.widevine.alpha')
226-
if is_helper.check_inputstream():
227-
play_item.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')
228-
play_item.setProperty('inputstream.adaptive.license_key', license_key)
229-
230-
play_item.setContentLookup(False)
231-
232-
xbmcplugin.setResolvedUrl(routing.handle, True, listitem=play_item)
199+
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
200+
playlist.clear()
201+
202+
if ads_list:
203+
ads_list.append(stream)
204+
stream = ads_list
205+
206+
if not isinstance(stream, list):
207+
stream = [stream]
208+
209+
for i, url in enumerate(stream):
210+
play_item = xbmcgui.ListItem(label=title, path=url)
211+
if art_dict:
212+
play_item.setArt(art_dict)
213+
if info_dict:
214+
play_item.setInfo(type='video', infoLabels=info_dict)
215+
if prop_dict:
216+
play_item.setProperties(prop_dict)
217+
if stream_dict:
218+
play_item.addStreamInfo('video', stream_dict)
219+
220+
if not url.endswith('.mp4'):
221+
# Setup Inputstream Adaptive
222+
if kodi_version_major() >= 19:
223+
play_item.setProperty('inputstream', 'inputstream.adaptive')
224+
else:
225+
play_item.setProperty('inputstreamaddon', 'inputstream.adaptive')
226+
227+
if stream_type == STREAM_HLS:
228+
play_item.setProperty('inputstream.adaptive.manifest_type', 'hls')
229+
play_item.setMimeType('application/vnd.apple.mpegurl')
230+
231+
elif stream_type == STREAM_DASH:
232+
play_item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
233+
play_item.setMimeType('application/dash+xml')
234+
if license_key is not None:
235+
import inputstreamhelper
236+
is_helper = inputstreamhelper.Helper('mpd', drm='com.widevine.alpha')
237+
if is_helper.check_inputstream():
238+
play_item.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')
239+
play_item.setProperty('inputstream.adaptive.license_key', license_key)
240+
241+
play_item.setContentLookup(False)
242+
243+
if i == 0:
244+
first_item = play_item
245+
246+
playlist.add(url=url, listitem=play_item, index=i)
247+
248+
xbmcplugin.setResolvedUrl(routing.handle, True, listitem=first_item)
233249

234250

235251
def get_search_string(heading='', message=''):

resources/lib/modules/player.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ def play_from_page(self, channel, path):
4848
kodiutils.ok_dialog(message=kodiutils.localize(30712))
4949
return
5050

51+
# Get advertisements
52+
ad_streams = self._api.get_ad_streams(episode.channel, episode.program_title, path, episode.uuid, episode.video_type, kodiutils.get_setting('username'))
53+
_LOGGER.info('Advertisements: %s', ad_streams)
54+
5155
if episode.stream:
5256
# We already have a resolved stream. Nice!
5357
# We don't need credentials for these streams.
@@ -78,7 +82,8 @@ def play_from_page(self, channel, path):
7882
license_key,
7983
info_dict=titleitem.info_dict,
8084
art_dict=titleitem.art_dict,
81-
prop_dict=titleitem.prop_dict)
85+
prop_dict=titleitem.prop_dict,
86+
ads_list=ad_streams)
8287

8388
def play(self, uuid):
8489
""" Play the requested item.

resources/lib/viervijfzes/content.py

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

101-
def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None, background=None,
102-
duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None):
101+
def __init__(self, uuid=None, video_type=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, cover=None,
102+
background=None, duration=None, season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None):
103103
"""
104104
:type uuid: str
105+
:type video_type: str
105106
:type nodeid: str
106107
:type path: str
107108
:type channel: str
@@ -120,6 +121,7 @@ def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_titl
120121
:type stream: string
121122
"""
122123
self.uuid = uuid
124+
self.video_type = video_type
123125
self.nodeid = nodeid
124126
self.path = path
125127
self.channel = channel
@@ -401,6 +403,73 @@ def get_categories(self, channel):
401403

402404
return categories
403405

406+
def get_weather(self, channel):
407+
""" Get a weather dictionary.
408+
:type channel: str
409+
:rtype dict
410+
"""
411+
response = self._get_url(self.SITE_APIS[channel] + '/weather', authentication=True)
412+
weather = json.loads(response)
413+
return weather
414+
415+
def get_ad_streams(self, channel, program, path, uuid, video_type, username):
416+
""" Get a list of advertisement stream URLs to use for this video.
417+
:type channel: str
418+
:type path: str
419+
:rtype list
420+
"""
421+
ad_streams = []
422+
ad_url = 'https://pubads.g.doubleclick.net/gampad/ads'
423+
weather = self.get_weather(channel)
424+
channel_info = dict(
425+
vier=dict(cmsid='2493239', network_id='21797861328'),
426+
vijf=dict(cmsid='2493512', network_id='21797861328'),
427+
zes=dict(cmsid='2496240', network_id='21797861328')
428+
)
429+
network_id = channel_info.get(channel).get('network_id')
430+
from unicodedata import normalize
431+
program = normalize('NFD', program).replace(' ', '-')
432+
program = re.sub(r'[^A-Za-z0-9-]+', '', program).lower()
433+
from hashlib import sha1
434+
ppid = sha1(username.encode('utf-8')).hexdigest()
435+
if program:
436+
iu_id = '/{}/{}/{}/{}'.format(network_id, channel, 'programmas', program)
437+
else:
438+
iu_id = '/{}/{}/'.format(network_id, channel)
439+
params = dict(ad_rule=1,
440+
cmsid=channel_info.get(channel).get('cmsid'),
441+
correlator=int(round(time.time() * 1000)),
442+
sbs_weather_cond=weather.get('summary'),
443+
sbs_weather_temp=weather.get('temperature'),
444+
description_url=path,
445+
env='vp',
446+
gdfp_req=1,
447+
impl='s',
448+
iu=iu_id,
449+
output='vast',
450+
pp='SBSNoDash',
451+
ppid=ppid,
452+
sz='640x360',
453+
unviewed_position_start=1,
454+
url=path,
455+
vid=uuid,
456+
video_type=video_type)
457+
458+
xml = self._get_url(ad_url, params)
459+
import xml.etree.ElementTree as ET
460+
tree = ET.fromstring(xml)
461+
for item in tree:
462+
if item.tag == 'Preroll':
463+
url = item.find('Ad').text
464+
xml = self._get_url(url)
465+
tree = ET.fromstring(xml)
466+
for adv in tree.findall('.//Ad'):
467+
for stream in adv.findall('.//MediaFile'):
468+
if stream.get('type') == 'video/mp4' and stream.get('width') == '1920':
469+
ad_streams.append(stream.text)
470+
break
471+
return ad_streams
472+
404473
@staticmethod
405474
def _extract_programs(html, channel):
406475
""" Extract Programs from HTML code """
@@ -561,6 +630,7 @@ def _parse_episode_data(data, season_uuid=None):
561630

562631
episode = Episode(
563632
uuid=data.get('videoUuid'),
633+
video_type=data.get('type', {}),
564634
nodeid=data.get('pageInfo', {}).get('nodeId'),
565635
path=data.get('link').lstrip('/'),
566636
channel=data.get('pageInfo', {}).get('site'),

0 commit comments

Comments
 (0)