diff --git a/app/api/endpoints/tmdb.py b/app/api/endpoints/tmdb.py index 8a265824..d1320965 100644 --- a/app/api/endpoints/tmdb.py +++ b/app/api/endpoints/tmdb.py @@ -36,6 +36,46 @@ def tmdb_season_episodes(tmdbid: int, season: int, return episodes_info +@router.get("/{tmdbid}/similar", summary="类似电影/电视剧", response_model=List[schemas.MediaInfo]) +def movie_similar(tmdbid: int, + mtype: str, + _: schemas.TokenPayload = Depends(verify_token)) -> Any: + """ + 根据TMDBID查询类似电影 + """ + mediatype = MediaType(mtype) + if mediatype == MediaType.MOVIE: + tmdbinfos = TmdbChain().movie_similar(tmdbid=tmdbid) + elif mediatype == MediaType.TV: + tmdbinfos = TmdbChain().tv_similar(tmdbid=tmdbid) + else: + return [] + if not tmdbinfos: + return [] + else: + return [MediaInfo(tmdb_info=tmdbinfo).to_dict() for tmdbinfo in tmdbinfos] + + +@router.get("/{tmdbid}/credits", summary="演员阵容", response_model=List[schemas.TmdbCast]) +def movie_similar(tmdbid: int, + mtype: str, + _: schemas.TokenPayload = Depends(verify_token)) -> Any: + """ + 根据TMDBID查询演员阵容 + """ + mediatype = MediaType(mtype) + if mediatype == MediaType.MOVIE: + tmdbinfos = TmdbChain().movie_credits(tmdbid=tmdbid) + elif mediatype == MediaType.TV: + tmdbinfos = TmdbChain().tv_credits(tmdbid=tmdbid) + else: + return [] + if not tmdbinfos: + return [] + else: + return tmdbinfos + + @router.get("/movies", summary="TMDB电影", response_model=List[schemas.MediaInfo]) def tmdb_movies(sort_by: str = "popularity.desc", with_genres: str = "", diff --git a/app/chain/tmdb.py b/app/chain/tmdb.py index 488d3d9c..eb1f2b90 100644 --- a/app/chain/tmdb.py +++ b/app/chain/tmdb.py @@ -47,3 +47,31 @@ class TmdbChain(ChainBase): :param season: 季 """ return self.run_module("tmdb_episodes", tmdbid=tmdbid, season=season) + + def movie_similar(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询类似电影 + :param tmdbid: TMDBID + """ + return self.run_module("movie_similar", tmdbid=tmdbid) + + def tv_similar(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询类似电视剧 + :param tmdbid: TMDBID + """ + return self.run_module("tv_similar", tmdbid=tmdbid) + + def movie_credits(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询电影演职人员 + :param tmdbid: TMDBID + """ + return self.run_module("movie_credits", tmdbid=tmdbid) + + def tv_credits(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询电视剧演职人员 + :param tmdbid: TMDBID + """ + return self.run_module("tv_credits", tmdbid=tmdbid) diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 96e2c7f8..cd354f5e 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -9,7 +9,7 @@ from app.log import logger from app.modules import _ModuleBase from app.modules.themoviedb.category import CategoryHelper from app.modules.themoviedb.scraper import TmdbScraper -from app.modules.themoviedb.tmdb import TmdbHelper +from app.modules.themoviedb.tmdbapi import TmdbHelper from app.modules.themoviedb.tmdb_cache import TmdbCache from app.schemas.types import MediaType, MediaImageType from app.utils.system import SystemUtils @@ -331,3 +331,31 @@ class TheMovieDbModule(_ModuleBase): if image_path: return f"https://image.tmdb.org/t/p/{image_prefix}{image_path}" return None + + def movie_similar(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询类似电影 + :param tmdbid: TMDBID + """ + return self.tmdb.get_movie_similar(tmdbid=tmdbid) + + def tv_similar(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询类似电视剧 + :param tmdbid: TMDBID + """ + return self.tmdb.get_tv_similar(tmdbid=tmdbid) + + def movie_credits(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询电影演职员表 + :param tmdbid: TMDBID + """ + return self.tmdb.get_movie_credits(tmdbid=tmdbid) + + def tv_credits(self, tmdbid: int) -> List[dict]: + """ + 根据TMDBID查询电视剧演职员表 + :param tmdbid: TMDBID + """ + return self.tmdb.get_tv_credits(tmdbid=tmdbid) diff --git a/app/modules/themoviedb/tmdb.py b/app/modules/themoviedb/tmdbapi.py similarity index 95% rename from app/modules/themoviedb/tmdb.py rename to app/modules/themoviedb/tmdbapi.py index e24fd8cc..9637f0ea 100644 --- a/app/modules/themoviedb/tmdb.py +++ b/app/modules/themoviedb/tmdbapi.py @@ -5,8 +5,8 @@ from urllib.parse import quote import zhconv from lxml import etree -from tmdbv3api import TMDb, Search, Movie, TV, Season, Episode, Discover, Trending -from tmdbv3api.exceptions import TMDbException +from .tmdbv3api import TMDb, Search, Movie, TV, Season, Episode, Discover, Trending +from .tmdbv3api.exceptions import TMDbException from app.core.config import settings from app.log import logger @@ -1045,3 +1045,59 @@ class TmdbHelper: except Exception as e: print(str(e)) return {} + + def get_movie_similar(self, tmdbid: int) -> List[dict]: + """ + 获取电影的相似电影 + """ + if not self.movie: + return [] + try: + logger.info(f"正在获取相似电影:{tmdbid}...") + info = self.movie.similar(tmdbid) or {} + return info.get('results') or [] + except Exception as e: + print(str(e)) + return [] + + def get_tv_similar(self, tmdbid: int) -> List[dict]: + """ + 获取电视剧的相似电视剧 + """ + if not self.tv: + return [] + try: + logger.info(f"正在获取相似电视剧:{tmdbid}...") + info = self.tv.similar(tmdbid) or {} + return info.get('results') or [] + except Exception as e: + print(str(e)) + return [] + + def get_movie_credits(self, tmdbid: int) -> List[dict]: + """ + 获取电影的演职员列表 + """ + if not self.movie: + return [] + try: + logger.info(f"正在获取电影演职员:{tmdbid}...") + info = self.movie.credits(tmdbid) or {} + return info.get('cast') or [] + except Exception as e: + print(str(e)) + return [] + + def get_tv_credits(self, tmdbid: int) -> List[dict]: + """ + 获取电视剧的演职员列表 + """ + if not self.tv: + return [] + try: + logger.info(f"正在获取电视剧演职员:{tmdbid}...") + info = self.tv.credits(tmdbid) or {} + return info.get('cast') or [] + except Exception as e: + print(str(e)) + return [] diff --git a/app/modules/themoviedb/tmdbv3api/__init__.py b/app/modules/themoviedb/tmdbv3api/__init__.py new file mode 100644 index 00000000..1169bfd1 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/__init__.py @@ -0,0 +1,25 @@ +from .objs.account import Account +from .objs.auth import Authentication +from .objs.certification import Certification +from .objs.change import Change +from .objs.collection import Collection +from .objs.company import Company +from .objs.configuration import Configuration +from .objs.credit import Credit +from .objs.discover import Discover +from .objs.episode import Episode +from .objs.find import Find +from .objs.genre import Genre +from .objs.group import Group +from .objs.keyword import Keyword +from .objs.list import List +from .objs.movie import Movie +from .objs.network import Network +from .objs.person import Person +from .objs.provider import Provider +from .objs.review import Review +from .objs.search import Search +from .objs.season import Season +from .objs.trending import Trending +from .objs.tv import TV +from .tmdb import TMDb diff --git a/app/modules/themoviedb/tmdbv3api/as_obj.py b/app/modules/themoviedb/tmdbv3api/as_obj.py new file mode 100644 index 00000000..898031f6 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/as_obj.py @@ -0,0 +1,102 @@ +# encoding: utf-8 +import sys + + +class AsObj: + def __init__(self, json=None, key=None, dict_key=False, dict_key_name=None): + self._json = json if json else {} + self._key = key + self._dict_key = dict_key + self._dict_key_name = dict_key_name + self._obj_list = [] + self._list_only = False + if isinstance(self._json, list): + self._obj_list = [AsObj(o) if isinstance(o, (dict, list)) else o for o in self._json] + self._list_only = True + elif dict_key: + self._obj_list = [ + AsObj({k: v}, key=k, dict_key_name=dict_key_name) if isinstance(v, (dict, list)) else v + for k, v in self._json.items() + ] + self._list_only = True + else: + for key, value in self._json.items(): + if isinstance(value, (dict, list)): + if self._key and key == self._key: + final = AsObj(value, dict_key=isinstance(value, dict), dict_key_name=key) + self._obj_list = final + else: + final = AsObj(value) + else: + final = value + if dict_key_name: + setattr(self, dict_key_name, key) + setattr(self, key, final) + + def _dict(self): + return {k: v for k, v in self.__dict__.items() if not k.startswith("_")} + + def __delitem__(self, key): + return delattr(self, key) + + def __getitem__(self, key): + if isinstance(key, int) and self._obj_list: + return self._obj_list[key] + else: + return getattr(self, key) + + def __iter__(self): + return (o for o in self._obj_list) if self._obj_list else iter(self._dict()) + + def __len__(self): + return len(self._obj_list) if self._obj_list else len(self._dict()) + + def __repr__(self): + return str(self._obj_list) if self._list_only else str(self._dict()) + + def __setitem__(self, key, value): + return setattr(self, key, value) + + def __str__(self): + return str(self._obj_list) if self._list_only else str(self._dict()) + + if sys.version_info >= (3, 8): + def __reversed__(self): + return reversed(self._dict()) + + if sys.version_info >= (3, 9): + def __class_getitem__(self, key): + return self.__dict__.__class_getitem__(key) + + def __ior__(self, value): + return self._dict().__ior__(value) + + def __or__(self, value): + return self._dict().__or__(value) + + def copy(self): + return AsObj(self._json.copy(), key=self._key, dict_key=self._dict_key, dict_key_name=self._dict_key_name) + + def get(self, key, value=None): + return self._dict().get(key, value) + + def items(self): + return self._dict().items() + + def keys(self): + return self._dict().keys() + + def pop(self, key, value=None): + return self.__dict__.pop(key, value) + + def popitem(self): + return self.__dict__.popitem() + + def setdefault(self, key, value=None): + return self.__dict__.setdefault(key, value) + + def update(self, entries): + return self.__dict__.update(entries) + + def values(self): + return self._dict().values() diff --git a/app/modules/themoviedb/tmdbv3api/exceptions.py b/app/modules/themoviedb/tmdbv3api/exceptions.py new file mode 100644 index 00000000..e17eeb27 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/exceptions.py @@ -0,0 +1,2 @@ +class TMDbException(Exception): + pass diff --git a/app/modules/themoviedb/tmdbv3api/objs/__init__.py b/app/modules/themoviedb/tmdbv3api/objs/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/modules/themoviedb/tmdbv3api/objs/account.py b/app/modules/themoviedb/tmdbv3api/objs/account.py new file mode 100644 index 00000000..217e9e18 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/account.py @@ -0,0 +1,177 @@ +import os + +from ..tmdb import TMDb +from ..exceptions import TMDbException + + +class Account(TMDb): + _urls = { + "details": "/account", + "created_lists": "/account/%s/lists", + "favorite_movies": "/account/%s/favorite/movies", + "favorite_tv": "/account/%s/favorite/tv", + "favorite": "/account/%s/favorite", + "rated_movies": "/account/%s/rated/movies", + "rated_tv": "/account/%s/rated/tv", + "rated_episodes": "/account/%s/rated/tv/episodes", + "movie_watchlist": "/account/%s/watchlist/movies", + "tv_watchlist": "/account/%s/watchlist/tv", + "watchlist": "/account/%s/watchlist", + } + + @property + def account_id(self): + if not os.environ.get("TMDB_ACCOUNT_ID"): + os.environ["TMDB_ACCOUNT_ID"] = str(self.details()["id"]) + return os.environ.get("TMDB_ACCOUNT_ID") + + def details(self): + """ + Get your account details. + :return: + """ + return self._request_obj( + self._urls["details"], + params="session_id=%s" % self.session_id + ) + + def created_lists(self, page=1): + """ + Get all of the lists created by an account. Will include private lists if you are the owner. + :param page: int + :return: + """ + return self._request_obj( + self._urls["created_lists"] % self.account_id, + params="session_id=%s&page=%s" % (self.session_id, page), + key="results" + ) + + def _get_list(self, url, asc_sort=True, page=1): + params = "session_id=%s&page=%s" % (self.session_id, page) + if asc_sort is False: + params += "&sort_by=created_at.desc" + return self._request_obj( + self._urls[url] % self.account_id, + params=params, + key="results" + ) + + def favorite_movies(self, asc_sort=True, page=1): + """ + Get the list of your favorite movies. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("favorite_movies", asc_sort=asc_sort, page=page) + + def favorite_tv_shows(self, asc_sort=True, page=1): + """ + Get the list of your favorite TV shows. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("favorite_tv", asc_sort=asc_sort, page=page) + + def mark_as_favorite(self, media_id, media_type, favorite=True): + """ + This method allows you to mark a movie or TV show as a favorite item. + :param media_id: int + :param media_type: str + :param favorite:bool + """ + if media_type not in ["tv", "movie"]: + raise TMDbException("Media Type should be tv or movie.") + self._request_obj( + self._urls["favorite"] % self.account_id, + params="session_id=%s" % self.session_id, + method="POST", + json={ + "media_type": media_type, + "media_id": media_id, + "favorite": favorite, + } + ) + + def unmark_as_favorite(self, media_id, media_type): + """ + This method allows you to unmark a movie or TV show as a favorite item. + :param media_id: int + :param media_type: str + """ + self.mark_as_favorite(media_id, media_type, favorite=False) + + def rated_movies(self, asc_sort=True, page=1): + """ + Get a list of all the movies you have rated. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("rated_movies", asc_sort=asc_sort, page=page) + + def rated_tv_shows(self, asc_sort=True, page=1): + """ + Get a list of all the TV shows you have rated. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("rated_tv", asc_sort=asc_sort, page=page) + + def rated_episodes(self, asc_sort=True, page=1): + """ + Get a list of all the TV episodes you have rated. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("rated_episodes", asc_sort=asc_sort, page=page) + + def movie_watchlist(self, asc_sort=True, page=1): + """ + Get a list of all the movies you have added to your watchlist. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("movie_watchlist", asc_sort=asc_sort, page=page) + + def tv_show_watchlist(self, asc_sort=True, page=1): + """ + Get a list of all the TV shows you have added to your watchlist. + :param asc_sort: bool + :param page: int + :return: + """ + return self._get_list("tv_watchlist", asc_sort=asc_sort, page=page) + + def add_to_watchlist(self, media_id, media_type, watchlist=True): + """ + Add a movie or TV show to your watchlist. + :param media_id: int + :param media_type: str + :param watchlist: bool + """ + if media_type not in ["tv", "movie"]: + raise TMDbException("Media Type should be tv or movie.") + self._request_obj( + self._urls["watchlist"] % self.account_id, + "session_id=%s" % self.session_id, + method="POST", + json={ + "media_type": media_type, + "media_id": media_id, + "watchlist": watchlist, + } + ) + + def remove_from_watchlist(self, media_id, media_type): + """ + Remove a movie or TV show from your watchlist. + :param media_id: int + :param media_type: str + """ + self.add_to_watchlist(media_id, media_type, watchlist=False) diff --git a/app/modules/themoviedb/tmdbv3api/objs/auth.py b/app/modules/themoviedb/tmdbv3api/objs/auth.py new file mode 100644 index 00000000..c610860b --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/auth.py @@ -0,0 +1,64 @@ +from ..tmdb import TMDb + + +class Authentication(TMDb): + _urls = { + "create_request_token": "/authentication/token/new", + "validate_with_login": "/authentication/token/validate_with_login", + "create_session": "/authentication/session/new", + "delete_session": "/authentication/session", + } + + def __init__(self, username, password): + super().__init__() + self.username = username + self.password = password + self.expires_at = None + self.request_token = self._create_request_token() + self._authorise_request_token_with_login() + self._create_session() + + def _create_request_token(self): + """ + Create a temporary request token that can be used to validate a TMDb user login. + """ + response = self._request_obj(self._urls["create_request_token"]) + self.expires_at = response.expires_at + return response.request_token + + def _create_session(self): + """ + You can use this method to create a fully valid session ID once a user has validated the request token. + """ + response = self._request_obj( + self._urls["create_session"], + method="POST", + json={"request_token": self.request_token} + ) + self.session_id = response.session_id + + def _authorise_request_token_with_login(self): + """ + This method allows an application to validate a request token by entering a username and password. + """ + self._request_obj( + self._urls["validate_with_login"], + method="POST", + json={ + "username": self.username, + "password": self.password, + "request_token": self.request_token, + } + ) + + def delete_session(self): + """ + If you would like to delete (or "logout") from a session, call this method with a valid session ID. + """ + if self.has_session: + self._request_obj( + self._urls["delete_session"], + method="DELETE", + json={"session_id": self.session_id} + ) + self.session_id = "" diff --git a/app/modules/themoviedb/tmdbv3api/objs/certification.py b/app/modules/themoviedb/tmdbv3api/objs/certification.py new file mode 100644 index 00000000..3bf68787 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/certification.py @@ -0,0 +1,22 @@ +from ..tmdb import TMDb + + +class Certification(TMDb): + _urls = { + "movie_list": "/certification/movie/list", + "tv_list": "/certification/tv/list", + } + + def movie_list(self): + """ + Get an up to date list of the officially supported movie certifications on TMDB. + :return: + """ + return self._request_obj(self._urls["movie_list"], key="certifications") + + def tv_list(self): + """ + Get an up to date list of the officially supported TV show certifications on TMDB. + :return: + """ + return self._request_obj(self._urls["tv_list"], key="certifications") diff --git a/app/modules/themoviedb/tmdbv3api/objs/change.py b/app/modules/themoviedb/tmdbv3api/objs/change.py new file mode 100644 index 00000000..f0a0eac0 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/change.py @@ -0,0 +1,54 @@ +from ..tmdb import TMDb + + +class Change(TMDb): + _urls = { + "movie": "/movie/changes", + "tv": "/tv/changes", + "person": "/person/changes" + } + + def _change_list(self, change_type, start_date="", end_date="", page=1): + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls[change_type], + params=params, + key="results" + ) + + def movie_change_list(self, start_date="", end_date="", page=1): + """ + Get the changes for a movie. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + return self._change_list("movie", start_date=start_date, end_date=end_date, page=page) + + def tv_change_list(self, start_date="", end_date="", page=1): + """ + Get a list of all of the TV show ids that have been changed in the past 24 hours. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + return self._change_list("tv", start_date=start_date, end_date=end_date, page=page) + + def person_change_list(self, start_date="", end_date="", page=1): + """ + Get a list of all of the person ids that have been changed in the past 24 hours. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + return self._change_list("person", start_date=start_date, end_date=end_date, page=page) diff --git a/app/modules/themoviedb/tmdbv3api/objs/collection.py b/app/modules/themoviedb/tmdbv3api/objs/collection.py new file mode 100644 index 00000000..73ca1701 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/collection.py @@ -0,0 +1,33 @@ +from ..tmdb import TMDb + + +class Collection(TMDb): + _urls = { + "details": "/collection/%s", + "images": "/collection/%s/images", + "translations": "/collection/%s/translations" + } + + def details(self, collection_id): + """ + Get collection details by id. + :param collection_id: int + :return: + """ + return self._request_obj(self._urls["details"] % collection_id, key="parts") + + def images(self, collection_id): + """ + Get the images for a collection by id. + :param collection_id: int + :return: + """ + return self._request_obj(self._urls["images"] % collection_id) + + def translations(self, collection_id): + """ + Get the list translations for a collection by id. + :param collection_id: int + :return: + """ + return self._request_obj(self._urls["translations"] % collection_id, key="translations") diff --git a/app/modules/themoviedb/tmdbv3api/objs/company.py b/app/modules/themoviedb/tmdbv3api/objs/company.py new file mode 100644 index 00000000..eed7add3 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/company.py @@ -0,0 +1,47 @@ +from ..tmdb import TMDb + + +class Company(TMDb): + _urls = { + "details": "/company/%s", + "alternative_names": "/company/%s/alternative_names", + "images": "/company/%s/images", + "movies": "/company/%s/movies" + } + + def details(self, company_id): + """ + Get a companies details by id. + :param company_id: int + :return: + """ + return self._request_obj(self._urls["details"] % company_id) + + def alternative_names(self, company_id): + """ + Get the alternative names of a company. + :param company_id: int + :return: + """ + return self._request_obj(self._urls["alternative_names"] % company_id, key="results") + + def images(self, company_id): + """ + Get the alternative names of a company. + :param company_id: int + :return: + """ + return self._request_obj(self._urls["images"] % company_id, key="logos") + + def movies(self, company_id, page=1): + """ + Get the movies of a company by id. + :param company_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["movies"] % company_id, + params="page=%s" % page, + key="results" + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/configuration.py b/app/modules/themoviedb/tmdbv3api/objs/configuration.py new file mode 100644 index 00000000..0cb258c5 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/configuration.py @@ -0,0 +1,54 @@ +import warnings +from ..tmdb import TMDb + + +class Configuration(TMDb): + _urls = { + "api_configuration": "/configuration", + "countries": "/configuration/countries", + "jobs": "/configuration/jobs", + "languages": "/configuration/languages", + "primary_translations": "/configuration/primary_translations", + "timezones": "/configuration/timezones" + } + + def info(self): + warnings.warn("info method is deprecated use tmdbv3api.Configuration().api_configuration()", + DeprecationWarning) + return self.api_configuration() + + def api_configuration(self): + """ + Get the system wide configuration info. + """ + return self._request_obj(self._urls["api_configuration"]) + + def countries(self): + """ + Get the list of countries (ISO 3166-1 tags) used throughout TMDb. + """ + return self._request_obj(self._urls["countries"]) + + def jobs(self): + """ + Get a list of the jobs and departments we use on TMDb. + """ + return self._request_obj(self._urls["jobs"]) + + def languages(self): + """ + Get the list of languages (ISO 639-1 tags) used throughout TMDb. + """ + return self._request_obj(self._urls["languages"]) + + def primary_translations(self): + """ + Get a list of the officially supported translations on TMDb. + """ + return self._request_obj(self._urls["primary_translations"]) + + def timezones(self): + """ + Get the list of timezones used throughout TMDb. + """ + return self._request_obj(self._urls["timezones"]) diff --git a/app/modules/themoviedb/tmdbv3api/objs/credit.py b/app/modules/themoviedb/tmdbv3api/objs/credit.py new file mode 100644 index 00000000..d75be563 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/credit.py @@ -0,0 +1,15 @@ +from ..tmdb import TMDb + + +class Credit(TMDb): + _urls = { + "details": "/credit/%s" + } + + def details(self, credit_id): + """ + Get a movie or TV credit details by id. + :param credit_id: int + :return: + """ + return self._request_obj(self._urls["details"] % credit_id) diff --git a/app/modules/themoviedb/tmdbv3api/objs/discover.py b/app/modules/themoviedb/tmdbv3api/objs/discover.py new file mode 100644 index 00000000..de7964cb --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/discover.py @@ -0,0 +1,30 @@ +from ..tmdb import TMDb + +try: + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode + + +class Discover(TMDb): + _urls = { + "movies": "/discover/movie", + "tv": "/discover/tv" + } + + def discover_movies(self, params): + """ + Discover movies by different types of data like average rating, number of votes, genres and certifications. + :param params: dict + :return: + """ + return self._request_obj(self._urls["movies"], urlencode(params), key="results") + + def discover_tv_shows(self, params): + """ + Discover TV shows by different types of data like average rating, number of votes, genres, + the network they aired on and air dates. + :param params: dict + :return: + """ + return self._request_obj(self._urls["tv"], urlencode(params), key="results") diff --git a/app/modules/themoviedb/tmdbv3api/objs/episode.py b/app/modules/themoviedb/tmdbv3api/objs/episode.py new file mode 100644 index 00000000..af749050 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/episode.py @@ -0,0 +1,157 @@ +from ..tmdb import TMDb + + +class Episode(TMDb): + _urls = { + "details": "/tv/%s/season/%s/episode/%s", + "account_states": "/tv/%s/season/%s/episode/%s/account_states", + "changes": "/tv/episode/%s/changes", + "credits": "/tv/%s/season/%s/episode/%s/credits", + "external_ids": "/tv/%s/season/%s/episode/%s/external_ids", + "images": "/tv/%s/season/%s/episode/%s/images", + "translations": "/tv/%s/season/%s/episode/%s/translations", + "rate_tv_episode": "/tv/%s/season/%s/episode/%s/rating", + "delete_rating": "/tv/%s/season/%s/episode/%s/rating", + "videos": "/tv/%s/season/%s/episode/%s/videos", + } + + def details(self, tv_id, season_num, episode_num, append_to_response="trailers,images,casts,translations"): + """ + Get the TV episode details by id. + :param tv_id: int + :param season_num: int + :param episode_num: int + :param append_to_response: str + :return: + """ + return self._request_obj( + self._urls["details"] % (tv_id, season_num, episode_num), + params="append_to_response=%s" % append_to_response + ) + + def account_states(self, tv_id, season_num, episode_num): + """ + Get your rating for a episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :return: + """ + return self._request_obj( + self._urls["account_states"] % (tv_id, season_num, episode_num), + params="session_id=%s" % self.session_id + ) + + def changes(self, episode_id, start_date=None, end_date=None, page=1): + """ + Get the changes for a TV episode. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param episode_id: int + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls["changes"] % episode_id, + params=params, + key="changes" + ) + + def credits(self, tv_id, season_num, episode_num): + """ + Get the credits for TV season. + :param tv_id: int + :param season_num: int + :param episode_num: int + :return: + """ + return self._request_obj(self._urls["credits"] % (tv_id, season_num, episode_num)) + + def external_ids(self, tv_id, season_num, episode_num): + """ + Get the external ids for a TV episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :return: + """ + return self._request_obj(self._urls["external_ids"] % (tv_id, season_num, episode_num)) + + def images(self, tv_id, season_num, episode_num, include_image_language=None): + """ + Get the images that belong to a TV episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :param include_image_language: str + :return: + """ + return self._request_obj( + self._urls["images"] % (tv_id, season_num, episode_num), + params="include_image_language=%s" % include_image_language if include_image_language else "", + key="stills" + ) + + def translations(self, tv_id, season_num, episode_num): + """ + Get the translation data for an episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :return: + """ + return self._request_obj( + self._urls["translations"] % (tv_id, season_num, episode_num), + key="translations" + ) + + def rate_tv_episode(self, tv_id, season_num, episode_num, rating): + """ + Rate a TV episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :param rating: float + """ + self._request_obj( + self._urls["rate_tv_episode"] % (tv_id, season_num, episode_num), + params="session_id=%s" % self.session_id, + method="POST", + json={"value": rating} + ) + + def delete_rating(self, tv_id, season_num, episode_num): + """ + Remove your rating for a TV episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + """ + self._request_obj( + self._urls["delete_rating"] % (tv_id, season_num, episode_num), + params="session_id=%s" % self.session_id, + method="DELETE" + ) + + def videos(self, tv_id, season_num, episode_num, include_video_language=None): + """ + Get the videos that have been added to a TV episode. + :param tv_id: int + :param season_num: int + :param episode_num: int + :param include_video_language: str + :return: + """ + params = "" + if include_video_language: + params += "&include_video_language=%s" % include_video_language + return self._request_obj( + self._urls["videos"] % (tv_id, season_num, episode_num), + params=params + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/find.py b/app/modules/themoviedb/tmdbv3api/objs/find.py new file mode 100644 index 00000000..7fffe5f7 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/find.py @@ -0,0 +1,83 @@ +from ..tmdb import TMDb + + +class Find(TMDb): + _urls = { + "find": "/find/%s" + } + + def find(self, external_id, external_source): + """ + The find method makes it easy to search for objects in our database by an external id. For example, an IMDB ID. + :param external_id: str + :param external_source str + :return: + """ + return self._request_obj( + self._urls["find"] % external_id.replace("/", "%2F"), + params="external_source=" + external_source + ) + + def find_by_imdb_id(self, imdb_id): + """ + The find method makes it easy to search for objects in our database by an IMDB ID. + :param imdb_id: str + :return: + """ + return self.find(imdb_id, "imdb_id") + + def find_by_tvdb_id(self, tvdb_id): + """ + The find method makes it easy to search for objects in our database by a TVDB ID. + :param tvdb_id: int + :return: + """ + return self.find(tvdb_id, "tvdb_id") + + def find_by_freebase_mid(self, freebase_mid): + """ + The find method makes it easy to search for objects in our database by a Freebase MID. + :param freebase_mid: str + :return: + """ + return self.find(freebase_mid, "freebase_mid") + + def find_by_freebase_id(self, freebase_id): + """ + The find method makes it easy to search for objects in our database by a Freebase ID. + :param freebase_id: str + :return: + """ + return self.find(freebase_id, "freebase_id") + + def find_by_tvrage_id(self, tvrage_id): + """ + The find method makes it easy to search for objects in our database by a TVRage ID. + :param tvrage_id: str + :return: + """ + return self.find(tvrage_id, "tvrage_id") + + def find_by_facebook_id(self, facebook_id): + """ + The find method makes it easy to search for objects in our database by a Facebook ID. + :param facebook_id: str + :return: + """ + return self.find(facebook_id, "facebook_id") + + def find_by_instagram_id(self, instagram_id): + """ + The find method makes it easy to search for objects in our database by a Instagram ID. + :param instagram_id: str + :return: + """ + return self.find(instagram_id, "instagram_id") + + def find_by_twitter_id(self, twitter_id): + """ + The find method makes it easy to search for objects in our database by a Twitter ID. + :param twitter_id: str + :return: + """ + return self.find(twitter_id, "twitter_id") diff --git a/app/modules/themoviedb/tmdbv3api/objs/genre.py b/app/modules/themoviedb/tmdbv3api/objs/genre.py new file mode 100644 index 00000000..d8bfb974 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/genre.py @@ -0,0 +1,22 @@ +from ..tmdb import TMDb + + +class Genre(TMDb): + _urls = { + "movie_list": "/genre/movie/list", + "tv_list": "/genre/tv/list" + } + + def movie_list(self): + """ + Get the list of official genres for movies. + :return: + """ + return self._request_obj(self._urls["movie_list"], key="genres") + + def tv_list(self): + """ + Get the list of official genres for TV shows. + :return: + """ + return self._request_obj(self._urls["tv_list"], key="genres") diff --git a/app/modules/themoviedb/tmdbv3api/objs/group.py b/app/modules/themoviedb/tmdbv3api/objs/group.py new file mode 100644 index 00000000..910cb877 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/group.py @@ -0,0 +1,15 @@ +from ..tmdb import TMDb + + +class Group(TMDb): + _urls = { + "details": "/tv/episode_group/%s" + } + + def details(self, group_id): + """ + Get the details of a TV episode group. + :param group_id: int + :return: + """ + return self._request_obj(self._urls["details"] % group_id, key="groups") diff --git a/app/modules/themoviedb/tmdbv3api/objs/keyword.py b/app/modules/themoviedb/tmdbv3api/objs/keyword.py new file mode 100644 index 00000000..98ff7a95 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/keyword.py @@ -0,0 +1,24 @@ +from ..tmdb import TMDb + + +class Keyword(TMDb): + _urls = { + "details": "/keyword/%s", + "movies": "/keyword/%s/movies" + } + + def details(self, keyword_id): + """ + Get a keywords details by id. + :param keyword_id: int + :return: + """ + return self._request_obj(self._urls["details"] % keyword_id) + + def movies(self, keyword_id): + """ + Get the movies of a keyword by id. + :param keyword_id: int + :return: + """ + return self._request_obj(self._urls["movies"] % keyword_id, key="results") diff --git a/app/modules/themoviedb/tmdbv3api/objs/list.py b/app/modules/themoviedb/tmdbv3api/objs/list.py new file mode 100644 index 00000000..9e756341 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/list.py @@ -0,0 +1,96 @@ +from ..tmdb import TMDb + + +class List(TMDb): + _urls = { + "details": "/list/%s", + "check_status": "/list/%s/item_status", + "create": "/list", + "add_movie": "/list/%s/add_item", + "remove_movie": "/list/%s/remove_item", + "clear_list": "/list/%s/clear", + "delete_list": "/list/%s", + } + + def details(self, list_id): + """ + Get list details by id. + :param list_id: int + :return: + """ + return self._request_obj(self._urls["details"] % list_id, key="items") + + def check_item_status(self, list_id, movie_id): + """ + You can use this method to check if a movie has already been added to the list. + :param list_id: int + :param movie_id: int + :return: + """ + return self._request_obj(self._urls["check_status"] % list_id, params="movie_id=%s" % movie_id)["item_present"] + + def create_list(self, name, description): + """ + You can use this method to check if a movie has already been added to the list. + :param name: str + :param description: str + :return: + """ + return self._request_obj( + self._urls["create"], + params="session_id=%s" % self.session_id, + method="POST", + json={ + "name": name, + "description": description, + "language": self.language + } + ).list_id + + def add_movie(self, list_id, movie_id): + """ + Add a movie to a list. + :param list_id: int + :param movie_id: int + """ + self._request_obj( + self._urls["add_movie"] % list_id, + params="session_id=%s" % self.session_id, + method="POST", + json={"media_id": movie_id} + ) + + def remove_movie(self, list_id, movie_id): + """ + Remove a movie from a list. + :param list_id: int + :param movie_id: int + """ + self._request_obj( + self._urls["remove_movie"] % list_id, + params="session_id=%s" % self.session_id, + method="POST", + json={"media_id": movie_id} + ) + + def clear_list(self, list_id): + """ + Clear all of the items from a list. + :param list_id: int + """ + self._request_obj( + self._urls["clear_list"] % list_id, + params="session_id=%s&confirm=true" % self.session_id, + method="POST" + ) + + def delete_list(self, list_id): + """ + Delete a list. + :param list_id: int + """ + self._request_obj( + self._urls["delete_list"] % list_id, + params="session_id=%s" % self.session_id, + method="DELETE" + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/movie.py b/app/modules/themoviedb/tmdbv3api/objs/movie.py new file mode 100644 index 00000000..58073a93 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/movie.py @@ -0,0 +1,348 @@ +import warnings +from ..tmdb import TMDb +from .find import Find +from .search import Search + + +class Movie(TMDb): + _urls = { + "details": "/movie/%s", + "account_states": "/movie/%s/account_states", + "alternative_titles": "/movie/%s/alternative_titles", + "changes": "/movie/%s/changes", + "credits": "/movie/%s/credits", + "external_ids": "/movie/%s/external_ids", + "images": "/movie/%s/images", + "keywords": "/movie/%s/keywords", + "lists": "/movie/%s/lists", + "recommendations": "/movie/%s/recommendations", + "release_dates": "/movie/%s/release_dates", + "reviews": "/movie/%s/reviews", + "similar": "/movie/%s/similar", + "translations": "/movie/%s/translations", + "videos": "/movie/%s/videos", + "watch_providers": "/movie/%s/watch/providers", + "rate_movie": "/movie/%s/rating", + "delete_rating": "/movie/%s/rating", + "latest": "/movie/latest", + "now_playing": "/movie/now_playing", + "popular": "/movie/popular", + "top_rated": "/movie/top_rated", + "upcoming": "/movie/upcoming", + } + + def details(self, movie_id, append_to_response="videos,trailers,images,casts,translations,keywords,release_dates"): + """ + Get the primary information about a movie. + :param movie_id: int + :param append_to_response: str + :return: + """ + return self._request_obj( + self._urls["details"] % movie_id, + params="append_to_response=%s" % append_to_response + ) + + def account_states(self, movie_id): + """ + Grab the following account states for a session: + Movie rating, If it belongs to your watchlist, or If it belongs to your favourite list. + :param movie_id: int + :return: + """ + return self._request_obj( + self._urls["account_states"] % movie_id, + params="session_id=%s" % self.session_id + ) + + def alternative_titles(self, movie_id, country=None): + """ + Get all of the alternative titles for a movie. + :param movie_id: int + :param country: str + :return: + """ + return self._request_obj( + self._urls["alternative_titles"] % movie_id, + params="country=%s" % country if country else "", + key="titles" + ) + + def changes(self, movie_id, start_date=None, end_date=None, page=1): + """ + Get the changes for a movie. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param movie_id: int + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls["changes"] % movie_id, + params=params, + key="changes" + ) + + def credits(self, movie_id): + """ + Get the cast and crew for a movie. + :param movie_id: int + :return: + """ + return self._request_obj(self._urls["credits"] % movie_id) + + def external_ids(self, movie_id): + """ + Get the external ids for a movie. + :param movie_id: int + :return: + """ + return self._request_obj(self._urls["external_ids"] % movie_id) + + def images(self, movie_id, include_image_language=None): + """ + Get the images that belong to a movie. + Querying images with a language parameter will filter the results. + If you want to include a fallback language (especially useful for backdrops) + you can use the include_image_language parameter. + This should be a comma separated value like so: include_image_language=en,null. + :param movie_id: int + :param include_image_language: str + :return: + """ + return self._request_obj( + self._urls["images"] % movie_id, + params="include_image_language=%s" % include_image_language if include_image_language else "" + ) + + def keywords(self, movie_id): + """ + Get the keywords associated to a movie. + :param movie_id: int + :return: + """ + return self._request_obj( + self._urls["keywords"] % movie_id, + key="keywords" + ) + + def lists(self, movie_id, page=1): + """ + Get a list of lists that this movie belongs to. + :param movie_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["lists"] % movie_id, + params="page=%s" % page, + key="results" + ) + + def recommendations(self, movie_id, page=1): + """ + Get a list of recommended movies for a movie. + :param movie_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["recommendations"] % movie_id, + params="page=%s" % page, + key="results" + ) + + def release_dates(self, movie_id): + """ + Get the release date along with the certification for a movie. + :param movie_id: int + :return: + """ + return self._request_obj( + self._urls["release_dates"] % movie_id, + key="results" + ) + + def reviews(self, movie_id, page=1): + """ + Get the user reviews for a movie. + :param movie_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["reviews"] % movie_id, + params="page=%s" % page, + key="results" + ) + + def similar(self, movie_id, page=1): + """ + Get a list of similar movies. + :param movie_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["similar"] % movie_id, + params="page=%s" % page, + key="results" + ) + + def translations(self, movie_id): + """ + Get a list of translations that have been created for a movie. + :param movie_id: int + :return: + """ + return self._request_obj( + self._urls["translations"] % movie_id, + key="translations" + ) + + def videos(self, movie_id, page=1): + """ + Get the videos that have been added to a movie. + :param movie_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["videos"] % movie_id, + params="page=%s" % page, + key="results" + ) + + def watch_providers(self, movie_id): + """ + You can query this method to get a list of the availabilities per country by provider. + :param movie_id: int + :return: + """ + return self._request_obj( + self._urls["watch_providers"] % movie_id, + key="results" + ) + + def rate_movie(self, movie_id, rating): + """ + Rate a movie. + :param movie_id: int + :param rating: float + """ + self._request_obj( + self._urls["rate_movie"] % movie_id, + params="session_id=%s" % self.session_id, + method="POST", + json={"value": rating} + ) + + def delete_rating(self, movie_id): + """ + Remove your rating for a movie. + :param movie_id: int + """ + self._request_obj( + self._urls["delete_rating"] % movie_id, + params="session_id=%s" % self.session_id, + method="DELETE" + ) + + def latest(self): + """ + Get the most newly created movie. This is a live response and will continuously change. + :return: + """ + return self._request_obj(self._urls["latest"]) + + def now_playing(self, region=None, page=1): + """ + Get a list of movies in theatres. + :param region: str + :param page: int + :return: + """ + params = "page=%s" % page + if region: + params += "®ion=%s" % region + return self._request_obj( + self._urls["now_playing"], + params=params, + key="results" + ) + + def popular(self, region=None, page=1): + """ + Get a list of the current popular movies on TMDb. This list updates daily. + :param region: str + :param page: int + :return: + """ + params = "page=%s" % page + if region: + params += "®ion=%s" % region + return self._request_obj( + self._urls["popular"], + params=params, + key="results" + ) + + def top_rated(self, region=None, page=1): + """ + Get the top rated movies on TMDb. + :param region: str + :param page: int + :return: + """ + params = "page=%s" % page + if region: + params += "®ion=%s" % region + return self._request_obj( + self._urls["top_rated"], + params=params, + key="results" + ) + + def upcoming(self, region=None, page=1): + """ + Get a list of upcoming movies in theatres. + :param region: str + :param page: int + :return: + """ + params = "page=%s" % page + if region: + params += "®ion=%s" % region + return self._request_obj( + self._urls["upcoming"], + params=params, + key="results" + ) + + def search(self, term, page=1): + """ + Search for movies. + :param term: str + :param page: int + :return: + """ + warnings.warn("search method is deprecated use tmdbv3api.Search().movies(term)", + DeprecationWarning) + return Search().movies(term, page=page) + + def external(self, external_id, external_source): + """ + The find method makes it easy to search for objects in our database by an external id. For example, an IMDB ID. + :param external_id: str + :param external_source str + :return: + """ + warnings.warn("external method is deprecated use tmdbv3api.Find().find(external_id, external_source)", + DeprecationWarning) + return Find().find(external_id, external_source) diff --git a/app/modules/themoviedb/tmdbv3api/objs/network.py b/app/modules/themoviedb/tmdbv3api/objs/network.py new file mode 100644 index 00000000..8283b43b --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/network.py @@ -0,0 +1,39 @@ +from ..tmdb import TMDb + + +class Network(TMDb): + _urls = { + "details": "/network/%s", + "alternative_names": "/network/%s/alternative_names", + "images": "/network/%s/images" + } + + def details(self, network_id): + """ + Get a networks details by id. + :param network_id: int + :return: + """ + return self._request_obj(self._urls["details"] % network_id) + + def alternative_names(self, network_id): + """ + Get the alternative names of a network. + :param network_id: int + :return: + """ + return self._request_obj( + self._urls["alternative_names"] % network_id, + key="results" + ) + + def images(self, network_id): + """ + Get the TV network logos by id. + :param network_id: int + :return: + """ + return self._request_obj( + self._urls["images"] % network_id, + key="logos" + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/person.py b/app/modules/themoviedb/tmdbv3api/objs/person.py new file mode 100644 index 00000000..277c1158 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/person.py @@ -0,0 +1,151 @@ +import warnings +from ..tmdb import TMDb +from .search import Search + + +class Person(TMDb): + _urls = { + "details": "/person/%s", + "changes": "/person/%s/changes", + "movie_credits": "/person/%s/movie_credits", + "tv_credits": "/person/%s/tv_credits", + "combined_credits": "/person/%s/combined_credits", + "external_ids": "/person/%s/external_ids", + "images": "/person/%s/images", + "tagged_images": "/person/%s/tagged_images", + "translations": "/person/%s/translations", + "latest": "/person/latest", + "popular": "/person/popular", + "search_people": "/search/person", + } + + def details(self, person_id, append_to_response="videos,images"): + """ + Get the primary person details by id. + :param append_to_response: str + :param person_id: int + :return: + """ + return self._request_obj( + self._urls["details"] % person_id, + params="append_to_response=%s" % append_to_response + ) + + def changes(self, person_id, start_date=None, end_date=None, page=1): + """ + Get the changes for a person. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param person_id: int + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls["changes"] % person_id, + params=params, + key="changes" + ) + + def movie_credits(self, person_id): + """ + Get the movie credits for a person. + :param person_id: int + :return: + """ + return self._request_obj(self._urls["movie_credits"] % person_id) + + def tv_credits(self, person_id): + """ + Get the TV show credits for a person. + :param person_id: int + :return: + """ + return self._request_obj(self._urls["tv_credits"] % person_id) + + def combined_credits(self, person_id): + """ + Get the movie and TV credits together in a single response. + :param person_id: int + :return: + """ + return self._request_obj(self._urls["combined_credits"] % person_id) + + def external_ids(self, person_id): + """ + Get the external ids for a person. We currently support the following external sources. + IMDB ID, Facebook, Freebase MID, Freebase ID, Instagram, TVRage ID, and Twitter + :param person_id: int + :return: + """ + return self._request_obj(self._urls["external_ids"] % person_id) + + def images(self, person_id): + """ + Get the images for a person. + :param person_id: int + :return: + """ + return self._request_obj( + self._urls["images"] % person_id, + key="profiles" + ) + + def tagged_images(self, person_id, page=1): + """ + Get the images that this person has been tagged in. + :param person_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["tagged_images"] % person_id, + params="page=%s" % page, + key="results" + ) + + def translations(self, person_id): + """ + Get a list of translations that have been created for a person. + :param person_id: int + :return: + """ + return self._request_obj( + self._urls["translations"] % person_id, + key="translations" + ) + + def latest(self): + """ + Get the most newly created person. This is a live response and will continuously change. + :return: + """ + return self._request_obj(self._urls["latest"]) + + def popular(self, page=1): + """ + Get the list of popular people on TMDb. This list updates daily. + :param page: int + :return: + """ + return self._request_obj( + self._urls["popular"], + params="page=%s" % page, + key="results" + ) + + def search(self, term, page=1): + """ + Search for people. + :param term: string + :param page: int + :return: + """ + warnings.warn("search method is deprecated use tmdbv3api.Search().people(params)", + DeprecationWarning) + return Search().people(term, page=page) diff --git a/app/modules/themoviedb/tmdbv3api/objs/provider.py b/app/modules/themoviedb/tmdbv3api/objs/provider.py new file mode 100644 index 00000000..7abb3f7f --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/provider.py @@ -0,0 +1,41 @@ +from ..tmdb import TMDb + + +class Provider(TMDb): + _urls = { + "regions": "/watch/providers/regions", # TODO: + "movie": "/watch/providers/movie", # TODO: + "tv": "/watch/providers/tv", # TODO: + } + + def available_regions(self): + """ + Returns a list of all of the countries we have watch provider (OTT/streaming) data for. + :return: + """ + return self._request_obj( + self._urls["regions"], + key="results" + ) + + def movie_providers(self, region=None): + """ + Returns a list of the watch provider (OTT/streaming) data we have available for movies. + :return: + """ + return self._request_obj( + self._urls["movie"], + params="watch_region=%s" % region if region else "", + key="results" + ) + + def tv_providers(self, region=None): + """ + Returns a list of the watch provider (OTT/streaming) data we have available for TV series. + :return: + """ + return self._request_obj( + self._urls["tv"], + params="watch_region=%s" % region if region else "", + key="results" + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/review.py b/app/modules/themoviedb/tmdbv3api/objs/review.py new file mode 100644 index 00000000..4d2d217b --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/review.py @@ -0,0 +1,15 @@ +from ..tmdb import TMDb + + +class Review(TMDb): + _urls = { + "details": "/review/%s", + } + + def details(self, review_id): + """ + Get the primary person details by id. + :param review_id: int + :return: + """ + return self._request_obj(self._urls["details"] % review_id) diff --git a/app/modules/themoviedb/tmdbv3api/objs/search.py b/app/modules/themoviedb/tmdbv3api/objs/search.py new file mode 100644 index 00000000..1d4b377e --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/search.py @@ -0,0 +1,144 @@ +from ..tmdb import TMDb + +try: + from urllib import quote +except ImportError: + from urllib.parse import quote + + +class Search(TMDb): + _urls = { + "companies": "/search/company", + "collections": "/search/collection", + "keywords": "/search/keyword", + "movies": "/search/movie", + "multi": "/search/multi", + "people": "/search/person", + "tv_shows": "/search/tv", + } + + def companies(self, term, page=1): + """ + Search for companies. + :param term: str + :param page: int + :return: + """ + return self._request_obj( + self._urls["companies"], + params="query=%s&page=%s" % (quote(term), page), + key="results" + ) + + def collections(self, term, page=1): + """ + Search for collections. + :param term: str + :param page: int + :return: + """ + return self._request_obj( + self._urls["collections"], + params="query=%s&page=%s" % (quote(term), page), + key="results" + ) + + def keywords(self, term, page=1): + """ + Search for keywords. + :param term: str + :param page: int + :return: + """ + return self._request_obj( + self._urls["keywords"], + params="query=%s&page=%s" % (quote(term), page), + key="results" + ) + + def movies(self, term, adult=None, region=None, year=None, release_year=None, page=1): + """ + Search for movies. + :param term: str + :param adult: bool + :param region: str + :param year: int + :param release_year: int + :param page: int + :return: + """ + params = "query=%s&page=%s" % (quote(term), page) + if adult is not None: + params += "&include_adult=%s" % "true" if adult else "false" + if region is not None: + params += "®ion=%s" % quote(region) + if year is not None: + params += "&year=%s" % year + if release_year is not None: + params += "&primary_release_year=%s" % release_year + return self._request_obj( + self._urls["movies"], + params=params, + key="results" + ) + + def multi(self, term, adult=None, region=None, page=1): + """ + Search multiple models in a single request. + Multi search currently supports searching for movies, tv shows and people in a single request. + :param term: str + :param adult: bool + :param region: str + :param page: int + :return: + """ + params = "query=%s&page=%s" % (quote(term), page) + if adult is not None: + params += "&include_adult=%s" % "true" if adult else "false" + if region is not None: + params += "®ion=%s" % quote(region) + return self._request_obj( + self._urls["multi"], + params=params, + key="results" + ) + + def people(self, term, adult=None, region=None, page=1): + """ + Search for people. + :param term: str + :param adult: bool + :param region: str + :param page: int + :return: + """ + params = "query=%s&page=%s" % (quote(term), page) + if adult is not None: + params += "&include_adult=%s" % "true" if adult else "false" + if region is not None: + params += "®ion=%s" % quote(region) + return self._request_obj( + self._urls["people"], + params=params, + key="results" + ) + + def tv_shows(self, term, adult=None, release_year=None, page=1): + """ + Search for a TV show. + :param term: str + :param adult: bool + :param release_year: int + :param page: int + :return: + """ + params = "query=%s&page=%s" % (quote(term), page) + if adult is not None: + params += "&include_adult=%s" % "true" if adult else "false" + if release_year is not None: + params += "&first_air_date_year=%s" % release_year + return self._request_obj( + self._urls["tv_shows"], + params=params, + key="results" + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/season.py b/app/modules/themoviedb/tmdbv3api/objs/season.py new file mode 100644 index 00000000..4a5c3927 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/season.py @@ -0,0 +1,133 @@ +from ..tmdb import TMDb + + +class Season(TMDb): + _urls = { + "details": "/tv/%s/season/%s", + "account_states": "/tv/%s/season/%s/account_states", + "aggregate_credits": "/tv/%s/season/%s/aggregate_credits", + "changes": "/tv/season/%s/changes", + "credits": "/tv/%s/season/%s/credits", + "external_ids": "/tv/%s/season/%s/external_ids", + "images": "/tv/%s/season/%s/images", + "translations": "/tv/%s/season/%s/translations", + "videos": "/tv/%s/season/%s/videos", + } + + def details(self, tv_id, season_num, append_to_response="videos,trailers,images,credits,translations"): + """ + Get the TV season details by id. + :param tv_id: int + :param season_num: int + :param append_to_response: str + :return: + """ + return self._request_obj( + self._urls["details"] % (tv_id, season_num), + params="append_to_response=%s" % append_to_response + ) + + def account_states(self, tv_id, season_num): + """ + Get all of the user ratings for the season's episodes. + :param tv_id: int + :param season_num: int + :return: + """ + return self._request_obj( + self._urls["account_states"] % (tv_id, season_num), + params="session_id=%s" % self.session_id, + key="results" + ) + + def aggregate_credits(self, tv_id, season_num): + """ + Get the aggregate credits for TV season. + This call differs from the main credits call in that it does not only return the season credits, + but rather is a view of all the cast & crew for all of the episodes belonging to a season. + :param tv_id: int + :param season_num: int + :return: + """ + return self._request_obj(self._urls["aggregate_credits"] % (tv_id, season_num)) + + def changes(self, season_id, start_date=None, end_date=None, page=1): + """ + Get the changes for a TV season. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param season_id: int + :param start_date: str + :param end_date: str + :param page: int + :return: + """ + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls["changes"] % season_id, + params=params, + key="changes" + ) + + def credits(self, tv_id, season_num): + """ + Get the credits for TV season. + :param tv_id: int + :param season_num: int + :return: + """ + return self._request_obj(self._urls["credits"] % (tv_id, season_num)) + + def external_ids(self, tv_id, season_num): + """ + Get the external ids for a TV season. + :param tv_id: int + :param season_num: int + :return: + """ + return self._request_obj(self._urls["external_ids"] % (tv_id, season_num)) + + def images(self, tv_id, season_num, include_image_language=None): + """ + Get the images that belong to a TV season. + :param tv_id: int + :param season_num: int + :param include_image_language: str + :return: + """ + return self._request_obj( + self._urls["images"] % (tv_id, season_num), + params="include_image_language=%s" % include_image_language if include_image_language else "", + key="posters" + ) + + def translations(self, tv_id, season_num): + """ + Get a list of the translations that exist for a TV show. + :param tv_id: int + :param season_num: int + """ + return self._request_obj( + self._urls["translations"] % (tv_id, season_num), + key="translations" + ) + + def videos(self, tv_id, season_num, include_video_language=None, page=1): + """ + Get the videos that have been added to a TV show. + :param tv_id: int + :param season_num: int + :param include_video_language: str + :param page: int + :return: + """ + params = "page=%s" % page + if include_video_language: + params += "&include_video_language=%s" % include_video_language + return self._request_obj( + self._urls["videos"] % (tv_id, season_num), + params=params + ) diff --git a/app/modules/themoviedb/tmdbv3api/objs/trending.py b/app/modules/themoviedb/tmdbv3api/objs/trending.py new file mode 100644 index 00000000..d3dd904b --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/trending.py @@ -0,0 +1,75 @@ +from ..tmdb import TMDb + + +class Trending(TMDb): + _urls = {"trending": "/trending/%s/%s"} + + def _trending(self, media_type="all", time_window="day", page=1): + return self._request_obj( + self._urls["trending"] % (media_type, time_window), + params="page=%s" % page + ) + + def all_day(self, page=1): + """ + Get all daily trending + :param page: int + :return: + """ + return self._trending(media_type="all", time_window="day", page=page) + + def all_week(self, page=1): + """ + Get all weekly trending + :param page: int + :return: + """ + return self._trending(media_type="all", time_window="week", page=page) + + def movie_day(self, page=1): + """ + Get movie daily trending + :param page: int + :return: + """ + return self._trending(media_type="movie", time_window="day", page=page) + + def movie_week(self, page=1): + """ + Get movie weekly trending + :param page: int + :return: + """ + return self._trending(media_type="movie", time_window="week", page=page) + + def tv_day(self, page=1): + """ + Get tv daily trending + :param page: int + :return: + """ + return self._trending(media_type="tv", time_window="day", page=page) + + def tv_week(self, page=1): + """ + Get tv weekly trending + :param page: int + :return: + """ + return self._trending(media_type="tv", time_window="week", page=page) + + def person_day(self, page=1): + """ + Get person daily trending + :param page: int + :return: + """ + return self._trending(media_type="person", time_window="day", page=page) + + def person_week(self, page=1): + """ + Get person weekly trending + :param page: int + :return: + """ + return self._trending(media_type="person", time_window="week", page=page) diff --git a/app/modules/themoviedb/tmdbv3api/objs/tv.py b/app/modules/themoviedb/tmdbv3api/objs/tv.py new file mode 100644 index 00000000..d9a21711 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/objs/tv.py @@ -0,0 +1,334 @@ +from ..tmdb import TMDb + +try: + from urllib import quote +except ImportError: + from urllib.parse import quote + + +class TV(TMDb): + _urls = { + "details": "/tv/%s", + "account_states": "/tv/%s/account_states", + "aggregate_credits": "/tv/%s/aggregate_credits", + "alternative_titles": "/tv/%s/alternative_titles", + "changes": "/tv/%s/changes", + "content_ratings": "/tv/%s/content_ratings", + "credits": "/tv/%s/credits", + "episode_groups": "/tv/%s/episode_groups", + "external_ids": "/tv/%s/external_ids", + "images": "/tv/%s/images", + "keywords": "/tv/%s/keywords", + "recommendations": "/tv/%s/recommendations", + "reviews": "/tv/%s/reviews", + "screened_theatrically": "/tv/%s/screened_theatrically", + "similar": "/tv/%s/similar", + "translations": "/tv/%s/translations", + "videos": "/tv/%s/videos", + "watch_providers": "/tv/%s/watch/providers", + "rate_tv_show": "/tv/%s/rating", + "delete_rating": "/tv/%s/rating", + "latest": "/tv/latest", + "airing_today": "/tv/airing_today", + "on_the_air": "/tv/on_the_air", + "popular": "/tv/popular", + "top_rated": "/tv/top_rated", + } + + def details(self, tv_id, append_to_response="videos,trailers,images,credits,translations"): + """ + Get the primary TV show details by id. + :param tv_id: int + :param append_to_response: str + :return: + """ + return self._request_obj( + self._urls["details"] % tv_id, + params="append_to_response=%s" % append_to_response, + ) + + def account_states(self, tv_id): + """ + Grab the following account states for a session: + TV show rating, If it belongs to your watchlist, or If it belongs to your favourite list. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["account_states"] % tv_id, + params="session_id=%s" % self.session_id + ) + + def aggregate_credits(self, tv_id): + """ + Get the aggregate credits (cast and crew) that have been added to a TV show. + This call differs from the main credits call in that it does not return the newest season but rather, + is a view of all the entire cast & crew for all episodes belonging to a TV show. + :param tv_id: int + :return: + """ + return self._request_obj(self._urls["aggregate_credits"] % tv_id) + + def alternative_titles(self, tv_id): + """ + Returns all of the alternative titles for a TV show. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["alternative_titles"] % tv_id, + key="results" + ) + + def changes(self, tv_id, start_date=None, end_date=None, page=1): + """ + Get the changes for a TV show. By default only the last 24 hours are returned. + You can query up to 14 days in a single query by using the start_date and end_date query parameters. + :param tv_id: int + :param start_date: str + :param end_date: str + :param page: int + """ + params = "page=%s" % page + if start_date: + params += "&start_date=%s" % start_date + if end_date: + params += "&end_date=%s" % end_date + return self._request_obj( + self._urls["changes"] % tv_id, + params=params, + key="changes" + ) + + def content_ratings(self, tv_id): + """ + Get the list of content ratings (certifications) that have been added to a TV show. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["content_ratings"] % tv_id, + key="results" + ) + + def credits(self, tv_id): + """ + Get the credits (cast and crew) that have been added to a TV show. + :param tv_id: int + :return: + """ + return self._request_obj(self._urls["credits"] % tv_id) + + def episode_groups(self, tv_id): + """ + Get all of the episode groups that have been created for a TV show. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["episode_groups"] % tv_id, + key="results" + ) + + def external_ids(self, tv_id): + """ + Get the external ids for a TV show. + :param tv_id: int + :return: + """ + return self._request_obj(self._urls["external_ids"] % tv_id) + + def images(self, tv_id, include_image_language=None): + """ + Get the images that belong to a TV show. + Querying images with a language parameter will filter the results. + If you want to include a fallback language (especially useful for backdrops) + you can use the include_image_language parameter. + This should be a comma separated value like so: include_image_language=en,null. + :param tv_id: int + :param include_image_language: str + :return: + """ + return self._request_obj( + self._urls["images"] % tv_id, + params="include_image_language=%s" % include_image_language if include_image_language else "" + ) + + def keywords(self, tv_id): + """ + Get the keywords that have been added to a TV show. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["keywords"] % tv_id, + key="results" + ) + + def recommendations(self, tv_id, page=1): + """ + Get the list of TV show recommendations for this item. + :param tv_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["recommendations"] % tv_id, + params="page=%s" % page, + key="results" + ) + + def reviews(self, tv_id, page=1): + """ + Get the reviews for a TV show. + :param tv_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["reviews"] % tv_id, + params="page=%s" % page, + key="results" + ) + + def screened_theatrically(self, tv_id): + """ + Get a list of seasons or episodes that have been screened in a film festival or theatre. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["screened_theatrically"] % tv_id, + key="results" + ) + + def similar(self, tv_id, page=1): + """ + Get the primary TV show details by id. + :param tv_id: int + :param page: int + :return: + """ + return self._request_obj( + self._urls["similar"] % tv_id, + params="page=%s" % page, + key="results" + ) + + def translations(self, tv_id): + """ + Get a list of the translations that exist for a TV show. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["translations"] % tv_id, + key="translations" + ) + + def videos(self, tv_id, include_video_language=None, page=1): + """ + Get the videos that have been added to a TV show. + :param tv_id: int + :param include_video_language: str + :param page: int + :return: + """ + params = "page=%s" % page + if include_video_language: + params += "&include_video_language=%s" % include_video_language + return self._request_obj( + self._urls["videos"] % tv_id, + params=params + ) + + def watch_providers(self, tv_id): + """ + You can query this method to get a list of the availabilities per country by provider. + :param tv_id: int + :return: + """ + return self._request_obj( + self._urls["watch_providers"] % tv_id, + key="results" + ) + + def rate_tv_show(self, tv_id, rating): + """ + Rate a TV show. + :param tv_id: int + :param rating: float + """ + self._request_obj( + self._urls["rate_tv_show"] % tv_id, + params="session_id=%s" % self.session_id, + method="POST", + json={"value": rating} + ) + + def delete_rating(self, tv_id): + """ + Remove your rating for a TV show. + :param tv_id: int + """ + self._request_obj( + self._urls["delete_rating"] % tv_id, + params="session_id=%s" % self.session_id, + method="DELETE" + ) + + def latest(self): + """ + Get the most newly created TV show. This is a live response and will continuously change. + :return: + """ + return self._request_obj(self._urls["latest"]) + + def airing_today(self, page=1): + """ + Get a list of TV shows that are airing today. + This query is purely day based as we do not currently support airing times. + :param page: int + :return: + """ + return self._request_obj( + self._urls["airing_today"], + params="page=%s" % page, + key="results" + ) + + def on_the_air(self, page=1): + """ + Get a list of shows that are currently on the air. + :param page: + :return: + """ + return self._request_obj( + self._urls["on_the_air"], + params="page=%s" % page, + key="results" + ) + + def popular(self, page=1): + """ + Get a list of the current popular TV shows on TMDb. This list updates daily. + :param page: + :return: + """ + return self._request_obj( + self._urls["popular"], + params="page=%s" % page, + key="results" + ) + + def top_rated(self, page=1): + """ + Get a list of the top rated TV shows on TMDb. + :param page: + :return: + """ + return self._request_obj( + self._urls["top_rated"], + params="page=%s" % page, + key="results" + ) diff --git a/app/modules/themoviedb/tmdbv3api/tmdb.py b/app/modules/themoviedb/tmdbv3api/tmdb.py new file mode 100644 index 00000000..87d21b52 --- /dev/null +++ b/app/modules/themoviedb/tmdbv3api/tmdb.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +import logging +import os +import time + +import requests +import requests.exceptions + +from .as_obj import AsObj +from .exceptions import TMDbException +from functools import lru_cache + +logger = logging.getLogger(__name__) + + +class TMDb(object): + _session = None + TMDB_API_KEY = "TMDB_API_KEY" + TMDB_LANGUAGE = "TMDB_LANGUAGE" + TMDB_SESSION_ID = "TMDB_SESSION_ID" + TMDB_WAIT_ON_RATE_LIMIT = "TMDB_WAIT_ON_RATE_LIMIT" + TMDB_DEBUG_ENABLED = "TMDB_DEBUG_ENABLED" + TMDB_CACHE_ENABLED = "TMDB_CACHE_ENABLED" + TMDB_PROXIES = "TMDB_PROXIES" + REQUEST_CACHE_MAXSIZE = None + + def __init__(self, obj_cached=True, session=None): + if self.__class__._session is None or session is not None: + self.__class__._session = requests.Session() if session is None else session + self._base = "https://api.themoviedb.org/3" + self._remaining = 40 + self._reset = None + self.obj_cached = obj_cached + if os.environ.get(self.TMDB_LANGUAGE) is None: + os.environ[self.TMDB_LANGUAGE] = "en-US" + + @property + def page(self): + return os.environ["page"] + + @property + def total_results(self): + return os.environ["total_results"] + + @property + def total_pages(self): + return os.environ["total_pages"] + + @property + def api_key(self): + return os.environ.get(self.TMDB_API_KEY) + + @property + def proxies(self): + proxy = os.environ.get(self.TMDB_PROXIES) + if proxy is not None: + proxy = eval(proxy) + return proxy + + @proxies.setter + def proxies(self, proxies): + if proxies is not None: + os.environ[self.TMDB_PROXIES] = str(proxies) + + @api_key.setter + def api_key(self, api_key): + os.environ[self.TMDB_API_KEY] = str(api_key) + + @property + def language(self): + return os.environ.get(self.TMDB_LANGUAGE) + + @language.setter + def language(self, language): + os.environ[self.TMDB_LANGUAGE] = language + + @property + def has_session(self): + return True if os.environ.get(self.TMDB_SESSION_ID) else False + + @property + def session_id(self): + if not os.environ.get(self.TMDB_SESSION_ID): + raise TMDbException("Must Authenticate to create a session run Authentication(username, password)") + return os.environ.get(self.TMDB_SESSION_ID) + + @session_id.setter + def session_id(self, session_id): + os.environ[self.TMDB_SESSION_ID] = session_id + + @property + def wait_on_rate_limit(self): + if os.environ.get(self.TMDB_WAIT_ON_RATE_LIMIT) == "False": + return False + else: + return True + + @wait_on_rate_limit.setter + def wait_on_rate_limit(self, wait_on_rate_limit): + os.environ[self.TMDB_WAIT_ON_RATE_LIMIT] = str(wait_on_rate_limit) + + @property + def debug(self): + if os.environ.get(self.TMDB_DEBUG_ENABLED) == "True": + return True + else: + return False + + @debug.setter + def debug(self, debug): + os.environ[self.TMDB_DEBUG_ENABLED] = str(debug) + + @property + def cache(self): + if os.environ.get(self.TMDB_CACHE_ENABLED) == "False": + return False + else: + return True + + @cache.setter + def cache(self, cache): + os.environ[self.TMDB_CACHE_ENABLED] = str(cache) + + @staticmethod + @lru_cache(maxsize=REQUEST_CACHE_MAXSIZE) + def cached_request(method, url, data, json, proxies): + return requests.request(method, url, data=data, json=json, proxies=proxies) + + def cache_clear(self): + return self.cached_request.cache_clear() + + def _request_obj(self, action, params="", call_cached=True, method="GET", data=None, json=None, key=None): + if self.api_key is None or self.api_key == "": + raise TMDbException("No API key found.") + + url = "%s%s?api_key=%s&%s&language=%s" % ( + self._base, + action, + self.api_key, + params, + self.language, + ) + + if self.cache and self.obj_cached and call_cached and method != "POST": + req = self.cached_request(method, url, data, json, self.proxies) + else: + req = self.__class__._session.request(method, url, data=data, json=json, proxies=self.proxies) + + headers = req.headers + + if "X-RateLimit-Remaining" in headers: + self._remaining = int(headers["X-RateLimit-Remaining"]) + + if "X-RateLimit-Reset" in headers: + self._reset = int(headers["X-RateLimit-Reset"]) + + if self._remaining < 1: + current_time = int(time.time()) + sleep_time = self._reset - current_time + + if self.wait_on_rate_limit: + logger.warning("Rate limit reached. Sleeping for: %d" % sleep_time) + time.sleep(abs(sleep_time)) + return self._request_obj(action, params, call_cached, method, data, json, key) + else: + raise TMDbException("Rate limit reached. Try again in %d seconds." % sleep_time) + + json = req.json() + + if "page" in json: + os.environ["page"] = str(json["page"]) + + if "total_results" in json: + os.environ["total_results"] = str(json["total_results"]) + + if "total_pages" in json: + os.environ["total_pages"] = str(json["total_pages"]) + + if self.debug: + logger.info(json) + logger.info(self.cached_request.cache_info()) + + if "errors" in json: + raise TMDbException(json["errors"]) + + if "success" in json and json["success"] is False: + raise TMDbException(json["status_message"]) + + return AsObj(json, key=key) diff --git a/app/schemas/tmdb.py b/app/schemas/tmdb.py index 58c21618..efb7878e 100644 --- a/app/schemas/tmdb.py +++ b/app/schemas/tmdb.py @@ -30,3 +30,12 @@ class TmdbEpisode(BaseModel): vote_average: Optional[float] = None crew: Optional[list] = [] guest_stars: Optional[list] = [] + + +class TmdbCast(BaseModel): + id: Optional[int] = None + name: Optional[str] = None + character: Optional[str] = None + profile_path: Optional[str] = None + gender: Optional[int] = None + original_name: Optional[str] = None diff --git a/requirements.txt b/requirements.txt index 12ad2a5b..bc5abaff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,6 @@ anitopy~=2.1.1 requests~=2.31.0 urllib3~=2.0.2 lxml~=4.9.2 -tmdbv3api~=1.7.7 pyquery~=2.0.0 ruamel.yaml~=0.17.31 APScheduler~=3.10.1 diff --git a/tests/run.py b/tests/run.py index a36036d4..78e85040 100644 --- a/tests/run.py +++ b/tests/run.py @@ -1,7 +1,6 @@ import unittest from tests.test_cookiecloud import CookieCloudTest -from tests.test_doubansync import DoubanSyncTest from tests.test_filter import FilterTest from tests.test_metainfo import MetaInfoTest from tests.test_recognize import RecognizeTest @@ -11,17 +10,15 @@ if __name__ == '__main__': suite = unittest.TestSuite() # 测试过滤器 - # suite.addTest(FilterTest('test_filter')) + suite.addTest(FilterTest('test_filter')) # 测试名称识别 suite.addTest(MetaInfoTest('test_metainfo')) # 测试媒体识别 - # suite.addTest(RecognizeTest('test_recognize')) + suite.addTest(RecognizeTest('test_recognize')) # 测试CookieCloud同步 - # suite.addTest(CookieCloudTest('test_cookiecloud')) + suite.addTest(CookieCloudTest('test_cookiecloud')) # 测试文件转移 - # suite.addTest(TransferTest('test_transfer')) - # 测试豆瓣同步 - # suite.addTest(DoubanSyncTest('test_doubansync')) + suite.addTest(TransferTest('test_transfer')) # 运行测试 runner = unittest.TextTestRunner() diff --git a/tests/test_doubansync.py b/tests/test_doubansync.py deleted file mode 100644 index 316af178..00000000 --- a/tests/test_doubansync.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- - -from unittest import TestCase - -from app.chain.douban import DoubanChain - - -class DoubanSyncTest(TestCase): - def setUp(self) -> None: - pass - - def tearDown(self) -> None: - pass - - @staticmethod - def test_doubansync(): - DoubanChain().sync()