mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-22 12:33:10 +00:00
[46] add letterboxd filters
This commit is contained in:
parent
4928a25b71
commit
534eda26dc
6 changed files with 74 additions and 18 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.16.2-develop45
|
||||
1.16.2-develop46
|
||||
|
|
|
@ -35,3 +35,21 @@ collections:
|
|||
collection_order: custom
|
||||
sync_mode: sync
|
||||
```
|
||||
|
||||
You can add 3 different filters directly to this builder.
|
||||
|
||||
| Filter Attribute | Description |
|
||||
|:-----------------|:---------------------------------------------------------------------------------------------------|
|
||||
| `rating` | **Description:** Search for the specified rating range<br>**Values:** range of int i.e. `80-100` |
|
||||
| `year` | **Description:** Search for the specified year range<br>**Values:** range of int i.e. `1990-1999` |
|
||||
| `note` | **Description:** Search for the specified value in the note<br>**Values:** Any String |
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
Vulture’s 101 Best Movie Endings From the 90s:
|
||||
letterboxd_list_details:
|
||||
url: https://letterboxd.com/brianformo/list/vultures-101-best-movie-endings/
|
||||
year: 1990-1999
|
||||
collection_order: custom
|
||||
sync_mode: sync
|
||||
```
|
|
@ -1084,11 +1084,11 @@ class CollectionBuilder:
|
|||
|
||||
def _letterboxd(self, method_name, method_data):
|
||||
if method_name.startswith("letterboxd_list"):
|
||||
letterboxd_lists = self.config.Letterboxd.validate_letterboxd_lists(method_data, self.language)
|
||||
letterboxd_lists = self.config.Letterboxd.validate_letterboxd_lists(self.Type, method_data, self.language)
|
||||
for letterboxd_list in letterboxd_lists:
|
||||
self.builders.append(("letterboxd_list", letterboxd_list))
|
||||
if method_name.endswith("_details"):
|
||||
self.summaries[method_name] = self.config.Letterboxd.get_list_description(letterboxd_lists[0], self.language)
|
||||
self.summaries[method_name] = self.config.Letterboxd.get_list_description(letterboxd_lists[0]["url"], self.language)
|
||||
|
||||
def _mal(self, method_name, method_data):
|
||||
if method_name == "mal_id":
|
||||
|
@ -2575,7 +2575,7 @@ class CollectionBuilder:
|
|||
items = self.library.get_filter_items(search_data[2])
|
||||
previous = None
|
||||
for i, item in enumerate(items, 0):
|
||||
if len(self.items) <= i or item.ratingKey != self.items[i]:
|
||||
if len(self.items) <= i or item.ratingKey != self.items[i].ratingKey:
|
||||
text = f"after {util.item_title(previous)}" if previous else "to the beginning"
|
||||
logger.info(f"Moving {util.item_title(item)} {text}")
|
||||
self.library.moveItem(self.obj, item, previous)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import time
|
||||
import re, time
|
||||
from modules import util
|
||||
from modules.util import Failed
|
||||
|
||||
|
@ -20,6 +20,16 @@ class Letterboxd:
|
|||
for letterboxd_id in letterboxd_ids:
|
||||
slugs = response.xpath(f"//div[@data-film-id='{letterboxd_id}']/@data-film-slug")
|
||||
items.append((letterboxd_id, slugs[0]))
|
||||
slugs = response.xpath(f"//div[@data-film-id='{letterboxd_id}']/@data-film-slug")
|
||||
notes = response.xpath(f"//div[@data-film-id='{letterboxd_id}']/parent::li/div[@class='film-detail-content']/div/p/text()")
|
||||
ratings = response.xpath(f"//div[@data-film-id='{letterboxd_id}']/parent::li/div[@class='film-detail-content']//span[contains(@class, 'rating')]/@class")
|
||||
years = response.xpath(f"//div[@data-film-id='{letterboxd_id}']/parent::li/div[@class='film-detail-content']/h2/small/a/text()")
|
||||
rating = None
|
||||
if ratings:
|
||||
match = re.search("rated-(\\d+)", ratings[0])
|
||||
if match:
|
||||
rating = int(match.group(1))
|
||||
items.append((letterboxd_id, slugs[0], int(years[0]) if years else None, notes[0] if notes else None, rating))
|
||||
next_url = response.xpath("//a[@class='next']/@href")
|
||||
if len(next_url) > 0:
|
||||
time.sleep(2)
|
||||
|
@ -44,27 +54,50 @@ class Letterboxd:
|
|||
descriptions = response.xpath("//meta[@property='og:description']/@content")
|
||||
return descriptions[0] if len(descriptions) > 0 and len(descriptions[0]) > 0 else None
|
||||
|
||||
def validate_letterboxd_lists(self, letterboxd_lists, language):
|
||||
def validate_letterboxd_lists(self, err_type, letterboxd_lists, language):
|
||||
valid_lists = []
|
||||
for letterboxd_list in util.get_list(letterboxd_lists, split=False):
|
||||
list_url = letterboxd_list.strip()
|
||||
if not list_url.startswith(base_url):
|
||||
raise Failed(f"Letterboxd Error: {list_url} must begin with: {base_url}")
|
||||
elif len(self._parse_list(list_url, language)) > 0:
|
||||
valid_lists.append(list_url)
|
||||
else:
|
||||
raise Failed(f"Letterboxd Error: {list_url} failed to parse")
|
||||
for letterboxd_dict in util.get_list(letterboxd_lists, split=False):
|
||||
if not isinstance(letterboxd_dict, dict):
|
||||
letterboxd_dict = {"url": letterboxd_dict}
|
||||
dict_methods = {dm.lower(): dm for dm in letterboxd_dict}
|
||||
final = {
|
||||
"url": util.parse(err_type, "url", letterboxd_dict, methods=dict_methods, parent="letterboxd_list").strip(),
|
||||
"note": util.parse(err_type, "note", letterboxd_dict, methods=dict_methods, parent="letterboxd_list") if "note" in dict_methods else None,
|
||||
"rating": util.parse(err_type, "rating", letterboxd_dict, methods=dict_methods, datatype="int", parent="letterboxd_list", maximum=100, range_split="-") if "rating" in dict_methods else None,
|
||||
"year": util.parse(err_type, "year", letterboxd_dict, methods=dict_methods, datatype="int", parent="letterboxd_list", minimum=1000, maximum=3000, range_split="-") if "year" in dict_methods else None
|
||||
}
|
||||
if not final["url"].startswith(base_url):
|
||||
raise Failed(f"{err_type} Error: {final['url']} must begin with: {base_url}")
|
||||
elif not self._parse_list(final["url"], language):
|
||||
raise Failed(f"{err_type} Error: {final['url']} failed to parse")
|
||||
valid_lists.append(final)
|
||||
return valid_lists
|
||||
|
||||
def get_tmdb_ids(self, method, data, language):
|
||||
if method == "letterboxd_list":
|
||||
logger.info(f"Processing Letterboxd List: {data}")
|
||||
items = self._parse_list(data, language)
|
||||
items = self._parse_list(data["url"], language)
|
||||
total_items = len(items)
|
||||
if total_items > 0:
|
||||
ids = []
|
||||
filtered_ids = []
|
||||
for i, item in enumerate(items, 1):
|
||||
letterboxd_id, slug = item
|
||||
letterboxd_id, slug, year, note, rating = item
|
||||
filtered = False
|
||||
if data["year"]:
|
||||
start_year, end_year = data["year"].split("-")
|
||||
if not year or int(end_year) < year or year < int(start_year):
|
||||
filtered = True
|
||||
if data["rating"]:
|
||||
start_rating, end_rating = data["rating"].split("-")
|
||||
if not rating or int(end_rating) < rating or rating < int(start_rating):
|
||||
filtered = True
|
||||
if data["note"]:
|
||||
if not note or data["note"] not in note:
|
||||
filtered = True
|
||||
if filtered:
|
||||
filtered_ids.append(slug)
|
||||
continue
|
||||
logger.ghost(f"Finding TMDb ID {i}/{total_items}")
|
||||
tmdb_id = None
|
||||
expired = None
|
||||
|
@ -80,6 +113,8 @@ class Letterboxd:
|
|||
self.config.Cache.update_letterboxd_map(expired, letterboxd_id, tmdb_id)
|
||||
ids.append((tmdb_id, "tmdb"))
|
||||
logger.info(f"Processed {total_items} TMDb IDs")
|
||||
if filtered_ids:
|
||||
logger.info(f"Filtered: {filtered_ids}")
|
||||
return ids
|
||||
else:
|
||||
raise Failed(f"Letterboxd Error: No List Items found in {data}")
|
||||
|
|
|
@ -521,8 +521,11 @@ class MetadataFile(DataFile):
|
|||
"name": template_name,
|
||||
"value": other_keys,
|
||||
auto_type: other_keys,
|
||||
"key_name": str(map_name), "key": str(map_name)
|
||||
"key_name": other_name, "key": "other"
|
||||
}
|
||||
for k, v in template_variables.items():
|
||||
if "other" in v:
|
||||
template_call[k] = v["other"]
|
||||
col = {"template": template_call, "label": str(map_name)}
|
||||
if test:
|
||||
col["test"] = True
|
||||
|
|
|
@ -860,7 +860,7 @@ class Plex(Library):
|
|||
self.query_data(getattr(obj, f"remove{attr_call}"), _remove)
|
||||
display += f"-{', -'.join(_remove)}"
|
||||
final = f"{obj.title[:25]:<25} | {attr_display} | {display}" if display else display
|
||||
if do_print:
|
||||
if do_print and final:
|
||||
logger.info(final)
|
||||
return final
|
||||
|
||||
|
|
Loading…
Reference in a new issue