diff --git a/VERSION b/VERSION
index 5479faaa..7fc35385 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.16.2-develop33
+1.16.2-develop34
diff --git a/docs/metadata/builders/trakt.md b/docs/metadata/builders/trakt.md
index 8792eff0..8d619c96 100644
--- a/docs/metadata/builders/trakt.md
+++ b/docs/metadata/builders/trakt.md
@@ -4,31 +4,14 @@ You can find items using the features of [Trakt.tv](https://trakt.tv/) (Trakt).
[Configuring Trakt](../../config/trakt) in the config is required for any of these builders.
-| Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort |
-|:---------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:|
-| [`trakt_list`](#trakt-list) | Finds every item in the Trakt List | ✅ | ✅ | ✅ |
-| [`trakt_list_details`](#trakt-list) | Finds every item in the Trakt List and updates the collection summary with the list description | ✅ | ✅ | ✅ |
-| [`trakt_watchlist`](#trakt-user-watchlist) | Finds every item in a Users Watchlist | ✅ | ✅ | ✅ |
-| [`trakt_collection`](#trakt-user-collection) | Finds every item in a Users Collection | ✅ | ✅ | ✅ |
-| [`trakt_trending`](#trakt-trending) | Finds the movies/shows in Trakt's Trending [Movies](https://trakt.tv/movies/trending)/[Shows](https://trakt.tv/shows/trending) list | ✅ | ✅ | ✅ |
-| [`trakt_popular`](#trakt-popular) | Finds the movies/shows in Trakt's Popular [Movies](https://trakt.tv/movies/popular)/[Shows](https://trakt.tv/shows/popular) list | ✅ | ✅ | ✅ |
-| [`trakt_recommended_personal`](#trakt-recommended) | Finds the movies/shows in Trakt's Personal Recommendations for your User [Movies](https://trakt.docs.apiary.io/#reference/recommendations/movies/get-movie-recommendations)/[Shows](https://trakt.docs.apiary.io/#reference/recommendations/shows/get-show-recommendations) | ✅ | ✅ | ✅ |
-| [`trakt_recommended_daily`](#trakt-recommended) | Finds the movies/shows in Trakt's Daily Recommended [Movies](https://trakt.tv/movies/recommended/daily)/[Shows](https://trakt.tv/shows/recommended/daily) list | ✅ | ✅ | ✅ |
-| [`trakt_recommended_weekly`](#trakt-recommended) | Finds the movies/shows in Trakt's Weekly Recommended [Movies](https://trakt.tv/movies/recommended/weekly)/[Shows](https://trakt.tv/shows/recommended/weekly) list | ✅ | ✅ | ✅ |
-| [`trakt_recommended_monthly`](#trakt-recommended) | Finds the movies/shows in Trakt's Monthly Recommended [Movies](https://trakt.tv/movies/recommended/monthly)/[Shows](https://trakt.tv/shows/recommended/monthly) list | ✅ | ✅ | ✅ |
-| [`trakt_recommended_yearly`](#trakt-recommended) | Finds the movies/shows in Trakt's Yearly Recommended [Movies](https://trakt.tv/movies/recommended/yearly)/[Shows](https://trakt.tv/shows/recommended/yearly) list | ✅ | ✅ | ✅ |
-| [`trakt_recommended_all`](#trakt-recommended) | Finds the movies/shows in Trakt's All-Time Recommended [Movies](https://trakt.tv/movies/recommended/all)/[Shows](https://trakt.tv/shows/recommended/all) list | ✅ | ✅ | ✅ |
-| [`trakt_watched_daily`](#trakt-watched) | Finds the movies/shows in Trakt's Daily Watched [Movies](https://trakt.tv/movies/watched/daily)/[Shows](https://trakt.tv/shows/watched/daily) list | ✅ | ✅ | ✅ |
-| [`trakt_watched_weekly`](#trakt-watched) | Finds the movies/shows in Trakt's Weekly Watched [Movies](https://trakt.tv/movies/watched/weekly)/[Shows](https://trakt.tv/shows/watched/weekly) list | ✅ | ✅ | ✅ |
-| [`trakt_watched_monthly`](#trakt-watched) | Finds the movies/shows in Trakt's Monthly Watched [Movies](https://trakt.tv/movies/watched/monthly)/[Shows](https://trakt.tv/shows/watched/monthly) list | ✅ | ✅ | ✅ |
-| [`trakt_watched_yearly`](#trakt-watched) | Finds the movies/shows in Trakt's Yearly Watched [Movies](https://trakt.tv/movies/watched/yearly)/[Shows](https://trakt.tv/shows/watched/yearly) list | ✅ | ✅ | ✅ |
-| [`trakt_watched_all`](#trakt-watched) | Finds the movies/shows in Trakt's All-Time Watched [Movies](https://trakt.tv/movies/watched/all)/[Shows](https://trakt.tv/shows/watched/all) list | ✅ | ✅ | ✅ |
-| [`trakt_collected_daily`](#trakt-collected) | Finds the movies/shows in Trakt's Daily Collected [Movies](https://trakt.tv/movies/collected/daily)/[Shows](https://trakt.tv/shows/collected/daily) list | ✅ | ✅ | ✅ |
-| [`trakt_collected_weekly`](#trakt-collected) | Finds the movies/shows in Trakt's Weekly Collected [Movies](https://trakt.tv/movies/collected/weekly)/[Shows](https://trakt.tv/shows/collected/weekly) list | ✅ | ✅ | ✅ |
-| [`trakt_collected_monthly`](#trakt-collected) | Finds the movies/shows in Trakt's Monthly Collected [Movies](https://trakt.tv/movies/collected/monthly)/[Shows](https://trakt.tv/shows/collected/monthly) list | ✅ | ✅ | ✅ |
-| [`trakt_collected_yearly`](#trakt-collected) | Finds the movies/shows in Trakt's Yearly Collected [Movies](https://trakt.tv/movies/collected/yearly)/[Shows](https://trakt.tv/shows/collected/yearly) list | ✅ | ✅ | ✅ |
-| [`trakt_collected_all`](#trakt-collected) | Finds the movies/shows in Trakt's All-Time Collected [Movies](https://trakt.tv/movies/collected/all)/[Shows](https://trakt.tv/shows/collected/all) list | ✅ | ✅ | ✅ |
-| [`trakt_boxoffice`](#trakt-box-office) | Finds the 10 movies in Trakt's Top Box Office [Movies](https://trakt.tv/movies/boxoffice) list | ✅ | ❌ | ✅ |
+| Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort |
+|:--------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------:|:----------------:|:------------------------------------:|
+| [`trakt_list`](#trakt-list) | Finds every movie/show in the Trakt List | ✅ | ✅ | ✅ |
+| [`trakt_list_details`](#trakt-list) | Finds every movie/show in the Trakt List and updates the collection summary with the list description | ✅ | ✅ | ✅ |
+| [`trakt_chart`](#trakt-chart) | Finds the movies/shows in the Trakt Chart | ✅ | ✅ | ✅ |
+| [`trakt_userlist`](#trakt-userlist) | Finds every movie/show in the Trakt Userlist | ✅ | ✅ | ✅ |
+| [`trakt_recommendations`](#trakt-recommendations) | Finds the movies/shows in Trakt's Personal Recommendations for your User [Movies](https://trakt.docs.apiary.io/#reference/recommendations/movies/get-movie-recommendations)/[Shows](https://trakt.docs.apiary.io/#reference/recommendations/shows/get-show-recommendations) | ✅ | ✅ | ✅ |
+| [`trakt_boxoffice`](#trakt-box-office) | Finds the 10 movies in Trakt's Top Box Office [Movies](https://trakt.tv/movies/boxoffice) list | ✅ | ❌ | ✅ |
## Trakt List
@@ -38,6 +21,8 @@ The expected input is a Trakt List URL. Multiple values are supported only as a
The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
+**Trakt Lists cannot be sorted through the API, but the list is always returned to the default list order if you own the list.**
+
```yaml
collections:
Christmas:
@@ -65,131 +50,92 @@ collections:
sync_mode: sync
```
-## Trakt User Watchlist
+## Trakt Chart
-Finds every item in a Users Watchlist.
+Finds the movies/shows in the Trakt Chart. The options are detailed below.
-The expected input is a user's Trakt Username or `me`. Multiple values are supported as either a list or a comma-separated string.
+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.
+| Attribute | Description & Values |
+|:--------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `chart` | **Description:** Which Trakt chart to query
**Values:**
`trending` | Trakt's Trending [Movies](https://trakt.tv/movies/trending)/[Shows](https://trakt.tv/shows/trending) list |
`popular` | Trakt's Popular [Movies](https://trakt.tv/movies/popular)/[Shows](https://trakt.tv/shows/popular) list |
`recommended` | Trakt's Recommended [Movies](https://trakt.tv/movies/recommended)/[Shows](https://trakt.tv/shows/recommended) list |
`watched` | Trakt's Watched [Movies](https://trakt.tv/movies/watched)/[Shows](https://trakt.tv/shows/watched) list |
`collected` | Trakt's Collected [Movies](https://trakt.tv/movies/collected)/[Shows](https://trakt.tv/shows/collected) list |
|
+| `time_period` | **Description:** Time Period for the chart. Does not work with `trending` or `popular` chart types.
**Default:** `weekly`
**Values:** `daily`, `weekly`, `monthly`, `yearly`, or `all` |
+| `limit` | **Description:** Don't return more then this number
**Default:** `10`
**Values:** Number of Items to query. |
-```yaml
-collections:
- Trakt Watchlist:
- trakt_watchlist: me
- collection_order: custom
- sync_mode: sync
-```
-
-## Trakt User Collection
+These are the links to the trakt charts that is looked at by time period.
-Finds every item in a Users Collection.
-
-The expected input is a user's Trakt Username or `me`. Multiple values are supported as either a list or a comma-separated string.
-
-The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
-
-```yaml
-collections:
- Trakt Collection:
- trakt_collection:
- - me
- - traktbuddy
- sync_mode: sync
-```
-
-## Trakt Trending
-
-Finds the movies/shows in Trakt's Trending [Movies](https://trakt.tv/movies/trending)/[Shows](https://trakt.tv/shows/trending) list.
-
-The expected input is a single integer value of how many movies/shows to query.
-
-The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
+| Period | Collected | Recommended | Watched |
+|:---------|:-----------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------:|
+| Daily | [Movies](https://trakt.tv/movies/collected/daily)/[Shows](https://trakt.tv/shows/collected/daily) | [Movies](https://trakt.tv/movies/recommended/daily)/[Shows](https://trakt.tv/shows/recommended/daily) | [Movies](https://trakt.tv/movies/watched/daily)/[Shows](https://trakt.tv/shows/watched/daily) |
+| Weekly | [Movies](https://trakt.tv/movies/collected/weekly)/[Shows](https://trakt.tv/shows/collected/weekly) | [Movies](https://trakt.tv/movies/recommended/weekly)/[Shows](https://trakt.tv/shows/recommended/weekly) | [Movies](https://trakt.tv/movies/watched/weekly)/[Shows](https://trakt.tv/shows/watched/weekly) |
+| Monthly | [Movies](https://trakt.tv/movies/collected/monthly)/[Shows](https://trakt.tv/shows/collected/monthly) | [Movies](https://trakt.tv/movies/recommended/monthly)/[Shows](https://trakt.tv/shows/recommended/monthly) | [Movies](https://trakt.tv/movies/watched/monthly)/[Shows](https://trakt.tv/shows/watched/monthly) |
+| Yearly | [Movies](https://trakt.tv/movies/collected/yearly)/[Shows](https://trakt.tv/shows/collected/yearly) | [Movies](https://trakt.tv/movies/recommended/yearly)/[Shows](https://trakt.tv/shows/recommended/yearly) | [Movies](https://trakt.tv/movies/watched/yearly)/[Shows](https://trakt.tv/shows/watched/yearly) |
+| All-Time | [Movies](https://trakt.tv/movies/collected/all)/[Shows](https://trakt.tv/shows/collected/all) | [Movies](https://trakt.tv/movies/recommended/all)/[Shows](https://trakt.tv/shows/recommended/all) | [Movies](https://trakt.tv/movies/watched/all)/[Shows](https://trakt.tv/shows/watched/all) |
```yaml
collections:
Trakt Trending:
- trakt_trending: 30
+ trakt_chart:
+ chart: trending
+ limit: 30
collection_order: custom
sync_mode: sync
```
-## Trakt Popular
-
-Finds the movies/shows in Trakt's Popular [Movies](https://trakt.tv/movies/popular)/[Shows](https://trakt.tv/shows/popular) list.
-
-The expected input is a single integer value of how many movies/shows to query.
-
-The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
+You can use multiple charts in one builder using a list.
```yaml
collections:
- Trakt Popular:
- trakt_popular: 30
+ Trakt Trending & Popular:
+ trakt_chart:
+ - chart: trending
+ limit: 30
+ - chart: popular
+ limit: 30
collection_order: custom
sync_mode: sync
```
-## Trakt Recommended
+## Trakt Userlist
-Finds the movies/shows in Trakt's Recommended lists.
+Finds every movie/show in the Trakt Userlist.
-| Builder | Period | Movie List | Show List |
-|:-----------------------------|:--------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|
-| `trakt_recommended_personal` | Custom | [Movies](https://trakt.docs.apiary.io/#reference/recommendations/movies/get-movie-recommendations) | [Shows](https://trakt.docs.apiary.io/#reference/recommendations/shows/get-show-recommendations) |
-| `trakt_recommended_daily` | Daily | [Daily Movies](https://trakt.tv/movies/recommended/daily) | [Daily Shows](https://trakt.tv/shows/recommended/daily) |
-| `trakt_recommended_weekly` | Weekly | [Weekly Movies](https://trakt.tv/movies/recommended/weekly) | [Weekly Shows](https://trakt.tv/shows/recommended/weekly) |
-| `trakt_recommended_monthly` | Monthly | [Monthly Movies](https://trakt.tv/movies/recommended/monthly) | [Monthly Shows](https://trakt.tv/shows/recommended/monthly) |
-| `trakt_recommended_yearly` | Yearly | [Yearly Movies](https://trakt.tv/movies/recommended/yearly) | [Yearly Shows](https://trakt.tv/shows/recommended/yearly) |
-| `trakt_recommended_all` | All-Time | [All-Time Movies](https://trakt.tv/movies/recommended/all) | [All-Time Shows](https://trakt.tv/shows/recommended/all) |
+The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
-The expected input is a single integer value of how many movies/shows to query.
-
-The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
+| Attribute | Description & Values |
+|:-----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `userlist` | **Description:** Which Trakt userlist to query
**Values:**`trending` | Trakt's Trending [Movies](https://trakt.tv/movies/trending)/[Shows](https://trakt.tv/shows/trending) list |
`popular` | Trakt's Popular [Movies](https://trakt.tv/movies/popular)/[Shows](https://trakt.tv/shows/popular) list |
`recommended` | Trakt's Recommended [Movies](https://trakt.tv/movies/recommended)/[Shows](https://trakt.tv/shows/recommended) list |
`watched` | Trakt's Watched [Movies](https://trakt.tv/movies/watched)/[Shows](https://trakt.tv/shows/watched) list |
`collected` | Trakt's Collected [Movies](https://trakt.tv/movies/collected)/[Shows](https://trakt.tv/shows/collected) list |
|
+| `user` | **Description:** The User who's user lists you want to query.
**Default:** `me`
**Values:** Username of User or `me` for the authenticated user. |
+| `sort_by` | **Description:** How to sort the results
**Default:** `rank`
**Values:** `rank`, `added`, `released`, `title` |
```yaml
collections:
- Trakt Recommended:
- trakt_recommended_weekly: 30
+ Trakt Watchlist:
+ trakt_userlist:
+ userlist: watchlist
+ user: me
+ sort_by: released
collection_order: custom
sync_mode: sync
```
-## Trakt Watched
-
-Finds the movies/shows in Trakt's Watched lists.
-
-| Builder | Period | Movie List | Show List |
-|:------------------------|:--------:|:---------------------------------------------------------:|:-------------------------------------------------------:|
-| `trakt_watched_daily` | Daily | [Daily Movies](https://trakt.tv/movies/watched/daily) | [Daily Shows](https://trakt.tv/shows/watched/daily) |
-| `trakt_watched_weekly` | Weekly | [Weekly Movies](https://trakt.tv/movies/watched/weekly) | [Weekly Shows](https://trakt.tv/shows/watched/weekly) |
-| `trakt_watched_monthly` | Monthly | [Monthly Movies](https://trakt.tv/movies/watched/monthly) | [Monthly Shows](https://trakt.tv/shows/watched/monthly) |
-| `trakt_watched_yearly` | Yearly | [Yearly Movies](https://trakt.tv/movies/watched/yearly) | [Yearly Shows](https://trakt.tv/shows/watched/yearly) |
-| `trakt_watched_all` | All-Time | [All-Time Movies](https://trakt.tv/movies/watched/all) | [All-Time Shows](https://trakt.tv/shows/watched/all) |
-
-The expected input is a single integer value of how many movies/shows to query.
-
-The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.
+You can use multiple charts in one builder using a list.
```yaml
collections:
- Trakt Watched:
- trakt_watched_weekly: 30
+ Trakt Watchlist:
+ trakt_userlist:
+ - userlist: watched
+ user: me
+ - userlist: collected
+ user: me
collection_order: custom
sync_mode: sync
```
-## Trakt Collected
+## Trakt Recommendations
-Finds the movies/shows in Trakt's Collected [Movies](https://trakt.tv/movies/collected/weekly)/[Shows](https://trakt.tv/shows/collected/weekly) list.
-
-| Builder | Period | Movie List | Show List |
-|:--------------------------|:--------:|:-----------------------------------------------------------:|:---------------------------------------------------------:|
-| `trakt_collected_daily` | Daily | [Daily Movies](https://trakt.tv/movies/collected/daily) | [Daily Shows](https://trakt.tv/shows/collected/daily) |
-| `trakt_collected_weekly` | Weekly | [Weekly Movies](https://trakt.tv/movies/collected/weekly) | [Weekly Shows](https://trakt.tv/shows/collected/weekly) |
-| `trakt_collected_monthly` | Monthly | [Monthly Movies](https://trakt.tv/movies/collected/monthly) | [Monthly Shows](https://trakt.tv/shows/collected/monthly) |
-| `trakt_collected_yearly` | Yearly | [Yearly Movies](https://trakt.tv/movies/collected/yearly) | [Yearly Shows](https://trakt.tv/shows/collected/yearly) |
-| `trakt_collected_all` | All-Time | [All-Time Movies](https://trakt.tv/movies/collected/all) | [All-Time Shows](https://trakt.tv/shows/collected/all) |
+Finds the movies/shows in Trakt's Recommendations for [Movies](https://trakt.docs.apiary.io/#reference/recommendations/movies/get-movie-recommendations)/[Shows](https://trakt.docs.apiary.io/#reference/recommendations/shows/get-show-recommendations)
The expected input is a single integer value of how many movies/shows to query.
@@ -197,8 +143,8 @@ The `sync_mode: sync` and `collection_order: custom` Details are recommended sin
```yaml
collections:
- Trakt Collected:
- trakt_collected_weekly: 30
+ Trakt Recommendations:
+ trakt_recommendations: 30
collection_order: custom
sync_mode: sync
```
diff --git a/docs/metadata/dynamic.md b/docs/metadata/dynamic.md
index 9e21c1cc..398d098d 100644
--- a/docs/metadata/dynamic.md
+++ b/docs/metadata/dynamic.md
@@ -120,7 +120,7 @@ Depending on the `type` of dynamic collection, `data` is used to specify the opt
| [`genre`](#genre) | Create a collection for each genre found in the library | ❌ | ✅ | ✅ | ✅ | ✅ |
| [`content_rating`](#content-rating) | Create a collection for each content rating found in the library | ❌ | ✅ | ✅ | ❌ | ✅ |
| [`year`](#year) | Create a collection for each year found in the library | ❌ | ✅ | ✅ | ❌ | ❌ |
-| [`decade`](#decade) | Create a collection for each decade found in the library | ❌ | ✅ | ❌ | ❌ | ❌ |
+| [`decade`](#decade) | Create a collection for each decade found in the library | ❌ | ✅ | ✅ | ❌ | ❌ |
| [`country`](#country) | Create a collection for each country found in the library | ❌ | ✅ | ❌ | ✅ | ✅ |
| [`resolution`](#resolution) | Create a collection for each resolution found in the library | ❌ | ✅ | ✅ | ❌ | ❌ |
| [`subtitle_language`](#subtitle-language) | Create a collection for each subtitle language found in the library | ❌ | ✅ | ✅ | ❌ | ❌ |
@@ -1585,7 +1585,6 @@ Defines how multiple `keys` can be combined under a parent key.
For example, the `addons` attribute can be used to combine multiple `keys`, i.e. merging "MTV2", "MTV3" and "MTV (UK)" into the "MTV" collection.
-
```yaml
dynamic_collections:
networks:
@@ -1597,6 +1596,8 @@ dynamic_collections:
- MTV (UK)
```
+You can also define custom keys under addons if the main key doesn't exist as a key it will be considered a custom key combining all keys into one key.
+
## Template
Name of the template to use for these dynamic collections. Each `type` has its own default template, but if you want to define and use your own template you can.
diff --git a/modules/builder.py b/modules/builder.py
index b0139667..67c40ccf 100644
--- a/modules/builder.py
+++ b/modules/builder.py
@@ -47,6 +47,7 @@ method_alias = {
"trakt_recommended": "trakt_recommended_weekly", "trakt_watched": "trakt_watched_weekly", "trakt_collected": "trakt_collected_weekly",
"collection_changes_webhooks": "changes_webhooks",
"radarr_add": "radarr_add_missing", "sonarr_add": "sonarr_add_missing",
+ "trakt_recommended_personal": "trakt_recommendations"
}
filter_translation = {
"record_label": "studio",
@@ -745,7 +746,7 @@ class CollectionBuilder:
elif method_name == "tvdb_description":
self.summaries[method_name] = self.config.TVDb.get_list_description(method_data)
elif method_name == "trakt_description":
- self.summaries[method_name] = self.config.Trakt.list_description(self.config.Trakt.validate_trakt(method_data, self.library.is_movie)[0])
+ self.summaries[method_name] = self.config.Trakt.list_description(self.config.Trakt.validate_list(method_data, self.library.is_movie)[0])
elif method_name == "letterboxd_description":
self.summaries[method_name] = self.config.Letterboxd.get_list_description(method_data, self.language)
elif method_name == "icheckmovies_description":
@@ -1068,7 +1069,7 @@ class CollectionBuilder:
else:
raise Failed(f"{self.Type} Error: imdb_id {value} must begin with tt")
elif method_name == "imdb_list":
- for imdb_dict in self.config.IMDb.validate_imdb_lists(method_data, self.language):
+ for imdb_dict in self.config.IMDb.validate_imdb_lists(self.Type, method_data, self.language):
self.builders.append((method_name, imdb_dict))
elif method_name == "imdb_chart":
for value in util.get_list(method_data):
@@ -1265,21 +1266,37 @@ class CollectionBuilder:
def _trakt(self, method_name, method_data):
if method_name.startswith("trakt_list"):
- trakt_lists = self.config.Trakt.validate_trakt(method_data, self.library.is_movie)
+ trakt_lists = self.config.Trakt.validate_list(method_data)
for trakt_list in trakt_lists:
self.builders.append(("trakt_list", trakt_list))
if method_name.endswith("_details"):
self.summaries[method_name] = self.config.Trakt.list_description(trakt_lists[0])
- elif method_name in ["trakt_watchlist", "trakt_collection"]:
- for trakt_list in self.config.Trakt.validate_trakt(method_data, self.library.is_movie, trakt_type=method_name[6:]):
- self.builders.append((method_name, trakt_list))
elif method_name == "trakt_boxoffice":
if util.parse(self.Type, method_name, method_data, datatype="bool", default=False):
self.builders.append((method_name, 10))
else:
raise Failed(f"{self.Type} Error: {method_name} must be set to true")
+ elif method_name == "trakt_recommendations":
+ self.builders.append((method_name, util.parse(self.Type, method_name, method_data, datatype="int", default=10, maximum=100)))
elif method_name in trakt.builders:
- self.builders.append((method_name, util.parse(self.Type, method_name, method_data, datatype="int", default=10)))
+ if method_name in ["trakt_chart", "trakt_userlist"]:
+ trakt_dicts = method_data
+ final_method = method_name
+ elif method_name in ["trakt_watchlist", "trakt_collection"]:
+ trakt_dicts = []
+ for trakt_user in util.get_list(method_data, split=False):
+ trakt_dicts.append({"userlist": "watchlist" if "trakt_watchlist" else "collected", "user": trakt_user})
+ final_method = "trakt_userlist"
+ else:
+ terms = method_name.split("_")
+ trakt_dicts = {
+ "chart": terms[1],
+ "amount": util.parse(self.Type, method_name, method_data, datatype="int", default=10),
+ "time_period": terms[2] if len(terms) > 2 else None
+ }
+ final_method = "trakt_chart"
+ for trakt_dict in self.config.Trakt.validate_chart(final_method, trakt_dicts, self.language):
+ self.builders.append((method_name, trakt_dict))
def _tvdb(self, method_name, method_data):
values = util.get_list(method_data)
diff --git a/modules/imdb.py b/modules/imdb.py
index 10b1cafe..48bc8f7a 100644
--- a/modules/imdb.py
+++ b/modules/imdb.py
@@ -31,16 +31,16 @@ class IMDb:
def __init__(self, config):
self.config = config
- def validate_imdb_lists(self, imdb_lists, language):
+ def validate_imdb_lists(self, err_type, imdb_lists, language):
valid_lists = []
for imdb_dict in util.get_list(imdb_lists, split=False):
if not isinstance(imdb_dict, dict):
imdb_dict = {"url": imdb_dict}
dict_methods = {dm.lower(): dm for dm in imdb_dict}
if "url" not in dict_methods:
- raise Failed(f"Collection Error: imdb_list url attribute not found")
+ raise Failed(f"{err_type} Error: imdb_list url attribute not found")
elif imdb_dict[dict_methods["url"]] is None:
- raise Failed(f"Collection Error: imdb_list url attribute is blank")
+ raise Failed(f"{err_type} Error: imdb_list url attribute is blank")
else:
imdb_url = imdb_dict[dict_methods["url"]].strip()
if not imdb_url.startswith(tuple([v for k, v in urls.items()])):
@@ -50,7 +50,7 @@ class IMDb:
list_count = None
if "limit" in dict_methods:
if imdb_dict[dict_methods["limit"]] is None:
- logger.warning(f"Collection Warning: imdb_list limit attribute is blank using 0 as default")
+ logger.warning(f"{err_type} Warning: imdb_list limit attribute is blank using 0 as default")
else:
try:
value = int(str(imdb_dict[dict_methods["limit"]]))
@@ -59,7 +59,7 @@ class IMDb:
except ValueError:
pass
if list_count is None:
- logger.warning(f"Collection Warning: imdb_list limit attribute must be an integer 0 or greater using 0 as default")
+ logger.warning(f"{err_type} Warning: imdb_list limit attribute must be an integer 0 or greater using 0 as default")
if list_count is None:
list_count = 0
valid_lists.append({"url": imdb_url, "limit": list_count})
diff --git a/modules/meta.py b/modules/meta.py
index 506aa9de..f3796332 100644
--- a/modules/meta.py
+++ b/modules/meta.py
@@ -266,19 +266,14 @@ class MetadataFile(DataFile):
auto_type = dynamic[methods["type"]].lower()
og_exclude = util.parse("Config", "exclude", dynamic, parent=map_name, methods=methods, datatype="strlist") if "exclude" in methods else []
include = util.parse("Config", "include", dynamic, parent=map_name, methods=methods, datatype="strlist") if "include" in methods else []
- custom_keys = util.parse("Config", "custom_keys", dynamic, parent=map_name, methods=methods, datatype="dictliststr") if "custom_keys" in methods else {}
if og_exclude and include:
raise Failed(f"Config Error: {map_name} cannot have both include and exclude attributes")
addons = util.parse("Config", "addons", dynamic, parent=map_name, methods=methods, datatype="dictliststr") if "addons" in methods else {}
exclude = [str(e) for e in og_exclude]
- for custom_key, combined_keys in custom_keys.items():
- for combined_key in combined_keys:
- if combined_key not in exclude:
- exclude.append(combined_key)
for k, v in addons.items():
if k in v:
- logger.warning(f"Config Warning: {k} cannot be an addon for itself")
- exclude.extend([y for y in v if y != k])
+ raise Failed(f"Config Warning: {k} cannot be an addon for itself")
+ exclude.extend([y for y in v if y != k and y not in exclude])
default_title_format = "<>"
default_template = None
auto_list = {}
@@ -409,9 +404,9 @@ class MetadataFile(DataFile):
elif auto_type == "trakt_user_lists":
dynamic_data = util.parse("Config", "data", dynamic, parent=map_name, methods=methods, datatype="list")
for option in dynamic_data:
- _check_dict(self.config.Trakt.get_user_lists(option))
+ _check_dict(self.config.Trakt.all_user_lists(option))
elif auto_type == "trakt_liked_lists":
- _check_dict(self.config.Trakt.get_liked_lists())
+ _check_dict(self.config.Trakt.all_liked_lists())
elif auto_type == "tmdb_popular_people":
dynamic_data = util.parse("Config", "data", dynamic, parent=map_name, methods=methods, datatype="int", minimum=1)
_check_dict(self.config.TMDb.get_popular_people(dynamic_data))
@@ -421,15 +416,16 @@ class MetadataFile(DataFile):
_check_dict(self.config.Trakt.get_people(option))
else:
raise Failed(f"Config Error: {map_name} type attribute {dynamic[methods['type']]} invalid")
- for custom_key, combined_keys in custom_keys.items():
- if custom_key in all_keys:
- raise Failed(f"Config Error: Custom key: {custom_key} cannot be an actual key")
- final_keys = [ck for ck in combined_keys if ck in all_keys]
- if final_keys:
- if include:
- include.append(custom_key)
- auto_list[custom_key] = custom_key
- addons[custom_key] = final_keys
+ for add_key, combined_keys in addons.items():
+ if add_key not in all_keys:
+ final_keys = [ck for ck in combined_keys if ck in all_keys]
+ if final_keys:
+ if include:
+ include.append(add_key)
+ auto_list[add_key] = add_key
+ addons[add_key] = final_keys
+ else:
+ logger.warning(f"Config Error: {add_key} Custom Key must have at least one Key")
title_format = default_title_format
if "title_format" in methods:
title_format = util.parse("Config", "title_format", dynamic, parent=map_name, methods=methods, default=default_title_format)
@@ -466,7 +462,6 @@ class MetadataFile(DataFile):
logger.debug(f"Data: {dynamic_data}")
logger.debug(f"Exclude: {exclude}")
logger.debug(f"Addons: {addons}")
- logger.debug(f"Custom Keys: {custom_keys}")
logger.debug(f"Template: {template_name}")
logger.debug(f"Template Variables: {template_variables}")
logger.debug(f"Remove Prefix: {remove_prefix}")
diff --git a/modules/trakt.py b/modules/trakt.py
index 1167220d..6de5d222 100644
--- a/modules/trakt.py
+++ b/modules/trakt.py
@@ -8,15 +8,17 @@ logger = util.logger
redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
base_url = "https://api.trakt.tv"
builders = [
+ "trakt_list", "trakt_list_details", "trakt_chart", "trakt_userlist", "trakt_boxoffice", "trakt_recommendations",
"trakt_collected_daily", "trakt_collected_weekly", "trakt_collected_monthly", "trakt_collected_yearly", "trakt_collected_all",
- "trakt_recommended_personal", "trakt_recommended_daily", "trakt_recommended_weekly", "trakt_recommended_monthly", "trakt_recommended_yearly", "trakt_recommended_all",
+ "trakt_recommended_daily", "trakt_recommended_weekly", "trakt_recommended_monthly", "trakt_recommended_yearly", "trakt_recommended_all",
"trakt_watched_daily", "trakt_watched_weekly", "trakt_watched_monthly", "trakt_watched_yearly", "trakt_watched_all",
- "trakt_collection", "trakt_list", "trakt_list_details", "trakt_popular", "trakt_trending", "trakt_watchlist", "trakt_boxoffice"
+ "trakt_collection", "trakt_popular", "trakt_trending", "trakt_watchlist"
]
sorts = [
"rank", "added", "title", "released", "runtime", "popularity",
"percentage", "votes", "random", "my_rating", "watched", "collected"
]
+periods = ["daily", "weekly", "monthly", "yearly", "all"]
id_translation = {"movie": "movie", "show": "show", "season": "show", "episode": "show", "person": "person", "list": "list"}
id_types = {
"movie": ("tmdb", "TMDb ID"),
@@ -194,16 +196,16 @@ class Trakt:
logger.error(f"Trakt Error: No {id_display} found for {name}")
return ids
- def get_user_lists(self, data):
+ def all_user_lists(self, user):
try:
- items = self._request(f"/users/{data}/lists")
+ items = self._request(f"/users/{user}/lists")
except Failed:
- raise Failed(f"Trakt Error: User {data} not found")
+ raise Failed(f"Trakt Error: User {user} not found")
if len(items) == 0:
- raise Failed(f"Trakt Error: User {data} has no lists")
- return {self.build_user_url(data, i["ids"]["slug"]): i["name"] for i in items}
+ raise Failed(f"Trakt Error: User {user} has no lists")
+ return {self.build_user_url(user, i["ids"]["slug"]): i["name"] for i in items}
- def get_liked_lists(self):
+ def all_liked_lists(self):
items = self._request(f"/users/likes/lists")
if len(items) == 0:
raise Failed(f"Trakt Error: No Liked lists found")
@@ -212,7 +214,7 @@ class Trakt:
def build_user_url(self, user, name):
return f"{base_url.replace('api.', '')}/users/{user}/lists/{name}"
- def _user_list(self, data):
+ def _list(self, data):
try:
items = self._request(f"{requests.utils.urlparse(data).path}/items")
except Failed:
@@ -221,70 +223,94 @@ class Trakt:
raise Failed(f"Trakt Error: List {data} is empty")
return self._parse(items)
- def _user_items(self, list_type, data, is_movie):
+ def _userlist(self, list_type, user, is_movie, sort_by=None):
try:
- items = self._request(f"/users/{data}/{list_type}/{'movies' if is_movie else 'shows'}")
+ url_end = "movies" if is_movie else "shows"
+ if sort_by:
+ url_end = f"{url_end}/{sort_by}"
+ items = self._request(f"/users/{user}/{list_type}/{url_end}")
except Failed:
- raise Failed(f"Trakt Error: User {data} not found")
+ raise Failed(f"Trakt Error: User {user} not found")
if len(items) == 0:
- raise Failed(f"Trakt Error: {data}'s {list_type.capitalize()} is empty")
+ raise Failed(f"Trakt Error: {user}'s {list_type.capitalize()} is empty")
return self._parse(items, item_type="movie" if is_movie else "show")
- def _user_recommendations(self, amount, is_movie):
+ def _recommendations(self, limit, is_movie):
media_type = "Movie" if is_movie else "Show"
try:
- items = self._request(f"/recommendations/{'movies' if is_movie else 'shows'}/?limit={amount}")
+ items = self._request(f"/recommendations/{'movies' if is_movie else 'shows'}/?limit={limit}")
except Failed:
raise Failed(f"Trakt Error: failed to fetch {media_type} Recommendations")
if len(items) == 0:
raise Failed(f"Trakt Error: no {media_type} Recommendations were found")
return self._parse(items, typeless=True, item_type="movie" if is_movie else "show")
- def _pagenation(self, pagenation, amount, is_movie):
- items = self._request(f"/{'movies' if is_movie else 'shows'}/{pagenation}?limit={amount}")
- return self._parse(items, typeless=pagenation == "popular", item_type="movie" if is_movie else "show")
+ def _charts(self, chart_type, limit, is_movie, time_period=None):
+ chart_url = f"{chart_type}/{time_period}" if time_period else chart_type
+ items = self._request(f"/{'movies' if is_movie else 'shows'}/{chart_url}?limit={limit}")
+ return self._parse(items, typeless=chart_type == "popular", item_type="movie" if is_movie else "show")
def get_people(self, data):
- return {str(i[0][0]): i[0][1] for i in self._user_list(data) if i[1] == "tmdb_person"}
+ return {str(i[0][0]): i[0][1] for i in self._list(data) if i[1] == "tmdb_person"}
- def validate_trakt(self, trakt_lists, is_movie, trakt_type="list"):
+ def validate_list(self, trakt_lists):
values = util.get_list(trakt_lists, split=False)
trakt_values = []
for value in values:
if isinstance(value, dict):
raise Failed("Trakt Error: List cannot be a dictionary")
try:
- if trakt_type == "list":
- self._user_list(value)
- else:
- self._user_items(trakt_type, value, is_movie)
+ self._list(value)
trakt_values.append(value)
except Failed as e:
logger.error(e)
if len(trakt_values) == 0:
- if trakt_type == "watchlist":
- raise Failed(f"Trakt Error: No valid Trakt Watchlists in {values}")
- elif trakt_type == "collection":
- raise Failed(f"Trakt Error: No valid Trakt Collections in {values}")
- else:
- raise Failed(f"Trakt Error: No valid Trakt Lists in {values}")
+ raise Failed(f"Trakt Error: No valid Trakt Lists in {values}")
return trakt_values
+ def validate_chart(self, method_name, err_type, data, is_movie):
+ valid_dicts = []
+ for trakt_dict in util.get_list(data, split=False):
+ if not isinstance(trakt_dict, dict):
+ raise Failed(f"{err_type} Error: {method_name} must be a dictionary")
+ dict_methods = {dm.lower(): dm for dm in trakt_dict}
+ try:
+ if method_name == "trakt_chart":
+ chart = util.parse(err_type, "chart", trakt_dict, methods=dict_methods, parent=method_name, options=["recommended", "watched", "collected", "trending", "popular"])
+ limit = util.parse(err_type, "limit", trakt_dict, methods=dict_methods, parent=method_name, datatype="int", default=10)
+ time_period = None
+ if chart in ["recommended", "watched", "collected"] and "time_period" in dict_methods:
+ time_period = util.parse(err_type, "time_period", trakt_dict, methods=dict_methods, parent=method_name, default="weekly", options=periods)
+ valid_dicts.append({"chart": chart, "limit": limit, "time_period": time_period})
+ else:
+ userlist = util.parse(err_type, "userlist", trakt_dict, methods=dict_methods, parent=method_name, options=["recommended", "watched", "collected", "watchlist"])
+ user = util.parse(err_type, "user", trakt_dict, methods=dict_methods, parent=method_name, default="me")
+ sort_by = None
+ if userlist in ["recommended", "watchlist"] and "sort" in dict_methods:
+ sort_by = util.parse(err_type, "sort_by", trakt_dict, methods=dict_methods, parent=method_name, default="rank", options=["rank", "added", "released", "title"])
+ self._userlist("collection" if userlist == "collected" else userlist, user, is_movie, sort_by=sort_by)
+ valid_dicts.append({"userlist": userlist, "user": user, "sort_by": sort_by})
+ except Failed as e:
+ logger.error(e)
+ if len(valid_dicts) == 0:
+ raise Failed(f"Trakt Error: No valid Trakt {method_name[6:].capitalize()}")
+ return valid_dicts
+
def get_trakt_ids(self, method, data, is_movie):
pretty = method.replace("_", " ").title()
media_type = "Movie" if is_movie else "Show"
- if method in ["trakt_collection", "trakt_watchlist"]:
- logger.info(f"Processing {pretty} {media_type}s for {data}")
- return self._user_items(method[6:], data, is_movie)
- elif method == "trakt_list":
+ if method == "trakt_list":
logger.info(f"Processing {pretty}: {data}")
- return self._user_list(data)
- elif method == "trakt_recommended_personal":
- logger.info(f"Processing {pretty}: {data} {media_type}{'' if data == 1 else 's'}")
- return self._user_recommendations(data, is_movie)
- elif method in builders:
+ return self._list(data)
+ elif method == "trakt_recommendations":
logger.info(f"Processing {pretty}: {data} {media_type}{'' if data == 1 else 's'}")
- terms = method.split("_")
- return self._pagenation(f"{terms[1]}{f'/{terms[2]}' if len(terms) > 2 else ''}", data, is_movie)
+ return self._recommendations(data, is_movie)
+ elif method == "trakt_chart":
+ chart_title = data["chart"] if data["time_period"] else f"{data['chart']} {data['time_period'].capitalize()}"
+ logger.info(f"Processing {pretty}: {chart_title} {data['chart'].capitalize()} {media_type}{'' if data == 1 else 's'}")
+ return self._charts(data["chart"], data["limit"], is_movie, time_period=data["time_period"])
+ elif method == "trakt_userlist":
+ logger.info(f"Processing {pretty} {media_type}s from {data['user']}'s {data['userlist'].capitalize()}")
+ return self._userlist(data["userlist"], data["user"], is_movie, sort_by=data["sort_by"])
else:
raise Failed(f"Trakt Error: Method {method} not supported")