diff --git a/Contents/Code/__init__.py b/Contents/Code/__init__.py index cbe5fcd..7b1d98b 100644 --- a/Contents/Code/__init__.py +++ b/Contents/Code/__init__.py @@ -1,5 +1,5 @@ from search import search_anime -from update import update_anime +from update import update_anime, update_movie EN = Locale.Language.English @@ -25,7 +25,7 @@ def search(self, results, media, lang, manual): search_anime('tv', results, media, lang) def update(self, metadata, media, lang, force): - update_anime('tv', metadata, media, force) + update_anime(metadata, media, force) class AniListMovie(Agent.Movies): @@ -40,4 +40,4 @@ def search(self, results, media, lang, manual): search_anime('movie', results, media, lang) def update(self, metadata, media, lang, force): - update_anime('movie', metadata, media, force) + update_movie(metadata, media, force) diff --git a/Contents/Code/providers.py b/Contents/Code/providers.py index 111adc2..e6db03e 100644 --- a/Contents/Code/providers.py +++ b/Contents/Code/providers.py @@ -1,15 +1,14 @@ -from datetime import datetime from time import sleep import certifi import requests - def get_anime(id): query = ''' query { Page { media(id: ''' + id + ''') { genres + duration episodes averageScore description @@ -110,27 +109,27 @@ def get_anime(id): def get_episodes(id): - sleep(4) + sleep(4) #TODO: Rate limit FIX anime_episodes = {} - - mal_request = requests.get( - 'https://api.jikan.moe/v3/anime/' + id + '/episodes', - verify=certifi.where() - ).content - episodes = JSON.ObjectFromString(mal_request) - + page = 1 + has_next_page = True try: - mal_request = requests.get( - 'https://api.jikan.moe/v3/anime/' + id + '/episodes', - verify=certifi.where() - ).content - episodes = JSON.ObjectFromString(mal_request) - - for episode in episodes['episodes']: - if not episode['recap']: - anime_episodes[episode['episode_id']] = episode - + while has_next_page: + episodes = get_episode_data(id, page) + has_next_page = episodes['pagination']['has_next_page'] + page += 1 + for episode in episodes['data']: + if not episode['recap']: + anime_episodes[episode['mal_id']] = episode return anime_episodes except: Log.Error('Error getting mal data') return + +def get_episode_data(id, page): + + mal_request = requests.get( + 'https://api.jikan.moe/v4/anime/' + id + '/episodes?page=' + str(page), + verify=certifi.where() + ).content + return JSON.ObjectFromString(mal_request) \ No newline at end of file diff --git a/Contents/Code/search.py b/Contents/Code/search.py index f48adce..b0f27a7 100644 --- a/Contents/Code/search.py +++ b/Contents/Code/search.py @@ -1,7 +1,7 @@ from utils import requests_retry_session import certifi import re - + def search_anime(type, results, media, lang): search_term = media.show if type == 'tv' else media.name @@ -77,7 +77,6 @@ def search_anime(type, results, media, lang): id=str(result['id']), name=result['title']['romaji'], year=result['startDate']['year'], - thumb=result['coverImage']['extraLarge'], score=s, lang=lang )) diff --git a/Contents/Code/update.py b/Contents/Code/update.py index b0a6c33..bc5c672 100644 --- a/Contents/Code/update.py +++ b/Contents/Code/update.py @@ -11,13 +11,119 @@ # Python 3 from html.parser import HTMLParser +def update_generic(metadata, media, force, anime): -def update_anime(type, metadata, media, force): - resp = get_anime(metadata.id) - Log.Debug("Anilist Response: {}".format(resp)) - result = JSON.ObjectFromString(resp) + # genres + if metadata.genres is None or force: + try: + metadata.genres = anime['genres'] + except: + Log.Error('Error: Show has no genres: ' + metadata.id) + + try: + for tag in anime['tags']: + metadata.genres.add(tag['name']) + except: + Log.Error('Error: Show has no tags: ' + metadata.id) + + try: + metadata.genres.add(anime['format']) + except: + Log.Error('Error: Show has no format: ' + metadata.id) + + try: + metadata.genres.add(anime['status']) + except: + Log.Error('Error: Show has no status: ' + metadata.id) + + try: + metadata.genres.add(str(str(anime['seasonYear']) + ' ' + anime['season'])) + except: + Log.Error('Error: Show has no season or seasonYear: ' + metadata.id) + + + # tags + + # collections + + # reviews + if metadata.reviews is None or force: + metadata.reviews.clear() + try: + for review in anime['reviews']['edges']: + + # Create new review + r = metadata.reviews.new() + + # Set Review Author + try: + r.author = review['node']['user']['name'] + except: + pass + + # Set Review Source + r.source = 'AniList' + + # Set Review Image + try: + if int(review['node']['score']) >= 50: + r.image = 'rottentomatoes://image.review.fresh' + else: + r.image = 'rottentomatoes://image.review.rotten' + except: + pass + + # Set Review Link + try: + r.link = review['node']['siteUrl'] + except: + pass + + # Set Review Text + try: + r.text = review['node']['summary'] + except: + pass + except: + Log.Error('Error: Show has no reviews: ' + metadata.id) + + # duration + if metadata.duration is None or force: + try: + metadata.duration = anime['duration'] + except: + Log.Error('Error: Show has no duration: ' + metadata.id) + + # rating + if metadata.rating is None or force: + try: + metadata.rating = float(anime['averageScore']) / 10 + except: + Log.Error('Error: Show has no rating: ' + metadata.id) + + # audience_rating + + # rating_image + + # audience_rating_image + + # original_title + + # title_sort + + # rating_count + + # key + + # rating_key + + # source_title + +def update_anime(metadata, media, force): + result = JSON.ObjectFromString(get_anime(metadata.id)) anime = result['data']['Page']['media'][0] has_mal_page = True + # Get episode data if Prefs['episode_support']: try: @@ -28,31 +134,45 @@ def update_anime(type, metadata, media, force): else: has_mal_page = False - # Genres - metadata.genres.clear() - try: - metadata.genres = anime['genres'] + anime['tags'] + [anime['format']] + [ - anime['status']] + [anime['season'] + ' ' + anime['seasonYear']] - except: - Log.Error('Error: Show has no genres: ' + metadata.id) - - # Rating - if metadata.rating is None or force: - try: - metadata.rating = float(anime['averageScore']) / 10 - except: - Log.Error('Error: Show has no rating: ' + metadata.id) + update_generic(metadata, media, force, anime) - # Title + # title if metadata.title is None or force: - title_language = Prefs['title_language'] for language in anime['title']: - if language == title_language: + if language == Prefs['title_language']: metadata.title = anime['title'][language] break metadata.title = anime['title'][language] - # Posters + # summary + if metadata.summary is None or force: + try: + h = HTMLParser() + cleanr = re.compile('<.*?>') + metadata.summary = re.sub( + cleanr, '', h.unescape(anime['description'])) + except: + Log.Error('Error: Show has no summary: ' + metadata.id) + + # originally_available_at + if metadata.originally_available_at is None or force: + try: + metadata.originally_available_at = datetime( + anime['startDate']['year'], anime['startDate']['month'], anime['startDate']['day']) + except: + Log.Error('Error: Show has no start date: ' + metadata.id) + + # content_rating + + # studio + if metadata.studio is None or force: + try: + #TODO: Plex does not support multiple studios + metadata.studio = anime['studios']['edges'][0]['node']['name'] + except: + Log.Error('Error: Show has multiple or no studio: ' + metadata.id) + + # posters if metadata.posters is None or force: try: poster = Proxy.Media( @@ -61,22 +181,100 @@ def update_anime(type, metadata, media, force): verify=certifi.where() ).content ) - metadata.posters.validate_keys([]) + metadata.posters.validate_keys([]) #TODO: VERIFY metadata.posters[anime['coverImage']['extraLarge']] = poster except: Log.Error('Error: Show has no posters: ' + metadata.id) - # Summary - if metadata.summary is None or force: + # banners + if metadata.banners is None or force: try: - h = HTMLParser() - cleanr = re.compile('<.*?>') - metadata.summary = re.sub( - cleanr, '', h.unescape(anime['description'])) + banner_hash = base64.b64encode(str(anime['bannerImage'])) + banner = Proxy.Media( + requests_retry_session().get( + anime['bannerImage'], + verify=certifi.where() + ).content + ) + metadata.banners[banner_hash] = banner except: - Log.Error('Error: Show has no summary: ' + metadata.id) + Log.Error('Error: Show has no banners: ' + metadata.id) + + # art + if metadata.art is None or force: + try: + banner_hash = base64.b64encode(str(anime['bannerImage'])) + banner = Proxy.Media( + requests_retry_session().get( + anime['bannerImage'], + verify=certifi.where() + ).content + ) + metadata.art[banner_hash] = banner + except: + Log.Error('Error: Show has no banners: ' + metadata.id) - # Country + # themes + + # seasons + + # roles + if metadata.roles is None or force: + try: + for character in anime['characters']['edges']: + # Create new role + role = metadata.roles.new() + + # Get correct VA + for VA in character['voiceActors']: + + # Set VA Name + try: + role.name = VA['name']['full'] + except: + pass + + # Set VA Photo + try: + role.photo = VA['image']['large'] + except: + pass + + # Set Character Name + try: + role.role = character['node']['name']['full'] + except: + pass + except: + Log.Error('Error: Show has no Characters: ' + metadata.id) + + try: + for staff in anime['staff']['edges']: + + # Create new role + role = metadata.roles.new() + + # Set Staff Name + try: + role.name = staff['node']['name']['full'] + except: + pass + + # Set Staff Photo + try: + role.photo = staff['node']['image']['large'] + except: + pass + + # Set Staff Role + try: + role.role = staff['role'] + except: + pass + except: + Log.Error('Error: Show has no staff: ' + metadata.id) + + # countries if metadata.countries is None or force: try: if anime['countryOfOrigin'] == 'JP': @@ -90,7 +288,44 @@ def update_anime(type, metadata, media, force): except: Log.Error('Error: Show has no country of origin: ' + metadata.id) - # Start Date + # extras + + # similar + + # thumb + + # art_url + + # episode_count + + # viewed_episode_count + + # has episodes? + if Prefs['episode_support'] and has_mal_page and 1 in media.seasons: + update_episodes(media, metadata, force, mal_episodes) + +def update_movie(metadata, media, force): + result = JSON.ObjectFromString(get_anime(metadata.id)) + anime = result['data']['Page']['media'][0] + + update_generic(metadata, media, force, anime) + + # title + if metadata.title is None or force: + for language in anime['title']: + if language == Prefs['title_language']: + metadata.title = anime['title'][language] + break + metadata.title = anime['title'][language] + + # year + if metadata.year is None or force: + try: + metadata.year = anime['startDate']['year'] + except: + Log.Error('Error: Show has no start date: ' + metadata.id) + + # originally_available_at if metadata.originally_available_at is None or force: try: metadata.originally_available_at = datetime( @@ -98,17 +333,67 @@ def update_anime(type, metadata, media, force): except: Log.Error('Error: Show has no start date: ' + metadata.id) - # Studio + # studio if metadata.studio is None or force: try: metadata.studio = anime['studios']['edges'][0]['node']['name'] except: Log.Error('Error: Show has no studio: ' + metadata.id) - if metadata.roles is None or force: - metadata.roles.clear() + # tagline - # Characters + # summary + if metadata.summary is None or force: + try: + h = HTMLParser() + cleanr = re.compile('<.*?>') + metadata.summary = re.sub( + cleanr, '', h.unescape(anime['description'])) + except: + Log.Error('Error: Show has no summary: ' + metadata.id) + + # trivia + + # quotes + + # content_rating + + # content_rating_age + + # writers + if metadata.writers is None or force: + try: + for staff in anime['staff']['edges']: + # Create new role + if staff['role'] == 'Original Creator': + writer = metadata.writers.new() + writer.name = staff['node']['name']['full'] + except: + Log.Error('Error: Show has no Writers: ' + metadata.id) + + # directors + if metadata.directors is None or force: + try: + for staff in anime['staff']['edges']: + # Create new role + if staff['role'] == 'Director': + director = metadata.directors.new() + director.name = staff['node']['name']['full'] + except: + Log.Error('Error: Show has no Directors: ' + metadata.id) + + # producers + if metadata.producers is None or force: + try: + for staff in anime['staff']['edges']: + # Create new role + if staff['role'] == 'Producer': + producer = metadata.producers.new() + producer.name = staff['node']['name']['full'] + except: + Log.Error('Error: Show has no Producers: ' + metadata.id) + + # roles if metadata.roles is None or force: try: for character in anime['characters']['edges']: @@ -138,8 +423,6 @@ def update_anime(type, metadata, media, force): except: Log.Error('Error: Show has no Characters: ' + metadata.id) - # Staff - if metadata.roles is None or force: try: for staff in anime['staff']['edges']: @@ -166,147 +449,110 @@ def update_anime(type, metadata, media, force): except: Log.Error('Error: Show has no staff: ' + metadata.id) - # Reviews - if metadata.reviews is None or force: - metadata.reviews.clear() + # countries + if metadata.countries is None or force: try: - for review in anime['reviews']['edges']: - - # Create new review - r = metadata.reviews.new() - - # Set Review Author - try: - r.author = review['node']['user']['name'] - except: - pass - - # Set Review Source - r.source = 'AniList' - - # Set Review Image - try: - if int(review['node']['score']) >= 50: - r.image = 'rottentomatoes://image.review.fresh' - else: - r.image = 'rottentomatoes://image.review.rotten' - except: - pass - - # Set Review Link - try: - r.link = review['node']['siteUrl'] - except: - pass - - # Set Review Text - try: - r.text = review['node']['summary'] - except: - pass + if anime['countryOfOrigin'] == 'JP': + metadata.countries = ['Japan'] + elif anime['countryOfOrigin'] == 'CN': + metadata.countries = ['China'] + elif anime['countryOfOrigin'] == 'KR': + metadata.countries = ['Korea'] + else: + metadata.countries = ['Unknown, please report'] except: - Log.Error('Error: Show has no reviews: ' + metadata.id) - - # TV Specific - if type == 'tv': + Log.Error('Error: Show has no country of origin: ' + metadata.id) - # Banners - if metadata.banners is None or metadata.art is None or force: - try: - banner_hash = base64.b64encode(str(anime['bannerImage'])) - banner = Proxy.Media( - requests_retry_session().get( - anime['bannerImage'], - verify=certifi.where() - ).content - ) - except: - Log.Error('Error: Show has no banners: ' + metadata.id) - if metadata.banners is None or force: - metadata.banners[banner_hash] = banner - if metadata.art is None or force: - metadata.art[banner_hash] = banner + # posters + if metadata.posters is None or force: + try: + poster = Proxy.Media( + requests_retry_session().get( + anime['coverImage']['extraLarge'], + verify=certifi.where() + ).content + ) + metadata.posters.validate_keys([]) #TODO: VERIFY + metadata.posters[anime['coverImage']['extraLarge']] = poster + except: + Log.Error('Error: Show has no posters: ' + metadata.id) - # Episodes - if Prefs['episode_support'] and has_mal_page and 1 in media.seasons: - update_episodes(media, metadata, force, mal_episodes) + # art + if metadata.art is None or force: + try: + banner_hash = base64.b64encode(str(anime['bannerImage'])) + banner = Proxy.Media( + requests_retry_session().get( + anime['bannerImage'], + verify=certifi.where() + ).content + ) + metadata.art[banner_hash] = banner + except: + Log.Error('Error: Show has no banners: ' + metadata.id) - # Movie Specific - if type == 'movie': + # banners + if metadata.banners is None or force: + try: + banner_hash = base64.b64encode(str(anime['bannerImage'])) + banner = Proxy.Media( + requests_retry_session().get( + anime['bannerImage'], + verify=certifi.where() + ).content + ) + metadata.banners[banner_hash] = banner + except: + Log.Error('Error: Show has no banners: ' + metadata.id) - if metadata.art is None or force: - try: - banner_hash = base64.b64encode(str(anime['bannerImage'])) - banner = Proxy.Media( - requests_retry_session().get( - anime['bannerImage'], - verify=certifi.where() - ).content - ) - metadata.art[banner_hash] = banner - except: - Log.Error('Error: Show has no banners: ' + metadata.id) + # themes - # Year - if metadata.year is None or force: - try: - metadata.year = anime['startDate']['year'] - except: - Log.Error('Error: Show has no start date: ' + metadata.id) + # chapters - # Roles - if metadata.roles is None or force: + # extras - # Staff - try: - for staff in anime['staff']['edges']: + # similar - # Director - try: - if staff['role'] == 'Director': - director = metadata.directors.new() - director.name = staff['node']['name']['full'] - except: - pass - except: - Log.Error('Error: Show has no staff: ' + metadata.id) + # thumb + # art_url def update_episodes(media, metadata, force, mal_episodes): for plex_episode_number in media.seasons[1].episodes: try: episode = metadata.seasons[1].episodes[int(plex_episode_number)] mal_episode = mal_episodes.get(int(plex_episode_number)) - except: - Log.Error('Error: could not get episode data') - try: - # # Title - if episode.title is None or force: - if Prefs['episode_title_language'] == 'default' and mal_episode['title']: - episode.title = mal_episode['title'] - elif Prefs['episode_title_language'] == 'japanese' and mal_episode['title_japanese']: - episode.title = mal_episode['title_japanese'] - elif Prefs['episode_title_language'] == 'romaji' and mal_episode['title_romaji']: - episode.title = mal_episode['title_romaji'] - else: - if mal_episode['title']: + + try: + # Title + if episode.title is None or force: + if Prefs['episode_title_language'] == 'default' and mal_episode['title']: episode.title = mal_episode['title'] - elif mal_episode['title_romanji']: - episode.title = mal_episode['title_romanji'] - elif mal_episode['title_japanese']: + elif Prefs['episode_title_language'] == 'japanese' and mal_episode['title_japanese']: episode.title = mal_episode['title_japanese'] + elif Prefs['episode_title_language'] == 'romaji' and mal_episode['title_romaji']: + episode.title = mal_episode['title_romaji'] + else: + if mal_episode['title']: + episode.title = mal_episode['title'] + elif mal_episode['title_romanji']: + episode.title = mal_episode['title_romanji'] + elif mal_episode['title_japanese']: + episode.title = mal_episode['title_japanese'] + except: + Log.Error('Error: Episode has no title: ' + + metadata.id + ' Episode:' + str(plex_episode_number)) + + # Air date + try: + if mal_episode and mal_episode['aired'] and episode.originally_available_at is None or force: + cleanr = re.compile('\+[0-9][0-9]:[0-9][0-9]') + timestr = re.sub(cleanr, '', mal_episode['aired']) + episode.originally_available_at = datetime.strptime(timestr, '%Y-%m-%dT%H:%M:%S') + except: + Log.Error('Error: Episode has no air date: ' + metadata.id + ' Episode:' + str(plex_episode_number)) except: - Log.Error('Error: Episode has no title: ' + - metadata.id + ' Episode:' + str(plex_episode_number)) + Log.Error('Error: could not get episode data') + - # Air date - if mal_episode and episode.originally_available_at is None or force: - try: - if mal_episode['aired']: - cleanr = re.compile('\+[0-9][0-9]:[0-9][0-9]') - timestr = re.sub(cleanr, '', mal_episode['aired']) - episode.originally_available_at = datetime.strptime( - timestr, '%Y-%m-%dT%H:%M:%S') - except: - Log.Error('Error: Episode has no air date: ' + - metadata.id + ' Episode:' + str(plex_episode_number)) +