mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
[47] add imdb_award
This commit is contained in:
parent
7113ef4256
commit
6cfd46fd67
5 changed files with 126 additions and 14 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.19.1-develop46
|
||||
1.19.1-develop47
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
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 |
|
||||
|:------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:|
|
||||
|:------------------------------------|:------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:|
|
||||
| [`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_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_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
|
||||
|
@ -154,9 +155,38 @@ collections:
|
|||
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
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -1500,6 +1500,42 @@ class CollectionBuilder:
|
|||
elif method_name == "imdb_watchlist":
|
||||
for imdb_user in self.config.IMDb.validate_imdb_watchlists(self.Type, method_data, self.language):
|
||||
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":
|
||||
for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
|
||||
dict_methods = {dm.lower(): dm for dm in dict_data}
|
||||
|
|
|
@ -5,7 +5,7 @@ from urllib.parse import urlparse, parse_qs
|
|||
|
||||
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"]
|
||||
show_charts = ["popular_shows", "top_shows"]
|
||||
charts = {
|
||||
|
@ -145,6 +145,23 @@ class IMDb:
|
|||
valid_users.append(user)
|
||||
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):
|
||||
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()")
|
||||
|
@ -401,6 +418,27 @@ class IMDb:
|
|||
return imdb_ids
|
||||
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):
|
||||
imdb_keywords = {}
|
||||
expired = None
|
||||
|
@ -408,7 +446,7 @@ class IMDb:
|
|||
imdb_keywords, expired = self.config.Cache.query_imdb_keywords(imdb_id, self.config.Cache.expiration)
|
||||
if imdb_keywords and expired is False:
|
||||
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:
|
||||
raise Failed(f"IMDb Error: No Item Found for IMDb ID: {imdb_id}")
|
||||
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)
|
||||
if parental_dict and expired is False:
|
||||
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:
|
||||
results = response.xpath(f"//section[@id='advisory-{ptype}']//span[contains(@class,'ipl-status-pill')]/text()")
|
||||
if results:
|
||||
|
@ -460,7 +498,7 @@ class IMDb:
|
|||
url = "chart/bottom"
|
||||
else:
|
||||
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]
|
||||
|
||||
def get_imdb_ids(self, method, data, language):
|
||||
|
@ -477,6 +515,14 @@ class IMDb:
|
|||
elif method == "imdb_watchlist":
|
||||
logger.info(f"Processing IMDb Watchlist: {data}")
|
||||
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":
|
||||
logger.info(f"Processing IMDb Search:")
|
||||
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}"
|
||||
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):
|
||||
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:
|
||||
return translation[str(value).lower()] if translation is not None else value
|
||||
|
||||
|
|
Loading…
Reference in a new issue