def get_calendar_episodes(self, startdate=0, days=1, limit=25): items = [] if not self.tmdb or not self.authorize(): return items date = datetime.date.today() + datetime.timedelta(days=startdate) response = self.get_calendar('shows', True, start_date=date.strftime('%Y-%m-%d'), days=days) if not response: return items for i in response[-limit:]: episode = i.get('episode', {}).get('number') season = i.get('episode', {}).get('season') tmdb_id = i.get('show', {}).get('ids', {}).get('tmdb') item = ListItem(library=self.library, **self.tmdb.get_detailed_item(itemtype='tv', tmdb_id=tmdb_id, season=season, episode=episode)) item.tmdb_id, item.season, item.episode = tmdb_id, season, episode item = self.get_calendar_properties(item, i) items.append(item) return items
def get_calendar_episodes(self, startdate=0, days=1, limit=25): items = [] if not self.tmdb or not self.authorize(): return items mod_date = startdate - 1 mod_days = days + 2 # Broaden date range in case utc conversion bumps into different day date = datetime.date.today() + datetime.timedelta(days=mod_date) response = self.get_calendar('shows', True, start_date=date.strftime('%Y-%m-%d'), days=mod_days) if not response: return items traktitems = reversed(response) if startdate < -1 else response # Reverse items for date ranges in past count = 0 for i in traktitems: if not utils.date_in_range(i.get('first_aired'), utc_convert=True, start_date=startdate, days=days): continue # Don't add items that aren't in our timezone converted range if count >= limit: break # Only add the limit episode = i.get('episode', {}).get('number') season = i.get('episode', {}).get('season') tmdb_id = i.get('show', {}).get('ids', {}).get('tmdb') item = ListItem(library=self.library, **self.tmdb.get_detailed_item( itemtype='tv', tmdb_id=tmdb_id, season=season, episode=episode)) item.tmdb_id, item.season, item.episode = tmdb_id, season, episode item = self.get_calendar_properties(item, i) items.append(item) count += 1 return items
def get_collection(self, tmdbtype, page=1, limit=20): items = [] if not self.tmdb or not self.authorize(): return items collection = self.sync_collection(utils.type_convert( tmdbtype, 'trakt')) collection = sorted( collection, key=lambda i: i[utils.type_convert(tmdbtype, 'trakt')]['title'], reverse=False) start_at = limit * (page - 1) end_at = start_at + limit for i in collection[start_at:end_at]: i = i.get(utils.type_convert(tmdbtype, 'trakt')) i_tmdb = i.get('ids', {}).get('tmdb', '') item = ListItem(library=self.library, **self.tmdb.get_detailed_item(tmdbtype, i_tmdb)) if item and item.label != 'N/A': items.append(item) if items and collection[ end_at:]: # If there's more items add the next page item items.append( ListItem(library=self.library, label=xbmc.getLocalizedString(33078), nextpage=page + 1)) return items
def get_limitedlist(self, itemlist, tmdbtype, limit, islistitem): items, added_items = [], [] if not self.tmdb or not self.authorize(): return items n = 0 itemtype = utils.type_convert(tmdbtype, 'trakt') for i in itemlist: if limit and n >= limit: break item = ( i.get(itemtype, {}).get('ids', {}).get('slug'), i.get(itemtype, {}).get('ids', {}).get('tmdb'), i.get(itemtype, {}).get('title')) if item in added_items: continue added_items.append(item) if islistitem: item = ListItem(library=self.library, **self.tmdb.get_detailed_item(tmdbtype, item[1])) items.append(item) n += 1 return items
def play_external(self, playerindex=-1, force_dialog=False): playerindex = self.player_getnewindex(playerindex, force_dialog=force_dialog) # User cancelled dialog if not playerindex > -1: utils.kodi_log(u'Player -- User cancelled', 2) return False # Run through player actions player = self.player_resolveurl(self.actions[playerindex]) # Previous player failed so ask user to select a new one if player == -1: return self.play_external(playerindex, force_dialog=force_dialog) # Play/Search found item if player and player[1]: action = string_format_map(player[1], self.item) if player[0] and (action.endswith('.strm') or self.identifierlist[playerindex] == 'play_kodi'): # Action is play and is a strm/local so PlayMedia utils.kodi_log(u'Player -- Found strm or local.\nAttempting PLAYMEDIA({})'.format(action), 1) xbmc.executebuiltin(utils.try_decode_string(u'PlayMedia(\"{0}\")'.format(action))) elif player[0]: # Action is play and not a strm so play with player utils.kodi_log(u'Player -- Found file.\nAttempting to PLAY: {}'.format(action), 2) xbmcgui.Window(10000).setProperty('TMDbHelper.PlayerInfoString', self.playerstring) if self.playerstring else None xbmc.Player().play(action, ListItem(library='video', **self.details).set_listitem()) else: action = u'Container.Update({0})'.format(action) if xbmc.getCondVisibility("Window.IsMedia") else u'ActivateWindow(videos,{0},return)'.format(action) utils.kodi_log(u'Player -- Found folder.\nAttempting to OPEN: {}'.format(action), 2) xbmc.executebuiltin(utils.try_encode_string(utils.try_decode_string(action))) return action
def get_nicelist(self, items): return [ ListItem(library=self.library, **self.get_niceitem(i)) for i in items if not utils.filtered_item(i, self.filter_key, self.filter_value) and not utils.filtered_item(i, self.exclude_key, self.exclude_value, True) ]
def get_upnext_episodes(self, tmdb_id=None, imdb_id=None, limit=10): if not self.tmdb or not self.authorize() or not tmdb_id: return [] if not imdb_id: imdb_id = self.tmdb.get_item_externalid(itemtype='tv', tmdb_id=tmdb_id, external_id='imdb_id') return [ListItem(library=self.library, **self.tmdb.get_detailed_item( itemtype='tv', tmdb_id=tmdb_id, season=i[0], episode=i[1])) for i in self.get_upnext(imdb_id)[:limit]]
def player_dialogselect(self, folder, auto=False): d_items = [] for f in folder: # Skip items without labels as probably not worth playing if not f.get('label') or f.get('label') == 'None': continue # Get the label of the item label_a = f.get('label') # Add year to our label if exists and not special value of 1601 if f.get('year') and f.get('year') != 1601: label_a = u'{} ({})'.format(label_a, f.get('year')) # Add season and episode numbers to label if utils.try_parse_int(f.get('season', 0)) > 0 and utils.try_parse_int(f.get('episode', 0)) > 0: label_a = u'{}x{}. {}'.format(f.get('season'), f.get('episode'), label_a) # Add various stream details to ListItem.Label2 (aka label_b) label_b_list = [] if f.get('streamdetails'): sdv_list = f.get('streamdetails', {}).get('video', [{}]) or [{}] sda_list = f.get('streamdetails', {}).get('audio', [{}]) or [{}] sdv, sda = sdv_list[0], sda_list[0] if sdv.get('width') or sdv.get('height'): label_b_list.append(u'{}x{}'.format(sdv.get('width'), sdv.get('height'))) if sdv.get('codec'): label_b_list.append(u'{}'.format(sdv.get('codec', '').upper())) if sda.get('codec'): label_b_list.append(u'{}'.format(sda.get('codec', '').upper())) if sda.get('channels'): label_b_list.append(u'{} CH'.format(sda.get('channels', ''))) for i in sda_list: if i.get('language'): label_b_list.append(u'{}'.format(i.get('language', '').upper())) if sdv.get('duration'): label_b_list.append(u'{} mins'.format(utils.try_parse_int(sdv.get('duration', 0)) // 60)) if f.get('size'): label_b_list.append(u'{}'.format(utils.normalise_filesize(f.get('size', 0)))) label_b = ' | '.join(label_b_list) if label_b_list else '' # Add item to select dialog list d_items.append(ListItem(label=label_a, label2=label_b, icon=f.get('thumbnail')).set_listitem()) if not d_items: return -1 # No items so ask user to select new player # If autoselect enabled and only 1 item choose that otherwise ask user to choose idx = 0 if auto and len(d_items) == 1 else xbmcgui.Dialog().select('Select Item', d_items, useDetails=True) if idx == -1: return # User exited the dialog so return nothing resolve_url = True if folder[idx].get('filetype') == 'file' else False # Set true for files so we can play return (resolve_url, folder[idx].get('file')) # Return the player
def get_list(self, *args, **kwargs): key = kwargs.pop('key', 'results') pagination = kwargs.pop('pagination', True) longcache = kwargs.pop('longcache', False) func = self.get_request_lc if longcache else self.get_request_sc request = func(*args, language=self.req_language, **kwargs) items = self.get_nicelist(request.get(key, [])) if pagination and utils.try_parse_int(request.get('page', 0)) < utils.try_parse_int(request.get('total_pages', 0)): items.append(ListItem(library=self.library, label=xbmc.getLocalizedString(33078), nextpage=utils.try_parse_int(request.get('page', 0)) + 1)) return items
def get_calendar_episodes(self, startdate=0, days=1, limit=25): items = [] if not self.tmdb or not self.authorize(): return items date = datetime.datetime.today() + datetime.timedelta(days=startdate) response = TraktAPI().get_calendar( 'shows', True, start_date=date.strftime('%Y-%m-%d'), days=days) if not response: return items for i in response[-limit:]: episode = i.get('episode', {}).get('number') season = i.get('episode', {}).get('season') tmdb_id = i.get('show', {}).get('ids', {}).get('tmdb') item = ListItem(library=self.library, **self.tmdb.get_detailed_item(itemtype='tv', tmdb_id=tmdb_id, season=season, episode=episode)) item.tmdb_id, item.season, item.episode = tmdb_id, season, episode item.infolabels['title'] = item.label = i.get('episode', {}).get('title') air_date = utils.convert_timestamp(i.get( 'first_aired', '')) + datetime.timedelta(hours=self.utc_offset) item.infolabels['premiered'] = air_date.strftime('%Y-%m-%d') item.infolabels['year'] = air_date.strftime('%Y') item.infoproperties['air_time'] = air_date.strftime('%I:%M %p') items.append(item) return items
def get_inprogress(self, userslug, limit=None, episodes=False): """ UPDATED: Now looks at all shows sorted by recently watched OLD VERSION: Looked at user's most recently watched 200 episodes in last 3 years Adds each unique show to list in order then checks if show has an upnext episode Returns list of tmdb_ids representing shows with upnext episodes in recently watched order """ items = [] if not self.tmdb or not self.authorize(): return items n = 0 # utils.kodi_log(u'Getting In-Progress For Trakt User {0}'.format(userslug), 2) last_updated = self.get_response_json('sync/last_activities') last_updated = last_updated.get( 'episodes', {}).get('watched_at') if last_updated else None hidden_shows = self.get_hiddenitems('show') for i in self.get_recentlywatched_shows(userslug, islistitem=False): if limit and n >= limit: break # Got limit so stop if i[0] in hidden_shows: continue # Show is hidden so don't get it # utils.kodi_log(u'In-Progress -- Searching Next Episode For:\n{0}'.format(i), 1) progress = self.get_upnext(i[0], True, last_updated=last_updated) if progress and progress.get('next_episode'): if (episodes and progress.get('next_episode', {}).get('season') == 1 and progress.get('next_episode', {}).get('number') == 1): continue # utils.kodi_log(u'In-Progress -- Found Next Episode:\n{0}'.format(progress.get('next_episode')), 2) season = progress.get('next_episode', {}).get('season') if episodes else None episode = progress.get('next_episode', {}).get('number') if episodes else None item = self.tmdb.get_detailed_item('tv', i[1], season=season, episode=episode) item['tmdb_id'] = i[1] # utils.kodi_log(u'In-Progress -- Got Next Episode Details:\n{0}'.format(item), 2) items.append(ListItem(library=self.library, **item)) n += 1 return sorted( items, key=lambda i: i.infolabels.get('premiered'), reverse=True) if episodes and self.addon.getSettingString( 'trakt_nextepisodesort') == 'airdate' else items
def get_inprogress(self, userslug, limit=None, episodes=False): """ UPDATED: Now looks at all shows sorted by recently watched OLD VERSION: Looked at user's most recently watched 200 episodes in last 3 years Adds each unique show to list in order then checks if show has an upnext episode Returns list of tmdb_ids representing shows with upnext episodes in recently watched order """ items = [] if not self.tmdb or not self.authorize(): return items n = 0 utils.kodi_log( 'Getting In-Progress For Trakt User {0}'.format(userslug), 2) # for i in self.get_recentlywatched(userslug, 'tv', islistitem=False, months=36): for i in self.get_recentlywatched_shows(userslug, islistitem=False): if limit and n >= limit: break utils.kodi_log( 'In-Progress -- Searching Next Episode For:\n{0}'.format(i), 2) progress = self.get_upnext(i[0], True) if progress and progress.get('next_episode'): utils.kodi_log( 'In-Progress -- Found Next Episode:\n{0}'.format( progress.get('next_episode')), 2) season = progress.get('next_episode', {}).get('season') if episodes else None episode = progress.get('next_episode', {}).get('number') if episodes else None item = self.tmdb.get_detailed_item('tv', i[1], season=season, episode=episode) item['tmdb_id'] = i[1] utils.kodi_log( 'In-Progress -- Got Next Episode Details:\n{0}'.format( item), 2) items.append(ListItem(library=self.library, **item)) n += 1 return items
def get_itemlist(self, *args, **kwargs): items = [] if not self.tmdb or (kwargs.pop('req_auth', False) and not self.authorize()): return items key_list = kwargs.pop('key_list', ['dummy']) rnd_list = kwargs.pop('rnd_list', 0) usr_list = kwargs.pop('usr_list', False) this_page = int(kwargs.get('page', 1)) limit = kwargs.get('limit', 0) if usr_list: # Check if userlist and apply special sorting kwparams = { 'page': this_page, 'limit': limit, 'sortmethod': kwargs.pop('sortmethod', None), 'sortdirection': kwargs.pop('sortdirection', None)} response = self.get_itemlist_sortedcached(*args, **kwparams) itemlist = response.get('items') if not itemlist: return items last_page = response.get('pagecount') else: response = self.get_response(*args, **kwargs) if not response: return items itemlist = response.json() last_page = int(response.headers.get('X-Pagination-Page-Count', 0)) next_page = this_page + 1 if this_page < last_page and not rnd_list else False if rnd_list: rnd_list = random.sample(range(len(itemlist) - 1), rnd_list) itemlist = [itemlist[i] for i in rnd_list] n = 0 for i in itemlist: if limit and not n < limit: break for key in key_list: if limit and not n < limit: break myitem = i.get(key) or i if not myitem: continue tmdbtype = 'tv' if key == 'show' else 'movie' item = None if myitem.get('ids', {}).get('imdb'): item = self.tmdb.get_externalid_item(tmdbtype, myitem.get('ids', {}).get('imdb'), 'imdb_id') elif myitem.get('ids', {}).get('tvdb'): item = self.tmdb.get_externalid_item(tmdbtype, myitem.get('ids', {}).get('tvdb'), 'tvdb_id') if not item: continue item['mixed_type'] = tmdbtype items.append(ListItem(library=self.library, **item)) n += 1 if next_page: items.append(ListItem(library=self.library, label=xbmc.getLocalizedString(33078), nextpage=next_page)) return items
def play_external(self, force_dialog=False, playerindex=-1): if playerindex > -1: # Previous iteration didn't find an item to play so remove it and retry xbmcgui.Dialog().notification( self.itemlist[playerindex].getLabel(), self.addon.getLocalizedString(32040)) del self.actions[ playerindex] # Item not found so remove the player's action list del self.itemlist[ playerindex] # Item not found so remove the player's select dialog entry del self.identifierlist[ playerindex] # Item not found so remove the player's index playerindex = self.get_playerindex(force_dialog=force_dialog) # User cancelled dialog if not playerindex > -1: return False player = self.actions[playerindex] if not player or not player[1]: return False # External player has list of actions so let's iterate through them to find our item resolve_url = False if isinstance(player[1], list): actionlist = player[1] player = (False, actionlist[0]) for d in actionlist[1:]: if player[0]: break # Playable item was found in last action so let's break and play it folder = KodiLibrary().get_directory( string_format_map( player[1], self.item)) # Get the next folder from the plugin if d.get( 'dialog' ): # Special option to show dialog of items to select from d_items = [] for f in folder: # Create our list of items if not f.get('label') or f.get('label') == 'None': continue lb_list = [] label_a = f.get('label') if f.get('year') and f.get('year') != 1601: label_a = u'{} ({})'.format(label_a, f.get('year')) if utils.try_parse_int(f.get( 'season', 0)) > 0 and utils.try_parse_int( f.get('episode', 0)) > 0: label_a = u'{}x{}. {}'.format( f.get('season'), f.get('episode'), label_a) if f.get('streamdetails'): sdv_list = f.get('streamdetails', {}).get( 'video', [{}]) or [{}] sda_list = f.get('streamdetails', {}).get( 'audio', [{}]) or [{}] sdv, sda = sdv_list[0], sda_list[0] if sdv.get('width') or sdv.get('height'): lb_list.append(u'{}x{}'.format( sdv.get('width'), sdv.get('height'))) if sdv.get('codec'): lb_list.append(u'{}'.format( sdv.get('codec', '').upper())) if sda.get('codec'): lb_list.append(u'{}'.format( sda.get('codec', '').upper())) if sda.get('channels'): lb_list.append(u'{} CH'.format( sda.get('channels', ''))) for i in sda_list: if i.get('language'): lb_list.append(u'{}'.format( i.get('language', '').upper())) if sdv.get('duration'): lb_list.append(u'{} mins'.format( utils.try_parse_int(sdv.get('duration', 0)) // 60)) if f.get('size'): lb_list.append(u'{}'.format( utils.normalise_filesize(f.get('size', 0)))) label_b = ' | '.join(lb_list) if lb_list else '' d_items.append( ListItem(label=label_a, label2=label_b, icon=f.get('thumbnail')).set_listitem()) if d_items: idx = 0 if d.get('dialog', '').lower() != 'auto' or len(d_items) != 1: idx = xbmcgui.Dialog().select('Select Item', d_items, useDetails=True) if idx == -1: # User exited the dialog so return and do nothing return resolve_url = True if folder[idx].get( 'filetype' ) == 'file' else False # Set true for files so we can play player = (resolve_url, folder[idx].get('file') ) # Set the folder path to open/play break # Move onto next action else: # Ask user to select a different player if no items in dialog return self.play_external(force_dialog=force_dialog, playerindex=playerindex) x = 0 for f in folder: # Iterate through plugin folder looking for a matching item x += 1 # Keep an index for position matching for k, v in d.items( ): # Iterate through our key (infolabel) / value (infolabel must match) pairs of our action if k == 'position': # We're looking for an item position not an infolabel if utils.try_parse_int( string_format_map(v, self.item) ) != x: # Format our position value break # Not the item position we want so let's go to next item in folder elif not f.get(k) or string_format_map( v, self.item ) not in u'{}'.format( f.get(k, '') ): # Format our value and check if it matches the infolabel key break # Item's key value doesn't match value we are looking for so let's got to next item in folder else: # Item matched our criteria so let's open it up resolve_url = True if f.get( 'filetype' ) == 'file' else False # Set true for files so we can play player = (resolve_url, f.get('file') ) # Get ListItem.FolderPath for item break # Move onto next action (either open next folder or play file) else: return self.play_external( force_dialog=force_dialog, playerindex=playerindex ) # Ask user to select a different player # Play/Search found item if player and player[1]: action = string_format_map(player[1], self.item) if player[0] and action.endswith( '.strm'): # Action is play and is a strm so PlayMedia xbmc.executebuiltin( utils.try_decode_string(u'PlayMedia({0})'.format(action))) elif player[ 0]: # Action is play and not a strm so play with player xbmc.Player().play( action, ListItem(library='video', **self.details).set_listitem()) else: action = u'Container.Update({0})'.format( action) if xbmc.getCondVisibility( "Window.IsMedia" ) else u'ActivateWindow(videos,{0},return)'.format(action) xbmc.executebuiltin(utils.try_decode_string(action)) return action
def play_external(self, force_dialog=False): itemindex = self.get_itemindex(force_dialog=force_dialog) # User cancelled dialog if not itemindex > -1: return False player = self.actions[itemindex] if not player or not player[1]: return False # External player has list of actions so let's iterate through them to find our item resolve_url = False if isinstance(player[1], list): actionlist = player[1] player = (False, actionlist[0]) with utils.busy_dialog(): for d in actionlist[1:]: if player[0]: break # Playable item was found in last action so let's break and play it folder = KodiLibrary().get_directory( string_format_map( player[1], self.item)) # Get the next folder from the plugin x = 0 for f in folder: # Iterate through plugin folder looking for a matching item x += 1 # Keep an index for position matching for k, v in d.items( ): # Iterate through our key (infolabel) / value (infolabel must match) pairs of our action if k == 'position': # We're looking for an item position not an infolabel if utils.try_parse_int( string_format_map(v, self.item) ) != x: # Format our position value break # Not the item position we want so let's go to next item in folder elif not f.get(k) or string_format_map( v, self.item ) not in u'{}'.format( f.get(k, '') ): # Format our value and check if it matches the infolabel key break # Item's key value doesn't match value we are looking for so let's got to next item in folder else: # Item matched our criteria so let's open it up resolve_url = True if f.get( 'filetype' ) == 'file' else False # Set true for files so we can play player = (resolve_url, f.get('file') ) # Get ListItem.FolderPath for item break # Move onto next action (either open next folder or play file) else: xbmcgui.Dialog().notification( self.itemlist[itemindex].getLabel(), self.addon.getLocalizedString(32040)) del self.actions[ itemindex] # Item not found so remove the player's action list del self.itemlist[ itemindex] # Item not found so remove the player's select dialog entry return self.play_external( force_dialog=True ) # Ask user to select a different player # Play/Search found item if player and player[1]: action = string_format_map(player[1], self.item) if player[0]: # Action is play so let's play the item and return xbmc.Player().play( action, ListItem(library='video', **self.details).set_listitem()) return action # Action is search so let's load the plugin path action = u'Container.Update({0})'.format( action) if xbmc.getCondVisibility( "Window.IsMedia" ) else u'ActivateWindow(videos,{0},return)'.format(action) xbmc.executebuiltin(utils.try_decode_string(action)) return action
def get_itemlist(self, *args, **kwargs): items = [] if not self.tmdb or (kwargs.pop('req_auth', False) and not self.authorize()): return items key_list = kwargs.pop('key_list', ['dummy']) rnd_list = kwargs.pop('rnd_list', 0) response = self.get_response(*args, **kwargs) if not response: return items itemlist = response.json() this_page = int(kwargs.get('page', 1)) last_page = int(response.headers.get('X-Pagination-Page-Count', 0)) next_page = this_page + 1 if this_page < last_page and not rnd_list else False if rnd_list: rnd_list = random.sample(range(len(itemlist) - 1), rnd_list) itemlist = [itemlist[i] for i in rnd_list] n = 0 limit = kwargs.get('limit', 0) for i in itemlist: if limit and not n < limit: break for key in key_list: if limit and not n < limit: break myitem = i.get(key) or i if not myitem: continue tmdbtype = 'tv' if key == 'show' else 'movie' item = None if myitem.get('ids', {}).get('imdb'): item = self.tmdb.get_externalid_item( tmdbtype, myitem.get('ids', {}).get('imdb'), 'imdb_id') elif myitem.get('ids', {}).get('tvdb'): item = self.tmdb.get_externalid_item( tmdbtype, myitem.get('ids', {}).get('tvdb'), 'tvdb_id') if not item: continue item['mixed_type'] = tmdbtype items.append(ListItem(library=self.library, **item)) n += 1 if next_page: items.append( ListItem(library=self.library, label='Next Page', nextpage=next_page)) return items