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.
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/PKG-INFO +31 -14
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/README.md +30 -13
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/pyproject.toml +1 -1
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/PKG-INFO +31 -14
- simple_justwatch_python_api-0.16/src/simplejustwatchapi/main.py +34 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simplejustwatchapi/query.py +188 -2
- simple-justwatch-python-api-0.14/src/simplejustwatchapi/main.py +0 -21
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/LICENSE +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/setup.cfg +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/SOURCES.txt +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/dependency_links.txt +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/requires.txt +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simple_justwatch_python_api.egg-info/top_level.txt +0 -0
- {simple-justwatch-python-api-0.14 → simple_justwatch_python_api-0.16}/src/simplejustwatchapi/__init__.py +0 -0
- {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.
|
|
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
|
|
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** | -
|
|
826
|
-
| 2 | `countries` | `set[str]` | **YES** | -
|
|
827
|
-
| 3 | `language` | `str` | NO | `"en"`
|
|
828
|
-
| 5 | `best_only` | `bool` | NO | `True`
|
|
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
|
|
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** | -
|
|
131
|
-
| 2 | `countries` | `set[str]` | **YES** | -
|
|
132
|
-
| 3 | `language` | `str` | NO | `"en"`
|
|
133
|
-
| 5 | `best_only` | `bool` | NO | `True`
|
|
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.
|
|
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.
|
|
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
|
|
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** | -
|
|
826
|
-
| 2 | `countries` | `set[str]` | **YES** | -
|
|
827
|
-
| 3 | `language` | `str` | NO | `"en"`
|
|
828
|
-
| 5 | `best_only` | `bool` | NO | `True`
|
|
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"
|
|
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()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|