simple-justwatch-python-api 0.18.2__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.
@@ -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
+ [![PyPi](https://img.shields.io/pypi/v/simple-justwatch-python-api.svg)](https://pypi.python.org/pypi/simple-justwatch-python-api)
30
+ [![License](https://img.shields.io/pypi/l/simple-justwatch-python-api.svg)](https://pypi.python.org/pypi/simple-justwatch-python-api)
31
+ [![Python versions](https://img.shields.io/pypi/pyversions/simple-justwatch-python-api.svg)](https://pypi.python.org/pypi/simple-justwatch-python-api)
32
+ [![CodeQL](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/codeql.yml/badge.svg)](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/codeql.yml)
33
+ [![Ruff](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/ruff.yml/badge.svg)](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/ruff.yml)
34
+ [![Pytest](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/pytest.yml/badge.svg)](https://github.com/Electronic-Mango/simple-justwatch-python-api/actions/workflows/pytest.yml)
35
+ [![Coverage Status](https://coveralls.io/repos/github/Electronic-Mango/simple-justwatch-python-api/badge.svg?branch=main)](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.
@@ -1,26 +1,28 @@
1
1
  [project]
2
2
  name = "simple-justwatch-python-api"
3
- authors = [{name = "Electronic Mango", email = "78230210+Electronic-Mango@users.noreply.github.com"}]
4
- version = "0.18.2"
5
- description="A simple JustWatch Python API"
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 = {file = "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
- "Topic :: Software Development :: Build Tools",
14
- "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
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
- "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",
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
  ]