Example #1
0
def _post_login(args, notice_msg, current_datetime):
    """Check premium type and report usage.

    """
    acc_type_error = args._lang(30312)

    # Verify user is premium
    if args.user_data['premium_type'] in 'anime|drama|manga':
        log("CR: User is a premium " + str(args.user_data['premium_type']) +
            " member")

        # Cache queued series
        if 'queue' not in args.user_data:
            args.user_data['queue'] = get_queued(args)

        return True

    else:
        log("CR: User is not a premium member")
        xbmc.executebuiltin('Notification(' + notice_msg + ',' +
                            acc_type_error + ',5000)')

        crm.add_item(args, {'title': acc_type_error, 'mode': 'fail'})
        crm.endofdirectory('none')

        return False
def list_collections(args):
    """List collections.

    """
    fields  = "".join(["collection.collection_id,",
                       "collection.season,",
                       "collection.name,",
                       "collection.description,",
                       "collection.complete,",
                       "collection.media_count"])
    options = {'series_id': args.series_id,
               'fields':    fields,
               'sort':      'desc',
               'limit':     args.count}

    request = makeAPIRequest(args, 'list_collections', options)

    if request['error'] is False:
        if len(request['data']) <= 1:
            for collection in request['data']:
                args.complete = '1' if collection['complete'] else '0'
                args.id       = collection['collection_id']

                return list_media(args)
        else:
            queued = (args.series_id in args.user_data['queue'])

            for collection in request['data']:
                complete = '1' if collection['complete'] else '0'
                crm.add_item(args,
                             {'title':        collection['name'].encode("utf8"),
                              'filterx':      args.name,
                              'mode':         'list_media',
                              'count':        str(args.count),
                              'id':           collection['collection_id'],
                              'plot':         collection['description'].encode("utf8"),
                              'complete':     complete,
                              'season':       str(collection['season']),
                              'series_id':    args.series_id,
                              'thumb':        args.icon,
                              'fanart_image': args.fanart},
                             isFolder=True,
                             queued=queued)

    crm.endofdirectory('none')
def list_categories(args):
    """List categories.

    """
    options = {'media_type': args.media_type}

    request = makeAPIRequest(args, 'categories', options)

    if request['error'] is False:
        for i in request['data'][args.filterx]:
            crm.add_item(args,
                         {'title':      i['label'].encode("utf8"),
                          'mode':       'list_series',
                          'media_type': args.media_type,
                          'filterx':    'tag:' + i['tag']},
                         isFolder=True)

    crm.endofdirectory('none')
Example #4
0
def list_categories(args):
    """List categories.

    """
    options = {'media_type': args.media_type}

    request = makeAPIRequest(args, 'categories', options)

    if request['error'] is False:
        for i in request['data'][args.filterx]:
            crm.add_item(args, {
                'title': i['label'].encode("utf8"),
                'mode': 'list_series',
                'media_type': args.media_type,
                'filterx': 'tag:' + i['tag']
            },
                         isFolder=True)

    crm.endofdirectory('none')
def _post_login(args,
                notice_msg,
                current_datetime):
    """Check premium type and report usage.

    """
    acc_type_error = args._lang(30312)

    # Call for usage reporting
    if current_datetime > args.user_data['lastreported']:
        args.user_data['lastreported'] = (current_datetime +
                                          durel.relativedelta(hours = +24))
        usage_reporting(args)

    # Verify user is premium
    if args.user_data['premium_type'] in 'anime|drama|manga':
        log("CR: User is a premium "
            + str(args.user_data['premium_type']) + " member")

        # Cache queued series
        if 'queue' not in args.user_data:
            args.user_data['queue'] = get_queued(args)

        return True

    else:
        log("CR: User is not a premium member")
        xbmc.executebuiltin('Notification(' + notice_msg + ','
                            + acc_type_error + ',5000)')

        crm.add_item(args,
                     {'title': acc_type_error,
                      'mode':  'fail'})
        crm.endofdirectory('none')

        return False
Example #6
0
def queue(args):
    """Show Crunchyroll queue.

    """
    queue_type = args._addon.getSetting("queue_type")

    log("CR: Queue: queue type is " + str(queue_type))
    if queue_type == '0':
        fields = "".join([
            "media.episode_number,", "media.name,", "media.description,",
            "media.media_type,", "media.series_name,", "media.available,",
            "media.available_time,", "media.free_available,",
            "media.free_available_time,", "media.duration,", "media.playhead,",
            "media.url,", "media.screenshot_image,", "image.fwide_url,",
            "image.fwidestar_url,", "series.landscape_image,",
            "series.series_id,", "image.full_url"
        ])
        options = {'media_types': "anime|drama", 'fields': fields}

        request = makeAPIRequest(args, 'queue', options)

        log("CR: Queue: request['error'] = " + str(request['error']))
        if request['error'] is False:
            log("CR: Queue: has %d series" % len(request['data']))

            # Cache series
            args.user_data['queue'] = [
                col['series']['series_id'] for col in request['data']
            ]

            return list_media_items(args, request['data'], 'Queue', '1',
                                    'queue', 'fanart')

    elif queue_type == '1':
        fields = "".join([
            "series.name,", "series.description,", "series.series_id,",
            "series.rating,", "series.media_count,", "series.url,",
            "series.publisher_name,", "series.year,", "series.portrait_image,",
            "image.large_url,", "series.landscape_image,", "image.full_url"
        ])
        options = {'media_types': "anime|drama", 'fields': fields}

        request = makeAPIRequest(args, 'queue', options)

        log("CR: Queue: request['error'] = " + str(request['error']))
        if request['error'] is False:
            log("CR: Queue: has %d series" % len(request['data']))

            # Cache series
            args.user_data['queue'] = [
                col['series']['series_id'] for col in request['data']
            ]

            for series in request['data']:
                series = series['series']
                # Only available for some series
                year = ('None' if series['year'] is None else series['year'])
                desc = ('' if series['description'] is None else
                        series['description'].encode('utf-8'))

                thumb = ('' if
                         (series['portrait_image'] is None
                          or series['portrait_image']['large_url'] is None
                          or 'portrait_image' not in series
                          or 'large_url' not in series['portrait_image']) else
                         series['portrait_image']['full_url'])
                art = ('' if (series['landscape_image'] is None
                              or series['landscape_image']['full_url'] is None
                              or 'landscape_image' not in series
                              or 'full_url' not in series['landscape_image'])
                       else series['landscape_image']['full_url'])
                rating = ('0' if
                          (series['rating'] == ''
                           or 'rating' not in series) else series['rating'])

                # Crunchyroll seems to like passing series
                # without these things
                if ('media_count' in series and 'series_id' in series
                        and 'name' in series and series['media_count'] > 0):

                    crm.add_item(args, {
                        'title': series['name'].encode("utf8"),
                        'mode': 'list_coll',
                        'series_id': series['series_id'],
                        'thumb': thumb,
                        'fanart_image': art,
                        'plot': desc,
                        'year': year
                    },
                                 isFolder=True,
                                 queued=True)

                    log(
                        "CR: Queue: series = '%s' queued" %
                        series['name'].encode('latin-1', 'ignore'),
                        xbmc.LOGDEBUG)

                else:
                    log("CR: Queue: series not queued!", xbmc.LOGDEBUG)

            crm.endofdirectory('none')
Example #7
0
def list_media_items(args, request, series_name, season, mode, fanart):
    """List video episodes.

    """
    for media in request:
        ordering = 0

        if (mode == "queue"):
            ordering = media['ordering']
        if (mode == "history" or mode == "queue"):
            series_id = media['series']['series_id']
        elif args.series_id:
            series_id = args.series_id
        else:
            series_id = 'None'

        queued = (series_id in args.user_data['queue'])

        # The following are items to help display Recently Watched
        # and Queue items correctly
        season = (media['collection']['season']
                  if mode == "history" else season)
        series_name = (media['series']['name']
                       if mode == "history" else series_name)
        series_name = (media['most_likely_media']['series_name'] if
                       (mode == "queue"
                        and 'most_likely_media' in media) else series_name)
        # On history/queue, the fanart is obtained directly from the json
        fanart = (media['series']['landscape_image']['fwide_url'] if
                  (mode == "history" or mode == "queue") else fanart)
        # History media is one level deeper in the json string
        # than normal media items
        media = (media['media'] if mode == "history" else media)

        # Some queue items don't have most_likely_media, skip them
        if mode == "queue" and 'most_likely_media' not in media:
            continue

        # Queue media is one level deeper in the json string
        # than normal media items
        media = media['most_likely_media'] if mode == "queue" else media

        current_datetime = datetime.datetime.now(dateutil.tz.tzutc())
        available_datetime = dateutil.parser.parse(media['available_time'])
        available_datetime = available_datetime.astimezone(
            dateutil.tz.tzlocal())
        available_date = available_datetime.date()
        available_delta = available_datetime - current_datetime
        available_in = (str(available_delta.days) +
                        " days." if available_delta.days > 0 else
                        str(available_delta.seconds / 60 / 60) + " hours.")

        # Fix Crunchyroll inconsistencies & add details for upcoming or
        # unreleased episodes.
        # PV episodes have no episode number so we set it to 0.
        media['episode_number'] = ('0' if media['episode_number'] == '' else
                                   media['episode_number'])
        # CR puts letters into some rare episode numbers
        media['episode_number'] = re.sub('\D', '', media['episode_number'])

        if media['episode_number'] == '0':
            name = ("NO NAME" if media['name'] == '' else media['name'])
        else:
            # CR doesn't seem to include episode names for all media,
            # make one up
            name = ("Episode " + str(media['episode_number'])
                    if media['name'] == '' else "Episode " +
                    media['episode_number'] + " - " + media['name'])

        name = (series_name + " " + name if
                (mode == "history" or mode == "queue") else name)
        name = (args._addon.getSetting("prefix_premium") +
                name if media['free_available'] is False else name)
        soon = (args._addon.getSetting("prefix_coming") + series_name +
                "Episode " + str(media['episode_number']) if mode == "queue"
                else args._addon.getSetting("prefix_coming") + "Episode " +
                str(media['episode_number']))
        # Set the name for upcoming episode
        name = soon if media['available'] is False else name

        # Not all shows have thumbnails
        thumb = ("http://static.ak.crunchyroll.com/i/no_image_beta_full.jpg"
                 if media['screenshot_image'] is None else
                 media['screenshot_image']['fwide_url']
                 if media['free_available'] is True else
                 media['screenshot_image']['fwidestar_url'])
        # Sets the thumbnail to coming soon if the episode
        # isn't available yet
        thumb = (
            "http://static.ak.crunchyroll.com/i/coming_soon_beta_fwide.jpg"
            if media['available'] is False else thumb)

        description = ('' if media['description'] is None else
                       media['description'].encode('utf-8'))
        # Set the description for upcoming episodes
        description = ("This episode will be available in " + str(available_in)
                       if media['available'] is False else description)

        duration = ("0"
                    if media['available'] is False else str(media['duration']))
        # Current playback point
        playhead = ("0" if
                    (media['available'] is False
                     or not 'playhead' in media) else str(media['playhead']))

        # Adding published date instead
        year = ('None' if media['available_time'] is None else
                media['available_time'][:10])

        url = media['url']
        media_id = url.split('-')[-1]

        if int(float(playhead)) > 10:
            percent = ((int(float(playhead)) * 100) / int(float(duration))) + 1
        else:
            percent = 0

        crm.add_item(args, {
            'title': name.encode("utf8"),
            'mode': 'videoplay',
            'id': media_id.encode("utf8"),
            'series_id': series_id,
            'episode': str(media['episode_number']).encode("utf8"),
            'thumb': thumb.encode("utf8"),
            'url': url.encode("utf8"),
            'fanart_image': fanart,
            'plot': description,
            'year': year,
            'playhead': playhead,
            'duration': duration,
            'percent': percent,
            'ordering': ordering
        },
                     isFolder=False,
                     queued=queued)

    if mode == 'queue':
        crm.endofdirectory('user')
    else:
        crm.endofdirectory('none')
Example #8
0
def list_collections(args, random=False):
    """List collections.

    """
    fields = "".join([
        "collection.collection_id,", "collection.season,", "collection.name,",
        "collection.description,", "collection.complete,",
        "collection.media_count"
    ])
    options = {
        'series_id': args.series_id,
        'fields': fields,
        'sort': 'desc',
        'limit': args.count
    }

    request = makeAPIRequest(args, 'list_collections', options)

    if request['error'] is False:
        if random:
            try:
                random_media_type = str(args.media_type)
            except:
                random_media_type = 'anime'
            try:
                random_name = request['data'][0]['name']
            except:
                random_name = "[New random]"
            random_li = xbmcgui.ListItem(label=random_name)
            random_li.setInfo(type="Video",
                              infoLabels={"Title": "[New random]"})

            random_li.setArt({
                'fanart':
                xbmc.translatePath(args._addon.getAddonInfo('fanart')),
                'thumb':
                xbmc.validatePath(
                    xbmc.translatePath(
                        args._addon.getAddonInfo('path') + "\dice.png"))
            })

            xbmcplugin.addDirectoryItem(
                handle=int(sys.argv[1]),
                url=crm.build_url(
                    crm.set_info_defaults(
                        args, {
                            'mode': 'get_random',
                            'media_type': random_media_type,
                            'title': random_name
                        })),
                listitem=random_li,
                isFolder=True)

        if len(request['data']) <= 1:
            for collection in request['data']:
                args.complete = '1' if collection['complete'] else '0'
                args.id = collection['collection_id']

                return list_media(args)
        else:
            queued = (args.series_id in args.user_data['queue'])

            for collection in request['data']:
                complete = '1' if collection['complete'] else '0'
                crm.add_item(args, {
                    'title': collection['name'].encode("utf8"),
                    'filterx': args.name,
                    'mode': 'list_media',
                    'count': str(args.count),
                    'id': collection['collection_id'],
                    'plot': collection['description'].encode("utf8"),
                    'complete': complete,
                    'season': str(collection['season']),
                    'series_id': args.series_id,
                    'thumb': args.icon,
                    'fanart_image': args.fanart
                },
                             isFolder=True,
                             queued=queued)

    crm.endofdirectory('none')
Example #9
0
def list_series(args):
    """List series.

    """
    fields = "".join([
        "series.name,", "series.description,", "series.series_id,",
        "series.rating,", "series.media_count,", "series.url,",
        "series.publisher_name,", "series.year,", "series.portrait_image,",
        "image.large_url,", "series.landscape_image,", "image.full_url"
    ])
    options = {
        'media_type': args.media_type,
        'filter': args.filterx,
        'fields': fields,
        'limit': '64',
        'offset': int(args.offset)
    }

    request = makeAPIRequest(args, 'list_series', options)

    if request['error'] is False:
        counter = 0
        for series in request['data']:
            counter = counter + 1

            # Only available on some series
            year = ('None' if series['year'] is None else series['year'])
            desc = ('' if series['description'] is None else
                    series['description'].encode('utf-8'))
            thumb = ('' if (series['portrait_image'] is None
                            or series['portrait_image']['large_url'] is None
                            or 'portrait_image' not in series
                            or 'large_url' not in series['portrait_image'])
                     else series['portrait_image']['full_url'])
            art = ('' if (series['landscape_image'] is None
                          or series['landscape_image']['full_url'] is None
                          or 'landscape_image' not in series
                          or 'full_url' not in series['landscape_image']) else
                   series['landscape_image']['full_url'])
            rating = ('0' if (series['rating'] == '' or 'rating' not in series)
                      else series['rating'])

            # Crunchyroll seems to like passing series
            # without these things
            if ('media_count' in series and 'series_id' in series
                    and 'name' in series and series['media_count'] > 0):

                queued = (series['series_id'] in args.user_data['queue'])

                crm.add_item(args, {
                    'title': series['name'].encode("utf8"),
                    'mode': 'list_coll',
                    'series_id': series['series_id'],
                    'count': str(series['media_count']),
                    'thumb': thumb,
                    'fanart_image': art,
                    'plot': desc,
                    'year': year
                },
                             isFolder=True,
                             queued=queued)

        if counter >= 64:
            offset = str(int(args.offset) + counter)
            crm.add_item(
                args, {
                    'title': '...load more',
                    'mode': 'list_series',
                    'media_type': args.media_type,
                    'filterx': args.filterx,
                    'offset': offset
                })

    crm.endofdirectory('none')
def queue(args):
    """Show Crunchyroll queue.

    """
    queue_type = args._addon.getSetting("queue_type")

    log("CR: Queue: queue type is " + str(queue_type))
    if queue_type == '0':
        fields  = "".join(["media.episode_number,",
                           "media.name,",
                           "media.description,",
                           "media.media_type,",
                           "media.series_name,",
                           "media.available,",
                           "media.available_time,",
                           "media.free_available,",
                           "media.free_available_time,",
                           "media.duration,",
                           "media.playhead,",
                           "media.url,",
                           "media.screenshot_image,",
                           "image.fwide_url,",
                           "image.fwidestar_url,",
                           "series.landscape_image,",
                           "series.series_id,",
                           "image.full_url"])
        options = {'media_types': "anime|drama",
                   'fields':      fields}

        request = makeAPIRequest(args, 'queue', options)

        log("CR: Queue: request['error'] = " + str(request['error']))
        if request['error'] is False:
            log("CR: Queue: has %d series" % len(request['data']))

            # Cache series
            args.user_data['queue'] = [col['series']['series_id']
                                           for col in request['data']]

            return list_media_items(args,
                                    request['data'],
                                    'Queue',
                                    '1',
                                    'queue',
                                    'fanart')

    elif queue_type == '1':
        fields  = "".join(["series.name,",
                           "series.description,",
                           "series.series_id,",
                           "series.rating,",
                           "series.media_count,",
                           "series.url,",
                           "series.publisher_name,",
                           "series.year,",
                           "series.portrait_image,",
                           "image.large_url,",
                           "series.landscape_image,",
                           "image.full_url"])
        options = {'media_types': "anime|drama",
                   'fields':      fields}

        request = makeAPIRequest(args, 'queue', options)

        log("CR: Queue: request['error'] = " + str(request['error']))
        if request['error'] is False:
            log("CR: Queue: has %d series" % len(request['data']))

            # Cache series
            args.user_data['queue'] = [col['series']['series_id']
                                           for col in request['data']]

            for series in request['data']:
                series = series['series']
                # Only available for some series
                year   = ('None'
                              if series['year'] is None
                              else series['year'])
                desc   = (''
                              if series['description'] is None
                              else series['description'].encode('utf-8'))

                thumb  = (''
                              if (series['portrait_image'] is None or
                                  series['portrait_image']['large_url'] is None or
                                  'portrait_image' not in series or
                                  'large_url' not in series['portrait_image'])
                              else series['portrait_image']['full_url'])
                art    = (''
                              if (series['landscape_image'] is None or
                                  series['landscape_image']['full_url'] is None or
                                  'landscape_image' not in series or
                                  'full_url' not in series['landscape_image'])
                              else series['landscape_image']['full_url'])
                rating = ('0'
                              if (series['rating'] == '' or
                                  'rating' not in series)
                              else series['rating'])

                # Crunchyroll seems to like passing series
                # without these things
                if ('media_count' in series and
                    'series_id' in series and
                    'name' in series and
                    series['media_count'] > 0):

                    crm.add_item(args,
                                 {'title':        series['name'].encode("utf8"),
                                  'mode':         'list_coll',
                                  'series_id':    series['series_id'],
                                  'thumb':        thumb,
                                  'fanart_image': art,
                                  'plot':         desc,
                                  'year':         year},
                                 isFolder=True,
                                 queued=True)

                    log("CR: Queue: series = '%s' queued"
                        % series['name'].encode('latin-1', 'ignore'), xbmc.LOGDEBUG)

                else:
                    log("CR: Queue: series not queued!", xbmc.LOGDEBUG)

            crm.endofdirectory('none')
def list_media_items(args, request, series_name, season, mode, fanart):
    """List video episodes.

    """
    for media in request:
        queued = ((media['series']['series_id']
                       if mode == "history"
                       else args.series_id) in args.user_data['queue'])

        # The following are items to help display Recently Watched
        # and Queue items correctly
        season      = (media['collection']['season']
                           if mode == "history"
                           else season)
        series_name = (media['series']['name']
                           if mode == "history"
                           else series_name)
        series_name = (media['most_likely_media']['series_name']
                           if mode == "queue"
                           else series_name)
        # On history/queue, the fanart is obtained directly from the json
        fanart      = (media['series']['landscape_image']['fwide_url']
                           if (mode == "history" or mode == "queue")
                           else fanart)
        # History media is one level deeper in the json string
        # than normal media items
        media       = (media['media']
                           if mode == "history"
                           else media)

        # Some queue items don't have most_likely_media, skip them
        if mode == "queue" and 'most_likely_media' not in media:
            continue

        # Queue media is one level deeper in the json string
        # than normal media items
        media = media['most_likely_media'] if mode == "queue" else media

        current_datetime   = datetime.datetime.now(dateutil.tz.tzutc())
        available_datetime = dateutil.parser.parse(media['available_time'])
        available_datetime = available_datetime.astimezone(dateutil.tz.tzlocal())
        available_date     = available_datetime.date()
        available_delta    = available_datetime - current_datetime
        available_in       = (str(available_delta.days) + " days."
                                  if available_delta.days > 0
                                  else str(available_delta.seconds/60/60)
                                      + " hours.")

        # Fix Crunchyroll inconsistencies & add details for upcoming or
        # unreleased episodes.
        # PV episodes have no episode number so we set it to 0.
        media['episode_number'] = ('0'
                                       if media['episode_number'] == ''
                                       else media['episode_number'])
        # CR puts letters into some rare episode numbers
        media['episode_number'] = re.sub('\D', '', media['episode_number'])

        if media['episode_number'] == '0':
            name = ("NO NAME"
                        if media['name'] == ''
                        else media['name'])
        else:
            # CR doesn't seem to include episode names for all media,
            # make one up
            name = ("Episode " + str(media['episode_number'])
                        if media['name'] == ''
                        else "Episode " + media['episode_number'] + " - "
                            + media['name'])

        name = (series_name + " " + name
                    if (mode == "history" or
                        mode == "queue")
                    else name)
        name = ("* " + name
                    if media['free_available'] is False
                    else name)
        soon = ("Coming Soon - " + series_name
                + " Episode " + str(media['episode_number'])
                    if mode == "queue"
                    else "Coming Soon - Episode "
                        + str(media['episode_number']))
        # Set the name for upcoming episode
        name = soon if media['available'] is False else name

        # Not all shows have thumbnails
        thumb = ("http://static.ak.crunchyroll.com/i/no_image_beta_full.jpg"
                     if media['screenshot_image'] is None
                     else media['screenshot_image']['fwide_url']
                         if media['free_available'] is True
                         else media['screenshot_image']['fwidestar_url'])
        # Sets the thumbnail to coming soon if the episode
        # isn't available yet
        thumb = ("http://static.ak.crunchyroll.com/i/coming_soon_beta_fwide.jpg"
                     if media['available'] is False
                     else thumb)

        description = (''
                           if media['description'] is None
                           else media['description'].encode('utf-8'))
        # Set the description for upcoming episodes
        description = ("This episode will be available in " + str(available_in)
                           if media['available'] is False
                           else description)

        duration = ("0"
                        if media['available'] is False
                        else str(media['duration']))
        # Current playback point
        playhead = ("0"
                        if media['available'] is False
                        else str(media['playhead']))

        # Adding published date instead
        year = ('None'
                    if media['available_time'] is None
                    else media['available_time'][:10])

        url = media['url']
        media_id = url.split('-')[-1]

        crm.add_item(args,
                     {'title':        name.encode("utf8"),
                      'mode':         'videoplay',
                      'id':           media_id.encode("utf8"),
                      'thumb':        thumb.encode("utf8"),
                      'url':          url.encode("utf8"),
                      'fanart_image': fanart,
                      'plot':         description,
                      'year':         year,
                      'playhead':     playhead,
                      'duration':     duration},
                     isFolder=False,
                     queued=queued)

    crm.endofdirectory('none')
def list_series(args):
    """List series.

    """
    fields  = "".join(["series.name,",
                       "series.description,",
                       "series.series_id,",
                       "series.rating,",
                       "series.media_count,",
                       "series.url,",
                       "series.publisher_name,",
                       "series.year,",
                       "series.portrait_image,",
                       "image.large_url,",
                       "series.landscape_image,",
                       "image.full_url"])
    options = {'media_type': args.media_type,
               'filter':     args.filterx,
               'fields':     fields,
               'limit':      '64',
               'offset':     int(args.offset)}

    request = makeAPIRequest(args, 'list_series', options)

    if request['error'] is False:
        counter = 0
        for series in request['data']:
            counter = counter + 1

            # Only available on some series
            year   = ('None'
                          if series['year'] is None
                          else series['year'])
            desc   = (''
                          if series['description'] is None
                          else series['description'].encode('utf-8'))
            thumb  = (''
                          if (series['portrait_image'] is None or
                              series['portrait_image']['large_url'] is None or
                              'portrait_image' not in series or
                              'large_url' not in series['portrait_image'])
                          else series['portrait_image']['full_url'])
            art    = (''
                          if (series['landscape_image'] is None or
                              series['landscape_image']['full_url'] is None or
                              'landscape_image' not in series or
                              'full_url' not in series['landscape_image'])
                          else series['landscape_image']['full_url'])
            rating = ('0'
                          if (series['rating'] == '' or
                              'rating' not in series)
                          else series['rating'])

            # Crunchyroll seems to like passing series
            # without these things
            if ('media_count' in series and
                'series_id' in series and
                'name' in series and
                series['media_count'] > 0):

                queued = (series['series_id'] in args.user_data['queue'])

                crm.add_item(args,
                             {'title':        series['name'].encode("utf8"),
                              'mode':         'list_coll',
                              'series_id':    series['series_id'],
                              'count':        str(series['media_count']),
                              'thumb':        thumb,
                              'fanart_image': art,
                              'plot':         desc,
                              'year':         year},
                             isFolder=True,
                             queued=queued)

        if counter >= 64:
            offset = str(int(args.offset) + counter)
            crm.add_item(args,
                         {'title':      '...load more',
                          'mode':       'list_series',
                          'media_type': args.media_type,
                          'filterx':    args.filterx,
                          'offset':     offset})

    crm.endofdirectory('none')