diff --git a/CHANGELOG b/CHANGELOG index a2fcfba3a..bd21e4dbc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,46 +1,11 @@ -# Requirements Update (requirements will need to be reinstalled) -Added tenacity requirement at 9.0.0 -Update lxml requirement to 5.3.0 -Update pathvalidate requirement to 3.2.1 -Update pillow requirement to 10.4.0 -Update PlexAPI requirement to 4.15.16 -Update psutil requirement to 6.0.0 -Update setuptools requirement to 74.0.0 -Update tmdbapis requirement to 1.2.21 - -# Removed Features - # New Features -Introducing the [Kometa Blog](https://blog.kometa.wiki) - a new home for all kometa-related news stories, ranging from showcasing our community creations to providing you with important updates. -Added [`letterboxd_user_lists`](https://kometa.wiki/en/latest/files/dynamic_types/#letterboxd-user-lists) Dynamic Collection Type -Added `item_analyze` item detail to analyze each item in a collection - -# Updates -F1 session naming improvements -Added new studios : Disney Television Animation, DisneyToon Studios, Dynamic Planning, Film4 Productions, Golden Harvest, Hungry Man, Screen Gems, Shaw Brothers, Studio Live, The Stone Quarry +Added the `character` search option to the `imdb_search` builder # Defaults -Fixed #2150; change xmen list to a new one -Added `A Quiet Place: Day One` to the `A Quiet Place` collection in the `franchise` Defaults file -Add `minimum_items_<>` to universe Default file -Added workaround to `Streaming` for TMDb issue with TMDb Discover +Fixed incorrect content rating mappings in various Default files # Bug Fixes -Fixed multiple anime `int()` Errors -Fixed #2100 `verify_ssl` wasn't working when downloading images -Fixed an issue with `delete_collections` where items were being deleted if they only matched one criteria vs all criteria -Fixed `imdb_watchlist` -Fixes #2135 AniDB Builder type conversion error -Fixed #2169 Add handling for blank secrets -Fixed #2176 `clean_bundles`, `optimize`, and `empty_trash` not working as global attributes -Fixed #2186 `total_runtime` will now trigger an overlay update -Fixed #2195 an image on the docs was a dead link -Fixes sort order of resolution collections -Fixes #2228 ".any" not accepted for a variety of imdb_search parameters -Fixes `streaming` defaults adding and removing items randomly -Fixes missing TMDb Discover parameters -Fixes `imdb_chart` error when using `trending_india` -Adds error information to help with #2201 -Added warning to TMDb Discover builder regarding ongoing bug with using `popularity.desc` as sort order -Various other Minor Fixes +Fixed the `cast` search option for the `imdb_search` builder +Fixes #2258 `imdb_list` sort was not being parsed correctly +Fixes `letterboxd_list` rating filter to use a 1-10 rating vs 1-100 to reflect how letterboxd ratings work on their website Fixes #2274 Enhance handling of smart collections in deletion diff --git a/VERSION b/VERSION index 7ec1d6db4..3b9295c29 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 +2.1.0-build4 diff --git a/defaults/both/content_rating_au.yml b/defaults/both/content_rating_au.yml index c90e45201..cd1b1f0f0 100644 --- a/defaults/both/content_rating_au.yml +++ b/defaults/both/content_rating_au.yml @@ -141,13 +141,13 @@ dynamic_collections: - R - 17+ (violence & profanity) - no/18 - R18 - - gb/R18 - gb/X - X - NC-17 - R+ - Mild Nudity - Rx - Hentai X18+: + - gb/R18 - au/X 18+ - de/BPjM Restricted - BPjM Restricted \ No newline at end of file diff --git a/defaults/both/content_rating_uk.yml b/defaults/both/content_rating_uk.yml index 2a186d80d..d6896190a 100644 --- a/defaults/both/content_rating_uk.yml +++ b/defaults/both/content_rating_uk.yml @@ -144,12 +144,12 @@ dynamic_collections: - R - 16 - 17 + - NC-17 - R - 17+ (violence & profanity) + - gb/X - no/18 R18: - gb/R18 - - gb/X - X - - NC-17 - R+ - Mild Nudity - Rx - Hentai \ No newline at end of file diff --git a/defaults/overlays/content_rating_au.yml b/defaults/overlays/content_rating_au.yml index a0e183902..c213281ac 100644 --- a/defaults/overlays/content_rating_au.yml +++ b/defaults/overlays/content_rating_au.yml @@ -69,12 +69,12 @@ overlays: r: template: - name: standard - - {name: cr_au, rating: "au/R 18+, de/18, gb/18, M, 18, R - 17+ (violence & profanity), no/18, R18, gb/R18, gb/X, X, NC-17, R+ - Mild Nudity, Rx - Hentai"} + - {name: cr_au, rating: "au/R 18+, de/18, gb/18, M, 18, R - 17+ (violence & profanity), no/18, R18, gb/X, X, NC-17, R+ - Mild Nudity, Rx - Hentai"} x: template: - name: standard - - {name: cr_au, rating: "au/X 18+, de/BPjM Restricted, BPjM Restricted"} + - {name: cr_au, rating: "au/X 18+, de/BPjM Restricted, BPjM Restricted, gb/R18"} nr: template: - {name: standard, key: nr} diff --git a/defaults/overlays/content_rating_uk.yml b/defaults/overlays/content_rating_uk.yml index efe0064d8..4f1bcec50 100644 --- a/defaults/overlays/content_rating_uk.yml +++ b/defaults/overlays/content_rating_uk.yml @@ -73,12 +73,12 @@ overlays: 18: template: - name: standard - - {name: cr_uk, rating: "gb/18, gb/18+, MA-17, TVMA, TV-MA, R, 16, 17, 18, R - 17+ (violence & profanity), no/18"} + - {name: cr_uk, rating: "gb/18, gb/18+, MA-17, TVMA, TV-MA, R, 16, 17, NC-17, 18, R - 17+ (violence & profanity), no/18, gb/X"} r18: template: - name: standard - - {name: cr_uk, rating: "R18, gb/R18, gb/X, X, NC-17, R+ - Mild Nudity, Rx - Hentai"} + - {name: cr_uk, rating: "R18, gb/R18, X, R+ - Mild Nudity, Rx - Hentai"} nr: template: diff --git a/docs/defaults/movie/seasonal.md b/docs/defaults/movie/seasonal.md index 869ae0ac1..e36bc3bc4 100644 --- a/docs/defaults/movie/seasonal.md +++ b/docs/defaults/movie/seasonal.md @@ -122,7 +122,7 @@ work. Any value not specified will use its default value if it has one if not it apes: Planet of the Apes Day #(4)! schedule_apes: range(11/24-11/26) #(5)! imdb_list_apes: https://www.imdb.com/list/ls005126084/ #(6)! - emoji_veteran: "🐵 " #(7)! + emoji_apes: "🐵 " #(7)! ``` 1. Do not create the "Independence Day" collection diff --git a/docs/files/builders/imdb.md b/docs/files/builders/imdb.md index fa62b3b54..f9c6ef50c 100644 --- a/docs/files/builders/imdb.md +++ b/docs/files/builders/imdb.md @@ -276,6 +276,7 @@ The `sync_mode: sync` and `collection_order: custom` Setting are recommended sin | `cast` | Item must have all the given cast members. Can be a comma-separated list.
**Options:** Any IMDb Person ID (ex. `nm0000138`) | | `cast.any` | Item must have any of the given cast members. Can be a comma-separated list.
**Options:** Any IMDb Person ID (ex. `nm0000138`) | | `cast.not` | Item must not have any of the given cast members. Can be a comma-separated list.
**Options:** Any IMDb Person ID (ex. `nm0000138`) | +| `character` | Item must have any of the given character listed in its credits. Can be a comma-separated list.
**Options:** Any String | | `runtime.gte` | Item must have a Runtime greater than or equal to the given number.
**Options:** Any Integer greater than `0`
**Example:** `1000` | | `runtime.lte` | Item must have a Runtime less than or equal to the given number.
**Options:** Any Integer greater than `0`
**Example:** `1000` | | `adult` | Include adult titles in the search results.
**Options:** `true`/`false` | diff --git a/docs/files/builders/letterboxd.md b/docs/files/builders/letterboxd.md index a9911af98..05dcd126f 100644 --- a/docs/files/builders/letterboxd.md +++ b/docs/files/builders/letterboxd.md @@ -40,14 +40,16 @@ collections: You can add different filters directly to this builder. -| Filter Attribute | Description | -|:---------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `limit` | **Description:** Max number of items per returned.
**Values:** number greater than `1` | -| `rating`1 | **Description:** Search for the specified rating range. The rating is the list owner's rating not site wide rating.
**Values:** range of int i.e. `80-100` | -| `year`1 | **Description:** Search for the specified year range.
**Values:** range of int i.e. `1990-1999` | -| `note`1 | **Description:** Search for the specified value in the note. The note is the list owner's note not site wide note.
**Values:** Any String | +| Filter Attribute | Description | +|:---------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `limit` | **Description:** Max number of items per returned.
**Values:** number greater than `1` | +| `rating`1 | **Description:** Search for the specified rating range. The rating is the list owner's rating not site wide rating.
**Values:** range of int i.e. `8-10` (convert Letterboxd stars to a 10 point scale) | +| `year`1 | **Description:** Search for the specified year range.
**Values:** range of int i.e. `1990-1999` | +| `note`2 | **Description:** Search for the specified value in the note. The note is the list owner's note not site wide note.
**Values:** Any String | -1 These filters only work if the URL is to the List View of the Letterboxd list. (i.e. it should have `/detail/` in the url) +1 These filters only work if the URL is to the List View of the Letterboxd list (i.e. it should have `/detail/` in the url) or to an account's Reviews (i.e. it should have `/USERNAME/films/reviews/` in the url) + +2 This filters only work if the URL is to the List View of the Letterboxd list. (i.e. it should have `/detail/` in the url) ```yaml collections: @@ -57,4 +59,4 @@ collections: year: 1990-1999 collection_order: custom sync_mode: sync -``` \ No newline at end of file +``` diff --git a/docs/index.md b/docs/index.md index 0197108c6..5fec3a5c3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,12 +1,5 @@ # - -
![Logo](assets/logo-full.png) diff --git a/docs/kometa/environmental.md b/docs/kometa/environmental.md index 778400ff6..54d84254c 100644 --- a/docs/kometa/environmental.md +++ b/docs/kometa/environmental.md @@ -55,18 +55,18 @@ different ways to specify these things. **Accepted Values:** Path to YAML config file - **Shell Flags:** `-c` or `--config` (ex. `--config /data/config.yml`) + **Shell Flags:** `-c` or `--config` (ex. `--config /some/path/to/your-config-file.yml`) - **Environment Variable:** `KOMETA_CONFIG` (ex. `KOMETA_CONFIG=/data/config.yml`) + **Environment Variable:** `KOMETA_CONFIG` (ex. `KOMETA_CONFIG=/some/path/to/your-config-file.yml`) !!! example === "Local Environment" ``` - python kometa.py --config /data/config.yml + python kometa.py --config /some/path/to/your-config-file.yml ``` === "Docker Environment" ``` - docker run -it -v "X:\Media\Kometa\config:/config:rw" kometateam/kometa --config /data/config.yml + docker run -it -v "X:\Media\Kometa\config:/config:rw" -v "Z:\some\path:/data:rw" kometateam/kometa --config /data/your-config-file.yml ``` ??? blank "Time to Run      `-t`/`--times`      `KOMETA_TIMES`" diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 7285442a3..defbed952 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -25,6 +25,10 @@ --md-code-hl-comment-color: #8b949e; } +.md-content h1, .md-content__button { + display: none; +} + table tr td code { white-space: pre; } diff --git a/json-schema/config-schema.json b/json-schema/config-schema.json index cca55d5ed..3cfd1905e 100644 --- a/json-schema/config-schema.json +++ b/json-schema/config-schema.json @@ -954,7 +954,7 @@ "properties": { "pmm": { "type": "string", - "enum": ["actor", "anilist","aspect","audio_language","bafta","based","basic","berlinale","cannes","cesar","choice","collectionless","content_rating_au","content_rating_cs","content_rating_de","content_rating_nz","content_rating_mal","content_rating_uk","content_rating_us","continent","country","decade","director","emmy","flixpatrol","franchise","genre","golden","imdb","myanimelist","network","nfr","oscars","other_chart","pca","producer","razzie","region","resolution","sag","seasonal","separator_award","separator_chart","spirit","streaming","studio","subtitle_language","sundance","tautulli","tiff","tmdb","trakt","universe","venice","writer","year"] + "enum": ["actor", "anilist","aspect","audio_language","bafta","based","basic","berlinale","cannes","cesar","choice","collectionless","content_rating_au","content_rating_cs","content_rating_de","content_rating_nz","content_rating_mal","content_rating_uk","content_rating_us","continent","country","decade","director","emmy","flixpatrol","franchise","genre","golden","imdb","letterboxd","myanimelist","network","nfr","oscars","other_chart","pca","producer","razzie","region","resolution","sag","seasonal","separator_award","separator_chart","spirit","streaming","studio","subtitle_language","sundance","tautulli","tiff","tmdb","trakt","universe","venice","writer","year"] }, "schedule": { "type": "string" @@ -979,7 +979,7 @@ "properties": { "default": { "type": "string", - "enum": ["actor", "anilist","aspect","audio_language","bafta","based","basic","berlinale","cannes","cesar","choice","collectionless","content_rating_au","content_rating_cs","content_rating_de","content_rating_nz","content_rating_mal","content_rating_uk","content_rating_us","continent","country","decade","director","emmy","flixpatrol","franchise","genre","golden","imdb","myanimelist","network","nfr","oscars","other_chart","pca","producer","razzie","region","resolution","sag","seasonal","separator_award","separator_chart","spirit","streaming","studio","subtitle_language","sundance","tautulli","tiff","tmdb","trakt","universe","venice","writer","year"] + "enum": ["actor", "anilist","aspect","audio_language","bafta","based","basic","berlinale","cannes","cesar","choice","collectionless","content_rating_au","content_rating_cs","content_rating_de","content_rating_nz","content_rating_mal","content_rating_uk","content_rating_us","continent","country","decade","director","emmy","flixpatrol","franchise","genre","golden","imdb","letterboxd","myanimelist","network","nfr","oscars","other_chart","pca","producer","razzie","region","resolution","sag","seasonal","separator_award","separator_chart","spirit","streaming","studio","subtitle_language","sundance","tautulli","tiff","tmdb","trakt","universe","venice","writer","year"] }, "schedule": { "type": "string" diff --git a/json-schema/kitchen_sink_config.yml b/json-schema/kitchen_sink_config.yml index 11753cd46..474fa088c 100644 --- a/json-schema/kitchen_sink_config.yml +++ b/json-schema/kitchen_sink_config.yml @@ -31,6 +31,7 @@ libraries: collection_files: # These files contain collections: and/or dynamic_collections attributes - default: based # collections based on a book, comic, story, video game # - file: config/metadata/overlay_label.yml # Creates collection of all items with an Overlay label (Testing only) + - default: letterboxd # 16 possible collections based on Letterboxd - default: aspect # Creates collections based on aspect ratio of media item - git: bullmoose20/movies_refresh # tells plex to refresh media items added within the last 7 days - default: separator_award # An "index card" @@ -101,6 +102,7 @@ libraries: - default: separator_chart # An "index card" - default: anilist # AniDB Charts (Popular, Trending, etc.) - default: imdb # IMDb Charts (Popular, Trending, etc.) + - default: letterboxd # Letterboxd charts/collections - default: myanimelist # MAL Charts (Popular, Trending, etc.) - default: other_chart # Other Charts (Popular, Trending, etc.) - default: tautulli # Tautulli Charts (Popular, Trending, etc.) @@ -384,6 +386,7 @@ libraries: - git: bullmoose20/money_heist # Custom metadata file for Money Heist collection_files: # These files contain collections: and/or dynamic_collections attributes - default: based # collections based on a book, comic, story, video game + - default: letterboxd # 16 possible collections based on Letterboxd # - file: config/metadata/overlay_label.yml # Creates collection of all items with an Overlay label (Testing only) - default: aspect # Creates collections based on aspect ratio of media item - git: bullmoose20/tv_refresh # Tells plex to refresh media items added within the last 7 days @@ -407,6 +410,7 @@ libraries: - default: separator_chart # An "index card" - default: anilist # AniDB Charts (Popular, Trending, etc.) - default: imdb # IMDb Charts (Popular, Trending, etc.) + - default: letterboxd # Letterboxd charts/collections - default: myanimelist # MAL Charts (Popular, Trending, etc.) - default: other_chart # Other Charts (Popular, Trending, etc.) - default: tautulli # Tautulli Charts (Popular, Trending, etc.) diff --git a/modules/builder.py b/modules/builder.py index 8d0505302..16d579a04 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -1629,7 +1629,7 @@ def _imdb(self, method_name, method_data): countries.append(str(country)) if countries: new_dictionary[lower_method] = countries - elif search_attr in ["keyword", "language", "alternate_version", "crazy_credit", "location", "goof", "plot", "quote", "soundtrack", "trivia"]: + elif search_attr in ["keyword", "language", "alternate_version", "crazy_credit", "location", "goof", "plot", "quote", "soundtrack", "trivia", "character"]: new_dictionary[lower_method] = util.parse(self.Type, search_method, search_data, datatype="lowerlist", parent=method_name) elif search_attr == "cast": casts = [] diff --git a/modules/imdb.py b/modules/imdb.py index 1e30faf4a..5e0701190 100644 --- a/modules/imdb.py +++ b/modules/imdb.py @@ -69,7 +69,8 @@ "series", "series.not", "list", "list.any", "list.not", "language", "language.any", "language.not", "language.primary", - "popularity.gte", "popularity.lte", + "popularity.gte", "popularity.lte", + "character", "cast", "cast.any", "cast.not", "runtime.gte", "runtime.lte", "adult", @@ -84,7 +85,7 @@ "year": "YEAR", "release": "RELEASE_DATE", } -sort_options = [f"{a}.{d}"for a in sort_by_options for d in ["asc", "desc"]] +sort_options = [f"{a}.{d}" for a in sort_by_options for d in ["asc", "desc"]] list_sort_by_options = { "custom": "LIST_ORDER", "popularity": "POPULARITY", @@ -95,7 +96,7 @@ "added": "DATE_ADDED", "release": "RELEASE_DATE", } -list_sort_options = [f"{a}.{d}"for a in sort_by_options for d in ["asc", "desc"]] +list_sort_options = [f"{a}.{d}" for a in list_sort_by_options for d in ["asc", "desc"]] title_type_options = { "movie": "movie", "tv_series": "tvSeries", "short": "short", "tv_episode": "tvEpisode", "tv_mini_series": "tvMiniSeries", "tv_movie": "tvMovie", "tv_special": "tvSpecial", "tv_short": "tvShort", "video_game": "videoGame", "video": "video", @@ -256,7 +257,7 @@ def validate_imdb(self, err_type, method, imdb_dicts): new_dict["limit"] = 0 if "sort_by" in dict_methods: - new_dict["sort_by"] = util.parse(err_type, dict_methods, imdb_dict, parent=method, default="custom.asc", options=list_sort_options) + new_dict["sort_by"] = util.parse(err_type, "sort_by", imdb_dict, methods=dict_methods, parent=method, default="custom.asc", options=list_sort_options) valid_lists.append(new_dict) return valid_lists @@ -303,7 +304,7 @@ def _graphql_json(self, data, list_type): "first": data["limit"] if "limit" in data and 0 < data["limit"] < page_limit else page_limit, } - def check_constraint(bases, mods, constraint, lower="", translation=None, range_name=None): + def check_constraint(bases, mods, constraint, lower="", translation=None, range_name=None, obj_name=None): if not isinstance(bases, list): bases = [bases] if range_name and not isinstance(range_name, list): @@ -318,6 +319,8 @@ def check_constraint(bases, mods, constraint, lower="", translation=None, range_ if full_attr in data: if range_name is not None: range_data[imdb_mod] = data[full_attr] + elif obj_name is not None: + out[constraint][f"{imdb_mod}{lower}"] = [{obj_name: d} for d in data[full_attr]] elif translation is None: out[constraint][f"{imdb_mod}{lower}"] = data[full_attr] elif isinstance(translation, tuple): @@ -392,7 +395,8 @@ def check_constraint(bases, mods, constraint, lower="", translation=None, range_ check_constraint("country", [("", "all"), ("any", "any"), ("not", "exclude"), ("origin", "anyPrimary")], "originCountryConstraint", lower="Countries") check_constraint("keyword", [("", "all"), ("any", "any"), ("not", "exclude")], "keywordConstraint", lower="Keywords", translation=(" ", "-")) check_constraint("language", [("", "all"), ("any", "any"), ("not", "exclude"), ("primary", "anyPrimary")], "languageConstraint", lower="Languages") - check_constraint("cast", [("", "all"), ("any", "any"), ("not", "exclude")], "creditedNameConstraint", lower="NameIds") + check_constraint("cast", [("", "all"), ("any", "any"), ("not", "exclude")], "titleCreditsConstraint", lower="Credits", obj_name="nameId") + check_constraint("character", [("", "any")], "characterConstraint", lower="CharacterNames") check_constraint("runtime", [("gte", "min"), ("lte", "max")], "runtimeConstraint", range_name="runtimeRangeMinutes") if "adult" in data and data["adult"]: diff --git a/modules/letterboxd.py b/modules/letterboxd.py index a01836603..6ff40ad9a 100644 --- a/modules/letterboxd.py +++ b/modules/letterboxd.py @@ -88,7 +88,7 @@ def validate_letterboxd_lists(self, err_type, letterboxd_lists, language): "url": util.parse(err_type, "url", letterboxd_dict, methods=dict_methods, parent="letterboxd_list").strip(), "limit": util.parse(err_type, "limit", letterboxd_dict, methods=dict_methods, datatype="int", parent="letterboxd_list", default=0) if "limit" in dict_methods else 0, "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, + "rating": util.parse(err_type, "rating", letterboxd_dict, methods=dict_methods, datatype="int", parent="letterboxd_list", maximum=10, 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):