Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

always use programUrl (instead of programName) #300

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 24 additions & 31 deletions resources/lib/favorites.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
''' Implementation of Favorites class '''

from __future__ import absolute_import, division, unicode_literals
from resources.lib import statichelper

try: # Python 3
from urllib.request import build_opener, install_opener, ProxyHandler, Request, urlopen
Expand Down Expand Up @@ -54,12 +55,12 @@ def get_favorites(self, ttl=None):
self._kodi.update_cache('favorites.json', api_json)
self._favorites = api_json

def set_favorite(self, program, path, value=True):
def set_favorite(self, title, program, value=True):
''' Set a program as favorite, and update local copy '''
import json

self.get_favorites(ttl=60 * 60)
if value is self.is_favorite(path):
if value is self.is_favorite(program):
# Already followed/unfollowed, nothing to do
return True

Expand All @@ -74,63 +75,55 @@ def set_favorite(self, program, path, value=True):
'content-type': 'application/json',
'Referer': 'https://www.vrt.be/vrtnu',
}
payload = dict(isFavorite=value, programUrl=path, title=program)
payload = dict(isFavorite=value, programUrl=statichelper.program_to_url(program, 'short'), title=title)
data = json.dumps(payload).encode('utf-8')
self._kodi.log_notice('URL post: https://video-user-data.vrt.be/favorites/%s' % self.uuid(path), 'Verbose')
req = Request('https://video-user-data.vrt.be/favorites/%s' % self.uuid(path), data=data, headers=headers)
self._kodi.log_notice('URL post: https://video-user-data.vrt.be/favorites/%s' % self.uuid(program), 'Verbose')
req = Request('https://video-user-data.vrt.be/favorites/%s' % self.uuid(program), data=data, headers=headers)
result = urlopen(req)
if result.getcode() != 200:
self._kodi.show_notification(message="Failed to (un)follow program '%s' at VRT NU" % path)
self._kodi.log_error("Failed to (un)follow program '%s' at VRT NU" % path)
self._kodi.show_notification(message="Failed to (un)follow program '%s' at VRT NU" % program)
self._kodi.log_error("Failed to (un)follow program '%s' at VRT NU" % program)
return False
# NOTE: Updates to favorites take a longer time to take effect, so we keep our own cache and use it
self._favorites[self.uuid(path)] = dict(value=payload)
self._favorites[self.uuid(program)] = dict(value=payload)
self._kodi.update_cache('favorites.json', self._favorites)
self.invalidate_caches()
return True

def is_favorite(self, path):
def is_favorite(self, program):
''' Is a program a favorite ? '''
value = False
favorite = self._favorites.get(self.uuid(path))
favorite = self._favorites.get(self.uuid(program))
if favorite is not None:
value = favorite.get('value', dict(isFavorite=False)).get('isFavorite', False)
return value

def follow(self, program, path):
def follow(self, title, program):
''' Follow your favorite program '''
ok = self.set_favorite(program, path, True)
ok = self.set_favorite(title, program, True)
if ok:
self._kodi.show_notification(message='Follow ' + program)
self._kodi.show_notification(message='Follow ' + title)
self._kodi.container_refresh()

def unfollow(self, program, path):
def unfollow(self, title, program):
''' Unfollow your favorite program '''
ok = self.set_favorite(program, path, False)
ok = self.set_favorite(title, program, False)
if ok:
self._kodi.show_notification(message='Unfollow ' + program)
self._kodi.show_notification(message='Unfollow ' + title)
self._kodi.container_refresh()

def uuid(self, path):
''' Return a favorite uuid, used for lookups in favorites dict '''
return path.replace('/', '').replace('-', '')

def name(self, path):
''' Return the favorite name '''
try:
return path.replace('.relevant/', '/').split('/')[-2]
except IndexError:
# FIXME: Investigate when this fails !
return path

def names(self):
''' Return all favorite names '''
return [self.name(p.get('value').get('programUrl')) for p in self._favorites.values() if p.get('value').get('isFavorite')]
def uuid(self, program):
''' Convert a program url component (e.g. de-campus-cup) to a favorite uuid (e.g. vrtnuazdecampuscup), used for lookups in favorites dict '''
return 'vrtnuaz' + program.replace('-', '')

def titles(self):
''' Return all favorite titles '''
return [p.get('value').get('title') for p in self._favorites.values() if p.get('value').get('isFavorite')]

def programs(self):
''' Return all favorite programs '''
return [statichelper.url_to_program(p.get('value').get('programUrl')) for p in self._favorites.values() if p.get('value').get('isFavorite')]

def invalidate_caches(self):
''' Invalidate caches that rely on favorites '''
# NOTE/ Do not invalidate favorites cache as we manage it ourselves
Expand Down
8 changes: 4 additions & 4 deletions resources/lib/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ def router(argv):

# Actions requiring _favorites as well
if action == actions.FOLLOW:
_favorites.follow(program=params.get('program'), path=params.get('path'))
_favorites.follow(title=params.get('title'), program=params.get('program'))
return
if action == actions.UNFOLLOW:
_favorites.unfollow(program=params.get('program'), path=params.get('path'))
_favorites.unfollow(title=params.get('title'), program=params.get('program'))
return
if action == actions.REFRESH_FAVORITES:
_favorites.get_favorites(ttl=0)
Expand Down Expand Up @@ -109,11 +109,11 @@ def router(argv):
return
if action == actions.LISTING_EPISODES:
_favorites.get_favorites(ttl=60 * 60)
_vrtplayer.show_episodes(path=params.get('video_url'))
_vrtplayer.show_episodes(program=params.get('program'), season=params.get('season'))
return
if action == actions.LISTING_ALL_EPISODES:
_favorites.get_favorites(ttl=60 * 60)
_vrtplayer.show_all_episodes(path=params.get('video_url'))
_vrtplayer.show_all_episodes(program=params.get('program'))
return
if action == actions.SEARCH:
_favorites.get_favorites(ttl=60 * 60)
Expand Down
35 changes: 30 additions & 5 deletions resources/lib/statichelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,36 @@ def convert_html_to_kodilabel(text):
return unescape(text).strip()


def unique_path(path):
''' Create a unique path to be used in VRT favorites '''
if path.startswith('//www.vrt.be/vrtnu'):
return path.replace('//www.vrt.be/vrtnu/', '/vrtnu/').replace('.relevant/', '/')
return path
def program_to_url(program, url_type):
''' Convert a program url component (e.g. de-campus-cup) to a short programUrl (e.g. /vrtnu/a-z/de-campus-cup/)
or to a long programUrl (e.g. //www.vrt.be/vrtnu/a-z/de-campus-cup/)
'''
url = None
if program:
# short programUrl
if url_type == 'short':
url = '/vrtnu/a-z/' + program + '/'
# long programUrl
elif url_type == 'long':
url = '//www.vrt.be/vrtnu/a-z/' + program + '/'
return url


def url_to_program(url):
''' Convert a targetUrl (e.g. //www.vrt.be/vrtnu/a-z/de-campus-cup.relevant/), a short programUrl (e.g. /vrtnu/a-z/de-campus-cup/)
or a long programUrl (e.g. //www.vrt.be/vrtnu/a-z/de-campus-cup/) to a program url component (e.g. de-campus-cup)
'''
program = None
# targetUrl
if url.startswith('//www.vrt.be/vrtnu/a-z/') and url.endswith('.relevant/'):
program = url.replace('//www.vrt.be/vrtnu/a-z/', '').replace('.relevant/', '')
# short programUrl
elif url.startswith('/vrtnu/a-z/'):
program = url.replace('/vrtnu/a-z/', '').rstrip('/')
# long programUrl
elif url.startswith('//www.vrt.be/vrtnu/a-z/'):
program = url.replace('//www.vrt.be/vrtnu/a-z/', '').rstrip('/')
return program


def shorten_link(url):
Expand Down
82 changes: 36 additions & 46 deletions resources/lib/vrtapihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ def _map_to_tvshow_items(self, tvshows, use_favorites=False):
''' Construct a list of TV show TitleItems based on Suggests API query and filtered by favorites '''
tvshow_items = []
if statichelper.boolean(use_favorites):
favorite_names = self._favorites.names()
programs = self._favorites.programs()
for tvshow in tvshows:
if statichelper.boolean(use_favorites) and tvshow.get('programName') not in favorite_names:
program = statichelper.url_to_program(tvshow.get('targetUrl'))
if statichelper.boolean(use_favorites) and program not in programs:
continue
metadata = metadatacreator.MetadataCreator()
metadata.tvshowtitle = tvshow.get('title', '???')
Expand All @@ -82,35 +83,31 @@ def _map_to_tvshow_items(self, tvshows, use_favorites=False):
else:
thumbnail = 'DefaultAddonVideo.png'
if self._favorites.is_activated():
program_path = statichelper.unique_path(tvshow.get('targetUrl'))
program = tvshow.get('title').encode('utf-8')
if self._favorites.is_favorite(program_path):
params = dict(action='unfollow', program=program, path=program_path)
title = tvshow.get('title').encode('utf-8')
if self._favorites.is_favorite(program):
params = dict(action='unfollow', title=title, program=program)
context_menu = [(self._kodi.localize(30412), 'RunPlugin(plugin://plugin.video.vrt.nu?%s)' % urlencode(params))]
else:
params = dict(action='follow', program=program, path=program_path)
params = dict(action='follow', title=title, program=program)
context_menu = [(self._kodi.localize(30411), 'RunPlugin(plugin://plugin.video.vrt.nu?%s)' % urlencode(params))]
else:
context_menu = []
# 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(TitleItem(
title=label,
url_dict=dict(action=actions.LISTING_EPISODES, video_url=video_url),
url_dict=dict(action=actions.LISTING_EPISODES, program=program),
is_playable=False,
art_dict=dict(thumb=thumbnail, icon='DefaultAddonVideo.png', fanart=thumbnail),
video_dict=metadata.get_video_dict(),
context_menu=context_menu,
))
return tvshow_items

def get_latest_episode(self, tvshow):
def get_latest_episode(self, program):
''' Get the latest episode of a program '''
import json
video = None
params = {
'facets[programName]': tvshow,
'facets[programUrl]': statichelper.program_to_url(program, 'long'),
'i': 'video',
'size': '1',
}
Expand All @@ -122,10 +119,9 @@ def get_latest_episode(self, tvshow):
video = dict(video_id=episode.get('videoId'), publication_id=episode.get('publicationId'))
return video

def get_episode_items(self, path=None, page=None, show_seasons=False, use_favorites=False, variety=None):
def get_episode_items(self, program=None, season=None, page=None, show_seasons=False, use_favorites=False, variety=None):
''' Construct a list of TV show episodes TitleItems based on API query and filtered by favorites '''
titletype = None
season_key = None
all_items = True
episode_items = []
sort = 'episode'
Expand All @@ -150,7 +146,8 @@ def get_episode_items(self, path=None, page=None, show_seasons=False, use_favori
params['facets[assetOffTime]'] = datetime.now(dateutil.tz.gettz('Europe/Brussels')).strftime('%Y-%m-%d')

if statichelper.boolean(use_favorites):
params['facets[programName]'] = '[%s]' % (','.join(self._favorites.names()))
program_urls = [statichelper.program_to_url(p, 'long') for p in self._favorites.programs()]
params['facets[programUrl]'] = '[%s]' % (','.join(program_urls))
cache_file = 'my-%s-%s.json' % (variety, page)
else:
params['facets[programBrands]'] = '[%s]' % (','.join(self._channel_filter))
Expand All @@ -165,28 +162,23 @@ def get_episode_items(self, path=None, page=None, show_seasons=False, use_favori
api_json = json.load(urlopen(api_url))
self._kodi.update_cache(cache_file, api_json)
return self._map_to_episode_items(api_json.get('results', []), titletype=variety, use_favorites=use_favorites)
if program:
params = {
'facets[programUrl]': statichelper.program_to_url(program, 'long'),
'i': 'video',
'size': '150',
}
if season:
params.update({'facets[seasonTitle]': season})

if path:
if '.relevant/' in path:
params = {
'facets[programUrl]': '//www.vrt.be' + path.replace('.relevant/', '/'),
'i': 'video',
'size': '150',
}
api_url = self._VRTNU_SEARCH_URL + '?' + urlencode(params)
else:
api_url = path

path = unquote(path)
if 'facets[seasonTitle]' in path:
season_key = path.split('facets[seasonTitle]=')[1]
api_url = self._VRTNU_SEARCH_URL + '?' + urlencode(params)

results, episodes = self._get_season_episode_data(api_url, show_seasons=show_seasons, all_items=all_items)

if results.get('episodes'):
return self._map_to_episode_items(results.get('episodes', []), titletype=titletype, season_key=season_key, use_favorites=use_favorites)
return self._map_to_episode_items(results.get('episodes', []), titletype=titletype, season=season, use_favorites=use_favorites)
if results.get('seasons'):
return self._map_to_season_items(api_url, results.get('seasons'), episodes)
return self._map_to_season_items(program, results.get('seasons'), episodes)

return episode_items, sort, ascending, content

Expand Down Expand Up @@ -216,7 +208,7 @@ def _get_season_episode_data(self, api_url, show_seasons, all_items=True):
episodes += page_json.get('results', [{}])
return dict(episodes=episodes), None

def _map_to_episode_items(self, episodes, titletype=None, season_key=None, use_favorites=False):
def _map_to_episode_items(self, episodes, titletype=None, season=None, use_favorites=False):
''' Construct a list of TV show episodes TitleItems based on Search API query and filtered by favorites '''
from datetime import datetime
import dateutil.parser
Expand All @@ -225,15 +217,16 @@ def _map_to_episode_items(self, episodes, titletype=None, season_key=None, use_f
sort = 'episode'
ascending = True
if statichelper.boolean(use_favorites):
favorite_names = self._favorites.names()
programs = self._favorites.programs()
episode_items = []
for episode in episodes:
# VRT API workaround: seasonTitle facet behaves as a partial match regex,
# so we have to filter out the episodes from seasons that don't exactly match.
if season_key and episode.get('seasonTitle') != season_key:
if season and episode.get('seasonTitle') != season:
continue

if statichelper.boolean(use_favorites) and episode.get('programName') not in favorite_names:
program = statichelper.url_to_program(episode.get('programUrl'))
if statichelper.boolean(use_favorites) and program not in programs:
continue

# Support search highlights
Expand Down Expand Up @@ -297,13 +290,12 @@ def _map_to_episode_items(self, episodes, titletype=None, season_key=None, use_f
metadata.plot = '%s\n\n[COLOR yellow]%s[/COLOR]' % (metadata.plot, metadata.permalink)

if self._favorites.is_activated():
program_path = statichelper.unique_path(episode.get('programUrl'))
program = episode.get('program').encode('utf-8')
if self._favorites.is_favorite(program_path):
params = dict(action='unfollow', program=program, path=program_path)
program_title = episode.get('program').encode('utf-8')
if self._favorites.is_favorite(program):
params = dict(action='unfollow', title=program_title, program=program)
context_menu = [(self._kodi.localize(30412), 'RunPlugin(plugin://plugin.video.vrt.nu?%s)' % urlencode(params))]
else:
params = dict(action='follow', program=program, path=program_path)
params = dict(action='follow', title=program_title, program=program)
context_menu = [(self._kodi.localize(30411), 'RunPlugin(plugin://plugin.video.vrt.nu?%s)' % urlencode(params))]
else:
context_menu = []
Expand All @@ -328,7 +320,7 @@ def _map_to_episode_items(self, episodes, titletype=None, season_key=None, use_f

return episode_items, sort, ascending, 'episodes'

def _map_to_season_items(self, api_url, seasons, episodes):
def _map_to_season_items(self, program, seasons, episodes):
''' Construct a list of TV show season TitleItems based on Search API query and filtered by favorites '''
import random

Expand Down Expand Up @@ -366,7 +358,7 @@ def _map_to_season_items(self, api_url, seasons, episodes):
if self._kodi.get_global_setting('videolibrary.showallitems') is True:
season_items.append(TitleItem(
title=self._kodi.localize(30096),
url_dict=dict(action=actions.LISTING_ALL_EPISODES, video_url=api_url),
url_dict=dict(action=actions.LISTING_ALL_EPISODES, program=program),
is_playable=False,
art_dict=dict(thumb=fanart, icon='DefaultSets.png', fanart=fanart),
video_dict=metadata.get_video_dict(),
Expand All @@ -389,11 +381,9 @@ def _map_to_season_items(self, api_url, seasons, episodes):
fanart = 'DefaultSets.png'
thumbnail = 'DefaultSets.png'
label = '%s %s' % (self._kodi.localize(30094), season_key)
params = {'facets[seasonTitle]': season_key}
path = api_url + '&' + urlencode(params)
season_items.append(TitleItem(
title=label,
url_dict=dict(action=actions.LISTING_EPISODES, video_url=path),
url_dict=dict(action=actions.LISTING_EPISODES, program=program, season=season_key),
is_playable=False,
art_dict=dict(thumb=thumbnail, icon='DefaultSets.png', fanart=fanart),
video_dict=metadata.get_video_dict(),
Expand Down
Loading