def get_episode_items(self, date, channel): """Show episodes for a given date and channel""" now = datetime.now(dateutil.tz.tzlocal()) epg = self.parse(date, now) epg_url = epg.strftime(self.VRT_TVGUIDE) self._favorites.refresh(ttl=ttl('indirect')) self._resumepoints.refresh(ttl=ttl('indirect')) cache_file = 'schedule.{date}.json'.format(date=date) if date in ('today', 'yesterday', 'tomorrow'): schedule = get_cached_url_json(url=epg_url, cache=cache_file, ttl=ttl('indirect'), fail={}) else: schedule = get_url_json(url=epg_url, fail={}) entry = find_entry(CHANNELS, 'name', channel) if entry: episodes = schedule.get(entry.get('id'), []) else: episodes = [] episode_items = [] for episode in episodes: program = url_to_program(episode.get('url', '')) if episode.get('url'): video_url = add_https_proto(episode.get('url')) path = url_for('play_url', video_url=video_url) context_menu, favorite_marker, watchlater_marker = self._metadata.get_context_menu( episode, program, cache_file) label = self._metadata.get_label( episode) + favorite_marker + watchlater_marker is_playable = True else: label = '[COLOR={greyedout}]%s[/COLOR]' % self._metadata.get_label( episode) path = url_for('noop') context_menu, _, _ = self._metadata.get_context_menu( episode, program, cache_file) is_playable = False info_labels = self._metadata.get_info_labels(episode, date=date, channel=entry) # FIXME: Due to a bug in Kodi, ListItem.Title is used when Sort methods are used, not ListItem.Label info_labels['title'] = colour(label) episode_items.append( TitleItem( label=colour(label), path=path, art_dict=self._metadata.get_art(episode), info_dict=info_labels, context_menu=context_menu, is_playable=is_playable, )) return episode_items
def show_recent_menu(self, page=0, use_favorites=False): """The VRT NU add-on 'Most recent' and 'My most recent' listing menu""" # My favorites menus may need more up-to-date favorites self._favorites.refresh( ttl=ttl('direct' if use_favorites else 'indirect')) self._resumepoints.refresh( ttl=ttl('direct' if use_favorites else 'indirect')) page = realpage(page) episode_items, sort, ascending, content = self._apihelper.list_episodes( page=page, use_favorites=use_favorites, variety='recent') # Add 'More...' entry at the end if len(episode_items) == get_setting_int('itemsperpage', default=50): recent = 'favorites_recent' if use_favorites else 'recent' episode_items.append( TitleItem( label=colour(localize(30300)), path=url_for(recent, page=page + 1), art_dict=dict(thumb='DefaultRecentlyAddedEpisodes.png'), info_dict=dict(), )) show_listing(episode_items, category=30020, sort=sort, ascending=ascending, content=content, cache=False)
def live_description(self, channel): """Return the EPG information for current and next live program""" now = datetime.now(dateutil.tz.tzlocal()) epg = now # Daily EPG information shows information from 6AM until 6AM if epg.hour < 6: epg += timedelta(days=-1) entry = find_entry(CHANNELS, 'name', channel) if not entry: return '' epg_url = epg.strftime(self.VRT_TVGUIDE) schedule = get_cached_url_json(url=epg_url, cache='schedule.today.json', ttl=ttl('indirect'), fail={}) episodes = iter(schedule.get(entry.get('id'), [])) description = '' episode = None while True: try: episode = next(episodes) except StopIteration: break start_date = dateutil.parser.parse(episode.get('startTime')) end_date = dateutil.parser.parse(episode.get('endTime')) if start_date <= now <= end_date: # Now playing description = '[COLOR={highlighted}][B]%s[/B] %s[/COLOR]\n' % ( localize(30421), self.episode_description(episode)) try: description += '[B]%s[/B] %s' % (localize(30422), self.episode_description( next(episodes))) except StopIteration: break break if now < start_date: # Nothing playing now, but this may be next description = '[B]%s[/B] %s\n' % ( localize(30422), self.episode_description(episode)) try: description += '[B]%s[/B] %s' % (localize(30422), self.episode_description( next(episodes))) except StopIteration: break break if episode and not description: # Add a final 'No transmission' program description = '[COLOR={highlighted}][B]%s[/B] %s - 06:00\n» %s[/COLOR]' % ( localize(30421), episode.get('end'), localize(30423)) return colour(description)
def search(self, keywords=None, page=0, edit=False): """The VRT NU add-on Search functionality and results""" if keywords is None or edit is True: keywords = get_search_string(keywords) if not keywords: end_of_directory() return if edit is True: container_update(url_for('search_query', keywords=keywords)) return from apihelper import ApiHelper from utils import realpage page = realpage(page) self.add(keywords) search_items, sort, ascending, content = ApiHelper(self._favorites, self._resumepoints).list_search(keywords, page=page) if not search_items: ok_dialog(heading=localize(30135), message=localize(30136, keywords=keywords)) end_of_directory() return # Add 'More…' entry at the end from helperobjects import TitleItem if len(search_items) == get_setting_int('itemsperpage', default=50): search_items.append(TitleItem( label=colour(localize(30300)), # More… path=url_for('search_query', keywords=keywords, page=page + 1), art_dict=dict(thumb='DefaultAddonSearch.png'), info_dict={}, )) self._favorites.refresh(ttl=ttl('indirect')) show_listing(search_items, category=30032, sort=sort, ascending=ascending, content=content, cache=False)
def get_episode_items(self, date, channel): """Show episodes for a given date and channel""" now = datetime.now(dateutil.tz.tzlocal()) epg = self.parse(date, now) epg_url = epg.strftime(self.VRT_TVGUIDE) self._favorites.refresh(ttl=ttl('indirect')) self._resumepoints.refresh(ttl=ttl('indirect')) cache_file = 'schedule.{date}.json'.format(date=date) if date in ('today', 'yesterday', 'tomorrow'): schedule = get_cached_url_json(url=epg_url, cache=cache_file, ttl=ttl('indirect'), fail={}) else: schedule = get_url_json(url=epg_url, fail={}) entry = find_entry(CHANNELS, 'name', channel) if entry: episodes = schedule.get(entry.get('id'), []) else: episodes = [] episode_items = [] for episode in episodes: program = url_to_program(episode.get('url', '')) context_menu, favorite_marker, watchlater_marker = self._metadata.get_context_menu( episode, program, cache_file) label = self._metadata.get_label(episode) path = self.get_episode_path(episode, channel) # Playable item if '/play/' in path: is_playable = True label += favorite_marker + watchlater_marker # Non-actionable item else: is_playable = False label = '[COLOR={greyedout}]%s[/COLOR]' % label # Now playing start_date = dateutil.parser.parse(episode.get('startTime')) end_date = dateutil.parser.parse(episode.get('endTime')) if start_date <= now <= end_date: if is_playable: label = '[COLOR={highlighted}]%s[/COLOR] %s' % ( label, localize(30301)) else: label += localize(30301) info_labels = self._metadata.get_info_labels(episode, date=date, channel=entry) # FIXME: Due to a bug in Kodi, ListItem.Title is used when Sort methods are used, not ListItem.Label info_labels['title'] = colour(label) episode_items.append( TitleItem( label=colour(label), path=path, art_dict=self._metadata.get_art(episode), info_dict=info_labels, context_menu=context_menu, is_playable=is_playable, )) return episode_items
def get_label(api_data, titletype=None, return_sort=False): """Get an appropriate label string matching the type of listing and VRT NU provided displayOptions from single item json api data""" # VRT NU Search API if api_data.get('type') == 'episode': display_options = api_data.get('displayOptions', {}) # NOTE: Hard-code showing seasons because it is unreliable (i.e; Thuis or Down the Road have it disabled) display_options['showSeason'] = True program_type = api_data.get('programType') if not titletype: titletype = program_type if display_options.get('showEpisodeTitle'): label = html_to_kodi( api_data.get('title', '') or api_data.get('shortDescription', '')) elif display_options.get('showShortDescription'): label = html_to_kodi( api_data.get('shortDescription', '') or api_data.get('title', '')) else: label = html_to_kodi( api_data.get('title', '') or api_data.get('shortDescription', '')) sort = 'unsorted' ascending = True if titletype in ('continue', 'offline', 'recent', 'watchlater'): ascending = False label = '[B]%s[/B] - %s' % (api_data.get('program'), label) sort = 'dateadded' elif titletype in ('reeksaflopend', 'reeksoplopend'): if titletype == 'reeksaflopend': ascending = False # NOTE: This is disable on purpose as 'showSeason' is not reliable if (display_options.get('showSeason') is False and display_options.get('showEpisodeNumber') and api_data.get('seasonName') and api_data.get('episodeNumber')): try: label = 'S%02dE%02d: %s' % ( int(api_data.get('seasonName')), int(api_data.get('episodeNumber')), label) except ValueError: # Season may not always be a perfect number sort = 'episode' else: sort = 'dateadded' elif display_options.get('showEpisodeNumber') and api_data.get( 'episodeNumber') and ascending: # NOTE: Do not prefix with "Episode X" when sorting by episode # label = '%s %s: %s' % (localize(30132), api_data.get('episodeNumber'), label) sort = 'episode' elif display_options.get('showBroadcastDate') and api_data.get( 'formattedBroadcastShortDate'): label = '%s - %s' % ( api_data.get('formattedBroadcastShortDate'), label) sort = 'dateadded' else: sort = 'dateadded' elif titletype == 'daily': ascending = False label = '%s - %s' % ( api_data.get('formattedBroadcastShortDate'), label) sort = 'dateadded' elif titletype == 'oneoff': label = api_data.get('program', label) sort = 'label' # VRT NU Suggest API elif api_data.get('type') == 'program': label = api_data.get('title', '???') # VRT NU Schedule API (some are missing vrt.whatson-id) elif api_data.get('vrt.whatson-id') or api_data.get('startTime'): title = html_to_kodi( api_data.get('subtitle', '') or api_data.get('shortDescription', '')) label = '{start} - [B]{program}[/B]{title}'.format( start=api_data.get('start'), program=api_data.get('title'), title=' - ' + title if title else '', ) # Not Found else: label = '' if return_sort: return colour(label), sort, ascending return colour(label)
def get_context_menu(self, api_data, program, cache_file): """Get context menu""" from addon import plugin favorite_marker = '' watchlater_marker = '' context_menu = [] # WATCH LATER if self._resumepoints.is_activated(): asset_id = self.get_asset_id(api_data) # VRT NU Search API if api_data.get('type') == 'episode': program_title = api_data.get('program') # VRT NU Schedule API (some are missing vrt.whatson-id) elif api_data.get('vrt.whatson-id') or api_data.get('startTime'): program_title = api_data.get('title') if asset_id is not None: # We need to ensure forward slashes are quoted program_title = to_unicode( quote_plus(from_unicode(program_title))) url = url_to_episode(api_data.get('url', '')) if self._resumepoints.is_watchlater(asset_id): extras = {} # If we are in a watchlater menu, move cursor down before removing a favorite if plugin.path.startswith('/resumepoints/watchlater'): extras = dict(move_down=True) # Unwatch context menu context_menu.append( (capitalize(localize(30402)), 'RunPlugin(%s)' % url_for('unwatchlater', asset_id=asset_id, title=program_title, url=url, **extras))) watchlater_marker = '[COLOR={highlighted}]ᶫ[/COLOR]' else: # Watch context menu context_menu.append( (capitalize(localize(30401)), 'RunPlugin(%s)' % url_for('watchlater', asset_id=asset_id, title=program_title, url=url))) # FOLLOW PROGRAM if self._favorites.is_activated(): # VRT NU Search API if api_data.get('type') == 'episode': program_title = api_data.get('program') program_type = api_data.get('programType') follow_suffix = localize( 30410) if program_type != 'oneoff' else '' # program follow_enabled = True # VRT NU Suggest API elif api_data.get('type') == 'program': program_title = api_data.get('title') follow_suffix = '' follow_enabled = True # VRT NU Schedule API (some are missing vrt.whatson-id) elif api_data.get('vrt.whatson-id') or api_data.get('startTime'): program_title = api_data.get('title') follow_suffix = localize(30410) # program follow_enabled = bool(api_data.get('url')) if follow_enabled and program: program_title = to_unicode( quote_plus(from_unicode(program_title)) ) # We need to ensure forward slashes are quoted if self._favorites.is_favorite(program): extras = {} # If we are in a favorites menu, move cursor down before removing a favorite if plugin.path.startswith('/favorites'): extras = dict(move_down=True) context_menu.append(( localize(30412, title=follow_suffix), # Unfollow 'RunPlugin(%s)' % url_for('unfollow', program=program, title=program_title, **extras))) favorite_marker = '[COLOR={highlighted}]ᵛ[/COLOR]' else: context_menu.append(( localize(30411, title=follow_suffix), # Follow 'RunPlugin(%s)' % url_for( 'follow', program=program, title=program_title))) # GO TO PROGRAM if api_data.get('programType') != 'oneoff' and program: if plugin.path.startswith( ('/favorites/offline', '/favorites/recent', '/offline', '/recent', '/resumepoints/continue', '/resumepoints/watchlater', '/tvguide')): context_menu.append(( localize(30417), # Go to program 'Container.Update(%s)' % url_for('programs', program=program, season='allseasons'))) # REFRESH MENU context_menu.append(( localize(30413), # Refresh menu 'RunPlugin(%s)' % url_for('delete_cache', cache_file=cache_file))) return context_menu, colour(favorite_marker), colour(watchlater_marker)
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 is not False: plot = html_to_kodi(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 colour(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 # Add product placement if api_data.get('productPlacement') is True: if plot_meta: plot_meta += ' ' plot_meta += '[B]PP[/B]' # Add film rating rating = self.get_mpaa(api_data) if rating: if plot_meta: plot_meta += ' ' plot_meta += '[B]%s[/B]' % rating plot = html_to_kodi(api_data.get('description', '')) if plot_meta: plot = '%s\n\n%s' % (plot_meta, plot) permalink = shorten_link( api_data.get('permalink')) or api_data.get('externalPermalink') if permalink and get_setting_bool('showpermalink', default=False): plot = '%s\n\n[COLOR={highlighted}]%s[/COLOR]' % (plot, permalink) return colour(plot) # VRT NU Suggest API if api_data.get('type') == 'program': plot = unescape(api_data.get('description', '???')) # permalink = shorten_link(api_data.get('programUrl')) # if permalink and get_setting_bool('showpermalink', default=False): # plot = '%s\n\n[COLOR={highlighted}]%s[/COLOR]' % (plot, permalink) return colour(plot) # VRT NU Schedule API (some are missing vrt.whatson-id) if api_data.get('vrt.whatson-id') or api_data.get('startTime'): now = datetime.now(dateutil.tz.tzlocal()) epg = self.parse(date, now) plot = '[B]{datelong}[/B]\n{start} - {end}\n\n{description}'.format( datelong=localize_datelong(epg), start=api_data.get('start'), end=api_data.get('end'), description=html_to_kodi(api_data.get('description', '')), ) return colour(plot) # Not Found return ''