def show_favorites_menu(self): ''' The VRT NU addon 'My programs' menu ''' self._favorites.refresh(ttl=60 * 60) favorites_items = [ TitleItem( title=localize(30040), # My programs path=url_for('favorites_programs'), art_dict=dict(thumb='DefaultMovieTitle.png'), info_dict=dict(plot=localize(30041))), TitleItem( title=localize(30046), # My recent items path=url_for('favorites_recent'), art_dict=dict(thumb='DefaultRecentlyAddedEpisodes.png'), info_dict=dict(plot=localize(30047))), TitleItem( title=localize(30048), # My soon offline path=url_for('favorites_offline'), art_dict=dict(thumb='DefaultYear.png'), info_dict=dict(plot=localize(30049))), ] # Only add 'My watch later' and 'Continue watching' when it has been activated if self._resumepoints.is_activated(): favorites_items.append( TitleItem( title=localize(30050), # My watch later path=url_for('resumepoints_watchlater'), art_dict=dict(thumb='DefaultVideoPlaylists.png'), info_dict=dict(plot=localize(30051)), )) favorites_items.append( TitleItem( title=localize(30052), # Continue Watching path=url_for('resumepoints_continue'), art_dict=dict(thumb='DefaultInProgressShows.png'), info_dict=dict(plot=localize(30053)), )) if get_setting('addmymovies', 'true') == 'true': favorites_items.append( TitleItem( title=localize(30042), # My movies path=url_for('categories', category='films'), art_dict=dict(thumb='DefaultAddonVideo.png'), info_dict=dict(plot=localize(30043))), ) if get_setting('addmydocu', 'true') == 'true': favorites_items.append( TitleItem( title=localize(30044), # My documentaries path=url_for('favorites_docu'), art_dict=dict(thumb='DefaultMovies.png'), info_dict=dict(plot=localize(30045))), ) show_listing(favorites_items, category=30010, cache=False) # My favorites # Show dialog when no favorites were found if not self._favorites.titles(): ok_dialog(heading=localize(30415), message=localize(30416))
def get_art(api_data, season=False): ''' Get art dict from single item json api data ''' art_dict = dict() # VRT NU Search API if api_data.get('type') == 'episode': if season: if get_setting('showfanart', 'true') == 'true': art_dict['fanart'] = statichelper.add_https_method( api_data.get('programImageUrl', 'DefaultSets.png')) art_dict['banner'] = art_dict.get('fanart') if season != 'allseasons': art_dict['thumb'] = statichelper.add_https_method( api_data.get('videoThumbnailUrl', art_dict.get('fanart'))) else: art_dict['thumb'] = art_dict.get('fanart') else: art_dict['thumb'] = 'DefaultSets.png' else: if get_setting('showfanart', 'true') == 'true': art_dict['thumb'] = statichelper.add_https_method( api_data.get('videoThumbnailUrl', 'DefaultAddonVideo.png')) art_dict['fanart'] = statichelper.add_https_method( api_data.get('programImageUrl', art_dict.get('thumb'))) art_dict['banner'] = art_dict.get('fanart') else: art_dict['thumb'] = 'DefaultAddonVideo.png' return art_dict # VRT NU Suggest API if api_data.get('type') == 'program': if get_setting('showfanart', 'true') == 'true': art_dict['thumb'] = statichelper.add_https_method( api_data.get('thumbnail', 'DefaultAddonVideo.png')) art_dict['fanart'] = art_dict.get('thumb') art_dict['banner'] = art_dict.get('fanart') else: art_dict['thumb'] = 'DefaultAddonVideo.png' return art_dict # VRT NU Schedule API (some are missing vrt.whatson-id) if api_data.get('vrt.whatson-id') or api_data.get('startTime'): if get_setting('showfanart', 'true') == 'true': art_dict['thumb'] = api_data.get('image', 'DefaultAddonVideo.png') art_dict['fanart'] = art_dict.get('thumb') art_dict['banner'] = art_dict.get('fanart') else: art_dict['thumb'] = 'DefaultAddonVideo.png' return art_dict # Not Found return art_dict
def _get_login_json(self): """Get login json""" payload = dict( loginID=from_unicode(get_setting('username')), password=from_unicode(get_setting('password')), sessionExpiration='-2', APIKey=self._API_KEY, targetEnv='jssdk', ) data = urlencode(payload).encode() return get_url_json(self._LOGIN_URL, data=data, fail={})
def _credentials_changed(): """Check if credentials have changed""" old_hash = get_setting('credentials_hash') username = get_setting('username') password = get_setting('password') new_hash = '' if username or password: from hashlib import md5 new_hash = md5((username + password).encode('utf-8')).hexdigest() if new_hash != old_hash: set_setting('credentials_hash', new_hash) return True return False
def _get_login_json(self): ''' Get login json ''' from json import load payload = dict( loginID=from_unicode(get_setting('username')), password=from_unicode(get_setting('password')), sessionExpiration='-1', APIKey=self._API_KEY, targetEnv='jssdk', ) data = urlencode(payload).encode() log(2, 'URL post: {url}', url=unquote(self._LOGIN_URL)) req = Request(self._LOGIN_URL, data=data) login_json = load(urlopen(req)) return login_json
def _get_xvrttoken(self, login_json=None): """Get a one year valid X-VRT-Token""" from json import dumps if not login_json: login_json = self._get_login_json() login_token = login_json.get('sessionInfo', {}).get('login_token') if not login_token: return None login_cookie = 'glt_{api_key}={token}'.format(api_key=self._API_KEY, token=login_token) payload = dict(uid=login_json.get('UID'), uidsig=login_json.get('UIDSignature'), ts=login_json.get('signatureTimestamp'), email=from_unicode(get_setting('username'))) data = dumps(payload).encode() headers = {'Content-Type': 'application/json', 'Cookie': login_cookie} response = open_url(self._TOKEN_GATEWAY_URL, data=data, headers=headers) if response is None: return None setcookie_header = response.info().get('Set-Cookie') xvrttoken = TokenResolver._create_token_dictionary(setcookie_header) if xvrttoken is None: return None notification(message=localize(30952)) # Login succeeded. return xvrttoken
def getChannelUrl(channel_id): global raw qmap = {'auto': '', 'low': '_LOW', 'medium': '_MED', 'high': '_HIG'} quality = kodiutils.get_setting('quality').lower() url = raw[str(channel_id)]['url'] token_params = _hotstarauth_key() if 'hotstar' in url else getTokenParams() return url.format(token=token_params, q=qmap[quality])
def _get_new_xvrttoken(self, login_json, token_variant=None): """Get new X-VRT-Token from VRT NU website""" if token_variant == 'roaming': xvrttoken = self._get_roaming_xvrttoken() else: login_token = login_json.get('sessionInfo', {}).get('login_token') if not login_token: return None from json import dumps login_cookie = 'glt_{api_key}={token}'.format(api_key=self._API_KEY, token=login_token) payload = dict( uid=login_json.get('UID'), uidsig=login_json.get('UIDSignature'), ts=login_json.get('signatureTimestamp'), email=from_unicode(get_setting('username')), ) data = dumps(payload).encode() headers = {'Content-Type': 'application/json', 'Cookie': login_cookie} log(2, 'URL post: {url}', url=unquote(self._TOKEN_GATEWAY_URL)) req = Request(self._TOKEN_GATEWAY_URL, data=data, headers=headers) try: # Python 3 setcookie_header = urlopen(req).info().get('Set-Cookie') except AttributeError: # Python 2 setcookie_header = urlopen(req).info().getheader('Set-Cookie') xvrttoken = TokenResolver._create_token_dictionary(setcookie_header) if xvrttoken is None: return None self._set_cached_token(xvrttoken, token_variant) notification(message=localize(30952)) # Login succeeded. return xvrttoken.get('X-VRT-Token')
def check_login(): username = kodiutils.get_setting('username') password = kodiutils.get_setting('password') if os.path.isfile(ADDONDATA + 'headers.json'): return True elif username and password and not os.path.isfile(ADDONDATA + 'headers.json'): login(username, password) return True else: kodiutils.notification( 'Login Error', 'You need to login with Jio Username and password to use this plugin' ) kodiutils.show_settings() return False
def check_login(): username = kodiutils.get_setting('username') password = kodiutils.get_setting('password') # token is 5 days old ? if os.path.isfile(TOKEN_FILE_PATH) and time.time( ) < os.path.getmtime(TOKEN_FILE_PATH) + 432000000: return True elif username and password: login(username, password) return True else: kodiutils.notification( 'Login Error', 'You need to login with Jio Username and password to use this add-on' ) kodiutils.show_settings() return False
def push_upnext(self, info): ''' Push episode info to Up Next service add-on''' if has_addon('service.upnext') and get_setting('useupnext', 'true') == 'true': next_info = self._apihelper.get_upnext(info) if next_info: from binascii import hexlify from json import dumps data = [to_unicode(hexlify(dumps(next_info).encode()))] sender = '%s.SIGNAL' % addon_id() notify(sender=sender, message='upnext_data', data=data)
def get_images(self, override=False): # Read google images from json file self.images = [] if kodiutils.get_setting_as_int( "screensaver-mode") == 0 or kodiutils.get_setting_as_int( "screensaver-mode") == 2 or override: with open(IMAGE_FILE, "r") as f: images = f.read() self.images = json.loads(images) # Check if we have images to append if kodiutils.get_setting_as_int( "screensaver-mode") == 1 or kodiutils.get_setting_as_int( "screensaver-mode") == 2 and not override: if kodiutils.get_setting("my-pictures-folder") and xbmcvfs.exists( xbmc.translatePath( kodiutils.get_setting("my-pictures-folder"))): for image in screensaverutils.get_own_pictures( kodiutils.get_setting("my-pictures-folder")): self.images.append(image) else: return self.get_images(override=True) shuffle(self.images) return
def list_tvshows(self, category=None, channel=None, feature=None, use_favorites=False): ''' List all TV shows for a given category, channel or feature, optionally filtered by favorites ''' # Get tvshows tvshows = self.get_tvshows(category=category, channel=channel, feature=feature) # Get oneoffs if get_setting('showoneoff', 'true') == 'true': cache_file = 'oneoff.json' oneoffs = self.get_episodes(variety='oneoff', cache_file=cache_file) else: # Return empty list oneoffs = [] return self.__map_tvshows(tvshows, oneoffs, use_favorites=use_favorites, cache_file=cache_file)
def set_property(self): if "estuary" in xbmc.getSkinDir(): self.setProperty("clockfont", "fontclock") else: self.setProperty("clockfont", "fontmainmenu") # Set skin properties as settings for setting in [ "hide-clock-info", "hide-kodi-logo", "hide-weather-info", "hide-pic-info" ]: self.setProperty(setting, kodiutils.get_setting(setting)) # Set animations if kodiutils.get_setting_as_int("animation") == 1: self.setProperty("animation", "panzoom") return
def _handle_bad_stream_error(protocol, code=None, reason=None): ''' Show a localized error message in Kodi GUI for a failing VRT NU stream based on protocol: hls, hls_aes, mpeg_dash) message: VRT NU stream <stream_type> problem, try again with (InputStream Adaptive) (and) (DRM) enabled/disabled: 30959=and DRM, 30960=disabled, 30961=enabled ''' # HLS AES DRM failed if protocol == 'hls_aes' and not supports_drm(): message = localize(30962, protocol=protocol.upper(), version=kodi_version()) elif protocol == 'hls_aes' and not has_inputstream_adaptive( ) and get_setting('usedrm', 'true') == 'false': message = localize(30958, protocol=protocol.upper(), component=localize(30959), state=localize(30961)) elif protocol == 'hls_aes' and has_inputstream_adaptive(): message = localize(30958, protocol=protocol.upper(), component='Widevine DRM', state=localize(30961)) elif protocol == 'hls_aes' and get_setting('usedrm', 'true') == 'true': message = localize(30958, protocol=protocol.upper(), component='InputStream Adaptive', state=localize(30961)) else: message = localize(30958, protocol=protocol.upper(), component='InputStream Adaptive', state=localize(30960)) heading = 'HTTP Error %s: %s' % (code, reason) if code and reason else None log_error('Unable to play stream. {error}', error=heading) ok_dialog(heading=heading, message=message) end_of_directory()
def list_youtube(channels=None): ''' Construct a list of youtube ListItems, either for Live TV or the TV Guide listing ''' youtube_items = [] if not has_addon('plugin.video.youtube') or get_setting('showyoutube', 'true') == 'false': return youtube_items for channel in CHANNELS: if channels and channel.get('name') not in channels: continue context_menu = [] art_dict = dict() # Try to use the white icons for thumbnails (used for icons as well) if has_addon('resource.images.studios.white'): art_dict['thumb'] = 'resource://resource.images.studios.white/{studio}.png'.format(**channel) else: art_dict['thumb'] = 'DefaultTags.png' if channel.get('youtube'): path = channel.get('youtube') label = localize(30143, **channel) # Channel on YouTube # 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 = '[B]%s[/B]' % label plot = localize(30144, **channel) # Watch on YouTube # NOTE: Playcount is required to not have live streams as "Watched" info_dict = dict(title=label, plot=plot, studio=channel.get('studio'), mediatype='video', playcount=0) context_menu.append(( localize(30413), 'RunPlugin(%s)' % url_for('delete_cache', cache_file='channel.%s.json' % channel) )) else: # Not a playable channel continue youtube_items.append(TitleItem( title=label, path=path, art_dict=art_dict, info_dict=info_dict, context_menu=context_menu, is_playable=False, )) return youtube_items
def _first_run(): '''Check if this add-on version is run for the first time''' # Get version from settings.xml settings_version = get_setting('version', default='') # Get version from addon.xml addon_version = get_addon_info('version') # Compare versions (settings_version was not present in version 1.10.0 and older) settings_comp = tuple(map(int, settings_version.split('+')[0].split('.'))) if settings_version != '' else (1, 10, 0) addon_comp = tuple(map(int, addon_version.split('+')[0].split('.'))) if addon_comp > settings_comp: # New version found, save addon version to settings set_setting('version', addon_version) return True, settings_version, addon_version return False, settings_version, addon_version
def _version_check(self): first_run, settings_version, addon_version = self._first_run() if first_run: # 2.2.3 version: max_log_level to be an integer try: int(get_setting('max_log_level', 0)) # May return string except ValueError: set_setting('max_log_level', 0) # 2.0.0 version: changed plugin:// url interface: show warning that Kodi favourites and what-was-watched will break if settings_version == '' and has_credentials(): ok_dialog(localize(30978), localize(30979)) if addon_version == '2.2.1': # 2.2.1 version: changed artwork: delete old cached artwork delete_cached_thumbnail( get_addon_info('fanart').replace('.png', '.jpg')) delete_cached_thumbnail(get_addon_info('icon')) # 2.2.1 version: moved tokens: delete old tokens from tokenresolver import TokenResolver TokenResolver().delete_tokens()
def emit(self, record): """ Emit a log message """ levels = { logging.CRITICAL: xbmc.LOGFATAL, logging.ERROR: xbmc.LOGERROR, logging.WARNING: xbmc.LOGWARNING, logging.INFO: xbmc.LOGNOTICE, logging.DEBUG: xbmc.LOGDEBUG, logging.NOTSET: xbmc.LOGNONE, } # Map DEBUG level to LOGNOTICE if debug logging setting has been activated # This is for troubleshooting only if get_setting('debug_logging') == 'true': levels[logging.DEBUG] = xbmc.LOGNOTICE try: xbmc.log(self.format(record), levels[record.levelno]) except UnicodeEncodeError: xbmc.log( self.format(record).encode('utf-8', 'ignore'), levels[record.levelno])
def list_categories(self): ''' Construct a list of category ListItems ''' categories = [] # Try the cache if it is fresh categories = get_cache('categories.json', ttl=7 * 24 * 60 * 60) # Try to scrape from the web if not categories: try: categories = self.get_categories() except Exception: # pylint: disable=broad-except categories = [] else: update_cache('categories.json', categories) # Use the cache anyway (better than hard-coded) if not categories: categories = get_cache('categories.json', ttl=None) # Fall back to internal hard-coded categories if all else fails from data import CATEGORIES if not categories: categories = CATEGORIES category_items = [] for category in self.localize_categories(categories, CATEGORIES): if get_setting('showfanart', 'true') == 'true': thumbnail = category.get('thumbnail', 'DefaultGenre.png') else: thumbnail = 'DefaultGenre.png' category_items.append(TitleItem( title=category.get('name'), path=url_for('categories', category=category.get('id')), art_dict=dict(thumb=thumbnail, icon='DefaultGenre.png'), info_dict=dict(plot='[B]%s[/B]' % category.get('name'), studio='VRT'), )) return category_items
# -*- coding: utf-8 -*- import requests import kodiutils import addonutils import xbmc import math import re import xbmcaddon from xbmcgui import ListItem CHANNEL_ID = kodiutils.get_setting("channel_id") YOUTUBE_API_KEY = kodiutils.get_setting("api_key") TVSHOWTITLE = "It's a Pixel THING" CAST = [TVSHOWTITLE] STATUS = 'in production' def get_playlists(): api_endpoint = 'https://www.googleapis.com/youtube/v3/playlists?part=snippet,contentDetails&channelId=%s&maxResults=50&key=%s' % (CHANNEL_ID,YOUTUBE_API_KEY) try: resp = requests.get(api_endpoint).json() except ValueError: kodiutils.log(kodiutils.get_string(32003), xbmc.LOGERROR) if "items" in resp.keys(): for playlist in resp["items"]: liz = ListItem(playlist["snippet"]["title"]) infolabels = {"plot": playlist["snippet"]["localized"]["description"]} liz.setInfo(type="video", infoLabels=infolabels) liz.setArt({"thumb": playlist["snippet"]["thumbnails"]["high"]["url"], "fanart": xbmcaddon.Addon().getAddonInfo("fanart")}) liz.setProperty("type","playlist") liz.setProperty("playlist_id", playlist["id"])
def get_category_thumbnail(element): ''' Return a category thumbnail, if available ''' if get_setting('showfanart', 'true') == 'true': raw_thumbnail = element.find(class_='media').get('data-responsive-image', 'DefaultGenre.png') return statichelper.add_https_method(raw_thumbnail) return 'DefaultGenre.png'
def get_plot(self, api_data, season=False, date=None): ''' Get plot string from single item json api data ''' from datetime import datetime import dateutil.parser import dateutil.tz # VRT NU Search API if api_data.get('type') == 'episode': if season: plot = statichelper.convert_html_to_kodilabel( api_data.get('programDescription')) # Add additional metadata to plot plot_meta = '' if api_data.get('allowedRegion') == 'BE': plot_meta += localize(30201) + '\n\n' # Geo-blocked plot = '%s[B]%s[/B]\n%s' % (plot_meta, api_data.get('program'), plot) return plot # Add additional metadata to plot plot_meta = '' # Only display when a video disappears if it is within the next 3 months if api_data.get('assetOffTime'): offtime = dateutil.parser.parse(api_data.get('assetOffTime')) # Show the remaining days/hours the episode is still available if offtime: now = datetime.now(dateutil.tz.tzlocal()) remaining = offtime - now if remaining.days / 365 > 5: pass # If it is available for more than 5 years, do not show elif remaining.days / 365 > 2: plot_meta += localize( 30202, years=int(remaining.days / 365)) # X years remaining elif remaining.days / 30.5 > 3: plot_meta += localize( 30203, months=int(remaining.days / 30.5)) # X months remaining elif remaining.days > 1: plot_meta += localize( 30204, days=remaining.days) # X days to go elif remaining.days == 1: plot_meta += localize(30205) # 1 day to go elif remaining.seconds // 3600 > 1: plot_meta += localize(30206, hours=remaining.seconds // 3600) # X hours to go elif remaining.seconds // 3600 == 1: plot_meta += localize(30207) # 1 hour to go else: plot_meta += localize(30208, minutes=remaining.seconds // 60) # X minutes to go if api_data.get('allowedRegion') == 'BE': if plot_meta: plot_meta += ' ' plot_meta += localize(30201) # Geo-blocked plot = statichelper.convert_html_to_kodilabel( api_data.get('description')) if plot_meta: plot = '%s\n\n%s' % (plot_meta, plot) permalink = statichelper.shorten_link( api_data.get('permalink')) or api_data.get('externalPermalink') if permalink and get_setting('showpermalink', 'false') == 'true': plot = '%s\n\n[COLOR yellow]%s[/COLOR]' % (plot, permalink) return plot # VRT NU Suggest API if api_data.get('type') == 'program': plot = statichelper.unescape(api_data.get('description', '???')) # permalink = statichelper.shorten_link(api_data.get('programUrl')) # if permalink and get_setting('showpermalink', 'false') == 'true': # plot = '%s\n\n[COLOR yellow]%s[/COLOR]' % (plot, permalink) return plot # VRT NU Schedule API (some are missing vrt.whatson-id) if api_data.get('vrt.whatson-id') or api_data.get('startTime'): title = api_data.get('title') now = datetime.now(dateutil.tz.tzlocal()) epg = self.parse(date, now) datelong = localize_datelong(epg) start = api_data.get('start') end = api_data.get('end') plot = '[B]%s[/B]\n%s\n%s - %s' % (title, datelong, start, end) return plot # Not Found return ''
# -*- coding: utf-8 -*- import requests import kodiutils import addonutils import xbmc import math import re import sys import xbmcaddon from xbmcgui import ListItem CHANNEL_ID = kodiutils.get_setting("channel_id") YOUTUBE_API_KEY = kodiutils.get_setting("api_key") TVSHOWTITLE = kodiutils.get_setting("tvshow_title") CAST = [TVSHOWTITLE] STATUS = 'in production' def get_live_videos(): api_endpoint = 'https://www.googleapis.com/youtube/v3/search?eventType=live&part=snippet&channelId=%s&type=video&maxResults=50&key=%s' % ( CHANNEL_ID, YOUTUBE_API_KEY) try: resp = requests.get(api_endpoint).json() except ValueError: kodiutils.log(kodiutils.get_string(32009), xbmc.LOGERROR) sys.exit(0) if "items" in resp.keys(): for item in resp["items"]: yield { "label": item["snippet"]["title"], "video_id": item["id"]["videoId"]
def list_channels(self, channels=None, live=True): ''' Construct a list of channel ListItems, either for Live TV or the TV Guide listing ''' from tvguide import TVGuide _tvguide = TVGuide() channel_items = [] for channel in CHANNELS: if channels and channel.get('name') not in channels: continue context_menu = [] art_dict = dict() # Try to use the white icons for thumbnails (used for icons as well) if has_addon('resource.images.studios.white'): art_dict['thumb'] = 'resource://resource.images.studios.white/{studio}.png'.format(**channel) else: art_dict['thumb'] = 'DefaultTags.png' if not live: path = url_for('channels', channel=channel.get('name')) label = channel.get('label') plot = '[B]%s[/B]' % channel.get('label') is_playable = False info_dict = dict(title=label, plot=plot, studio=channel.get('studio'), mediatype='video') stream_dict = [] elif channel.get('live_stream') or channel.get('live_stream_id'): if channel.get('live_stream_id'): path = url_for('play_id', video_id=channel.get('live_stream_id')) elif channel.get('live_stream'): path = url_for('play_url', video_url=channel.get('live_stream')) label = localize(30141, **channel) # Channel live playing_now = _tvguide.playing_now(channel.get('name')) if playing_now: label += ' [COLOR yellow]| %s[/COLOR]' % playing_now # 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 = '[B]%s[/B]' % label is_playable = True if channel.get('name') in ['een', 'canvas', 'ketnet']: if get_setting('showfanart', 'true') == 'true': art_dict['fanart'] = self.get_live_screenshot(channel.get('name', art_dict.get('fanart'))) plot = '%s\n\n%s' % (localize(30142, **channel), _tvguide.live_description(channel.get('name'))) else: plot = localize(30142, **channel) # Watch live # NOTE: Playcount is required to not have live streams as "Watched" info_dict = dict(title=label, plot=plot, studio=channel.get('studio'), mediatype='video', playcount=0, duration=0) stream_dict = dict(duration=0) context_menu.append(( localize(30413), 'RunPlugin(%s)' % url_for('delete_cache', cache_file='channel.%s.json' % channel) )) else: # Not a playable channel continue channel_items.append(TitleItem( title=label, path=path, art_dict=art_dict, info_dict=info_dict, stream_dict=stream_dict, context_menu=context_menu, is_playable=is_playable, )) return channel_items
def get_episodes(self, program=None, season=None, episodes=None, category=None, feature=None, programtype=None, keywords=None, whatson_id=None, video_id=None, video_url=None, page=None, use_favorites=False, variety=None, cache_file=None): ''' Get episodes or season data from VRT NU Search API ''' # Contruct params if page: page = statichelper.realpage(page) all_items = False params = { 'from': ((page - 1) * 50) + 1, 'i': 'video', 'size': 50, } elif variety == 'single': all_items = False params = { 'i': 'video', 'size': '1', } else: all_items = True params = { 'i': 'video', 'size': '300', } if variety: season = 'allseasons' if variety == 'offline': from datetime import datetime import dateutil.tz params['facets[assetOffTime]'] = datetime.now(dateutil.tz.gettz('Europe/Brussels')).strftime('%Y-%m-%d') if variety == 'oneoff': params['facets[programType]'] = 'oneoff' if variety == 'watchlater': self._resumepoints.refresh(ttl=5 * 60) episode_urls = self._resumepoints.watchlater_urls() params['facets[url]'] = '[%s]' % (','.join(episode_urls)) if variety == 'continue': self._resumepoints.refresh(ttl=5 * 60) episode_urls = self._resumepoints.resumepoints_urls() params['facets[url]'] = '[%s]' % (','.join(episode_urls)) if use_favorites: program_urls = [statichelper.program_to_url(p, 'medium') for p in self._favorites.programs()] params['facets[programUrl]'] = '[%s]' % (','.join(program_urls)) elif variety in ('offline', 'recent'): channel_filter = [channel.get('name') for channel in CHANNELS if get_setting(channel.get('name'), 'true') == 'true'] params['facets[programBrands]'] = '[%s]' % (','.join(channel_filter)) if program: params['facets[programUrl]'] = statichelper.program_to_url(program, 'medium') if season and season != 'allseasons': params['facets[seasonTitle]'] = season if episodes: params['facets[episodeNumber]'] = '[%s]' % (','.join(str(episode) for episode in episodes)) if category: params['facets[categories]'] = category if feature: params['facets[programTags.title]'] = feature if programtype: params['facets[programType]'] = programtype if keywords: if not season: season = 'allseasons' params['q'] = quote_plus(statichelper.from_unicode(keywords)) params['highlight'] = 'true' if whatson_id: params['facets[whatsonId]'] = whatson_id if video_id: params['facets[videoId]'] = video_id if video_url: params['facets[url]'] = video_url # Construct VRT NU Search API Url and get api data querystring = '&'.join('{}={}'.format(key, value) for key, value in list(params.items())) search_url = self._VRTNU_SEARCH_URL + '?' + querystring.replace(' ', '%20') # Only encode spaces to minimize url length from json import load if cache_file: # Get api data from cache if it is fresh search_json = get_cache(cache_file, ttl=60 * 60) if not search_json: log(2, 'URL get: {url}', url=unquote(search_url)) req = Request(search_url) try: search_json = load(urlopen(req)) except (TypeError, ValueError): # No JSON object could be decoded return [] except HTTPError as exc: url_length = len(req.get_selector()) if exc.code == 413 and url_length > 8192: ok_dialog(heading='HTTP Error 413', message=localize(30967)) log_error('HTTP Error 413: Exceeded maximum url length: ' 'VRT Search API url has a length of {length} characters.', length=url_length) return [] if exc.code == 400 and 7600 <= url_length <= 8192: ok_dialog(heading='HTTP Error 400', message=localize(30967)) log_error('HTTP Error 400: Probably exceeded maximum url length: ' 'VRT Search API url has a length of {length} characters.', length=url_length) return [] raise update_cache(cache_file, search_json) else: log(2, 'URL get: {url}', url=unquote(search_url)) search_json = load(urlopen(search_url)) # Check for multiple seasons seasons = None if 'facets[seasonTitle]' not in unquote(search_url): facets = search_json.get('facets', dict()).get('facets') seasons = next((f.get('buckets', []) for f in facets if f.get('name') == 'seasons' and len(f.get('buckets', [])) > 1), None) episodes = search_json.get('results', [{}]) show_seasons = bool(season != 'allseasons') # Return seasons if show_seasons and seasons: return (seasons, episodes) api_pages = search_json.get('meta').get('pages').get('total') api_page_size = search_json.get('meta').get('pages').get('size') total_results = search_json.get('meta').get('total_results') if all_items and total_results > api_page_size: for api_page in range(1, api_pages): api_page_url = search_url + '&from=' + str(api_page * api_page_size + 1) api_page_json = load(urlopen(api_page_url)) episodes += api_page_json.get('results', [{}]) # Return episodes return episodes
def _select_hls_substreams(self, master_hls_url, protocol): ''' Select HLS substreams to speed up Kodi player start, workaround for slower kodi selection ''' hls_variant_url = None subtitle_url = None hls_audio_id = None hls_subtitle_id = None hls_base_url = master_hls_url.split('.m3u8')[0] log(2, 'URL get: {url}', url=unquote(master_hls_url)) try: hls_playlist = urlopen(master_hls_url).read().decode('utf-8') except HTTPError as exc: if exc.code == 415: self._handle_bad_stream_error(protocol, exc.code, exc.reason) return None raise max_bandwidth = get_max_bandwidth() stream_bandwidth = None # Get hls variant url based on max_bandwith setting import re hls_variant_regex = re.compile( r'#EXT-X-STREAM-INF:[\w\-.,=\"]*?BANDWIDTH=(?P<BANDWIDTH>\d+),' r'[\w\-.,=\"]+\d,(?:AUDIO=\"(?P<AUDIO>[\w\-]+)\",)?(?:SUBTITLES=\"' r'(?P<SUBTITLES>\w+)\",)?[\w\-.,=\"]+?[\r\n](?P<URI>[\w:\/\-.=?&]+)' ) # reverse sort by bandwidth for match in sorted(re.finditer(hls_variant_regex, hls_playlist), key=lambda m: int(m.group('BANDWIDTH')), reverse=True): stream_bandwidth = int(match.group('BANDWIDTH')) // 1000 if max_bandwidth == 0 or stream_bandwidth < max_bandwidth: if match.group('URI').startswith('http'): hls_variant_url = match.group('URI') else: hls_variant_url = hls_base_url + match.group('URI') hls_audio_id = match.group('AUDIO') hls_subtitle_id = match.group('SUBTITLES') break if stream_bandwidth > max_bandwidth and not hls_variant_url: message = localize(30057, max=max_bandwidth, min=stream_bandwidth) ok_dialog(message=message) open_settings() # Get audio url if hls_audio_id: audio_regex = re.compile( r'#EXT-X-MEDIA:TYPE=AUDIO[\w\-=,\.\"\/]+?GROUP-ID=\"' + hls_audio_id + '' r'\"[\w\-=,\.\"\/]+?URI=\"(?P<AUDIO_URI>[\w\-=]+)\.m3u8\"') match_audio = re.search(audio_regex, hls_playlist) if match_audio: hls_variant_url = hls_base_url + match_audio.group( 'AUDIO_URI') + '-' + hls_variant_url.split('-')[-1] # Get subtitle url, works only for on demand streams if get_setting( 'showsubtitles', 'true' ) == 'true' and '/live/' not in master_hls_url and hls_subtitle_id: subtitle_regex = re.compile( r'#EXT-X-MEDIA:TYPE=SUBTITLES[\w\-=,\.\"\/]+?GROUP-ID=\"' + hls_subtitle_id + '' r'\"[\w\-=,\.\"\/]+URI=\"(?P<SUBTITLE_URI>[\w\-=]+)\.m3u8\"') match_subtitle = re.search(subtitle_regex, hls_playlist) if match_subtitle: subtitle_url = hls_base_url + match_subtitle.group( 'SUBTITLE_URI') + '.webvtt' return StreamURLS(hls_variant_url, subtitle_url)
def is_activated(): ''' Is favorites activated in the menu and do we have credentials ? ''' return get_setting('usefavorites') == 'true' and has_credentials()
# -*- coding: utf-8 -*- import requests import kodiutils import addonutils import xbmc import math import re import xbmcaddon from xbmcgui import ListItem CHANNEL_ID = kodiutils.get_setting("channel_id") YOUTUBE_API_KEY = kodiutils.get_setting("api_key") TVSHOWTITLE = "Fitness Blender" CAST = [TVSHOWTITLE] STATUS = 'in production' def get_playlists(): api_endpoint = 'https://www.googleapis.com/youtube/v3/playlists?part=snippet,contentDetails&channelId=%s&maxResults=50&key=%s' % ( CHANNEL_ID, YOUTUBE_API_KEY) try: resp = requests.get(api_endpoint).json() except ValueError: kodiutils.log(kodiutils.get_string(32003), xbmc.LOGERROR) if "items" in resp.keys(): for playlist in resp["items"]: liz = ListItem(playlist["snippet"]["title"]) infolabels = { "plot": playlist["snippet"]["localized"]["description"] } liz.setInfo(type="video", infoLabels=infolabels)
def is_activated(): ''' Is resumepoints activated in the menu and do we have credentials ? ''' return get_setting('useresumepoints') == 'true' and has_credentials()
import xbmc import os try: from sqlite3 import dbapi2 as sqlite xbmc.log("Loading sqlite3 as DB engine", 2) except: from pysqlite2 import dbapi2 as sqlite xbmc.log("Loading pysqlite2 as DB engine", 2) import datetime import requests import json from xbmcgui import ListItem import xbmcaddon import kodiutils API_ENDPOINT = str(kodiutils.get_setting("api_endpoint")) db = sqlite.connect(os.path.dirname(os.path.realpath(__file__)) + '/db.db') db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)]) f = open(os.path.dirname(os.path.realpath(__file__)) + "/../init.sql", "r") sql = f.read() f.close() db.executescript(sql) try: lastTimestamp = db.execute( "select CAST(strftime('%s', updatedAt) as integer) from playlists order by updatedAt desc limit 1" ).fetchone()['updatedAt'] except: lastTimestamp = 0
def build_episode_item(episode, show_fanart=None): #create episode listitem episode_title = episode["name"] if episode["name"] else "None" liz = ListItem(episode["name"]) #infolabels infolabels = { "title": episode["name"] } if "summary" in episode.keys(): infolabels["plot"] = episode["summary"] if "number" in episode.keys() and episode["number"].isdigit(): infolabels["episode"] = int(episode["number"]) if "published" in episode.keys(): try: infolabels["aired"] = episode['published'].rsplit('T')[0] infolabels["date"] = episode['published'].rsplit('T')[0].replace("-",".") infolabels["year"] = int(episode['published'].rsplit('T')[0].split("-")[0]) except: xbmc.log(msg='[Revision3] could not get date information', level=xbmc.LOGERROR) if "show" in episode.keys() and "name" in episode["show"].keys(): infolabels["tvshowtitle"] = episode["show"]["name"] if "duration" in episode.keys() and episode["duration"].isdigit(): infolabels["duration"] = int(episode["duration"]) #Art art = {} if "images" in episode.keys(): if "medium" in episode["images"].keys(): art["thumb"] = episode["images"]["medium"] art["icon"] = episode["images"]["medium"] art["poster"] = episode["images"]["medium"] if show_fanart: art["fanart"] = urllib.unquote(show_fanart) liz.setInfo( type="Video", infoLabels=infolabels) liz.setArt(art) #Videos url = "" if "media" in episode.keys(): media_urls = [] video_info = {} if "hd720p30" in episode["media"].keys(): media_urls.append(episode["media"]["hd720p30"]["url"]) if "large" in episode["media"].keys(): media_urls.append(episode["media"]["large"]["url"]) if "small" in episode["media"].keys(): media_urls.append(episode["media"]["small"]["url"]) #Parse user preference if len(media_urls) > 0: if kodiutils.get_setting_as_int("format") == 0: url = media_urls[0]; video_info['width'] = 1280; video_info['height'] = 720 if kodiutils.get_setting_as_int("format") == 1: url = media_urls[1] if len(media_urls) > 1 else media_urls[-1]; video_info['width'] = 854; video_info['height'] = 480 if kodiutils.get_setting_as_int("format") == 2: url = media_urls[-1]; video_info['width'] = 854; video_info['height'] = 480 #context menu items cm = [] cm.append((kodiutils.get_string(32063), 'XBMC.Action(Info)')) if url: if kodiutils.get_setting_as_bool("download") and kodiutils.get_setting("downloadPath") and xbmcvfs.exists(kodiutils.get_setting("downloadPath")): cm.append((kodiutils.get_string(32062), 'XBMC.RunPlugin(plugin://%s/download/%s/%s)' % (ADDON.getAddonInfo("id"),urllib.quote(episode_title, safe=''),urllib.quote(url, safe='')) )) liz.setPath("plugin://%s/play/%s" % (ADDON.getAddonInfo("id"),urllib.quote(url, safe='')) ) liz.setProperty('IsPlayable', 'true') liz.addStreamInfo('video', video_info) liz.addContextMenuItems(cm, replaceItems=False) return liz else: return None