示例#1
0
    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()
示例#2
0
    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()
示例#3
0
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 + ')')
示例#4
0
    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()
示例#5
0
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 + ')')
示例#6
0
 def _buildCatalog():
     catalog = self.catalogFunctions.get(params['route'], self.genericCatalog)(params)
     cache.setCacheProperty(self.PROPERTY_CATALOG, catalog, saveToDisk = False)
     return catalog