From df453ba73edbaddbd7bd171af18f0e3cb08c3bbc Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Sun, 5 May 2019 02:02:57 +0200 Subject: [PATCH] WIP: Reorganize structure and design --- Build-Zip.ps1 | 2 +- Makefile | 6 +- addon.py | 287 +++++++++++++++--- addon.xml | 3 +- resources/lib/__init__.py | 0 resources/lib/helperobjects/__init__.py | 0 resources/lib/helperobjects/apidata.py | 48 --- resources/lib/helperobjects/helperobjects.py | 42 --- resources/lib/helperobjects/streamurls.py | 35 --- resources/lib/kodiwrappers/__init__.py | 0 resources/lib/vrtplayer/actions.py | 17 -- resources/lib/vrtplayer/tvguide.py | 142 --------- service.py | 19 +- test/vrtplayertests.py | 11 +- {resources => vrtnu}/__init__.py | 0 .../vrtplayer/__init__.py => vrtnu/data.py | 8 + vrtnu/helperobjects.py | 127 ++++++++ .../lib/kodiwrappers => vrtnu}/kodiwrapper.py | 15 +- .../vrtplayer => vrtnu}/metadatacreator.py | 2 +- .../lib/vrtplayer => vrtnu}/statichelper.py | 0 .../lib/vrtplayer => vrtnu}/streamservice.py | 29 +- .../lib/vrtplayer => vrtnu}/tokenresolver.py | 4 +- .../lib/vrtplayer => vrtnu}/vrtapihelper.py | 20 +- .../lib/vrtplayer => vrtnu}/vrtplayer.py | 91 ++---- 24 files changed, 459 insertions(+), 449 deletions(-) delete mode 100644 resources/lib/__init__.py delete mode 100644 resources/lib/helperobjects/__init__.py delete mode 100644 resources/lib/helperobjects/apidata.py delete mode 100644 resources/lib/helperobjects/helperobjects.py delete mode 100644 resources/lib/helperobjects/streamurls.py delete mode 100644 resources/lib/kodiwrappers/__init__.py delete mode 100644 resources/lib/vrtplayer/actions.py delete mode 100644 resources/lib/vrtplayer/tvguide.py rename {resources => vrtnu}/__init__.py (100%) rename resources/lib/vrtplayer/__init__.py => vrtnu/data.py (94%) create mode 100644 vrtnu/helperobjects.py rename {resources/lib/kodiwrappers => vrtnu}/kodiwrapper.py (96%) rename {resources/lib/vrtplayer => vrtnu}/metadatacreator.py (99%) rename {resources/lib/vrtplayer => vrtnu}/statichelper.py (100%) rename {resources/lib/vrtplayer => vrtnu}/streamservice.py (89%) rename {resources/lib/vrtplayer => vrtnu}/tokenresolver.py (98%) rename {resources/lib/vrtplayer => vrtnu}/vrtapihelper.py (95%) rename {resources/lib/vrtplayer => vrtnu}/vrtplayer.py (52%) diff --git a/Build-Zip.ps1 b/Build-Zip.ps1 index 400a9c42..d0eeec96 100755 --- a/Build-Zip.ps1 +++ b/Build-Zip.ps1 @@ -3,7 +3,7 @@ Set-StrictMode -Version 5.0 $include_files = @( 'addon.py', 'addon.xml', 'LICENSE', 'README.md', 'service.py' ) -$include_paths = @( 'resources/' ) +$include_paths = @( 'resources/', 'vrtnu/' ) $exclude_files = @( '*.new', '*.orig', '*.pyc' ) # Get addon metadata diff --git a/Makefile b/Makefile index b9fa99da..a7240f1f 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ version = $(shell xmllint --xpath 'string(/addon/@version)' $(addon_xml)) git_hash = $(shell git rev-parse --short HEAD) zip_name = $(name)-$(version)-$(git_hash).zip -include_files = addon.py addon.xml LICENSE README.md resources/ service.py +include_files = addon.py addon.xml LICENSE README.md resources/ service.py vrtnu/ include_paths = $(patsubst %,$(name)/%,$(include_files)) exclude_files = \*.new \*.orig \*.pyc zip_dir = $(name)/ @@ -32,12 +32,12 @@ tox: pylint: @echo -e "$(white)=$(blue) Starting sanity pylint test$(reset)" - pylint *.py resources/lib/*/*.py + pylint *.py vrtnu/*.py @echo -e "$(white)=$(blue) Sanity pylint test finished successfully.$(reset)" unit: @echo -e "$(white)=$(blue) Starting unit tests$(reset)" - PYTHONPATH=$(pwd) python test/vrtplayertests.py + PYTHONPATH=$(shell pwd) python test/vrtplayertests.py @echo -e "$(white)=$(blue) Unit tests finished successfully.$(reset)" zip: test diff --git a/addon.py b/addon.py index e5195380..63596680 100644 --- a/addon.py +++ b/addon.py @@ -7,56 +7,255 @@ from __future__ import absolute_import, division, unicode_literals import sys -import xbmcaddon -from resources.lib.kodiwrappers import kodiwrapper -from resources.lib.vrtplayer import actions +from vrtnu.kodiwrapper import KodiWrapper +from vrtnu.helperobjects import TitleItem +import routing +from xbmcaddon import Addon try: - from urllib.parse import parse_qsl + from urllib.request import build_opener, install_opener, ProxyHandler, urlopen except ImportError: - from urlparse import parse_qsl + from urllib2 import build_opener, install_opener, ProxyHandler, urlopen + +plugin = routing.Plugin() _ADDON_URL = sys.argv[0] -_ADDON_HANDLE = int(sys.argv[1]) - - -def router(params_string): - ''' This is the main router for the video plugin menu ''' - addon = xbmcaddon.Addon() - params = dict(parse_qsl(params_string)) - action = params.get('action') - - kodi_wrapper = kodiwrapper.KodiWrapper(_ADDON_HANDLE, _ADDON_URL, addon) - - if action == actions.LISTING_TVGUIDE: - from resources.lib.vrtplayer import tvguide - tv_guide = tvguide.TVGuide(kodi_wrapper) - tv_guide.show_tvguide(params) - return - - from resources.lib.vrtplayer import vrtapihelper, vrtplayer - api_helper = vrtapihelper.VRTApiHelper(kodi_wrapper) - vrt_player = vrtplayer.VRTPlayer(kodi_wrapper, api_helper) - - if action == actions.LISTING_AZ_TVSHOWS: - vrt_player.show_tvshow_menu_items() - elif action == actions.LISTING_CATEGORIES: - vrt_player.show_category_menu_items() - elif action == actions.LISTING_CHANNELS: - vrt_player.show_channels_menu_items(channel=params.get('channel')) - elif action == actions.LISTING_LIVE: - vrt_player.show_livestream_items() - elif action == actions.LISTING_EPISODES: - vrt_player.show_episodes(path=params.get('video_url')) - elif action == actions.LISTING_RECENT: - vrt_player.show_recent(page=params.get('page', 1)) - elif action == actions.LISTING_CATEGORY_TVSHOWS: - vrt_player.show_tvshow_menu_items(category=params.get('category')) - elif action == actions.PLAY: - vrt_player.play(params) +addon = Addon() +kodi_wrapper = KodiWrapper(_ADDON_URL, addon, plugin) + + +# if action == actions.LISTING_AZ_TVSHOWS: +# vrt_player.show_tvshow_menu_items() +# elif action == actions.LISTING_CATEGORIES: +# vrt_player.show_category_menu_items() +# elif action == actions.LISTING_CHANNELS: +# vrt_player.show_channels_menu_items(channel=params.get('channel')) +# elif action == actions.LISTING_LIVE: +# vrt_player.show_livestream_items() +# elif action == actions.LISTING_EPISODES: +# vrt_player.show_episodes(path=params.get('video_url')) +# elif action == actions.LISTING_RECENT: +# vrt_player.show_recent(page=params.get('page', 1)) +# elif action == actions.LISTING_CATEGORY_TVSHOWS: +# vrt_player.show_tvshow_menu_items(category=params.get('category')) +# elif action == actions.PLAY: +# vrt_player.play(params) +# else: +# vrt_player.show_main_menu_items() + + +@plugin.route('/') +def main(): + main_items = [ + # TitleItem(title=kodi_wrapper.get_localized_string(30080), + # url=plugin.url_for(programs), + # is_playable=False, + # art_dict=dict(thumb='DefaultMovieTitle.png', icon='DefaultMovieTitle.png', fanart='DefaultMovieTitle.png'), + # video_dict=dict(plot=kodi_wrapper.get_localized_string(30081))), + # TitleItem(title=kodi_wrapper.get_localized_string(30082), + # url=plugin.url_for(categories), + # is_playable=False, + # art_dict=dict(thumb='DefaultGenre.png', icon='DefaultGenre.png', fanart='DefaultGenre.png'), + # video_dict=dict(plot=kodi_wrapper.get_localized_string(30083))), + TitleItem(title=kodi_wrapper.get_localized_string(30084), + url=plugin.url_for(channels, channel=None), + is_playable=False, + art_dict=dict(thumb='DefaultTags.png', icon='DefaultTags.png', fanart='DefaultTags.png'), + video_dict=dict(plot=kodi_wrapper.get_localized_string(30085))), + TitleItem(title=kodi_wrapper.get_localized_string(30086), + url=plugin.url_for(livetv, channel=None), + is_playable=False, + art_dict=dict(thumb='DefaultAddonPVRClient.png', icon='DefaultAddonPVRClient.png', fanart='DefaultAddonPVRClient.png'), + video_dict=dict(plot=kodi_wrapper.get_localized_string(30087))), + TitleItem(title=kodi_wrapper.get_localized_string(30088), + url=plugin.url_for(recent, page=None), + is_playable=False, + art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), + video_dict=dict(plot=kodi_wrapper.get_localized_string(30089))), + TitleItem(title=kodi_wrapper.get_localized_string(30090), + url=plugin.url_for(tvguide, date=None, channel=None), + is_playable=False, + art_dict=dict(thumb='DefaultAddonTvInfo.png', icon='DefaultAddonTvInfo.png', fanart='DefaultAddonTvInfo.png'), + video_dict=dict(plot=kodi_wrapper.get_localized_string(30091))), + ] + kodi_wrapper.show_listing(main_items) + + +# @plugin.route('/categories/') +# def categories(category=None): +# from vrtnu.vrtplayer import VRTPlayer +# if category: +# VRTPlayer(kodi_wrapper).show_tvshow_menu_items(category=category) +# else: +# VRTPlayer(kodi_wrapper).show_category_menu_items() + + +@plugin.route('/channels/') +def channels(channel=None): + from vrtnu.vrtplayer import VRTPlayer + VRTPlayer(kodi_wrapper).show_channels_menu_items(channel=channel) + + +@plugin.route('/livetv/') +def livetv(channel=None): + from vrtnu.vrtplayer import VRTPlayer + if channel: + pass # play() + else: + VRTPlayer(kodi_wrapper).show_livestream_items() + + +# /play/id/ +# /play/video/ +@plugin.route('/play/url/') +@plugin.route('/play/id/') +@plugin.route('/play/pub/') +@plugin.route('/play/url//id//pub/') +def play(video_url=None, video_id=None, publication_id=None): + import streamservice + import tokenresolver + token_resolver = tokenresolver.TokenResolver(kodi_wrapper) + stream_service = streamservice.StreamService(kodi_wrapper, token_resolver) + stream = stream_service.get_stream(video_url, video_id, publication_id) + if stream is not None: + kodi_wrapper.play(stream) + + +# @plugin.route('/programs//') +# def programs(program=None, season=None): +# from vrtnu.vrtplayer import VRTPlayer +# if program and season: +# pass +# elif program: +# pass +# else: +# VRTPlayer(kodi_wrapper).show_tvshow_menu_items() + + +@plugin.route('/recent/') +def recent(page=None): + from vrtnu.vrtplayer import VRTPlayer + VRTPlayer(kodi_wrapper).show_recent(page=page) + +# /tvguide/yesterday +# /tvguide/today +# /tvguide/tomorrow +@plugin.route('/tvguide//') +def tvguide(date=None, channel=None): + from datetime import datetime, timedelta + import dateutil.parser + import dateutil.tz + import json + + from vrtnu import metadatacreator, statichelper + from vrtnu.data import CHANNELS, DATE_STRINGS + + VRT_TVGUIDE = 'https://www.vrt.be/bin/epg/schedule.%Y-%m-%d.json' + + proxies = kodi_wrapper.get_proxies() + install_opener(build_opener(ProxyHandler(proxies))) + kodi_wrapper.set_locale() + + if not date: + now = datetime.now(dateutil.tz.tzlocal()) + date_items = [] + for i in range(7, -31, -1): + day = now + timedelta(days=i) + title = day.strftime(kodi_wrapper.get_localized_datelong()) + if str(i) in DATE_STRINGS: + if i == 0: + title = '[COLOR yellow][B]%s[/B], %s[/COLOR]' % (kodi_wrapper.get_localized_string(DATE_STRINGS[str(i)]), title) + else: + title = '[B]%s[/B], %s' % (kodi_wrapper.get_localized_string(DATE_STRINGS[str(i)]), title) + date_items.append(TitleItem( + title=title, + url=plugin.url_for(tvguide, date=day.strftime('%Y-%m-%d')), + is_playable=False, + art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), + video_dict=dict(plot=day.strftime(kodi_wrapper.get_localized_datelong())) + )) + kodi_wrapper.show_listing(date_items, content_type='files') + + elif not channel: + dateobj = dateutil.parser.parse(date) + datelong = dateobj.strftime(kodi_wrapper.get_localized_datelong()) + + fanart_path = 'resource://resource.images.studios.white/%(studio)s.png' + icon_path = 'resource://resource.images.studios.white/%(studio)s.png' + # NOTE: Wait for resource.images.studios.coloured v0.16 to be released + # icon_path = 'resource://resource.images.studios.coloured/%(studio)s.png' + + channel_items = [] + for chan in CHANNELS: + if chan.get('name') not in ('een', 'canvas', 'ketnet'): + continue + + icon = icon_path % chan + fanart = fanart_path % chan + plot = kodi_wrapper.get_localized_string(30301) % chan.get('label') + '\n' + datelong + channel_items.append(TitleItem( + title=chan.get('label'), + url=plugin.url_for(tvguide, date=date, channel=chan.get('name')), + is_playable=False, + art_dict=dict(thumb=icon, icon=icon, fanart=fanart), + video_dict=dict(plot=plot, studio=chan.get('studio')), + )) + kodi_wrapper.show_listing(channel_items) + else: - vrt_player.show_main_menu_items() + now = datetime.now(dateutil.tz.tzlocal()) + dateobj = dateutil.parser.parse(date) + datelong = dateobj.strftime(kodi_wrapper.get_localized_datelong()) + api_url = dateobj.strftime(VRT_TVGUIDE) + schedule = json.loads(urlopen(api_url).read()) + name = channel + try: + channel = next(c for c in CHANNELS if c.get('name') == name) + episodes = schedule[channel.get('id')] + except StopIteration: + episodes = [] + episode_items = [] + for episode in episodes: + metadata = metadatacreator.MetadataCreator() + title = episode.get('title') + start = episode.get('start') + end = episode.get('end') + start_date = dateutil.parser.parse(episode.get('startTime')) + end_date = dateutil.parser.parse(episode.get('endTime')) + url = episode.get('url') + label = '%s - %s' % (start, title) + metadata.tvshowtitle = title + metadata.datetime = dateobj + # NOTE: Do not use startTime and endTime as we don't want duration in seconds + metadata.duration = (dateutil.parser.parse(end) - dateutil.parser.parse(start)).total_seconds() + metadata.plot = '[B]%s[/B]\n%s\n%s - %s\n[I]%s[/I]' % (title, datelong, start, end, channel.get('label')) + metadata.brands = [channel] + metadata.mediatype = 'episode' + thumb = episode.get('image', 'DefaultAddonVideo.png') + metadata.icon = thumb + if url: + video_url = statichelper.add_https_method(url) + url = plugin.url_for(play, video_url=video_url) + if start_date < now <= end_date: # Now playing + metadata.title = '[COLOR yellow]%s[/COLOR] %s' % (label, kodi_wrapper.get_localized_string(30302)) + else: + metadata.title = label + else: + # FIXME: Find a better solution for non-actionable items + url = plugin.url_for(tvguide, date=date, channel=channel) + if start_date < now <= end_date: # Now playing + metadata.title = '[COLOR brown]%s[/COLOR] %s' % (label, kodi_wrapper.get_localized_string(30302)) + else: + metadata.title = '[COLOR gray]%s[/COLOR]' % label + episode_items.append(TitleItem( + title=metadata.title, + url=url, + is_playable=bool(url), + art_dict=dict(thumb=thumb, icon='DefaultAddonVideo.png', fanart=thumb), + video_dict=metadata.get_video_dict(), + )) + kodi_wrapper.show_listing(episode_items, content_type='episodes', cache=False) if __name__ == '__main__': - router(sys.argv[2][1:]) + plugin.run() diff --git a/addon.xml b/addon.xml index 9022ebdb..00e0b2de 100644 --- a/addon.xml +++ b/addon.xml @@ -11,10 +11,11 @@ - + + video diff --git a/resources/lib/__init__.py b/resources/lib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/resources/lib/helperobjects/__init__.py b/resources/lib/helperobjects/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/resources/lib/helperobjects/apidata.py b/resources/lib/helperobjects/apidata.py deleted file mode 100644 index 032c0a5d..00000000 --- a/resources/lib/helperobjects/apidata.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, unicode_literals - - -class ApiData: - - def __init__(self, client, media_api_url, video_id, publication_id, xvrttoken, is_live_stream): - self._client = client - self._media_api_url = media_api_url - self._video_id = video_id - self._publication_id = publication_id - self._xvrttoken = xvrttoken - self._is_live_stream = is_live_stream - - @property - def client(self): - return self._client - - @property - def media_api_url(self): - return self._media_api_url - - @property - def video_id(self): - return self._video_id - - @property - def publication_id(self): - return self._publication_id - - @property - def xvrttoken(self): - return self._xvrttoken - - @xvrttoken.setter - def xvrttoken(self, value): - self._xvrttoken = value - - @property - def is_live_stream(self): - return self._is_live_stream - - @is_live_stream.setter - def is_live_stream(self, value): - self._is_live_stream = value diff --git a/resources/lib/helperobjects/helperobjects.py b/resources/lib/helperobjects/helperobjects.py deleted file mode 100644 index ec4f1369..00000000 --- a/resources/lib/helperobjects/helperobjects.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, unicode_literals - - -class TitleItem: - - def __init__(self, title, url_dict, is_playable, art_dict=None, video_dict=None): - self.title = title - self.url_dict = url_dict - self.is_playable = is_playable - self.art_dict = art_dict - self.video_dict = video_dict - - -class Credentials: - - def __init__(self, kodi_wrapper): - self._kodi_wrapper = kodi_wrapper - self._username = self._kodi_wrapper.get_setting('username') - self._password = self._kodi_wrapper.get_setting('password') - - def are_filled_in(self): - return not (self._username is None or self._password is None or self._username == '' or self._password == '') - - def reload(self): - self._username = self._kodi_wrapper.get_setting('username') - self._password = self._kodi_wrapper.get_setting('password') - - def reset(self): - self._username = self._kodi_wrapper.set_setting('username', None) - self._password = self._kodi_wrapper.set_setting('password', None) - - @property - def username(self): - return self._username - - @property - def password(self): - return self._password diff --git a/resources/lib/helperobjects/streamurls.py b/resources/lib/helperobjects/streamurls.py deleted file mode 100644 index 9448211a..00000000 --- a/resources/lib/helperobjects/streamurls.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, unicode_literals - - -class StreamURLS: - - def __init__(self, stream_url, subtitle_url=None, license_key=None, use_inputstream_adaptive=False): - self._stream_url = stream_url - self._subtitle_url = subtitle_url - self._license_key = license_key - self._use_inputstream_adaptive = use_inputstream_adaptive - self._video_id = None - - @property - def stream_url(self): - return self._stream_url - - @property - def subtitle_url(self): - return self._subtitle_url - - @property - def video_id(self): - return self._video_id - - @property - def license_key(self): - return self._license_key - - @property - def use_inputstream_adaptive(self): - return self._use_inputstream_adaptive diff --git a/resources/lib/kodiwrappers/__init__.py b/resources/lib/kodiwrappers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/resources/lib/vrtplayer/actions.py b/resources/lib/vrtplayer/actions.py deleted file mode 100644 index 132228d8..00000000 --- a/resources/lib/vrtplayer/actions.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, unicode_literals - - -LISTING_AZ_TVSHOWS = 'listingaztvshows' -LISTING_CATEGORIES = 'listingcategories' -LISTING_CATEGORY_TVSHOWS = 'listingcategorytvshows' -LISTING_CHANNELS = 'listingchannels' -LISTING_EPISODES = 'listingepisodes' -LISTING_LIVE = 'listinglive' -LISTING_RECENT = 'listingrecent' -LISTING_TVGUIDE = 'listingtvguide' - -PLAY = 'play' diff --git a/resources/lib/vrtplayer/tvguide.py b/resources/lib/vrtplayer/tvguide.py deleted file mode 100644 index 8db1c3cc..00000000 --- a/resources/lib/vrtplayer/tvguide.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, unicode_literals -from datetime import datetime, timedelta -import dateutil.parser -import dateutil.tz -import json - -try: - from urllib.request import build_opener, install_opener, ProxyHandler, urlopen -except ImportError: - from urllib2 import build_opener, install_opener, ProxyHandler, urlopen - -from resources.lib.helperobjects import helperobjects -from resources.lib.vrtplayer import CHANNELS, actions, metadatacreator, statichelper - -DATE_STRINGS = { - '-2': 30330, # 2 days ago - '-1': 30331, # Yesterday - '0': 30332, # Today - '1': 30333, # Tomorrow - '2': 30334, # In 2 days -} - - -class TVGuide: - - VRT_TVGUIDE = 'https://www.vrt.be/bin/epg/schedule.%Y-%m-%d.json' - - def __init__(self, kodi_wrapper): - self._kodi_wrapper = kodi_wrapper - self._proxies = self._kodi_wrapper.get_proxies() - install_opener(build_opener(ProxyHandler(self._proxies))) - kodi_wrapper.set_locale() - - def show_tvguide(self, params): - date = params.get('date') - channel = params.get('channel') - - if not date: - now = datetime.now(dateutil.tz.tzlocal()) - date_items = [] - for i in range(7, -31, -1): - day = now + timedelta(days=i) - title = day.strftime(self._kodi_wrapper.get_localized_datelong()) - if str(i) in DATE_STRINGS: - if i == 0: - title = '[COLOR yellow][B]%s[/B], %s[/COLOR]' % (self._kodi_wrapper.get_localized_string(DATE_STRINGS[str(i)]), title) - else: - title = '[B]%s[/B], %s' % (self._kodi_wrapper.get_localized_string(DATE_STRINGS[str(i)]), title) - date_items.append( - helperobjects.TitleItem(title=title, - url_dict=dict(action=actions.LISTING_TVGUIDE, date=day.strftime('%Y-%m-%d')), - is_playable=False, - art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), - video_dict=dict(plot=day.strftime(self._kodi_wrapper.get_localized_datelong()))), - ) - self._kodi_wrapper.show_listing(date_items, content_type='files') - - elif not channel: - dateobj = dateutil.parser.parse(date) - datelong = dateobj.strftime(self._kodi_wrapper.get_localized_datelong()) - - fanart_path = 'resource://resource.images.studios.white/%(studio)s.png' - icon_path = 'resource://resource.images.studios.white/%(studio)s.png' - # NOTE: Wait for resource.images.studios.coloured v0.16 to be released - # icon_path = 'resource://resource.images.studios.coloured/%(studio)s.png' - - channel_items = [] - for channel in CHANNELS: - if channel.get('name') not in ('een', 'canvas', 'ketnet'): - continue - - icon = icon_path % channel - fanart = fanart_path % channel - plot = self._kodi_wrapper.get_localized_string(30301) % channel.get('label') + '\n' + datelong - channel_items.append( - helperobjects.TitleItem( - title=channel.get('label'), - url_dict=dict(action=actions.LISTING_TVGUIDE, date=date, channel=channel.get('name')), - is_playable=False, - art_dict=dict(thumb=icon, icon=icon, fanart=fanart), - video_dict=dict(plot=plot, studio=channel.get('studio')), - ), - ) - self._kodi_wrapper.show_listing(channel_items) - - else: - now = datetime.now(dateutil.tz.tzlocal()) - dateobj = dateutil.parser.parse(date) - datelong = dateobj.strftime(self._kodi_wrapper.get_localized_datelong()) - api_url = dateobj.strftime(self.VRT_TVGUIDE) - schedule = json.loads(urlopen(api_url).read()) - name = channel - try: - channel = next(c for c in CHANNELS if c.get('name') == name) - episodes = schedule[channel.get('id')] - except StopIteration: - episodes = [] - episode_items = [] - for episode in episodes: - metadata = metadatacreator.MetadataCreator() - title = episode.get('title') - start = episode.get('start') - end = episode.get('end') - start_date = dateutil.parser.parse(episode.get('startTime')) - end_date = dateutil.parser.parse(episode.get('endTime')) - url = episode.get('url') - label = '%s - %s' % (start, title) - metadata.tvshowtitle = title - metadata.datetime = dateobj - # NOTE: Do not use startTime and endTime as we don't want duration in seconds - metadata.duration = (dateutil.parser.parse(end) - dateutil.parser.parse(start)).total_seconds() - metadata.plot = '[B]%s[/B]\n%s\n%s - %s\n[I]%s[/I]' % (title, datelong, start, end, channel.get('label')) - metadata.brands = [channel] - metadata.mediatype = 'episode' - thumb = episode.get('image', 'DefaultAddonVideo.png') - metadata.icon = thumb - if url: - video_url = statichelper.add_https_method(url) - url_dict = dict(action=actions.PLAY, video_url=video_url) - if start_date < now <= end_date: # Now playing - metadata.title = '[COLOR yellow]%s[/COLOR] %s' % (label, self._kodi_wrapper.get_localized_string(30302)) - else: - metadata.title = label - else: - # FIXME: Find a better solution for non-actionable items - url_dict = dict(action=actions.LISTING_TVGUIDE, date=date, channel=channel) - if start_date < now <= end_date: # Now playing - metadata.title = '[COLOR brown]%s[/COLOR] %s' % (label, self._kodi_wrapper.get_localized_string(30302)) - else: - metadata.title = '[COLOR gray]%s[/COLOR]' % label - episode_items.append(helperobjects.TitleItem( - title=metadata.title, - url_dict=url_dict, - is_playable=bool(url), - art_dict=dict(thumb=thumb, icon='DefaultAddonVideo.png', fanart=thumb), - video_dict=metadata.get_video_dict(), - )) - self._kodi_wrapper.show_listing(episode_items, content_type='episodes', cache=False) diff --git a/service.py b/service.py index 5663c74c..2b72dfc5 100644 --- a/service.py +++ b/service.py @@ -6,26 +6,25 @@ from __future__ import absolute_import, division, unicode_literals -import xbmc -import xbmcaddon -from resources.lib.kodiwrappers import kodiwrapper -from resources.lib.vrtplayer import tokenresolver +from vrtnu.kodiwrapper import KodiWrapper +from vrtnu.tokenresolver import TokenResolver +from xbmc import Monitor +from xbmcaddon import Addon -class VrtMonitor(xbmc.Monitor): +class VrtMonitor(Monitor): ''' This is the class that monitors Kodi for the VRT NU video plugin ''' def __init__(self): ''' VRT Monitor initialisiation ''' - xbmc.Monitor.__init__(self) + Monitor.__init__(self) def onSettingsChanged(self): ''' Handler for changes to settings ''' - addon = xbmcaddon.Addon(id='plugin.video.vrt.nu') - kodi_wrapper = kodiwrapper.KodiWrapper(None, None, addon) + addon = Addon(id='plugin.video.vrt.nu') + kodi_wrapper = KodiWrapper(None, addon) kodi_wrapper.log_notice('VRT NU Addon: settings changed') - token_resolver = tokenresolver.TokenResolver(kodi_wrapper) - token_resolver.reset_cookies() + TokenResolver(kodi_wrapper).reset_cookies() if __name__ == '__main__': diff --git a/test/vrtplayertests.py b/test/vrtplayertests.py index d4a8247c..dd7f2bd7 100644 --- a/test/vrtplayertests.py +++ b/test/vrtplayertests.py @@ -7,7 +7,8 @@ import random import unittest -from resources.lib.vrtplayer import CATEGORIES, vrtapihelper, vrtplayer +from vrtnu.data import CATEGORIES +from vrtnu import vrtapihelper, vrtplayer class TestVRTPlayer(unittest.TestCase): @@ -24,7 +25,7 @@ def test_show_videos_single_episode_shows_videos(self): self.assertEqual(sort, 'dateadded') self.assertFalse(ascending) - player = vrtplayer.VRTPlayer(self._kodi_wrapper, self._api_helper) + player = vrtplayer.VRTPlayer(self._kodi_wrapper) player.show_episodes(path) self.assertTrue(self._kodi_wrapper.show_listing.called) @@ -35,7 +36,7 @@ def test_show_videos_single_season_shows_videos(self): self.assertEqual(sort, 'dateadded') self.assertFalse(ascending) - player = vrtplayer.VRTPlayer(self._kodi_wrapper, self._api_helper) + player = vrtplayer.VRTPlayer(self._kodi_wrapper) player.show_episodes(path) self.assertTrue(self._kodi_wrapper.show_listing.called) @@ -46,7 +47,7 @@ def test_show_videos_multiple_seasons_shows_videos(self): self.assertEqual(sort, 'label') self.assertFalse(ascending) - player = vrtplayer.VRTPlayer(self._kodi_wrapper, self._api_helper) + player = vrtplayer.VRTPlayer(self._kodi_wrapper) player.show_episodes(path) self.assertTrue(self._kodi_wrapper.show_listing.called) @@ -57,7 +58,7 @@ def test_show_videos_specific_seasons_shows_videos(self): self.assertEqual(sort, 'label') self.assertFalse(ascending) - player = vrtplayer.VRTPlayer(self._kodi_wrapper, self._api_helper) + player = vrtplayer.VRTPlayer(self._kodi_wrapper) player.show_episodes(path) self.assertTrue(self._kodi_wrapper.show_listing.called) diff --git a/resources/__init__.py b/vrtnu/__init__.py similarity index 100% rename from resources/__init__.py rename to vrtnu/__init__.py diff --git a/resources/lib/vrtplayer/__init__.py b/vrtnu/data.py similarity index 94% rename from resources/lib/vrtplayer/__init__.py rename to vrtnu/data.py index 4518e9c0..4c7c7f5d 100644 --- a/resources/lib/vrtplayer/__init__.py +++ b/vrtnu/data.py @@ -112,3 +112,11 @@ # live_stream_id='vualto_journaal', ), ] + +DATE_STRINGS = { + '-2': 30330, # 2 days ago + '-1': 30331, # Yesterday + '0': 30332, # Today + '1': 30333, # Tomorrow + '2': 30334, # In 2 days +} diff --git a/vrtnu/helperobjects.py b/vrtnu/helperobjects.py new file mode 100644 index 00000000..9a299f39 --- /dev/null +++ b/vrtnu/helperobjects.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, unicode_literals + + +class actions: + LISTING_AZ_TVSHOWS = 'listingaztvshows' + LISTING_CATEGORIES = 'listingcategories' + LISTING_CATEGORY_TVSHOWS = 'listingcategorytvshows' + LISTING_CHANNELS = 'listingchannels' + LISTING_EPISODES = 'listingepisodes' + LISTING_LIVE = 'listinglive' + LISTING_RECENT = 'listingrecent' + LISTING_TVGUIDE = 'listingtvguide' + PLAY = 'play' + + +class TitleItem: + + def __init__(self, title, url, is_playable, art_dict=None, video_dict=None): + self.title = title + self.url = url + self.is_playable = is_playable + self.art_dict = art_dict + self.video_dict = video_dict + + +class Credentials: + + def __init__(self, kodi_wrapper): + self._kodi_wrapper = kodi_wrapper + self._username = self._kodi_wrapper.get_setting('username') + self._password = self._kodi_wrapper.get_setting('password') + + def are_filled_in(self): + return not (self._username is None or self._password is None or self._username == '' or self._password == '') + + def reload(self): + self._username = self._kodi_wrapper.get_setting('username') + self._password = self._kodi_wrapper.get_setting('password') + + def reset(self): + self._username = self._kodi_wrapper.set_setting('username', None) + self._password = self._kodi_wrapper.set_setting('password', None) + + @property + def username(self): + return self._username + + @property + def password(self): + return self._password + + +class ApiData: + + def __init__(self, client, media_api_url, video_id, publication_id, xvrttoken, is_live_stream): + self._client = client + self._media_api_url = media_api_url + self._video_id = video_id + self._publication_id = publication_id + self._xvrttoken = xvrttoken + self._is_live_stream = is_live_stream + + @property + def client(self): + return self._client + + @property + def media_api_url(self): + return self._media_api_url + + @property + def video_id(self): + return self._video_id + + @property + def publication_id(self): + return self._publication_id + + @property + def xvrttoken(self): + return self._xvrttoken + + @xvrttoken.setter + def xvrttoken(self, value): + self._xvrttoken = value + + @property + def is_live_stream(self): + return self._is_live_stream + + @is_live_stream.setter + def is_live_stream(self, value): + self._is_live_stream = value + + +class StreamURLS: + + def __init__(self, stream_url, subtitle_url=None, license_key=None, use_inputstream_adaptive=False): + self._stream_url = stream_url + self._subtitle_url = subtitle_url + self._license_key = license_key + self._use_inputstream_adaptive = use_inputstream_adaptive + self._video_id = None + + @property + def stream_url(self): + return self._stream_url + + @property + def subtitle_url(self): + return self._subtitle_url + + @property + def video_id(self): + return self._video_id + + @property + def license_key(self): + return self._license_key + + @property + def use_inputstream_adaptive(self): + return self._use_inputstream_adaptive diff --git a/resources/lib/kodiwrappers/kodiwrapper.py b/vrtnu/kodiwrapper.py similarity index 96% rename from resources/lib/kodiwrappers/kodiwrapper.py rename to vrtnu/kodiwrapper.py index 1b2e11e9..429bb194 100644 --- a/resources/lib/kodiwrappers/kodiwrapper.py +++ b/vrtnu/kodiwrapper.py @@ -6,10 +6,6 @@ import xbmc import xbmcplugin -try: - from urllib.parse import urlencode -except ImportError: - from urllib import urlencode sort_methods = { # 'date': xbmcplugin.SORT_METHOD_DATE, @@ -39,11 +35,15 @@ def has_socks(): class KodiWrapper: - def __init__(self, handle, url, addon): - self._handle = handle + def __init__(self, url, addon, plugin=None): self._url = url self._addon = addon self._addon_id = addon.getAddonInfo('id') + self._plugin = plugin + if plugin: + self._handle = plugin.handle + else: + self._handle = None def show_listing(self, list_items, sort='unsorted', ascending=True, content_type=None, cache=True): import xbmcgui @@ -72,7 +72,6 @@ def show_listing(self, list_items, sort='unsorted', ascending=True, content_type for title_item in list_items: list_item = xbmcgui.ListItem(label=title_item.title, thumbnailImage=title_item.art_dict.get('thumb')) - url = self._url + '?' + urlencode(title_item.url_dict) list_item.setProperty(key='IsPlayable', value='true' if title_item.is_playable else 'false') # FIXME: This does not appear to be working, we have to order it ourselves @@ -89,7 +88,7 @@ def show_listing(self, list_items, sort='unsorted', ascending=True, content_type if title_item.video_dict: list_item.setInfo(type='video', infoLabels=title_item.video_dict) - listing.append((url, list_item, not title_item.is_playable)) + listing.append((title_item.url, list_item, not title_item.is_playable)) ok = xbmcplugin.addDirectoryItems(self._handle, listing, len(listing)) xbmcplugin.endOfDirectory(self._handle, ok, cacheToDisc=cache) diff --git a/resources/lib/vrtplayer/metadatacreator.py b/vrtnu/metadatacreator.py similarity index 99% rename from resources/lib/vrtplayer/metadatacreator.py rename to vrtnu/metadatacreator.py index afb7d7e4..9b113627 100644 --- a/resources/lib/vrtplayer/metadatacreator.py +++ b/vrtnu/metadatacreator.py @@ -156,7 +156,7 @@ def year(self, value): def get_video_dict(self): from datetime import datetime import dateutil.tz - from resources.lib.vrtplayer import CHANNELS + from vrtnu.data import CHANNELS epoch = datetime.fromtimestamp(0, dateutil.tz.UTC) video_dict = dict() diff --git a/resources/lib/vrtplayer/statichelper.py b/vrtnu/statichelper.py similarity index 100% rename from resources/lib/vrtplayer/statichelper.py rename to vrtnu/statichelper.py diff --git a/resources/lib/vrtplayer/streamservice.py b/vrtnu/streamservice.py similarity index 89% rename from resources/lib/vrtplayer/streamservice.py rename to vrtnu/streamservice.py index 59b1a53e..97e724c9 100644 --- a/resources/lib/vrtplayer/streamservice.py +++ b/vrtnu/streamservice.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, unicode_literals import json -from resources.lib.helperobjects import apidata, streamurls +from vrtnu.helperobjects import ApiData, StreamURLS try: from urllib.parse import urlencode, quote @@ -78,21 +78,18 @@ def _get_license_key(self, key_url, key_type='R', key_headers=None, key_value=No return '%s|%s|%s|' % (key_url, header, key_value) - def _get_api_data(self, video): + def _get_api_data(self, video_url, video_id, publication_id): '''Get and prepare api data object''' - video_url = video.get('video_url') - video_id = video.get('video_id') - publication_id = video.get('publication_id') # Prepare api_data for on demand streams by video_id and publication_id if video_id and publication_id: xvrttoken = self.token_resolver.get_xvrttoken() - api_data = apidata.ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, publication_id + quote('$'), xvrttoken, False) + api_data = ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, publication_id + quote('$'), xvrttoken, False) # Prepare api_data for livestreams by video_id, e.g. vualto_strubru, vualto_mnm elif video_id and not video_url: - api_data = apidata.ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, '', None, True) + api_data = ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, '', None, True) # Webscrape api_data with video_id fallback elif video_url: - api_data = self._webscrape_api_data(video_url) or apidata.ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, '', None, True) + api_data = self._webscrape_api_data(video_url) or ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, '', None, True) return api_data def _webscrape_api_data(self, video_url): @@ -133,7 +130,7 @@ def _webscrape_api_data(self, video_url): self._kodi_wrapper.log_error('Web scraping api data failed, required attributes missing') return None - return apidata.ApiData(client, media_api_url, video_id, publication_id, xvrttoken, is_live_stream) + return ApiData(client, media_api_url, video_id, publication_id, xvrttoken, is_live_stream) def _get_video_json(self, api_data): token_url = api_data.media_api_url + '/tokens' @@ -183,11 +180,11 @@ def _fix_virtualsubclip(stream_dict, duration): stream_dict[key] = '-'.join((value, end_time.strftime('%Y-%m-%dT%H:%M:%S'))) return stream_dict - def get_stream(self, video, retry=False, api_data=None): + def get_stream(self, video_url, video_id, publication_id, retry=False, api_data=None): '''Main streamservice function''' from datetime import timedelta if not api_data: - api_data = self._get_api_data(video) + api_data = self._get_api_data(video_url, video_id, publication_id) vudrm_token = None video_json = self._get_video_json(api_data) @@ -210,7 +207,7 @@ def get_stream(self, video, retry=False, api_data=None): self._kodi_wrapper.delete_path(self._kodi_wrapper.get_userdata_path() + 'ondemand_vrtPlayerToken') # Update api_data with roaming_xvrttoken and try again api_data.xvrttoken = roaming_xvrttoken - return self.get_stream(video, retry=True, api_data=api_data) + return self.get_stream(video_url, video_id, publication_id, retry=True, api_data=api_data) message = self._kodi_wrapper.get_localized_string(30053) self._kodi_wrapper.show_ok_dialog('', message) else: @@ -227,7 +224,7 @@ def _try_get_drm_stream(self, stream_dict, vudrm_token): key_type='D', key_value=encryption_json, key_headers={'Content-Type': 'text/plain;charset=UTF-8'}) - return streamurls.StreamURLS(stream_dict[protocol], license_key=license_key, use_inputstream_adaptive=True) if protocol in stream_dict else None + return StreamURLS(stream_dict[protocol], license_key=license_key, use_inputstream_adaptive=True) if protocol in stream_dict else None def _select_stream(self, stream_dict, vudrm_token): stream_url = None @@ -240,18 +237,18 @@ def _select_stream(self, stream_dict, vudrm_token): if vudrm_token and stream_url is None: protocol = 'hls_aes' self._kodi_wrapper.log_notice('protocol: ' + protocol) - stream_url = streamurls.StreamURLS(*self._select_hls_substreams(stream_dict[protocol])) if protocol in stream_dict else None + stream_url = StreamURLS(*self._select_hls_substreams(stream_dict[protocol])) if protocol in stream_dict else None if self._kodi_wrapper.has_inputstream_adaptive_installed() and stream_url is None: protocol = 'mpeg_dash' self._kodi_wrapper.log_notice('protocol: ' + protocol) - stream_url = streamurls.StreamURLS(stream_dict[protocol], use_inputstream_adaptive=True) if protocol in stream_dict else None + stream_url = StreamURLS(stream_dict[protocol], use_inputstream_adaptive=True) if protocol in stream_dict else None if stream_url is None: protocol = 'hls' self._kodi_wrapper.log_notice('protocol: ' + protocol) # No if-else statement because this is the last resort stream selection - stream_url = streamurls.StreamURLS(*self._select_hls_substreams(stream_dict[protocol])) + stream_url = StreamURLS(*self._select_hls_substreams(stream_dict[protocol])) return stream_url diff --git a/resources/lib/vrtplayer/tokenresolver.py b/vrtnu/tokenresolver.py similarity index 98% rename from resources/lib/vrtplayer/tokenresolver.py rename to vrtnu/tokenresolver.py index 8d8bba5f..012d66c3 100644 --- a/resources/lib/vrtplayer/tokenresolver.py +++ b/vrtnu/tokenresolver.py @@ -3,7 +3,7 @@ # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, unicode_literals -from resources.lib.helperobjects import helperobjects +from vrtnu.helperobjects import Credentials try: from urllib.parse import urlencode @@ -101,7 +101,7 @@ def _get_cached_token(self, path, token_name): def _get_new_xvrttoken(self, path, get_roaming_token): import json - cred = helperobjects.Credentials(self._kodi_wrapper) + cred = Credentials(self._kodi_wrapper) if not cred.are_filled_in(): self._kodi_wrapper.open_settings() cred.reload() diff --git a/resources/lib/vrtplayer/vrtapihelper.py b/vrtnu/vrtapihelper.py similarity index 95% rename from resources/lib/vrtplayer/vrtapihelper.py rename to vrtnu/vrtapihelper.py index 9033001f..44a8e22b 100644 --- a/resources/lib/vrtplayer/vrtapihelper.py +++ b/vrtnu/vrtapihelper.py @@ -3,8 +3,8 @@ # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, unicode_literals -from resources.lib.helperobjects import helperobjects -from resources.lib.vrtplayer import actions, metadatacreator, statichelper +from vrtnu.helperobjects import actions, TitleItem +from vrtnu import metadatacreator, statichelper try: from urllib.parse import urlencode, unquote @@ -58,11 +58,13 @@ def get_tvshow_items(self, category=None, channel=None): # Cut vrtbase url off since it will be added again when searching for episodes # (with a-z we dont have the full url) video_url = statichelper.add_https_method(tvshow.get('targetUrl')).replace(self._VRT_BASE, '') - tvshow_items.append(helperobjects.TitleItem(title=label, - url_dict=dict(action=actions.LISTING_EPISODES, video_url=video_url), - is_playable=False, - art_dict=dict(thumb=thumbnail, icon='DefaultAddonVideo.png', fanart=thumbnail), - video_dict=metadata.get_video_dict())) + tvshow_items.append(TitleItem( + title=label, + url_dict=dict(action=actions.LISTING_EPISODES, video_url=video_url), + is_playable=False, + art_dict=dict(thumb=thumbnail, icon='DefaultAddonVideo.png', fanart=thumbnail), + video_dict=metadata.get_video_dict(), + )) return tvshow_items def _get_season_items(self, api_url, api_json): @@ -213,7 +215,7 @@ def _map_to_episode_items(self, episodes, titletype=None, season_key=None): video_url = statichelper.add_https_method(episode.get('url')) label, sort, ascending = self._make_label(episode, titletype, options=display_options) metadata.title = label - episode_items.append(helperobjects.TitleItem( + episode_items.append(TitleItem( title=label, url_dict=dict(action=actions.PLAY, video_url=video_url, video_id=episode.get('videoId'), publication_id=episode.get('publicationId')), is_playable=True, @@ -245,7 +247,7 @@ def _map_to_season_items(self, api_url, seasons, episode): label = '%s %s' % (self._kodi_wrapper.get_localized_string(30094), season_key) params = {'facets[seasonTitle]': season_key} path = api_url + '&' + urlencode(params) - season_items.append(helperobjects.TitleItem( + season_items.append(TitleItem( title=label, url_dict=dict(action=actions.LISTING_EPISODES, video_url=path), is_playable=False, diff --git a/resources/lib/vrtplayer/vrtplayer.py b/vrtnu/vrtplayer.py similarity index 52% rename from resources/lib/vrtplayer/vrtplayer.py rename to vrtnu/vrtplayer.py index 9afcad44..3eb7153d 100644 --- a/resources/lib/vrtplayer/vrtplayer.py +++ b/vrtnu/vrtplayer.py @@ -3,8 +3,9 @@ # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, unicode_literals -from resources.lib.helperobjects import helperobjects -from resources.lib.vrtplayer import actions +from vrtnu.helperobjects import actions, TitleItem +from vrtnu.statichelper import add_https_method, strip_newlines +from vrtnu.vrtapihelper import VRTApiHelper try: from urllib.request import build_opener, install_opener, ProxyHandler, urlopen @@ -30,61 +31,25 @@ def get_categories(proxies=None): def get_category_thumbnail(element): - from resources.lib.vrtplayer import statichelper raw_thumbnail = element.find(class_='media').get('data-responsive-image', 'DefaultGenre.png') - return statichelper.add_https_method(raw_thumbnail) + return add_https_method(raw_thumbnail) def get_category_title(element): - from resources.lib.vrtplayer import statichelper found_element = element.find('h3') if found_element is not None: - return statichelper.strip_newlines(found_element.contents[0]) + return strip_newlines(found_element.contents[0]) return '' class VRTPlayer: - def __init__(self, kodi_wrapper, api_helper): + def __init__(self, kodi_wrapper): self._kodi_wrapper = kodi_wrapper self._proxies = self._kodi_wrapper.get_proxies() install_opener(build_opener(ProxyHandler(self._proxies))) - self._api_helper = api_helper - - def show_main_menu_items(self): - main_items = [ - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30080), - url_dict=dict(action=actions.LISTING_AZ_TVSHOWS), - is_playable=False, - art_dict=dict(thumb='DefaultMovieTitle.png', icon='DefaultMovieTitle.png', fanart='DefaultMovieTitle.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30081))), - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30082), - url_dict=dict(action=actions.LISTING_CATEGORIES), - is_playable=False, - art_dict=dict(thumb='DefaultGenre.png', icon='DefaultGenre.png', fanart='DefaultGenre.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30083))), - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30084), - url_dict=dict(action=actions.LISTING_CHANNELS), - is_playable=False, - art_dict=dict(thumb='DefaultTags.png', icon='DefaultTags.png', fanart='DefaultTags.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30085))), - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30086), - url_dict=dict(action=actions.LISTING_LIVE), - is_playable=False, - art_dict=dict(thumb='DefaultAddonPVRClient.png', icon='DefaultAddonPVRClient.png', fanart='DefaultAddonPVRClient.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30087))), - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30088), - url_dict=dict(action=actions.LISTING_RECENT, page='1'), - is_playable=False, - art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30089))), - helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30090), - url_dict=dict(action=actions.LISTING_TVGUIDE), - is_playable=False, - art_dict=dict(thumb='DefaultAddonTvInfo.png', icon='DefaultAddonTvInfo.png', fanart='DefaultAddonTvInfo.png'), - video_dict=dict(plot=self._kodi_wrapper.get_localized_string(30091))), - ] - self._kodi_wrapper.show_listing(main_items) + self._api_helper = VRTApiHelper(kodi_wrapper) + self._plugin = kodi_wrapper._plugin def show_tvshow_menu_items(self, category=None): tvshow_items = self._api_helper.get_tvshow_items(category=category) @@ -99,14 +64,14 @@ def show_channels_menu_items(self, channel=None): tvshow_items = self._api_helper.get_tvshow_items(channel=channel) self._kodi_wrapper.show_listing(tvshow_items, sort='label', content_type='tvshows') else: - from resources.lib.vrtplayer import CHANNELS + from vrtnu.data import CHANNELS self.show_channels(action=actions.LISTING_CHANNELS, channels=[c.get('name') for c in CHANNELS]) def show_livestream_items(self): self.show_channels(action=actions.PLAY, channels=['een', 'canvas', 'sporza', 'ketnet', 'stubru', 'mnm']) def show_channels(self, action=actions.PLAY, channels=None): - from resources.lib.vrtplayer import CHANNELS + from vrtnu.data import CHANNELS fanart_path = 'resource://resource.images.studios.white/%(studio)s.png' icon_path = 'resource://resource.images.studios.white/%(studio)s.png' @@ -141,7 +106,7 @@ def show_channels(self, action=actions.PLAY, channels=None): if channel.get('live_stream_id'): url_dict['video_id'] = channel.get('live_stream_id') - channel_items.append(helperobjects.TitleItem( + channel_items.append(TitleItem( title=label, url_dict=url_dict, is_playable=is_playable, @@ -169,22 +134,16 @@ def show_recent(self, page): episode_items, sort, ascending = self._api_helper.get_episode_items(page=page) # Add 'More...' entry at the end - episode_items.append(helperobjects.TitleItem(title=self._kodi_wrapper.get_localized_string(30300), - url_dict=dict(action=actions.LISTING_RECENT, page=page + 1), - is_playable=False, - art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), - video_dict=dict())) + episode_items.append(TitleItem( + title=self._kodi_wrapper.get_localized_string(30300), + url_dict=dict(action=actions.LISTING_RECENT, page=page + 1), + is_playable=False, + art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), + video_dict=dict(), + )) self._kodi_wrapper.show_listing(episode_items, sort=sort, ascending=ascending, content_type='episodes', cache=False) - def play(self, params): - from resources.lib.vrtplayer import streamservice, tokenresolver - token_resolver = tokenresolver.TokenResolver(self._kodi_wrapper) - stream_service = streamservice.StreamService(self._kodi_wrapper, token_resolver) - stream = stream_service.get_stream(params) - if stream is not None: - self._kodi_wrapper.play(stream) - def __get_category_menu_items(self): try: categories = get_categories(self._proxies) @@ -193,15 +152,17 @@ def __get_category_menu_items(self): # Fallback to internal categories if web-scraping fails if not categories: - from resources.lib.vrtplayer import CATEGORIES + from channels import CATEGORIES categories = CATEGORIES category_items = [] for category in categories: thumbnail = category.get('thumbnail', 'DefaultGenre.png') - category_items.append(helperobjects.TitleItem(title=category.get('name'), - url_dict=dict(action=actions.LISTING_CATEGORY_TVSHOWS, category=category.get('id')), - is_playable=False, - art_dict=dict(thumb=thumbnail, icon='DefaultGenre.png', fanart=thumbnail), - video_dict=dict(plot='[B]%s[/B]' % category.get('name'), studio='VRT'))) + category_items.append(TitleItem( + title=category.get('name'), + url_dict=dict(action=actions.LISTING_CATEGORY_TVSHOWS, category=category.get('id')), + is_playable=False, + art_dict=dict(thumb=thumbnail, icon='DefaultGenre.png', fanart=thumbnail), + video_dict=dict(plot='[B]%s[/B]' % category.get('name'), studio='VRT'), + )) return category_items