html-imdbinfo 0.9.1__py3-none-any.whl

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,410 @@
1
+ Metadata-Version: 2.4
2
+ Name: html_imdbinfo
3
+ Version: 0.9.1
4
+ Summary: A Python service for querying IMDb data
5
+ Author-email: "@tveronesi" <tveronesi+imdbinfo@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Tiago Veronesi
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://tveronesi.github.io/imdbinfo/
29
+ Keywords: imdb,movie,information,data
30
+ Classifier: Development Status :: 5 - Production/Stable
31
+ Classifier: Intended Audience :: Developers
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3.10
34
+ Classifier: Programming Language :: Python :: 3.11
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Programming Language :: Python :: 3.13
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Requires-Dist: niquests
40
+ Requires-Dist: lxml
41
+ Requires-Dist: pydantic
42
+ Requires-Dist: jmespath
43
+ Requires-Dist: deprecated
44
+ Requires-Dist: imdbinfo-aws
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest>=7.0; extra == "dev"
47
+ Requires-Dist: mypy; extra == "dev"
48
+ Requires-Dist: ruff; extra == "dev"
49
+ Requires-Dist: black; extra == "dev"
50
+ Provides-Extra: build
51
+ Requires-Dist: build; extra == "build"
52
+ Requires-Dist: twine; extra == "build"
53
+ Provides-Extra: test
54
+ Requires-Dist: pytest>=7.0; extra == "test"
55
+ Dynamic: license-file
56
+
57
+ [![PyPI Downloads](https://static.pepy.tech/badge/imdbinfo)](https://pepy.tech/projects/imdbinfo)
58
+ [![PyPI Version](https://img.shields.io/pypi/v/imdbinfo?style=flat-square)](https://pypi.org/project/imdbinfo/)
59
+ [![Build Status](https://github.com/tveronesi/imdbinfo/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/tveronesi/imdbinfo/actions/workflows/pypi-publish.yml)
60
+ [![Python Versions](https://img.shields.io/pypi/pyversions/imdbinfo?style=flat-square)](https://pypi.org/project/imdbinfo/)
61
+
62
+ [//]: # (![PyPI - Daily Downloads]&#40;https://img.shields.io/pypi/dm/your-package-name?label=PyPI%20downloads&logo=pypi&#41;)
63
+
64
+ # imdbinfo
65
+
66
+ **Your personal gateway to IMDb data**. Search for movies, series and people and get structured information in seconds.
67
+
68
+ ## Features
69
+
70
+ - 🔍 **Search movies, series, miniseries and people** by name or title
71
+ - 🎬 **Detailed movie info** including cast, crew, ratings and more
72
+ - 👥 **Detailed person info** with biography, filmography and images
73
+ - 📺 **TV series and miniseries** support with seasons and episodes
74
+ - 🌐 **Localized results** in multiple languages (set globally or per request)
75
+ - 📅 **Release dates** and **box office** information
76
+ - 🌍 **International titles** and **alternate titles (AKAs)** via `get_akas`
77
+ - 📸 **Poster images** and **backdrops**
78
+ - 📊 **Ratings** from IMDb and other sources
79
+ - 📝 **User reviews and ratings** via `get_reviews`
80
+ - 🎭 **Movie trivia and interesting facts** via `get_trivia`
81
+ - 🗂️ **Full filmography** for actors, directors and writers via `get_filmography`
82
+ - 🛡️ **Parental guide** including content advisories via `get_parental_guide`
83
+ - 📝 **Typed Pydantic models** for predictable responses
84
+ - ⚡ **Built-in caching** for faster repeated requests
85
+ - 🛡️**AWS WAF** solver in CPython for better performance
86
+ - ✅ **No API keys required**
87
+
88
+ ## Installation
89
+
90
+ ```bash
91
+ pip install imdbinfo
92
+ ```
93
+
94
+ ## Quick Start
95
+
96
+ ```python
97
+ from imdbinfo import search_title, get_movie, get_name, get_season_episodes, get_reviews, get_trivia
98
+
99
+ # Search for a title
100
+ results = search_title("The Matrix")
101
+ for movie in results.titles:
102
+ print(f"{movie.title} ({movie.year}) - Rating: {movie.rating} - {movie.imdb_id}")
103
+
104
+ # Get movie details
105
+ movie = get_movie("0133093") # or 'tt0133093'
106
+ print(movie.title, movie.year, movie.rating)
107
+
108
+ # Get movie kind:
109
+ print(movie.kind) # movie, tvSeries, tvMiniSeries, tvMovie, tvEpisode, tvSpecial, tvShort, short, videoGame, video, musicVideo, podcastEpisode, podcastSeries
110
+ print(movie.is_series()) # False
111
+
112
+ # Get person details
113
+ person = get_name("nm0000206") # or '0000206'
114
+ print(person.name, person.birth_date)
115
+ ```
116
+ #### Working with Series and Episodes
117
+
118
+ The `movie` object provides helpful methods to identify its type:
119
+
120
+ - `movie.is_series()` — Returns `True` if the movie is a series.
121
+ - `movie.is_episode()` — Returns `True` if the movie is an episode.
122
+
123
+ Depending on the type, you can access additional information:
124
+
125
+ - For series: use `movie.info_series` to get series details (creators, seasons, episodes, ...)
126
+ - For episodes: use `movie.info_episode` to get episode details
127
+
128
+ #### Example: Working with Series and Episodes
129
+
130
+ ```python
131
+ from imdbinfo import get_movie, get_season_episodes
132
+
133
+ # Fetch a TV series as a Movie object
134
+ walking_dead_serie = get_movie("tt1520211") # Walking Dead
135
+
136
+ # Check if the object is a series
137
+ print(walking_dead_serie.is_series()) # True
138
+
139
+ # Access series-specific information
140
+ print(f"Series Info: {walking_dead_serie.info_series}")
141
+
142
+ # Retrieve episodes for the series season 1
143
+ walking_dead_episodes = get_season_episodes(walking_dead_serie.imdb_id, season=1)
144
+
145
+ # Print details for the first 3 episodes from the season 1
146
+ for episode_info in walking_dead_episodes[:3]:
147
+ print(episode_info)
148
+
149
+ # Fetch a single episode as a Movie object and check its type
150
+ episode_detail = get_movie(episode_info.imdb_id)
151
+ print("Is Episode:", episode_detail.is_episode()) # True
152
+
153
+ # Access episode-specific information: series imdbid, season and episode number ...
154
+ print(f"Episode Info: {episode_detail.info_episode}")
155
+ ```
156
+
157
+ #### All episodes in a series
158
+ You can now retrieve all episodes in a series with a single call:
159
+ ```python
160
+ from imdbinfo import get_all_episodes
161
+ # Fetch all episodes for a series
162
+ all_episodes = get_all_episodes("tt1520211") # Walking Dead
163
+ for episode in all_episodes:
164
+ print(f"Title: {episode.title} - ({episode.imdbId})")
165
+ print(f"Plot: {episode.plot[:100]}...")
166
+ print(f"Release Date: {episode.release_date}")
167
+ print(f"Rating: {episode.rating}")
168
+ print(f"Duration: {episode.duration/60}min")
169
+ print("" + "="*50)
170
+ ```
171
+
172
+ #### Company Credits
173
+
174
+ * distribution companies,
175
+ * production companies,
176
+ * sales companies,
177
+ * special effects companies,
178
+ * miscellaneous companies
179
+
180
+ You can now extract information about the companies involved in a movie or series:
181
+
182
+ ```python
183
+ from imdbinfo import get_movie
184
+
185
+ movie = get_movie("tt0133093") # The Matrix
186
+
187
+ # Distribution companies
188
+ for company in movie.company_credits["distribution"]:
189
+ print(f"Distribution: {company.name} ({company.country})")
190
+
191
+ # Sales companies
192
+ for company in movie.company_credits["sales"]:
193
+ print(f"Sales: {company.name}")
194
+
195
+ # Production companies
196
+ for company in movie.company_credits["production"]:
197
+ print(f"Production: {company.name}")
198
+
199
+ # Special effects companies
200
+ for company in movie.company_credits["specialEffects"]:
201
+ print(f"Special Effects: {company.name}")
202
+
203
+ # Miscellaneous companies
204
+ for company in movie.company_credits["miscellaneous"]:
205
+ print(f"Miscellaneous: {company.name}")
206
+ ```
207
+
208
+ #### Alternate titles (AKAs)
209
+ Fetch international and alternate titles for any movie or series:
210
+ ```python
211
+ from imdbinfo import get_akas
212
+ akas = get_akas("tt0133093") # The Matrix
213
+ for aka in akas["akas"][:5]:
214
+ print(f"{aka.title} ({aka.country_name})")
215
+ ```
216
+
217
+ #### Reviews and User Ratings
218
+ Get user reviews and ratings for any movie or series:
219
+ ```python
220
+ from imdbinfo import get_reviews
221
+ reviews = get_reviews("tt0133093") # The Matrix
222
+ for review in reviews[:3]:
223
+ print(f"Rating: {review['authorRating']}/10")
224
+ print(f"Summary: {review['summary']}")
225
+ print(f"Helpful votes: {review['upVotes']} up, {review['downVotes']} down")
226
+ print(f"Spoiler: {review['spoiler']}")
227
+ print("---")
228
+ ```
229
+
230
+ #### Movie Trivia and Facts
231
+ Discover interesting trivia and behind-the-scenes facts:
232
+ ```python
233
+ from imdbinfo import get_trivia
234
+ trivia = get_trivia("tt0133093") # The Matrix
235
+ for fact in trivia[:3]:
236
+ print(f"Interest Score: {fact['interestScore']}")
237
+ print(f"Fact: {fact['body'][:200]}...")
238
+ print("---")
239
+ ```
240
+
241
+ #### Parental Guide
242
+ Get parental guide information including content advisories, severity level, spoiler flags, and content descriptions:
243
+
244
+ ```python
245
+ from imdbinfo import get_parental_guide
246
+
247
+ pg = get_parental_guide("tt0133093") # The Matrix
248
+ for cat in pg.categories:
249
+ print(cat) # e.g. NUDITY - MILD (6 descriptions)
250
+ for txt in cat.category_texts_list(spolier=True):
251
+ print(f" - {txt.text} (SPOILER: {txt.is_spoiler})")
252
+ ```
253
+
254
+ #### Awards
255
+
256
+ The package groups award-related counts in the `MovieDetail.awards` object (an `AwardInfo` instance). The model currently exposes:
257
+
258
+ - `wins` — number of award wins
259
+ - `nominations` — number of nominations (excluding wins)
260
+ - `prestigious_award` — optional dict containing details of a prestigious award (may include `wins` and `nominations` keys)
261
+
262
+ Example showing how to safely read `MovieDetail.awards` using the current model shape:
263
+
264
+ ```python
265
+ from imdbinfo import get_movie
266
+
267
+ movie = get_movie("tt0133093") # The Matrix
268
+ aw = movie.awards
269
+ if not aw:
270
+ print("No award information available for this title")
271
+ else:
272
+ # basic counts
273
+ print("wins:", aw.wins)
274
+ print("nominations:", aw.nominations)
275
+
276
+ # prestigious award (may be None or a dict)
277
+ if aw.prestigious_award:
278
+ pa = aw.prestigious_award
279
+ print("prestigious wins:", pa.get("wins"))
280
+ print("prestigious nominations:", pa.get("nominations"))
281
+ else:
282
+ print("No prestigious award summary available")
283
+ ```
284
+
285
+ Notes:
286
+ - The JSON parser maps page data into `movie.awards` (a dict turned into an `AwardInfo` instance). Depending on the source data, `prestigious_award` can be None or a dict with `wins` and `nominations`.
287
+ - Use `if movie.awards:` to check presence before reading attributes.
288
+
289
+
290
+ ### Localized results in multiple languages (set globally or per request)
291
+
292
+ Added support for locales in `search_movie`, `get_movie`, `get_episodes`, `get_all_episodes`, `get_name`
293
+ ```python
294
+ from imdbinfo import get_movie, search_title
295
+ # Fetch movie details in Italian
296
+ movie_it = get_movie("tt0133093", locale="it") # The Matrix
297
+
298
+ # Search for titles in Spanish (although IMDb search is mostly in all languages)
299
+ results_es = search_title("La Casa de Papel", locale="es")
300
+ ```
301
+
302
+ Localized data can be set globally, dont need to pass `locale` every time in the functions:
303
+ ```python
304
+ from imdbinfo import get_movie
305
+ from imdbinfo.locale import set_locale
306
+ set_locale("it") # Set default locale to Italian
307
+ movie_it = get_movie("tt0133093") # The Matrix in Italian
308
+ ```
309
+
310
+ #### MovieInfoBrief.title_localized
311
+ The `MovieInfoBrief` object (e.g., items in `results.titles` from `search_title`) now includes the `title_localized` property. This property contains the title in the requested locale, if available, and falls back to the default `title` when a localized version is not present.
312
+
313
+ Example:
314
+ ```python
315
+ from imdbinfo import search_title
316
+
317
+ # Search for a title with a specific locale
318
+ results = search_title("The Matrix", locale="it")
319
+ for item in results.titles:
320
+ # Print the localized title if available, otherwise the default title
321
+ print(item.title, "->", getattr(item, "title_localized", item.title))
322
+ ```
323
+
324
+ ### Filtering results based on type (e.g. Movies, Series, Episodes etc.) 🔽
325
+ You can filter results from `search_title`, done server-side.
326
+ ```python
327
+ from imdbinfo import search_title, TitleType
328
+
329
+ # Search for single type: movies
330
+ results = search_title("The Matrix", title_type=TitleType.Movies)
331
+ for movie in results.titles:
332
+ print(f"{movie.title} ({movie.year}) - {movie.imdb_id}")
333
+
334
+ # Search for multiple types: movies, shorts and videos.
335
+ results = search_title("The Matrix", title_type=(TitleType.Movies, TitleType.Shorts, TitleType.Video))
336
+ for movie in results.titles:
337
+ print(f"{movie.title} ({movie.year}) - {movie.imdb_id}")
338
+
339
+ ```
340
+
341
+ ### Get filmography with images 🎬🖼️
342
+ You can now get filmography for actors, directors and writers and all credits with images:
343
+ ```python
344
+ from imdbinfo import get_filmography
345
+
346
+ filmography = get_filmography("nm0000206") # Brad Pitt
347
+ if filmography:
348
+ for role, films in filmography.items():
349
+ print(f"\nRole: {role}")
350
+ for film in films:
351
+ print(f" - {film.title} ({film.year}) [{film.imdbId}]")
352
+
353
+ ```
354
+
355
+ #### Get all interests for a title
356
+
357
+ _Fetch all interests for a title using the provided IMDb ID. Most time it returns the same as genres.
358
+ It requires a new request and parsing. Use it only if you really need it._
359
+
360
+ ```python
361
+ from imdbinfo import get_all_interests
362
+
363
+ movies = ["tt1490017", "tt0133093"]
364
+
365
+ for imdb_id in movies:
366
+ interests = get_all_interests(imdb_id)
367
+ print(f"Interests for {imdb_id}: {interests}")
368
+ ```
369
+
370
+
371
+ 📝 For more examples see the [examples](examples/) folder.
372
+
373
+ > 💡 **Looking for a ready-to-use API based on this package? Check out [qdMovieAPI](https://github.com/tveronesi/qdMovieAPI) — a fast and simple way to access IMDb data via REST!**
374
+
375
+ ## Why choose imdbinfo?
376
+
377
+ - Easy to use Python API
378
+ - Returns clean structured data
379
+ - Powered by niquests and lxml
380
+ - Uses Pydantic for type safety
381
+ - No external dependencies or API keys required
382
+ - Ideal for quick scripts and data analysis
383
+
384
+ ## Disclaimer
385
+ This project and its authors are not affiliated in any way with IMDb Inc. or its affiliates.
386
+ For more information, please refer to the [DISCLAIMER](DISCLAIMER.txt) file.
387
+
388
+ ## Contributing
389
+
390
+ Contributions are welcome! Open an issue or pull request on GitHub.
391
+
392
+ If you find this project useful, please consider giving it a ⭐ on GitHub!
393
+
394
+ Please read our [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
395
+
396
+ ## Star History
397
+
398
+ <a href="https://www.star-history.com/?repos=tveronesi%2Fimdbinfo&type=date&legend=top-left">
399
+ <picture>
400
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=tveronesi/imdbinfo&type=date&theme=dark&logscale&legend=top-left" />
401
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=tveronesi/imdbinfo&type=date&logscale&legend=top-left" />
402
+ <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=tveronesi/imdbinfo&type=date&logscale&legend=top-left" />
403
+ </picture>
404
+ </a>
405
+
406
+ ## License
407
+
408
+ imdbinfo is released under the MIT License.
409
+ See the [LICENSE](LICENSE) file for details.
410
+
@@ -0,0 +1,14 @@
1
+ html_imdbinfo-0.9.1.dist-info/licenses/LICENSE,sha256=rSm7MgM5XqJCkDsSPqByHUApT-v-Lexw314AZsnyPdg,1071
2
+ imdbinfo/__init__.py,sha256=Wxn4-M8RYwRrHBbciAd5DXN12QRQujY2i12_ILsHVDo,1995
3
+ imdbinfo/cli.py,sha256=jshdYSSp2j2b48CH1ZUy5h4xpviSEmfwrHwzdjwefOc,3404
4
+ imdbinfo/exceptions.py,sha256=VLXxHTZ0qEO6w3OWvyHPDbO7eeFb83GqNsaBEKk68Lk,5065
5
+ imdbinfo/locale.py,sha256=KfiEpWqC6aATKWKS7Gwa8pkpCiSQ5vfQ-wyunxICY9w,2924
6
+ imdbinfo/models.py,sha256=LC71OOYsUzAnGuB8LUGky8YUR-1UT3b_cs9YAcnt1tE,26305
7
+ imdbinfo/parsers.py,sha256=DxBH9-SmP_lyCJsh5VMq3zD0YLctFWxz7wwbxYXA6e4,33942
8
+ imdbinfo/services.py,sha256=SNfIXkaQ2LU3KqLzcYTbAP8uAZjDvihrkugDit-UOcg,24600
9
+ imdbinfo/transformers.py,sha256=cPhx5mY7fNccDPMrjjAVdN0jge_JbKLg8Clvc8DJPeY,3355
10
+ html_imdbinfo-0.9.1.dist-info/METADATA,sha256=xrjJd_Li-VQzidG4Geho5kC0Vjp2VbpcK5z1o3Dlm-M,15331
11
+ html_imdbinfo-0.9.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
12
+ html_imdbinfo-0.9.1.dist-info/entry_points.txt,sha256=QETfNv-2hupV4PK_e0SBeOVEQljTyVX0vWsaFyUcFvo,53
13
+ html_imdbinfo-0.9.1.dist-info/top_level.txt,sha256=1204ZLnfhCdCzFCOnxCX3kFFbXKWtHzuKD9Pg5e_14g,9
14
+ html_imdbinfo-0.9.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ imdbinfo-fetch = imdbinfo.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tiago Veronesi
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 @@
1
+ imdbinfo
imdbinfo/__init__.py ADDED
@@ -0,0 +1,70 @@
1
+ # MIT License
2
+ # Copyright (c) 2025 tveronesi+imdbinfo@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ # SOFTWARE.
21
+
22
+ import logging
23
+
24
+ from .services import (
25
+ get_movie,
26
+ search_title,
27
+ get_name,
28
+ get_episodes,
29
+ get_all_episodes,
30
+ get_season_episodes,
31
+ get_akas,
32
+ get_reviews,
33
+ get_trivia,
34
+ get_parental_guide,
35
+ get_filmography,
36
+ get_all_interests,
37
+ TitleType,
38
+ )
39
+ from .exceptions import (
40
+ ImdbinfoError,
41
+ HTTPError,
42
+ WAFError,
43
+ GraphQLError,
44
+ ParseError,
45
+ )
46
+
47
+ __all__ = [
48
+ "get_movie",
49
+ "search_title",
50
+ "get_name",
51
+ "get_episodes",
52
+ "get_all_episodes",
53
+ "get_season_episodes",
54
+ "get_akas",
55
+ "get_reviews",
56
+ "get_trivia",
57
+ "get_parental_guide",
58
+ "get_filmography",
59
+ "get_all_interests",
60
+ "TitleType",
61
+ # exceptions
62
+ "ImdbinfoError",
63
+ "HTTPError",
64
+ "WAFError",
65
+ "GraphQLError",
66
+ "ParseError",
67
+ ]
68
+
69
+ # setup library logging
70
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
imdbinfo/cli.py ADDED
@@ -0,0 +1,108 @@
1
+ """imdbinfo-fetch – minimal CLI that returns raw IMDb HTML to stdout.
2
+
3
+ Usage
4
+ -----
5
+ imdbinfo-fetch <url>
6
+
7
+ The HTTP request goes through the same ``request_handler`` used internally by
8
+ the library, so WAF cookie rotation and the browser-like headers are all
9
+ handled automatically – exactly what lets the library scrape IMDb reliably.
10
+
11
+ Your PHP app can then extract ``__NEXT_DATA__`` from the HTML however it likes,
12
+ for example with a regex:
13
+
14
+ preg_match('/<script id="__NEXT_DATA__"[^>]*>(.*?)<\\/script>/s', $html, $m);
15
+ $data = json_decode($m[1], true);
16
+
17
+ Exit codes
18
+ ----------
19
+ 0 – success, HTML written to stdout
20
+ 1 – bad arguments or non-200 HTTP response
21
+ 2 – WAF blocked the request (HTTP 202)
22
+ """
23
+
24
+ import sys
25
+ import argparse
26
+
27
+ from .services import request_handler
28
+ from .exceptions import HTTPError, WAFError
29
+
30
+
31
+ def _build_parser() -> argparse.ArgumentParser:
32
+ p = argparse.ArgumentParser(
33
+ prog="imdbinfo-fetch",
34
+ description=(
35
+ "Fetch a raw IMDb page and print its HTML to stdout.\n\n"
36
+ "The request uses the same WAF-aware headers as the imdbinfo library,\n"
37
+ "so the response is exactly what a real browser would receive."
38
+ ),
39
+ formatter_class=argparse.RawDescriptionHelpFormatter,
40
+ epilog=(
41
+ "Examples:\n"
42
+ " imdbinfo-fetch https://www.imdb.com/title/tt0166924/reference\n"
43
+ " imdbinfo-fetch https://www.imdb.com/lists/tt0166924\n"
44
+ " imdbinfo-fetch https://www.imdb.com/name/nm0000338/\n\n"
45
+ "Pipe to a file:\n"
46
+ " imdbinfo-fetch https://www.imdb.com/title/tt0133093/reference > matrix.html\n"
47
+ ),
48
+ )
49
+ p.add_argument(
50
+ "url",
51
+ help="Full IMDb URL to fetch (must start with https://www.imdb.com/)",
52
+ )
53
+ p.add_argument(
54
+ "--check-domain",
55
+ action="store_true",
56
+ default=True,
57
+ help="Warn (but do not abort) when the URL is not an IMDb domain (default: on)",
58
+ )
59
+ p.add_argument(
60
+ "--no-check-domain",
61
+ dest="check_domain",
62
+ action="store_false",
63
+ help="Skip the IMDb domain warning",
64
+ )
65
+ return p
66
+
67
+
68
+ def main() -> None:
69
+ parser = _build_parser()
70
+ args = parser.parse_args()
71
+
72
+ url: str = args.url
73
+
74
+ if not url.startswith(("http://", "https://")):
75
+ parser.error(f"URL must start with http:// or https:// – got: {url!r}")
76
+
77
+ if args.check_domain and "imdb.com" not in url:
78
+ print(
79
+ f"Warning: URL does not look like an IMDb URL: {url!r}",
80
+ file=sys.stderr,
81
+ )
82
+
83
+ try:
84
+ resp = request_handler(url)
85
+ except WAFError as exc:
86
+ print(f"Error: WAF blocked the request – {exc}", file=sys.stderr)
87
+ sys.exit(2)
88
+ except HTTPError as exc:
89
+ print(f"Error: HTTP {exc.status_code} – {exc}", file=sys.stderr)
90
+ sys.exit(1)
91
+ except Exception as exc: # network error, DNS, etc.
92
+ print(f"Error: {exc}", file=sys.stderr)
93
+ sys.exit(1)
94
+
95
+ if resp.status_code != 200:
96
+ print(
97
+ f"Error: received HTTP {resp.status_code} from {url}",
98
+ file=sys.stderr,
99
+ )
100
+ sys.exit(1)
101
+
102
+ # Write raw bytes to stdout so the encoding is preserved faithfully.
103
+ # PHP reads bytes too, so this is the safest approach.
104
+ sys.stdout.buffer.write(resp.content)
105
+
106
+
107
+ if __name__ == "__main__":
108
+ main()