def tvdb_series_id_episodes( token: str, id_tvdb: Union[str, int], page: int = 1, language: Optional[Language] = None, cache: bool = True, ) -> dict: """ All episodes for a given series. Note: Paginated with 100 results per page. Online docs: api.thetvdb.com/swagger#!/Series/get_series_id_episodes. """ Language.ensure_valid_for_tvdb(language) url = f"https://api.thetvdb.com/series/{id_tvdb}/episodes" headers = {"Authorization": f"Bearer {token}"} if language: headers["Accept-Language"] = language.a2 parameters = {"page": page} status, content = request_json( url, parameters, headers=headers, cache=cache is True and language is None, ) if status == 401: raise MnamerException("invalid token") elif status == 404: raise MnamerNotFoundException elif status != 200 or not content.get("data"): # pragma: no cover raise MnamerNetworkException("TVDb down or unavailable?") return content
def tvdb_series_id_episodes_query( token: str, id_tvdb: Union[str, int], episode: Optional[int] = None, season: Optional[int] = None, page: int = 1, language: Optional[Language] = None, cache: bool = True, ) -> dict: """ Allows the user to query against episodes for the given series. Note: Paginated with 100 results per page; omitted imdbId-- when would you ever need to query against both tvdb and imdb series ids? Online docs: api.thetvdb.com/swagger#!/Series/get_series_id_episodes_query. """ Language.ensure_valid_for_tvdb(language) url = f"https://api.thetvdb.com/series/{id_tvdb}/episodes/query" headers = {"Authorization": f"Bearer {token}"} if language: headers["Accept-Language"] = language.a2 parameters = {"airedSeason": season, "airedEpisode": episode, "page": page} status, content = request_json( url, parameters, headers=headers, cache=cache is True and language is None, ) if status == 401: raise MnamerException("invalid token") elif status == 404: raise MnamerNotFoundException elif status != 200 or not content.get("data"): # pragma: no cover raise MnamerNetworkException("TVDb down or unavailable?") return content
def tvdb_search_series( token: str, series: Optional[str] = None, id_imdb: Optional[str] = None, id_zap2it: Optional[str] = None, language: Optional[Language] = None, cache: bool = True, ) -> dict: """ Allows the user to search for a series based on the following parameters. Online docs: https://api.thetvdb.com/swagger#!/Search/get_search_series Note: results a maximum of 100 entries per page, no option for pagination. """ Language.ensure_valid_for_tvdb(language) url = "https://api.thetvdb.com/search/series" parameters = {"name": series, "imdbId": id_imdb, "zap2itId": id_zap2it} headers = {"Authorization": f"Bearer {token}"} if language: headers["Accept-Language"] = language.a2 status, content = request_json( url, parameters, headers=headers, cache=cache is True and language is None ) if status == 401: raise MnamerException("invalid token") elif status == 405: raise MnamerException( "series, id_imdb, id_zap2it parameters are mutually exclusive" ) elif status == 404: raise MnamerNotFoundException elif status != 200 or not content.get("data"): # pragma: no cover raise MnamerNetworkException("TVDb down or unavailable?") return content
def tvdb_series_id( token: str, id_tvdb: Union[str, int], language: Optional[Language] = None, cache: bool = True, ) -> dict: """ Returns a series records that contains all information known about a particular series id. Online docs: api.thetvdb.com/swagger#!/Series/get_series_id. """ Language.ensure_valid_for_tvdb(language) url = f"https://api.thetvdb.com/series/{id_tvdb}" headers = {"Authorization": f"Bearer {token}"} if language: headers["Accept-Language"] = language.a2 status, content = request_json( url, headers=headers, cache=cache is True and language is None ) if status == 401: raise MnamerException("invalid token") elif status == 404: raise MnamerNotFoundException elif status != 200 or not content.get("data"): # pragma: no cover raise MnamerNetworkException("TVDb down or unavailable?") elif content["data"]["id"] == 0: raise MnamerNotFoundException return content
def test_tvdb_episodes_id__invalid_lang(tvdb_token): with pytest.raises(MnamerException): tvdb_episodes_id( tvdb_token, LOST_TVDB_ID_EPISODE, language=Language(JUNK_TEXT, JUNK_TEXT, JUNK_TEXT), cache=False, )
def test_tvdb_series_id_episodes_query__invalid_lang(tvdb_token): with pytest.raises(MnamerException): tvdb_series_id_episodes_query( tvdb_token, LOST_TVDB_ID_SERIES, language=Language(JUNK_TEXT, JUNK_TEXT, JUNK_TEXT), cache=False, )
def test_tvdb_search_series__invalid_lang(tvdb_token): with pytest.raises(MnamerException): tvdb_search_series( tvdb_token, "Lost", language=Language(JUNK_TEXT, JUNK_TEXT, JUNK_TEXT), cache=False, )
def subtitle_prompt() -> Metadata: msg("select language") choices = [ChoiceHelper(language, language.name) for language in Language.all()] selector = SelectOne(choices + _abort_helpers(), **_chars()) choice = selector.prompt() if choice in (MnamerAbortException, MnamerSkipException): raise choice else: return choice
"media": "movie", "name": "Citizen Kane", "year": 1941, }, "Les Misérables": { "id_imdb": "tt10199590", "id_tmdb": 586863, "media": "movie", "name": "Les Misérables", "year": 2019, }, } TEST_DATE = date(2010, 12, 9) RUSSIAN_LANG = Language.parse("ru") class E2EResult(NamedTuple): code: int out: str class MockRequestResponse: def __init__(self, status: int, content: str) -> None: self.status_code = status self.content = content def json(self) -> Dict[str, Any]: from json import loads
def _parse(self, file_path: PurePath): path_data = {} options = {"type": self._settings.media} raw_data = dict(guessit(str(file_path), options)) if isinstance(raw_data.get("season"), list): raw_data = dict(guessit(str(file_path.parts[-1]), options)) for k, v in raw_data.items(): if hasattr(v, "alpha3"): try: path_data[k] = Language.parse(v) except MnamerException: continue elif isinstance(v, (int, str, date)): path_data[k] = v elif isinstance(v, list) and all( [isinstance(_, (int, str)) for _ in v] ): path_data[k] = v[0] if self._settings.media: media_type = self._settings.media elif path_data.get("type"): media_type = MediaType(path_data["type"]) else: media_type = None meta_cls = { MediaType.EPISODE: MetadataEpisode, MediaType.MOVIE: MetadataMovie, None: Metadata, }[media_type] self.metadata = meta_cls(language=self._settings.language) self.metadata.quality = ( " ".join( path_data[key] for key in path_data if key in ( "audio_codec", "audio_profile", "screen_size", "source", "video_codec", "video_profile", ) ) or None ) self.metadata.group = path_data.get("release_group") self.metadata.container = file_path.suffix or None if not self.metadata.language: try: self.metadata.language = path_data.get("language") except MnamerException: pass try: self.metadata.language_sub = path_data.get("subtitle_language") except MnamerException: pass if self.metadata.media is MediaType.MOVIE: self.metadata.name = path_data.get("title") self.metadata.year = path_data.get("year") elif self.metadata.media is MediaType.EPISODE: self.metadata.date = path_data.get("date") self.metadata.episode = path_data.get("episode") self.metadata.season = path_data.get("season") self.metadata.series = path_data.get("title") alternative_title = path_data.get("alternative_title") if alternative_title: self.metadata.series = ( f"{self.metadata.series} {alternative_title}" )
def test_tvdb_episodes_id__language__invalid(tvdb_token): invalid_language = Language("invalid", "xy", "xyz") with pytest.raises(MnamerException): tvdb_episodes_id(tvdb_token, LOST_TVDB_ID_EPISODE, invalid_language)
def test_language_parse__str(value): expected = Language("English", "en", "eng") actual = Language.parse(value) assert actual == expected
def test_language_all(): expected = ( Language("English", "en", "eng"), Language("French", "fr", "fra"), Language("Spanish", "es", "spa"), Language("German", "de", "deu"), Language("Hindi", "hi", "hin"), Language("Chinese", "zh", "zho"), Language("Japanese", "ja", "jpn"), Language("Italian", "it", "ita"), Language("Russian", "ru", "rus"), Language("Arabic", "ar", "ara"), Language("Korean", "ko", "kor"), Language("Hebrew", "he", "heb"), Language("Portuguese", "pt", "por"), Language("Swedish", "sv", "swe"), Language("Latin", "la", "lat"), Language("Ukrainian", "uk", "ukr"), Language("Danish", "da", "dan"), Language("Persian", "fa", "fas"), ) actual = Language.all() assert actual == expected
def test_language_parse__bl(): expected = Language("English", "en", "eng") actual = Language.parse(BabelLang("eng")) assert actual == expected