simple-justwatch-python-api 0.14__tar.gz → 0.16__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.
Files changed (15) hide show
  1. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/PKG-INFO +31 -14
  2. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/README.md +30 -13
  3. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/pyproject.toml +1 -1
  4. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/PKG-INFO +31 -14
  5. simple_justwatch_python_api-0.16/src/simplejustwatchapi/main.py +34 -0
  6. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simplejustwatchapi/query.py +188 -2
  7. simple-justwatch-python-api-0.14/src/simplejustwatchapi/main.py +0 -21
  8. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/LICENSE +0 -0
  9. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/setup.cfg +0 -0
  10. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/SOURCES.txt +0 -0
  11. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/dependency_links.txt +0 -0
  12. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/requires.txt +0 -0
  13. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/top_level.txt +0 -0
  14. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simplejustwatchapi/__init__.py +0 -0
  15. {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simplejustwatchapi/justwatch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simple-justwatch-python-api
3
- Version: 0.14
3
+ Version: 0.16
4
4
  Summary: A simple JustWatch Python API
5
5
  Author-email: Electronic Mango <78230210+Electronic-Mango@users.noreply.github.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -715,6 +715,7 @@ A simple unofficial JustWatch Python API which uses [`GraphQL`](https://graphql.
715
715
  * [Details](#details)
716
716
  * [Offers for countries](#offers-for-countries)
717
717
  * [Return data structures](#return-data-structures)
718
+ * [Locale, language, country](#locale-language-country)
718
719
  * [Disclaimer](#disclaimer)
719
720
 
720
721
 
@@ -760,10 +761,10 @@ Only the first argument is required, it specifies a title to search.
760
761
  | 4 | `count` | `int` | NO | `4` | Up to how many entries should be returned |
761
762
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
762
763
 
763
- `country` must be 2-letter code, e.g. `US`, `GB`, `FR`.
764
+ `country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
764
765
  It should be uppercase, however lowercase codes are automatically converted to uppercase.
765
766
 
766
- `language` is also 2-letter code, lowercase, e.g. `en`, `fr`.
767
+ `language` is a **ISO 639-1** (usually) 2-letter code, lowercase, e.g. `en`, `fr`.
767
768
 
768
769
  `count` determines **up to** how many entries should be returned.
769
770
  If JustWatch GraphQL API returns fewer entries, then this function will also return fewer values.
@@ -792,11 +793,11 @@ results = details("nodeID", "US", "en", False)
792
793
 
793
794
  Only the first argument is required - the node ID of element to look up details for.
794
795
 
795
- | | Argument | Type | Required | Default value | Description |
796
- |---|-------------|--------|----------|---------------|-------------------------------------------------------|
797
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
798
- | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
799
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
796
+ | | Argument | Type | Required | Default value | Description |
797
+ |---|-------------|--------|----------|---------------|--------------------------------------------------------|
798
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
799
+ | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
800
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
800
801
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
801
802
 
802
803
  General usage of these arguments matches the [`search`](#search) command.
@@ -821,13 +822,13 @@ results = offers_for_countries("nodeID", {"US", "UK", "CA"}, "en", True)
821
822
  First two arguments are required - node ID, and set of countries.
822
823
 
823
824
  | | Argument | Type | Required | Default value | Description |
824
- |---|-------------|------------|:---------|--------------|--------------------------------------------------------|
825
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
826
- | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
827
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
828
- | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
825
+ |---|-------------|------------|:---------|---------------|--------------------------------------------------------|
826
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
827
+ | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
828
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
829
+ | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
829
830
 
830
- Usage `language` and `best_only` arguments matches the [`search`](#search) command.
831
+ Usage of `language` and `best_only` arguments matches the [`search`](#search) command.
831
832
 
832
833
  Returned value `dict[str, list[Offer]]`, where key is country given as argument and value is a list of [`Offer`](#return-data-structures) tuples.
833
834
 
@@ -841,6 +842,22 @@ Detailed descriptions of all used data structures are available in the [document
841
842
 
842
843
 
843
844
 
845
+ ## Locale, language, country
846
+
847
+ Languages and countries are configured via ISO standard.
848
+ Countries are following **ISO 3166-1 alpha-2** standard (2-letter codes, uppercase).
849
+ Languages are following **ISO 639-1** standard (usually 2-letter codes, lowercase).
850
+
851
+ Language codes can also be country-specific, e.g. `es-MX` for Mexican Spanish, etc.
852
+ The country part **must** be uppercase.
853
+
854
+ There is a list of supported locales in [JustWatch **REST API** documentation](https://apis.justwatch.com/docs/api/#tips).
855
+ Any combination of those languages and countries should work with this API as well.
856
+
857
+ If you provide unsupported language JustWatch API should default to english.
858
+
859
+
860
+
844
861
  ## Disclaimer
845
862
 
846
863
  This API is in no way affiliated, associated, authorized, endorsed by, or in any way officially connected with JustWatch.
@@ -20,6 +20,7 @@ A simple unofficial JustWatch Python API which uses [`GraphQL`](https://graphql.
20
20
  * [Details](#details)
21
21
  * [Offers for countries](#offers-for-countries)
22
22
  * [Return data structures](#return-data-structures)
23
+ * [Locale, language, country](#locale-language-country)
23
24
  * [Disclaimer](#disclaimer)
24
25
 
25
26
 
@@ -65,10 +66,10 @@ Only the first argument is required, it specifies a title to search.
65
66
  | 4 | `count` | `int` | NO | `4` | Up to how many entries should be returned |
66
67
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
67
68
 
68
- `country` must be 2-letter code, e.g. `US`, `GB`, `FR`.
69
+ `country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
69
70
  It should be uppercase, however lowercase codes are automatically converted to uppercase.
70
71
 
71
- `language` is also 2-letter code, lowercase, e.g. `en`, `fr`.
72
+ `language` is a **ISO 639-1** (usually) 2-letter code, lowercase, e.g. `en`, `fr`.
72
73
 
73
74
  `count` determines **up to** how many entries should be returned.
74
75
  If JustWatch GraphQL API returns fewer entries, then this function will also return fewer values.
@@ -97,11 +98,11 @@ results = details("nodeID", "US", "en", False)
97
98
 
98
99
  Only the first argument is required - the node ID of element to look up details for.
99
100
 
100
- | | Argument | Type | Required | Default value | Description |
101
- |---|-------------|--------|----------|---------------|-------------------------------------------------------|
102
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
103
- | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
104
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
101
+ | | Argument | Type | Required | Default value | Description |
102
+ |---|-------------|--------|----------|---------------|--------------------------------------------------------|
103
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
104
+ | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
105
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
105
106
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
106
107
 
107
108
  General usage of these arguments matches the [`search`](#search) command.
@@ -126,13 +127,13 @@ results = offers_for_countries("nodeID", {"US", "UK", "CA"}, "en", True)
126
127
  First two arguments are required - node ID, and set of countries.
127
128
 
128
129
  | | Argument | Type | Required | Default value | Description |
129
- |---|-------------|------------|:---------|--------------|--------------------------------------------------------|
130
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
131
- | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
132
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
133
- | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
130
+ |---|-------------|------------|:---------|---------------|--------------------------------------------------------|
131
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
132
+ | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
133
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
134
+ | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
134
135
 
135
- Usage `language` and `best_only` arguments matches the [`search`](#search) command.
136
+ Usage of `language` and `best_only` arguments matches the [`search`](#search) command.
136
137
 
137
138
  Returned value `dict[str, list[Offer]]`, where key is country given as argument and value is a list of [`Offer`](#return-data-structures) tuples.
138
139
 
@@ -146,6 +147,22 @@ Detailed descriptions of all used data structures are available in the [document
146
147
 
147
148
 
148
149
 
150
+ ## Locale, language, country
151
+
152
+ Languages and countries are configured via ISO standard.
153
+ Countries are following **ISO 3166-1 alpha-2** standard (2-letter codes, uppercase).
154
+ Languages are following **ISO 639-1** standard (usually 2-letter codes, lowercase).
155
+
156
+ Language codes can also be country-specific, e.g. `es-MX` for Mexican Spanish, etc.
157
+ The country part **must** be uppercase.
158
+
159
+ There is a list of supported locales in [JustWatch **REST API** documentation](https://apis.justwatch.com/docs/api/#tips).
160
+ Any combination of those languages and countries should work with this API as well.
161
+
162
+ If you provide unsupported language JustWatch API should default to english.
163
+
164
+
165
+
149
166
  ## Disclaimer
150
167
 
151
168
  This API is in no way affiliated, associated, authorized, endorsed by, or in any way officially connected with JustWatch.
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "simple-justwatch-python-api"
7
7
  authors = [{name = "Electronic Mango", email = "78230210+Electronic-Mango@users.noreply.github.com"}]
8
- version = "0.14"
8
+ version = "0.16"
9
9
  description="A simple JustWatch Python API"
10
10
  readme = "README.md"
11
11
  license = {file = "LICENSE"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simple-justwatch-python-api
3
- Version: 0.14
3
+ Version: 0.16
4
4
  Summary: A simple JustWatch Python API
5
5
  Author-email: Electronic Mango <78230210+Electronic-Mango@users.noreply.github.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -715,6 +715,7 @@ A simple unofficial JustWatch Python API which uses [`GraphQL`](https://graphql.
715
715
  * [Details](#details)
716
716
  * [Offers for countries](#offers-for-countries)
717
717
  * [Return data structures](#return-data-structures)
718
+ * [Locale, language, country](#locale-language-country)
718
719
  * [Disclaimer](#disclaimer)
719
720
 
720
721
 
@@ -760,10 +761,10 @@ Only the first argument is required, it specifies a title to search.
760
761
  | 4 | `count` | `int` | NO | `4` | Up to how many entries should be returned |
761
762
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
762
763
 
763
- `country` must be 2-letter code, e.g. `US`, `GB`, `FR`.
764
+ `country` must be **ISO 3166-1 alpha-2** 2-letter code , e.g. `US`, `GB`, `FR`.
764
765
  It should be uppercase, however lowercase codes are automatically converted to uppercase.
765
766
 
766
- `language` is also 2-letter code, lowercase, e.g. `en`, `fr`.
767
+ `language` is a **ISO 639-1** (usually) 2-letter code, lowercase, e.g. `en`, `fr`.
767
768
 
768
769
  `count` determines **up to** how many entries should be returned.
769
770
  If JustWatch GraphQL API returns fewer entries, then this function will also return fewer values.
@@ -792,11 +793,11 @@ results = details("nodeID", "US", "en", False)
792
793
 
793
794
  Only the first argument is required - the node ID of element to look up details for.
794
795
 
795
- | | Argument | Type | Required | Default value | Description |
796
- |---|-------------|--------|----------|---------------|-------------------------------------------------------|
797
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
798
- | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
799
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
796
+ | | Argument | Type | Required | Default value | Description |
797
+ |---|-------------|--------|----------|---------------|--------------------------------------------------------|
798
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
799
+ | 2 | `country` | `str` | NO | `"US"` | Country to search for offers |
800
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
800
801
  | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
801
802
 
802
803
  General usage of these arguments matches the [`search`](#search) command.
@@ -821,13 +822,13 @@ results = offers_for_countries("nodeID", {"US", "UK", "CA"}, "en", True)
821
822
  First two arguments are required - node ID, and set of countries.
822
823
 
823
824
  | | Argument | Type | Required | Default value | Description |
824
- |---|-------------|------------|:---------|--------------|--------------------------------------------------------|
825
- | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
826
- | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
827
- | 3 | `language` | `str` | NO | `"en"` | Language of responses |
828
- | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
825
+ |---|-------------|------------|:---------|---------------|--------------------------------------------------------|
826
+ | 1 | `node_id` | `str` | **YES** | - | Node ID to look up |
827
+ | 2 | `countries` | `set[str]` | **YES** | - | Set of countries to look up offers for |
828
+ | 3 | `language` | `str` | NO | `"en"` | Language of responses |
829
+ | 5 | `best_only` | `bool` | NO | `True` | Determines whether only best offers should be returned |
829
830
 
830
- Usage `language` and `best_only` arguments matches the [`search`](#search) command.
831
+ Usage of `language` and `best_only` arguments matches the [`search`](#search) command.
831
832
 
832
833
  Returned value `dict[str, list[Offer]]`, where key is country given as argument and value is a list of [`Offer`](#return-data-structures) tuples.
833
834
 
@@ -841,6 +842,22 @@ Detailed descriptions of all used data structures are available in the [document
841
842
 
842
843
 
843
844
 
845
+ ## Locale, language, country
846
+
847
+ Languages and countries are configured via ISO standard.
848
+ Countries are following **ISO 3166-1 alpha-2** standard (2-letter codes, uppercase).
849
+ Languages are following **ISO 639-1** standard (usually 2-letter codes, lowercase).
850
+
851
+ Language codes can also be country-specific, e.g. `es-MX` for Mexican Spanish, etc.
852
+ The country part **must** be uppercase.
853
+
854
+ There is a list of supported locales in [JustWatch **REST API** documentation](https://apis.justwatch.com/docs/api/#tips).
855
+ Any combination of those languages and countries should work with this API as well.
856
+
857
+ If you provide unsupported language JustWatch API should default to english.
858
+
859
+
860
+
844
861
  ## Disclaimer
845
862
 
846
863
  This API is in no way affiliated, associated, authorized, endorsed by, or in any way officially connected with JustWatch.
@@ -0,0 +1,34 @@
1
+ from dataclasses import dataclass
2
+ from itertools import product
3
+
4
+ from justwatch import details, offers_for_countries, search
5
+
6
+
7
+ @dataclass
8
+ class Base:
9
+ base_field_1: int
10
+ base_field_2: int
11
+
12
+
13
+ @dataclass
14
+ class Child(Base):
15
+ child_field_1: int
16
+
17
+
18
+ def main():
19
+ obj = Child(1, 2, 3)
20
+ # result = details("ts4") # Breaking Bad
21
+ # result = details("tss25") # Breaking Bad S5
22
+ # result = details("tse411") # Breaking Bad S5E1
23
+ # result = details("tm10")
24
+ # print(result) # The Matrix
25
+ # result = details("ts20711") # The Simpsons
26
+ # result = details("tm118477") # Haker (2002)
27
+ # result = search("The Simpsons")
28
+ result = search("The Matrix", "US", "en", 3, True)
29
+ print(result)
30
+ print()
31
+
32
+
33
+ if __name__ == "__main__":
34
+ main()
@@ -92,6 +92,7 @@ fragment TitleDetails on MovieOrShow {
92
92
  }
93
93
  externalIds {
94
94
  imdbId
95
+ tmdbId
95
96
  __typename
96
97
  }
97
98
  posterUrl(profile: $profile, format: $formatPoster)
@@ -99,6 +100,40 @@ fragment TitleDetails on MovieOrShow {
99
100
  backdropUrl
100
101
  __typename
101
102
  }
103
+ ageCertification
104
+ scoring {
105
+ imdbScore
106
+ imdbVotes
107
+ tmdbPopularity
108
+ tmdbScore
109
+ tomatoMeter
110
+ certifiedFresh
111
+ jwRating
112
+ __typename
113
+ }
114
+ interactions {
115
+ likelistAdditions
116
+ dislikelistAdditions
117
+ __typename
118
+ }
119
+ __typename
120
+ }
121
+ streamingCharts(country: $country) {
122
+ edges {
123
+ streamingChartInfo {
124
+ rank
125
+ trend
126
+ trendDifference
127
+ daysInTop3
128
+ daysInTop10
129
+ daysInTop100
130
+ daysInTop1000
131
+ topRank
132
+ updatedAt
133
+ __typename
134
+ }
135
+ __typename
136
+ }
102
137
  __typename
103
138
  }
104
139
  offers(country: $country, platform: WEB, filter: $filter) {
@@ -201,7 +236,7 @@ class Offer(NamedTuple):
201
236
  url: str
202
237
  """URL to this offer."""
203
238
 
204
- element_count: int
239
+ element_count: int | None
205
240
  """Element count, usually 0."""
206
241
 
207
242
  available_to: str | None
@@ -223,6 +258,72 @@ class Offer(NamedTuple):
223
258
  """List of 2-letter language codes of available audio tracks, e.g. ``["en", "pt", "de"]``."""
224
259
 
225
260
 
261
+ class Scoring(NamedTuple):
262
+ """Parsed data related to user scoring for a single entry."""
263
+
264
+ imdb_score: float | None
265
+ """IMDB score."""
266
+
267
+ imdb_votes: int | None
268
+ """Number of votes on IMDB."""
269
+
270
+ tmdb_popularity: float | None
271
+ """TMDB popularity score."""
272
+
273
+ tmdb_score: float | None
274
+ """TMDB score."""
275
+
276
+ tomatometer: int | None
277
+ """Tomatometer score on Rotten Tomatoes."""
278
+
279
+ certified_fresh: bool | None
280
+ """Flag whether entry has "Certified Fresh" seal on Rotten Tomatoes."""
281
+
282
+ jw_rating: float | None
283
+ """JustWatch rating."""
284
+
285
+
286
+ class Interactions(NamedTuple):
287
+ """Parsed data regarding number of likes and dislikes on JustWatch for a single entry."""
288
+
289
+ likes: int | None
290
+ """Number of likes on JustWatch."""
291
+
292
+ dislikes: int | None
293
+ """Number of dislikes on JustWatch."""
294
+
295
+
296
+ class StreamingCharts(NamedTuple):
297
+ """Parsed data related to JustWatch rank for a single entry."""
298
+
299
+ rank: int
300
+ """Rank on JustWatch."""
301
+
302
+ trend: str
303
+ """Trend in ranking on JustWatch, ``UP``, ``DOWN``, ``STABLE``."""
304
+
305
+ trend_difference: int
306
+ """Difference in rank; related to trend."""
307
+
308
+ top_rank: int
309
+ """Top rank ever reached."""
310
+
311
+ days_in_top_3: int
312
+ """Number of days in top 3 ranks."""
313
+
314
+ days_in_top_10: int
315
+ """Number of days in top 10 ranks."""
316
+
317
+ days_in_top_100: int
318
+ """Number of days in top 100 ranks."""
319
+
320
+ days_in_top_1000: int
321
+ """Number of days in top 1000 ranks."""
322
+
323
+ updated: str
324
+ """Date when rank data was last updated as a string, e.g.: ``2024-10-06T09:20:36.397Z``."""
325
+
326
+
226
327
  class MediaEntry(NamedTuple):
227
328
  """Parsed response from JustWatch GraphQL API for "GetSearchTitles" query for single entry."""
228
329
 
@@ -259,12 +360,27 @@ class MediaEntry(NamedTuple):
259
360
  imdb_id: str | None
260
361
  """ID of this entry in IMDB."""
261
362
 
363
+ tmdb_id: str | None
364
+ """ID of this entry in TMDB."""
365
+
262
366
  poster: str | None
263
367
  """URL to poster for this ID."""
264
368
 
265
369
  backdrops: list[str]
266
370
  """List of URLs for backdrops (full screen images to use as background)."""
267
371
 
372
+ age_certification: str | None
373
+ """Age rating as a string, e.g.: "R", "TV-14"."""
374
+
375
+ scoring: Scoring | None
376
+ """Scoring data."""
377
+
378
+ interactions: Interactions | None
379
+ """Interactions (likes/dislikes) data."""
380
+
381
+ streaming_charts: StreamingCharts | None
382
+ """JustWatch charts/ranks data."""
383
+
268
384
  offers: list[Offer]
269
385
  """List of available offers for this entry, empty if there are no available offers."""
270
386
 
@@ -469,9 +585,14 @@ def _parse_entry(json: any) -> MediaEntry:
469
585
  genres = [node.get("shortName") for node in content.get("genres", []) if node]
470
586
  external_ids = content.get("externalIds")
471
587
  imdb_id = external_ids.get("imdbId") if external_ids else None
588
+ tmdb_id = external_ids.get("tmdbId") if external_ids else None
472
589
  poster_url_field = content.get("posterUrl")
473
590
  poster = _IMAGES_URL + poster_url_field if poster_url_field else None
474
591
  backdrops = [_IMAGES_URL + bd.get("backdropUrl") for bd in content.get("backdrops", []) if bd]
592
+ age_certification = content.get("ageCertification")
593
+ scoring = _parse_scores(content.get("scoring"))
594
+ interactions = _parse_interactions(content.get("interactions"))
595
+ streaming_charts = _parse_streaming_charts(json)
475
596
  offers = [_parse_offer(offer) for offer in json.get("offers", []) if offer]
476
597
  return MediaEntry(
477
598
  entry_id,
@@ -485,12 +606,77 @@ def _parse_entry(json: any) -> MediaEntry:
485
606
  short_description,
486
607
  genres,
487
608
  imdb_id,
609
+ tmdb_id,
488
610
  poster,
489
611
  backdrops,
612
+ age_certification,
613
+ scoring,
614
+ interactions,
615
+ streaming_charts,
490
616
  offers,
491
617
  )
492
618
 
493
619
 
620
+ def _parse_scores(json: any) -> Scoring | None:
621
+ if not json:
622
+ return None
623
+ imdb_score = json.get("imdbScore")
624
+ imdb_votes = json.get("imdbVotes")
625
+ tmdb_popularity = json.get("tmdbPopularity")
626
+ tmdb_score = json.get("tmdbScore")
627
+ tomatometer = json.get("tomatoMeter")
628
+ certified_fresh = json.get("certifiedFresh")
629
+ jw_rating = json.get("jwRating")
630
+ return Scoring(
631
+ imdb_score,
632
+ int(imdb_votes) if imdb_votes is not None else None,
633
+ tmdb_popularity,
634
+ tmdb_score,
635
+ int(tomatometer) if tomatometer is not None else None,
636
+ certified_fresh,
637
+ jw_rating,
638
+ )
639
+
640
+
641
+ def _parse_interactions(json: any) -> Interactions | None:
642
+ if not json:
643
+ return None
644
+ likes = json.get("likelistAdditions")
645
+ dislikes = json.get("dislikelistAdditions")
646
+ return Interactions(likes, dislikes)
647
+
648
+
649
+ def _parse_streaming_charts(json: any) -> StreamingCharts | None:
650
+ if (
651
+ not (streaming_chart_info := json.get("streamingCharts", {}).get("edges"))
652
+ or not (streaming_chart_info := streaming_chart_info[0].get("streamingChartInfo"))
653
+ # Getting final info is awkward, I think this in general can return a list when searching
654
+ # for ranks for multiple entries. In this case, to unify searching and displaying details,
655
+ # it's always getting single element in a list.
656
+ ):
657
+ return None
658
+ rank = streaming_chart_info.get("rank")
659
+ trend = streaming_chart_info.get("trend")
660
+ trend_difference = streaming_chart_info.get("trendDifference")
661
+ top_rank = streaming_chart_info.get("topRank")
662
+ days_in_top_3 = streaming_chart_info.get("daysInTop3")
663
+ days_in_top_10 = streaming_chart_info.get("daysInTop10")
664
+ days_in_top_100 = streaming_chart_info.get("daysInTop100")
665
+ days_in_top_1000 = streaming_chart_info.get("daysInTop1000")
666
+ updated = streaming_chart_info.get("updatedAt")
667
+ return StreamingCharts(
668
+ rank,
669
+ trend,
670
+ trend_difference,
671
+ top_rank,
672
+ days_in_top_3,
673
+ days_in_top_10,
674
+ days_in_top_100,
675
+ days_in_top_1000,
676
+ updated,
677
+ )
678
+
679
+
494
680
  def _parse_offer(json: any) -> Offer:
495
681
  id = json.get("id")
496
682
  monetization_type = json.get("monetizationType")
@@ -502,7 +688,7 @@ def _parse_offer(json: any) -> Offer:
502
688
  type = json.get("type")
503
689
  package = _parse_package(json["package"])
504
690
  url = json.get("standardWebURL")
505
- element_count = json.get("elementCount", 0)
691
+ element_count = json.get("elementCount")
506
692
  available_to = json.get("availableTo")
507
693
  deeplink_roku = json.get("deeplinkRoku")
508
694
  subtitle_languages = json.get("subtitleLanguages")
@@ -1,21 +0,0 @@
1
- from justwatch import details, offers_for_countries, search
2
- from query import MediaEntry, Offer, OfferPackage
3
-
4
-
5
- def main():
6
- response = search("The Matrix", "US", "en", 3, True)
7
- print(response)
8
- print()
9
-
10
- response = details("tm10", "US", "en", False)
11
- print(response)
12
- print()
13
-
14
- response = offers_for_countries("tm10", {"US", "GB", "FR"}, "en", True)
15
- print(response)
16
- print()
17
-
18
-
19
-
20
- if __name__ == "__main__":
21
- main()