From 0c537afaf6f621b82c8d12137640315569cb7f5a Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Tue, 10 Aug 2021 09:34:13 -0400 Subject: [PATCH] #347 Added mal_genre and mal_producer builders --- modules/builder.py | 42 +++++++++++++++++++++++------------- modules/mal.py | 53 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/modules/builder.py b/modules/builder.py index 95194131..3bc8a45e 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -137,7 +137,7 @@ custom_sort_builders = [ "anidb_popular", "anilist_top_rated", "anilist_popular", "anilist_season", "anilist_studio", "anilist_genre", "anilist_tag", "mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special", - "mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season" + "mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_producer" ] class CollectionBuilder: @@ -801,22 +801,34 @@ class CollectionBuilder: self.builders.append((method_name, util.parse(method_name, method_data, datatype="int", default=10))) elif method_name in ["mal_season", "mal_userlist"]: for dict_data, dict_methods in util.parse(method_name, method_data, datatype="dictlist"): - new_dictionary = {} if method_name == "mal_season": - if self.current_time.month in [1, 2, 3]: new_dictionary["season"] = "winter" - elif self.current_time.month in [4, 5, 6]: new_dictionary["season"] = "spring" - elif self.current_time.month in [7, 8, 9]: new_dictionary["season"] = "summer" - elif self.current_time.month in [10, 11, 12]: new_dictionary["season"] = "fall" - new_dictionary["season"] = util.parse("season", dict_data, methods=dict_methods, parent=method_name, default=new_dictionary["season"], options=["winter", "spring", "summer", "fall"]) - new_dictionary["sort_by"] = util.parse("sort_by", dict_data, methods=dict_methods, parent=method_name, default="members", options=mal.season_sort_options, translation=mal.season_sort_translation) - new_dictionary["year"] = util.parse("year", dict_data, datatype="int", methods=dict_methods, default=self.current_time.year, parent=method_name, minimum=1917, maximum=self.current_time.year + 1) - new_dictionary["limit"] = util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=100, parent=method_name, maximum=500) + if self.current_time.month in [1, 2, 3]: default_season = "winter" + elif self.current_time.month in [4, 5, 6]: default_season = "spring" + elif self.current_time.month in [7, 8, 9]: default_season = "summer" + else: default_season = "fall" + self.builders.append((method_name, { + "season": util.parse("season", dict_data, methods=dict_methods, parent=method_name, default=default_season, options=["winter", "spring", "summer", "fall"]), + "sort_by": util.parse("sort_by", dict_data, methods=dict_methods, parent=method_name, default="members", options=mal.season_sort_options, translation=mal.season_sort_translation), + "year": util.parse("year", dict_data, datatype="int", methods=dict_methods, default=self.current_time.year, parent=method_name, minimum=1917, maximum=self.current_time.year + 1), + "limit": util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=100, parent=method_name, maximum=500) + })) elif method_name == "mal_userlist": - new_dictionary["username"] = util.parse("username", dict_data, methods=dict_methods, parent=method_name) - new_dictionary["status"] = util.parse("status", dict_data, methods=dict_methods, parent=method_name, default="all", options=mal.userlist_status) - new_dictionary["sort_by"] = util.parse("sort_by", dict_data, methods=dict_methods, parent=method_name, default="score", options=mal.userlist_sort_options, translation=mal.userlist_sort_translation) - new_dictionary["limit"] = util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=100, parent=method_name, maximum=1000) - self.builders.append((method_name, new_dictionary)) + self.builders.append((method_name, { + "username": util.parse("username", dict_data, methods=dict_methods, parent=method_name), + "status": util.parse("status", dict_data, methods=dict_methods, parent=method_name, default="all", options=mal.userlist_status), + "sort_by": util.parse("sort_by", dict_data, methods=dict_methods, parent=method_name, default="score", options=mal.userlist_sort_options, translation=mal.userlist_sort_translation), + "limit": util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=100, parent=method_name, maximum=1000) + })) + elif method_name in ["mal_genre", "mal_producer"]: + id_name = f"{method_name[4:]}_id" + final_data = [] + for data in util.get_list(method_data): + final_data.append(data if isinstance(data, dict) else {id_name: data, "limit": 0}) + for dict_data, dict_methods in util.parse(method_name, method_data, datatype="dictlist"): + self.builders.append((method_name, { + id_name: util.parse(id_name, dict_data, datatype="int", methods=dict_methods, parent=method_name, maximum=999999), + "limit": util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=0, parent=method_name) + })) def _plex(self, method_name, method_data): if method_name == "plex_all": diff --git a/modules/mal.py b/modules/mal.py index 1df5c2fa..b86f6f13 100644 --- a/modules/mal.py +++ b/modules/mal.py @@ -1,4 +1,4 @@ -import logging, re, secrets, webbrowser +import logging, re, secrets, time, webbrowser from modules import util from modules.util import Failed, TimeoutExpired from ruamel import yaml @@ -6,8 +6,8 @@ from ruamel import yaml logger = logging.getLogger("Plex Meta Manager") builders = [ - "mal_id", "mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_ova", "mal_movie", - "mal_special", "mal_popular", "mal_favorite", "mal_season", "mal_suggested", "mal_userlist" + "mal_id", "mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_ova", "mal_movie", "mal_special", + "mal_popular", "mal_favorite", "mal_season", "mal_suggested", "mal_userlist", "mal_genre", "mal_producer" ] mal_ranked_name = { "mal_all": "all", "mal_airing": "airing", "mal_upcoming": "upcoming", "mal_tv": "tv", "mal_ova": "ova", @@ -17,7 +17,7 @@ mal_ranked_pretty = { "mal_all": "MyAnimeList All", "mal_airing": "MyAnimeList Airing", "mal_upcoming": "MyAnimeList Upcoming", "mal_tv": "MyAnimeList TV", "mal_ova": "MyAnimeList OVA", "mal_movie": "MyAnimeList Movie", "mal_special": "MyAnimeList Special", "mal_popular": "MyAnimeList Popular", - "mal_favorite": "MyAnimeList Favorite" + "mal_favorite": "MyAnimeList Favorite", "mal_genre": "MyAnimeList Genre", "mal_producer": "MyAnimeList Producer" } season_sort_translation = {"score": "anime_score", "anime_score": "anime_score", "members": "anime_num_list_users", "anime_num_list_users": "anime_num_list_users"} season_sort_options = ["score", "members"] @@ -35,6 +35,7 @@ userlist_sort_translation = { userlist_sort_options = ["score", "last_updated", "title", "start_date"] userlist_status = ["all", "watching", "completed", "on_hold", "dropped", "plan_to_watch"] base_url = "https://api.myanimelist.net" +jiken_base_url = "https://api.jikan.moe/v3" urls = { "oauth_token": f"https://myanimelist.net/v1/oauth2/token", "oauth_authorize": f"https://myanimelist.net/v1/oauth2/authorize", @@ -131,6 +132,11 @@ class MyAnimeList: if "error" in response: raise Failed(f"MyAnimeList Error: {response['error']}") else: return response + def _jiken_request(self, url): + data = self.config.get_json(f"{jiken_base_url}{url}") + time.sleep(2) + return data + def _parse_request(self, url): data = self._request(url) return [d["node"]["id"] for d in data["data"]] if "data" in data else [] @@ -155,6 +161,39 @@ class MyAnimeList: url = f"{urls['user']}/{username}/animelist?{final_status}sort={sort_by}&limit={limit}" return self._parse_request(url) + def _genre(self, genre_id, limit): + data = self._jiken_request(f"/genre/anime/{genre_id}") + if "item_count" not in data: + raise Failed(f"MyAnimeList Error: No MyAnimeList IDs for Genre ID: {genre_id}") + total_items = data["item_count"] + if total_items < limit or limit <= 0: + limit = total_items + mal_ids = [] + for i in range(1, int(((total_items - 1) / 100) + 2)): + if i > 1: + data = self._jiken_request(f"/genre/anime/{genre_id}/{i}") + mal_ids.extend([anime["mal_id"] for anime in data["anime"]]) + if len(mal_ids) > limit: + return mal_ids[:limit] + return mal_ids + + def _producer(self, producer_id, limit): + data = self._jiken_request(f"/producer/{producer_id}") + if "anime" not in data: + raise Failed(f"MyAnimeList Error: No MyAnimeList IDs for Producer ID: {producer_id}") + mal_ids = [] + count = 1 + while True: + if count > 1: + data = self._jiken_request(f"/producer/{producer_id}/{count}") + if "anime" not in data: + break + mal_ids.extend([anime["mal_id"] for anime in data["anime"]]) + if len(mal_ids) > limit > 0: + return mal_ids[:limit] + count += 1 + return mal_ids + def get_mal_ids(self, method, data): if method == "mal_id": logger.info(f"Processing MyAnimeList ID: {data}") @@ -162,6 +201,12 @@ class MyAnimeList: elif method in mal_ranked_name: logger.info(f"Processing {mal_ranked_pretty[method]}: {data} Anime") mal_ids = self._ranked(mal_ranked_name[method], data) + elif method == "mal_genre": + logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['genre_id']}") + mal_ids = self._genre(data["genre_id"], data["limit"]) + elif method == "mal_producer": + logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['producer_id']}") + mal_ids = self._producer(data["producer_id"], data["limit"]) elif method == "mal_season": logger.info(f"Processing MyAnimeList Season: {data['limit']} Anime from {util.pretty_seasons[data['season']]} {data['year']} sorted by {pretty_names[data['sort_by']]}") mal_ids = self._season(data["season"], data["year"], data["sort_by"], data["limit"])