diff --git a/.travis.yml b/.travis.yml index 8e7a80ef..e8bc2bb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,5 @@ script: - python test/apihelpertests.py - python test/tvguidetests.py - python test/searchtests.py -- python test/routertests.py +- python test/routingtests.py #- python test/favoritestests.py diff --git a/Makefile b/Makefile index 89152ac8..036bd388 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ unit: PYTHONPATH=$(CURDIR) python test/apihelpertests.py PYTHONPATH=$(CURDIR) python test/tvguidetests.py PYTHONPATH=$(CURDIR) python test/searchtests.py - PYTHONPATH=$(CURDIR) python test/routertests.py + PYTHONPATH=$(CURDIR) python test/routingtests.py PYTHONPATH=$(CURDIR) python test/favoritestests.py @echo -e "$(white)=$(blue) Unit tests finished successfully.$(reset)" diff --git a/addon.py b/addon.py index f162b430..1127aad7 100644 --- a/addon.py +++ b/addon.py @@ -4,10 +4,198 @@ ''' This is the actual VRT NU video plugin entry point ''' +# pylint: disable=missing-docstring + from __future__ import absolute_import, division, unicode_literals import sys +import routing +from resources.lib import kodiwrapper + +plugin = routing.Plugin() +_kodi = kodiwrapper.KodiWrapper(plugin) + + +@plugin.route('/') +def main_menu(): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_main_menu_items() + + +@plugin.route('/cache/delete') +@plugin.route('/cache/delete/') +def delete_cache(cache_file=None): + if cache_file: + _kodi.refresh_caches(cache_file) + return + _kodi.invalidate_caches() + + +@plugin.route('/widevine/install') +def install_widevine(): + _kodi.install_widevine() + + +@plugin.route('/tokens/delete') +def delete_tokens(): + from resources.lib import tokenresolver + _tokenresolver = tokenresolver.TokenResolver(_kodi) + _tokenresolver.delete_tokens() + + +@plugin.route('/follow//<program>') +def follow(title, program): + from resources.lib import favorites + _favorites = favorites.Favorites(_kodi) + _favorites.follow(title=title, program=program) + + +@plugin.route('/unfollow/<title>/<program>') +def unfollow(title, program): + from resources.lib import favorites + _favorites = favorites.Favorites(_kodi) + _favorites.unfollow(title=title, program=program) + + +@plugin.route('/play/id/<video_id>') +@plugin.route('/play/id/<publication_id>/<video_id>') +def play_id(video_id, publication_id=None): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + + if video_id and publication_id: + _vrtplayer.play(dict(publication_id=publication_id, video_id=video_id)) + elif video_id: + _vrtplayer.play(dict(video_id=video_id)) + + +@plugin.route('/play/url/<path:video_url>') +def play_url(video_url): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.play(dict(video_url=video_url)) + + +@plugin.route('/play/lastepisode/<program>') +def play_last(program): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.play_latest_episode(program) + + +@plugin.route('/favorites') +def favorites_menu(): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_favorites_menu_items() + + +@plugin.route('/favorites/programs') +def favorites_programs(): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_tvshow_menu_items(use_favorites=True) + + +@plugin.route('/favorites/recent') +@plugin.route('/favorites/recent/<page>') +def favorites_recent(page=1): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_recent(page=page, use_favorites=True) + + +@plugin.route('/favorites/offline') +@plugin.route('/favorites/offline/<page>') +def favorites_offline(page=1): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_offline(page=page, use_favorites=True) + + +@plugin.route('/favorites/refresh') +def favorites_refresh(): + from resources.lib import favorites + _favorites = favorites.Favorites(_kodi) + _favorites.get_favorites(ttl=0) + + +@plugin.route('/programs') +@plugin.route('/programs/<program>') +@plugin.route('/programs/<program>/<season>') +def programs(program=None, season=None): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + if program: + _vrtplayer.show_episodes(program, season) + return + _vrtplayer.show_tvshow_menu_items() + + +@plugin.route('/categories') +@plugin.route('/categories/<category>') +def categories(category=None): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + if category: + _vrtplayer.show_tvshow_menu_items(category=category) + return + _vrtplayer.show_category_menu_items() + + +@plugin.route('/channels') +@plugin.route('/channels/<channel>') +def channels(channel=None): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_channels_menu_items(channel=channel) + + +@plugin.route('/livetv') +def livetv(): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_livestream_items() + + +@plugin.route('/recent') +@plugin.route('/recent/<page>') +def recent(page=1): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_recent(page=page) + + +@plugin.route('/offline') +@plugin.route('/offline/<page>') +def offline(page=1): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.show_offline(page=page) + + +@plugin.route('/tvguide') +@plugin.route('/tvguide/<date>') +@plugin.route('/tvguide/<date>/<channel>') +def tv_guide(date=None, channel=None): + from resources.lib import tvguide + _tvguide = tvguide.TVGuide(_kodi) + _tvguide.show_tvguide(date=date, channel=channel) + + +@plugin.route('/search') +@plugin.route('/search/<search_string>') +@plugin.route('/search/<search_string>/<page>') +def search(search_string=None, page=1): + from resources.lib import vrtplayer + _vrtplayer = vrtplayer.VRTPlayer(_kodi) + _vrtplayer.search(search_string=search_string, page=page) + + +def test(path): + plugin.run(path) -from resources.lib import router if __name__ == '__main__': - router.router(sys.argv) + _kodi.log_access(sys.argv[0]) + plugin.run(sys.argv) diff --git a/addon.xml b/addon.xml index 0eba8ce4..387252a2 100644 --- a/addon.xml +++ b/addon.xml @@ -1,12 +1,13 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<addon id="plugin.video.vrt.nu" name="VRT NU" version="1.10.1" provider-name="Martijn Moreel, dagwieers"> +<addon id="plugin.video.vrt.nu" name="VRT NU" version="2.0.0" provider-name="Martijn Moreel, dagwieers"> <requires> <import addon="resource.images.studios.white" version="0.0.21"/> <import addon="script.module.beautifulsoup4" version="4.5.3"/> <import addon="script.module.dateutil" version="2.6.0"/> - <import addon="script.module.inputstreamhelper" version="0.3.3"/> <!-- import addon="inputstream.adaptive" version="2.0.20" optional="true"/ --> + <import addon="script.module.inputstreamhelper" version="0.3.3"/> <import addon="script.module.pysocks" version="1.6.8" optional="true"/> + <import addon="script.module.routing" version="0.2.0"/> <import addon="xbmc.python" version="2.25.0"/> </requires> diff --git a/pylintrc b/pylintrc index b4510c8f..9f82675f 100644 --- a/pylintrc +++ b/pylintrc @@ -1,5 +1,6 @@ [MESSAGES CONTROL] disable= + bad-option-value, broad-except, duplicate-code, fixme, diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index bfb2a8ab..a8e5a201 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -204,6 +204,10 @@ msgctxt "#30412" msgid "Unfollow" msgstr "" +msgctxt "#30413" +msgid "Refresh" +msgstr "" + msgctxt "#30415" msgid "No followed programs found" msgstr "" diff --git a/resources/language/resource.language.nl_nl/strings.po b/resources/language/resource.language.nl_nl/strings.po index b18968bf..403ffe4d 100644 --- a/resources/language/resource.language.nl_nl/strings.po +++ b/resources/language/resource.language.nl_nl/strings.po @@ -205,6 +205,10 @@ msgctxt "#30412" msgid "Unfollow" msgstr "Vergeet" +msgctxt "#30413" +msgid "Refresh" +msgstr "Vernieuw" + msgctxt "#30415" msgid "No followed programs found" msgstr "Geen programma's worden gevolgd" diff --git a/resources/lib/__init__.py b/resources/lib/__init__.py index bcb148bf..c0433c8d 100644 --- a/resources/lib/__init__.py +++ b/resources/lib/__init__.py @@ -66,6 +66,14 @@ studio='Sporza', live_stream_id='vualto_sporza_geo', ), + dict( + id='13', + name='vrtnws', + label='VRT NWS', + studio='VRT NWS', + live_stream_id='vualto_nieuws', + # live_stream_id='vualto_journaal', + ), dict( id='11', name='radio1', @@ -106,14 +114,6 @@ label='VRT NXT', studio='VRT NXT', ), - dict( - id='13', - name='vrtnws', - label='VRT NWS', - studio='VRT NWS', - live_stream_id='vualto_nieuws', - # live_stream_id='vualto_journaal', - ), ] diff --git a/resources/lib/favorites.py b/resources/lib/favorites.py index bef77a5c..40a8a6ee 100644 --- a/resources/lib/favorites.py +++ b/resources/lib/favorites.py @@ -6,7 +6,7 @@ ''' Implementation of Favorites class ''' from __future__ import absolute_import, division, unicode_literals -from resources.lib import statichelper +from resources.lib import statichelper, tokenresolver try: # Python 3 from urllib.parse import unquote @@ -18,10 +18,10 @@ class Favorites: ''' Track, cache and manage VRT favorites ''' - def __init__(self, _kodi, _tokenresolver): + def __init__(self, _kodi): ''' Initialize favorites, relies on XBMC vfs and a special VRT token ''' self._kodi = _kodi - self._tokenresolver = _tokenresolver + self._tokenresolver = tokenresolver.TokenResolver(_kodi) self._proxies = _kodi.get_proxies() install_opener(build_opener(ProxyHandler(self._proxies))) # This is our internal representation @@ -67,7 +67,7 @@ def set_favorite(self, title, program, value=True): xvrttoken = self._tokenresolver.get_xvrttoken(token_variant='user') if xvrttoken is None: - self._kodi.show_notification(message='Failed to get favorites roken from VRT NU') + self._kodi.show_notification(message='Failed to get favorites token from VRT NU') self._kodi.log_error('Failed to get favorites token from VRT NU') return False diff --git a/resources/lib/kodiwrapper.py b/resources/lib/kodiwrapper.py index 96f3490e..fcc8ae43 100644 --- a/resources/lib/kodiwrapper.py +++ b/resources/lib/kodiwrapper.py @@ -103,10 +103,11 @@ def has_socks(): class KodiWrapper: ''' A wrapper around all Kodi functionality ''' - def __init__(self, handle, url): + def __init__(self, plugin): ''' Initialize the Kodi wrapper ''' - self._handle = handle - self._url = url + self._plugin = plugin + self._handle = plugin.handle if plugin else -1 + self._url = plugin.base_url if plugin else 'plugin://plugin.video.vrt.nu' self._addon = xbmcaddon.Addon() self._addon_id = self._addon.getAddonInfo('id') self._max_log_level = log_levels.get(self.get_setting('max_log_level', 'Debug'), 3) diff --git a/resources/lib/router.py b/resources/lib/router.py deleted file mode 100644 index d23b7f12..00000000 --- a/resources/lib/router.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -''' Implements a router function as entrypoint for the add-on ''' - -from __future__ import absolute_import, division, unicode_literals - -from resources.lib import routes, kodiwrapper, tokenresolver - - -def get_params(path, route, params_length): - ''' Get a fixed size list of parameters ''' - max_split = -1 - params_data = path.split(route, 1)[1] - params = [] - if params_data != '': - if params_data.startswith('/url'): - max_split = 1 - params = params_data.lstrip('/').split('/', max_split) - params.extend([None] * (params_length - len(params))) - return params - - -def router(argv): - ''' This is the main router for the video plugin menu ''' - - addon_url = argv[0] - addon_handle = int(argv[1]) - path = '/' + addon_url.split('/', 3)[3] - - _kodi = kodiwrapper.KodiWrapper(addon_handle, addon_url) - _tokenresolver = tokenresolver.TokenResolver(_kodi) - _kodi.log_access(addon_url) - - # Cache delete method - if path.startswith(routes.CACHE_DELETE): - params = get_params(path, routes.CACHE_DELETE, 1) - if params[0]: - _kodi.refresh_caches(params[0]) - return - _kodi.invalidate_caches() - return - - # Tokens delete method - if path == 'routes.TOKENS_DELETE': - _tokenresolver.delete_tokens() - return - - # Widevine install method - if path == routes.WIDEVINE_INSTALL: - _kodi.install_widevine() - return - - from resources.lib import favorites - _favorites = favorites.Favorites(_kodi, _tokenresolver) - - # Follow method - if path.startswith(routes.FOLLOW): - params = get_params(path, routes.FOLLOW, 2) - _favorites.follow(title=params[0], program=params[1]) - return - - # Unfollow method - if path.startswith(routes.UNFOLLOW): - params = get_params(path, routes.UNFOLLOW, 2) - _favorites.unfollow(title=params[0], program=params[1]) - return - - from resources.lib import vrtapihelper, vrtplayer - _apihelper = vrtapihelper.VRTApiHelper(_kodi, _favorites) - _vrtplayer = vrtplayer.VRTPlayer(_kodi, _favorites, _apihelper) - - # Play methods - if path.startswith(routes.PLAY): - params = get_params(path, routes.PLAY, 3) - if params[0] == 'id': - if params[2]: - video = dict(publication_id=params[1], video_id=params[2]) - else: - video = dict(video_id=params[1]) - _vrtplayer.play(video) - elif params[0] == 'url': - video = dict(video_url=params[1]) - _vrtplayer.play(video) - elif params[0] == 'latestepisode': - _vrtplayer.play_latest_episode(params[1]) - return - - # Main menu - if path == routes.MAIN: - _vrtplayer.show_main_menu_items() - return - - # Favorites menu - if path.startswith(routes.FAVORITES): - params = get_params(path, routes.FAVORITES, 2) - if not params[0]: - _favorites.get_favorites(ttl=60 * 60) - _vrtplayer.show_favorites_menu_items() - return - if params[0] == 'programs': - # My programs menus may need more up-to-date favorites - _favorites.get_favorites(ttl=5 * 60) - _vrtplayer.show_tvshow_menu_items(use_favorites=True) - return - if params[0] == 'offline': - # My programs menus may need more up-to-date favorites - _favorites.get_favorites(ttl=5 * 60) - _vrtplayer.show_offline(use_favorites=True, page=params[1]) - return - if params[0] == 'recent': - # My programs menus may need more up-to-date favorites - _favorites.get_favorites(ttl=5 * 60) - _vrtplayer.show_recent(use_favorites=True, page=params[1]) - return - if params[0] == 'refresh': - _favorites.get_favorites(ttl=0) - return - - # A-Z menu, episode and season menu - if path.startswith(routes.PROGRAMS): - params = get_params(path, routes.PROGRAMS, 2) - if params[0]: - _favorites.get_favorites(ttl=60 * 60) - _vrtplayer.show_episodes(params[0], params[1]) - else: - _vrtplayer.show_tvshow_menu_items() - return - - # Categories menu - if path.startswith(routes.CATEGORIES): - params = get_params(path, routes.CATEGORIES, 1) - if params[0]: - _favorites.get_favorites(ttl=60 * 60) - _vrtplayer.show_tvshow_menu_items(category=params[0]) - return - _vrtplayer.show_category_menu_items() - return - - # Channels menu - if path.startswith(routes.CHANNELS): - params = get_params(path, routes.CHANNELS, 1) - if params[0]: - _favorites.get_favorites(ttl=60 * 60) - _vrtplayer.show_channels_menu_items(params[0]) - return - - # Live TV menu - if path == routes.LIVETV: - _vrtplayer.show_livestream_items() - return - - # Most recent menu - if path.startswith(routes.RECENT): - params = get_params(path, routes.RECENT, 1) - _vrtplayer.show_recent(page=params[0]) - return - - # Soon offline menu - if path.startswith(routes.OFFLINE): - params = get_params(path, routes.OFFLINE, 1) - _vrtplayer.show_offline(page=params[0]) - return - - # TV guide menu - if path.startswith(routes.TVGUIDE): - from resources.lib import tvguide - _tvguide = tvguide.TVGuide(_kodi) - params = get_params(path, routes.TVGUIDE, 2) - _tvguide.show_tvguide(params[0], params[1]) - return - - # Search VRT NU menu - if path.startswith(routes.SEARCH): - params = get_params(path, routes.SEARCH, 2) - _favorites.get_favorites(ttl=60 * 60) - _vrtplayer.search(search_string=params[0], page=params[1]) - return diff --git a/resources/lib/tvguide.py b/resources/lib/tvguide.py index 6f08a5a8..49214278 100644 --- a/resources/lib/tvguide.py +++ b/resources/lib/tvguide.py @@ -91,7 +91,7 @@ def show_date_menu(self): is_playable=False, art_dict=dict(thumb='DefaultYear.png', icon='DefaultYear.png', fanart='DefaultYear.png'), video_dict=dict(plot=self._kodi.localize_datelong(day)), - context_menu=[('Refresh', 'RunPlugin(%s%s)' % ('plugin://plugin.video.vrt.nu/cache/delete/', cache_file))], + context_menu=[(self._kodi.localize(30413), 'RunPlugin(%s%s)' % ('plugin://plugin.video.vrt.nu/cache/delete/', cache_file))], )) return date_items diff --git a/resources/lib/vrtapihelper.py b/resources/lib/vrtapihelper.py index 3b8d69a3..cbf7e9ab 100644 --- a/resources/lib/vrtapihelper.py +++ b/resources/lib/vrtapihelper.py @@ -92,7 +92,7 @@ def _map_to_tvshow_items(self, tvshows, use_favorites=False, cache_file=None): else: context_menu = [] refresh_url = plugin_url + routes.CACHE_DELETE - context_menu.append(('Refresh', 'RunPlugin(%s/%s)' % (refresh_url, cache_file))) + context_menu.append((self._kodi.localize(30413), 'RunPlugin(%s/%s)' % (refresh_url, cache_file))) tvshow_items.append(TitleItem( title=label, path=routes.PROGRAMS + '/' + program, @@ -301,7 +301,7 @@ def _map_to_episode_items(self, episodes, titletype=None, season=None, use_favor else: context_menu = [] refresh_url = plugin_url + routes.CACHE_DELETE - context_menu.append(('Refresh', 'RunPlugin(%s/%s)' % (refresh_url, cache_file))) + context_menu.append((self._kodi.localize(30413), 'RunPlugin(%s/%s)' % (refresh_url, cache_file))) if self._showfanart: thumb = statichelper.add_https_method(episode.get('videoThumbnailUrl', 'DefaultAddonVideo.png')) @@ -527,7 +527,7 @@ def get_channel_items(self, channels=None, live=True): label = self._kodi.localize(30101).format(**channel) # A single Live channel means it is the entry for channel's TV Show listing, so make it stand out if channels and len(channels) == 1: - label = '«%s»' % label + label = '[B]%s[/B]' % label is_playable = True if channel.get('name') in ['een', 'canvas', 'ketnet']: if self._showfanart: @@ -537,7 +537,7 @@ def get_channel_items(self, channels=None, live=True): plot = self._kodi.localize(30102).format(**channel) refresh_url = 'plugin://' + self._kodi.get_addon_id() + routes.CACHE_DELETE cache_file = 'channel.%s.json' % channel - context_menu = [('Refresh', 'RunPlugin(%s/%s)' % (refresh_url, cache_file))] + context_menu = [(self._kodi.localize(30413), 'RunPlugin(%s/%s)' % (refresh_url, cache_file))] else: # Not a playable channel continue diff --git a/resources/lib/vrtplayer.py b/resources/lib/vrtplayer.py index 1be28496..6899d274 100644 --- a/resources/lib/vrtplayer.py +++ b/resources/lib/vrtplayer.py @@ -5,21 +5,22 @@ ''' Implements a VRTPlayer class ''' from __future__ import absolute_import, division, unicode_literals -from resources.lib import routes, statichelper, streamservice, tokenresolver +from resources.lib import favorites, routes, statichelper, streamservice, tokenresolver, vrtapihelper from resources.lib.helperobjects import TitleItem class VRTPlayer: ''' An object providing all methods for Kodi menu generation ''' - def __init__(self, _kodi, _favorites, _apihelper): + def __init__(self, _kodi): ''' Initialise object ''' self._kodi = _kodi - self._favorites = _favorites - self._apihelper = _apihelper + self._favorites = favorites.Favorites(_kodi) + self._apihelper = vrtapihelper.VRTApiHelper(_kodi, self._favorites) def show_main_menu_items(self): ''' The VRT NU add-on main menu ''' + self._favorites.get_favorites(ttl=60 * 60) main_items = [] # Only add 'My programs' when it has been activated @@ -81,6 +82,7 @@ def show_main_menu_items(self): def show_favorites_menu_items(self): ''' The VRT NU addon 'My Programs' menu ''' + self._favorites.get_favorites(ttl=60 * 60) favorites_items = [ TitleItem(title=self._kodi.localize(30040), # My A-Z listing path=routes.FAVORITES_PROGRAMS, @@ -108,6 +110,11 @@ def show_favorites_menu_items(self): def show_tvshow_menu_items(self, category=None, use_favorites=False): ''' The VRT NU add-on 'A-Z' listing menu ''' + if use_favorites: + # My programs menus may need more up-to-date favorites + self._favorites.get_favorites(ttl=5 * 60) + else: + self._favorites.get_favorites(ttl=60 * 60) tvshow_items = self._apihelper.get_tvshow_items(category=category, use_favorites=use_favorites) self._kodi.show_listing(tvshow_items, sort='label', content='tvshows') @@ -119,6 +126,7 @@ def show_category_menu_items(self): def show_channels_menu_items(self, channel=None): ''' The VRT NU add-on 'Channels' listing menu ''' if channel: + self._favorites.get_favorites(ttl=60 * 60) # Add Live TV channel entry channel_item = self._apihelper.get_channel_items(channels=[channel]) tvshow_items = self._apihelper.get_tvshow_items(channel=channel) @@ -134,11 +142,17 @@ def show_livestream_items(self): def show_episodes(self, program, season=None): ''' The VRT NU add-on episodes listing menu ''' + self._favorites.get_favorites(ttl=60 * 60) episode_items, sort, ascending, content = self._apihelper.get_episode_items(program=program, season=season) self._kodi.show_listing(episode_items, sort=sort, ascending=ascending, content=content) def show_recent(self, page=0, use_favorites=False): ''' The VRT NU add-on 'Most recent' and 'My most recent' listing menu ''' + if use_favorites: + # My programs menus may need more up-to-date favorites + self._favorites.get_favorites(ttl=5 * 60) + else: + self._favorites.get_favorites(ttl=60 * 60) page = statichelper.realpage(page) episode_items, sort, ascending, content = self._apihelper.get_episode_items(page=page, use_favorites=use_favorites, variety='recent') @@ -160,6 +174,11 @@ def show_recent(self, page=0, use_favorites=False): def show_offline(self, page=0, use_favorites=False): ''' The VRT NU add-on 'Soon offline' and 'My soon offline' listing menu ''' + if use_favorites: + # My programs menus may need more up-to-date favorites + self._favorites.get_favorites(ttl=5 * 60) + else: + self._favorites.get_favorites(ttl=60 * 60) page = statichelper.realpage(page) episode_items, sort, ascending, content = self._apihelper.get_episode_items(page=page, use_favorites=use_favorites, variety='offline') @@ -181,6 +200,7 @@ def show_offline(self, page=0, use_favorites=False): def search(self, search_string=None, page=None): ''' The VRT NU add-on Search functionality and results ''' + self._favorites.get_favorites(ttl=60 * 60) page = statichelper.realpage(page) if search_string is None: diff --git a/service.py b/service.py index 1620e9db..19ef8cd1 100644 --- a/service.py +++ b/service.py @@ -19,7 +19,7 @@ def __init__(self): def onSettingsChanged(self): ''' Handler for changes to settings ''' - _kodi = kodiwrapper.KodiWrapper(None, None) + _kodi = kodiwrapper.KodiWrapper(None) _kodi.log_notice('VRT NU Addon: settings changed') _kodi.container_refresh() diff --git a/test/apihelpertests.py b/test/apihelpertests.py index a5e34e34..2a0673e8 100644 --- a/test/apihelpertests.py +++ b/test/apihelpertests.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import unittest -from resources.lib import CHANNELS, favorites, kodiwrapper, tokenresolver, vrtapihelper +from resources.lib import CHANNELS, favorites, kodiwrapper, vrtapihelper xbmc = __import__('xbmc') xbmcaddon = __import__('xbmcaddon') @@ -18,9 +18,8 @@ class ApiHelperTests(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin://plugin.video.vrt.nu') - _tokenresolver = tokenresolver.TokenResolver(_kodi) - _favorites = favorites.Favorites(_kodi, _tokenresolver) + _kodi = kodiwrapper.KodiWrapper(None) + _favorites = favorites.Favorites(_kodi) _apihelper = vrtapihelper.VRTApiHelper(_kodi, _favorites) def test_get_api_data_single_season(self): diff --git a/test/favoritestests.py b/test/favoritestests.py index a2e601ec..561830f5 100644 --- a/test/favoritestests.py +++ b/test/favoritestests.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import unittest -from resources.lib import favorites, kodiwrapper, tokenresolver +from resources.lib import favorites, kodiwrapper xbmc = __import__('xbmc') xbmcaddon = __import__('xbmcaddon') @@ -20,9 +20,8 @@ class TestFavorites(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin://plugin.video.vrt.nu') - _tokenresolver = tokenresolver.TokenResolver(_kodi) - _favorites = favorites.Favorites(_kodi, _tokenresolver) + _kodi = kodiwrapper.KodiWrapper(None) + _favorites = favorites.Favorites(_kodi) def test_follow_unfollow(self): programs = [ diff --git a/test/routertests.py b/test/routertests.py deleted file mode 100644 index 1b9609de..00000000 --- a/test/routertests.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- - -# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# pylint: disable=missing-docstring - -from __future__ import absolute_import, division, print_function, unicode_literals -import unittest - -from resources.lib import router - -xbmc = __import__('xbmc') -xbmcaddon = __import__('xbmcaddon') -xbmcgui = __import__('xbmcgui') -xbmcplugin = __import__('xbmcplugin') -xbmcvfs = __import__('xbmcvfs') - - -class TestRouter(unittest.TestCase): - - def test_main_menu(self): - router.router(['plugin://plugin.video.vrt.nu/', '0', '']) - - # Favorites menu: '/favorites' - def test_favorites(self): - router.router(['plugin://plugin.video.vrt.nu/favorites', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/favorites/programs', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/favorites/recent', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/favorites/recent/2', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/favorites/offline', '0', '']) - - # A-Z menu: '/programs' - def test_az_menu(self): - router.router(['plugin://plugin.video.vrt.nu/programs', '0', '']) - - # Episodes menu: '/programs/<program>' - def test_episodes_menu(self): - router.router(['plugin://plugin.video.vrt.nu/programs/thuis', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/programs/de-campus-cup', '0', '']) - - # Categories menu: '/categories' - def test_categories_menu(self): - router.router(['plugin://plugin.video.vrt.nu/categories', '0', '']) - - # Categories programs menu: '/categories/<category>' - def test_categories_tvshow_menu(self): - router.router(['plugin://plugin.video.vrt.nu/categories/docu', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/categories/kinderen', '0', '']) - - # Channels menu = '/channels/<channel>' - def test_channels_menu(self): - router.router(['plugin://plugin.video.vrt.nu/channels', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/ketnet', '0', '']) - - # Live TV menu: '/livetv' - def test_livetv_menu(self): - router.router(['plugin://plugin.video.vrt.nu/livetv', '0', '']) - - # Most recent menu: '/recent/<page>' - def test_recent_menu(self): - router.router(['plugin://plugin.video.vrt.nu/recent', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/recent/2', '0', '']) - - # Soon offline menu: '/offline/<page>' - def test_offline_menu(self): - router.router(['plugin://plugin.video.vrt.nu/offline', '0', '']) - - # TV guide menu: '/tvguide/<date>/<channel>' - def test_tvguide_date_menu(self): - router.router(['plugin://plugin.video.vrt.nu/tvguide', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/tvguide/today', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/tvguide/today/canvas', '0', '']) - - # Search VRT NU menu: '/search/<search_string>/<page>' - def test_search_menu(self): - router.router(['plugin://plugin.video.vrt.nu/search', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/search/dag', '0', '']) - router.router(['plugin://plugin.video.vrt.nu/search/dag/2', '0', '']) - - # Follow method: '/follow/<program_title>/<program>' - def test_follow_router(self): - router.router(['plugin://plugin.video.vrt.nu/follow/Thuis/thuis', '0', '']) - - # Unfollow method: '/unfollow/<program_title>/<program>' - def test_unfollow_router(self): - router.router(['plugin://plugin.video.vrt.nu/unfollow/Thuis/thuis', '0', '']) - - # Delete tokens method: '/tokens/delete' - def test_clear_cookies_router(self): - router.router(['plugin://plugin.video.vrt.nu/tokens/delete', '0', '']) - - # Delete cache method: '/cache/delete' - def test_invalidate_caches_router(self): - router.router(['plugin://plugin.video.vrt.nu/cache/delete', '0', '']) - - # Refresh favorites method: '/favorites/refresh' - def test_refresh_favorites_router(self): - router.router(['plugin://plugin.video.vrt.nu/favorites/refresh', '0', '']) - - # Play on demand by id = '/play/id/<publication_id>/<video_id>' - # Achterflap episode 8 available until 31/12/2025 - def test_play_on_demand_by_id_router(self): - router.router(['plugin://plugin.video.vrt.nu/play/id/pbs-pub-1a170972-dea3-4ea3-8c27-62d2442ee8a3/vid-f80fa527-6759-45a7-908d-ec6f0a7b164e', '0', '']) - - # Play livestream by id = '/play/id/<video_id>' - # Canvas livestream - def test_play_livestream_by_id_router(self): - router.router(['plugin://plugin.video.vrt.nu/play/id/vualto_canvas_geo', '0', '']) - - # Play on demand by url = '/play/url/<vrtnuwebsite_url>' - # Achterflap episode 8 available until 31/12/2025 - def test_play_on_demand_by_url_router(self): - router.router(['plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/a-z/achterflap/1/achterflap-s1a8/', '0', '']) - - # Play livestream by url = '/play/url/<vrtnuwebsite_url>' - # Canvas livestream - def test_play_livestream_by_url_router(self): - router.router(['plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/kanalen/canvas/', '0', '']) - - # Play last episode method = '/play/lastepisode/<program>' - def test_play_lastepisode_router(self): - router.router(['plugin://plugin.video.vrt.nu/play/lastepisode/het-journaal', '0', '']) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/routing.py b/test/routing.py new file mode 100644 index 00000000..3135fbe6 --- /dev/null +++ b/test/routing.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014-2015 Thomas Amland +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# pylint: disable=dangerous-default-value,missing-docstring,useless-object-inheritance + +from __future__ import absolute_import, division, print_function, unicode_literals + +import re +import sys +try: + from urlparse import urlsplit, parse_qs +except ImportError: + from urllib.parse import urlsplit, parse_qs +try: + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode + +try: + import xbmc + import xbmcaddon + _addon_id = xbmcaddon.Addon().getAddonInfo('id') + + def log(msg): + msg = "[%s][routing] %s" % (_addon_id, msg) + xbmc.log(msg, level=xbmc.LOGDEBUG) +except ImportError: + def log(msg): + print(msg) + + +class RoutingError(Exception): + pass + + +class Plugin(object): + """ + :ivar handle: The plugin handle from kodi + :type handle: int + + :ivar args: The parsed query string. + :type args: dict of byte strings + """ + + def __init__(self, base_url=None): + self._rules = {} # function to list of rules + argv = sys.argv if len(sys.argv) > 1 else ['', '', ''] + self.handle = int(argv[1]) if argv[1].isdigit() else -1 + self.args = {} + self.base_url = base_url + if self.base_url is None: + self.base_url = "plugin://" + xbmcaddon.Addon().getAddonInfo('id') + + def route_for(self, path): + """ + Returns the view function for path. + + :type path: byte string. + """ + if path.startswith(self.base_url): + path = path.split(self.base_url, 1)[1] + + for view_fun, rules in iter(self._rules.items()): + for rule in rules: + if rule.match(path) is not None: + return view_fun + return None + + def url_for(self, func, *args, **kwargs): + """ + Construct and returns an URL for view function with give arguments. + """ + if func in self._rules: + for rule in self._rules[func]: + path = rule.make_path(*args, **kwargs) + if path is not None: + return self.url_for_path(path) + raise RoutingError("No known paths to '{0}' with args {1} and " + "kwargs {2}".format(func.__name__, args, kwargs)) + + def url_for_path(self, path): + """ + Returns the complete URL for a path. + """ + path = path if path.startswith('/') else '/' + path + return self.base_url + path + + def route(self, pattern): + """ Register a route. """ + def decorator(func): + self.add_route(func, pattern) + return func + return decorator + + def add_route(self, func, pattern): + """ Register a route. """ + rule = UrlRule(pattern) + if func not in self._rules: + self._rules[func] = [] + self._rules[func].append(rule) + + def run(self, argv=sys.argv): + if len(argv) > 2: + self.args = parse_qs(argv[2].lstrip('?')) + path = urlsplit(argv[0]).path or '/' + self._dispatch(path) + + def redirect(self, path): + self._dispatch(path) + + def _dispatch(self, path): + for view_func, rules in iter(self._rules.items()): + for rule in rules: + kwargs = rule.match(path) + if kwargs is not None: + log("Dispatching to '%s', args: %s" % (view_func.__name__, kwargs)) + view_func(**kwargs) + return + raise RoutingError('No route to path "%s"' % path) + + +class UrlRule(object): + + def __init__(self, pattern): + kw_pattern = r'<(?:[^:]+:)?([A-z]+)>' + self._pattern = re.sub(kw_pattern, '{\\1}', pattern) + self._keywords = re.findall(kw_pattern, pattern) + + p = re.sub('<([A-z]+)>', '<string:\\1>', pattern) + p = re.sub('<string:([A-z]+)>', '(?P<\\1>[^/]+?)', p) + p = re.sub('<path:([A-z]+)>', '(?P<\\1>.*)', p) + self._compiled_pattern = p + self._regex = re.compile('^' + p + '$') + + def match(self, path): + """ + Check if path matches this rule. Returns a dictionary of the extracted + arguments if match, otherwise None. + """ + # match = self._regex.search(urlsplit(path).path) + match = self._regex.search(path) + return match.groupdict() if match else None + + def make_path(self, *args, **kwargs): + """Construct a path from arguments.""" + if args and kwargs: + return None # can't use both args and kwargs + if args: + # Replace the named groups %s and format + try: + return re.sub(r'{[A-z]+}', r'%s', self._pattern) % args + except TypeError: + return None + + # We need to find the keys from kwargs that occur in our pattern. + # Unknown keys are pushed to the query string. + url_kwargs = dict(((k, v) for k, v in kwargs.items() if k in self._keywords)) + qs_kwargs = dict(((k, v) for k, v in kwargs.items() if k not in self._keywords)) + + query = '?' + urlencode(qs_kwargs) if qs_kwargs else '' + try: + return self._pattern.format(**url_kwargs) + query + except KeyError: + return None + + def __str__(self): + return b"Rule(pattern=%s, keywords=%s)" % (self._pattern, self._keywords) diff --git a/test/routingtests.py b/test/routingtests.py new file mode 100644 index 00000000..35e37098 --- /dev/null +++ b/test/routingtests.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# pylint: disable=missing-docstring + +from __future__ import absolute_import, division, print_function, unicode_literals +import unittest +import addon + +xbmc = __import__('xbmc') +xbmcaddon = __import__('xbmcaddon') +xbmcgui = __import__('xbmcgui') +xbmcplugin = __import__('xbmcplugin') +xbmcvfs = __import__('xbmcvfs') + + +class TestRouter(unittest.TestCase): + + def test_main_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.main_menu), 'plugin://plugin.video.vrt.nu/') + + # Favorites menu: '/favorites' + def test_favorites(self): + addon.test(['plugin://plugin.video.vrt.nu/favorites', '0', '']) + addon.test(['plugin://plugin.video.vrt.nu/favorites/programs', '0', '']) + addon.test(['plugin://plugin.video.vrt.nu/favorites/recent', '0', '']) + addon.test(['plugin://plugin.video.vrt.nu/favorites/recent/2', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.favorites_recent, page=2), 'plugin://plugin.video.vrt.nu/favorites/recent/2') + addon.test(['plugin://plugin.video.vrt.nu/favorites/offline', '0', '']) + + # A-Z menu: '/programs' + def test_az_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/programs', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.programs), 'plugin://plugin.video.vrt.nu/programs') + + # Episodes menu: '/programs/<program>' + def test_episodes_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/programs/thuis', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.programs, program='thuis'), 'plugin://plugin.video.vrt.nu/programs/thuis') + addon.test(['plugin://plugin.video.vrt.nu/programs/de-campus-cup', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.programs, program='de-campus-cup'), 'plugin://plugin.video.vrt.nu/programs/de-campus-cup') + + # Categories menu: '/categories' + def test_categories_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/categories', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.categories), 'plugin://plugin.video.vrt.nu/categories') + + # Categories programs menu: '/categories/<category>' + def test_categories_tvshow_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/categories/docu', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.categories, category='docu'), 'plugin://plugin.video.vrt.nu/categories/docu') + addon.test(['plugin://plugin.video.vrt.nu/categories/kinderen', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.categories, category='kinderen'), 'plugin://plugin.video.vrt.nu/categories/kinderen') + + # Channels menu = '/channels/<channel>' + def test_channels_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/channels', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.channels), 'plugin://plugin.video.vrt.nu/channels') + addon.test(['plugin://plugin.video.vrt.nu/channels/ketnet', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.channels, channel='ketnet'), 'plugin://plugin.video.vrt.nu/channels/ketnet') + + # Live TV menu: '/livetv' + def test_livetv_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/livetv', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.livetv), 'plugin://plugin.video.vrt.nu/livetv') + + # Most recent menu: '/recent/<page>' + def test_recent_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/recent', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.recent), 'plugin://plugin.video.vrt.nu/recent') + addon.test(['plugin://plugin.video.vrt.nu/recent/2', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.recent, page=2), 'plugin://plugin.video.vrt.nu/recent/2') + + # Soon offline menu: '/offline/<page>' + def test_offline_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/offline', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.offline), 'plugin://plugin.video.vrt.nu/offline') + + # TV guide menu: '/tvguide/<date>/<channel>' + def test_tvguide_date_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/tvguide', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.tv_guide), 'plugin://plugin.video.vrt.nu/tvguide') + addon.test(['plugin://plugin.video.vrt.nu/tvguide/today', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.tv_guide, date='today'), 'plugin://plugin.video.vrt.nu/tvguide/today') + addon.test(['plugin://plugin.video.vrt.nu/tvguide/today/canvas', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.tv_guide, date='today', channel='canvas'), 'plugin://plugin.video.vrt.nu/tvguide/today/canvas') + + # Search VRT NU menu: '/search/<search_string>/<page>' + def test_search_menu(self): + addon.test(['plugin://plugin.video.vrt.nu/search', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.search), 'plugin://plugin.video.vrt.nu/search') + addon.test(['plugin://plugin.video.vrt.nu/search/dag', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.search, search_string='dag'), 'plugin://plugin.video.vrt.nu/search/dag') + addon.test(['plugin://plugin.video.vrt.nu/search/dag/2', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.search, search_string='dag', page=2), 'plugin://plugin.video.vrt.nu/search/dag/2') + + # Follow method: '/follow/<program_title>/<program>' + def test_follow_route(self): + addon.test(['plugin://plugin.video.vrt.nu/follow/Thuis/thuis', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.follow, title='Thuis', program='thuis'), 'plugin://plugin.video.vrt.nu/follow/Thuis/thuis') + + # Unfollow method: '/unfollow/<program_title>/<program>' + def test_unfollow_route(self): + addon.test(['plugin://plugin.video.vrt.nu/unfollow/Thuis/thuis', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.unfollow, title='Thuis', program='thuis'), 'plugin://plugin.video.vrt.nu/unfollow/Thuis/thuis') + + # Delete tokens method: '/tokens/delete' + def test_clear_cookies_route(self): + addon.test(['plugin://plugin.video.vrt.nu/tokens/delete', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.delete_tokens), 'plugin://plugin.video.vrt.nu/tokens/delete') + + # Delete cache method: '/cache/delete' + def test_invalidate_caches_route(self): + addon.test(['plugin://plugin.video.vrt.nu/cache/delete', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.delete_cache), 'plugin://plugin.video.vrt.nu/cache/delete') + + # Refresh favorites method: '/favorites/refresh' + def test_refresh_favorites_route(self): + addon.test(['plugin://plugin.video.vrt.nu/favorites/refresh', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.favorites_refresh), 'plugin://plugin.video.vrt.nu/favorites/refresh') + + # Play on demand by id = '/play/id/<publication_id>/<video_id>' + # Achterflap episode 8 available until 31/12/2025 + def test_play_on_demand_by_id_route(self): + addon.test(['plugin://plugin.video.vrt.nu/play/id/pbs-pub-1a170972-dea3-4ea3-8c27-62d2442ee8a3/vid-f80fa527-6759-45a7-908d-ec6f0a7b164e', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.play_id, publication_id='pbs-pub-1a170972-dea3-4ea3-8c27-62d2442ee8a3', video_id='vid-f80fa527-6759-45a7-908d-ec6f0a7b164e'), 'plugin://plugin.video.vrt.nu/play/id/pbs-pub-1a170972-dea3-4ea3-8c27-62d2442ee8a3/vid-f80fa527-6759-45a7-908d-ec6f0a7b164e') + + # Play livestream by id = '/play/id/<video_id>' + # Canvas livestream + def test_play_livestream_by_id_route(self): + addon.test(['plugin://plugin.video.vrt.nu/play/id/vualto_canvas_geo', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.play_id, video_id='vualto_canvas_geo'), 'plugin://plugin.video.vrt.nu/play/id/vualto_canvas_geo') + + # Play on demand by url = '/play/url/<vrtnuwebsite_url>' + # Achterflap episode 8 available until 31/12/2025 + def test_play_on_demand_by_url_route(self): + addon.test(['plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/a-z/achterflap/1/achterflap-s1a8/', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.play_url, video_url='https://www.vrt.be/vrtnu/a-z/achterflap/1/achterflap-s1a8/'), 'plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/a-z/achterflap/1/achterflap-s1a8/') + + # Play livestream by url = '/play/url/<vrtnuwebsite_url>' + # Canvas livestream + def test_play_livestream_by_url_route(self): + addon.test(['plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/kanalen/canvas/', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.play_url, video_url='https://www.vrt.be/vrtnu/kanalen/canvas/'), 'plugin://plugin.video.vrt.nu/play/url/https://www.vrt.be/vrtnu/kanalen/canvas/') + + # Play last episode method = '/play/lastepisode/<program>' + def test_play_lastepisode_route(self): + addon.test(['plugin://plugin.video.vrt.nu/play/lastepisode/het-journaal', '0', '']) + self.assertEqual(addon.plugin.url_for(addon.play_last, program='het-journaal'), 'plugin://plugin.video.vrt.nu/play/lastepisode/het-journaal') + + +if __name__ == '__main__': + unittest.main() diff --git a/test/searchtests.py b/test/searchtests.py index 7929fb1c..7953d52d 100644 --- a/test/searchtests.py +++ b/test/searchtests.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import unittest -from resources.lib import favorites, kodiwrapper, tokenresolver, vrtapihelper +from resources.lib import favorites, kodiwrapper, vrtapihelper xbmc = __import__('xbmc') xbmcaddon = __import__('xbmcaddon') @@ -18,9 +18,8 @@ class TestSearch(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin.video.vrt.nu') - _tokenresolver = tokenresolver.TokenResolver(_kodi) - _favorites = favorites.Favorites(_kodi, _tokenresolver) + _kodi = kodiwrapper.KodiWrapper(None) + _favorites = favorites.Favorites(_kodi) _apihelper = vrtapihelper.VRTApiHelper(_kodi, _favorites) def test_search_journaal(self): diff --git a/test/streamservicetests.py b/test/streamservicetests.py index 6552e977..780ebf71 100644 --- a/test/streamservicetests.py +++ b/test/streamservicetests.py @@ -29,7 +29,7 @@ class StreamServiceTests(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin://plugin.video.vrt.nu') + _kodi = kodiwrapper.KodiWrapper(None) _tokenresolver = tokenresolver.TokenResolver(_kodi) _streamservice = streamservice.StreamService(_kodi, _tokenresolver) diff --git a/test/tvguidetests.py b/test/tvguidetests.py index e1851866..1b3e28c1 100644 --- a/test/tvguidetests.py +++ b/test/tvguidetests.py @@ -23,7 +23,7 @@ class TestTVGuide(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin.video.vrt.nu') + _kodi = kodiwrapper.KodiWrapper(None) _tvguide = tvguide.TVGuide(_kodi) def test_tvguide_date_menu(self): diff --git a/test/vrtplayertests.py b/test/vrtplayertests.py index ac98f21b..b2b0319a 100644 --- a/test/vrtplayertests.py +++ b/test/vrtplayertests.py @@ -8,7 +8,7 @@ import random import unittest -from resources.lib import CATEGORIES, favorites, kodiwrapper, tokenresolver, vrtapihelper, vrtplayer +from resources.lib import CATEGORIES, favorites, kodiwrapper, vrtapihelper, vrtplayer xbmc = __import__('xbmc') xbmcaddon = __import__('xbmcaddon') @@ -19,11 +19,10 @@ class TestVRTPlayer(unittest.TestCase): - _kodi = kodiwrapper.KodiWrapper(None, 'plugin://plugin.video.vrt.nu') - _tokenresolver = tokenresolver.TokenResolver(_kodi) - _favorites = favorites.Favorites(_kodi, _tokenresolver) + _kodi = kodiwrapper.KodiWrapper(None) + _favorites = favorites.Favorites(_kodi) _apihelper = vrtapihelper.VRTApiHelper(_kodi, _favorites) - _vrtplayer = vrtplayer.VRTPlayer(_kodi, _favorites, _apihelper) + _vrtplayer = vrtplayer.VRTPlayer(_kodi) def test_show_videos_single_episode_shows_videos(self): program = 'marathonradio' diff --git a/test/xbmc.py b/test/xbmc.py index 4831475f..28077cb0 100644 --- a/test/xbmc.py +++ b/test/xbmc.py @@ -12,6 +12,7 @@ import polib +LOGDEBUG = 'Debug' LOGERROR = 'Error' LOGNOTICE = 'Notice'