├── setup.cfg ├── .gitignore ├── tests ├── __init__.py ├── keys.py ├── test_requests_session.py ├── test_changes.py ├── test_genres.py ├── test_find.py ├── test_discover.py ├── test_search.py ├── test_base.py ├── test_people.py ├── test_configuration.py ├── test_movies.py ├── test_tv.py └── test_account.py ├── .github └── workflows │ ├── python-publish.yml │ └── python-package.yml ├── setup.py ├── tmdbsimple ├── __init__.py ├── genres.py ├── changes.py ├── find.py ├── base.py ├── configuration.py ├── search.py ├── people.py ├── discover.py ├── account.py ├── movies.py └── tv.py └── README.md /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = .git,__pycache__,build,dist 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python files 2 | *.py[cod] 3 | *.py.swo 4 | *.egg-info 5 | __pycache__ 6 | build 7 | dist 8 | 9 | # Make files 10 | Makefile 11 | 12 | # Build files 13 | .coverage 14 | coverage.xml 15 | htmlcov 16 | 17 | # Editor files 18 | ## Vim files 19 | .*.swp 20 | .idea 21 | .vscode 22 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | __init__.py 5 | ~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of tmdbsimple. 8 | 9 | Use the following command to run all the tests: 10 | python -W ignore:ResourceWarning -m unittest discover tests 11 | 12 | :copyright: (c) 2013-2025 by Celia Oakley. 13 | :license: GPLv3, see LICENSE for more details. 14 | """ 15 | 16 | """ 17 | Either place your API_KEY in the following constant: 18 | """ 19 | API_KEY = '' 20 | 21 | """ 22 | or include it in a keys.py file. 23 | """ 24 | try: 25 | from .keys import API_KEY, USERNAME, PASSWORD, SESSION_ID 26 | except ImportError: 27 | pass 28 | 29 | __all__ = ['API_KEY', 'USERNAME', 'PASSWORD', 'SESSION_ID'] 30 | -------------------------------------------------------------------------------- /tests/keys.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | keys.py 5 | ~~~~~~~ 6 | 7 | This file contains the private keys for tmdbsimple. 8 | 9 | See: 10 | https://developers.themoviedb.org/3/getting-started/introduction 11 | https://developers.themoviedb.org/3/getting-started/authentication 12 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id 13 | """ 14 | 15 | import os 16 | 17 | API_KEY = os.environ.get('TMDB_API_KEY') or '' 18 | USERNAME = os.environ.get('TMDB_USERNAME') or '' 19 | PASSWORD = os.environ.get('TMDB_PASSWORD') or '' 20 | SESSION_ID = os.environ.get('TMDB_SESSION_ID') or '' 21 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload tmdbsimple to PyPI using Twine when a tag 2 | # (release) is pushed. 3 | 4 | name: pypi 5 | 6 | on: 7 | push: 8 | tags: 9 | - '*' 10 | 11 | jobs: 12 | deploy: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.x' 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install setuptools wheel twine 26 | - name: Build and publish 27 | env: 28 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 29 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 30 | run: | 31 | python setup.py sdist bdist_wheel 32 | twine upload dist/* 33 | -------------------------------------------------------------------------------- /tests/test_requests_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | test_requests_session.py 4 | ~~~~~~~~~~~~~~ 5 | 6 | This test suite checks having a user-defined REQUESTS_SESSION with tmdbsimple. 7 | 8 | Created by Celia Oakley on 2022-01-18 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley. 11 | :license: GPLv3, see LICENSE for more details. 12 | """ 13 | 14 | import unittest 15 | import tmdbsimple as tmdb 16 | 17 | from tests import API_KEY 18 | tmdb.API_KEY = API_KEY 19 | 20 | import requests 21 | tmdb.REQUESTS_SESSION = requests.Session() # specify an explicit session 22 | 23 | """ 24 | Constants 25 | """ 26 | MOVIE_ID = 103332 27 | MOVIE_TITLE = 'Ruby Sparks' 28 | 29 | 30 | class RequestsSessionTestCase(unittest.TestCase): 31 | def test_requests_session(self): 32 | id = MOVIE_ID 33 | title = MOVIE_TITLE 34 | movie = tmdb.Movies(id) 35 | movie.info() 36 | self.assertEqual(movie.title, title) 37 | -------------------------------------------------------------------------------- /tests/test_changes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_changes.py 5 | ~~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Changes class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | 22 | class ChangesTestCase(unittest.TestCase): 23 | def test_changes_movie(self): 24 | changes = tmdb.Changes() 25 | changes.movie() 26 | self.assertTrue(hasattr(changes, 'results')) 27 | 28 | def test_changes_tv(self): 29 | change = tmdb.Changes() 30 | change.tv() 31 | self.assertTrue(hasattr(change, 'results')) 32 | 33 | def test_changes_person(self): 34 | change = tmdb.Changes() 35 | change.person() 36 | self.assertTrue(hasattr(change, 'results')) 37 | -------------------------------------------------------------------------------- /tests/test_genres.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_genres.py 5 | ~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Genres class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | GENRE_ID = 18 25 | 26 | 27 | class GenresTestCase(unittest.TestCase): 28 | def test_genres_movie_list(self): 29 | genre = tmdb.Genres() 30 | genre.movie_list() 31 | self.assertTrue(hasattr(genre, 'genres')) 32 | 33 | def test_genres_tv_list(self): 34 | genre = tmdb.Genres() 35 | genre.tv_list() 36 | self.assertTrue(hasattr(genre, 'genres')) 37 | 38 | def test_genres_movies(self): 39 | id = GENRE_ID 40 | genre = tmdb.Genres(id) 41 | genre.movies() 42 | self.assertTrue(hasattr(genre, 'results')) 43 | -------------------------------------------------------------------------------- /tests/test_find.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_find.py 5 | ~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Find class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | FIND_MOVIE_ID = 'tt0266543' 25 | FIND_SOURCE = 'imdb_id' 26 | FIND_TITLE = 'Finding Nemo' 27 | TRENDING_MEDIA_TYPE = 'movie' 28 | TRENDING_TIME_WINDOW = 'week' 29 | 30 | 31 | class FindTestCase(unittest.TestCase): 32 | def test_find_info(self): 33 | id = FIND_MOVIE_ID 34 | external_source = FIND_SOURCE 35 | title = FIND_TITLE 36 | find = tmdb.Find(id) 37 | find.info(external_source=external_source) 38 | self.assertEqual(find.movie_results[0]['title'], title) 39 | 40 | 41 | class TrendingTestCase(unittest.TestCase): 42 | def test_trending_info(self): 43 | media_type = TRENDING_MEDIA_TYPE 44 | time_window = TRENDING_TIME_WINDOW 45 | trend = tmdb.Trending(media_type=media_type, time_window=time_window) 46 | trend.info() 47 | self.assertEqual(trend.results[0]['media_type'], TRENDING_MEDIA_TYPE) 48 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # See http://pythonhosted.org/an_example_pypi_project/setuptools.html 4 | # See https://packaging.python.org/tutorials/packaging-projects/#uploading-your-project-to-pypi 5 | 6 | from setuptools import setup 7 | 8 | with open("README.md", "r") as fh: 9 | long_description = fh.read() 10 | 11 | setup( 12 | name='tmdbsimple', 13 | version='2.9.2', 14 | author='Celia Oakley', 15 | author_email='celia.oakley@alumni.stanford.edu', 16 | description='A Python wrapper for The Movie Database API v3', 17 | keywords=['movie', 'the movie database', 'movie database', 'tmdb', 18 | 'wrapper', 'database', 'themoviedb', 'moviedb', 'api'], 19 | url='https://github.com/celiao/tmdbsimple', 20 | download_url='https://github.com/celiao/tmdbsimple/tarball/2.9.2', 21 | packages=['tmdbsimple'], 22 | long_description=long_description, 23 | long_description_content_type="text/markdown", 24 | install_requires=['requests'], 25 | classifiers=[ 26 | "Development Status :: 5 - Production/Stable", 27 | "Intended Audience :: Developers", 28 | "Operating System :: OS Independent", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.9", 31 | "Programming Language :: Python :: 3.10", 32 | "Programming Language :: Python :: 3.11", 33 | "Topic :: Utilities", 34 | ], 35 | ) 36 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run lint, execute tests, and 2 | # upload coverage with a variety of Python versions. 3 | 4 | name: build 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: ["3.9", "3.10", "3.11"] 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Set up Python ${{ matrix.python-version }} 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install flake8 28 | pip install pytest 29 | pip install pytest-cov 30 | pip install codecov 31 | pip install requests 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Test with pytest 39 | env: 40 | TMDB_API_KEY: ${{ secrets.TMDB_API_KEY }} 41 | TMDB_USERNAME: ${{ secrets.TMDB_USERNAME }} 42 | TMDB_PASSWORD: ${{ secrets.TMDB_PASSWORD }} 43 | TMDB_SESSION_ID: ${{ secrets.TMDB_SESSION_ID }} 44 | run: | 45 | pytest --cov=tmdbsimple --cov-report term-missing --cov-report=xml 46 | - name: Upload coverage to Codecov 47 | uses: codecov/codecov-action@v4 48 | with: 49 | files: ./coverage.xml 50 | name: codecov-tmdbsimple 51 | # token: ${{ secrets.CODECOV_TOKEN }} # not needed for public repos 52 | -------------------------------------------------------------------------------- /tests/test_discover.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_discover.py 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Discover class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | DISCOVER_YEAR = 2004 25 | DISCOVER_VOTE_AVERAGE_GTE = 5 26 | DISCOVER_VOTE_AVERAGE_LTE = 5 27 | 28 | 29 | class DiscoverTestCase(unittest.TestCase): 30 | def test_discover_movie(self): 31 | discover = tmdb.Discover() 32 | discover.movie(page=1, year=DISCOVER_YEAR) 33 | self.assertTrue(hasattr(discover, 'results')) 34 | 35 | # Test dot usage 36 | def test_discover_movie_dot_gte(self): 37 | discover = tmdb.Discover() 38 | kwargs = {'page': 2, 'vote_average.gte': DISCOVER_VOTE_AVERAGE_GTE} 39 | discover.movie(**kwargs) 40 | self.assertTrue(hasattr(discover, 'results')) 41 | 42 | # Test underscore usage 43 | def test_discover_movie_underscore_gte(self): 44 | discover = tmdb.Discover() 45 | discover.movie(page=2, vote_average_gte=DISCOVER_VOTE_AVERAGE_GTE) 46 | self.assertTrue(hasattr(discover, 'results')) 47 | 48 | def test_discover_movie_underscore_lte(self): 49 | discover = tmdb.Discover() 50 | discover.movie(page=2, vote_average_lte=DISCOVER_VOTE_AVERAGE_LTE) 51 | self.assertTrue(hasattr(discover, 'results')) 52 | 53 | def test_discover_tv_underscore_gte(self): 54 | discover = tmdb.Discover() 55 | discover.tv(page=2, vote_average_gte=DISCOVER_VOTE_AVERAGE_GTE) 56 | self.assertTrue(hasattr(discover, 'results')) 57 | 58 | def test_discover_tv_underscore_lte(self): 59 | discover = tmdb.Discover() 60 | discover.tv(page=2, vote_average_lte=DISCOVER_VOTE_AVERAGE_LTE) 61 | self.assertTrue(hasattr(discover, 'results')) 62 | -------------------------------------------------------------------------------- /tests/test_search.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_search.py 5 | ~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Search class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | QUERY_1 = 'Club' 25 | QUERY_2 = 'Avenger' 26 | QUERY_3 = 'Breaking' 27 | QUERY_4 = 'Brad Pitt' 28 | QUERY_6 = 'Sony Pictures' 29 | QUERY_7 = 'fight' 30 | QUERY_8 = 'blackjack' 31 | 32 | 33 | class SearchTestCase(unittest.TestCase): 34 | def test_search_company(self): 35 | query = QUERY_6 36 | search = tmdb.Search() 37 | search.company(query=query) 38 | self.assertTrue(hasattr(search, 'results')) 39 | 40 | def test_search_collection(self): 41 | query = QUERY_2 42 | search = tmdb.Search() 43 | search.collection(query=query) 44 | self.assertTrue(hasattr(search, 'results')) 45 | 46 | def test_search_keyword(self): 47 | query = QUERY_7 48 | search = tmdb.Search() 49 | search.keyword(query=query) 50 | self.assertTrue(hasattr(search, 'results')) 51 | 52 | def test_search_movie(self): 53 | query = QUERY_1 54 | search = tmdb.Search() 55 | search.movie(query=query) 56 | self.assertTrue(hasattr(search, 'results')) 57 | 58 | def test_search_multi(self): 59 | query = QUERY_8 60 | search = tmdb.Search() 61 | search.multi(query=query) 62 | self.assertTrue(hasattr(search, 'results')) 63 | 64 | def test_search_person(self): 65 | query = QUERY_4 66 | search = tmdb.Search() 67 | search.person(query=query) 68 | self.assertTrue(hasattr(search, 'results')) 69 | 70 | def test_search_tv(self): 71 | query = QUERY_3 72 | search = tmdb.Search() 73 | search.tv(query=query) 74 | self.assertTrue(hasattr(search, 'results')) 75 | -------------------------------------------------------------------------------- /tmdbsimple/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple 5 | ~~~~~~~~~~ 6 | 7 | *tmdbsimple* is a wrapper, written in Python, for The Movie Database (TMDb) 8 | API v3. By calling the functions available in *tmdbsimple* you can simplify 9 | your code and easily access a vast amount of movie, tv, and cast data. To find 10 | out more about The Movie Database API, check out the overview page 11 | http://www.themoviedb.org/documentation/api and documentation page 12 | https://developers.themoviedb.org/3/getting-started 13 | https://www.themoviedb.org/documentation/api/status-codes 14 | 15 | :copyright: (c) 2013-2025 by Celia Oakley. 16 | :license: GPLv3, see LICENSE for more details 17 | """ 18 | 19 | __title__ = 'tmdbsimple' 20 | __version__ = '2.9.2' 21 | __author__ = 'Celia Oakley' 22 | __copyright__ = 'Copyright (c) 2013-2025 Celia Oakley' 23 | __license__ = 'GPLv3' 24 | 25 | import os 26 | import requests 27 | 28 | from .account import Account, Authentication, GuestSessions, Lists 29 | from .base import APIKeyError 30 | from .changes import Changes 31 | from .configuration import Configuration, Certifications 32 | from .discover import Discover 33 | from .find import Find, Trending 34 | from .genres import Genres 35 | from .movies import Movies, Collections, Companies, Keywords, Reviews 36 | from .people import People, Credits 37 | from .search import Search 38 | from .tv import TV, TV_Seasons, TV_Episodes, TV_Episode_Groups, TV_Changes, Networks 39 | 40 | __all__ = ['Account', 'Authentication', 'GuestSessions', 'Lists', 41 | 'APIKeyError', 42 | 'Changes', 43 | 'Configuration', 'Certifications', 44 | 'Discover', 45 | 'Find', 'Trending', 46 | 'Genres', 47 | 'Movies', 'Collections', 'Companies', 'Keywords', 'Reviews', 48 | 'People', 'Credits' 49 | 'Search', 50 | 'TV', 'TV_Seasons', 'TV_Episodes', 'TV_Episode_Groups', 'TV_Changes', 'Networks' 51 | ] 52 | 53 | API_KEY = os.environ.get('TMDB_API_KEY', None) 54 | API_VERSION = '3' 55 | REQUESTS_SESSION = None 56 | REQUESTS_TIMEOUT = os.environ.get('TMDB_REQUESTS_TIMEOUT', None) 57 | -------------------------------------------------------------------------------- /tests/test_base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_base.py 5 | ~~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the TMDB class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2018-01-06 10 | 11 | :copyright: (c) 2018-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | MOVIE_ID = 103332 25 | MOVIEQUERY1 = 'Matrix' 26 | MOVIEQUERY2 = 'Star Wars' 27 | MOVIEQUERY3 = 'Kind' 28 | 29 | 30 | class TMDBTestCase(unittest.TestCase): 31 | # We want to be able to call methods multiple times. 32 | # If a method returns a dict with a key of the same name as the method, 33 | # e.g., Movies.keywords(), an attribute won't be set. 34 | # Confirm for this case that the method can be called again. 35 | def test_tmdb_set_attrs_to_values_method_equals_attribute(self): 36 | id = MOVIE_ID 37 | movie = tmdb.Movies(id) 38 | movie.keywords() 39 | raised = False 40 | try: 41 | movie.keywords() 42 | except Exception: 43 | raised = True 44 | self.assertFalse(raised) 45 | 46 | # Confirm for multiple calls to the same method with different arguments, 47 | # that the attributes are updated. 48 | def test_tmdb_set_attrs_to_values_attribute_multiple_calls(self): 49 | search = tmdb.Search() 50 | search.movie(query=MOVIEQUERY1) 51 | title1 = search.results[0]['original_title'] 52 | search.movie(query=MOVIEQUERY2) 53 | title2 = search.results[0]['original_title'] 54 | self.assertNotEqual(title1, title2) 55 | 56 | # Confirm boolean parameters are handled properly in _get_params(). 57 | def test_tmdb_get_params_bool(self): 58 | search = tmdb.Search() 59 | search.movie(query=MOVIEQUERY3, include_adult=True) 60 | total_results1 = search.total_results 61 | search.movie(query=MOVIEQUERY3, include_adult='true') 62 | total_results2 = search.total_results 63 | self.assertEqual(total_results1, total_results2) 64 | -------------------------------------------------------------------------------- /tmdbsimple/genres.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.genres 5 | ~~~~~~~~~~~~~~~~~ 6 | This module implements the Genres functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class Genres(TMDB): 18 | """ 19 | Genres functionality. 20 | 21 | See: https://developers.themoviedb.org/3/genres 22 | """ 23 | BASE_PATH = 'genre' 24 | URLS = { 25 | 'movie_list': '/movie/list', 26 | 'tv_list': '/tv/list', 27 | 'movies': '/{id}/movies', # backward compatability 28 | } 29 | 30 | def __init__(self, id=0): 31 | super(Genres, self).__init__() 32 | self.id = id 33 | 34 | def movie_list(self, **kwargs): 35 | """ 36 | Get the list of official genres for movies. 37 | 38 | Args: 39 | language: (optional) ISO 639-1 code. 40 | 41 | Returns: 42 | A dict respresentation of the JSON returned from the API. 43 | """ 44 | path = self._get_path('movie_list') 45 | 46 | response = self._GET(path, kwargs) 47 | self._set_attrs_to_values(response) 48 | return response 49 | 50 | def tv_list(self, **kwargs): 51 | """ 52 | Get the list of official genres for TV shows. 53 | 54 | Args: 55 | language: (optional) ISO 639-1 code. 56 | 57 | Returns: 58 | A dict respresentation of the JSON returned from the API. 59 | """ 60 | path = self._get_path('tv_list') 61 | 62 | response = self._GET(path, kwargs) 63 | self._set_attrs_to_values(response) 64 | return response 65 | 66 | # backward compatability 67 | def movies(self, **kwargs): 68 | """ 69 | Get the list of movies for a particular genre by id. By default, only 70 | movies with 10 or more votes are included. 71 | 72 | Args: 73 | page: (optional) Minimum 1, maximum 1000. 74 | language: (optional) ISO 639-1 code. 75 | include_all_movies: (optional) Toggle the inclusion of all movies 76 | and not just those with 10 or more ratings. 77 | Expected value is: True or False. 78 | include_adult: (optional) Toggle the inclusion of adult titles. 79 | Expected value is: True or False. 80 | 81 | Returns: 82 | A dict respresentation of the JSON returned from the API. 83 | """ 84 | path = self._get_id_path('movies') 85 | 86 | response = self._GET(path, kwargs) 87 | self._set_attrs_to_values(response) 88 | return response 89 | -------------------------------------------------------------------------------- /tests/test_people.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_people.py 5 | ~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the People class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | PEOPLE_ID = 287 25 | PEOPLE_NAME = 'Brad Pitt' 26 | CREDITS_ID = '52542282760ee313280017f9' 27 | CREDITS_DEPARTMENT = 'Acting' 28 | 29 | 30 | class PeopleTestCase(unittest.TestCase): 31 | def test_people_info(self): 32 | id = PEOPLE_ID 33 | name = PEOPLE_NAME 34 | person = tmdb.People(id) 35 | person.info() 36 | self.assertEqual(person.name, name) 37 | 38 | def test_people_changes(self): 39 | id = PEOPLE_ID 40 | person = tmdb.People(id) 41 | person.changes() 42 | self.assertTrue(hasattr(person, 'changes')) 43 | 44 | def test_people_movie_credits(self): 45 | id = PEOPLE_ID 46 | person = tmdb.People(id) 47 | person.movie_credits() 48 | self.assertTrue(hasattr(person, 'cast')) 49 | 50 | def test_people_tv_credits(self): 51 | id = PEOPLE_ID 52 | person = tmdb.People(id) 53 | person.tv_credits() 54 | self.assertTrue(hasattr(person, 'cast')) 55 | 56 | def test_people_combined_credits(self): 57 | id = PEOPLE_ID 58 | person = tmdb.People(id) 59 | person.combined_credits() 60 | self.assertTrue(hasattr(person, 'cast')) 61 | 62 | def test_people_external_ids(self): 63 | id = PEOPLE_ID 64 | person = tmdb.People(id) 65 | person.external_ids() 66 | self.assertTrue(hasattr(person, 'tvrage_id')) 67 | 68 | def test_people_images(self): 69 | id = PEOPLE_ID 70 | person = tmdb.People(id) 71 | person.images() 72 | self.assertTrue(hasattr(person, 'profiles')) 73 | 74 | def test_people_tagged_images(self): 75 | id = PEOPLE_ID 76 | person = tmdb.People(id) 77 | person.tagged_images() 78 | self.assertTrue(hasattr(person, 'results')) 79 | 80 | def test_people_translations(self): 81 | id = PEOPLE_ID 82 | person = tmdb.People(id) 83 | person.translations() 84 | self.assertTrue(hasattr(person, 'translations')) 85 | 86 | def test_people_latest(self): 87 | person = tmdb.People() 88 | person.latest() 89 | self.assertTrue(hasattr(person, 'name')) 90 | 91 | def test_people_popular(self): 92 | person = tmdb.People() 93 | person.popular() 94 | self.assertTrue(hasattr(person, 'results')) 95 | 96 | 97 | class CreditsTestCase(unittest.TestCase): 98 | def test_credits_info(self): 99 | id = CREDITS_ID 100 | department = CREDITS_DEPARTMENT 101 | credit = tmdb.Credits(id) 102 | credit.info() 103 | self.assertEqual(credit.department, department) 104 | -------------------------------------------------------------------------------- /tmdbsimple/changes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.changes 5 | ~~~~~~~~~~~~~~~~~~ 6 | This module implements the Changes functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class Changes(TMDB): 18 | """ 19 | Changes functionality. 20 | 21 | See: https://developers.themoviedb.org/3/changes 22 | """ 23 | BASE_PATH = '' 24 | URLS = { 25 | 'movie': 'movie/changes', 26 | 'tv': 'tv/changes', 27 | 'person': 'person/changes', 28 | } 29 | 30 | def movie(self, **kwargs): 31 | """ 32 | Get a list of all of the movie ids that have been changed 33 | in the past 24 hours. 34 | 35 | You can query it for up to 14 days worth of changed IDs at 36 | a time with the start_date and end_date query parameters. 37 | 100 items are returned per page. 38 | 39 | Args: 40 | start_date: (optional) Expected format is 'YYYY-MM-DD'. 41 | end_date: (optional) Expected format is 'YYYY-MM-DD'. 42 | page: (optional) Minimum 1, maximum 1000, default 1. 43 | 44 | Returns: 45 | A dict respresentation of the JSON returned from the API. 46 | """ 47 | path = self._get_path('movie') 48 | 49 | response = self._GET(path, kwargs) 50 | self._set_attrs_to_values(response) 51 | return response 52 | 53 | def tv(self, **kwargs): 54 | """ 55 | Get a list of all of the TV show ids that have been changed 56 | in the past 24 hours. 57 | 58 | You can query it for up to 14 days worth of changed IDs at 59 | a time with the start_date and end_date query parameters. 60 | 100 items are returned per page. 61 | 62 | Args: 63 | start_date: (optional) Expected format is 'YYYY-MM-DD'. 64 | end_date: (optional) Expected format is 'YYYY-MM-DD'. 65 | page: (optional) Minimum 1, maximum 1000, default 1. 66 | 67 | Returns: 68 | A dict respresentation of the JSON returned from the API. 69 | """ 70 | path = self._get_path('tv') 71 | 72 | response = self._GET(path, kwargs) 73 | self._set_attrs_to_values(response) 74 | return response 75 | 76 | def person(self, **kwargs): 77 | """ 78 | Get a list of all of the person ids that have been changed 79 | in the past 24 hours. 80 | 81 | You can query it for up to 14 days worth of changed IDs at 82 | a time with the start_date and end_date query parameters. 83 | 100 items are returned per page. 84 | 85 | Args: 86 | start_date: (optional) Expected format is 'YYYY-MM-DD'. 87 | end_date: (optional) Expected format is 'YYYY-MM-DD'. 88 | page: (optional) Minimum 1, maximum 1000, default 1. 89 | 90 | Returns: 91 | A dict respresentation of the JSON returned from the API. 92 | """ 93 | path = self._get_path('person') 94 | 95 | response = self._GET(path, kwargs) 96 | self._set_attrs_to_values(response) 97 | return response 98 | -------------------------------------------------------------------------------- /tmdbsimple/find.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.find 5 | ~~~~~~~~~~~~~~~ 6 | This module implements the Find functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class Find(TMDB): 18 | """ 19 | Find functionality. 20 | 21 | See: https://developers.themoviedb.org/3/find 22 | """ 23 | BASE_PATH = 'find' 24 | URLS = { 25 | 'info': '/{id}', 26 | } 27 | 28 | def __init__(self, id=0): 29 | super(Find, self).__init__() 30 | self.id = id 31 | 32 | def info(self, **kwargs): 33 | """ 34 | The find method makes it easy to search for objects in our database by 35 | an external id. For example, an IMDB ID. 36 | 37 | This method will search all objects (movies, TV shows and people) and 38 | return the results in a single response. 39 | 40 | The supported external sources for each object are as follows. 41 | Media Databases: IMDb ID, TVDB ID, Freebase MID*, Freebase ID*, 42 | TVRage ID* 43 | Social IDs: Facebook, Insagram, Twitter 44 | 45 | Args: 46 | language: (optional) ISO 639-1 code. 47 | external_source: Allowed Values: imdb_id, freebase_mid, 48 | freebase_id, tvdb_id, tvrage_id, facebook_id, twitter_id, 49 | instagram_id 50 | 51 | Returns: 52 | A dict respresentation of the JSON returned from the API. 53 | """ 54 | path = self._get_id_path('info') 55 | 56 | response = self._GET(path, kwargs) 57 | self._set_attrs_to_values(response) 58 | return response 59 | 60 | 61 | class Trending(TMDB): 62 | """ 63 | Trending functionality. 64 | 65 | See: https://developers.themoviedb.org/3/trending 66 | """ 67 | BASE_PATH = 'trending' 68 | URLS = { 69 | 'info': '/{media_type}/{time_window}', 70 | } 71 | 72 | def __init__(self, media_type='all', time_window='day'): 73 | super(Trending, self).__init__() 74 | self.media_type = media_type 75 | self.time_window = time_window 76 | 77 | def info(self, **kwargs): 78 | """ 79 | Get the daily or weekly trending items. The daily trending list tracks 80 | items over the period of a day while items have a 24 hour half life. 81 | The weekly list tracks items over a 7 day period, with a 7 day half 82 | life. 83 | 84 | Valid Media Types 85 | 'all': Include all movies, TV shows and people in the results as a 86 | global trending list. 87 | 'movie': Show the trending movies in the results. 88 | 'tv': Show the trending TV shows in the results. 89 | 'people': Show the trending people in the results. 90 | 91 | Valid Time Windows 92 | 'day': View the trending list for the day. 93 | 'week': View the trending list for the week. 94 | 95 | Args: 96 | None 97 | 98 | Returns: 99 | A dict respresentation of the JSON returned from the API. 100 | """ 101 | path = self._get_media_type_time_window_path('info') 102 | 103 | response = self._GET(path, kwargs) 104 | self._set_attrs_to_values(response) 105 | return response 106 | -------------------------------------------------------------------------------- /tests/test_configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_configuration.py 5 | ~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Configuration class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import re 17 | import tmdbsimple as tmdb 18 | 19 | from tests import API_KEY 20 | tmdb.API_KEY = API_KEY 21 | 22 | """ 23 | Constants 24 | """ 25 | CHANGE_KEYS = ['adult', 'air_date', 'also_known_as', 'alternative_titles', 26 | 'biography', 'birthday', 'budget', 'cast', 'certifications', 27 | 'character_names', 'created_by', 'crew', 'deathday', 'episode', 28 | 'episode_number', 'episode_run_time', 'freebase_id', 'freebase_mid', 29 | 'general', 'genres', 'guest_stars', 'homepage', 'images', 'imdb_id', 30 | 'languages', 'name', 'network', 'origin_country', 'original_name', 31 | 'original_title', 'overview', 'parts', 'place_of_birth', 'plot_keywords', 32 | 'production_code', 'production_companies', 'production_countries', 33 | 'releases', 'revenue', 'runtime', 'season', 'season_number', 34 | 'season_regular', 'spoken_languages', 'status', 'tagline', 'title', 35 | 'translations', 'tvdb_id', 'tvrage_id', 'type', 'video', 'videos' 36 | ] 37 | ISO_3166_1 = 'iso_3166_1' 38 | ANDORRA = 'AD' 39 | ISO_639_1 = 'iso_639_1' 40 | NO_LANGUAGE = 'xx' 41 | AFRIKAANS_SA = 'af-ZA' 42 | 43 | 44 | class ConfigurationTestCase(unittest.TestCase): 45 | def test_configuration_info(self): 46 | change_keys = CHANGE_KEYS 47 | config = tmdb.Configuration() 48 | config.info() 49 | self.assertEqual(config.change_keys, change_keys) 50 | 51 | # Also test that bad API_KEY results in exception 52 | # Restore key for sequential tests 53 | api_key_save = tmdb.API_KEY 54 | tmdb.API_KEY = 0 55 | config = tmdb.Configuration() 56 | self.assertRaises(tmdb.APIKeyError, config.info) 57 | tmdb.API_KEY = api_key_save 58 | 59 | def test_configuration_countries(self): 60 | config = tmdb.Configuration() 61 | response = config.countries() 62 | # Countries are two capital letters 63 | self.assertTrue(re.match('^[A-Z]{2}$', response[0][ISO_3166_1])) 64 | 65 | def test_configuration_jobs(self): 66 | config = tmdb.Configuration() 67 | config.jobs() 68 | self.assertTrue(hasattr(config, 'jobs')) 69 | 70 | def test_configuration_languages(self): 71 | config = tmdb.Configuration() 72 | response = config.languages() 73 | # Languages are two lowercase letters 74 | self.assertTrue(re.match('^[a-z]{2}$', response[0][ISO_639_1])) 75 | 76 | def test_configuration_primary_translations(self): 77 | config = tmdb.Configuration() 78 | response = config.primary_translations() 79 | # First primary translation is Afrikaans (South Africa) 80 | self.assertEqual(response[0], AFRIKAANS_SA) 81 | 82 | def test_configuration_timezones(self): 83 | config = tmdb.Configuration() 84 | response = config.timezones() 85 | # First country is Andorra 86 | self.assertEqual(response[0][ISO_3166_1], ANDORRA) 87 | 88 | 89 | class CertificationsTestCase(unittest.TestCase): 90 | def test_certifications_movie_list(self): 91 | certifications = tmdb.Certifications() 92 | certifications.movie_list() 93 | self.assertTrue(hasattr(certifications, 'certifications')) 94 | 95 | def test_certifications_tv_list(self): 96 | certifications = tmdb.Certifications() 97 | certifications.tv_list() 98 | self.assertTrue(hasattr(certifications, 'certifications')) 99 | 100 | def test_certifications_list(self): 101 | certifications = tmdb.Certifications() 102 | certifications.list() 103 | self.assertTrue(hasattr(certifications, 'certifications')) 104 | -------------------------------------------------------------------------------- /tmdbsimple/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.base 5 | ~~~~~~~~~~~~~~~ 6 | This module implements the base class of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | import json 15 | import requests 16 | 17 | 18 | class APIKeyError(Exception): 19 | pass 20 | 21 | 22 | class TMDB(object): 23 | headers = {'Content-Type': 'application/json', 24 | 'Accept': 'application/json', 25 | 'Connection': 'close'} 26 | BASE_PATH = '' 27 | URLS = {} 28 | 29 | def __init__(self): 30 | from . import API_VERSION, REQUESTS_SESSION, REQUESTS_TIMEOUT 31 | self.base_uri = 'https://api.themoviedb.org' 32 | self.base_uri += '/{version}'.format(version=API_VERSION) 33 | self.session = REQUESTS_SESSION 34 | self.timeout = REQUESTS_TIMEOUT 35 | 36 | def _get_path(self, key): 37 | return self.BASE_PATH + self.URLS[key] 38 | 39 | def _get_id_path(self, key): 40 | return self._get_path(key).format(id=self.id) 41 | 42 | def _get_guest_session_id_path(self, key): 43 | return self._get_path(key).format( 44 | guest_session_id=self.guest_session_id) 45 | 46 | def _get_credit_id_path(self, key): 47 | return self._get_path(key).format(credit_id=self.credit_id) 48 | 49 | def _get_media_type_time_window_path(self, key): 50 | return self._get_path(key).format( 51 | media_type=self.media_type, time_window=self.time_window) 52 | 53 | def _get_tv_id_season_number_path(self, key): 54 | return self._get_path(key).format( 55 | tv_id=self.tv_id, season_number=self.season_number) 56 | 57 | def _get_tv_id_season_number_episode_number_path(self, key): 58 | return self._get_path(key).format( 59 | tv_id=self.tv_id, season_number=self.season_number, 60 | episode_number=self.episode_number) 61 | 62 | def _get_complete_url(self, path): 63 | return '{base_uri}/{path}'.format(base_uri=self.base_uri, path=path) 64 | 65 | def _get_params(self, params): 66 | from . import API_KEY 67 | if not API_KEY: 68 | raise APIKeyError 69 | 70 | api_dict = {'api_key': API_KEY} 71 | if params: 72 | params.update(api_dict) 73 | for key, value in params.items(): 74 | if isinstance(params[key], bool): 75 | params[key] = 'true' if value is True else 'false' 76 | 77 | else: 78 | params = api_dict 79 | return params 80 | 81 | def _request(self, method, path, params=None, payload=None): 82 | url = self._get_complete_url(path) 83 | params = self._get_params(params) 84 | 85 | # Create a new request session if no global session is defined 86 | if self.session is None: 87 | response = requests.request( 88 | method, 89 | url, 90 | params=params, 91 | data=json.dumps(payload) if payload else payload, 92 | headers=self.headers, timeout=self.timeout 93 | ) 94 | 95 | # Use the global requests session the user provided 96 | else: 97 | response = self.session.request( 98 | method, 99 | url, 100 | params=params, 101 | data=json.dumps(payload) if payload else payload, 102 | headers=self.headers, timeout=self.timeout 103 | ) 104 | 105 | response.raise_for_status() 106 | response.encoding = 'utf-8' 107 | return response.json() 108 | 109 | def _GET(self, path, params=None): 110 | return self._request('GET', path, params=params) 111 | 112 | def _POST(self, path, params=None, payload=None): 113 | return self._request('POST', path, params=params, payload=payload) 114 | 115 | def _DELETE(self, path, params=None, payload=None): 116 | return self._request('DELETE', path, params=params, payload=payload) 117 | 118 | def _set_attrs_to_values(self, response={}): 119 | """ 120 | Set attributes to dictionary values. 121 | 122 | - e.g. 123 | >>> import tmdbsimple as tmdb 124 | >>> movie = tmdb.Movies(103332) 125 | >>> response = movie.info() 126 | >>> movie.title # instead of response['title'] 127 | """ 128 | if isinstance(response, dict): 129 | for key in response.keys(): 130 | if not hasattr(self, key) or not callable(getattr(self, key)): 131 | setattr(self, key, response[key]) 132 | -------------------------------------------------------------------------------- /tmdbsimple/configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.configuration 5 | ~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | This module implements the Configuration and Certifications functionality of 8 | tmdbsimple. 9 | 10 | Created by Celia Oakley on 2013-10-31. 11 | 12 | :copyright: (c) 2013-2025 by Celia Oakley 13 | :license: GPLv3, see LICENSE for more details 14 | """ 15 | 16 | from .base import TMDB 17 | 18 | 19 | class Configuration(TMDB): 20 | """ 21 | Configuration functionality. 22 | 23 | See: https://developers.themoviedb.org/3/configuration 24 | """ 25 | BASE_PATH = 'configuration' 26 | URLS = { 27 | 'info': '', 28 | 'countries': '/countries', 29 | 'jobs': '/jobs', 30 | 'languages': '/languages', 31 | 'primary_translations': '/primary_translations', 32 | 'timezones': '/timezones', 33 | } 34 | 35 | def info(self, **kwargs): 36 | """ 37 | Get the system wide configuration information. Some elements of the API 38 | require some knowledge of this configuration data. The purpose of this 39 | is to try and keep the actual API responses as light as possible. It is 40 | recommended you cache this data within your application and check for 41 | updates every few days. 42 | 43 | This method currently holds the data relevant to building image URLs as 44 | well as the change key map. 45 | 46 | To build an image URL, you will need 3 pieces of data. The base_url, 47 | size and file_path. Simply combine them all and you will have a fully 48 | qualified URL. Here’s an example URL: 49 | 50 | https://image.tmdb.org/t/p/w500/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg 51 | 52 | The configuration method also contains the list of change keys which 53 | can be useful if you are building an app that consumes data from the 54 | change feed. 55 | 56 | Args: 57 | None 58 | 59 | Returns: 60 | A dict respresentation of the JSON returned from the API. 61 | """ 62 | path = self._get_path('info') 63 | 64 | response = self._GET(path, kwargs) 65 | self._set_attrs_to_values(response) 66 | return response 67 | 68 | def countries(self, **kwargs): 69 | """ 70 | Get the list of countries (ISO 3166-1 tags) used throughout TMDb. 71 | 72 | Args: 73 | None 74 | 75 | Returns: 76 | A dict respresentation of the JSON returned from the API. 77 | """ 78 | path = self._get_path('countries') 79 | 80 | response = self._GET(path, kwargs) 81 | self._set_attrs_to_values(response) 82 | return response 83 | 84 | def jobs(self, **kwargs): 85 | """ 86 | Get a list of the jobs and departments we use on TMDb. 87 | 88 | Args: 89 | None 90 | 91 | Returns: 92 | A dict respresentation of the JSON returned from the API. 93 | """ 94 | path = self._get_path('jobs') 95 | 96 | response = self._GET(path, kwargs) 97 | self._set_attrs_to_values(response) 98 | return response 99 | 100 | def languages(self, **kwargs): 101 | """ 102 | Get the list of languages (ISO 639-1 tags) used throughout TMDb. 103 | 104 | Args: 105 | None 106 | 107 | Returns: 108 | A dict respresentation of the JSON returned from the API. 109 | """ 110 | path = self._get_path('languages') 111 | 112 | response = self._GET(path, kwargs) 113 | self._set_attrs_to_values(response) 114 | return response 115 | 116 | def primary_translations(self, **kwargs): 117 | """ 118 | Get a list of the officially supported translations on TMDb. 119 | 120 | Args: 121 | None 122 | 123 | Returns: 124 | A dict respresentation of the JSON returned from the API. 125 | """ 126 | path = self._get_path('primary_translations') 127 | 128 | response = self._GET(path, kwargs) 129 | self._set_attrs_to_values(response) 130 | return response 131 | 132 | def timezones(self, **kwargs): 133 | """ 134 | Get the list of timezones used throughout TMDb. 135 | 136 | Args: 137 | None 138 | 139 | Returns: 140 | A dict respresentation of the JSON returned from the API. 141 | """ 142 | path = self._get_path('timezones') 143 | 144 | response = self._GET(path, kwargs) 145 | self._set_attrs_to_values(response) 146 | return response 147 | 148 | 149 | class Certifications(TMDB): 150 | """ 151 | Certifications functionality. 152 | 153 | See: https://developers.themoviedb.org/3/certifications 154 | """ 155 | BASE_PATH = 'certification' 156 | URLS = { 157 | 'movie_list': '/movie/list', 158 | 'tv_list': '/tv/list', 159 | } 160 | 161 | def movie_list(self, **kwargs): 162 | """ 163 | Get an up to date list of the officially supported movie certifications on TMDb. 164 | 165 | Args: 166 | None 167 | 168 | Returns: 169 | A dict respresentation of the JSON returned from the API. 170 | """ 171 | path = self._get_path('movie_list') 172 | 173 | response = self._GET(path, kwargs) 174 | self._set_attrs_to_values(response) 175 | return response 176 | 177 | def tv_list(self, **kwargs): 178 | """ 179 | Get an up to date list of the officially supported TV show certifications on TMDb. 180 | 181 | Args: 182 | None 183 | 184 | Returns: 185 | A dict respresentation of the JSON returned from the API. 186 | """ 187 | path = self._get_path('tv_list') 188 | 189 | response = self._GET(path, kwargs) 190 | self._set_attrs_to_values(response) 191 | return response 192 | 193 | # backward compatability, when only /movie/list existed 194 | def list(self, **kwargs): 195 | """ 196 | Get the list of supported certifications for movies. 197 | 198 | Args: 199 | None 200 | 201 | Returns: 202 | A dict respresentation of the JSON returned from the API. 203 | """ 204 | path = self._get_path('movie_list') 205 | 206 | response = self._GET(path, kwargs) 207 | self._set_attrs_to_values(response) 208 | return response 209 | -------------------------------------------------------------------------------- /tmdbsimple/search.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.search 5 | ~~~~~~~~~~~~~~~~~ 6 | This module implements the Search functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class Search(TMDB): 18 | """ 19 | Search functionality 20 | 21 | See: https://developers.themoviedb.org/3/search 22 | """ 23 | BASE_PATH = 'search' 24 | URLS = { 25 | 'company': '/company', 26 | 'collection': '/collection', 27 | 'keyword': '/keyword', 28 | 'movie': '/movie', 29 | 'multi': '/multi', 30 | 'person': '/person', 31 | 'tv': '/tv', 32 | } 33 | 34 | def company(self, **kwargs): 35 | """ 36 | Search for companies. 37 | 38 | Args: 39 | query: (required) Pass a text query to search. This value should be 40 | URI encoded. 41 | page: (optional) Minimum 1, maximum 1000, default 1. 42 | 43 | Returns: 44 | A dict respresentation of the JSON returned from the API. 45 | """ 46 | path = self._get_path('company') 47 | 48 | response = self._GET(path, kwargs) 49 | self._set_attrs_to_values(response) 50 | return response 51 | 52 | def collection(self, **kwargs): 53 | """ 54 | Search for collections. 55 | 56 | Args: 57 | language: (optional) (optional) ISO 639-1 code. 58 | query: (required) Pass a text query to search. This value should be 59 | URI encoded. 60 | page: (optional) Minimum 1, maximum 1000, default 1. 61 | 62 | Returns: 63 | A dict respresentation of the JSON returned from the API. 64 | """ 65 | path = self._get_path('collection') 66 | 67 | response = self._GET(path, kwargs) 68 | self._set_attrs_to_values(response) 69 | return response 70 | 71 | def keyword(self, **kwargs): 72 | """ 73 | Search for keywords. 74 | 75 | Args: 76 | query: (required) Pass a text query to search. This value should be 77 | URI encoded. 78 | page: (optional) Minimum 1, maximum 1000, default 1. 79 | 80 | Returns: 81 | A dict respresentation of the JSON returned from the API. 82 | """ 83 | path = self._get_path('keyword') 84 | 85 | response = self._GET(path, kwargs) 86 | self._set_attrs_to_values(response) 87 | return response 88 | 89 | def movie(self, **kwargs): 90 | """ 91 | Search for movies. 92 | 93 | Args: 94 | language: (optional) (optional) ISO 639-1 code. 95 | query: (required) Pass a text query to search. This value should be 96 | URI encoded. 97 | page: (optional) Minimum 1, maximum 1000, default 1. 98 | include_adult: (optional) Choose whether to inlcude adult 99 | (pornography) content in the results. 100 | region: (optional) Specify a ISO 3166-1 code to filter release 101 | dates. Must be uppercase. 102 | year: (optional) A filter to limit the results to a specific year 103 | (looking at all release dates). 104 | primary_release_year: (optional) A filter to limit the results to a 105 | specific primary release year. 106 | 107 | Returns: 108 | A dict respresentation of the JSON returned from the API. 109 | """ 110 | path = self._get_path('movie') 111 | 112 | response = self._GET(path, kwargs) 113 | self._set_attrs_to_values(response) 114 | return response 115 | 116 | def multi(self, **kwargs): 117 | """ 118 | Search multiple models in a single request. Multi search currently 119 | supports searching for movies, tv shows and people in a single request. 120 | 121 | Args: 122 | language: (optional) (optional) ISO 639-1 code. 123 | query: (required) Pass a text query to search. This value should be 124 | URI encoded. 125 | page: (optional) Minimum 1, maximum 1000, default 1. 126 | include_adult: (optional) Choose whether to inlcude adult 127 | (pornography) content in the results. 128 | region: (optional) Specify a ISO 3166-1 code to filter release 129 | dates. Must be uppercase. 130 | 131 | Returns: 132 | A dict respresentation of the JSON returned from the API. 133 | """ 134 | path = self._get_path('multi') 135 | 136 | response = self._GET(path, kwargs) 137 | self._set_attrs_to_values(response) 138 | return response 139 | 140 | def person(self, **kwargs): 141 | """ 142 | Search for people. 143 | 144 | Args: 145 | language: (optional) (optional) ISO 639-1 code. 146 | query: (required) Pass a text query to search. This value should be 147 | URI encoded. 148 | page: (optional) Minimum 1, maximum 1000, default 1. 149 | include_adult: (optional) Choose whether to inlcude adult 150 | (pornography) content in the results. 151 | region: (optional) Specify a ISO 3166-1 code to filter release 152 | dates. Must be uppercase. 153 | 154 | Returns: 155 | A dict respresentation of the JSON returned from the API. 156 | """ 157 | path = self._get_path('person') 158 | 159 | response = self._GET(path, kwargs) 160 | self._set_attrs_to_values(response) 161 | return response 162 | 163 | def tv(self, **kwargs): 164 | """ 165 | Search for a TV show. 166 | 167 | Args: 168 | language: (optional) (optional) ISO 639-1 code. 169 | query: (required) Pass a text query to search. This value should be 170 | URI encoded. 171 | page: (optional) Minimum 1, maximum 1000, default 1. 172 | include_adult: (optional) Choose whether to inlcude adult 173 | (pornography) content in the results. 174 | first_air_date_year: (optional) Filter the results to only match 175 | shows that have an air date with with value. 176 | 177 | Returns: 178 | A dict respresentation of the JSON returned from the API. 179 | """ 180 | path = self._get_path('tv') 181 | 182 | response = self._GET(path, kwargs) 183 | self._set_attrs_to_values(response) 184 | return response 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tmdbsimple 2 | ========== 3 | 4 | ![Python package](https://github.com/celiao/tmdbsimple/workflows/build/badge.svg) 5 | ![codecov](https://img.shields.io/codecov/c/github/celiao/tmdbsimple) 6 | ![pypi](https://img.shields.io/pypi/pyversions/tmdbsimple) 7 | ![pypi](https://img.shields.io/pypi/v/tmdbsimple) 8 | 9 | A wrapper for The Movie Database API v3 10 | --------------------------------------- 11 | *tmdbsimple* is a wrapper, written in Python, for The Movie Database (TMDb) API 12 | v3. By calling the functions available in *tmdbsimple* you can simplify your 13 | code and easily access a vast amount of movie, tv, and cast data. To learn 14 | more about The Movie Database API, check out the [overview]( 15 | http://www.themoviedb.org/documentation/api) and [documentation]( 16 | https://developers.themoviedb.org/3). 17 | 18 | Features 19 | -------- 20 | - COMPLETELY UPDATED AND FULLY TESTED. 21 | - Supports only [Python versions with TLS 22 | 1.2](http://pyfound.blogspot.com/2017/01/time-to-upgrade-your-python-tls-v12.html). 23 | Keep it simple! 24 | - Tested with Python 3.9, 3.10, and 3.11. 25 | - One-to-one mapping between *tmdbsimple* methods and TMDb endpoints. 26 | - Implements all TMDb methods, including Accounts and Authentication. 27 | - Easy to access data using Python class attributes. 28 | - Easy to experiment with *tmdbsimple* functions inside the Python interpreter. 29 | - Code tested with unittests. Refer to the unittest code for method call syntax. 30 | 31 | Installation 32 | ------------ 33 | *tmdbsimple* is available on the Python Package Index (PyPI) at 34 | https://pypi.python.org/pypi/tmdbsimple. 35 | 36 | You can install *tmdbsimple* using one of the following techniques. 37 | 38 | - Use pip: 39 | 40 | ``` 41 | pip install tmdbsimple 42 | ``` 43 | 44 | - Download the .zip or .tar.gz file from PyPI and install it yourself 45 | - Download the [source from Github](http://github.com/celiao/tmdbsimple) and 46 | install it yourself 47 | 48 | If you install it yourself, also install 49 | [requests](https://requests.readthedocs.io/en/master/). 50 | 51 | API Key 52 | ------- 53 | You will need an API key to The Movie Database to access the API. To obtain a 54 | key, follow these steps: 55 | 56 | 1) Register for and verify an [account](https://www.themoviedb.org/account/signup). 57 | 2) [Log into](https://www.themoviedb.org/login) your account. 58 | 3) Select the API section on left side of your account page. 59 | 4) Click on the link to generate a new API key and follow the instructions. 60 | 61 | Examples 62 | -------- 63 | Once you have the *tmdbsimple* package installed and a TMDb API key, you can 64 | start to play with the data. 65 | 66 | First, import the library and assign your API_KEY. 67 | 68 | ```python 69 | import tmdbsimple as tmdb 70 | tmdb.API_KEY = 'YOUR_API_KEY_HERE' 71 | ``` 72 | 73 | _Optionally_, set a timeout for requests. See [here](https://docs.python-requests.org/en/master/user/advanced/#timeouts) for more info. 74 | 75 | ```python 76 | tmdb.REQUESTS_TIMEOUT = 5 # seconds, for both connect and read 77 | ``` 78 | 79 | or 80 | 81 | ```python 82 | tmdb.REQUESTS_TIMEOUT = (2, 5) # seconds, for connect and read specifically 83 | ``` 84 | 85 | _Optionally_, configure the library to use your own REQUESTS_SESSION. See [here](https://docs.python-requests.org/en/master/user/advanced/#session-objects) for more info. 86 | 87 | ```python 88 | import requests 89 | tmdb.REQUESTS_SESSION = requests.Session() 90 | ``` 91 | 92 | To communicate with The Movie Database API, create an instance of one of the 93 | object types, call one of the methods on the instance, and access the instance 94 | attributes. Use keys to access the values of attributes that are dictionaries. 95 | In this example, we create a movie instance for 'The Matrix' and determine the 96 | budget and certification. 97 | 98 | ```python 99 | >>> movie = tmdb.Movies(603) 100 | >>> response = movie.info() 101 | >>> movie.title 102 | 'The Matrix' 103 | >>> movie.budget 104 | 63000000 105 | >>> response = movie.releases() 106 | >>> for c in movie.countries: 107 | ... if c['iso_3166_1'] == 'US': 108 | ... print(c['certification']) 109 | ... 110 | 'R' 111 | ``` 112 | 113 | Let's play with the interface a bit more. Suppose you and your friend are 114 | arguing over which movie in the Bourne series was most popular. Your friend 115 | says the first in a series is always most popular. You disagree. 116 | 117 | ```python 118 | >>> search = tmdb.Search() 119 | >>> response = search.movie(query='The Bourne') 120 | >>> for s in search.results: 121 | ... print(s['title'], s['id'], s['release_date'], s['popularity']) 122 | ... 123 | The Bourne Ultimatum 2503 2007-08-03 55.2447062124256 124 | The Bourne Supremacy 2502 2004-07-23 43.4553609681985 125 | The Bourne Identity 2501 2002-06-06 38.5531563780592 126 | The Bourne Legacy 49040 2012-08-10 9.90635210153143 127 | The Bourne Identity 8677 1988-05-08 1.53988446573129 128 | Bette Bourne: It Goes with the Shoes 179304 0.23 129 | ``` 130 | 131 | You are correct! Now you claim the producers should be able to make sequels 132 | cheaper, based on what they learned from making the first movie. To be fair, 133 | you compute the budget per minute of runtime. Your friend disagrees, claiming 134 | the producers spend more money trying to out do the previous sequel. 135 | 136 | ```python 137 | >>> identity = tmdb.Movies(2501) 138 | >>> response = identity.info() 139 | >>> identity.budget, identity.runtime 140 | (60000000, 119) 141 | >>> int(identity.budget/identity.runtime) 142 | 504201 143 | >>> supremacy = tmdb.Movies(2502) 144 | >>> response = supremacy.info() 145 | >>> supremacy.budget, supremacy.runtime 146 | (75000000, 108) 147 | >>> int(supremacy.budget/supremacy.runtime) 148 | 694444 149 | >>> ultimatum = tmdb.Movies(2503) 150 | >>> response = ultimatum.info() 151 | >>> ultimatum.budget, ultimatum.runtime 152 | (70000000, 115) 153 | >>> int(ultimatum.budget/ultimatum.runtime) 154 | 608695 155 | ``` 156 | 157 | In this case you are both correct. The third movie was cheaper than the 158 | second, which was more expensive than the first. 159 | 160 | You also can call one of the methods without explicitly instanciating an 161 | object. 162 | 163 | ```python 164 | >>> response = tmdb.Movies(603).info() 165 | >>> response['budget'] 166 | 63000000 167 | ``` 168 | 169 | If you use Authentication to access a user Account, be sure to check out 170 | https://www.themoviedb.org/documentation/api/sessions. 171 | 172 | If you like this wrapper, and would like access to even more movie and TV data, 173 | check out *rtsimple* https://pypi.python.org/pypi/rtsimple, a wrapper for the 174 | Rotten Tomatoes API. 175 | -------------------------------------------------------------------------------- /tests/test_movies.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | test_movies.py 4 | ~~~~~~~~~~~~~~ 5 | 6 | This test suite checks the methods of the Movies class of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-11-05 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley. 11 | :license: GPLv3, see LICENSE for more details. 12 | """ 13 | 14 | import unittest 15 | import tmdbsimple as tmdb 16 | 17 | from tests import API_KEY, SESSION_ID 18 | tmdb.API_KEY = API_KEY 19 | 20 | """ 21 | Constants 22 | """ 23 | MOVIE_ID = 103332 24 | MOVIE_TITLE = 'Ruby Sparks' 25 | MOVIE_TITLE_GERMAN = 'Ruby Sparks - Meine fabelhafte Freundin' 26 | MOVIE_ID_ALTERNATIVE = 550 27 | RATING = 7.5 28 | COLLECTION_ID = 10 29 | COLLECTION_NAME = 'Star Wars Collection' 30 | COMPANY_ID = 1 31 | COMPANY_NAME = 'Lucasfilm Ltd.' 32 | KEYWORD_ID = 1721 33 | KEYWORD_NAME = 'fight' 34 | REVIEW_ID = '5013bc76760ee372cb00253e' 35 | REVIEW_AUTHOR = 'Chris' 36 | 37 | """ 38 | Status Codes 39 | """ 40 | SUCCESSFUL_CREATE = 1 41 | SUCCESSFUL_UPDATE = 12 42 | SUCCESSFUL_DELETE = 13 43 | 44 | 45 | class MoviesTestCase(unittest.TestCase): 46 | def test_movies_info(self): 47 | id = MOVIE_ID 48 | title = MOVIE_TITLE 49 | movie = tmdb.Movies(id) 50 | movie.info() 51 | self.assertEqual(movie.title, title) 52 | 53 | def test_movies_info_with_params(self): 54 | id = MOVIE_ID 55 | title = MOVIE_TITLE_GERMAN 56 | movie = tmdb.Movies(id) 57 | movie.info(language='de') 58 | self.assertEqual(movie.title, title) 59 | 60 | def test_movies_account_states(self): 61 | id = MOVIE_ID_ALTERNATIVE 62 | movie = tmdb.Movies(id) 63 | movie.account_states(session_id=SESSION_ID) 64 | self.assertTrue(hasattr(movie, 'favorite')) 65 | 66 | def test_movies_alternative_titles(self): 67 | id = MOVIE_ID_ALTERNATIVE 68 | movie = tmdb.Movies(id) 69 | movie.alternative_titles() 70 | self.assertTrue(hasattr(movie, 'titles')) 71 | 72 | def test_movies_changes(self): 73 | id = MOVIE_ID 74 | movie = tmdb.Movies(id) 75 | movie.changes() 76 | self.assertTrue(hasattr(movie, 'changes')) 77 | 78 | def test_movies_credits(self): 79 | id = MOVIE_ID 80 | movie = tmdb.Movies(id) 81 | movie.credits() 82 | self.assertTrue(hasattr(movie, 'cast')) 83 | 84 | def test_movies_external_ids(self): 85 | id = MOVIE_ID 86 | movie = tmdb.Movies(id) 87 | movie.external_ids() 88 | self.assertTrue(hasattr(movie, 'imdb_id')) 89 | 90 | def test_movies_images(self): 91 | id = MOVIE_ID 92 | movie = tmdb.Movies(id) 93 | movie.images() 94 | self.assertTrue(hasattr(movie, 'backdrops')) 95 | 96 | def test_movies_keywords(self): 97 | id = MOVIE_ID 98 | movie = tmdb.Movies(id) 99 | movie.keywords() 100 | self.assertTrue(hasattr(movie, 'keywords')) 101 | 102 | def test_movies_lists(self): 103 | id = MOVIE_ID 104 | movie = tmdb.Movies(id) 105 | movie.lists() 106 | self.assertTrue(hasattr(movie, 'results')) 107 | 108 | def test_movies_recommendations(self): 109 | id = MOVIE_ID 110 | movie = tmdb.Movies(id) 111 | movie.recommendations() 112 | self.assertTrue(hasattr(movie, 'results')) 113 | 114 | def test_movies_release_dates(self): 115 | id = MOVIE_ID 116 | movie = tmdb.Movies(id) 117 | movie.release_dates() 118 | self.assertTrue(hasattr(movie, 'results')) 119 | 120 | def test_movies_reviews(self): 121 | id = MOVIE_ID 122 | movie = tmdb.Movies(id) 123 | movie.reviews() 124 | self.assertTrue(hasattr(movie, 'results')) 125 | 126 | def test_movies_similar_movies(self): 127 | id = MOVIE_ID_ALTERNATIVE 128 | movie = tmdb.Movies(id) 129 | movie.similar_movies() 130 | self.assertTrue(hasattr(movie, 'results')) 131 | 132 | def test_movies_translations(self): 133 | id = MOVIE_ID_ALTERNATIVE 134 | movie = tmdb.Movies(id) 135 | movie.translations() 136 | self.assertTrue(hasattr(movie, 'translations')) 137 | 138 | def test_movies_videos(self): 139 | id = MOVIE_ID 140 | movie = tmdb.Movies(id) 141 | movie.videos() 142 | self.assertTrue(hasattr(movie, 'results')) 143 | 144 | def test_movies_watch_providers(self): 145 | id = MOVIE_ID 146 | movie = tmdb.Movies(id) 147 | movie.watch_providers() 148 | self.assertTrue(hasattr(movie, 'results')) 149 | 150 | def test_movies_rating_and_rating_delete(self): 151 | status_code_create = SUCCESSFUL_CREATE 152 | status_code_update = SUCCESSFUL_UPDATE 153 | status_code_delete = SUCCESSFUL_DELETE 154 | id = MOVIE_ID 155 | movie = tmdb.Movies(id) 156 | movie.rating(session_id=SESSION_ID, value=RATING) 157 | self.assertTrue(movie.status_code == status_code_create 158 | or movie.status_code == status_code_update) 159 | movie.rating_delete(session_id=SESSION_ID) 160 | self.assertEqual(movie.status_code, status_code_delete) 161 | 162 | def test_movies_latest(self): 163 | movie = tmdb.Movies() 164 | movie.latest() 165 | self.assertTrue(hasattr(movie, 'popularity')) 166 | 167 | def test_movies_now_playing(self): 168 | movie = tmdb.Movies() 169 | movie.now_playing() 170 | self.assertTrue(hasattr(movie, 'results')) 171 | 172 | def test_movies_popular(self): 173 | movie = tmdb.Movies() 174 | movie.popular() 175 | self.assertTrue(hasattr(movie, 'results')) 176 | 177 | def test_movies_top_rated(self): 178 | movie = tmdb.Movies() 179 | movie.top_rated() 180 | self.assertTrue(hasattr(movie, 'results')) 181 | 182 | def test_movies_upcoming(self): 183 | movie = tmdb.Movies() 184 | movie.upcoming() 185 | self.assertTrue(hasattr(movie, 'results')) 186 | 187 | def test_movies_releases(self): 188 | id = MOVIE_ID 189 | movie = tmdb.Movies(id) 190 | movie.releases() 191 | self.assertTrue(hasattr(movie, 'countries')) 192 | 193 | 194 | class CollectionsTestCase(unittest.TestCase): 195 | def test_collections_info(self): 196 | id = COLLECTION_ID 197 | name = COLLECTION_NAME 198 | collection = tmdb.Collections(id) 199 | collection.info() 200 | self.assertEqual(collection.name, name) 201 | 202 | def test_collections_images(self): 203 | id = COLLECTION_ID 204 | collection = tmdb.Collections(id) 205 | collection.images() 206 | self.assertTrue(hasattr(collection, 'backdrops')) 207 | 208 | def test_collections_translations(self): 209 | id = COLLECTION_ID 210 | collection = tmdb.Collections(id) 211 | collection.translations() 212 | self.assertTrue(hasattr(collection, 'translations')) 213 | 214 | 215 | class CompaniesTestCase(unittest.TestCase): 216 | def test_companies_info(self): 217 | id = COMPANY_ID 218 | name = COMPANY_NAME 219 | company = tmdb.Companies(id) 220 | company.info() 221 | self.assertEqual(company.name, name) 222 | 223 | def test_companies_alternative_names(self): 224 | id = COMPANY_ID 225 | company = tmdb.Companies(id) 226 | company.alternative_names() 227 | self.assertTrue(hasattr(company, 'results')) 228 | 229 | def test_companies_images(self): 230 | id = COMPANY_ID 231 | company = tmdb.Companies(id) 232 | company.images() 233 | self.assertTrue(hasattr(company, 'logos')) 234 | 235 | def test_companies_movies(self): 236 | id = COMPANY_ID 237 | company = tmdb.Companies(id) 238 | company.movies() 239 | self.assertTrue(hasattr(company, 'results')) 240 | 241 | 242 | class KeywordsTestCase(unittest.TestCase): 243 | def test_keywords_info(self): 244 | id = KEYWORD_ID 245 | name = KEYWORD_NAME 246 | keyword = tmdb.Keywords(id) 247 | keyword.info() 248 | self.assertEqual(keyword.name, name) 249 | 250 | def test_keywords_movies(self): 251 | id = KEYWORD_ID 252 | keyword = tmdb.Keywords(id) 253 | keyword.movies() 254 | self.assertTrue(hasattr(keyword, 'results')) 255 | 256 | 257 | class ReviewsTestCase(unittest.TestCase): 258 | def test_reviews_info(self): 259 | id = REVIEW_ID 260 | author = REVIEW_AUTHOR 261 | review = tmdb.Reviews(id) 262 | review.info() 263 | self.assertEqual(review.author, author) 264 | -------------------------------------------------------------------------------- /tmdbsimple/people.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.people 5 | ~~~~~~~~~~~~~~~~~ 6 | This module implements the People and Credits functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class People(TMDB): 18 | """ 19 | People functionality. 20 | 21 | See: https://developers.themoviedb.org/3/people 22 | """ 23 | BASE_PATH = 'person' 24 | URLS = { 25 | 'info': '/{id}', 26 | 'changes': '/{id}/changes', 27 | 'movie_credits': '/{id}/movie_credits', 28 | 'tv_credits': '/{id}/tv_credits', 29 | 'combined_credits': '/{id}/combined_credits', 30 | 'external_ids': '/{id}/external_ids', 31 | 'images': '/{id}/images', 32 | 'tagged_images': '/{id}/tagged_images', 33 | 'translations': '/{id}/translations', 34 | 'latest': '/latest', 35 | 'popular': '/popular', 36 | } 37 | 38 | def __init__(self, id=0): 39 | super(People, self).__init__() 40 | self.id = id 41 | 42 | def info(self, **kwargs): 43 | """ 44 | Get the primary person details by id. 45 | 46 | Supports append_to_response. Read more about this at 47 | https://developers.themoviedb.org/3/getting-started/append-to-response. 48 | 49 | Args: 50 | language: (optional) ISO 639-1 code. 51 | append_to_response: (optional) Append requests within the same 52 | namespace to the response. 53 | 54 | Returns: 55 | A dict respresentation of the JSON returned from the API. 56 | """ 57 | path = self._get_id_path('info') 58 | 59 | response = self._GET(path, kwargs) 60 | self._set_attrs_to_values(response) 61 | return response 62 | 63 | def changes(self, **kwargs): 64 | """ 65 | Get the changes for a person. By default only the last 24 hours are returned. 66 | 67 | You can query up to 14 days in a single query by using the start_date 68 | and end_date query parameters. 69 | 70 | Args: 71 | start_date: (optional) Filter the results with a start date. 72 | Expected format is 'YYYY-MM-DD'. 73 | end_date: (optional) Filter the results with a end date. 74 | Expected format is 'YYYY-MM-DD'. 75 | page: (optional) Minimum 1, maximum 1000, default 1. 76 | 77 | Returns: 78 | A dict respresentation of the JSON returned from the API. 79 | """ 80 | path = self._get_id_path('changes') 81 | 82 | response = self._GET(path, kwargs) 83 | self._set_attrs_to_values(response) 84 | return response 85 | 86 | def movie_credits(self, **kwargs): 87 | """ 88 | Get the movie credits for a person. 89 | 90 | Args: 91 | language: (optional) ISO 639-1 code. 92 | 93 | Returns: 94 | A dict respresentation of the JSON returned from the API. 95 | """ 96 | path = self._get_id_path('movie_credits') 97 | 98 | response = self._GET(path, kwargs) 99 | self._set_attrs_to_values(response) 100 | return response 101 | 102 | def tv_credits(self, **kwargs): 103 | """ 104 | Get the TV show credits for a person. 105 | 106 | You can query for some extra details about the credit with the credit 107 | method. 108 | 109 | Args: 110 | language: (optional) ISO 639-1 code. 111 | 112 | Returns: 113 | A dict respresentation of the JSON returned from the API. 114 | """ 115 | path = self._get_id_path('tv_credits') 116 | 117 | response = self._GET(path, kwargs) 118 | self._set_attrs_to_values(response) 119 | return response 120 | 121 | def combined_credits(self, **kwargs): 122 | """ 123 | Get the movie and TV credits together in a single response. 124 | 125 | Args: 126 | language: (optional) ISO 639-1 code. 127 | 128 | Returns: 129 | A dict respresentation of the JSON returned from the API. 130 | """ 131 | path = self._get_id_path('combined_credits') 132 | 133 | response = self._GET(path, kwargs) 134 | self._set_attrs_to_values(response) 135 | return response 136 | 137 | def external_ids(self, **kwargs): 138 | """ 139 | Get the external ids for a person. We currently support the following external sources. 140 | 141 | External Sources 142 | - IMDB ID 143 | - Facebook 144 | - Freebase MID 145 | - Freebase ID 146 | - Instagram 147 | - TVRage ID 148 | - Twitter 149 | 150 | Args: 151 | language: (optional) ISO 639-1 code. 152 | 153 | Returns: 154 | A dict respresentation of the JSON returned from the API. 155 | """ 156 | path = self._get_id_path('external_ids') 157 | 158 | response = self._GET(path, kwargs) 159 | self._set_attrs_to_values(response) 160 | return response 161 | 162 | def images(self, **kwargs): 163 | """ 164 | Get the images for a person. 165 | 166 | Args: 167 | None 168 | 169 | Returns: 170 | A dict respresentation of the JSON returned from the API. 171 | """ 172 | path = self._get_id_path('images') 173 | 174 | response = self._GET(path, kwargs) 175 | self._set_attrs_to_values(response) 176 | return response 177 | 178 | def tagged_images(self, **kwargs): 179 | """ 180 | Get the images that this person has been tagged in. 181 | 182 | Args: 183 | language: (optional) ISO 639-1 code. 184 | page: (optional) Minimum 1, maximum 1000, default 1. 185 | 186 | Returns: 187 | A dict respresentation of the JSON returned from the API. 188 | """ 189 | path = self._get_id_path('tagged_images') 190 | 191 | response = self._GET(path, kwargs) 192 | self._set_attrs_to_values(response) 193 | return response 194 | 195 | def translations(self, **kwargs): 196 | """ 197 | Get a list of translations that have been created for a person. 198 | 199 | Args: 200 | language: (optional) ISO 639-1 code. 201 | 202 | Returns: 203 | A dict respresentation of the JSON returned from the API. 204 | """ 205 | path = self._get_id_path('translations') 206 | 207 | response = self._GET(path, kwargs) 208 | self._set_attrs_to_values(response) 209 | return response 210 | 211 | def latest(self, **kwargs): 212 | """ 213 | Get the most newly created person. This is a live response and will 214 | continuously change. 215 | 216 | Args: 217 | language: (optional) ISO 639-1 code. 218 | 219 | Returns: 220 | A dict respresentation of the JSON returned from the API. 221 | """ 222 | path = self._get_path('latest') 223 | 224 | response = self._GET(path, kwargs) 225 | self._set_attrs_to_values(response) 226 | return response 227 | 228 | def popular(self, **kwargs): 229 | """ 230 | Get the list of popular people on TMDb. This list updates daily. 231 | 232 | Args: 233 | language: (optional) ISO 639-1 code. 234 | page: (optional) Minimum 1, maximum 1000, default 1. 235 | 236 | Returns: 237 | A dict respresentation of the JSON returned from the API. 238 | """ 239 | path = self._get_path('popular') 240 | 241 | response = self._GET(path, kwargs) 242 | self._set_attrs_to_values(response) 243 | return response 244 | 245 | 246 | class Credits(TMDB): 247 | """ 248 | Credits functionality. 249 | 250 | See: https://developers.themoviedb.org/3/credits 251 | """ 252 | BASE_PATH = 'credit' 253 | URLS = { 254 | 'info': '/{credit_id}', 255 | } 256 | 257 | def __init__(self, credit_id): 258 | super(Credits, self).__init__() 259 | self.credit_id = credit_id 260 | 261 | def info(self, **kwargs): 262 | """ 263 | Get a movie or TV credit details by id. 264 | 265 | Args: 266 | None 267 | 268 | Returns: 269 | A dict respresentation of the JSON returned from the API. 270 | """ 271 | path = self._get_credit_id_path('info') 272 | 273 | response = self._GET(path, kwargs) 274 | self._set_attrs_to_values(response) 275 | return response 276 | -------------------------------------------------------------------------------- /tests/test_tv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_tv.py 5 | ~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Test class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | 18 | from tests import API_KEY, SESSION_ID 19 | tmdb.API_KEY = API_KEY 20 | 21 | """ 22 | Constants 23 | """ 24 | TV_ID = 1396 25 | TV_NAME = 'Breaking Bad' 26 | TV_IMDB_ID = 'tt0903747' 27 | RATING = 7.5 28 | TV_SEASON_ID = 3572 29 | TV_SEASON_NUMBER = 1 30 | TV_SEASON_NAME = 'Season 1' 31 | TV_SEASON_TVDB_ID = 2547 32 | TV_EPISODE_ID = 62085 33 | TV_EPISODE_NUMBER = 1 34 | TV_EPISODE_NAME = 'Pilot' 35 | TV_EPISODE_IMDB_ID = 'tt0959621' 36 | TV_EPISODE_GROUP_ID = '5acf93e60e0a26346d0000ce' 37 | NETWORK_ID = 49 38 | NETWORK_NAME = 'HBO' 39 | 40 | 41 | """ 42 | Status codes and messages 43 | """ 44 | SUCCESSFUL_CREATE = 1 45 | SUCCESSFUL_UPDATE = 12 46 | SUCCESSFUL_DELETE = 13 47 | 48 | 49 | class TVTestCase(unittest.TestCase): 50 | def test_tv_info(self): 51 | id = TV_ID 52 | name = TV_NAME 53 | tv = tmdb.TV(id) 54 | tv.info() 55 | self.assertEqual(tv.name, name) 56 | 57 | def test_tv_account_states(self): 58 | id = TV_ID 59 | tv = tmdb.TV(id) 60 | tv.account_states(session_id=SESSION_ID) 61 | self.assertTrue(hasattr(tv, 'rated')) 62 | 63 | def test_tv_alternative_titles(self): 64 | id = TV_ID 65 | tv = tmdb.TV(id) 66 | tv.alternative_titles() 67 | self.assertTrue(hasattr(tv, 'results')) 68 | 69 | def test_tv_content_ratings(self): 70 | id = TV_ID 71 | tv = tmdb.TV(id) 72 | tv.content_ratings() 73 | self.assertTrue(hasattr(tv, 'results')) 74 | 75 | def test_tv_credits(self): 76 | id = TV_ID 77 | tv = tmdb.TV(id) 78 | tv.credits() 79 | self.assertTrue(hasattr(tv, 'cast')) 80 | 81 | def test_tv_episode_groups(self): 82 | id = TV_ID 83 | tv = tmdb.TV(id) 84 | tv.episode_groups() 85 | self.assertTrue(hasattr(tv, 'results')) 86 | 87 | def test_tv_external_ids(self): 88 | id = TV_ID 89 | imdb_id = TV_IMDB_ID 90 | tv = tmdb.TV(id) 91 | tv.external_ids() 92 | self.assertEqual(tv.imdb_id, imdb_id) 93 | 94 | def test_tv_images(self): 95 | id = TV_ID 96 | tv = tmdb.TV(id) 97 | tv.images() 98 | self.assertTrue(hasattr(tv, 'backdrops')) 99 | 100 | def test_tv_keywords(self): 101 | id = TV_ID 102 | tv = tmdb.TV(id) 103 | tv.keywords() 104 | self.assertTrue(hasattr(tv, 'keywords')) 105 | 106 | def test_tv_recommendations(self): 107 | id = TV_ID 108 | tv = tmdb.TV(id) 109 | tv.recommendations() 110 | self.assertTrue(hasattr(tv, 'results')) 111 | 112 | def test_tv_reviews(self): 113 | id = TV_ID 114 | tv = tmdb.TV(id) 115 | tv.reviews() 116 | self.assertTrue(hasattr(tv, 'results')) 117 | 118 | def test_tv_screened_theatrically(self): 119 | id = TV_ID 120 | tv = tmdb.TV(id) 121 | tv.screened_theatrically() 122 | self.assertTrue(hasattr(tv, 'results')) 123 | 124 | def test_tv_similar(self): 125 | id = TV_ID 126 | tv = tmdb.TV(id) 127 | tv.similar() 128 | self.assertTrue(hasattr(tv, 'results')) 129 | 130 | def test_tv_translations(self): 131 | id = TV_ID 132 | tv = tmdb.TV(id) 133 | tv.translations() 134 | self.assertTrue(hasattr(tv, 'translations')) 135 | 136 | def test_tv_videos(self): 137 | id = TV_ID 138 | tv = tmdb.TV(id) 139 | tv.videos() 140 | self.assertTrue(hasattr(tv, 'results')) 141 | 142 | def test_tv_watch_providers(self): 143 | id = TV_ID 144 | tv = tmdb.TV(id) 145 | tv.watch_providers() 146 | self.assertTrue(hasattr(tv, 'results')) 147 | 148 | def test_tv_rating_and_rating_delete(self): 149 | status_code_create = SUCCESSFUL_CREATE 150 | status_code_update = SUCCESSFUL_UPDATE 151 | status_code_delete = SUCCESSFUL_DELETE 152 | id = TV_ID 153 | tv = tmdb.TV(id) 154 | tv.rating(session_id=SESSION_ID, value=RATING) 155 | self.assertTrue(tv.status_code, status_code_create 156 | or tv.status_code == status_code_update) 157 | tv.rating_delete(session_id=SESSION_ID) 158 | self.assertEqual(tv.status_code, status_code_delete) 159 | 160 | def test_tv_latest(self): 161 | tv = tmdb.TV() 162 | tv.latest() 163 | self.assertTrue(hasattr(tv, 'first_air_date')) 164 | 165 | def test_tv_airing_today(self): 166 | tv = tmdb.TV() 167 | tv.airing_today() 168 | self.assertTrue(hasattr(tv, 'results')) 169 | 170 | def test_tv_on_the_air(self): 171 | tv = tmdb.TV() 172 | tv.on_the_air() 173 | self.assertTrue(hasattr(tv, 'results')) 174 | 175 | def test_tv_popular(self): 176 | tv = tmdb.TV() 177 | tv.popular() 178 | self.assertTrue(hasattr(tv, 'results')) 179 | 180 | def test_tv_top_rated(self): 181 | tv = tmdb.TV() 182 | tv.top_rated() 183 | self.assertTrue(hasattr(tv, 'results')) 184 | 185 | 186 | class TVSeasonsTestCase(unittest.TestCase): 187 | def test_tv_seasons_info(self): 188 | series_id = TV_SEASON_ID 189 | season_number = TV_SEASON_NUMBER 190 | name = TV_SEASON_NAME 191 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 192 | tv_seasons.info() 193 | self.assertEqual(tv_seasons.name, name) 194 | 195 | def test_tv_seasons_account_states(self): 196 | series_id = TV_SEASON_ID 197 | season_number = TV_SEASON_NUMBER 198 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 199 | tv_seasons.account_states(session_id=SESSION_ID) 200 | self.assertTrue(hasattr(tv_seasons, 'results')) 201 | 202 | def test_tv_seasons_credits(self): 203 | series_id = TV_SEASON_ID 204 | season_number = TV_SEASON_NUMBER 205 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 206 | tv_seasons.credits() 207 | self.assertTrue(hasattr(tv_seasons, 'crew')) 208 | 209 | def test_tv_seasons_external_ids(self): 210 | series_id = TV_SEASON_ID 211 | season_number = TV_SEASON_NUMBER 212 | tvdb_id = TV_SEASON_TVDB_ID 213 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 214 | tv_seasons.external_ids() 215 | self.assertEqual(tv_seasons.tvdb_id, tvdb_id) 216 | 217 | def test_tv_seasons_images(self): 218 | series_id = TV_SEASON_ID 219 | season_number = TV_SEASON_NUMBER 220 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 221 | tv_seasons.images() 222 | self.assertTrue(hasattr(tv_seasons, 'posters')) 223 | 224 | def test_tv_seasons_videos(self): 225 | series_id = TV_SEASON_ID 226 | season_number = TV_SEASON_NUMBER 227 | tv_seasons = tmdb.TV_Seasons(series_id, season_number) 228 | tv_seasons.videos() 229 | self.assertTrue(hasattr(tv_seasons, 'results')) 230 | 231 | 232 | class TVEpisodesTestCase(unittest.TestCase): 233 | def test_tv_episodes_info(self): 234 | series_id = TV_ID 235 | season_number = TV_SEASON_NUMBER 236 | episode_number = TV_EPISODE_NUMBER 237 | name = TV_EPISODE_NAME 238 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 239 | tv_episode.info() 240 | self.assertEqual(tv_episode.name, name) 241 | 242 | def test_tv_episodes_account_states(self): 243 | series_id = TV_ID 244 | season_number = TV_SEASON_NUMBER 245 | episode_number = TV_EPISODE_NUMBER 246 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 247 | tv_episode.account_states(session_id=SESSION_ID) 248 | self.assertTrue(hasattr(tv_episode, 'rated')) 249 | 250 | def test_tv_episodes_credits(self): 251 | series_id = TV_ID 252 | season_number = TV_SEASON_NUMBER 253 | episode_number = TV_EPISODE_NUMBER 254 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 255 | tv_episode.credits() 256 | self.assertTrue(hasattr(tv_episode, 'guest_stars')) 257 | 258 | def test_tv_episodes_external_ids(self): 259 | series_id = TV_ID 260 | season_number = TV_SEASON_NUMBER 261 | episode_number = TV_EPISODE_NUMBER 262 | imdb_id = TV_EPISODE_IMDB_ID 263 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 264 | tv_episode.external_ids() 265 | self.assertEqual(tv_episode.imdb_id, imdb_id) 266 | 267 | def test_tv_episodes_images(self): 268 | series_id = TV_ID 269 | season_number = TV_SEASON_NUMBER 270 | episode_number = TV_EPISODE_NUMBER 271 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 272 | tv_episode.images() 273 | self.assertTrue(hasattr(tv_episode, 'stills')) 274 | 275 | def test_tv_episodes_translations(self): 276 | series_id = TV_ID 277 | season_number = TV_SEASON_NUMBER 278 | episode_number = TV_EPISODE_NUMBER 279 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 280 | tv_episode.translations() 281 | self.assertTrue(hasattr(tv_episode, 'translations')) 282 | 283 | def test_tv_episodes_rating(self): 284 | status_code_create = SUCCESSFUL_CREATE 285 | status_code_update = SUCCESSFUL_UPDATE 286 | status_code_delete = SUCCESSFUL_DELETE 287 | series_id = TV_ID 288 | season_number = TV_SEASON_NUMBER 289 | episode_number = TV_EPISODE_NUMBER 290 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 291 | tv_episode.rating(session_id=SESSION_ID, value=RATING) 292 | self.assertTrue(tv_episode.status_code == status_code_create 293 | or tv_episode.status_code == status_code_update) 294 | tv_episode.rating_delete(session_id=SESSION_ID) 295 | self.assertEqual(tv_episode.status_code, status_code_delete) 296 | 297 | def test_tv_episodes_videos(self): 298 | series_id = TV_ID 299 | season_number = TV_SEASON_NUMBER 300 | episode_number = TV_EPISODE_NUMBER 301 | tv_episode = tmdb.TV_Episodes(series_id, season_number, episode_number) 302 | tv_episode.videos() 303 | self.assertTrue(hasattr(tv_episode, 'results')) 304 | 305 | 306 | class TVEpisodeGroupsTestCase(unittest.TestCase): 307 | def test_tv_episode_groups_info(self): 308 | tv_episode_group_id = TV_EPISODE_GROUP_ID 309 | tv_episode_group = tmdb.TV_Episode_Groups(tv_episode_group_id) 310 | tv_episode_group.info() 311 | self.assertTrue(hasattr(tv_episode_group, 'groups')) 312 | 313 | 314 | class TVChangesTestCase(unittest.TestCase): 315 | def test_series_changes(self): 316 | id = TV_ID 317 | tv_changes = tmdb.TV_Changes(id) 318 | tv_changes.series() 319 | self.assertTrue(hasattr(tv_changes, 'changes')) 320 | 321 | def test_season_changes(self): 322 | id = TV_SEASON_ID 323 | tv_changes = tmdb.TV_Changes(id) 324 | tv_changes.season() 325 | self.assertTrue(hasattr(tv_changes, 'changes')) 326 | 327 | def test_episode_changes(self): 328 | id = TV_EPISODE_ID 329 | tv_changes = tmdb.TV_Changes(id) 330 | tv_changes.episode() 331 | self.assertTrue(hasattr(tv_changes, 'changes')) 332 | 333 | 334 | class NetworksTestCase(unittest.TestCase): 335 | def test_networks_info(self): 336 | id = NETWORK_ID 337 | name = NETWORK_NAME 338 | network = tmdb.Networks(id) 339 | network.info() 340 | self.assertEqual(network.name, name) 341 | 342 | def test_networks_alternative_names(self): 343 | id = NETWORK_ID 344 | network = tmdb.Networks(id) 345 | network.alternative_names() 346 | self.assertTrue(hasattr(network, 'results')) 347 | 348 | def test_networks_images(self): 349 | id = NETWORK_ID 350 | network = tmdb.Networks(id) 351 | network.images() 352 | self.assertTrue(hasattr(network, 'logos')) 353 | -------------------------------------------------------------------------------- /tests/test_account.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | test_account.py 5 | ~~~~~~~~~~~~~~~ 6 | 7 | This test suite checks the methods of the Account class of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-11-05 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley. 12 | :license: GPLv3, see LICENSE for more details. 13 | """ 14 | 15 | import unittest 16 | import tmdbsimple as tmdb 17 | import time 18 | 19 | from tests import API_KEY, SESSION_ID, USERNAME, PASSWORD 20 | tmdb.API_KEY = API_KEY 21 | 22 | """ 23 | Constants 24 | """ 25 | MOVIETITLE = 'The Brother from Another Planet' 26 | TVTITLE = 'Breaking Bad' 27 | FAVORITE_MOVIE_ID = 62211 28 | GUEST_MOVIE_ID = 103332 29 | GUEST_MOVIE_RATING = 7.5 30 | GUEST_TV_ID = 1396 31 | GUEST_TV_RATING = 7.5 32 | GUEST_TV_SEASON_NUMBER = 1 33 | GUEST_TV_EPISODE_NUMBER = 1 34 | GUEST_TV_EPISODE_RATING = 9.5 35 | GUEST_TV_WATCHLIST_MEDIA_ID = 11 36 | WATCHLIST_MEDIA_ID = 11 37 | LIST_ID = '509ec17b19c2950a0600050d' 38 | LIST_CREATED_BY = 'regina.phalange' 39 | LIST_MOVIE_ID = 76203 # Argo 40 | LIST_NAME = 'My newly created list' 41 | LIST_DESCRIPTION = 'No duplicates here' 42 | LIST_LANGUAGE = 'de' 43 | LIST_ITEM_MEDIA_ID = 550 44 | 45 | """ 46 | Status codes and messages 47 | """ 48 | SUCCESS_PERIOD = 'Success.' 49 | SUCCESSFUL_UPDATE = 12 50 | SUCCESSFUL_REMOVE_ITEM = 13 51 | SUCCESSFUL_DELETE = 12 52 | 53 | 54 | class AccountTestCase(unittest.TestCase): 55 | # run this test with a valid session_id and authenticated account 56 | def test_account_info(self): 57 | username = USERNAME 58 | account = tmdb.Account(SESSION_ID) 59 | account.info() 60 | self.assertEqual(account.username, username) 61 | 62 | def test_account_lists(self): 63 | account = tmdb.Account(SESSION_ID) 64 | account.info() # to set account.id 65 | account.lists() 66 | self.assertTrue(hasattr(account, 'results')) 67 | 68 | def test_account_favorite_movies(self): 69 | movietitle = MOVIETITLE 70 | account = tmdb.Account(SESSION_ID) 71 | account.info() # to set account.id 72 | account.favorite_movies() 73 | self.assertEqual(account.results[0]['title'], movietitle) 74 | 75 | def test_account_favorite_tv(self): 76 | tvtitle = TVTITLE 77 | account = tmdb.Account(SESSION_ID) 78 | account.info() # to set account.id 79 | account.favorite_tv() 80 | self.assertEqual(account.results[0]['name'], tvtitle) 81 | 82 | def test_account_favorite(self): 83 | status_code = SUCCESSFUL_UPDATE 84 | account = tmdb.Account(SESSION_ID) 85 | account.info() # to set account.id 86 | kwargs = { 87 | 'media_type': 'movie', 88 | 'movie_id': FAVORITE_MOVIE_ID, 89 | 'favorite': True, 90 | } 91 | account.favorite(**kwargs) 92 | self.assertEqual(account.status_code, status_code) 93 | 94 | def test_account_rated_movies(self): 95 | account = tmdb.Account(SESSION_ID) 96 | account.info() # to set account.id 97 | kwargs = {'page': 1, 'sort_by': 'created_at.asc'} 98 | account.rated_movies(**kwargs) 99 | self.assertTrue(hasattr(account, 'results')) 100 | 101 | def test_account_rated_tv(self): 102 | account = tmdb.Account(SESSION_ID) 103 | account.info() # to set account.id 104 | kwargs = {'page': 1, 'sort_by': 'created_at.asc'} 105 | account.rated_tv(**kwargs) 106 | self.assertTrue(hasattr(account, 'results')) 107 | 108 | def test_account_rated_tv_episodes(self): 109 | account = tmdb.Account(SESSION_ID) 110 | account.info() # to set account.id 111 | kwargs = {'page': 1, 'sort_by': 'created_at.asc'} 112 | account.rated_tv_episodes(**kwargs) 113 | self.assertTrue(hasattr(account, 'results')) 114 | 115 | def test_account_watchlist_movies(self): 116 | movietitle = MOVIETITLE 117 | account = tmdb.Account(SESSION_ID) 118 | account.info() # to set account.id 119 | kwargs = {'page': 1, 'sort_by': 'created_at.asc'} 120 | account.watchlist_movies(**kwargs) 121 | self.assertEqual(account.results[0]['title'], movietitle) 122 | 123 | def test_account_watchlist_tv(self): 124 | tvtitle = TVTITLE 125 | account = tmdb.Account(SESSION_ID) 126 | account.info() # to set account.id 127 | kwargs = {'page': 1, 'sort_by': 'created_at.asc'} 128 | account.watchlist_tv(**kwargs) 129 | self.assertEqual(account.results[0]['name'], tvtitle) 130 | 131 | def test_account_watchlist(self): 132 | status_code = SUCCESSFUL_UPDATE 133 | account = tmdb.Account(SESSION_ID) 134 | account.info() # to set account.id 135 | kwargs = { 136 | 'media_type': 'movie', 137 | 'media_id': WATCHLIST_MEDIA_ID, 138 | 'watchlist': 'true', 139 | } 140 | account.watchlist(**kwargs) 141 | self.assertEqual(account.status_code, status_code) 142 | 143 | 144 | class AuthenticationTestCase(unittest.TestCase): 145 | def test_authentication_guest_session_new(self): 146 | success = True 147 | auth = tmdb.Authentication() 148 | auth.guest_session_new() 149 | self.assertEqual(auth.success, success) 150 | 151 | def test_authentication_token_new(self): 152 | success = True 153 | auth = tmdb.Authentication() 154 | auth.token_new() 155 | self.assertEqual(auth.success, success) 156 | 157 | # Example usage only. 158 | # User needs to approve request token, so would error here. 159 | # See https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 160 | # test_authentication_session_new(self): 161 | # kwargs = {'request_token': auth.request_token} 162 | # success = True 163 | # auth = tmdb.Authentication() 164 | # response = auth.session_new(**kwargs) 165 | # self.assertEqual(auth.success, success) 166 | 167 | # test_authentication_token_validate_with_login(self): 168 | kwargs = { 169 | 'request_token': auth.request_token, 170 | 'username': USERNAME, 171 | 'password': PASSWORD, 172 | } 173 | success = True 174 | auth = tmdb.Authentication() 175 | auth.token_validate_with_login(**kwargs) 176 | self.assertEqual(auth.success, success) 177 | 178 | # Example usage only. 179 | # Don't want to delete session every time test is run. 180 | # test_session_delete(self): 181 | # kwargs = {'session_id': SESSION_ID} 182 | # success = True 183 | # auth = tmdb.Authentication() 184 | # response = auth.session_delete(**kwargs) 185 | # self.assertEqual(auth.success, success) 186 | 187 | 188 | class GuestSessionsTestCase(unittest.TestCase): 189 | def test_guest_sessions_rated_movies(self): 190 | # shown is the code to test this feature 191 | # TMDB now requires that a guest add a rating to activate the guest session 192 | # but the rating may not be added immediately, leading the test to error out 193 | # so uncomment and run this test when needed 194 | 195 | # status_code_delete = SUCCESSFUL_DELETE 196 | 197 | # # get a guest session id 198 | # auth = tmdb.Authentication() 199 | # auth.guest_session_new() 200 | # guest_session_id = auth.guest_session_id 201 | 202 | # # TMDB now requires that a guest add a rating to activate the guest session. 203 | # # https://www.themoviedb.org/talk/65dde3f289d97f0130986fb2?language=af-ZA 204 | # movie = tmdb.Movies(GUEST_MOVIE_ID) 205 | # movie.rating(guest_session_id=guest_session_id, value=GUEST_MOVIE_RATING) 206 | # time.sleep(10) 207 | 208 | # # get a list of rated movies for the guest session id 209 | # guest_session = tmdb.GuestSessions(guest_session_id) 210 | # guest_session.rated_movies() 211 | # self.assertTrue(hasattr(guest_session, 'results')) 212 | 213 | # # delete the rating 214 | # movie.rating_delete(guest_session_id=SESSION_ID) 215 | # self.assertEqual(movie.status_code, status_code_delete) 216 | return True 217 | 218 | def test_guest_sessions_rated_tv(self): 219 | # shown is the code to test this feature 220 | # TMDB now requires that a guest add a rating to activate the guest session 221 | # but the rating may not be added immediately, leading the test to error out 222 | # so uncomment and run this test when needed 223 | 224 | # status_code_delete = SUCCESSFUL_DELETE 225 | 226 | # # get a guest session id 227 | # auth = tmdb.Authentication() 228 | # auth.guest_session_new() 229 | # guest_session_id = auth.guest_session_id 230 | 231 | # # TMDB now requires that a guest add a rating to activate the guest session. 232 | # # https://www.themoviedb.org/talk/65dde3f289d97f0130986fb2?language=af-ZA 233 | # tv = tmdb.TV(GUEST_TV_ID) 234 | # tv.rating(guest_session_id=guest_session_id, value=GUEST_TV_RATING) 235 | # # wait for the rating to be added 236 | # time.sleep(10) 237 | 238 | # # get a list of rated tv shows for the guest session id 239 | # guest_session = tmdb.GuestSessions(guest_session_id) 240 | # guest_session.rated_tv() 241 | # self.assertTrue(hasattr(guest_session, 'results')) 242 | 243 | # # delete the rating 244 | # tv.rating_delete(guest_session_id=SESSION_ID) 245 | # self.assertEqual(tv.status_code, status_code_delete) 246 | return True 247 | 248 | def test_guest_sessions_rated_tv_episodes(self): 249 | # shown is the code to test this feature 250 | # TMDB now requires that a guest add a rating to activate the guest session 251 | # but the rating may not be added immediately, leading the test to error out 252 | # so uncomment and run this test when needed 253 | 254 | # status_code_delete = SUCCESSFUL_DELETE 255 | 256 | # # get a guest session id 257 | # auth = tmdb.Authentication() 258 | # auth.guest_session_new() 259 | # guest_session_id = auth.guest_session_id 260 | 261 | # # TMDB now requires that a guest add a rating to activate the guest session. 262 | # # https://www.themoviedb.org/talk/65dde3f289d97f0130986fb2?language=af-ZA 263 | # tv_episode = tmdb.TV_Episodes(GUEST_TV_ID, GUEST_TV_SEASON_NUMBER, GUEST_TV_EPISODE_NUMBER) 264 | # tv_episode.rating(guest_session_id=guest_session_id, value=GUEST_TV_EPISODE_RATING) 265 | # # wait for the rating to be added 266 | # time.sleep(10) 267 | 268 | # # get a list of rated tv episodes for the guest session id 269 | # guest_session = tmdb.GuestSessions(guest_session_id) 270 | # guest_session.rated_tv_episodes() 271 | # self.assertTrue(hasattr(guest_session, 'results')) 272 | 273 | # # delete the rating 274 | # tv_episode.rating_delete(guest_session_id=SESSION_ID) 275 | # self.assertEqual(tv_episode.status_code, status_code_delete) 276 | return True 277 | 278 | class ListsTestCase(unittest.TestCase): 279 | def test_lists_info(self): 280 | id = LIST_ID 281 | created_by = LIST_CREATED_BY 282 | lst = tmdb.Lists(id) 283 | lst.info() 284 | self.assertEqual(lst.created_by, created_by) 285 | 286 | def test_lists_item_status(self): 287 | id = LIST_ID 288 | movie_id = LIST_MOVIE_ID 289 | lst = tmdb.Lists(id) 290 | lst.item_status(movie_id=movie_id) 291 | self.assertTrue(hasattr(lst, 'item_present')) 292 | 293 | def test_lists_create_add_remove_clear_delete(self): 294 | kwargs = { 295 | 'name': LIST_NAME, 296 | 'description': LIST_DESCRIPTION, 297 | 'language': LIST_LANGUAGE, 298 | } 299 | status_message = SUCCESS_PERIOD 300 | lst = tmdb.Lists(0, SESSION_ID) 301 | lst.list_create(**kwargs) 302 | self.assertEqual(lst.status_message, status_message) 303 | 304 | status_code = SUCCESSFUL_UPDATE 305 | lst.add_item(media_id=LIST_ITEM_MEDIA_ID) 306 | self.assertEqual(lst.status_code, status_code) 307 | 308 | status_code = SUCCESSFUL_REMOVE_ITEM 309 | lst.remove_item(media_id=LIST_ITEM_MEDIA_ID) 310 | self.assertEqual(lst.status_code, status_code) 311 | 312 | status_code = SUCCESSFUL_UPDATE 313 | lst.list_clear(confirm='true') 314 | self.assertEqual(lst.status_code, status_code) 315 | 316 | # TODO: add list_delete check when list delete bug is fixed: 317 | # https://www.themoviedb.org/talk/5e7bb85aeec4f30018aa327c#5f0b5ff91f98d100361f3037. 318 | # Deletes list, but returns 500 error rather than 201. 319 | # status_code = SUCCESSFUL_DELETE 320 | # lst.list_delete() 321 | # self.assertEqual(lst.status_code, status_code) 322 | -------------------------------------------------------------------------------- /tmdbsimple/discover.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.discover 5 | ~~~~~~~~~~~~~~~~~~~ 6 | This module implements the Discover functionality of tmdbsimple. 7 | 8 | Created by Celia Oakley on 2013-10-31. 9 | 10 | :copyright: (c) 2013-2025 by Celia Oakley 11 | :license: GPLv3, see LICENSE for more details 12 | """ 13 | 14 | from .base import TMDB 15 | 16 | 17 | class Discover(TMDB): 18 | """ 19 | Discover functionality. 20 | 21 | See: https://developers.themoviedb.org/3/discover 22 | """ 23 | BASE_PATH = 'discover' 24 | URLS = { 25 | 'movie': '/movie', 26 | 'tv': '/tv', 27 | } 28 | 29 | def movie(self, **kwargs): 30 | """ 31 | Discover movies by different types of data like average rating, number 32 | of votes, genres and certifications. You can get a valid list of 33 | certifications from the certifications list method. 34 | 35 | Discover also supports a nice list of sort options. See below for all 36 | of the available options. 37 | 38 | Please note, when using certification / certification.lte you must also 39 | specify certification_country. These two parameters work together in 40 | order to filter the results. You can only filter results with the 41 | countries we have added to our certifications list. 42 | 43 | If you specify the region parameter, the regional release date will be 44 | used instead of the primary release date. The date returned will be the 45 | first date based on your query (ie. if a with_release_type is 46 | specified). It's important to note the order of the release types that 47 | are used. Specifying "2|3" would return the limited theatrical release 48 | date as opposed to "3|2" which would return the theatrical date. 49 | 50 | Also note that a number of filters support being comma (,) or pipe (|) 51 | separated. Comma's are treated like an AND and query while pipe's are 52 | an OR. 53 | 54 | Some examples of what can be done with discover can be found at 55 | https://www.themoviedb.org/documentation/api/discover. 56 | 57 | Args: 58 | language: (optional) ISO 639-1 code. 59 | region: (optional) Specify a ISO 3166-1 code. 60 | sort_by: (optional) Allowed values: popularity.asc, 61 | popularity.desc, release_date.asc, release_date.desc, 62 | revenue.asc, revenue.desc, primary_release_date.asc, 63 | primary_release_date.desc, original_title.asc, 64 | original_title.desc, vote_average.asc, vote_average.desc, 65 | vote_count.asc, vote_count.desc 66 | Default: popularity.desc 67 | certification_country: (optional) Used in conjunction with the 68 | certification filter, use this to specify a country with a 69 | valid certification. 70 | certification: Filter results with a valid certification from the 71 | 'certification_country' field. 72 | certification.gte: Filter and only include movies that have a 73 | certification that is greater than or equal to the specified 74 | value. 75 | certification.lte: Filter and only include movies that have a 76 | certification that is less than or equal to the specified 77 | value. 78 | include_adult: (optional) A filter and include or exclude adult 79 | movies. 80 | include_video: (optional) A filter to include or exclude videos. 81 | page: (optional) Minimum 1, maximum 1000, default 1. 82 | primary_release_year: (optional) A filter to limit the results to a 83 | specific primary release year. 84 | primary_release_date.gte: (optional) Filter and only include movies 85 | that have a primary release date that is greater or equal to 86 | the specified value. 87 | primary_release_date.lte: (optional) Filter and only include movies 88 | that have a primary release date that is less than or equal to 89 | the specified value. 90 | release_date.gte: (optional) Filter and only include movies that 91 | have a primary release date that is greater or equal to the 92 | specified value. 93 | releaste_date.lte: (optional) Filter and only include movies that 94 | have a primary release date that is less than or equal to the 95 | specified value. 96 | with_release_type: (optional) Specify a comma (AND) or pipe (OR) 97 | separated value to filter release types by. These release types 98 | map to the same values found on the movie release date method. 99 | Minimum 1, maximum 6. 100 | year: (optional) A filter to limit the results to a specific year 101 | (looking at all release dates). 102 | vote_count.gte: (optional) Filter and only include movies that have 103 | a vote count that is greater or equal to the specified value. 104 | Minimum 0. 105 | vote_count.lte: (optional) Filter and only include movies that have 106 | a vote count that is less than or equal to the specified value. 107 | Minimum 1. 108 | vote_average.gte: (optional) Filter and only include movies that 109 | have a rating that is greater or equal to the specified value. 110 | Minimum 0. 111 | vote_average.lte: (optional) Filter and only include movies that 112 | have a rating that is less than or equal to the specified value. 113 | Minimum 0. 114 | with_cast: (optional) A comma separated list of person ID's. Only 115 | include movies that have one of the ID's added as an actor. 116 | with_crew: (optional) A comma separated list of person ID's. Only 117 | include movies that have one of the ID's added as a crew member. 118 | with_people: (optional) A comma separated list of person ID's. Only 119 | include movies that have one of the ID's added as a either a 120 | actor or a crew member. 121 | with_companies: (optional) A comma separated list of production 122 | company ID's. Only include movies that have one of the ID's 123 | added as a production company. 124 | with_genres: (optional) Comma separated value of genre ids that you 125 | want to include in the results. 126 | without_genres: (optional) Comma separated value of genre ids that 127 | you want to exclude from the results. 128 | with_keywords: (optional) A comma separated list of keyword ID's. 129 | Only includes movies that have one of the ID's added as a 130 | keyword. 131 | without_keywords: (optional) Exclude items with certain keywords. 132 | You can comma and pipe seperate these values to create an 'AND' or 'OR' logic. 133 | with_runtime.gte: (optional) Filter and only include movies that 134 | have a runtime that is greater or equal to a value. 135 | with_runtime.lte: (optional) Filter and only include movies that 136 | have a runtime that is less than or equal to a value. 137 | with_original_language: (optional) Specify an ISO 639-1 string to 138 | filter results by their original language value. 139 | 140 | Returns: 141 | A dict respresentation of the JSON returned from the API. 142 | """ 143 | # Periods are not allowed in keyword arguments but several API 144 | # arguments contain periods. See both usages in tests/test_discover.py. 145 | for param in dict(kwargs): 146 | if '_lte' in param: 147 | kwargs[param.replace('_lte', '.lte')] = kwargs.pop(param) 148 | if '_gte' in param: 149 | kwargs[param.replace('_gte', '.gte')] = kwargs.pop(param) 150 | 151 | path = self._get_path('movie') 152 | 153 | response = self._GET(path, kwargs) 154 | self._set_attrs_to_values(response) 155 | return response 156 | 157 | def tv(self, **kwargs): 158 | """ 159 | Discover TV shows by different types of data like average rating, 160 | number of votes, genres, the network they aired on and air dates. 161 | 162 | Discover also supports a nice list of sort options. See below for all 163 | of the available options. 164 | 165 | Also note that a number of filters support being comma (,) or pipe (|) 166 | separated. Comma's are treated like an AND and query while pipe's are 167 | an OR. 168 | 169 | Some examples of what can be done with discover can be found at 170 | https://www.themoviedb.org/documentation/api/discover. 171 | 172 | Args: 173 | language: (optional) ISO 639-1 code. 174 | sort_by: (optional) Available options are 'vote_average.desc', 175 | 'vote_average.asc', 'first_air_date.desc', 176 | 'first_air_date.asc', 'popularity.desc', 'popularity.asc' 177 | sort_by: (optional) Allowed values: vote_average.desc, 178 | vote_average.asc, first_air_date.desc, first_air_date.asc, 179 | popularity.desc, popularity.asc 180 | Default: popularity.desc 181 | air_date.gte: (optional) Filter and only include TV shows that have 182 | a air date (by looking at all episodes) that is greater or 183 | equal to the specified value. 184 | air_date.lte: (optional) Filter and only include TV shows that have 185 | a air date (by looking at all episodes) that is less than or 186 | equal to the specified value. 187 | first_air_date.gte: (optional) Filter and only include TV shows 188 | that have a original air date that is greater or equal to the 189 | specified value. Can be used in conjunction with the 190 | "include_null_first_air_dates" filter if you want to include 191 | items with no air date. 192 | first_air_date.lte: (optional) Filter and only include TV shows 193 | that have a original air date that is less than or equal to the 194 | specified value. Can be used in conjunction with the 195 | "include_null_first_air_dates" filter if you want to include 196 | items with no air date. 197 | first_air_date_year: (optional) Filter and only include TV shows 198 | that have a original air date year that equal to the specified 199 | value. Can be used in conjunction with the 200 | "include_null_first_air_dates" filter if you want to include 201 | items with no air date. 202 | page: (optional) Specify the page of results to query. Default 1. 203 | timezone: (optional) Used in conjunction with the air_date.gte/lte 204 | filter to calculate the proper UTC offset. Default 205 | America/New_York. 206 | vote_average.gte: (optional) Filter and only include movies that 207 | have a rating that is greater or equal to the specified value. 208 | Minimum 0. 209 | vote_count.gte: (optional) Filter and only include movies that have 210 | a rating that is less than or equal to the specified value. 211 | Minimum 0. 212 | with_genres: (optional) Comma separated value of genre ids that you 213 | want to include in the results. 214 | with_networks: (optional) Comma separated value of network ids that 215 | you want to include in the results. 216 | without_genres: (optional) Comma separated value of genre ids that 217 | you want to exclude from the results. 218 | with_runtime.gte: (optional) Filter and only include TV shows with 219 | an episode runtime that is greater than or equal to a value. 220 | with_runtime.lte: (optional) Filter and only include TV shows with 221 | an episode runtime that is less than or equal to a value. 222 | include_null_first_air_dates: (optional) Use this filter to include 223 | TV shows that don't have an air date while using any of the 224 | "first_air_date" filters. 225 | with_original_language: (optional) Specify an ISO 639-1 string to 226 | filter results by their original language value. 227 | without_keywords: (optional) Exclude items with certain keywords. 228 | You can comma and pipe seperate these values to create an 'AND' 229 | or 'OR' logic. 230 | screened_theatrically: (optional) Filter results to include items 231 | that have been screened theatrically. 232 | with_companies: (optional) A comma separated list of production 233 | company ID's. Only include movies that have one of the ID's 234 | added as a production company. 235 | with_keywords: (optional) A comma separated list of keyword ID's. 236 | Only includes TV shows that have one of the ID's added as a 237 | keyword. 238 | 239 | Returns: 240 | A dict respresentation of the JSON returned from the API. 241 | """ 242 | # Periods are not allowed in keyword arguments but several API 243 | # arguments contain periods. See both usages in tests/test_discover.py. 244 | for param in dict(kwargs): 245 | if '_lte' in param: 246 | kwargs[param.replace('_lte', '.lte')] = kwargs.pop(param) 247 | if '_gte' in param: 248 | kwargs[param.replace('_gte', '.gte')] = kwargs.pop(param) 249 | 250 | path = self._get_path('tv') 251 | 252 | response = self._GET(path, kwargs) 253 | self._set_attrs_to_values(response) 254 | return response 255 | -------------------------------------------------------------------------------- /tmdbsimple/account.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.account 5 | ~~~~~~~~~~~~~~~~~~ 6 | This module implements the Account, Authentication, and Lists functionality 7 | of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-10-31. 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley 12 | :license: GPLv3, see LICENSE for more details 13 | """ 14 | 15 | from .base import TMDB 16 | 17 | 18 | class Account(TMDB): 19 | """ 20 | Account functionality. 21 | 22 | See: https://developers.themoviedb.org/3/account 23 | https://www.themoviedb.org/documentation/api/sessions 24 | """ 25 | BASE_PATH = 'account' 26 | URLS = { 27 | 'info': '', 28 | 'lists': '/{id}/lists', 29 | 'favorite_movies': '/{id}/favorite/movies', 30 | 'favorite_tv': '/{id}/favorite/tv', 31 | 'favorite': '/{id}/favorite', 32 | 'rated_movies': '/{id}/rated/movies', 33 | 'rated_tv': '/{id}/rated/tv', 34 | 'rated_tv_episodes': '/{id}/rated/tv/episodes', 35 | 'watchlist_movies': '/{id}/watchlist/movies', 36 | 'watchlist_tv': '/{id}/watchlist/tv', 37 | 'watchlist': '/{id}/watchlist', 38 | } 39 | 40 | def __init__(self, session_id): 41 | super(Account, self).__init__() 42 | self.session_id = session_id 43 | 44 | def info(self, **kwargs): 45 | """ 46 | Get your account details. 47 | 48 | Args: 49 | 50 | Returns: 51 | A dict respresentation of the JSON returned from the API. 52 | """ 53 | path = self._get_path('info') 54 | kwargs.update({'session_id': self.session_id}) 55 | 56 | response = self._GET(path, kwargs) 57 | self.id = response['id'] 58 | self._set_attrs_to_values(response) 59 | return response 60 | 61 | def lists(self, **kwargs): 62 | """ 63 | Get all of the lists created by an account. Will include private lists 64 | if you are the owner. 65 | 66 | Args: 67 | language: (optional) ISO 639-1 code. 68 | page: (optional) Minimum 1, maximum 1000, default 1. 69 | 70 | Returns: 71 | A dict respresentation of the JSON returned from the API. 72 | """ 73 | path = self._get_id_path('lists') 74 | kwargs.update({'session_id': self.session_id}) 75 | 76 | response = self._GET(path, kwargs) 77 | self._set_attrs_to_values(response) 78 | return response 79 | 80 | def favorite_movies(self, **kwargs): 81 | """ 82 | Get the list of your favorite movies. 83 | 84 | Args: 85 | language: (optional) ISO 639-1 code. 86 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 87 | page: (optional) Minimum 1, maximum 1000, default 1. 88 | 89 | Returns: 90 | A dict respresentation of the JSON returned from the API. 91 | """ 92 | path = self._get_id_path('favorite_movies') 93 | kwargs.update({'session_id': self.session_id}) 94 | 95 | response = self._GET(path, kwargs) 96 | self._set_attrs_to_values(response) 97 | return response 98 | 99 | def favorite_tv(self, **kwargs): 100 | """ 101 | Get the list of your favorite TV shows. 102 | 103 | Args: 104 | language: (optional) ISO 639-1 code. 105 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 106 | page: (optional) Minimum 1, maximum 1000, default 1. 107 | 108 | Returns: 109 | A dict respresentation of the JSON returned from the API. 110 | """ 111 | path = self._get_id_path('favorite_tv') 112 | kwargs.update({'session_id': self.session_id}) 113 | 114 | response = self._GET(path, kwargs) 115 | self._set_attrs_to_values(response) 116 | return response 117 | 118 | def favorite(self, **kwargs): 119 | """ 120 | This method allows you to mark a movie or TV show as a favorite item. 121 | 122 | Args: 123 | media_type: 'movie' | 'tv' 124 | media_id: The id of the media. 125 | favorite: True (to add) | False (to remove). 126 | 127 | Returns: 128 | A dict respresentation of the JSON returned from the API. 129 | """ 130 | path = self._get_id_path('favorite') 131 | kwargs.update({'session_id': self.session_id}) 132 | 133 | payload = { 134 | 'media_type': kwargs.pop('media_type', None), 135 | 'media_id': kwargs.pop('media_id', None), 136 | 'favorite': kwargs.pop('favorite', None), 137 | } 138 | 139 | response = self._POST(path, kwargs, payload) 140 | self._set_attrs_to_values(response) 141 | return response 142 | 143 | def rated_movies(self, **kwargs): 144 | """ 145 | Get a list of all the movies you have rated. 146 | 147 | Args: 148 | language: (optional) ISO 639-1 value. 149 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 150 | page: (optional) Minimum 1, maximum 1000, default 1. 151 | 152 | Returns: 153 | A dict respresentation of the JSON returned from the API. 154 | """ 155 | path = self._get_id_path('rated_movies') 156 | kwargs.update({'session_id': self.session_id}) 157 | 158 | response = self._GET(path, kwargs) 159 | self._set_attrs_to_values(response) 160 | return response 161 | 162 | def rated_tv(self, **kwargs): 163 | """ 164 | Get a list of all the TV shows you have rated. 165 | 166 | Args: 167 | language: (optional) ISO 639-1 value. 168 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 169 | page: (optional) Minimum 1, maximum 1000, default 1. 170 | 171 | Returns: 172 | A dict respresentation of the JSON returned from the API. 173 | """ 174 | path = self._get_id_path('rated_tv') 175 | kwargs.update({'session_id': self.session_id}) 176 | 177 | response = self._GET(path, kwargs) 178 | self._set_attrs_to_values(response) 179 | return response 180 | 181 | def rated_tv_episodes(self, **kwargs): 182 | """ 183 | Get a list of all the TV episodes you have rated. 184 | 185 | Args: 186 | language: (optional) ISO 639-1 value. 187 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 188 | page: (optional) Minimum 1, maximum 1000, default 1. 189 | 190 | Returns: 191 | A dict respresentation of the JSON returned from the API. 192 | """ 193 | path = self._get_id_path('rated_tv_episodes') 194 | kwargs.update({'session_id': self.session_id}) 195 | 196 | response = self._GET(path, kwargs) 197 | self._set_attrs_to_values(response) 198 | return response 199 | 200 | def watchlist_movies(self, **kwargs): 201 | """ 202 | Get a list of all the movies you have added to your watchlist. 203 | 204 | Args: 205 | language: (optional) ISO 639-1 value. 206 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 207 | page: (optional) Minimum 1, maximum 1000, default 1. 208 | 209 | Returns: 210 | A dict respresentation of the JSON returned from the API. 211 | """ 212 | path = self._get_id_path('watchlist_movies') 213 | kwargs.update({'session_id': self.session_id}) 214 | 215 | response = self._GET(path, kwargs) 216 | self._set_attrs_to_values(response) 217 | return response 218 | 219 | def watchlist_tv(self, **kwargs): 220 | """ 221 | Get a list of all the TV shows you have added to your watchlist. 222 | 223 | Args: 224 | language: (optional) ISO 639-1 value. 225 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 226 | page: (optional) Minimum 1, maximum 1000, default 1. 227 | 228 | Returns: 229 | A dict respresentation of the JSON returned from the API. 230 | """ 231 | path = self._get_id_path('watchlist_tv') 232 | kwargs.update({'session_id': self.session_id}) 233 | 234 | response = self._GET(path, kwargs) 235 | self._set_attrs_to_values(response) 236 | return response 237 | 238 | def watchlist(self, **kwargs): 239 | """ 240 | Add a movie or TV show to your watchlist. 241 | 242 | Args: 243 | media_type: 'movie' | 'tv' 244 | media_id: The id of the media. 245 | watchlist: True (to add) | False (to remove). 246 | 247 | Returns: 248 | A dict respresentation of the JSON returned from the API. 249 | """ 250 | path = self._get_id_path('watchlist') 251 | kwargs.update({'session_id': self.session_id}) 252 | 253 | payload = { 254 | 'media_type': kwargs.pop('media_type', None), 255 | 'media_id': kwargs.pop('media_id', None), 256 | 'watchlist': kwargs.pop('watchlist', None), 257 | } 258 | 259 | response = self._POST(path, kwargs, payload) 260 | self._set_attrs_to_values(response) 261 | return response 262 | 263 | 264 | class Authentication(TMDB): 265 | """ 266 | Authentication functionality. 267 | 268 | See: https://developers.themoviedb.org/3/authentication 269 | https://www.themoviedb.org/documentation/api/sessions 270 | """ 271 | BASE_PATH = 'authentication' 272 | URLS = { 273 | 'guest_session_new': '/guest_session/new', 274 | 'token_new': '/token/new', 275 | 'session_new': '/session/new', 276 | 'token_validate_with_login': '/token/validate_with_login', 277 | 'session_delete': '/session', 278 | } 279 | 280 | def guest_session_new(self, **kwargs): 281 | """ 282 | This method will let you create a new guest session. Guest sessions 283 | are a type of session that will let a user rate movies and TV shows 284 | but not require them to have a TMDb user account. More 285 | information about user authentication can be found here 286 | (https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id). 287 | 288 | Please note, you should only generate a single guest session per 289 | user (or device) as you will be able to attach the ratings to a 290 | TMDb user account in the future. There is also IP limits in place 291 | so you should always make sure it's the end user doing the guest 292 | session actions. 293 | 294 | If a guest session is not used for the first time within 24 hours, 295 | it will be automatically deleted. 296 | 297 | Args: 298 | 299 | Returns: 300 | A dict respresentation of the JSON returned from the API. 301 | """ 302 | path = self._get_path('guest_session_new') 303 | 304 | response = self._GET(path, kwargs) 305 | self._set_attrs_to_values(response) 306 | return response 307 | 308 | def token_new(self, **kwargs): 309 | """ 310 | Create a temporary request token that can be used to validate a TMDb 311 | user login. More details about how this works can be found here 312 | (https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id). 313 | 314 | Args: 315 | 316 | Returns: 317 | A dict respresentation of the JSON returned from the API. 318 | """ 319 | path = self._get_path('token_new') 320 | 321 | response = self._GET(path, kwargs) 322 | self._set_attrs_to_values(response) 323 | return response 324 | 325 | def session_new(self, **kwargs): 326 | """ 327 | You can use this method to create a fully valid session ID once a user 328 | has validated the request token. More information about how this works 329 | can be found here 330 | (https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id). 331 | 332 | Args: 333 | request_token: The token you generated for the user to approve. 334 | The token needs to be approved before being 335 | used here. 336 | 337 | Returns: 338 | A dict respresentation of the JSON returned from the API. 339 | """ 340 | path = self._get_path('session_new') 341 | 342 | response = self._GET(path, kwargs) 343 | self._set_attrs_to_values(response) 344 | return response 345 | 346 | def token_validate_with_login(self, **kwargs): 347 | """ 348 | This method allows an application to validate a request token by entering 349 | a username and password. 350 | 351 | Not all applications have access to a web view so this can be used as a 352 | substitute. 353 | 354 | Please note, the preferred method of validating a request token is to 355 | have a user authenticate the request via the TMDb website. You can read 356 | about that method here 357 | (https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id). 358 | 359 | If you decide to use this method please use HTTPS. 360 | 361 | Args: 362 | username: The user's username on TMDb. 363 | password: The user's password on TMDb. 364 | request_token: The token you generated for the user to approve. 365 | 366 | Returns: 367 | A dict respresentation of the JSON returned from the API. 368 | """ 369 | path = self._get_path('token_validate_with_login') 370 | 371 | response = self._GET(path, kwargs) 372 | self._set_attrs_to_values(response) 373 | return response 374 | 375 | def session_delete(self, **kwargs): 376 | """ 377 | If you would like to delete (or "logout") from a session, call this 378 | method with a valid session ID. 379 | 380 | Args: 381 | 382 | Returns: 383 | A dict respresentation of the JSON returned from the API. 384 | """ 385 | path = self._get_path('session_delete') 386 | 387 | payload = { 388 | 'session_id': kwargs.pop('session_id', None), 389 | } 390 | 391 | response = self._DELETE(path, kwargs, payload) 392 | self._set_attrs_to_values(response) 393 | return response 394 | 395 | 396 | class GuestSessions(TMDB): 397 | """ 398 | Guest Sessions functionality. 399 | 400 | See: https://developers.themoviedb.org/3/guest-sessions 401 | """ 402 | BASE_PATH = 'guest_session' 403 | URLS = { 404 | 'rated_movies': '/{guest_session_id}/rated/movies', 405 | 'rated_tv': '/{guest_session_id}/rated/tv', 406 | 'rated_tv_episodes': '/{guest_session_id}/rated/tv/episodes', 407 | } 408 | 409 | def __init__(self, guest_session_id=0): 410 | super(GuestSessions, self).__init__() 411 | self.guest_session_id = guest_session_id 412 | 413 | def rated_movies(self, **kwargs): 414 | """ 415 | Get the rated movies for a guest session. 416 | 417 | Args: 418 | language: (optional) ISO 639-1 code. 419 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 420 | 421 | Returns: 422 | A dict respresentation of the JSON returned from the API. 423 | """ 424 | path = self._get_guest_session_id_path('rated_movies') 425 | 426 | response = self._GET(path, kwargs) 427 | self._set_attrs_to_values(response) 428 | return response 429 | 430 | def rated_tv(self, **kwargs): 431 | """ 432 | Get the rated TV shows for a guest session. 433 | 434 | Args: 435 | language: (optional) ISO 639-1 code. 436 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 437 | 438 | Returns: 439 | A dict respresentation of the JSON returned from the API. 440 | """ 441 | path = self._get_guest_session_id_path('rated_tv') 442 | 443 | response = self._GET(path, kwargs) 444 | self._set_attrs_to_values(response) 445 | return response 446 | 447 | def rated_tv_episodes(self, **kwargs): 448 | """ 449 | Get the rated TV episodes for a guest session. 450 | 451 | Args: 452 | language: (optional) ISO 639-1 code. 453 | sort_by: (optional) Allowed Values: created_at.asc, created_at.desc 454 | 455 | Returns: 456 | A dict respresentation of the JSON returned from the API. 457 | """ 458 | path = self._get_guest_session_id_path('rated_tv_episodes') 459 | 460 | response = self._GET(path, kwargs) 461 | self._set_attrs_to_values(response) 462 | return response 463 | 464 | 465 | class Lists(TMDB): 466 | """ 467 | Lists functionality. 468 | 469 | See: https://developers.themoviedb.org/3/lists 470 | """ 471 | BASE_PATH = 'list' 472 | URLS = { 473 | 'info': '/{id}', 474 | 'item_status': '/{id}/item_status', 475 | 'list_create': '', 476 | 'add_item': '/{id}/add_item', 477 | 'remove_item': '/{id}/remove_item', 478 | 'list_clear': '/{id}/clear', 479 | 'list_delete': '/{id}', 480 | } 481 | 482 | def __init__(self, id=0, session_id=0): 483 | super(Lists, self).__init__() 484 | self.id = id 485 | self.session_id = session_id 486 | 487 | def info(self, **kwargs): 488 | """ 489 | Get the details of a list. 490 | 491 | Args: 492 | language: (optional) ISO 639-1 code. 493 | 494 | Returns: 495 | A dict respresentation of the JSON returned from the API. 496 | """ 497 | path = self._get_id_path('info') 498 | 499 | response = self._GET(path, kwargs) 500 | self._set_attrs_to_values(response) 501 | return response 502 | 503 | def item_status(self, **kwargs): 504 | """ 505 | You can use this method to check if a movie has already been added to 506 | the list. 507 | 508 | Args: 509 | movie_id: The id of the movie. Minimum 1. 510 | 511 | Returns: 512 | A dict respresentation of the JSON returned from the API. 513 | """ 514 | path = self._get_id_path('item_status') 515 | 516 | response = self._GET(path, kwargs) 517 | self._set_attrs_to_values(response) 518 | return response 519 | 520 | def list_create(self, **kwargs): 521 | """ 522 | Create a list. 523 | 524 | Args: 525 | name: Name of the list. 526 | description: Description of the list. 527 | language: (optional) ISO 639-1 code. 528 | 529 | Returns: 530 | A dict respresentation of the JSON returned from the API. 531 | """ 532 | path = self._get_path('list_create') 533 | kwargs.update({'session_id': self.session_id}) 534 | 535 | payload = { 536 | 'name': kwargs.pop('name', None), 537 | 'description': kwargs.pop('description', None), 538 | 'language': kwargs.pop('language', None), 539 | } 540 | 541 | response = self._POST(path, kwargs, payload) 542 | self._set_attrs_to_values(response) 543 | self.id = self.list_id 544 | return response 545 | 546 | def add_item(self, **kwargs): 547 | """ 548 | Add a movie to a list. 549 | 550 | Args: 551 | media_id: A movie id. Minimum 1. 552 | 553 | Returns: 554 | A dict respresentation of the JSON returned from the API. 555 | """ 556 | path = self._get_id_path('add_item') 557 | kwargs.update({'session_id': self.session_id}) 558 | 559 | payload = { 560 | 'media_id': kwargs.pop('media_id', None), 561 | } 562 | 563 | response = self._POST(path, kwargs, payload) 564 | self._set_attrs_to_values(response) 565 | return response 566 | 567 | def remove_item(self, **kwargs): 568 | """ 569 | Remove a movie from a list. 570 | 571 | Args: 572 | media_id: A movie id. Minimum 1. 573 | 574 | Returns: 575 | A dict respresentation of the JSON returned from the API. 576 | """ 577 | path = self._get_id_path('remove_item') 578 | kwargs.update({'session_id': self.session_id}) 579 | 580 | payload = { 581 | 'media_id': kwargs.pop('media_id', None), 582 | } 583 | 584 | response = self._POST(path, kwargs, payload) 585 | self._set_attrs_to_values(response) 586 | return response 587 | 588 | def list_clear(self, **kwargs): 589 | """ 590 | Clear all of the items from a list. 591 | 592 | Args: 593 | confirm: True (do it) | False (don't do it) 594 | 595 | Returns: 596 | A dict respresentation of the JSON returned from the API. 597 | """ 598 | path = self._get_id_path('list_clear') 599 | kwargs.update({'session_id': self.session_id}) 600 | 601 | payload = {} 602 | 603 | response = self._POST(path, kwargs, payload) 604 | self._set_attrs_to_values(response) 605 | return response 606 | 607 | def list_delete(self, **kwargs): 608 | """ 609 | Delete a list. 610 | 611 | Args: 612 | None 613 | 614 | Returns: 615 | A dict respresentation of the JSON returned from the API. 616 | """ 617 | path = self._get_id_path('list_delete') 618 | kwargs.update({'session_id': self.session_id}) 619 | 620 | response = self._DELETE(path, kwargs) 621 | self._set_attrs_to_values(response) 622 | return response 623 | -------------------------------------------------------------------------------- /tmdbsimple/movies.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.movies 5 | ~~~~~~~~~~~~~~~~~ 6 | This module implements the Movies, Collections, Companies, Keywords, and 7 | Reviews functionality of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-10-31. 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley 12 | :license: GPLv3, see LICENSE for more details 13 | """ 14 | 15 | from .base import TMDB 16 | 17 | 18 | class Movies(TMDB): 19 | """ 20 | Movies functionality. 21 | 22 | See: https://developers.themoviedb.org/3/movies 23 | """ 24 | BASE_PATH = 'movie' 25 | URLS = { 26 | 'info': '/{id}', 27 | 'account_states': '/{id}/account_states', 28 | 'alternative_titles': '/{id}/alternative_titles', 29 | 'changes': '/{id}/changes', 30 | 'credits': '/{id}/credits', 31 | 'external_ids': '/{id}/external_ids', 32 | 'images': '/{id}/images', 33 | 'keywords': '/{id}/keywords', 34 | 'lists': '/{id}/lists', 35 | 'recommendations': '/{id}/recommendations', 36 | 'release_dates': '/{id}/release_dates', 37 | 'reviews': '/{id}/reviews', 38 | 'similar_movies': '/{id}/similar_movies', 39 | 'translations': '/{id}/translations', 40 | 'videos': '/{id}/videos', 41 | 'watch_providers': '/{id}/watch/providers', 42 | 'rating': '/{id}/rating', 43 | 'rating_delete': '/{id}/rating', 44 | 'latest': '/latest', 45 | 'now_playing': '/now_playing', 46 | 'popular': '/popular', 47 | 'top_rated': '/top_rated', 48 | 'upcoming': '/upcoming', 49 | 'releases': '/{id}/releases', # backward compatability 50 | } 51 | 52 | def __init__(self, id=0): 53 | super(Movies, self).__init__() 54 | self.id = id 55 | 56 | def info(self, **kwargs): 57 | """ 58 | Get the primary information about a movie. 59 | 60 | Supports append_to_response. Read more about this at 61 | https://developers.themoviedb.org/3/getting-started/append-to-response. 62 | 63 | Args: 64 | language: (optional) ISO 639-1 code. 65 | append_to_response: (optional) Append requests within the same 66 | namespace to the response. 67 | 68 | Returns: 69 | A dict representation of the JSON returned from the API. 70 | """ 71 | path = self._get_id_path('info') 72 | 73 | response = self._GET(path, kwargs) 74 | self._set_attrs_to_values(response) 75 | return response 76 | 77 | def account_states(self, **kwargs): 78 | """ 79 | Grab the following account states for a session: 80 | - Movie rating 81 | - If it belongs to your watchlist 82 | - If it belongs to your favourite list 83 | 84 | Args: 85 | session_id: (required) See Authentication. 86 | guest_session_id: (optional) See Authentication. 87 | 88 | Returns: 89 | A dict representation of the JSON returned from the API. 90 | """ 91 | path = self._get_id_path('account_states') 92 | 93 | response = self._GET(path, kwargs) 94 | self._set_attrs_to_values(response) 95 | return response 96 | 97 | def alternative_titles(self, **kwargs): 98 | """ 99 | Get all of the alternative titles for a movie. 100 | 101 | Args: 102 | country: (optional) ISO 3166-1 code. 103 | 104 | Returns: 105 | A dict representation of the JSON returned from the API. 106 | """ 107 | path = self._get_id_path('alternative_titles') 108 | 109 | response = self._GET(path, kwargs) 110 | self._set_attrs_to_values(response) 111 | return response 112 | 113 | def changes(self, **kwargs): 114 | """ 115 | Get the changes for a movie. By default only the last 24 hours are returned. 116 | 117 | You can query up to 14 days in a single query by using the start_date 118 | and end_date query parameters. 119 | 120 | Args: 121 | start_date: (optional) Filter the results with a start date. 122 | Expected format is 'YYYY-MM-DD'. 123 | end_date: (optional) Filter the results with a end date. 124 | Expected format is 'YYYY-MM-DD'. 125 | page: (optional) Minimum 1, maximum 1000, default 1. 126 | 127 | Returns: 128 | A dict representation of the JSON returned from the API. 129 | """ 130 | path = self._get_id_path('changes') 131 | 132 | response = self._GET(path, kwargs) 133 | self._set_attrs_to_values(response) 134 | return response 135 | 136 | def credits(self, **kwargs): 137 | """ 138 | Get the cast and crew for a movie. 139 | 140 | Args: 141 | None 142 | 143 | Returns: 144 | A dict representation of the JSON returned from the API. 145 | """ 146 | path = self._get_id_path('credits') 147 | 148 | response = self._GET(path, kwargs) 149 | self._set_attrs_to_values(response) 150 | return response 151 | 152 | def external_ids(self, **kwargs): 153 | """ 154 | Get the external ids for a movie. We currently support the following 155 | external sources. 156 | 157 | Media Databases - IMDb 158 | Social IDs - Facebok, Instagram, Twitter 159 | 160 | Args: 161 | None 162 | 163 | Returns: 164 | A dict representation of the JSON returned from the API. 165 | """ 166 | path = self._get_id_path('external_ids') 167 | 168 | response = self._GET(path, kwargs) 169 | self._set_attrs_to_values(response) 170 | return response 171 | 172 | def images(self, **kwargs): 173 | """ 174 | Get the images that belong to a movie. 175 | 176 | Querying images with a language parameter will filter the results. If 177 | you want to include a fallback language (especially useful for 178 | backdrops) you can use the include_image_language parameter. This 179 | should be a comma seperated value like so: 180 | include_image_language=en,null. 181 | 182 | Args: 183 | language: (optional) ISO 639-1 code. 184 | include_image_language: (optional) Comma separated, a valid 185 | ISO 69-1. 186 | 187 | Returns: 188 | A dict representation of the JSON returned from the API. 189 | """ 190 | path = self._get_id_path('images') 191 | 192 | response = self._GET(path, kwargs) 193 | self._set_attrs_to_values(response) 194 | return response 195 | 196 | def keywords(self): 197 | """ 198 | Get the keywords that have been added to a movie. 199 | 200 | Args: 201 | None 202 | 203 | Returns: 204 | A dict representation of the JSON returned from the API. 205 | """ 206 | path = self._get_id_path('keywords') 207 | 208 | response = self._GET(path) 209 | self._set_attrs_to_values(response) 210 | return response 211 | 212 | def lists(self, **kwargs): 213 | """ 214 | Get a list of lists that this movie belongs to. 215 | 216 | Args: 217 | language: (optional) ISO 639-1 code. 218 | page: (optional) Minimum 1, maximum 1000, default 1. 219 | 220 | Returns: 221 | A dict representation of the JSON returned from the API. 222 | """ 223 | path = self._get_id_path('lists') 224 | 225 | response = self._GET(path, kwargs) 226 | self._set_attrs_to_values(response) 227 | return response 228 | 229 | def recommendations(self, **kwargs): 230 | """ 231 | Get a list of recommended movies for a movie. 232 | 233 | Args: 234 | language: (optional) ISO 639-1 code. 235 | page: (optional) Minimum 1, maximum 1000, default 1. 236 | 237 | Returns: 238 | A dict representation of the JSON returned from the API. 239 | """ 240 | path = self._get_id_path('recommendations') 241 | 242 | response = self._GET(path, kwargs) 243 | self._set_attrs_to_values(response) 244 | return response 245 | 246 | def release_dates(self, **kwargs): 247 | """ 248 | Get the release date along with the certification for a movie. 249 | 250 | Release dates support different types: 251 | 252 | 1. Premiere 253 | 2. Theatrical (limited) 254 | 3. Theatrical 255 | 4. Digital 256 | 5. Physical 257 | 6. TV 258 | 259 | Args: 260 | None 261 | 262 | Returns: 263 | A dict representation of the JSON returned from the API. 264 | """ 265 | path = self._get_id_path('release_dates') 266 | 267 | response = self._GET(path, kwargs) 268 | self._set_attrs_to_values(response) 269 | return response 270 | 271 | def reviews(self, **kwargs): 272 | """ 273 | Get the user reviews for a movie. 274 | 275 | Args: 276 | language: (optional) ISO 639-1 code. 277 | page: (optional) Minimum 1, maximum 1000, default 1. 278 | 279 | Returns: 280 | A dict representation of the JSON returned from the API. 281 | """ 282 | path = self._get_id_path('reviews') 283 | 284 | response = self._GET(path, kwargs) 285 | self._set_attrs_to_values(response) 286 | return response 287 | 288 | def similar_movies(self, **kwargs): 289 | """ 290 | Get a list of similar movies. This is not the same as the 291 | "Recommendation" system you see on the website. 292 | 293 | These items are assembled by looking at keywords and genres. 294 | 295 | Args: 296 | language: (optional) ISO 639-1 code. 297 | page: (optional) Minimum 1, maximum 1000, default 1. 298 | 299 | Returns: 300 | A dict representation of the JSON returned from the API. 301 | """ 302 | path = self._get_id_path('similar_movies') 303 | 304 | response = self._GET(path, kwargs) 305 | self._set_attrs_to_values(response) 306 | return response 307 | 308 | def translations(self, **kwargs): 309 | """ 310 | Get a list of translations that have been created for a movie. 311 | 312 | Args: 313 | None 314 | 315 | Returns: 316 | A dict representation of the JSON returned from the API. 317 | """ 318 | path = self._get_id_path('translations') 319 | 320 | response = self._GET(path, kwargs) 321 | self._set_attrs_to_values(response) 322 | return response 323 | 324 | def videos(self, **kwargs): 325 | """ 326 | Get the videos that have been added to a movie. 327 | 328 | Args: 329 | language: (optional) ISO 639-1 code. 330 | 331 | Returns: 332 | A dict representation of the JSON returned from the API. 333 | """ 334 | path = self._get_id_path('videos') 335 | 336 | response = self._GET(path, kwargs) 337 | self._set_attrs_to_values(response) 338 | return response 339 | 340 | def watch_providers(self, **kwargs): 341 | """ 342 | Get a list of the availabilities per country by provider for movies. 343 | 344 | Args: 345 | None 346 | 347 | Returns: 348 | A dict representation of the JSON returned from the API. 349 | """ 350 | path = self._get_id_path('watch_providers') 351 | 352 | response = self._GET(path, kwargs) 353 | self._set_attrs_to_values(response) 354 | return response 355 | 356 | def rating(self, **kwargs): 357 | """ 358 | Rate a movie. 359 | 360 | A valid session or guest session ID is required. You can read more 361 | about how this works at 362 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 363 | 364 | Args: 365 | session_id: (optional) See Authentication. 366 | guest_session_id: (optional) See Authentication. 367 | value: (required) This is the value of the rating you want to 368 | submit. The value is expected to be between 0.5 and 10.0. 369 | 370 | Returns: 371 | A dict representation of the JSON returned from the API. 372 | """ 373 | path = self._get_id_path('rating') 374 | 375 | payload = { 376 | 'value': kwargs.pop('value', None), 377 | } 378 | 379 | response = self._POST(path, kwargs, payload) 380 | self._set_attrs_to_values(response) 381 | return response 382 | 383 | def rating_delete(self, **kwargs): 384 | """ 385 | Remove your rating for a movie. 386 | 387 | A valid session or guest session ID is required. You can read more 388 | about how this works at 389 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 390 | 391 | Args: 392 | session_id: (optional) See Authentication. 393 | guest_session_id: (optional) See Authentication. 394 | 395 | Returns: 396 | A dict representation of the JSON returned from the API. 397 | """ 398 | path = self._get_id_path('rating_delete') 399 | 400 | payload = { 401 | 'value': kwargs.pop('value', None), 402 | } 403 | 404 | response = self._DELETE(path, kwargs, payload) 405 | self._set_attrs_to_values(response) 406 | return response 407 | 408 | def latest(self, **kwargs): 409 | """ 410 | Get the most newly created movie. This is a live response and will 411 | continuously change. 412 | 413 | Args: 414 | language: (optional) ISO 639-1 code. 415 | 416 | Returns: 417 | A dict representation of the JSON returned from the API. 418 | """ 419 | path = self._get_path('latest') 420 | 421 | response = self._GET(path, kwargs) 422 | self._set_attrs_to_values(response) 423 | return response 424 | 425 | def now_playing(self, **kwargs): 426 | """ 427 | Get a list of movies in theatres. This is a release type query that 428 | looks for all movies that have a release type of 2 or 3 within the 429 | specified date range. 430 | 431 | You can optionally specify a region prameter which will narrow the 432 | search to only look for theatrical release dates within the specified 433 | country. 434 | 435 | Args: 436 | language: (optional) ISO 639-1 code. 437 | page: (optional) Minimum 1, maximum 1000, default 1. 438 | region: (optional) Specify a ISO 3166-1 code to filter release 439 | dates. Must be uppercase. 440 | 441 | Returns: 442 | A dict representation of the JSON returned from the API. 443 | """ 444 | path = self._get_path('now_playing') 445 | 446 | response = self._GET(path, kwargs) 447 | self._set_attrs_to_values(response) 448 | return response 449 | 450 | def popular(self, **kwargs): 451 | """ 452 | Get a list of the current popular movies on TMDb. This list updates 453 | daily. 454 | 455 | Args: 456 | language: (optional) ISO 639-1 code. 457 | page: (optional) Minimum 1, maximum 1000, default 1. 458 | region: (optional) Specify a ISO 3166-1 code to filter release 459 | dates. Must be uppercase. 460 | 461 | Returns: 462 | A dict representation of the JSON returned from the API. 463 | """ 464 | path = self._get_path('popular') 465 | 466 | response = self._GET(path, kwargs) 467 | self._set_attrs_to_values(response) 468 | return response 469 | 470 | def top_rated(self, **kwargs): 471 | """ 472 | Get the top rated movies on TMDb. 473 | 474 | Args: 475 | language: (optional) ISO 639-1 code. 476 | page: (optional) Minimum 1, maximum 1000, default 1. 477 | region: (optional) Specify a ISO 3166-1 code to filter release 478 | dates. Must be uppercase. 479 | 480 | Returns: 481 | A dict representation of the JSON returned from the API. 482 | """ 483 | path = self._get_path('top_rated') 484 | 485 | response = self._GET(path, kwargs) 486 | self._set_attrs_to_values(response) 487 | return response 488 | 489 | def upcoming(self, **kwargs): 490 | """ 491 | Get a list of upcoming movies in theatres. This is a release type query 492 | that looks for all movies that have a release type of 2 or 3 within the 493 | specified date range. 494 | 495 | You can optionally specify a region prameter which will narrow the 496 | search to only look for theatrical release dates within the specified 497 | country. 498 | 499 | Args: 500 | language: (optional) ISO 639-1 code. 501 | page: (optional) Minimum 1, maximum 1000, default 1. 502 | region: (optional) Specify a ISO 3166-1 code to filter release 503 | dates. Must be uppercase. 504 | 505 | Returns: 506 | A dict representation of the JSON returned from the API. 507 | """ 508 | path = self._get_path('upcoming') 509 | 510 | response = self._GET(path, kwargs) 511 | self._set_attrs_to_values(response) 512 | return response 513 | 514 | # backward compatability 515 | def releases(self, **kwargs): 516 | """ 517 | Get the release date and certification information by country for a 518 | specific movie id. 519 | 520 | Args: 521 | None 522 | 523 | Returns: 524 | A dict representation of the JSON returned from the API. 525 | """ 526 | path = self._get_id_path('releases') 527 | 528 | response = self._GET(path, kwargs) 529 | self._set_attrs_to_values(response) 530 | return response 531 | 532 | 533 | class Collections(TMDB): 534 | """ 535 | Collections functionality. 536 | 537 | See: https://developers.themoviedb.org/3/collections 538 | """ 539 | BASE_PATH = 'collection' 540 | URLS = { 541 | 'info': '/{id}', 542 | 'images': '/{id}/images', 543 | 'translations': '/{id}/translations', 544 | } 545 | 546 | def __init__(self, id): 547 | super(Collections, self).__init__() 548 | self.id = id 549 | 550 | def info(self, **kwargs): 551 | """ 552 | Get collection details by id. 553 | 554 | Args: 555 | language: (optional) ISO 639-1 code. 556 | 557 | Returns: 558 | A dict representation of the JSON returned from the API. 559 | """ 560 | path = self._get_id_path('info') 561 | 562 | response = self._GET(path, kwargs) 563 | self._set_attrs_to_values(response) 564 | return response 565 | 566 | def images(self, **kwargs): 567 | """ 568 | Get the images for a collection by id. 569 | 570 | Args: 571 | language: (optional) ISO 639-1 code. 572 | 573 | Returns: 574 | A dict representation of the JSON returned from the API. 575 | """ 576 | path = self._get_id_path('images') 577 | 578 | response = self._GET(path, kwargs) 579 | self._set_attrs_to_values(response) 580 | return response 581 | 582 | def translations(self, **kwargs): 583 | """ 584 | Get a list of the translations for a collection by id. 585 | 586 | Args: 587 | language: (optional) ISO 639-1 code. 588 | 589 | Returns: 590 | A dict representation of the JSON returned from the API. 591 | """ 592 | path = self._get_id_path('translations') 593 | 594 | response = self._GET(path, kwargs) 595 | self._set_attrs_to_values(response) 596 | return response 597 | 598 | 599 | class Companies(TMDB): 600 | """ 601 | Companies functionality. 602 | 603 | See: https://developers.themoviedb.org/3/companies 604 | """ 605 | BASE_PATH = 'company' 606 | URLS = { 607 | 'info': '/{id}', 608 | 'alternative_names': '/{id}/alternative_names', 609 | 'images': '/{id}/images', 610 | 'movies': '/{id}/movies', # backward compatability 611 | } 612 | 613 | def __init__(self, id=0): 614 | super(Companies, self).__init__() 615 | self.id = id 616 | 617 | def info(self, **kwargs): 618 | """ 619 | Get a companies details by id. 620 | 621 | Args: 622 | 623 | Returns: 624 | A dict representation of the JSON returned from the API. 625 | """ 626 | path = self._get_id_path('info') 627 | 628 | response = self._GET(path, kwargs) 629 | self._set_attrs_to_values(response) 630 | return response 631 | 632 | def alternative_names(self, **kwargs): 633 | """ 634 | Get the alternative names of a company. 635 | 636 | Args: 637 | 638 | Returns: 639 | A dict representation of the JSON returned from the API. 640 | """ 641 | path = self._get_id_path('alternative_names') 642 | 643 | response = self._GET(path, kwargs) 644 | self._set_attrs_to_values(response) 645 | return response 646 | 647 | def images(self, **kwargs): 648 | """ 649 | Get a company's logos by id. 650 | 651 | There are two image formats that are supported for companies, PNG's and 652 | SVG's. You can see which type the original file is by looking at the 653 | file_type field. We prefer SVG's as they are resolution independent and 654 | as such, the width and height are only there to reflect the original 655 | asset that was uploaded. An SVG can be scaled properly beyond those 656 | dimensions if you call them as a PNG. 657 | 658 | For more information about how SVG's and PNG's can be used, take a read 659 | through https://developers.themoviedb.org/3/getting-started/images. 660 | 661 | Args: 662 | 663 | Returns: 664 | A dict representation of the JSON returned from the API. 665 | """ 666 | path = self._get_id_path('images') 667 | 668 | response = self._GET(path, kwargs) 669 | self._set_attrs_to_values(response) 670 | return response 671 | 672 | # backward compatability 673 | def movies(self, **kwargs): 674 | """ 675 | Get the list of movies associated with a particular company. 676 | 677 | Args: 678 | language: (optional) ISO 639-1 code. 679 | page: (optional) Minimum value of 1. Expected value is an integer. 680 | 681 | Returns: 682 | A dict representation of the JSON returned from the API. 683 | """ 684 | path = self._get_id_path('movies') 685 | 686 | response = self._GET(path, kwargs) 687 | self._set_attrs_to_values(response) 688 | return response 689 | 690 | 691 | class Keywords(TMDB): 692 | """ 693 | Keywords functionality. 694 | 695 | See: https://developers.themoviedb.org/3/keywords 696 | """ 697 | BASE_PATH = 'keyword' 698 | URLS = { 699 | 'info': '/{id}', 700 | 'movies': '/{id}/movies', 701 | } 702 | 703 | def __init__(self, id): 704 | super(Keywords, self).__init__() 705 | self.id = id 706 | 707 | def info(self, **kwargs): 708 | """ 709 | Get the details of a keyword. 710 | 711 | Args: 712 | None 713 | 714 | Returns: 715 | A dict representation of the JSON returned from the API. 716 | """ 717 | path = self._get_id_path('info') 718 | 719 | response = self._GET(path, kwargs) 720 | self._set_attrs_to_values(response) 721 | return response 722 | 723 | def movies(self, **kwargs): 724 | """ 725 | Get the movies that belong to a keyword. 726 | 727 | We highly recommend using movie discover instead of this method as it 728 | is much more flexible. 729 | 730 | Args: 731 | language: (optional) ISO 639-1 code. 732 | include_adult: Choose whether to inlcude adult (pornography) 733 | content in the results. 734 | 735 | Returns: 736 | A dict representation of the JSON returned from the API. 737 | """ 738 | path = self._get_id_path('movies') 739 | 740 | response = self._GET(path, kwargs) 741 | self._set_attrs_to_values(response) 742 | return response 743 | 744 | 745 | class Reviews(TMDB): 746 | """ 747 | Reviews functionality. 748 | 749 | See: https://developers.themoviedb.org/3/reviews 750 | """ 751 | BASE_PATH = 'review' 752 | URLS = { 753 | 'info': '/{id}', 754 | } 755 | 756 | def __init__(self, id): 757 | super(Reviews, self).__init__() 758 | self.id = id 759 | 760 | def info(self, **kwargs): 761 | """ 762 | Get the review details by id. 763 | 764 | Args: 765 | None 766 | 767 | Returns: 768 | A dict representation of the JSON returned from the API. 769 | """ 770 | path = self._get_id_path('info') 771 | 772 | response = self._GET(path, kwargs) 773 | self._set_attrs_to_values(response) 774 | return response 775 | -------------------------------------------------------------------------------- /tmdbsimple/tv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tmdbsimple.tv 5 | ~~~~~~~~~~~~~ 6 | This module implements the TV, TV Seasons, TV Episodes, and Networks 7 | functionality of tmdbsimple. 8 | 9 | Created by Celia Oakley on 2013-10-31. 10 | 11 | :copyright: (c) 2013-2025 by Celia Oakley 12 | :license: GPLv3, see LICENSE for more details 13 | """ 14 | 15 | from .base import TMDB 16 | 17 | 18 | class TV(TMDB): 19 | """ 20 | TV functionality. 21 | 22 | See: https://developers.themoviedb.org/3/tv 23 | """ 24 | BASE_PATH = 'tv' 25 | URLS = { 26 | 'info': '/{id}', 27 | 'account_states': '/{id}/account_states', 28 | 'alternative_titles': '/{id}/alternative_titles', 29 | 'content_ratings': '/{id}/content_ratings', 30 | 'credits': '/{id}/credits', 31 | 'episode_groups': '/{id}/episode_groups', 32 | 'external_ids': '/{id}/external_ids', 33 | 'images': '/{id}/images', 34 | 'keywords': '/{id}/keywords', 35 | 'recommendations': '/{id}/recommendations', 36 | 'reviews': '/{id}/reviews', 37 | 'screened_theatrically': '/{id}/screened_theatrically', 38 | 'similar': '/{id}/similar', 39 | 'translations': '/{id}/translations', 40 | 'videos': '/{id}/videos', 41 | 'watch_providers': '/{id}/watch/providers', 42 | 'rating': '/{id}/rating', 43 | 'latest': '/latest', 44 | 'airing_today': '/airing_today', 45 | 'on_the_air': '/on_the_air', 46 | 'popular': '/popular', 47 | 'top_rated': '/top_rated', 48 | } 49 | 50 | def __init__(self, id=0): 51 | super(TV, self).__init__() 52 | self.id = id 53 | 54 | def info(self, **kwargs): 55 | """ 56 | Get the primary TV show details by id. 57 | 58 | Supports append_to_response. Read more about this at 59 | https://developers.themoviedb.org/3/getting-started/append-to-response. 60 | 61 | Args: 62 | language: (optional) ISO 639 code. 63 | append_to_response: (optional) Append requests within the same 64 | namespace to the response. 65 | 66 | Returns: 67 | A dict respresentation of the JSON returned from the API. 68 | """ 69 | path = self._get_id_path('info') 70 | 71 | response = self._GET(path, kwargs) 72 | self._set_attrs_to_values(response) 73 | return response 74 | 75 | def account_states(self, **kwargs): 76 | """ 77 | Grab the following account states for a session: 78 | - TV show rating 79 | - If it belongs to your watchlist 80 | - If it belongs to your favourite list 81 | 82 | Args: 83 | language: (optional) ISO 3166-1 code. 84 | session_id: (required) See Authentication. 85 | guest_session_id: (optional) See Authentication. 86 | 87 | Returns: 88 | A dict respresentation of the JSON returned from the API. 89 | """ 90 | path = self._get_id_path('account_states') 91 | 92 | response = self._GET(path, kwargs) 93 | self._set_attrs_to_values(response) 94 | return response 95 | 96 | def alternative_titles(self, **kwargs): 97 | """ 98 | Returns all of the alternative titles for a TV show. 99 | 100 | Args: 101 | language: (optional) ISO 3166-1 code. 102 | 103 | Returns: 104 | A dict respresentation of the JSON returned from the API. 105 | """ 106 | path = self._get_id_path('alternative_titles') 107 | 108 | response = self._GET(path, kwargs) 109 | self._set_attrs_to_values(response) 110 | return response 111 | 112 | def content_ratings(self, **kwargs): 113 | """ 114 | Get the list of content ratings (certifications) that have been added 115 | to a TV show. 116 | 117 | Args: 118 | language: (optional) ISO 3166-1 code. 119 | 120 | Returns: 121 | A dict respresentation of the JSON returned from the API. 122 | """ 123 | path = self._get_id_path('content_ratings') 124 | 125 | response = self._GET(path, kwargs) 126 | self._set_attrs_to_values(response) 127 | return response 128 | 129 | def credits(self, **kwargs): 130 | """ 131 | Get the credits (cast and crew) that have been added to a TV show. 132 | 133 | Args: 134 | language: (optional) ISO 639 code. 135 | 136 | Returns: 137 | A dict respresentation of the JSON returned from the API. 138 | """ 139 | path = self._get_id_path('credits') 140 | 141 | response = self._GET(path, kwargs) 142 | self._set_attrs_to_values(response) 143 | return response 144 | 145 | def episode_groups(self, **kwargs): 146 | """ 147 | Get all of the episode groups that have been created for a TV show. 148 | With a group ID you can call the get TV episode group details method. 149 | 150 | Args: 151 | language: (optional) ISO 639 code. 152 | 153 | Returns: 154 | A dict respresentation of the JSON returned from the API. 155 | """ 156 | path = self._get_id_path('episode_groups') 157 | 158 | response = self._GET(path, kwargs) 159 | self._set_attrs_to_values(response) 160 | return response 161 | 162 | def external_ids(self, **kwargs): 163 | """ 164 | Get the external ids for a TV show. We currently support the following 165 | external sources. 166 | 167 | Media Databases: IMDb ID, TVDB ID, Freebase MID*, Freebase ID*, TVRage 168 | ID* 169 | Social IDs: Facebook, Instagram, Twitter 170 | 171 | *Defunct or no longer available as a service. 172 | 173 | Args: 174 | language: (optional) ISO 639 code. 175 | 176 | Returns: 177 | A dict respresentation of the JSON returned from the API. 178 | """ 179 | path = self._get_id_path('external_ids') 180 | 181 | response = self._GET(path, kwargs) 182 | self._set_attrs_to_values(response) 183 | return response 184 | 185 | def images(self, **kwargs): 186 | """ 187 | Get the images that belong to a TV show. 188 | 189 | Querying images with a language parameter will filter the results. If 190 | you want to include a fallback language (especially useful for 191 | backdrops) you can use the include_image_language parameter. This 192 | should be a comma seperated value like so: 193 | include_image_language=en,null. 194 | 195 | Args: 196 | language: (optional) ISO 639 code. 197 | 198 | Returns: 199 | A dict respresentation of the JSON returned from the API. 200 | """ 201 | path = self._get_id_path('images') 202 | 203 | response = self._GET(path, kwargs) 204 | self._set_attrs_to_values(response) 205 | return response 206 | 207 | def keywords(self, **kwargs): 208 | """ 209 | Get the keywords that have been added to a TV show. 210 | 211 | Args: 212 | None 213 | 214 | Returns: 215 | A dict respresentation of the JSON returned from the API. 216 | """ 217 | path = self._get_id_path('keywords') 218 | 219 | response = self._GET(path, kwargs) 220 | self._set_attrs_to_values(response) 221 | return response 222 | 223 | def recommendations(self, **kwargs): 224 | """ 225 | Get the list of TV show recommendations for this item. 226 | 227 | Args: 228 | language: (optional) ISO 639-1 code. 229 | page: (optional) Minimum 1, maximum 1000, default 1. 230 | 231 | Returns: 232 | A dict respresentation of the JSON returned from the API. 233 | """ 234 | path = self._get_id_path('recommendations') 235 | 236 | response = self._GET(path, kwargs) 237 | self._set_attrs_to_values(response) 238 | return response 239 | 240 | def reviews(self, **kwargs): 241 | """ 242 | Get the reviews for a TV show. 243 | 244 | Args: 245 | language: (optional) ISO 639-1 code. 246 | page: (optional) Minimum 1, maximum 1000, default 1. 247 | 248 | Returns: 249 | A dict respresentation of the JSON returned from the API. 250 | """ 251 | path = self._get_id_path('reviews') 252 | 253 | response = self._GET(path, kwargs) 254 | self._set_attrs_to_values(response) 255 | return response 256 | 257 | def screened_theatrically(self, **kwargs): 258 | """ 259 | Get a list of seasons or episodes that have been screened in a film 260 | festival or theatre. 261 | 262 | Args: 263 | None 264 | 265 | Returns: 266 | A dict respresentation of the JSON returned from the API. 267 | """ 268 | path = self._get_id_path('screened_theatrically') 269 | 270 | response = self._GET(path, kwargs) 271 | self._set_attrs_to_values(response) 272 | return response 273 | 274 | def similar(self, **kwargs): 275 | """ 276 | Get a list of similar TV shows. These items are assembled by looking at 277 | keywords and genres. 278 | 279 | Args: 280 | language: (optional) ISO 639-1 code. 281 | page: (optional) Minimum 1, maximum 1000, default 1. 282 | 283 | Returns: 284 | A dict respresentation of the JSON returned from the API. 285 | """ 286 | path = self._get_id_path('similar') 287 | 288 | response = self._GET(path, kwargs) 289 | self._set_attrs_to_values(response) 290 | return response 291 | 292 | def translations(self, **kwargs): 293 | """ 294 | Get a list of the translations that exist for a TV show. 295 | 296 | Args: 297 | None 298 | 299 | Returns: 300 | A dict respresentation of the JSON returned from the API. 301 | """ 302 | path = self._get_id_path('translations') 303 | 304 | response = self._GET(path, kwargs) 305 | self._set_attrs_to_values(response) 306 | return response 307 | 308 | def videos(self, **kwargs): 309 | """ 310 | Get the videos that have been added to a TV show. 311 | 312 | Args: 313 | language: (optional) ISO 639 code. 314 | 315 | Returns: 316 | A dict respresentation of the JSON returned from the API. 317 | """ 318 | path = self._get_id_path('videos') 319 | 320 | response = self._GET(path, kwargs) 321 | self._set_attrs_to_values(response) 322 | return response 323 | 324 | def watch_providers(self, **kwargs): 325 | """ 326 | Get a list of the availabilities per country by provider for tv. 327 | 328 | Args: 329 | None 330 | 331 | Returns: 332 | A dict respresentation of the JSON returned from the API. 333 | """ 334 | path = self._get_id_path('watch_providers') 335 | 336 | response = self._GET(path, kwargs) 337 | self._set_attrs_to_values(response) 338 | 339 | def rating(self, **kwargs): 340 | """ 341 | Rate a TV show. 342 | 343 | A valid session or guest session ID is required. You can read more 344 | about how this works at 345 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 346 | 347 | Args: 348 | session_id: (optional) See Authentication. 349 | guest_session_id: (optional) See Authentication. 350 | value: (required) This is the value of the rating you want to 351 | submit. The value is expected to be between 0.5 and 10.0. 352 | 353 | Returns: 354 | A dict respresentation of the JSON returned from the API. 355 | """ 356 | path = self._get_id_path('rating') 357 | 358 | payload = { 359 | 'value': kwargs.pop('value', None), 360 | } 361 | 362 | response = self._POST(path, kwargs, payload) 363 | self._set_attrs_to_values(response) 364 | return response 365 | 366 | def rating_delete(self, **kwargs): 367 | """ 368 | Remove your rating for a TV show. 369 | 370 | A valid session or guest session ID is required. You can read more 371 | about how this works at 372 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 373 | 374 | Args: 375 | session_id: (optional) See Authentication. 376 | guest_session_id: (optional) See Authentication. 377 | 378 | Returns: 379 | A dict respresentation of the JSON returned from the API. 380 | """ 381 | path = self._get_id_path('rating') 382 | 383 | payload = { 384 | 'value': kwargs.pop('value', None), 385 | } 386 | 387 | response = self._DELETE(path, kwargs, payload) 388 | self._set_attrs_to_values(response) 389 | return response 390 | 391 | def latest(self, **kwargs): 392 | """ 393 | Get the most newly created TV show. This is a live response and will 394 | continuously change. 395 | 396 | Args: 397 | language: (optional) ISO 639 code. 398 | 399 | Returns: 400 | A dict respresentation of the JSON returned from the API. 401 | """ 402 | path = self._get_id_path('latest') 403 | 404 | response = self._GET(path, kwargs) 405 | self._set_attrs_to_values(response) 406 | return response 407 | 408 | def airing_today(self, **kwargs): 409 | """ 410 | Get a list of TV shows that are airing today. This query is purely day 411 | based as we do not currently support airing times. 412 | 413 | You can specify a timezone to offset the day calculation. Without a 414 | specified timezone, this query defaults to EST (Eastern Time 415 | UTC-05:00). 416 | 417 | Args: 418 | language: (optional) ISO 639 code. 419 | page: (optional) Minimum 1, maximum 1000, default 1. 420 | 421 | Returns: 422 | A dict respresentation of the JSON returned from the API. 423 | """ 424 | path = self._get_path('airing_today') 425 | 426 | response = self._GET(path, kwargs) 427 | self._set_attrs_to_values(response) 428 | return response 429 | 430 | def on_the_air(self, **kwargs): 431 | """ 432 | Get a list of shows that are currently on the air. 433 | 434 | This query looks for any TV show that has an episode with an air date 435 | in the next 7 days. 436 | 437 | Args: 438 | language: (optional) ISO 639 code. 439 | page: (optional) Minimum 1, maximum 1000, default 1. 440 | 441 | Returns: 442 | A dict respresentation of the JSON returned from the API. 443 | """ 444 | path = self._get_path('on_the_air') 445 | 446 | response = self._GET(path, kwargs) 447 | self._set_attrs_to_values(response) 448 | return response 449 | 450 | def popular(self, **kwargs): 451 | """ 452 | Get a list of the current popular TV shows on TMDb. This list updates 453 | daily. 454 | 455 | Args: 456 | language: (optional) ISO 639 code. 457 | page: (optional) Minimum 1, maximum 1000, default 1. 458 | 459 | Returns: 460 | A dict respresentation of the JSON returned from the API. 461 | """ 462 | path = self._get_path('popular') 463 | 464 | response = self._GET(path, kwargs) 465 | self._set_attrs_to_values(response) 466 | return response 467 | 468 | def top_rated(self, **kwargs): 469 | """ 470 | Get a list of the top rated TV shows on TMDb. 471 | 472 | Args: 473 | language: (optional) ISO 639 code. 474 | page: (optional) Minimum 1, maximum 1000, default 1. 475 | 476 | Returns: 477 | A dict respresentation of the JSON returned from the API. 478 | """ 479 | path = self._get_path('top_rated') 480 | 481 | response = self._GET(path, kwargs) 482 | self._set_attrs_to_values(response) 483 | return response 484 | 485 | 486 | class TV_Seasons(TMDB): 487 | """ 488 | TV Seasons functionality. 489 | 490 | See: https://developers.themoviedb.org/3/tv-seasons 491 | """ 492 | BASE_PATH = 'tv/{tv_id}/season/{season_number}' 493 | URLS = { 494 | 'info': '', 495 | 'account_states': '/account_states', 496 | 'credits': '/credits', 497 | 'external_ids': '/external_ids', 498 | 'images': '/images', 499 | 'videos': '/videos', 500 | } 501 | 502 | def __init__(self, tv_id, season_number): 503 | super(TV_Seasons, self).__init__() 504 | self.tv_id = tv_id 505 | self.season_number = season_number 506 | 507 | def info(self, **kwargs): 508 | """ 509 | Get the TV season details by id. 510 | 511 | Supports append_to_response. Read more about this at 512 | https://developers.themoviedb.org/3/getting-started/append-to-response. 513 | 514 | Args: 515 | language: (optional) ISO 639 code. 516 | append_to_response: (optional) Append requests within the same 517 | namespace to the response. 518 | 519 | Returns: 520 | A dict respresentation of the JSON returned from the API. 521 | """ 522 | path = self._get_tv_id_season_number_path('info') 523 | 524 | response = self._GET(path, kwargs) 525 | self._set_attrs_to_values(response) 526 | return response 527 | 528 | def account_states(self, **kwargs): 529 | """ 530 | Returns all of the user ratings for the season's episodes. 531 | 532 | Args: 533 | language: (optional) ISO 639 code. 534 | session_id: (required) See Authentication. 535 | guest_session_id: (optional) See Authentication. 536 | 537 | Returns: 538 | A dict respresentation of the JSON returned from the API. 539 | """ 540 | path = self._get_tv_id_season_number_path('account_states') 541 | 542 | response = self._GET(path, kwargs) 543 | self._set_attrs_to_values(response) 544 | return response 545 | 546 | def credits(self, **kwargs): 547 | """ 548 | Get the credits for TV season. 549 | 550 | Args: 551 | language: (optional) ISO 639 code. 552 | 553 | Returns: 554 | A dict respresentation of the JSON returned from the API. 555 | """ 556 | path = self._get_tv_id_season_number_path('credits') 557 | 558 | response = self._GET(path, kwargs) 559 | self._set_attrs_to_values(response) 560 | return response 561 | 562 | def external_ids(self, **kwargs): 563 | """ 564 | Get the external ids for a TV season. We currently support the 565 | following external sources. 566 | 567 | Media Databases: TVDB ID, Freebase MID*, Freebase ID*, TVRage ID* 568 | 569 | *Defunct or no longer available as a service. 570 | 571 | Args: 572 | language: (optional) ISO 639 code. 573 | 574 | Returns: 575 | A dict respresentation of the JSON returned from the API. 576 | """ 577 | path = self._get_tv_id_season_number_path('external_ids') 578 | 579 | response = self._GET(path, kwargs) 580 | self._set_attrs_to_values(response) 581 | return response 582 | 583 | def images(self, **kwargs): 584 | """ 585 | Get the images that belong to a TV season. 586 | 587 | Querying images with a language parameter will filter the results. If 588 | you want to include a fallback language (especially useful for 589 | backdrops) you can use the include_image_language parameter. This 590 | should be a comma seperated value like so: 591 | include_image_language=en,null. 592 | 593 | Args: 594 | language: (optional) ISO 639 code. 595 | 596 | Returns: 597 | A dict respresentation of the JSON returned from the API. 598 | """ 599 | path = self._get_tv_id_season_number_path('images') 600 | 601 | response = self._GET(path, kwargs) 602 | self._set_attrs_to_values(response) 603 | return response 604 | 605 | def videos(self, **kwargs): 606 | """ 607 | Get the videos that have been added to a TV season. 608 | 609 | Args: 610 | language: (optional) ISO 639 code. 611 | 612 | Returns: 613 | A dict respresentation of the JSON returned from the API. 614 | """ 615 | path = self._get_tv_id_season_number_path('videos') 616 | 617 | response = self._GET(path, kwargs) 618 | self._set_attrs_to_values(response) 619 | return response 620 | 621 | 622 | class TV_Episodes(TMDB): 623 | """ 624 | TV Episodes functionality. 625 | 626 | See: https://developers.themoviedb.org/3/tv-episodes 627 | """ 628 | BASE_PATH = 'tv/{tv_id}/season/{season_number}/episode/{episode_number}' 629 | URLS = { 630 | 'info': '', 631 | 'account_states': '/account_states', 632 | 'credits': '/credits', 633 | 'external_ids': '/external_ids', 634 | 'images': '/images', 635 | 'translations': '/translations', 636 | 'rating': '/rating', 637 | 'videos': '/videos', 638 | } 639 | 640 | def __init__(self, tv_id, season_number, episode_number): 641 | super(TV_Episodes, self).__init__() 642 | self.tv_id = tv_id 643 | self.season_number = season_number 644 | self.episode_number = episode_number 645 | 646 | def info(self, **kwargs): 647 | """ 648 | Get the TV episode details by id. 649 | 650 | Supports append_to_response. Read more about this at 651 | https://developers.themoviedb.org/3/getting-started/append-to-response. 652 | 653 | Args: 654 | language: (optional) ISO 639 code. 655 | append_to_response: (optional) Append requests within the same 656 | namespace to the response. 657 | 658 | Returns: 659 | A dict respresentation of the JSON returned from the API. 660 | """ 661 | path = self._get_tv_id_season_number_episode_number_path('info') 662 | 663 | response = self._GET(path, kwargs) 664 | self._set_attrs_to_values(response) 665 | return response 666 | 667 | def account_states(self, **kwargs): 668 | """ 669 | Get your rating for an episode. 670 | 671 | Args: 672 | session_id: (required) See Authentication. 673 | guest_session_id: (optional) See Authentication. 674 | 675 | Returns: 676 | A dict respresentation of the JSON returned from the API. 677 | """ 678 | path = self._get_tv_id_season_number_episode_number_path( 679 | 'account_states') 680 | 681 | response = self._GET(path, kwargs) 682 | self._set_attrs_to_values(response) 683 | return response 684 | 685 | def credits(self, **kwargs): 686 | """ 687 | Get the credits (cast, crew and guest stars) for a TV episode. 688 | 689 | Args: 690 | None 691 | 692 | Returns: 693 | A dict respresentation of the JSON returned from the API. 694 | """ 695 | path = self._get_tv_id_season_number_episode_number_path('credits') 696 | 697 | response = self._GET(path, kwargs) 698 | self._set_attrs_to_values(response) 699 | return response 700 | 701 | def external_ids(self, **kwargs): 702 | """ 703 | Get the external ids for a TV episode. We currently support the 704 | following external sources. 705 | 706 | External Sources: IMDb ID, TVDB ID, Freebase MID*, Freebase ID*, TVRage 707 | ID* 708 | 709 | *Defunct or no longer available as a service. 710 | 711 | Args: 712 | None 713 | 714 | Returns: 715 | A dict respresentation of the JSON returned from the API. 716 | """ 717 | path = self._get_tv_id_season_number_episode_number_path( 718 | 'external_ids') 719 | 720 | response = self._GET(path, kwargs) 721 | self._set_attrs_to_values(response) 722 | return response 723 | 724 | def images(self, **kwargs): 725 | """ 726 | Get the images that belong to a TV episode. 727 | 728 | Querying images with a language parameter will filter the results. If 729 | you want to include a fallback language (especially useful for 730 | backdrops) you can use the include_image_language parameter. This 731 | should be a comma seperated value like so: 732 | include_image_language=en,null. 733 | 734 | Args: 735 | None 736 | 737 | Returns: 738 | A dict respresentation of the JSON returned from the API. 739 | """ 740 | path = self._get_tv_id_season_number_episode_number_path('images') 741 | 742 | response = self._GET(path, kwargs) 743 | self._set_attrs_to_values(response) 744 | return response 745 | 746 | def translations(self, **kwargs): 747 | """ 748 | Get the translation data for an episode. 749 | 750 | Args: 751 | None 752 | 753 | Returns: 754 | A dict respresentation of the JSON returned from the API. 755 | """ 756 | path = self._get_tv_id_season_number_episode_number_path( 757 | 'translations') 758 | 759 | response = self._GET(path, kwargs) 760 | self._set_attrs_to_values(response) 761 | return response 762 | 763 | def rating(self, **kwargs): 764 | """ 765 | Rate a TV episode. 766 | 767 | A valid session or guest session ID is required. You can read more 768 | about how this works at 769 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 770 | 771 | Args: 772 | session_id: (optional) See Authentication. 773 | guest_session_id: (optional) See Authentication. 774 | value: (required) This is the value of the rating you want to 775 | submit. The value is expected to be between 0.5 and 10.0. 776 | 777 | Returns: 778 | A dict respresentation of the JSON returned from the API. 779 | """ 780 | path = self._get_tv_id_season_number_episode_number_path('rating') 781 | 782 | payload = { 783 | 'value': kwargs.pop('value', None), 784 | } 785 | 786 | response = self._POST(path, kwargs, payload) 787 | self._set_attrs_to_values(response) 788 | return response 789 | 790 | def rating_delete(self, **kwargs): 791 | """ 792 | Remove your rating for a TV episode. 793 | 794 | A valid session or guest session ID is required. You can read more 795 | about how this works at 796 | https://developers.themoviedb.org/3/authentication/how-do-i-generate-a-session-id. 797 | 798 | Args: 799 | session_id: (optional) See Authentication. 800 | guest_session_id: (optional) See Authentication. 801 | 802 | Returns: 803 | A dict respresentation of the JSON returned from the API. 804 | """ 805 | path = self._get_tv_id_season_number_episode_number_path('rating') 806 | 807 | payload = { 808 | 'value': kwargs.pop('value', None), 809 | } 810 | 811 | response = self._DELETE(path, kwargs, payload) 812 | self._set_attrs_to_values(response) 813 | return response 814 | 815 | def videos(self, **kwargs): 816 | """ 817 | Get the videos that have been added to a TV episode. 818 | 819 | Args: 820 | language: (optional) ISO 639 code. 821 | 822 | Returns: 823 | A dict respresentation of the JSON returned from the API. 824 | """ 825 | path = self._get_tv_id_season_number_episode_number_path('videos') 826 | 827 | response = self._GET(path, kwargs) 828 | self._set_attrs_to_values(response) 829 | return response 830 | 831 | 832 | class TV_Episode_Groups(TMDB): 833 | """ 834 | TV Episode Groups functionality. 835 | 836 | See: https://developers.themoviedb.org/3/tv-episode-groups 837 | """ 838 | BASE_PATH = 'tv/episode_group' 839 | URLS = { 840 | 'info': '/{id}', 841 | } 842 | 843 | def __init__(self, id): 844 | super(TV_Episode_Groups, self).__init__() 845 | self.id = id 846 | 847 | def info(self, **kwargs): 848 | """ 849 | Get the details of a TV episode group. Groups support 7 different types 850 | which are enumerated as the following: 851 | 1. Original air date 852 | 2. Absolute 853 | 3. DVD 854 | 4. Digital 855 | 5. Story arc 856 | 6. Production 857 | 7. TV 858 | 859 | Args: 860 | language: (optional) ISO 639 code. 861 | 862 | Returns: 863 | A dict respresentation of the JSON returned from the API. 864 | """ 865 | path = self._get_id_path('info') 866 | 867 | response = self._GET(path, kwargs) 868 | self._set_attrs_to_values(response) 869 | return response 870 | 871 | 872 | class TV_Changes(TMDB): 873 | """ 874 | Changes functionality for TV Series, Season and Episode. 875 | 876 | See: https://developers.themoviedb.org/3/tv/get-tv-changes 877 | https://developers.themoviedb.org/3/tv-seasons/get-tv-season-changes 878 | https://developers.themoviedb.org/3/tv-episodes/get-tv-episode-changes 879 | """ 880 | BASE_PATH = 'tv' 881 | URLS = { 882 | 'series': '/{id}/changes', # id => tv_id 883 | 'season': '/season/{id}/changes', # id => season_id 884 | 'episode': '/episode/{id}/changes', # id => episode_id 885 | } 886 | 887 | def __init__(self, id=0): 888 | super(TV_Changes, self).__init__() 889 | self.id = id 890 | 891 | def series(self, **kwargs): 892 | """ 893 | Get the changes for a TV show. By default only the last 24 hours are returned. 894 | 895 | You can query up to 14 days in a single query by using the start_date 896 | and end_date query parameters. 897 | 898 | TV show changes are different than movie changes in that there are some 899 | edits on seasons and episodes that will create a change entry at the 900 | show level. These can be found under the season and episode keys. These 901 | keys will contain a series_id and episode_id. You can use the season 902 | changes and episode changes methods to look these up individually. 903 | 904 | Args: 905 | start_date: (optional) Filter the results with a start date. 906 | Expected format is 'YYYY-MM-DD'. 907 | end_date: (optional) Filter the results with a end date. 908 | Expected format is 'YYYY-MM-DD'. 909 | page: (optional) Minimum 1, maximum 1000, default 1. 910 | 911 | Returns: 912 | A dict respresentation of the JSON returned from the API. 913 | """ 914 | path = self._get_id_path('series') 915 | 916 | response = self._GET(path, kwargs) 917 | self._set_attrs_to_values(response) 918 | return response 919 | 920 | def season(self, **kwargs): 921 | """ 922 | Get the changes for a TV season. By default only the last 24 hours are returned. 923 | 924 | You can query up to 14 days in a single query by using the start_date 925 | and end_date query parameters. 926 | 927 | Args: 928 | start_date: (optional) Filter the results with a start date. 929 | Expected format is 'YYYY-MM-DD'. 930 | end_date: (optional) Filter the results with a end date. 931 | Expected format is 'YYYY-MM-DD'. 932 | page: (optional) Minimum 1, maximum 1000, default 1. 933 | 934 | Returns: 935 | A dict respresentation of the JSON returned from the API. 936 | """ 937 | path = self._get_id_path('season') 938 | 939 | response = self._GET(path, kwargs) 940 | self._set_attrs_to_values(response) 941 | return response 942 | 943 | def episode(self, **kwargs): 944 | """ 945 | Get the changes for a TV episode. By default only the last 24 hours are returned. 946 | 947 | You can query up to 14 days in a single query by using the start_date 948 | and end_date query parameters. 949 | 950 | Args: 951 | start_date: (optional) Filter the results with a start date. 952 | Expected format is 'YYYY-MM-DD'. 953 | end_date: (optional) Filter the results with a end date. 954 | Expected format is 'YYYY-MM-DD'. 955 | page: (optional) Minimum 1, maximum 1000, default 1. 956 | 957 | Returns: 958 | A dict respresentation of the JSON returned from the API. 959 | """ 960 | path = self._get_id_path('episode') 961 | 962 | response = self._GET(path, kwargs) 963 | self._set_attrs_to_values(response) 964 | return response 965 | 966 | 967 | class Networks(TMDB): 968 | """ 969 | Networks functionality. 970 | 971 | See: https://developers.themoviedb.org/3/networks 972 | """ 973 | BASE_PATH = 'network' 974 | URLS = { 975 | 'info': '/{id}', 976 | 'alternative_names': '/{id}/alternative_names', 977 | 'images': '/{id}/images', 978 | } 979 | 980 | def __init__(self, id): 981 | super(Networks, self).__init__() 982 | self.id = id 983 | 984 | def info(self, **kwargs): 985 | """ 986 | Get the details of a network. 987 | 988 | Args: 989 | None 990 | 991 | Returns: 992 | A dict respresentation of the JSON returned from the API. 993 | """ 994 | path = self._get_id_path('info') 995 | 996 | response = self._GET(path, kwargs) 997 | self._set_attrs_to_values(response) 998 | return response 999 | 1000 | def alternative_names(self, **kwargs): 1001 | """ 1002 | Get the alternative names of a network. 1003 | 1004 | Args: 1005 | None 1006 | 1007 | Returns: 1008 | A dict representation of the JSON returned from the API. 1009 | """ 1010 | path = self._get_id_path('alternative_names') 1011 | 1012 | response = self._GET(path, kwargs) 1013 | self._set_attrs_to_values(response) 1014 | return response 1015 | 1016 | def images(self, **kwargs): 1017 | """ 1018 | Get a TV network logos by id. 1019 | 1020 | There are two image formats that are supported for networks, PNG's and 1021 | SVG's. You can see which type the original file is by looking at the 1022 | file_type field. We prefer SVG's as they are resolution independent and 1023 | as such, the width and height are only there to reflect the original 1024 | asset that was uploaded. An SVG can be scaled properly beyond those 1025 | dimensions if you call them as a PNG. 1026 | 1027 | For more information about how SVG's and PNG's can be used, take a read 1028 | through https://developers.themoviedb.org/3/getting-started/images. 1029 | 1030 | Args: 1031 | None 1032 | 1033 | Returns: 1034 | A dict representation of the JSON returned from the API. 1035 | """ 1036 | path = self._get_id_path('images') 1037 | 1038 | response = self._GET(path, kwargs) 1039 | self._set_attrs_to_values(response) 1040 | return response 1041 | --------------------------------------------------------------------------------