def get_total(self, imdb_url, language): header = {"Accept-Language": language} if imdb_url.startswith(self.urls["keyword"]): results = self.send_request( imdb_url, header).xpath("//div[@class='desc']/text()") total = None for result in results: if "title" in result: try: total = int(re.findall("(\\d+) title", result)[0]) break except IndexError: pass if total is None: raise Failed(f"IMDb Error: No Results at URL: {imdb_url}") return total, 50 else: try: results = self.send_request(imdb_url, header).xpath( "//div[@class='desc']/span/text()")[0].replace(",", "") except IndexError: raise Failed(f"IMDb Error: Failed to parse URL: {imdb_url}") try: total = int(re.findall("(\\d+) title", results)[0]) except IndexError: raise Failed(f"IMDb Error: No Results at URL: {imdb_url}") return total, 250
def __init__(self, params): self.url = params["url"] self.token = params["token"] self.version = params["version"] self.base_url = f"{self.url}/api{'/v3' if self.version == 'v3' else ''}/" try: result = requests.get(f"{self.base_url}system/status", params={ "apikey": f"{self.token}" }).json() except Exception: util.print_stacktrace() raise Failed( f"Radarr Error: Could not connect to Radarr at {self.url}") if "error" in result and result["error"] == "Unauthorized": raise Failed("Radarr Error: Invalid API Key") if "version" not in result: raise Failed("Radarr Error: Unexpected Response Check URL") self.add = params["add"] self.root_folder_path = params["root_folder_path"] self.monitor = params["monitor"] self.availability = params["availability"] self.quality_profile_id = self.get_profile_id( params["quality_profile"]) self.tag = params["tag"] self.tags = self.get_tags() self.search = params["search"]
def get_tmdb_ids(self, method, data, language): if method == "letterboxd_list": logger.info(f"Processing Letterboxd List: {data}") items = self._parse_list(data, language) total_items = len(items) if total_items > 0: ids = [] for i, item in enumerate(items, 1): letterboxd_id, slug = item logger.ghost(f"Finding TMDb ID {i}/{total_items}") tmdb_id = None expired = None if self.config.Cache: tmdb_id, expired = self.config.Cache.query_letterboxd_map( letterboxd_id) if not tmdb_id or expired is not False: try: tmdb_id = self._tmdb(f"{base_url}{slug}", language) except Failed as e: logger.error(e) continue if self.config.Cache: self.config.Cache.update_letterboxd_map( expired, letterboxd_id, tmdb_id) ids.append((tmdb_id, "tmdb")) logger.info(f"Processed {total_items} TMDb IDs") return ids else: raise Failed( f"Letterboxd Error: No List Items found in {data}") else: raise Failed(f"Letterboxd Error: Method {method} not supported")
def _request(self, imdb_id=None, tmdb_id=None, is_movie=True, ignore_cache=False): params = {"apikey": self.apikey} if imdb_id: params["i"] = imdb_id key = imdb_id elif tmdb_id: params["tm"] = tmdb_id params["m"] = "movie" if is_movie else "show" key = f"{'tm' if is_movie else 'ts'}{tmdb_id}" else: raise Failed("MdbList Error: Either IMDb ID or TMDb ID and TMDb Type Required") expired = None if self.config.Cache and not ignore_cache: mdb_dict, expired = self.config.Cache.query_mdb(key, self.expiration) if mdb_dict and expired is False: return MDbObj(mdb_dict) if self.config.trace_mode: logger.debug(f"ID: {key}") response = self.config.get_json(api_url, params=params) if "response" in response and response["response"] is False: if response["error"] == "API Limit Reached!": self.limit = True raise Failed(f"MdbList Error: {response['error']}") else: mdb = MDbObj(response) if self.config.Cache and not ignore_cache: self.config.Cache.update_mdb(expired, key, mdb, self.expiration) return mdb
def check_for_attribute(data, attribute, parent=None, test_list=None, options="", default=None, do_print=True, default_is_none=False, req_default=False, var_type="str", throw=False, save=True): message = "" endline = "" if parent is not None: if parent in data: data = data[parent] else: data = None do_print = False save = False text = "{} attribute".format(attribute) if parent is None else "{} sub-attribute {}".format(parent, attribute) if data is None or attribute not in data: message = "{} not found".format(text) if parent and save is True: new_config, ind, bsi = yaml.util.load_yaml_guess_indent(open(self.config_path)) endline = "\n{} sub-attribute {} added to config".format(parent, attribute) if parent not in new_config: new_config = {parent: {attribute: default}} elif not new_config[parent]: new_config[parent] = {attribute: default} elif attribute not in new_config[parent]: new_config[parent][attribute] = default else: endLine = "" yaml.round_trip_dump(new_config, open(self.config_path, "w"), indent=ind, block_seq_indent=bsi) elif not data[attribute] and data[attribute] != False: if default_is_none is True: return None else: message = "{} is blank".format(text) elif var_type == "bool": if isinstance(data[attribute], bool): return data[attribute] else: message = "{} must be either true or false".format(text) elif var_type == "int": if isinstance(data[attribute], int) and data[attribute] > 0: return data[attribute] else: message = "{} must an integer > 0".format(text) elif var_type == "path": if os.path.exists(os.path.abspath(data[attribute])): return data[attribute] else: message = "Path {} does not exist".format(os.path.abspath(data[attribute])) elif var_type == "list": return util.get_list(data[attribute]) elif var_type == "listpath": temp_list = [path for path in util.get_list(data[attribute], split=True) if os.path.exists(os.path.abspath(path))] if len(temp_list) > 0: return temp_list else: message = "No Paths exist" elif var_type == "lowerlist": return util.get_list(data[attribute], lower=True) elif test_list is None or data[attribute] in test_list: return data[attribute] else: message = "{}: {} is an invalid input".format(text, data[attribute]) if var_type == "path" and default and os.path.exists(os.path.abspath(default)): return default elif var_type == "path" and default: default = None message = "neither {} or the default path {} could be found".format(data[attribute], default) if default is not None or default_is_none: message = message + " using {} as default".format(default) message = message + endline if req_default and default is None: raise Failed("Config Error: {} attribute must be set under {} globally or under this specific Library".format(attribute, parent)) if (default is None and not default_is_none) or throw: if len(options) > 0: message = message + "\n" + options raise Failed("Config Error: {}".format(message)) if do_print: util.print_multiline("Config Warning: {}".format(message)) if attribute in data and data[attribute] and test_list is not None and data[attribute] not in test_list: util.print_multiline(options) return default
def get_tvdb_ids_from_url(self, tvdb_url, language): show_ids = [] movie_ids = [] tvdb_url = tvdb_url.strip() if tvdb_url.startswith((self.list_url, self.alt_list_url)): try: items = self.send_request(tvdb_url, language).xpath("//div[@class='col-xs-12 col-sm-12 col-md-8 col-lg-8 col-md-pull-4']/div[@class='row']") for item in items: title = item.xpath(".//div[@class='col-xs-12 col-sm-9 mt-2']//a/text()")[0] item_url = item.xpath(".//div[@class='col-xs-12 col-sm-9 mt-2']//a/@href")[0] if item_url.startswith("/series/"): try: show_ids.append(self.get_series(language, tvdb_url="{}{}".format(self.site_url, item_url)).id) except Failed as e: logger.error("{} for series {}".format(e, title)) elif item_url.startswith("/movies/"): try: tmdb_id = self.get_movie(language, tvdb_url="{}{}".format(self.site_url, item_url)).tmdb_id if tmdb_id: movie_ids.append(tmdb_id) else: raise Failed("TVDb Error: TMDb ID not found from TVDb URL: {}".format(tvdb_url)) except Failed as e: logger.error("{} for series {}".format(e, title)) else: logger.error("TVDb Error: Skipping Movie: {}".format(title)) if len(show_ids) > 0 or len(movie_ids) > 0: return movie_ids, show_ids raise Failed("TVDb Error: No TVDb IDs found at {}".format(tvdb_url)) except requests.exceptions.MissingSchema as e: util.print_stacktrace() raise Failed("TVDb Error: URL Lookup Failed for {}".format(tvdb_url)) else: raise Failed("TVDb Error: {} must begin with {}".format(tvdb_url, self.list_url))
def __init__(self, tmdb, params): self.url_params = {"apikey": "{}".format(params["token"])} self.base_url = "{}/api{}".format(params["url"], "/v3/" if params["version"] == "v3" else "/") try: result = requests.get("{}system/status".format(self.base_url), params=self.url_params).json() except Exception as e: util.print_stacktrace() raise Failed("Radarr Error: Could not connect to Radarr at {}".format(params["url"])) if "error" in result and result["error"] == "Unauthorized": raise Failed("Radarr Error: Invalid API Key") if "version" not in result: raise Failed("Radarr Error: Unexpected Response Check URL") self.quality_profile_id = None profiles = "" for profile in self.send_get("{}{}".format(self.base_url, "qualityProfile" if params["version"] == "v3" else "profile")): if len(profiles) > 0: profiles += ", " profiles += profile["name"] if profile["name"] == params["quality_profile"]: self.quality_profile_id = profile["id"] if not self.quality_profile_id: raise Failed("Radarr Error: quality_profile: {} does not exist in radarr. Profiles available: {}".format(params["quality_profile"], profiles)) self.tmdb = tmdb self.url = params["url"] self.version = params["version"] self.token = params["token"] self.root_folder_path = params["root_folder_path"] self.add = params["add"] self.search = params["search"] self.tag = params["tag"]
def _request(self, query, variables, level=1): if self.config.trace_mode: logger.debug(f"Query: {query}") logger.debug(f"Variables: {variables}") response = self.config.post(base_url, json={ "query": query, "variables": variables }) json_obj = response.json() if self.config.trace_mode: logger.debug(f"Response: {json_obj}") if "errors" in json_obj: if json_obj['errors'][0]['message'] == "Too Many Requests.": wait_time = int(response.headers["Retry-After"] ) if "Retry-After" in response.headers else 0 time.sleep(wait_time if wait_time > 0 else 10) if level < 6: return self._request(query, variables, level=level + 1) raise Failed(f"AniList Error: Connection Failed") else: raise Failed( f"AniList Error: {json_obj['errors'][0]['message']}") else: time.sleep(60 / 90) return json_obj
def _request(self, webhooks, json): if self.config.trace_mode: logger.separator("Webhooks", space=False, border=False) logger.debug("") logger.debug(f"JSON: {json}") for webhook in list(set(webhooks)): response = None if self.config.trace_mode: logger.debug(f"Webhook: {webhook}") if webhook == "notifiarr": if self.notifiarr: url, params = self.notifiarr.get_url("notification/pmm/") for x in range(6): response = self.config.get(url, json=json, params=params) if response.status_code < 500: break else: response = self.config.post(webhook, json=json) if response: try: response_json = response.json() if self.config.trace_mode: logger.debug(f"Response: {response_json}") if "result" in response_json and response_json["result"] == "error" and "details" in response_json and "response" in response_json["details"]: raise Failed(f"Notifiarr Error: {response_json['details']['response']}") if response.status_code >= 400 or ("result" in response_json and response_json["result"] == "error"): raise Failed(f"({response.status_code} [{response.reason}]) {response_json}") except JSONDecodeError: if response.status_code >= 400: raise Failed(f"({response.status_code} [{response.reason}])")
def _authorization(self): url = f"https://trakt.tv/oauth/authorize?response_type=code&client_id={self.client_id}&redirect_uri={redirect_uri_encoded}" logger.info(f"Navigate to: {url}") logger.info( "If you get an OAuth error your client_id or client_secret is invalid" ) webbrowser.open(url, new=2) try: pin = util.logger_input("Trakt pin (case insensitive)", timeout=300).strip() except TimeoutExpired: raise Failed("Input Timeout: Trakt pin required.") if not pin: raise Failed("Trakt Error: No input Trakt pin required.") json = { "code": pin, "client_id": self.client_id, "client_secret": self.client_secret, "redirect_uri": redirect_uri, "grant_type": "authorization_code" } response = self.config.post( f"{base_url}/oauth/token", json=json, headers={"Content-Type": "application/json"}) if response.status_code != 200: raise Failed( "Trakt Error: Invalid trakt pin. If you're sure you typed it in correctly your client_id or client_secret may be invalid" ) elif not self._save(response.json()): raise Failed("Trakt Error: New Authorization Failed")
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 = [] num_of_pages = math.ceil(int(limit) / 100) current_page = 1 chances = 0 while current_page <= num_of_pages: if chances > 6: logger.debug(data) raise Failed("AniList Error: Connection Failed") start_num = (current_page - 1) * 100 + 1 util.print_return( f"Parsing Page {current_page}/{num_of_pages} {start_num}-{limit if current_page == num_of_pages else current_page * 100}" ) if current_page > 1: data = self._jiken_request( f"/genre/anime/{genre_id}/{current_page}") if "anime" in data: chances = 0 mal_ids.extend([anime["mal_id"] for anime in data["anime"]]) if len(mal_ids) > limit: return mal_ids[:limit] current_page += 1 else: chances += 1 util.print_end() return mal_ids
def get_authorization(self): code_verifier = secrets.token_urlsafe(100)[:128] url = f"{self.urls['oauth_authorize']}?response_type=code&client_id={self.client_id}&code_challenge={code_verifier}" logger.info("") logger.info(f"Navigate to: {url}") logger.info("") logger.info("Login and click the Allow option. You will then be redirected to a localhost") logger.info("url that most likely won't load, which is fine. Copy the URL and paste it below") webbrowser.open(url, new=2) try: url = util.logger_input("URL").strip() except TimeoutExpired: raise Failed("Input Timeout: URL required.") if not url: raise Failed("MyAnimeList Error: No input MyAnimeList code required.") match = re.search("code=([^&]+)", str(url)) if not match: raise Failed("MyAnimeList Error: Invalid URL") code = match.group(1) data = { "client_id": self.client_id, "client_secret": self.client_secret, "code": code, "code_verifier": code_verifier, "grant_type": "authorization_code" } new_authorization = self.oauth_request(data) if "error" in new_authorization: raise Failed("MyAnimeList Error: Invalid code") if not self.save_authorization(new_authorization): raise Failed("MyAnimeList Error: New Authorization Failed")
def convert_from_tmdb(self, tmdb_id, convert_to, is_movie): try: id_to_return = self.Movie.external_ids(tmdb_id)[convert_to] if is_movie else self.TV.external_ids(tmdb_id)[convert_to] if not id_to_return or (convert_to == "tvdb_id" and id_to_return == 0): raise Failed(f"TMDb Error: No {convert_to.upper().replace('B_', 'b ')} found for TMDb ID {tmdb_id}") return id_to_return except TMDbException: raise Failed(f"TMDb Error: {'Movie' if is_movie else 'Show'} TMDb ID: {tmdb_id} not found")
def _user_items(self, list_type, data, is_movie): try: items = self._request(f"/users/{data}/{list_type}/{'movies' if is_movie else 'shows'}") except Failed: raise Failed(f"Trakt Error: User {data} not found") if len(items) == 0: raise Failed(f"Trakt Error: {data}'s {list_type.capitalize()} is empty") return self._parse(items, item_type="movie" if is_movie else "show")
def _user_list(self, data): try: items = self._request(f"{requests.utils.urlparse(data).path}/items") except Failed: raise Failed(f"Trakt Error: List {data} not found") if len(items) == 0: raise Failed(f"Trakt Error: List {data} is empty") return self._parse(items)
def __init__(self, tvdb_url, language, is_movie, TVDb): tvdb_url = tvdb_url.strip() if not is_movie and tvdb_url.startswith( (TVDb.series_url, TVDb.alt_series_url, TVDb.series_id_url)): self.media_type = "Series" elif is_movie and tvdb_url.startswith( (TVDb.movies_url, TVDb.alt_movies_url, TVDb.movie_id_url)): self.media_type = "Movie" else: raise Failed("TVDb Error: {} must begin with {}".format( tvdb_url, TVDb.movies_url if is_movie else TVDb.series_url)) response = TVDb.send_request(tvdb_url, language) results = response.xpath( "//*[text()='TheTVDB.com {} ID']/parent::node()/span/text()". format(self.media_type)) if len(results) > 0: self.id = int(results[0]) else: raise Failed( "TVDb Error: Could not find a TVDb {} ID at the URL {}".format( self.media_type, tvdb_url)) results = response.xpath( "//div[@class='change_translation_text' and @data-language='eng']/@data-title" ) if len(results) > 0 and len(results[0]) > 0: self.title = results[0] else: raise Failed("TVDb Error: Name not found from TVDb URL: {}".format( tvdb_url)) results = response.xpath( "//div[@class='row hidden-xs hidden-sm']/div/img/@src") self.poster_path = results[0] if len(results) > 0 and len( results[0]) > 0 else None tmdb_id = None if is_movie: results = response.xpath("//*[text()='TheMovieDB.com']/@href") if len(results) > 0: try: tmdb_id = util.regex_first_int(results[0], "TMDb ID") except Failed as e: logger.error(e) if not tmdb_id: results = response.xpath("//*[text()='IMDB']/@href") if len(results) > 0: try: tmdb_id = TVDb.convert_from_imdb( util.get_id_from_imdb_url(results[0]), language) except Failed as e: logger.error(e) self.tmdb_id = tmdb_id self.tvdb_url = tvdb_url self.language = language self.is_movie = is_movie self.TVDb = TVDb
def mal_to_anidb(self, mal_id): anime_ids = self._arms_ids(mal_ids=mal_id) if anime_ids[0] is None: raise Failed( f"Arms Error: MyAnimeList ID: {mal_id} does not exist") if anime_ids[0]["anidb"] is None: raise Failed( f"Arms Error: No AniDB ID for MyAnimeList ID: {mal_id}") return anime_ids[0]["anidb"]
def get_item(self, data, year=None): if isinstance(data, (int, Movie, Show)): try: return self.fetchItem(data.ratingKey if isinstance(data, (Movie, Show)) else data) except BadRequest: raise Failed("Plex Error: Item {} not found".format(data)) else: item_list = self.search(title=data) if year is None else self.search(data, year=year) item = util.choose_from_list(item_list, "movie" if self.is_movie else "show", data) if item: return item else: raise Failed("Plex Error: Item {} not found".format(data))
def get_imdb_ids_from_url(self, imdb_url, language, limit): imdb_url = imdb_url.strip() if not imdb_url.startswith( self.urls["list"]) and not imdb_url.startswith( self.urls["search"]): raise Failed( f"IMDb Error: {imdb_url} must begin with either:\n| {self.urls['list']} (For Lists)\n| {self.urls['search']} (For Searches)" ) if imdb_url.startswith(self.urls["list"]): try: list_id = re.search("(\\d+)", str(imdb_url)).group(1) except AttributeError: raise Failed( f"IMDb Error: Failed to parse List ID from {imdb_url}") current_url = f"{self.urls['search']}lists=ls{list_id}" else: current_url = imdb_url header = {"Accept-Language": language} length = 0 imdb_ids = [] try: results = self.send_request( current_url, header).xpath("//div[@class='desc']/span/text()")[0].replace( ",", "") except IndexError: raise Failed(f"IMDb Error: Failed to parse URL: {imdb_url}") try: total = int(re.findall("(\\d+) title", results)[0]) except IndexError: raise Failed(f"IMDb Error: No Results at URL: {imdb_url}") if "&start=" in current_url: current_url = re.sub("&start=\\d+", "", current_url) if "&count=" in current_url: current_url = re.sub("&count=\\d+", "", current_url) if limit < 1 or total < limit: limit = total remainder = limit % 250 if remainder == 0: remainder = 250 num_of_pages = math.ceil(int(limit) / 250) for i in range(1, num_of_pages + 1): start_num = (i - 1) * 250 + 1 length = util.print_return( length, f"Parsing Page {i}/{num_of_pages} {start_num}-{limit if i == num_of_pages else i * 250}" ) response = self.send_request( f"{current_url}&count={remainder if i == num_of_pages else 250}&start={start_num}", header) imdb_ids.extend( response.xpath( "//div[contains(@class, 'lister-item-image')]//a/img//@data-tconst" )) util.print_end(length) if imdb_ids: return imdb_ids else: raise Failed(f"IMDb Error: No Movies Found at {imdb_url}")
def __init__(self, params): try: response = requests.get(f"{params['url']}/api/v2?apikey={params['apikey']}&cmd=get_library_names").json() except Exception: util.print_stacktrace() raise Failed("Tautulli Error: Invalid url") if response["response"]["result"] != "success": raise Failed(f"Tautulli Error: {response['response']['message']}") self.url = params["url"] self.apikey = params["apikey"]
def get_tmdb(self, letterboxd_url, language): response = self.send_request(letterboxd_url, language) ids = response.xpath("//a[@data-track-action='TMDb']/@href") if len(ids) > 0 and ids[0]: if "themoviedb.org/movie" in ids[0]: return util.regex_first_int(ids[0], "TMDB Movie ID") raise Failed( f"Letterboxd Error: TMDb Movie ID not found in {ids[0]}") raise Failed( f"Letterboxd Error: TMDb Movie ID not found at {letterboxd_url}")
def get_items(self, method, data, status_message=True): if status_message: logger.debug(f"Data: {data}") pretty = util.pretty_names[ method] if method in util.pretty_names else method if method == "mal_id": mal_ids = [data] if status_message: logger.info(f"Processing {pretty}: {data}") elif method in mal_ranked_name: mal_ids = self.get_ranked(mal_ranked_name[method], data) if status_message: logger.info(f"Processing {pretty}: {data} Anime") elif method == "mal_season": mal_ids = self.get_season(data["season"], data["year"], data["sort_by"], data["limit"]) if status_message: logger.info( f"Processing {pretty}: {data['limit']} Anime from {util.pretty_seasons[data['season']]} {data['year']} sorted by {pretty_names[data['sort_by']]}" ) elif method == "mal_suggested": mal_ids = self.get_suggestions(data) if status_message: logger.info(f"Processing {pretty}: {data} Anime") elif method == "mal_userlist": mal_ids = self.get_userlist(data["username"], data["status"], data["sort_by"], data["limit"]) if status_message: logger.info( f"Processing {pretty}: {data['limit']} Anime from {self.get_username() if data['username'] == '@me' else data['username']}'s {pretty_names[data['status']]} list sorted by {pretty_names[data['sort_by']]}" ) else: raise Failed(f"MyAnimeList Error: Method {method} not supported") show_ids = [] movie_ids = [] for mal_id in mal_ids: try: ids = self.MyAnimeListIDList.find_mal_ids(mal_id) if "thetvdb_id" in ids and int(ids["thetvdb_id"]) > 0: show_ids.append(int(ids["thetvdb_id"])) elif "themoviedb_id" in ids and int(ids["themoviedb_id"]) > 0: movie_ids.append(int(ids["themoviedb_id"])) else: raise Failed( f"MyAnimeList Error: MyAnimeList ID: {mal_id} has no other IDs associated with it" ) except Failed as e: if status_message: logger.error(e) if status_message: logger.debug(f"MyAnimeList IDs Found: {mal_ids}") logger.debug(f"Shows Found: {show_ids}") logger.debug(f"Movies Found: {movie_ids}") return movie_ids, show_ids
def validate_icheckmovies_lists(self, icheckmovies_lists, language): valid_lists = [] for icheckmovies_list in util.get_list(icheckmovies_lists, split=False): list_url = icheckmovies_list.strip() if not list_url.startswith(base_url): raise Failed(f"ICheckMovies Error: {list_url} must begin with: {base_url}") elif len(self._parse_list(list_url, language)) > 0: valid_lists.append(list_url) else: raise Failed(f"ICheckMovies Error: {list_url} failed to parse") return valid_lists
def get_user_lists(self, data): try: items = self._request(f"/users/{data}/lists") except Failed: raise Failed(f"Trakt Error: User {data} not found") if len(items) == 0: raise Failed(f"Trakt Error: User {data} has no lists") return { self.build_user_url(data, i["ids"]["slug"]): i["name"] for i in items }
def _tmdb(self, flixpatrol_url, language): ids = self._request(flixpatrol_url, language, "//script[@type='application/ld+json']/text()") if len(ids) > 0 and ids[0]: if "https://www.themoviedb.org" in ids[0]: return util.regex_first_int( ids[0].split("https://www.themoviedb.org")[1], "TMDB Movie ID") raise Failed( f"FlixPatrol Error: TMDb Movie ID not found in {ids[0]}") raise Failed( f"FlixPatrol Error: TMDb Movie ID not found at {flixpatrol_url}")
def get_items(self, method, data, status_message=True): if status_message: logger.debug(f"Data: {data}") pretty = util.pretty_names[ method] if method in util.pretty_names else method if method == "anilist_id": mal_id, name = self.anilist_id(data) mal_ids = [mal_id] if status_message: logger.info(f"Processing {pretty}: ({data}) {name}") elif method in ["anilist_popular", "anilist_top_rated"]: mal_ids = self.popular( data) if method == "anilist_popular" else self.top_rated(data) if status_message: logger.info(f"Processing {pretty}: {data} Anime") elif method == "anilist_season": mal_ids = self.season(data["season"], data["year"], data["sort_by"], data["limit"]) if status_message: logger.info( f"Processing {pretty}: {data['limit']} Anime from {util.pretty_seasons[data['season']]} {data['year']} sorted by {util.anilist_pretty[data['sort_by']]}" ) elif method in ["anilist_studio", "anilist_relations"]: if method == "anilist_studio": mal_ids, name = self.studio(data) else: mal_ids, _, name = self.relations(data) if status_message: logger.info( f"Processing {pretty}: ({data}) {name} ({len(mal_ids)} Anime)" ) else: raise Failed(f"AniList Error: Method {method} not supported") show_ids = [] movie_ids = [] for mal_id in mal_ids: try: ids = self.config.MyAnimeListIDList.find_mal_ids(mal_id) if "thetvdb_id" in ids and int(ids["thetvdb_id"]) > 0: show_ids.append(int(ids["thetvdb_id"])) elif "themoviedb_id" in ids and int(ids["themoviedb_id"]) > 0: movie_ids.append(int(ids["themoviedb_id"])) else: raise Failed( f"MyAnimeList Error: MyAnimeList ID: {mal_id} has no other IDs associated with it" ) except Failed as e: if status_message: logger.error(e) if status_message: logger.debug(f"MyAnimeList IDs Found: {mal_ids}") logger.debug(f"Shows Found: {show_ids}") logger.debug(f"Movies Found: {movie_ids}") return movie_ids, show_ids
def validate_letterboxd_lists(self, letterboxd_lists, language): valid_lists = [] for letterboxd_list in util.get_list(letterboxd_lists, split=False): list_url = letterboxd_list.strip() if not list_url.startswith(base_url): raise Failed( f"Letterboxd Error: {list_url} must begin with: {base_url}" ) elif len(self._parse_list(list_url, language)) > 0: valid_lists.append(list_url) else: raise Failed(f"Letterboxd Error: {list_url} failed to parse") return valid_lists
def __init__(self, params): try: response = requests.get( "{}/api/v2?apikey={}&cmd=get_library_names".format( params["url"], params["apikey"])).json() except Exception as e: util.print_stacktrace() raise Failed("Tautulli Error: Invalid url") if response["response"]["result"] != "success": raise Failed("Tautulli Error: {}".format( response["response"]["message"])) self.url = params["url"] self.apikey = params["apikey"]
def __init__(self, config, params): self.config = config self.apikey = params["apikey"] self.develop = params["develop"] self.test = params["test"] url, _ = self.get_url("user/validate/") response = self.config.get(url) response_json = response.json() if response.status_code >= 400 or ("result" in response_json and response_json["result"] == "error"): logger.debug(f"Response: {response_json}") raise Failed(f"({response.status_code} [{response.reason}]) {response_json}") if not params["test"] and not response_json["details"]["response"]: raise Failed("Notifiarr Error: Invalid apikey")
def validate_imdb_url(self, imdb_url, language): imdb_url = imdb_url.strip() if not imdb_url.startswith( self.urls["list"]) and not imdb_url.startswith( self.urls["search"]) and not imdb_url.startswith( self.urls["keyword"]): raise Failed( f"IMDb Error: {imdb_url} must begin with either:\n{self.urls['list']} (For Lists)\n{self.urls['search']} (For Searches)\n{self.urls['keyword']} (For Keyword Searches)" ) total, _ = self.get_total(self.fix_url(imdb_url), language) if total > 0: return imdb_url raise Failed(f"IMDb Error: {imdb_url} failed to parse")