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')
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
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: 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')
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')
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')