├── .travis.yml ├── LICENSE ├── README.md ├── api_payload.txt ├── justwatch ├── __init__.py └── justwatchapi.py ├── requirements.txt ├── setup.py └── tests.py /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.6" 4 | cache: pip 5 | install: 6 | - pip install -r requirements.txt 7 | script: 8 | - python3.6 tests.py -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Dawoud Tabboush 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial JustWatch API 2 | [![Build Status](https://travis-ci.com/dawoudt/JustWatchAPI.svg?branch=master)](https://travis-ci.com/dawoudt/JustWatchAPI) 3 | 4 | JustWatch.com Python 3 API 5 | 6 | ## Install 7 | ```bash 8 | python3 -m pip install JustWatch 9 | ``` 10 | 11 | ## Disclaimer 12 | 13 | **This is not the official JustWatch API.** 14 | 15 | The work of many developers went and is still going into the development and maintenance of the data and the API. The main business of JustWatch is to operate a streaming guide with apps for iOS, Android and TV that offers the data for business intelligence and marketing. Therefore it is prohibited to use the API for commercial purposes, meaning all purposes intended for, or directed towards, commercial advantage or monetization by an individual or organization (consumer service, data science, business intelligence etc.). The API may be used for non-commercial purposes such as private projects, but please be respectful with your API calls to prevent an overload on the API. 16 | 17 | JustWatch does not warrant that the API is free of inaccuracies, errors, bugs, malicious code or interruptions or that it is reliable, flawless, complete or otherwise valid. JustWatch does not warrant that the API will meet your requirements, will be available without interruption, or that the results from its use will be accurate or reliable, the quality of the products, services, information or other materials received through the API meets your expectations, and errors regarding the API are corrected. Use of the API is at your sole discretion and risk. You are solely responsible for any damages resulting from your use of the API, including damage to its system or loss of data. JustWatch can disable and change the API at any time without notice and without giving any reason. JustWatch excludes any liability to the extent permitted for direct, indirect or incidental damages, consequential damages, lost profits, quantifiable pecuniary losses arising out of or in connection with the use of the API. 18 | Incorrect or prohibited use of the API, for example for commercial use, may result in a claim for damages by JustWatch. 19 | 20 | If you would like to work with JustWatch and use the official Data API take a look at JustWatch Media and contact us at data-partner@justwatch.com. Currently, JustWatch can only work with bigger partners and clients. JustWatch is also hiring: https://www.justwatch.com/us/talent and has some interesting open source projects on GitHub. 21 | 22 | ## How To 23 | #### search for an item 24 | ```python 25 | from justwatch import JustWatch 26 | 27 | just_watch = JustWatch(country='US') 28 | 29 | results = just_watch.search_for_item(query='the matrix') 30 | ``` 31 | #### or search for combination of genres 32 | ```python 33 | just_watch = JustWatch(genres=['act', 'scf', 'hrr']) 34 | 35 | results_by_genres = just_watch.search_for_item() 36 | ``` 37 | #### or maybe search by provider 38 | ```python 39 | just_watch = JustWatch() 40 | 41 | results_by_providers = just_watch.search_for_item(providers=['nfx', 'stn']) 42 | ``` 43 | 44 | #### or possibly a combination of the above 45 | ```python 46 | just_watch = JustWatch() 47 | 48 | results_by_multiple = just_watch.search_for_item( 49 | providers=['nfx', 'stn'], 50 | content_types=['movie'], 51 | monetization_types=['free']) 52 | ``` 53 | 54 | #### search for a person 55 | ```python 56 | just_watch = JustWatch() 57 | results = just_watch.search_for_item(query="Keanu Reeves", 58 | content_types=['person']) 59 | ``` 60 | 61 | #### search for items of a person 62 | ```python 63 | just_watch = JustWatch() 64 | titles_person = just_watch.search_for_item(person_id=3036) 65 | ``` 66 | 67 | #### get list of genres and codes 68 | ```python 69 | just_watch = JustWatch(country='GB') 70 | genre_details = just_watch.get_genres() 71 | 72 | ``` 73 | 74 | #### get list of providers for a country 75 | ```python 76 | just_watch = JustWatch(country='DE') 77 | provider_details = just_watch.get_providers() 78 | 79 | ``` 80 | 81 | #### get further details on a movie or tv program 82 | 83 | Based on title id found in previous search 84 | 85 | ```python 86 | just_watch = JustWatch(country='GB') 87 | megamind = just_watch.get_title(title_id=103561) 88 | dark = just_watch.get_title(title_id=55668, content_type='show') 89 | 90 | ``` 91 | 92 | #### You can query for title IDs 93 | 94 | ```python 95 | just_watch = JustWatch(country='GB') 96 | the_matrix = just_watch.search_title_id(query='the matrix') 97 | 98 | {'The Matrix': 10, 'The Matrix Revisited': 30701, ...} 99 | 100 | ``` 101 | 102 | #### get further defails on a specific season of a tv program 103 | 104 | `season_id` can be found in the response from get_title of a tv program 105 | 106 | ```python 107 | just_watch = JustWatch(country='GB') 108 | hannibal_season2 = just_watch.get_season(season_id=20236) 109 | 110 | ``` 111 | 112 | #### get country specific certification details 113 | 114 | ```python 115 | just_watch = JustWatch(country='GB') 116 | certs = just_watch.get_certifications() 117 | 118 | ``` 119 | 120 | content_type can be specified but (for GB at least) setting to 'show' gives less detail than the default of 'movie' 121 | 122 | 123 | #### get cinema details 124 | 125 | Setting ```"monetization_types" to "cinema"``` and possibly setting ```nationwide_cinema_releases_only = True``` will return a list of potential showings. 126 | 127 | ```python 128 | just_watch = JustWatch(country='GB') 129 | cinema_showings = just_watch.search_for_item(monetization_types='cinema') 130 | 131 | ``` 132 | 133 | Then based on title_id obtained from that search 134 | 135 | ```python 136 | cinema_times = just_watch.get_cinema_times(title_id=this_title_id, 137 | date='2018-03-24', 138 | latitude=51.5287718, 139 | longitude=-0.2416809, 140 | radius=20000) 141 | ``` 142 | This will return details of all the showings in the area. Details of all the cinemas in the area can be obtained by a call to ```get_cinema_details()```. This takes the same latitutde, longitude and radius parameters as ```get_cinema_times()```, and if a call has already been made they'll be reused. 143 | 144 | ```python 145 | local_cinemas = just_watch.get_cinema_details() 146 | ``` 147 | 148 | You can then join the data from the two calls by joining ```'cinema_id'``` from ```get_cinema_times()``` with ```'id'``` from ```get_cinema_details()``` 149 | 150 | #### get upcoming cinema details 151 | 152 | Call ```get_upcoming_cinema()``` with number of weeks forward or back and whether you only require national releases 153 | 154 | ```python 155 | showings_last_week = just_watch.get_upcoming_cinema(weeks_offset=-1, nationwide_cinema_releases_only=True) 156 | showings_three_weeks = just_watch.get_upcoming_cinema(weeks_offset=3, nationwide_cinema_releases_only=False) 157 | ``` 158 | 159 | #### get person details 160 | 161 | ```python 162 | just_watch = JustWatch() 163 | person_detail = just_watch.get_person_detail(3036) 164 | ``` 165 | 166 | ##### Notes: 167 | * Default country is AU 168 | * `person_id` is a justwatch specific id and does not work with imdb or tmdb ids. 169 | You can get the `person_id` for example from the credits of a title or from search. 170 | 171 | #### Read api_payload.txt for more information 172 | 173 | ## Contributions 174 | ### Contributions are welcome! 175 | Please write unit tests for any new functionality :) 176 | -------------------------------------------------------------------------------- /api_payload.txt: -------------------------------------------------------------------------------- 1 | """ 2 | -- json payload values -- 3 | values can be null (None), or each or all items in corresponding list 4 | "age_certifications": -- null or country specific list 5 | "content_types": -- null or ['movie', 'show'] 6 | "presentation_types": -- null or ['hd', 'sd'] 7 | "providers": -- null or ["mbi", "qfs", "tpl", "msf", "pls", "ply", "itu", "ddi", "crk", "qfx", "prs", "stn", "nfx"] 8 | "genres": -- null or ["act", "ani", "cmy", "crm", "drm", "msc", "hrr", "hst", "fnt", "trl", "war", "wsn", "rma", "scf","doc", "fml", "spt"] 9 | "languages": -- null 10 | "release_year_from": -- null or year > 1900 11 | "release_year_until": -- null or year < current year 12 | "monetization_types": -- null or ["flatrate", "ads", "rent", "buy", "free", "cinema"] 13 | "min_price": -- null or integer value 14 | "max_price": -- null or integer value, 15 | "nationwide_cinema_releases_only": -- null or True or False 16 | "scoring_filter_types": -- null or 17 | { 18 | "imdb:score": 19 | { 20 | "min_scoring_value":0.0,"max_scoring_value":10.0 21 | }, 22 | "tomato:meter": 23 | { 24 | "min_scoring_value":0,"max_scoring_value":100 25 | } 26 | }, 27 | "cinema_release": -- null, 28 | "query": -- null or title as string 29 | "page": --null or integer value 30 | "page_size": --null or integer value 31 | "timeline_type": TBC 32 | } 33 | shortened values 34 | 35 | providers 36 | -- 37 | mbi - mubi 38 | qfs - quickflix store 39 | tpl - tenplay 40 | msf - micrsoft 41 | pls - playstation 42 | ply - google play store 43 | itu - itunes 44 | ddi - dendy direct 45 | crk - crackle 46 | qfx - quickflix 47 | prs - presto 48 | stn - stan 49 | nfx - netflix 50 | 51 | genres 52 | -- 53 | act - action 54 | ani - animation 55 | cmy - comedy 56 | crm - crime 57 | drm - drama 58 | msc - music and musical 59 | hrr - horror 60 | hst - history 61 | fnt - fantasy 62 | trl - mystery and thriller 63 | war - war 64 | wsn - western 65 | rma - romance 66 | scf - scifi 67 | doc - documentary 68 | fml - kids and family 69 | spt - sport 70 | 71 | """ 72 | -------------------------------------------------------------------------------- /justwatch/__init__.py: -------------------------------------------------------------------------------- 1 | from .justwatchapi import JustWatch -------------------------------------------------------------------------------- /justwatch/justwatchapi.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from datetime import timedelta 3 | import requests 4 | import sys 5 | 6 | 7 | HEADER = {'User-Agent':'JustWatch client (github.com/dawoudt/JustWatchAPI)'} 8 | 9 | 10 | class JustWatch: 11 | api_base_template = "https://apis.justwatch.com/content/{path}" 12 | 13 | def __init__(self, country='AU', use_sessions=True, **kwargs): 14 | self.kwargs = kwargs 15 | self.country = country 16 | self.kwargs_cinema = [] 17 | self.requests = requests.Session() if use_sessions else requests 18 | self.locale = self.set_locale() 19 | 20 | 21 | def __del__(self): 22 | ''' Should really use context manager 23 | but this should do without changing functionality. 24 | ''' 25 | if isinstance(self.requests, requests.Session): 26 | self.requests.close() 27 | 28 | 29 | def set_locale(self): 30 | warn = '\nWARN: Unable to locale for {}! Defaulting to en_AU\n' 31 | default_locale = 'en_AU' 32 | path = 'locales/state' 33 | api_url = self.api_base_template.format(path=path) 34 | 35 | r = self.requests.get(api_url, headers=HEADER) 36 | try: 37 | r.raise_for_status() 38 | except requests.exceptions.HTTPError: 39 | sys.stderr.write(warn.format(self.country)) 40 | return default_locale 41 | else: 42 | results = r.json() 43 | 44 | for result in results: 45 | if result['iso_3166_2'] == self.country or \ 46 | result['country'] == self.country: 47 | 48 | return result['full_locale'] 49 | 50 | sys.stderr.write(warn.format(self.country)) 51 | return default_locale 52 | 53 | def search_for_item(self, query=None, **kwargs): 54 | 55 | path = 'titles/{}/popular'.format(self.locale) 56 | api_url = self.api_base_template.format(path=path) 57 | 58 | if kwargs: 59 | self.kwargs = kwargs 60 | if query: 61 | self.kwargs.update({'query': query}) 62 | null = None 63 | payload = { 64 | "age_certifications":null, 65 | "content_types":null, 66 | "presentation_types":null, 67 | "providers":null, 68 | "genres":null, 69 | "languages":null, 70 | "release_year_from":null, 71 | "release_year_until":null, 72 | "monetization_types":null, 73 | "min_price":null, 74 | "max_price":null, 75 | "nationwide_cinema_releases_only":null, 76 | "scoring_filter_types":null, 77 | "cinema_release":null, 78 | "query":null, 79 | "page":null, 80 | "page_size":null, 81 | "timeline_type":null, 82 | "person_id":null 83 | } 84 | for key, value in self.kwargs.items(): 85 | if key in payload.keys(): 86 | payload[key] = value 87 | else: 88 | print('{} is not a valid keyword'.format(key)) 89 | r = self.requests.post(api_url, json=payload, headers=HEADER) 90 | 91 | # Client should deal with rate-limiting. JustWatch may send a 429 Too Many Requests response. 92 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 93 | 94 | return r.json() 95 | 96 | def get_providers(self): 97 | path = 'providers/locale/{}'.format(self.locale) 98 | api_url = self.api_base_template.format(path=path) 99 | r = self.requests.get(api_url, headers=HEADER) 100 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 101 | 102 | return r.json() 103 | 104 | def get_genres(self): 105 | path = 'genres/locale/{}'.format(self.locale) 106 | api_url = self.api_base_template.format(path=path) 107 | r = self.requests.get(api_url, headers=HEADER) 108 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 109 | 110 | return r.json() 111 | 112 | def get_title(self, title_id, content_type='movie'): 113 | path = 'titles/{content_type}/{title_id}/locale/{locale}'.format(content_type=content_type, 114 | title_id=title_id, 115 | locale=self.locale) 116 | 117 | api_url = self.api_base_template.format(path=path) 118 | r = self.requests.get(api_url, headers=HEADER) 119 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 120 | 121 | return r.json() 122 | 123 | def search_title_id(self, query): 124 | ''' Returns a dictionary of titles returned 125 | from search and their respective ID's 126 | 127 | >>> ... 128 | >>> just_watch.get_title_id('The Matrix') 129 | {'The Matrix': 10, ... } 130 | 131 | ''' 132 | 133 | results = self.search_for_item(query) 134 | return {item['id']: item['title'] for item in results['items']} 135 | 136 | 137 | def get_season(self, season_id): 138 | 139 | header = HEADER 140 | api_url = 'https://apis.justwatch.com/content/titles/show_season/{}/locale/{}'.format(season_id, self.locale) 141 | r = self.requests.get(api_url, headers=header) 142 | 143 | # Client should deal with rate-limiting. JustWatch may send a 429 Too Many Requests response. 144 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 145 | 146 | return r.json() 147 | 148 | 149 | def get_episodes(self, show_id, page=''): 150 | ''' Fetches episodes details from the API, based on show_id. 151 | API returns 200 episodes (from newest to oldest) but takes a 'page' param. 152 | ''' 153 | header = HEADER 154 | api_url = 'https://apis.justwatch.com/content/titles/show/{}/locale/{}/newest_episodes'.format(show_id, self.locale) 155 | if page: 156 | api_url += '?page={}'.format(page) 157 | r = self.requests.get(api_url, headers=header) 158 | 159 | # Client should deal with rate-limiting. JustWatch may send a 429 Too Many Requests response. 160 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 161 | 162 | return r.json() 163 | 164 | 165 | def get_cinema_times(self, title_id, content_type = 'movie', **kwargs): 166 | 167 | if kwargs: 168 | self.kwargs_cinema = kwargs 169 | 170 | null = None 171 | payload = { 172 | "date":null, 173 | "latitude":null, 174 | "longitude":null, 175 | "radius":20000 176 | } 177 | for key, value in self.kwargs_cinema.items(): 178 | if key in payload.keys(): 179 | payload[key] = value 180 | else: 181 | print('{} is not a valid keyword'.format(key)) 182 | 183 | 184 | header = HEADER 185 | api_url = 'https://apis.justwatch.com/content/titles/{}/{}/showtimes'.format(content_type, title_id) 186 | r = self.requests.get(api_url, params=payload, headers=header) 187 | 188 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 189 | 190 | return r.json() 191 | 192 | 193 | def get_cinema_details(self, **kwargs): 194 | 195 | if kwargs: 196 | self.kwargs_cinema = kwargs 197 | 198 | null = None 199 | payload = { 200 | "latitude":null, 201 | "longitude":null, 202 | "radius":20000 203 | } 204 | for key, value in self.kwargs_cinema.items(): 205 | if key in payload.keys(): 206 | payload[key] = value 207 | elif key == 'date': 208 | #ignore the date value if passed 209 | pass 210 | else: 211 | print('{} is not a valid keyword'.format(key)) 212 | 213 | 214 | header = HEADER 215 | api_url = 'https://apis.justwatch.com/content/cinemas/{}'.format(self.locale) 216 | r = self.requests.get(api_url, params=payload, headers=header) 217 | 218 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 219 | 220 | return r.json() 221 | 222 | 223 | 224 | def get_upcoming_cinema(self, weeks_offset, nationwide_cinema_releases_only=True): 225 | 226 | header = HEADER 227 | payload = { 'nationwide_cinema_releases_only': nationwide_cinema_releases_only, 228 | 'body': {} } 229 | now_date = datetime.now() 230 | td = timedelta(weeks=weeks_offset) 231 | year_month_day = (now_date + td).isocalendar() 232 | api_url = 'https://apis.justwatch.com/content/titles/movie/upcoming/{}/{}/locale/{}' 233 | api_url = api_url.format(year_month_day[0], year_month_day[1], self.locale) 234 | 235 | #this throws an error if you go too many weeks forward, so return a blank payload if we hit an error 236 | try: 237 | r = self.requests.get(api_url, params=payload, headers=header) 238 | 239 | # Client should deal with rate-limiting. JustWatch may send a 429 Too Many Requests response. 240 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 241 | 242 | return r.json() 243 | except: 244 | return {'page': 0, 'page_size': 0, 'total_pages': 1, 'total_results': 0, 'items': []} 245 | 246 | def get_certifications(self, content_type = 'movie'): 247 | 248 | header = HEADER 249 | payload = { 'country': self.country, 'object_type': content_type } 250 | api_url = 'https://apis.justwatch.com/content/age_certifications' 251 | r = self.requests.get(api_url, params=payload, headers=header) 252 | 253 | # Client should deal with rate-limiting. JustWatch may send a 429 Too Many Requests response. 254 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 255 | 256 | return r.json() 257 | 258 | def get_person_detail(self, person_id): 259 | path = 'titles/person/{person_id}/locale/{locale}'.format(person_id=person_id, locale=self.locale) 260 | api_url = self.api_base_template.format(path=path) 261 | 262 | r = self.requests.get(api_url, headers=HEADER) 263 | r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 264 | 265 | return r.json() 266 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.31.0 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | 2 | desc = """# JustWatchAPI 3 | 4 | JustWatch.com Python 3 API 5 | 6 | How To 7 | ---------------------------------------------------------- 8 | search for an item 9 | ---------------------------------------------------------- 10 | from justwatchapi import JustWatch 11 | 12 | just_watch = JustWatch() 13 | 14 | results = just_watch.search_for_item(query='the matrix') 15 | ---------------------------------------------------------- 16 | or search for combination of genres 17 | ---------------------------------------------------------- 18 | just_watch = JustWatch(genres=['act', 'scf', 'hrr']) 19 | 20 | results_by_genres = just_watch.search_for_item() 21 | ---------------------------------------------------------- 22 | or maybe search by provider 23 | ---------------------------------------------------------- 24 | just_watch = JustWatch() 25 | 26 | results_by_providers = just_watch.search_for_item(providers=['nfx', 'stn']) 27 | ---------------------------------------------------------- 28 | or possibly a combination of the above 29 | ---------------------------------------------------------- 30 | just_watch = JustWatch() 31 | 32 | results_by_multiple = just_watch.search_for_item( 33 | providers=['nfx', 'stn'], 34 | content_types=['movie'], 35 | monetization_types=['free']) 36 | ---------------------------------------------------------- 37 | Read api_payload.txt for more information""" 38 | 39 | import os 40 | from setuptools import setup 41 | 42 | 43 | setup( 44 | name = "JustWatch", 45 | version = "0.5.1", 46 | author = "Dawoud Tabboush", 47 | author_email = "dtabboush@gmail.com", 48 | description = ("A simple api for justwatch.com"), 49 | license = "MIT", 50 | keywords = "movies tv api", 51 | url = "https://github.com/dawoudt/JustWatchAPI", 52 | packages=['justwatch'], 53 | long_description=desc, 54 | platforms='any', 55 | install_requires=[ 56 | 'requests>=2.0' 57 | ], 58 | classifiers=[ 59 | 'Development Status :: 4 - Beta', 60 | 'Intended Audience :: Developers', 61 | 'License :: OSI Approved :: MIT License', 62 | 'Operating System :: OS Independent', 63 | 'Programming Language :: Python', 64 | 'Programming Language :: Python :: 3', 65 | 'Topic :: Software Development :: Libraries :: Python Modules' 66 | ], 67 | ) 68 | -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from justwatch import justwatchapi, JustWatch 3 | from requests.exceptions import HTTPError 4 | 5 | 6 | class TestJustWatchAPI(unittest.TestCase): 7 | def test_header(self): 8 | ''' Assert header has not changed''' 9 | 10 | expected_header = {'User-Agent': 'JustWatch client (github.com/dawoudt/JustWatchAPI)'} 11 | header = justwatchapi.HEADER 12 | self.assertEqual(header, expected_header) 13 | 14 | def test_get(self): 15 | '''Test that we at least don't fail to get a response''' 16 | 17 | just_watch = JustWatch(country='US') 18 | try: 19 | just_watch.search_for_item(query='the matrix', page_size=1) 20 | except Exception as e: 21 | self.fail(f"test_get() failed with Exception: {e}") # noqa 22 | 23 | def test_results_contains_query_item(self): 24 | '''Test that searching for something correctly returns correct results''' 25 | 26 | search_item = 'the matrix' 27 | 28 | just_watch = JustWatch(country='US') 29 | results = just_watch.search_for_item(query=search_item, page_size=1) 30 | first_result_title = results['items'][0]['title'].lower() 31 | 32 | self.assertEqual(search_item, first_result_title) 33 | 34 | def test_locale_defaults_correctly(self): 35 | ''' Test that locale defaults to en_AU ''' 36 | 37 | just_watch = JustWatch(country='NotRealCountry') 38 | self.assertEqual(just_watch.locale, 'en_AU') 39 | res = just_watch.search_for_item(query='the matrix', page_size=1) 40 | self.assertIsNotNone(res) 41 | 42 | def test_locale_works_with_full_country_name(self): 43 | '''Test that full country name can be used to get locale ''' 44 | 45 | just_watch = JustWatch(country='Australia') 46 | self.assertEqual(just_watch.locale, 'en_AU') 47 | res = just_watch.search_for_item(query='the matrix', page_size=1) 48 | self.assertIsNotNone(res) 49 | 50 | def test_get_providers(self): 51 | just_watch = JustWatch(country='US') 52 | prov = just_watch.get_providers() 53 | self.assertIsNotNone(prov) 54 | 55 | def test_get_genres(self): 56 | just_watch = JustWatch(country='US') 57 | genres = just_watch.get_genres() 58 | self.assertIsNotNone(genres) 59 | self.assertGreater(len(genres), 2) 60 | 61 | def test_get_title(self): 62 | the_matrix_title_id = '10' 63 | just_watch = JustWatch() 64 | titles = just_watch.get_title(the_matrix_title_id) 65 | self.assertIsNotNone(titles) 66 | self.assertGreater(len(titles), 0) 67 | 68 | def test_search_title_id(self): 69 | just_watch = JustWatch() 70 | title_ids = just_watch.search_title_id(query='the matrix') 71 | self.assertIn('The Matrix', title_ids.values()) 72 | 73 | def test_person_detail(self): 74 | just_watch = JustWatch() 75 | person_detail = just_watch.get_person_detail(3036) 76 | self.assertIn('Keanu Reeves', person_detail.values()) 77 | 78 | 79 | 80 | if __name__ == '__main__': 81 | unittest.main() 82 | --------------------------------------------------------------------------------