simple-justwatch-python-api 0.18.1__tar.gz → 0.19.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simple_justwatch_python_api-0.19.0/LICENSE +21 -0
- simple_justwatch_python_api-0.19.0/PKG-INFO +511 -0
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/README.md +10 -6
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/pyproject.toml +23 -23
- simple_justwatch_python_api-0.18.1/LICENSE +0 -674
- simple_justwatch_python_api-0.18.1/PKG-INFO +0 -1178
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/src/simplejustwatchapi/__init__.py +0 -0
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/src/simplejustwatchapi/graphql.py +0 -0
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/src/simplejustwatchapi/justwatch.py +0 -0
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/src/simplejustwatchapi/query.py +0 -0
- {simple_justwatch_python_api-0.18.1 → simple_justwatch_python_api-0.19.0}/src/simplejustwatchapi/tuples.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Electronic Mango
|
|
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.
|
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simple-justwatch-python-api
|
|
3
|
+
Version: 0.19.0
|
|
4
|
+
Summary: A simple JustWatch Python API
|
|
5
|
+
Keywords: justwatch,api,graphql
|
|
6
|
+
Author: Electronic Mango
|
|
7
|
+
Author-email: Electronic Mango <78230210+Electronic-Mango@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Dist: httpx>=0.28.1
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Project-URL: Homepage, https://github.com/Electronic-Mango/simple-justwatch-python-api
|
|
23
|
+
Project-URL: Documentation, https://electronic-mango.github.io/simple-justwatch-python-api
|
|
24
|
+
Project-URL: Repository, https://github.com/Electronic-Mango/simple-justwatch-python-api
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Simple JustWatch Python API
|
|
28
|
+
|
|
29
|
+
[](https://pypi.python.org/pypi/simple-justwatch-python-api)
|
|
30
|
+
[](https://pypi.python.org/pypi/simple-justwatch-python-api)
|
|
31
|
+
[](https://pypi.python.org/pypi/simple-justwatch-python-api)
|
|
32
|
+
[](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/codeql.yml)
|
|
33
|
+
[](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/ruff.yml)
|
|
34
|
+
[](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/pytest.yml)
|
|
35
|
+
[](https://coveralls.io/github/Electronic-Mango/simple-justwatch-python-api?branch=main)
|
|
36
|
+
|
|
37
|
+
A simple unofficial JustWatch Python API which uses [`GraphQL`](https://graphql.org/) to access JustWatch data, built with [`httpx`](https://www.python-httpx.org/) and `Python3.11`.
|
|
38
|
+
|
|
39
|
+
This project is managed by [uv](https://docs.astral.sh/uv/).
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Table of contents
|
|
44
|
+
|
|
45
|
+
- [Installation](#installation)
|
|
46
|
+
- [Usage](#usage)
|
|
47
|
+
- [Search](#search)
|
|
48
|
+
- [Popular](#popular)
|
|
49
|
+
- [Details](#details)
|
|
50
|
+
- [Seasons](#seasons)
|
|
51
|
+
- [Episodes](#episodes)
|
|
52
|
+
- [Offers for countries](#offers-for-countries)
|
|
53
|
+
- [Providers](#providers)
|
|
54
|
+
- [Data structures](#data-structures)
|
|
55
|
+
- [Locale, language, country](#locale-language-country)
|
|
56
|
+
- [Request complexity](#request-complexity)
|
|
57
|
+
- [Maximum number of entries](#maximum-number-of-entries)
|
|
58
|
+
- [Provider codes](#provider-codes)
|
|
59
|
+
- [`providers` function](#providers-function)
|
|
60
|
+
- [Query parameters from JustWatch](#query-parameters-from-justwatch)
|
|
61
|
+
- [Stored output from other functions with offers](#stored-output-from-other-functions-with-offers)
|
|
62
|
+
- [Disclaimer](#disclaimer)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
Project is available in [PyPi](https://pypi.org/project/simple-justwatch-python-api/):
|
|
68
|
+
```bash
|
|
69
|
+
pip install simple-justwatch-python-api
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
This Python API has multiple functions:
|
|
77
|
+
|
|
78
|
+
- [`search`](#search) - search for entries based on title
|
|
79
|
+
- [`popular`](#popular) - get a list of currently popular titles
|
|
80
|
+
- [`details`](#details) - get details for entry based on its node ID
|
|
81
|
+
- [`seasons`](#seasons) - get information about all seasons of a show
|
|
82
|
+
- [`episodes`](#episodes) - get information about all episodes of a season
|
|
83
|
+
- [`offers_for_countries`](#offers-for-countries) - get offers for entry based on its node ID,
|
|
84
|
+
can look for offers in multiple countries
|
|
85
|
+
- [`providers`](#providers) - get data about available providers (e.g., Netflix)
|
|
86
|
+
|
|
87
|
+
Detailed documentation is available in https://electronic-mango.github.io/simple-justwatch-python-api/.
|
|
88
|
+
|
|
89
|
+
Example outputs from all functions are in [`examples/`](examples/) directory.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### Search
|
|
93
|
+
Search functions allows for searching entries based on a given title.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from simplejustwatchapi import search
|
|
97
|
+
|
|
98
|
+
results = search("title", "US", "en", 5, True, 0, {"nfx", "apv"})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
No arguments are required.
|
|
102
|
+
|
|
103
|
+
| | Argument | Type | Required | Default value | Description |
|
|
104
|
+
|---|-------------|--------|----------|---------------------|--------------------------------------------------------|
|
|
105
|
+
| 1 | `title` | `str` | NO | - | Title to look up |
|
|
106
|
+
| 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
|
|
107
|
+
| 3 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
108
|
+
| 4 | `count` | `int` | NO | `4` | Up to how many entries should be returned |
|
|
109
|
+
| 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
110
|
+
| 6 | `offset` | `int` | NO | `0` | How many titles should be skipped from the output |
|
|
111
|
+
| 7 | `providers` | `list[str] \| str \| None`| NO | `None` | Determines whether only best offers should be returned |
|
|
112
|
+
|
|
113
|
+
`title` is just a string to look up. If empty, or not provided, you'll get a selection of popular titles,
|
|
114
|
+
similar to [`popular`](#popular) function.
|
|
115
|
+
|
|
116
|
+
> **Note**: value of `title` isn't stripped, so passing a string
|
|
117
|
+
with multiple spaces will look them up. For more than 1 space it will (probably) always return an empty list.
|
|
118
|
+
|
|
119
|
+
`country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
|
|
120
|
+
It should be uppercase, however lowercase codes are automatically converted to uppercase.
|
|
121
|
+
|
|
122
|
+
`language` is a **ISO 639-1** (usually) 2-letter code, lowercase, e.g. `en`, `fr`.
|
|
123
|
+
|
|
124
|
+
`count` determines **up to** how many entries should be returned.
|
|
125
|
+
If JustWatch GraphQL API returns fewer entries, then this function will also return fewer values.
|
|
126
|
+
|
|
127
|
+
`best_only` determines whether similar offers, but lower quality should be included in response.
|
|
128
|
+
If a platform offers streaming for a given entry in 4K, HD and SD, then `best_only = True` will return only the 4K offer, `best_only = False` will return all three.
|
|
129
|
+
|
|
130
|
+
`offset` allows for very basic pagination, letting you get more data without running into [request complexity](#request-complexity).
|
|
131
|
+
It simply skips `offset` number of first entries (on the API side, nothing is done inside the library).
|
|
132
|
+
Since there is no session there's no guarantee of results "stability" - if JustWatch decides to
|
|
133
|
+
shuffle returned values (I'm not sure what would be the reason, but in theory it's possible)
|
|
134
|
+
you might get repeats, or missing entries. It's also not possible to get **all** the data,
|
|
135
|
+
only up to 1999, check [Maximum number of entries](#maximum-number-of-entries) for details.
|
|
136
|
+
|
|
137
|
+
`providers` is a selection of (usually) **3-letter** identifiers for a service provider ("Netflix", "Amazon Prime Video", etc.).
|
|
138
|
+
It can be either a list, or (for single providers) a string.
|
|
139
|
+
`None` (used as default) turns off any filtering based on providers.
|
|
140
|
+
You can get the possible values through [`providers`](#providers) function and `short_name` field from returned `OfferPackage` NamedTuples,
|
|
141
|
+
or check [Provider codes](#provider-codes) for more details.
|
|
142
|
+
|
|
143
|
+
Returned value is a list of [`MediaEntry`](#return-data-structures) objects.
|
|
144
|
+
|
|
145
|
+
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [request complexity](#request-complexity).
|
|
146
|
+
|
|
147
|
+
Example function call and its output is in [`examples/search_output.py`](examples/search_output.py).
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### Popular
|
|
151
|
+
Look up all currently popular titles.
|
|
152
|
+
The usage and output will be similar to [`search`](#search), function without any titles specified.
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from simplejustwatchapi import popular
|
|
156
|
+
|
|
157
|
+
results = popular("US", "en", 5, True, 0, {"nfx", "apv"})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
No arguments are required.
|
|
161
|
+
|
|
162
|
+
| | Argument | Type | Required | Default value | Description |
|
|
163
|
+
|---|-------------|--------|----------|---------------------|--------------------------------------------------------|
|
|
164
|
+
| 1 | `country` | `str` | NO | `"US"` | Country to search for titles |
|
|
165
|
+
| 2 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
166
|
+
| 3 | `count` | `int` | NO | `4` | Up to how many entries should be returned |
|
|
167
|
+
| 4 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
168
|
+
| 5 | `offset` | `int` | NO | `0` | How many titles should be skipped from the output |
|
|
169
|
+
| 6 | `providers` | `list[str] \| str \| None`| NO | `None` | Determines whether only best offers should be returned |
|
|
170
|
+
|
|
171
|
+
`country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
|
|
172
|
+
It should be uppercase, however lowercase codes are automatically converted to uppercase.
|
|
173
|
+
|
|
174
|
+
`language` is a **ISO 639-1** (usually) 2-letter code, lowercase, e.g. `en`, `fr`.
|
|
175
|
+
|
|
176
|
+
`count` determines **up to** how many entries should be returned.
|
|
177
|
+
If JustWatch GraphQL API returns fewer entries, then this function will also return fewer values.
|
|
178
|
+
|
|
179
|
+
`best_only` determines whether similar offers, but lower quality should be included in response.
|
|
180
|
+
If a platform offers streaming for a given entry in 4K, HD and SD, then `best_only = True` will return only the 4K offer, `best_only = False` will return all three.
|
|
181
|
+
|
|
182
|
+
`offset` allows for very basic pagination letting you get more data without running into [request complexity](#request-complexity).
|
|
183
|
+
It simply skips first entries (on the API side, nothing is done inside the library).
|
|
184
|
+
Since there is no session there's no guarantee of results "stability" - if JustWatch decides to
|
|
185
|
+
shuffle returned values (I'm not sure what would be the reason, but in theory it's possible)
|
|
186
|
+
you might get repeats, or missing entries. It's also not possible to get **all** the data,
|
|
187
|
+
only up to 2000, check [Maximum number of entries](#maximum-number-of-entries) for details.
|
|
188
|
+
|
|
189
|
+
`providers` is a selection of (usually) **3-letter** identifiers for a service provider ("Netflix", "Amazon Prime Video", etc.).
|
|
190
|
+
It can be either a list, or (for single providers) a string.
|
|
191
|
+
`None` (used as default) turns off any filtering based on providers.
|
|
192
|
+
You can get the possible values through [`providers`](#providers) function and `short_name` field from returned `OfferPackage` NamedTuples,
|
|
193
|
+
or check [Provider codes](#provider-codes) for more details.
|
|
194
|
+
|
|
195
|
+
Returned value is a list of [`MediaEntry`](#return-data-structures) objects.
|
|
196
|
+
|
|
197
|
+
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [request complexity](#request-complexity).
|
|
198
|
+
|
|
199
|
+
Example function call and its output is in [`examples/popular_output.py`](examples/popular_output.py).
|
|
200
|
+
|
|
201
|
+
### Details
|
|
202
|
+
|
|
203
|
+
Details function allows for looking up details for a single entry via its node ID.
|
|
204
|
+
Node ID can be taken from output of the [`search`](#search) function.
|
|
205
|
+
|
|
206
|
+
Output from this function contains the same data as a single entry from the [`search`](#search) function.
|
|
207
|
+
|
|
208
|
+
> **In general using this function is only useful if you have node ID already stored.**
|
|
209
|
+
There's no reason to first use the [`search`](#search) function, then use node ID from one of entries for `details`, you won't get any additional information.
|
|
210
|
+
If you want to get seasons/episodes you can use the ID from [`search`](#search) function to call [`seasons`](#seasons), and then [`episodes`](#episodes). Calling `details` on an individual season/episode won't give you more information than outputs from the dedicated functions.
|
|
211
|
+
|
|
212
|
+
Usage is similar to [`search`](#search) function, just without `count` argument:
|
|
213
|
+
```python
|
|
214
|
+
from simplejustwatchapi import details
|
|
215
|
+
|
|
216
|
+
results = details("nodeID", "US", "en", False)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Only the first argument is required - the node ID of element to look up details for.
|
|
220
|
+
|
|
221
|
+
| | Argument | Type | Required | Default value | Description |
|
|
222
|
+
|---|-------------|--------|----------|---------------|--------------------------------------------------------|
|
|
223
|
+
| 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
|
|
224
|
+
| 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
|
|
225
|
+
| 3 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
226
|
+
| 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
227
|
+
|
|
228
|
+
General usage of these arguments matches the [`search`](#search) function.
|
|
229
|
+
|
|
230
|
+
Returned value is a single [`MediaEntry`](#return-data-structures) object.
|
|
231
|
+
|
|
232
|
+
This function can be used for all types of media - shows, movies, episodes, seasons (the last two having their dedicated functions described below),
|
|
233
|
+
for all types the result is a single [`MediaEntry`](#return-data-structures) object.
|
|
234
|
+
Some fields are specific for one of the media types and will be `None` for others - e.g.:
|
|
235
|
+
- `total_episode_count` is only present for seasons
|
|
236
|
+
- `season_number` is present for seasons and episodes
|
|
237
|
+
- `episode_number` is present only for episodes
|
|
238
|
+
- `age_certification` is present only for movies and shows
|
|
239
|
+
|
|
240
|
+
For episodes specifically most of the fields will be empty (which is why [`episodes`](#episodes) function returns different structure).
|
|
241
|
+
|
|
242
|
+
Example function call and its output is in [`examples/details_output.py`](examples/details_output.py).
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
### Seasons
|
|
246
|
+
|
|
247
|
+
Seasons function allows for looking up all seasons of a show via its node ID.
|
|
248
|
+
Node/show ID can be taken from output of the [`search`](#search) function.
|
|
249
|
+
It's also the same ID as input for [`details`](#details) function.
|
|
250
|
+
|
|
251
|
+
Each season contains similar data to the [`details`](#details) function, with additional season number and number of episodes.
|
|
252
|
+
|
|
253
|
+
Usage also matches [`details`](#details) function:
|
|
254
|
+
```python
|
|
255
|
+
from simplejustwatchapi import seasons
|
|
256
|
+
|
|
257
|
+
results = seasons("nodeID", "US", "en", False)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Only the first argument is required - the node ID of element to look up details for.
|
|
261
|
+
|
|
262
|
+
| | Argument | Type | Required | Default value | Description |
|
|
263
|
+
|---|-------------|--------|----------|---------------|--------------------------------------------------------|
|
|
264
|
+
| 1 | `show_id` | `str` | **YES** | - | Node/show ID to look up |
|
|
265
|
+
| 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
|
|
266
|
+
| 3 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
267
|
+
| 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
268
|
+
|
|
269
|
+
Returned value is a list of [`MediaEntry`](#return-data-structures) objects, each describing a single season.
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
### Episodes
|
|
273
|
+
|
|
274
|
+
Episodes function allows for looking up all episodes of a season via season's node ID.
|
|
275
|
+
Node/season ID can be taken from output of the [`seasons`](#seasons) function.
|
|
276
|
+
|
|
277
|
+
Usage matches [`details`](#details) function:
|
|
278
|
+
```python
|
|
279
|
+
from simplejustwatchapi import seasons
|
|
280
|
+
|
|
281
|
+
results = seasons("nodeID", "US", "en", False)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Only the first argument is required - the node ID of element to look up details for.
|
|
285
|
+
|
|
286
|
+
| | Argument | Type | Required | Default value | Description |
|
|
287
|
+
|---|-------------|--------|----------|---------------|--------------------------------------------------------|
|
|
288
|
+
| 1 | `season_id` | `str` | **YES** | - | Node/season ID to look up |
|
|
289
|
+
| 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
|
|
290
|
+
| 3 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
291
|
+
| 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
292
|
+
|
|
293
|
+
Returned value is a list of [`Episode`](#return-data-structures) objects, each describing a single episode.
|
|
294
|
+
Each contains only a small subset of fields from the [`MediaEntry`](#return-data-structures) object,
|
|
295
|
+
JustWatch API doesn't return "full" data.
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
### Offers for countries
|
|
299
|
+
|
|
300
|
+
This function allows looking up offers for entry by given node ID.
|
|
301
|
+
It allows specifying a set of countries, instead of a single one.
|
|
302
|
+
This way you can simultaneously look up offers for multiple countries.
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
from simplejustwatchapi import offers_for_countries
|
|
306
|
+
|
|
307
|
+
results = offers_for_countries("nodeID", {"US", "UK", "CA"}, "en", True)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
First two arguments are required - node ID, and set of countries.
|
|
311
|
+
|
|
312
|
+
| | Argument | Type | Required | Default value | Description |
|
|
313
|
+
|---|-------------|------------|:---------|---------------|--------------------------------------------------------|
|
|
314
|
+
| 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
|
|
315
|
+
| 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
|
|
316
|
+
| 3 | `language` | `str` | NO | `"en"` | Language of responses |
|
|
317
|
+
| 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
|
|
318
|
+
|
|
319
|
+
Usage of `language` and `best_only` arguments matches the [`search`](#search) function.
|
|
320
|
+
|
|
321
|
+
Returned value `dict[str, list[Offer]]`, where key is country given as argument and value is a list of [`Offer`](#return-data-structures) tuples.
|
|
322
|
+
|
|
323
|
+
Example function call and its output is in [`examples/offers_for_countries_output.py`](examples/offers_for_countries_output.py).
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
### Providers
|
|
327
|
+
|
|
328
|
+
Get all available service providers ("Netflix", "Amazon Prime Video, etc.) for a given country.
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
from simplejustwatchapi import providers
|
|
332
|
+
|
|
333
|
+
results = providers("US")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
| | Argument | Type | Required | Default value | Description |
|
|
337
|
+
|---|-------------|--------|----------|---------------|---------------------------------|
|
|
338
|
+
| 1 | `country` | `str` | NO | `"US"` | Country to search for providers |
|
|
339
|
+
|
|
340
|
+
`country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
|
|
341
|
+
It should be uppercase, however lowercase codes are automatically converted to uppercase.
|
|
342
|
+
|
|
343
|
+
Returned value is a list of `OfferPackage` tuples.
|
|
344
|
+
Initially they were meant to be used for `Offer` in `MediaEntry`/`Episode`, however the data structure
|
|
345
|
+
matches output here, so it's reused.
|
|
346
|
+
|
|
347
|
+
You can use this function to get values for providers for [`search`](#search) and [`popular`](#popular) functions,
|
|
348
|
+
the `short_name` field in returned `OfferPackage` tuples is the exact 3-letter code needed there.
|
|
349
|
+
|
|
350
|
+
Example function call and its output is in [`examples/providers_output.py`](examples/providers_output.py).
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
## Data structures
|
|
355
|
+
|
|
356
|
+
Detailed descriptions of all used data structures are available in the [documentation](https://electronic-mango.github.io/simple-justwatch-python-api/simplejustwatchapi.html#module-simplejustwatchapi.query).
|
|
357
|
+
|
|
358
|
+
The main structure `MediaEntry` contains fields for all media types - movies, shows, seasons, episodes.
|
|
359
|
+
Some fields are specific for one of the media types and will be `None` for others - e.g.:
|
|
360
|
+
- `total_episode_count` is only present for seasons
|
|
361
|
+
- `season_number` is present for seasons and episodes
|
|
362
|
+
- `episode_number` is present only for episodes
|
|
363
|
+
- `age_certification` is present only for movies and shows
|
|
364
|
+
|
|
365
|
+
For episodes specifically most of the fields will be empty (which is why [`episodes`](#episodes) function returns different structure).
|
|
366
|
+
|
|
367
|
+
As [`search`](#search) function can return only movies and shows the episode-specific and season-specific fields will always be `None`,
|
|
368
|
+
but are included in `MediaEntry` so they will be present in output from [`details`](#details) function.
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
## Locale, language, country
|
|
372
|
+
|
|
373
|
+
Languages and countries are configured via ISO standard.
|
|
374
|
+
Countries are following **ISO 3166-1 alpha-2** standard (2-letter codes, uppercase).
|
|
375
|
+
Languages are following **ISO 639-1** standard (usually 2-letter codes, lowercase).
|
|
376
|
+
|
|
377
|
+
Language codes can also be country-specific, e.g. `es-MX` for Mexican Spanish, etc.
|
|
378
|
+
The country part **must** be uppercase.
|
|
379
|
+
|
|
380
|
+
There is a list of supported locales in [JustWatch **REST API** documentation](https://apis.justwatch.com/docs/api/#tips).
|
|
381
|
+
Any combination of those languages and countries should work with this API as well.
|
|
382
|
+
|
|
383
|
+
If you provide unsupported language JustWatch API should default to english.
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
## Request complexity
|
|
388
|
+
|
|
389
|
+
JustWatch API will respond with error on too high request/response complexity - essentially when returned graph would be too large.
|
|
390
|
+
It's the reason for why seasons/episodes data isn't available directly in [`search`](#search), or [`details`](#details) function
|
|
391
|
+
(mostly the former).
|
|
392
|
+
|
|
393
|
+
This issue can still occur for [`search`](#search) with too high `count` value.
|
|
394
|
+
In my tests the limit is around 100 (in the worst case with `best_only=False`).
|
|
395
|
+
It's a lot, but keep it in mind.
|
|
396
|
+
|
|
397
|
+
Using `best_only=True` should alleviate the issue somewhat, so for very large requests I recommend using its default `True` value.
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
## Maximum number of entries
|
|
402
|
+
|
|
403
|
+
The JustWatch API itself won't allow for getting more than 1999 entries, through `count` and `offset`, regardless of request complexity.
|
|
404
|
+
If you try to get the 2000th entry the API (and functions in this libary) will return an empty list.
|
|
405
|
+
|
|
406
|
+
**If you try to access over the 1999th entry you won't get *up to* 1999 entries, you'll get an empty list.**
|
|
407
|
+
|
|
408
|
+
For example, this will get you entries 1990 - 1999 - a 9 element list of `MediaEntry`, as expected:
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
from simplejustwatchapi import search
|
|
412
|
+
|
|
413
|
+
results = search("title", count=9, offset=1990)
|
|
414
|
+
# len(results) == 9, as expected
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
But trying to get 1990 - 2000 will result in an empty list:
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
from simplejustwatchapi import search
|
|
421
|
+
|
|
422
|
+
results = search("title", count=10, offset=1990)
|
|
423
|
+
# len(results) == 0, API responded with empty list
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Overshooting will also result in an empty list:
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
from simplejustwatchapi import search
|
|
430
|
+
|
|
431
|
+
results = search("title", count=100, offset=1950)
|
|
432
|
+
# len(results) == 0, API responded with empty list
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Interestingly, you'll still hit [too high request complexity](#request-complexity)
|
|
436
|
+
for too high values of `count`, even though you'd get an empty list anyway:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from simplejustwatchapi import search
|
|
440
|
+
|
|
441
|
+
results = search("title", count=200, offset=1950)
|
|
442
|
+
# Errors out due to complexity
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
## Provider codes
|
|
448
|
+
|
|
449
|
+
One note to keep in mind - the codes can be different for different countries.
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
### [`providers`](#providers) function
|
|
453
|
+
|
|
454
|
+
The easiest way of getting all provider codes for filtering in [`search`](#search) and [`popular`](#popular) functions
|
|
455
|
+
is through [`providers`](#providers) function, for example:
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
from simplejustwatchapi import popular, providers
|
|
459
|
+
|
|
460
|
+
codes = [
|
|
461
|
+
package.short_name
|
|
462
|
+
for package
|
|
463
|
+
in providers("GB") # Look up all providers in the UK.
|
|
464
|
+
if package.name in ("Netflix", "Amazon Prime Video") # Only get codes for specific providers
|
|
465
|
+
]
|
|
466
|
+
|
|
467
|
+
# codes == ["nfx", "amp"]
|
|
468
|
+
|
|
469
|
+
# Get popular titles only for selected providers:
|
|
470
|
+
popular_netflix_amazon = popular(providers=codes)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
### Query parameters from JustWatch
|
|
475
|
+
|
|
476
|
+
You can also get them by going to [JustWatch main page](https://www.justwatch.com/)
|
|
477
|
+
and selecting **at least 2** of available services.
|
|
478
|
+
**You need 2**, for 1 you'll get its full name.
|
|
479
|
+
Only for multiple you'll get the needed codes as `?providers=<code1>+<code2>+...` query parameter,
|
|
480
|
+
for example on US version the URL when selecting "Netflix" and "Amazon Prime Video" is:
|
|
481
|
+
|
|
482
|
+
```url
|
|
483
|
+
https://www.justwatch.com/us?providers=nfx,prv
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
So the codes for them are `nfx` and `prv` for the US.
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
### Stored output from other functions with offers
|
|
490
|
+
|
|
491
|
+
The codes are also returned when looking up offers (through pretty much any function aside from `providers`) through `OfferPackage` and its `short_name` field.
|
|
492
|
+
For example, to get a `dict` "**full name**": "**code**" you can:
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
from simplejustwatchapi import search
|
|
496
|
+
|
|
497
|
+
results = search("title", "US", "en", 5, True)
|
|
498
|
+
name_to_code_dict = {
|
|
499
|
+
offer.package.name: offer.package.short_name # Get name and short_name/code from packages
|
|
500
|
+
for entry in results # Iterate all entries
|
|
501
|
+
for offer in entry.offers # Iterate all offers per entry
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
## Disclaimer
|
|
508
|
+
|
|
509
|
+
This API is in no way affiliated, associated, authorized, endorsed by, or in any way officially connected with JustWatch.
|
|
510
|
+
This is an independent and unofficial project.
|
|
511
|
+
Use at your own risk.
|
|
@@ -47,12 +47,16 @@ pip install simple-justwatch-python-api
|
|
|
47
47
|
|
|
48
48
|
## Usage
|
|
49
49
|
|
|
50
|
-
This Python API has
|
|
51
|
-
|
|
52
|
-
- `search` - search for entries based on title
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
55
|
-
|
|
50
|
+
This Python API has multiple functions:
|
|
51
|
+
|
|
52
|
+
- [`search`](#search) - search for entries based on title
|
|
53
|
+
- [`popular`](#popular) - get a list of currently popular titles
|
|
54
|
+
- [`details`](#details) - get details for entry based on its node ID
|
|
55
|
+
- [`seasons`](#seasons) - get information about all seasons of a show
|
|
56
|
+
- [`episodes`](#episodes) - get information about all episodes of a season
|
|
57
|
+
- [`offers_for_countries`](#offers-for-countries) - get offers for entry based on its node ID,
|
|
58
|
+
can look for offers in multiple countries
|
|
59
|
+
- [`providers`](#providers) - get data about available providers (e.g., Netflix)
|
|
56
60
|
|
|
57
61
|
Detailed documentation is available in https://electronic-mango.github.io/simple-justwatch-python-api/.
|
|
58
62
|
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "simple-justwatch-python-api"
|
|
3
|
-
authors = [
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
authors = [
|
|
4
|
+
{ name = "Electronic Mango", email = "78230210+Electronic-Mango@users.noreply.github.com" },
|
|
5
|
+
]
|
|
6
|
+
version = "0.19.0"
|
|
7
|
+
description = "A simple JustWatch Python API"
|
|
6
8
|
readme = "README.md"
|
|
7
|
-
license =
|
|
9
|
+
license = "MIT"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
8
11
|
requires-python = ">= 3.11"
|
|
9
12
|
keywords = ["justwatch", "api", "graphql"]
|
|
10
13
|
classifiers = [
|
|
11
14
|
"Development Status :: 3 - Alpha",
|
|
12
15
|
"Intended Audience :: Developers",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"Programming Language :: Python :: 3",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
16
18
|
"Programming Language :: Python :: 3.11",
|
|
17
19
|
"Programming Language :: Python :: 3.12",
|
|
18
20
|
"Programming Language :: Python :: 3.13",
|
|
19
21
|
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
24
|
]
|
|
21
|
-
dependencies = [
|
|
22
|
-
"httpx>=0.28.1",
|
|
23
|
-
]
|
|
25
|
+
dependencies = ["httpx>=0.28.1"]
|
|
24
26
|
|
|
25
27
|
[dependency-groups]
|
|
26
28
|
dev = [
|
|
@@ -44,9 +46,7 @@ build-backend = "uv_build"
|
|
|
44
46
|
module-name = "simplejustwatchapi"
|
|
45
47
|
|
|
46
48
|
[tool.pytest.ini_options]
|
|
47
|
-
pythonpath = [
|
|
48
|
-
"src", "test"
|
|
49
|
-
]
|
|
49
|
+
pythonpath = ["src", "test"]
|
|
50
50
|
|
|
51
51
|
[tool.ruff]
|
|
52
52
|
line-length = 100
|
|
@@ -55,14 +55,14 @@ line-length = 100
|
|
|
55
55
|
exclude = ["./examples/*", "./docs/*"]
|
|
56
56
|
select = ["ALL"]
|
|
57
57
|
ignore = [
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
"ANN401", # Type hinting JSONs is problematic
|
|
59
|
+
"COM812", # Avoid issues with formatter
|
|
60
|
+
"D203", # Conflicts with D211
|
|
61
|
+
"D212", # Conflicts with D213
|
|
62
|
+
"FBT",
|
|
63
|
+
"FIX002",
|
|
64
|
+
"PLR0913", # I think it makes sense for functions here to have more arguments
|
|
65
|
+
"S101", # Remove once asserts are converted to exceptions
|
|
66
|
+
"TD002",
|
|
67
|
+
"TD003",
|
|
68
68
|
]
|