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
|
||||||
|
|
|
@ -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…
Reference in a new issue