[47] add imdb_award

pull/1771/head
meisnate12 12 months ago
parent 7113ef4256
commit 6cfd46fd67

@ -1 +1 @@
1.19.1-develop46 1.19.1-develop47

@ -2,13 +2,14 @@
You can find items using the features of [IMDb.com](https://www.imdb.com/) (IMDb). You can find items using the features of [IMDb.com](https://www.imdb.com/) (IMDb).
| Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort | | Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort |
|:------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:| |:------------------------------------|:------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:|
| [`imdb_id`](#imdb-id) | Gets the movie/show specified. | ✅ | ✅ | ❌ | | [`imdb_id`](#imdb-id) | Gets the movie/show specified. | ✅ | ✅ | ❌ |
| [`imdb_chart`](#imdb-chart) | Gets every movie/show in an IMDb Chart like [IMDb Top 250 Movies](https://www.imdb.com/chart/top). | ✅ | ✅ | ✅ | | [`imdb_chart`](#imdb-chart) | Gets every movie/show in an IMDb Chart like [IMDb Top 250 Movies](https://www.imdb.com/chart/top). | ✅ | ✅ | ✅ |
| [`imdb_list`](#imdb-list) | Gets every movie/show in an IMDb List or [IMDb Keyword Search](https://www.imdb.com/search/keyword/). | ✅ | ✅ | ✅ | | [`imdb_list`](#imdb-list) | Gets every movie/show in an IMDb List or [IMDb Keyword Search](https://www.imdb.com/search/keyword/). | ✅ | ✅ | ✅ |
| [`imdb_watchlist`](#imdb-watchlist) | Gets every movie/show in an IMDb User's Watchlist. | ✅ | ✅ | ✅ | | [`imdb_watchlist`](#imdb-watchlist) | Gets every movie/show in an IMDb User's Watchlist. | ✅ | ✅ | ✅ |
| [`imdb_search`](#imdb-search) | Gets every movie/show in an [IMDb Search](https://www.imdb.com/search/title/). | ✅ | ✅ | ✅ | | [`imdb_award`](#imdb-award) | Gets every movie/show in an [IMDb Event](https://www.imdb.com/event/). | ✅ | ✅ | ❌ |
| [`imdb_search`](#imdb-search) | Gets every movie/show in an [IMDb Search](https://www.imdb.com/search/title/). | ✅ | ✅ | ✅ |
## IMDb ID ## IMDb ID
@ -154,9 +155,38 @@ collections:
sync_mode: sync sync_mode: sync
``` ```
## IMDb Award
Finds every item in an [IMDb Event](https://www.imdb.com/event/).
| Award Parameter | Description |
|:------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `event_id` | Specify the IMDb Event ID to search.<br>**Options:** The ID found in the URLs linked on the [IMDb Events Page](https://www.imdb.com/event/). (ex. `ev0000003`) |
| `event_year` | Specify the Year of the Event to look at.<br>**Options:** Any Year under the Event History Sidebar on an Event page. |
| `award_filter` | Filter by the Award heading. Can only accept multiple values as a list.<br>**Options:** Any Black Award heading on an Event Page. |
| `category_filter` | Filter by the Category heading. Can only accept multiple values as a list.<br>**Options:** Any Gold/Yellow Category heading on an Event Page. |
| `winning` | Filter by if the Item Won the award.<br>**Options:** `true`/`false`<br>**Default:** `false` |
```yaml
collections:
Academy Award Winners 2023:
imdb_award:
event_id: ev0000003
event_year: 2023
winning: true
```
```yaml
collections:
Academy Award 2023 Best Picture Nominees:
imdb_award:
event_id: ev0000003
event_year: 2023
category_filter: Best Motion Picture of the Year
```
## IMDb Search ## IMDb Search
Finds every item using an [IMDb Advance Title Search](https://www.imdb.com/search/title/) Finds every item using an [IMDb Advance Title Search](https://www.imdb.com/search/title/).
The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order. The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.

@ -1500,6 +1500,42 @@ class CollectionBuilder:
elif method_name == "imdb_watchlist": elif method_name == "imdb_watchlist":
for imdb_user in self.config.IMDb.validate_imdb_watchlists(self.Type, method_data, self.language): for imdb_user in self.config.IMDb.validate_imdb_watchlists(self.Type, method_data, self.language):
self.builders.append((method_name, imdb_user)) self.builders.append((method_name, imdb_user))
elif method_name == "imdb_award":
for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
dict_methods = {dm.lower(): dm for dm in dict_data}
event_id = util.parse(self.Type, "event_id", dict_data, parent=method_name, methods=dict_methods, regex=(r"(ev\d+)", "ev0000003"))
year_options = self.config.IMDb.get_event_years(event_id)
if not year_options:
raise Failed(f"{self.Type} Error: imdb_award event_id attribute: No event found at {imdb.base_url}/event/{event_id}")
event_year = util.parse(self.Type, "event_year", dict_data, parent=method_name, methods=dict_methods, options=year_options)
try:
award_filters = util.parse(self.Type, "award_filter", dict_data, parent=method_name, methods=dict_methods, datatype="lowerlist")
except Failed:
award_filters = []
try:
category_filters = util.parse(self.Type, "category_filter", dict_data, parent=method_name, methods=dict_methods, datatype="lowerlist")
except Failed:
category_filters = []
final_category = []
final_awards = []
if award_filters or category_filters:
award_names, category_names = self.config.IMDb.get_award_names(event_id, event_year)
lower_award = {a.lower(): a for a in award_names if a}
for award_filter in award_filters:
if award_filter in lower_award:
final_awards.append(lower_award[award_filter])
else:
raise Failed(f"{self.Type} Error: imdb_award award_filter attribute invalid: {award_filter} must be in in [{', '.join([v for _, v in lower_award.items()])}]")
lower_category = {c.lower(): c for c in category_names if c}
for category_filter in category_filters:
if category_filter in lower_category:
final_category.append(lower_category[category_filter])
else:
raise Failed(f"{self.Type} Error: imdb_award category_filter attribute invalid: {category_filter} must be in in [{', '.join([v for _, v in lower_category.items()])}]")
self.builders.append((method_name, {
"event_id": event_id, "event_year": event_year, "award_filter": final_awards if final_awards else None, "category_filter": final_category if final_category else None,
"winning": util.parse(self.Type, "winning", dict_data, parent=method_name, methods=dict_methods, datatype="bool", default=False)
}))
elif method_name == "imdb_search": elif method_name == "imdb_search":
for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"): for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
dict_methods = {dm.lower(): dm for dm in dict_data} dict_methods = {dm.lower(): dm for dm in dict_data}

@ -5,7 +5,7 @@ from urllib.parse import urlparse, parse_qs
logger = util.logger logger = util.logger
builders = ["imdb_list", "imdb_id", "imdb_chart", "imdb_watchlist", "imdb_search"] builders = ["imdb_list", "imdb_id", "imdb_chart", "imdb_watchlist", "imdb_search", "imdb_award"]
movie_charts = ["box_office", "popular_movies", "top_movies", "top_english", "top_indian", "lowest_rated"] movie_charts = ["box_office", "popular_movies", "top_movies", "top_english", "top_indian", "lowest_rated"]
show_charts = ["popular_shows", "top_shows"] show_charts = ["popular_shows", "top_shows"]
charts = { charts = {
@ -145,6 +145,23 @@ class IMDb:
valid_users.append(user) valid_users.append(user)
return valid_users return valid_users
def get_event_years(self, event_id):
return self._request(f"{base_url}/event/{event_id}", xpath="//div[@class='event-history-widget']//a/text()")
def get_award_names(self, event_id, event_year):
award_names = []
category_names = []
for text in self._request(f"{base_url}/event/{event_id}/{event_year}", xpath="//div[@class='article']/script/text()")[0].split("\n"):
if text.strip().startswith("IMDbReactWidgets.NomineesWidget.push"):
jsonline = text.strip()
obj = json.loads(jsonline[jsonline.find("{"):-3])
for award in obj["nomineesWidgetModel"]["eventEditionSummary"]["awards"]:
award_names.append(award["awardName"])
for category in award["categories"]:
category_names.append(category["categoryName"])
break
return award_names, category_names
def _watchlist(self, user, language): def _watchlist(self, user, language):
imdb_url = f"{base_url}/user/{user}/watchlist" imdb_url = f"{base_url}/user/{user}/watchlist"
group = self._request(imdb_url, language=language, xpath="//span[@class='ab_widget']/script[@type='text/javascript']/text()") group = self._request(imdb_url, language=language, xpath="//span[@class='ab_widget']/script[@type='text/javascript']/text()")
@ -401,6 +418,27 @@ class IMDb:
return imdb_ids return imdb_ids
raise Failed("IMDb Error: No IMDb IDs Found") raise Failed("IMDb Error: No IMDb IDs Found")
def _award(self, data):
final_list = []
for text in self._request(f"{base_url}/event/{data['event_id']}/{data['event_year']}", xpath="//div[@class='article']/script/text()")[0].split("\n"):
if text.strip().startswith("IMDbReactWidgets.NomineesWidget.push"):
jsonline = text.strip()
obj = json.loads(jsonline[jsonline.find('{'):-3])
for award in obj["nomineesWidgetModel"]["eventEditionSummary"]["awards"]:
if data["award_filter"] and award["awardName"] not in data["award_filter"]:
continue
for cat in award["categories"]:
if data["category_filter"] and cat["categoryName"] not in data["category_filter"]:
continue
for nom in cat["nominations"]:
if data["winning"] and not nom["isWinner"]:
continue
imdb_set = next(((n["const"], n["name"]) for n in nom["primaryNominees"] + nom["secondaryNominees"] if n["const"].startswith("tt")), None)
if imdb_set:
final_list.append(imdb_set)
break
return final_list
def keywords(self, imdb_id, language, ignore_cache=False): def keywords(self, imdb_id, language, ignore_cache=False):
imdb_keywords = {} imdb_keywords = {}
expired = None expired = None
@ -408,7 +446,7 @@ class IMDb:
imdb_keywords, expired = self.config.Cache.query_imdb_keywords(imdb_id, self.config.Cache.expiration) imdb_keywords, expired = self.config.Cache.query_imdb_keywords(imdb_id, self.config.Cache.expiration)
if imdb_keywords and expired is False: if imdb_keywords and expired is False:
return imdb_keywords return imdb_keywords
keywords = self._request(f"https://www.imdb.com/title/{imdb_id}/keywords", language=language, xpath="//td[@class='soda sodavote']") keywords = self._request(f"{base_url}/title/{imdb_id}/keywords", language=language, xpath="//td[@class='soda sodavote']")
if not keywords: if not keywords:
raise Failed(f"IMDb Error: No Item Found for IMDb ID: {imdb_id}") raise Failed(f"IMDb Error: No Item Found for IMDb ID: {imdb_id}")
for k in keywords: for k in keywords:
@ -430,7 +468,7 @@ class IMDb:
parental_dict, expired = self.config.Cache.query_imdb_parental(imdb_id, self.config.Cache.expiration) parental_dict, expired = self.config.Cache.query_imdb_parental(imdb_id, self.config.Cache.expiration)
if parental_dict and expired is False: if parental_dict and expired is False:
return parental_dict return parental_dict
response = self._request(f"https://www.imdb.com/title/{imdb_id}/parentalguide") response = self._request(f"{base_url}/title/{imdb_id}/parentalguide")
for ptype in util.parental_types: for ptype in util.parental_types:
results = response.xpath(f"//section[@id='advisory-{ptype}']//span[contains(@class,'ipl-status-pill')]/text()") results = response.xpath(f"//section[@id='advisory-{ptype}']//span[contains(@class,'ipl-status-pill')]/text()")
if results: if results:
@ -460,7 +498,7 @@ class IMDb:
url = "chart/bottom" url = "chart/bottom"
else: else:
raise Failed(f"IMDb Error: chart: {chart} not ") raise Failed(f"IMDb Error: chart: {chart} not ")
links = self._request(f"https://www.imdb.com/{url}", language=language, xpath="//li//a[@class='ipc-title-link-wrapper']/@href") links = self._request(f"{base_url}/{url}", language=language, xpath="//li//a[@class='ipc-title-link-wrapper']/@href")
return [re.search("(tt\\d+)", l).group(1) for l in links] return [re.search("(tt\\d+)", l).group(1) for l in links]
def get_imdb_ids(self, method, data, language): def get_imdb_ids(self, method, data, language):
@ -477,6 +515,14 @@ class IMDb:
elif method == "imdb_watchlist": elif method == "imdb_watchlist":
logger.info(f"Processing IMDb Watchlist: {data}") logger.info(f"Processing IMDb Watchlist: {data}")
return [(_i, "imdb") for _i in self._watchlist(data, language)] return [(_i, "imdb") for _i in self._watchlist(data, language)]
elif method == "imdb_award":
logger.info(f"Processing IMDb Award: {base_url}/{data['event_id']}/{data['event_year']}")
for k in ["award_filter", "category_filter", "winning"]:
logger.info(f" {k}: {data[k]}")
awards = self._award(data)
for award in awards:
logger.info(award)
return [(_i, "imdb") for _i, _ in awards]
elif method == "imdb_search": elif method == "imdb_search":
logger.info(f"Processing IMDb Search:") logger.info(f"Processing IMDb Search:")
for k, v in data.items(): for k, v in data.items():

@ -852,7 +852,7 @@ def parse(error, attribute, data, datatype=None, methods=None, parent=None, defa
message = f"{e}" message = f"{e}"
elif (translation is not None and str(value).lower() not in translation) or \ elif (translation is not None and str(value).lower() not in translation) or \
(options is not None and translation is None and str(value).lower() not in options): (options is not None and translation is None and str(value).lower() not in options):
message = f"{display} {value} must be in {', '.join([str(o) for o in options])}" message = f"{display} {value} must be in [{', '.join([str(o) for o in options])}]"
else: else:
return translation[str(value).lower()] if translation is not None else value return translation[str(value).lower()] if translation is not None else value

Loading…
Cancel
Save