def latestUpdatesCatalog(self, params): ''' Returns a catalog for the Latest Updates category. This route is cached memory-only to make sure it's always fresh. This memory cache lasts one Kodi session. Closing Kodi and reopening it will do a new web request. ''' api = params['api'] if api == requestHelper.API_ANIMETOON: _PROPERTY_LAST_UPDATES = 'tmania2.prop.toonUpdates' else: _PROPERTY_LAST_UPDATES = 'tmania2.prop.plusUpdates' # Memory-only cache of the latest updates IDs. latestIDs = cache.getCacheProperty(_PROPERTY_LAST_UPDATES, readFromDisk = False) if not latestIDs: requestHelper.setAPISource(api) requestHelper.delayBegin() jsonData = requestHelper.routeGET(params['route']) if jsonData: latestIDs = tuple(entry['id'] for entry in jsonData.get('updates', [ ])) cache.setCacheProperty(_PROPERTY_LAST_UPDATES, latestIDs, saveToDisk = False) requestHelper.delayEnd(1000) if latestIDs: # Latest Updates needs all items of the current API loaded, to compare IDs with. # Make a dictionary to map item IDs to the items themselves. allData = self._getMainRoutesData(api) idDict = {item[0]: item for item in chain.from_iterable(allData)} # Find the entries based on their IDs from the latest updates list. return self.catalogFromIterable(idDict[entryID] for entryID in latestIDs if entryID in idDict) else: return self.getEmptyCatalog()
def genericCatalog(self, params): ''' Returns a catalog for either the '/GetNew(...)' or '/GetPopular(...)' routes. These routes are cached memory-only, so they last one Kodi session. Closing and reopening Kodi will make a new web request for fresh data. ''' api = params['api'] route = params['route'] # Get the corresponding '/GetAll(...)' route with the data that will be needed. allRoute = route.replace('New', 'All') if '/GetNew' in route else route.replace('Popular', 'All') genericIDs = cache.getCacheProperty(api+route, readFromDisk = False) if not genericIDs: requestHelper.setAPISource(api) requestHelper.delayBegin() jsonData = requestHelper.routeGET(route) if jsonData: genericIDs = tuple(entry['id'] for entry in jsonData) cache.setCacheProperty(api+route, genericIDs, saveToDisk = False) requestHelper.delayEnd(500) if genericIDs: # Load all the main routes of the API (they are disk-cached), to compare IDs with. allData = self._getMainRoutesData(api, allRoute) idDict = {item[0]: item for item in chain.from_iterable(allData)} return self.catalogFromIterable(idDict[entryID] for entryID in genericIDs if entryID in idDict) else: return self.getEmptyCatalog()
def viewSearchGenre(params): ''' Directory for a sub menu that lists the available genres to filter items by. The genre list is cached memory-only to last a Kodi session. This is done because if you hit "Back" Kodi will reload this directory and do a redundant web request... ''' xbmcplugin.setContent(int(sys.argv[1]), 'tvshows') # Optional, influences the skin layout. api = params['api'] route = params['route'] if api == requestHelper.API_ANIMETOON: _PROPERTY_GENRE_NAMES = 'tmania2.prop.toonGenres' else: _PROPERTY_GENRE_NAMES = 'tmania2.prop.plusGenres' genreList = cache.getCacheProperty(_PROPERTY_GENRE_NAMES, readFromDisk=True) if not genreList: # The data from the '/GetGenres/' route is a dict with a list of genre names like "Action", # "Comedy" etc., but it also has some weird texts in the list probably from data entry errors. requestHelper.setAPISource(api) requestHelper.delayBegin() genreList = requestHelper.routeGET(route).get('genres', []) requestHelper.delayEnd() # Store the current API genres in a disk-persistent property with 1 week of lifetime. cache.setCacheProperty(_PROPERTY_GENRE_NAMES, genreList, saveToDisk=True, lifetime=cache.LIFETIME_ONE_WEEK) listItems = ((buildURL({ 'view': 'CATALOG_MENU', 'api': api, 'route': route, 'genreName': genreName }), xbmcgui.ListItem(genreName), True) for genreName in genreList) xbmcplugin.addDirectoryItems(int(sys.argv[1]), tuple(listItems)) xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False) useCatalogLayout, layoutType = ADDON_SETTINGS['layoutCatalog'] if useCatalogLayout: xbmc.executebuiltin('Container.SetViewMode(' + layoutType + ')')
def allRouteCatalog(self, params): ''' Returns a catalog for one of the main '/GetAll(...)' routes. ''' api = params['api'] route = params['route'] propName = self._diskFriendlyPropName(api, route) jsonData = cache.getCacheProperty(propName, readFromDisk = True) if not jsonData: requestHelper.setAPISource(api) requestHelper.delayBegin() jsonData = requestHelper.routeGET(route) if jsonData: cache.setCacheProperty(propName, jsonData, saveToDisk = True) # Defaults to 3 days cache lifetime. requestHelper.delayEnd(500) if jsonData: return self.catalogFromIterable(self.makeCatalogEntry(entry) for entry in jsonData) else: return self.getEmptyCatalog()
def viewListEpisodes(params): ''' Directory for the list of episodes from a show. This is the last directory before playing a video. Pages aren't necessary in here even if the thumbnails setting is on, because for now all episodes use the same thumb and plot, inherited from the show. ''' xbmcplugin.setContent(int(sys.argv[1]), 'episodes') # Sort episode list by labels. In some rare cases the episode date is set wrong, # so Kodi lists them out of order. xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) api = params['api'] jsonData = None # Cache (memory-only) the episode list of the show, as the user might watch more than one in sequence. _PROPERTY_LAST_SHOW_DETAILS = 'tmania2.prop.lastShow' lastShowDetails = cache.getCacheProperty(_PROPERTY_LAST_SHOW_DETAILS, readFromDisk=False) showKey = params['id'] + api if lastShowDetails and showKey in lastShowDetails: jsonData = lastShowDetails[ showKey] # Use the show ID + API name as the unique identifier. if not jsonData: requestHelper.setAPISource(api) requestHelper.delayBegin() jsonData = requestHelper.routeGET('/GetDetails/' + params['id']) if jsonData: cache.setCacheProperty(_PROPERTY_LAST_SHOW_DETAILS, {showKey: jsonData}, saveToDisk=False) requestHelper.delayEnd() # Genres, thumb and plot are taken from the parent show \ movie. # But the date of the parent show \ movie will only be used if the individual episode doesn't have a date itself. showTitle = jsonData.get('name', '') showGenres = params['genres'].split(',') showThumb = params.get( 'thumb', '') # Might be empty in case ADDON_SETTINGS['showThumbs'] is off. showPlot = params['plot'] showDate = params.get('date', '') # If the JSON data for this show has more than one episode, list all the episodes as usual. if len(jsonData['episode']) > 1: xbmcplugin.addDirectoryItems( int(sys.argv[1]), tuple( _makeEpisodeItems(api, jsonData['episode'], showTitle, showGenres, showThumb, showPlot, showDate))) else: # For a single episode, this is probably a movie, OVA or special (considered as a "1 episode show"). # Try to get the direct stream links to see if it's a movie (which are always multi-part). episodeEntry = jsonData['episode'][0] episodeProviders = None # Cache (memory-only) this request, as it might be for a multi part video (a movie) # where the user would go back and forth a lot on this view to watch all the movie parts. _PROPERTY_LAST_EPISODE_DETAILS = 'tmania2.prop.lastEpisode' lastEpisodeDetails = cache.getCacheProperty( _PROPERTY_LAST_EPISODE_DETAILS, readFromDisk=False) episodeKey = episodeEntry['id'] + api if lastEpisodeDetails and episodeKey in lastEpisodeDetails: episodeProviders = lastEpisodeDetails[episodeKey] else: episodeProviders = getEpisodeProviders(api, episodeEntry['id']) if episodeProviders: cache.setCacheProperty(_PROPERTY_LAST_EPISODE_DETAILS, {episodeKey: episodeProviders}, saveToDisk=False) if episodeProviders: if len(next(episodeProviders.itervalues()) ) > 1: # If it's a multi-video-part media. xbmcplugin.addDirectoryItems( int(sys.argv[1]), tuple( _makeEpisodePartItems(episodeEntry, episodeProviders, showTitle, showGenres, showThumb, showPlot, showDate))) else: # The item doesn't have multiple video parts. List the single item as usual and send its providers # as a URL parameter so they don't have to be retrieved again. dirItem = next( _makeEpisodeItems(api, (episodeEntry, ), showTitle, showGenres, showThumb, showPlot, showDate)) newUrl = dirItem[0] + '&' + urlencode( {'providers': str(episodeProviders)}) xbmcplugin.addDirectoryItem(int(sys.argv[1]), newUrl, dirItem[1], False) else: logStreamError(params['api'], api, episodeEntry['id']) xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False) # Custom layout. useEpisodeLayout, layoutType = ADDON_SETTINGS['layoutEpisodes'] if useEpisodeLayout: xbmc.executebuiltin('Container.SetViewMode(' + layoutType + ')')
def _buildCatalog(): catalog = self.catalogFunctions.get(params['route'], self.genericCatalog)(params) cache.setCacheProperty(self.PROPERTY_CATALOG, catalog, saveToDisk = False) return catalog