mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-14 00:37:22 +00:00
v1.15.0
This commit is contained in:
parent
6c98aac971
commit
42b4666c1c
8 changed files with 140 additions and 50 deletions
92
README.md
92
README.md
|
@ -5,7 +5,7 @@
|
||||||
[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/meisnate12/plex-meta-manager?label=docker&sort=semver&style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/meisnate12/plex-meta-manager?label=docker&sort=semver&style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
||||||
[![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/meisnate12/plex-meta-manager?style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
[![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/meisnate12/plex-meta-manager?style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
||||||
[![Docker Pulls](https://img.shields.io/docker/pulls/meisnate12/plex-meta-manager?style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
[![Docker Pulls](https://img.shields.io/docker/pulls/meisnate12/plex-meta-manager?style=plastic)](https://hub.docker.com/r/meisnate12/plex-meta-manager)
|
||||||
[![Discord](https://img.shields.io/discord/822460010649878528?label=Discord&style=plastic)](https://discord.gg/TsdpsFYqqm)
|
[![Discord](https://img.shields.io/discord/822460010649878528?label=Discord&style=plastic)](https://discord.gg/NfH6mGFuAB)
|
||||||
[![Sponsor or Donate](https://img.shields.io/badge/-Sponsor_or_Donate-blueviolet?style=plastic)](https://github.com/sponsors/meisnate12)
|
[![Sponsor or Donate](https://img.shields.io/badge/-Sponsor_or_Donate-blueviolet?style=plastic)](https://github.com/sponsors/meisnate12)
|
||||||
|
|
||||||
The original concept for Plex Meta Manager is [Plex Auto Collections](https://github.com/mza921/Plex-Auto-Collections), but this is rewritten from the ground up to be able to include a scheduler, metadata edits, multiple libraries, and logging. Plex Meta Manager is a Python 3 script that can be continuously run using YAML configuration files to update on a schedule the metadata of the movies, shows, and collections in your libraries as well as automatically build collections based on various methods all detailed in the wiki. Some collection examples that the script can automatically build and update daily include Plex Based Searches like actor, genre, or studio collections or Collections based on TMDb, IMDb, Trakt, TVDb, AniDB, or MyAnimeList lists and various other services.
|
The original concept for Plex Meta Manager is [Plex Auto Collections](https://github.com/mza921/Plex-Auto-Collections), but this is rewritten from the ground up to be able to include a scheduler, metadata edits, multiple libraries, and logging. Plex Meta Manager is a Python 3 script that can be continuously run using YAML configuration files to update on a schedule the metadata of the movies, shows, and collections in your libraries as well as automatically build collections based on various methods all detailed in the wiki. Some collection examples that the script can automatically build and update daily include Plex Based Searches like actor, genre, or studio collections or Collections based on TMDb, IMDb, Trakt, TVDb, AniDB, or MyAnimeList lists and various other services.
|
||||||
|
@ -14,25 +14,95 @@ The script can update many metadata fields for movies, shows, collections, seaso
|
||||||
|
|
||||||
The script works with most Metadata agents including the New Plex Movie Agent, New Plex TV Agent, [Hama Anime Agent](https://github.com/ZeroQI/Hama.bundle), [MyAnimeList Anime Agent](https://github.com/Fribb/MyAnimeList.bundle), and [XBMC NFO Movie and TV Agents](https://github.com/gboudreau/XBMCnfoMoviesImporter.bundle).
|
The script works with most Metadata agents including the New Plex Movie Agent, New Plex TV Agent, [Hama Anime Agent](https://github.com/ZeroQI/Hama.bundle), [MyAnimeList Anime Agent](https://github.com/Fribb/MyAnimeList.bundle), and [XBMC NFO Movie and TV Agents](https://github.com/gboudreau/XBMCnfoMoviesImporter.bundle).
|
||||||
|
|
||||||
|
![Colletions1](https://raw.githubusercontent.com/wiki/meisnate12/Plex-Meta-Manager/collections1.png)
|
||||||
|
|
||||||
|
![Colletions2](https://raw.githubusercontent.com/wiki/meisnate12/Plex-Meta-Manager/collections2.png)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
1. Install Plex Meta Manager either by installing Python3 and following the [Local Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Local-Walkthrough)
|
1. Install Plex Meta Manager either by installing Python3 and following the [Local Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Local-Walkthrough)
|
||||||
or by installing Docker and following the [Docker Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Docker-Walkthrough) or the [unRAID Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/unRAID-Walkthrough).
|
or by installing Docker and following the [Docker Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Docker-Walkthrough) or the [unRAID Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/unRAID-Walkthrough).
|
||||||
2. Once installed, you have to create a [Configuration File](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Configuration-File) filled with all your values to connect to the various services.
|
2. Once installed, you have to create a [Configuration File](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Configuration-File) filled with all your values to connect to the various services.
|
||||||
3. After that you can start updating Metadata and building automatic Collections by creating a [Metadata and Playlist File](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Metadata-and-Playlist-File) for each Library you want to interact with.
|
3. After that you can start updating Metadata and building automatic Collections by creating a [Metadata File](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Metadata-and-Playlist-File) for each Library you want to interact with.
|
||||||
4. Explore the [Wiki](https://github.com/meisnate12/Plex-Meta-Manager/wiki) to see all the different Collection Builders that can be used to create collections.
|
4. Explore the [Wiki](https://github.com/meisnate12/Plex-Meta-Manager/wiki) to see all the different Collection Builders that can be used to create collections.
|
||||||
|
|
||||||
|
## Wiki
|
||||||
|
The [Wiki](https://github.com/meisnate12/Plex-Meta-Manager/wiki) details evey available option you have with Plex Meta Manager its Table of Contents is below.
|
||||||
|
|
||||||
|
## Example Community Metadata Files
|
||||||
|
To see user submitted Metadata configuration files, and you to even add your own, go to the [Plex Meta Manager Configs](https://github.com/meisnate12/Plex-Meta-Manager-Configs).
|
||||||
|
|
||||||
|
## Support Discord
|
||||||
|
Before posting on GitHub about an enhancement, error, or configuration question please visit the [Plex Meta Manager Discord Server](https://discord.gg/NfH6mGFuAB) **it is without a doubt the best place to get support**.
|
||||||
|
|
||||||
|
## Feature Requests, Errors, and Configuration Questions
|
||||||
|
* If you have an idea for how to enhance Plex Meta Manager please open a new [Feature Request](https://github.com/meisnate12/Plex-Meta-Manager/issues/new?assignees=meisnate12&labels=status%3Anot-yet-viewed%2C+enhancement&template=feature_request.md&title=Feature+Request%3A+).
|
||||||
|
* If you're getting an Error please update to the latest develop branch and then open a [Bug Report](https://github.com/meisnate12/Plex-Meta-Manager/issues/new?assignees=meisnate12&labels=status%3Anot-yet-viewed%2C+bug&template=bug_report.md&title=Bug%3A+) if it's still happening.
|
||||||
|
* If you have a metadata configuration question post in the [Discussions](https://github.com/meisnate12/Plex-Meta-Manager/discussions).
|
||||||
|
|
||||||
|
## Development Build
|
||||||
|
* There is a [develop](https://github.com/meisnate12/Plex-Meta-Manager/tree/develop) branch which will have the most updated fixes and enhancements to the script.
|
||||||
|
* to access the Docker Image for the develop branch use the `develop` tag by adding `:develop` to the image name. i.e. `meisnate12/plex-meta-manager:develop`
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
* Pull Request are welcome but please submit them to the develop branch.
|
||||||
|
* If you wish to contribute to the Wiki please fork and send a pull request on the [Plex Meta Manager Wiki Repository](https://github.com/meisnate12/Plex-Meta-Manager-Wiki).
|
||||||
|
|
||||||
## IBRACORP Video Walkthrough
|
## IBRACORP Video Walkthrough
|
||||||
|
|
||||||
[IBRACORP](https://ibracorp.io/) made a video walkthough for installing Plex Meta Manager on unRAID. While you might not be using unRAID the video goes over many key aspects of Plex Meta Manager and can be a great place to start learning how to use the script.
|
[IBRACORP](https://ibracorp.io/) made a video walkthough for installing Plex Meta Manager on unRAID. While you might not be using unRAID the video goes over many key accepts of Plex Meta Manager and can be a great place to start learning how to use the script.
|
||||||
|
|
||||||
[![Plex Meta Manager](https://img.youtube.com/vi/dF69MNoot3w/0.jpg)](https://www.youtube.com/watch?v=dF69MNoot3w "Plex Meta Manager")
|
[![Plex Meta Manager](https://img.youtube.com/vi/dF69MNoot3w/0.jpg)](https://www.youtube.com/watch?v=dF69MNoot3w "Plex Meta Manager")
|
||||||
|
|
||||||
## Support
|
## Wiki Table of Contents
|
||||||
|
- [Home](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Home)
|
||||||
* Before posting on GitHub about an enhancement, error, or configuration question please visit the [Plex Meta Manager Discord Server](https://discord.gg/TsdpsFYqqm).
|
- [Installation](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Installation)
|
||||||
* If you're getting an Error or have an Enhancement post in the [Issues](https://github.com/meisnate12/Plex-Meta-Manager/issues).
|
- [Local Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Local-Walkthrough)
|
||||||
* If you have a configuration question post in the [Discussions](https://github.com/meisnate12/Plex-Meta-Manager/discussions).
|
- [Docker Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Docker-Walkthrough)
|
||||||
* To see user submitted Metadata configuration files, and even add your own, go to the [Plex Meta Manager Configs](https://github.com/meisnate12/Plex-Meta-Manager-Configs).
|
- [unRAID Walkthrough](https://github.com/meisnate12/Plex-Meta-Manager/wiki/unRAID-Walkthrough)
|
||||||
* Pull Requests are welcome but please submit them to the develop branch.
|
- [Configuration File](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Configuration-File)
|
||||||
* If you wish to contribute to the Wiki please fork and send a pull request on the [Plex Meta Manager Wiki Repository](https://github.com/meisnate12/Plex-Meta-Manager-Wiki).
|
- [Libraries Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Libraries-Attributes)
|
||||||
|
- [Operations Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Operations-Attributes)
|
||||||
|
- [Playlist Files Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Playlist-Files-Attributes)
|
||||||
|
- [Settings Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Settings-Attributes)
|
||||||
|
- [Image Asset Directory](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Image-Asset-Directory)
|
||||||
|
- [Webhooks Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Webhooks-Attributes)
|
||||||
|
- [Plex Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Plex-Attributes)
|
||||||
|
- [TMDb Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/TMDb-Attributes)
|
||||||
|
- [Tautulli Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Tautulli-Attributes)
|
||||||
|
- [OMDb Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/OMDb-Attributes)
|
||||||
|
- [Notifiarr Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Notifiarr-Attributes)
|
||||||
|
- [AniDB Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/AniDB-Attributes)
|
||||||
|
- [Radarr Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Radarr-Attributes)
|
||||||
|
- [Sonarr Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Sonarr-Attributes)
|
||||||
|
- [Trakt Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Trakt-Attributes)
|
||||||
|
- [MyAnimeList Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/MyAnimeList-Attributes)
|
||||||
|
- [Metadata and Playlist Files](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Metadata-and-Playlist-Files)
|
||||||
|
- Metadata
|
||||||
|
- [Movies Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Movies-Metadata)
|
||||||
|
- [Shows Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Shows-Metadata)
|
||||||
|
- [Artists Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Artists-Metadata)
|
||||||
|
- [Templates](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Templates)
|
||||||
|
- [Filters](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Filters)
|
||||||
|
- Builders
|
||||||
|
- [Plex Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Plex-Builders)
|
||||||
|
- [Smart Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Smart-Builders)
|
||||||
|
- [TMDb Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/TMDb-Builders)
|
||||||
|
- [TVDb Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/TVDb-Builders)
|
||||||
|
- [IMDb Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/IMDb-Builders)
|
||||||
|
- [Trakt Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Trakt-Builders)
|
||||||
|
- [Tautulli Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Tautulli-Builders)
|
||||||
|
- [Letterboxd Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Letterboxd-Builders)
|
||||||
|
- [ICheckMovies Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/ICheckMovies-Builders)
|
||||||
|
- [FlixPatrol Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/FlixPatrol-Builders)
|
||||||
|
- [StevenLu Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/StevenLu-Builders)
|
||||||
|
- [AniDB Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/AniDB-Builders)
|
||||||
|
- [AniList Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/AniList-Builders)
|
||||||
|
- [MyAnimeList Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/MyAnimeList-Builders)
|
||||||
|
- Details
|
||||||
|
- [Setting Details](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Setting-Details)
|
||||||
|
- [Schedule Detail](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Schedule-Detail)
|
||||||
|
- [Image Overlay Detail](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Image-Overlay-Detail)
|
||||||
|
- [Metadata Details](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Metadata-Details)
|
||||||
|
- [Arr Details](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Arr-Details)
|
||||||
|
- [Acknowledgements](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Acknowledgements)
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
1.14.1-develop1722
|
1.15.0
|
|
@ -14,7 +14,8 @@ libraries: # Library mappings must have a c
|
||||||
- file: config/Anime.yml # You have to create this file the other is online
|
- file: config/Anime.yml # You have to create this file the other is online
|
||||||
- git: meisnate12/AnimeCharts
|
- git: meisnate12/AnimeCharts
|
||||||
playlist_files:
|
playlist_files:
|
||||||
- file: config/playlists.yml
|
- file: config/playlists.yml # You have to create this file the other is online
|
||||||
|
- git: meisnate12/Playlists
|
||||||
settings: # Can be individually specified per library as well
|
settings: # Can be individually specified per library as well
|
||||||
cache: true
|
cache: true
|
||||||
cache_expiration: 60
|
cache_expiration: 60
|
||||||
|
@ -23,6 +24,7 @@ settings: # Can be individually specified
|
||||||
asset_depth: 0
|
asset_depth: 0
|
||||||
create_asset_folders: false
|
create_asset_folders: false
|
||||||
dimensional_asset_rename: false
|
dimensional_asset_rename: false
|
||||||
|
download_url_assets: false
|
||||||
show_missing_season_assets: false
|
show_missing_season_assets: false
|
||||||
sync_mode: append
|
sync_mode: append
|
||||||
minimum_items: 1
|
minimum_items: 1
|
||||||
|
@ -42,6 +44,7 @@ settings: # Can be individually specified
|
||||||
ignore_ids:
|
ignore_ids:
|
||||||
ignore_imdb_ids:
|
ignore_imdb_ids:
|
||||||
playlist_sync_to_user: all
|
playlist_sync_to_user: all
|
||||||
|
verify_ssl: true
|
||||||
webhooks: # Can be individually specified per library as well
|
webhooks: # Can be individually specified per library as well
|
||||||
error:
|
error:
|
||||||
run_start:
|
run_start:
|
||||||
|
|
|
@ -169,7 +169,7 @@ custom_sort_builders = [
|
||||||
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio"
|
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio"
|
||||||
]
|
]
|
||||||
parts_collection_valid = [
|
parts_collection_valid = [
|
||||||
"plex_search", "trakt_list", "trakt_list_details", "collection_mode", "label", "visible_library", "changes_webhooks"
|
"plex_all", "plex_search", "trakt_list", "trakt_list_details", "collection_mode", "label", "visible_library", "changes_webhooks"
|
||||||
"visible_home", "visible_shared", "show_missing", "save_missing", "missing_only_released", "server_preroll",
|
"visible_home", "visible_shared", "show_missing", "save_missing", "missing_only_released", "server_preroll",
|
||||||
"item_lock_background", "item_lock_poster", "item_lock_title", "item_refresh", "imdb_list"
|
"item_lock_background", "item_lock_poster", "item_lock_title", "item_refresh", "imdb_list"
|
||||||
] + summary_details + poster_details + background_details + string_details
|
] + summary_details + poster_details + background_details + string_details
|
||||||
|
@ -338,9 +338,10 @@ class CollectionBuilder:
|
||||||
else:
|
else:
|
||||||
self.sync = self.data[methods["sync_mode"]].lower() == "sync"
|
self.sync = self.data[methods["sync_mode"]].lower() == "sync"
|
||||||
|
|
||||||
self.collection_level = "movie" if self.library.is_movie else "show"
|
if self.playlist: self.collection_level = "item"
|
||||||
if self.playlist:
|
elif self.library.is_show: self.collection_level = "show"
|
||||||
self.collection_level = "item"
|
elif self.library.is_music: self.collection_level = "artist"
|
||||||
|
else: self.collection_level = "movie"
|
||||||
if "collection_level" in methods and not self.playlist:
|
if "collection_level" in methods and not self.playlist:
|
||||||
logger.debug("")
|
logger.debug("")
|
||||||
logger.debug("Validating Method: collection_level")
|
logger.debug("Validating Method: collection_level")
|
||||||
|
@ -719,10 +720,10 @@ class CollectionBuilder:
|
||||||
elif method_name == "tvdb_poster":
|
elif method_name == "tvdb_poster":
|
||||||
self.posters[method_name] = f"{self.config.TVDb.get_item(method_data, self.library.is_movie).poster_path}"
|
self.posters[method_name] = f"{self.config.TVDb.get_item(method_data, self.library.is_movie).poster_path}"
|
||||||
elif method_name == "file_poster":
|
elif method_name == "file_poster":
|
||||||
if os.path.exists(method_data):
|
if os.path.exists(os.path.abspath(method_data)):
|
||||||
self.posters[method_name] = os.path.abspath(method_data)
|
self.posters[method_name] = os.path.abspath(method_data)
|
||||||
else:
|
else:
|
||||||
raise Failed(f"{self.Type} Error: Poster Path Does Not Exist: {os.path.abspath(method_data)}")
|
logger.error(f"{self.Type} Error: Poster Path Does Not Exist: {os.path.abspath(method_data)}")
|
||||||
|
|
||||||
def _background(self, method_name, method_data):
|
def _background(self, method_name, method_data):
|
||||||
if method_name == "url_background":
|
if method_name == "url_background":
|
||||||
|
@ -733,10 +734,10 @@ class CollectionBuilder:
|
||||||
elif method_name == "tvdb_background":
|
elif method_name == "tvdb_background":
|
||||||
self.posters[method_name] = f"{self.config.TVDb.get_item(method_data, self.library.is_movie).background_path}"
|
self.posters[method_name] = f"{self.config.TVDb.get_item(method_data, self.library.is_movie).background_path}"
|
||||||
elif method_name == "file_background":
|
elif method_name == "file_background":
|
||||||
if os.path.exists(method_data):
|
if os.path.exists(os.path.abspath(method_data)):
|
||||||
self.backgrounds[method_name] = os.path.abspath(method_data)
|
self.backgrounds[method_name] = os.path.abspath(method_data)
|
||||||
else:
|
else:
|
||||||
raise Failed(f"{self.Type} Error: Background Path Does Not Exist: {os.path.abspath(method_data)}")
|
logger.error(f"{self.Type} Error: Background Path Does Not Exist: {os.path.abspath(method_data)}")
|
||||||
|
|
||||||
def _details(self, method_name, method_data, method_final, methods):
|
def _details(self, method_name, method_data, method_final, methods):
|
||||||
if method_name == "collection_mode":
|
if method_name == "collection_mode":
|
||||||
|
@ -1053,7 +1054,7 @@ class CollectionBuilder:
|
||||||
|
|
||||||
def _plex(self, method_name, method_data):
|
def _plex(self, method_name, method_data):
|
||||||
if method_name == "plex_all":
|
if method_name == "plex_all":
|
||||||
self.builders.append((method_name, True))
|
self.builders.append((method_name, self.collection_level))
|
||||||
elif method_name in ["plex_search", "plex_collectionless"]:
|
elif method_name in ["plex_search", "plex_collectionless"]:
|
||||||
for dict_data, dict_methods in self._parse(method_name, method_data, datatype="dictlist"):
|
for dict_data, dict_methods in self._parse(method_name, method_data, datatype="dictlist"):
|
||||||
new_dictionary = {}
|
new_dictionary = {}
|
||||||
|
@ -1510,7 +1511,7 @@ class CollectionBuilder:
|
||||||
elif self.library.is_movie and final_attr in plex.show_only_searches:
|
elif self.library.is_movie and final_attr in plex.show_only_searches:
|
||||||
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute only works for show libraries")
|
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute only works for show libraries")
|
||||||
elif self.library.is_music and final_attr not in plex.music_searches:
|
elif self.library.is_music and final_attr not in plex.music_searches:
|
||||||
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute only works for movie or show libraries")
|
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute does not work for music libraries")
|
||||||
elif not self.library.is_music and final_attr in plex.music_searches:
|
elif not self.library.is_music and final_attr in plex.music_searches:
|
||||||
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute only works for music libraries")
|
raise Failed(f"{self.Type} Error: {final_attr} {method} attribute only works for music libraries")
|
||||||
elif _data is None:
|
elif _data is None:
|
||||||
|
|
|
@ -226,7 +226,7 @@ class Library(ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_all(self):
|
def get_all(self, collection_level=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_missing(self, collection, items, is_movie):
|
def add_missing(self, collection, items, is_movie):
|
||||||
|
|
|
@ -13,7 +13,7 @@ advance_tags_to_edit = {
|
||||||
"Movie": ["metadata_language", "use_original_title"],
|
"Movie": ["metadata_language", "use_original_title"],
|
||||||
"Show": ["episode_sorting", "keep_episodes", "delete_episodes", "season_display", "episode_ordering",
|
"Show": ["episode_sorting", "keep_episodes", "delete_episodes", "season_display", "episode_ordering",
|
||||||
"metadata_language", "use_original_title"],
|
"metadata_language", "use_original_title"],
|
||||||
"Artist": ["album_sort"]
|
"Artist": ["album_sorting"]
|
||||||
}
|
}
|
||||||
|
|
||||||
tags_to_edit = {
|
tags_to_edit = {
|
||||||
|
@ -616,26 +616,31 @@ class MetadataFile(DataFile):
|
||||||
else:
|
else:
|
||||||
for album_name, album_dict in meta[methods["albums"]].items():
|
for album_name, album_dict in meta[methods["albums"]].items():
|
||||||
updated = False
|
updated = False
|
||||||
|
title = None
|
||||||
|
album_methods = {am.lower(): am for am in album_dict}
|
||||||
logger.info("")
|
logger.info("")
|
||||||
logger.info(f"Updating album {album_name} of {mapping_name}...")
|
logger.info(f"Updating album {album_name} of {mapping_name}...")
|
||||||
try:
|
try:
|
||||||
album = item.album(album_name)
|
album = item.album(album_name)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
logger.error(f"Metadata Error: Album: {album_name} not found")
|
try:
|
||||||
continue
|
if "alt_title" not in album_methods or not album_dict[album_methods["alt_title"]]:
|
||||||
album_methods = {am.lower(): am for am in album_dict}
|
raise NotFound
|
||||||
|
album = item.album(album_dict[album_methods["alt_title"]])
|
||||||
|
title = album_name
|
||||||
|
except NotFound:
|
||||||
|
logger.error(f"Metadata Error: Album: {album_name} not found")
|
||||||
|
continue
|
||||||
|
|
||||||
if "album" in album_methods and album_dict[album_methods["album"]]:
|
if not title:
|
||||||
title = album_dict[album_methods["album"]]
|
|
||||||
else:
|
|
||||||
title = album.title
|
title = album.title
|
||||||
edits = {}
|
edits = {}
|
||||||
add_edit("album", album, album_dict, album_methods, key="title", value=title)
|
add_edit("title", album, album_dict, album_methods, value=title)
|
||||||
add_edit("sort_album", album, album_dict, album_methods, key="titleSort")
|
add_edit("sort_title", album, album_dict, album_methods, key="titleSort")
|
||||||
add_edit("rating", album, album_dict, album_methods, var_type="float")
|
add_edit("rating", album, album_dict, album_methods, var_type="float")
|
||||||
add_edit("originally_available", album, album_dict, album_methods, key="originallyAvailableAt", var_type="date")
|
add_edit("originally_available", album, album_dict, album_methods, key="originallyAvailableAt", var_type="date")
|
||||||
add_edit("record_label", album, album_dict, album_methods, key="studio")
|
add_edit("record_label", album, album_dict, album_methods, key="studio")
|
||||||
add_edit("review", album, album_dict, album_methods, key="summary")
|
add_edit("summary", album, album_dict, album_methods)
|
||||||
if self.library.edit_item(album, title, "Album", edits):
|
if self.library.edit_item(album, title, "Album", edits):
|
||||||
updated = True
|
updated = True
|
||||||
for tag_edit in ["genre", "style", "mood", "collection", "label"]:
|
for tag_edit in ["genre", "style", "mood", "collection", "label"]:
|
||||||
|
@ -652,6 +657,8 @@ class MetadataFile(DataFile):
|
||||||
else:
|
else:
|
||||||
for track_num, track_dict in album_dict[album_methods["tracks"]].items():
|
for track_num, track_dict in album_dict[album_methods["tracks"]].items():
|
||||||
updated = False
|
updated = False
|
||||||
|
title = None
|
||||||
|
track_methods = {tm.lower(): tm for tm in track_dict}
|
||||||
logger.info("")
|
logger.info("")
|
||||||
logger.info(f"Updating track {track_num} on {album_name} of {mapping_name}...")
|
logger.info(f"Updating track {track_num} on {album_name} of {mapping_name}...")
|
||||||
try:
|
try:
|
||||||
|
@ -660,20 +667,23 @@ class MetadataFile(DataFile):
|
||||||
else:
|
else:
|
||||||
track = album.track(title=track_num)
|
track = album.track(title=track_num)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
logger.error(f"Metadata Error: Track: {track_num} not found")
|
try:
|
||||||
continue
|
if "alt_title" not in track_methods or not track_dict[track_methods["alt_title"]]:
|
||||||
track_methods = {tm.lower(): tm for tm in track_dict}
|
raise NotFound
|
||||||
|
track = album.track(title=track_dict[track_methods["alt_title"]])
|
||||||
|
title = track_num
|
||||||
|
except NotFound:
|
||||||
|
logger.error(f"Metadata Error: Track: {track_num} not found")
|
||||||
|
continue
|
||||||
|
|
||||||
if "title" in track_methods and track_dict[track_methods["title"]]:
|
if not title:
|
||||||
title = track_dict[track_methods["title"]]
|
|
||||||
else:
|
|
||||||
title = track.title
|
title = track.title
|
||||||
edits = {}
|
edits = {}
|
||||||
add_edit("title", track, track_dict, track_methods, value=title)
|
add_edit("title", track, track_dict, track_methods, value=title)
|
||||||
add_edit("rating", track, track_dict, track_methods, var_type="float")
|
add_edit("rating", track, track_dict, track_methods, var_type="float")
|
||||||
add_edit("track", track, track_dict, track_methods, key="index", var_type="int")
|
add_edit("track", track, track_dict, track_methods, key="index", var_type="int")
|
||||||
add_edit("disc", track, track_dict, track_methods, key="parentIndex", var_type="int")
|
add_edit("disc", track, track_dict, track_methods, key="parentIndex", var_type="int")
|
||||||
add_edit("artist", track, track_dict, track_methods, key="originalTitle")
|
add_edit("original_artist", track, track_dict, track_methods, key="originalTitle")
|
||||||
if self.library.edit_item(album, title, "Track", edits):
|
if self.library.edit_item(album, title, "Track", edits):
|
||||||
updated = True
|
updated = True
|
||||||
if self.edit_tags("mood", track, track_dict, track_methods):
|
if self.edit_tags("mood", track, track_dict, track_methods):
|
||||||
|
|
|
@ -338,10 +338,10 @@ album_sorts = {
|
||||||
"title.asc": "titleSort", "title.desc": "titleSort%3Adesc",
|
"title.asc": "titleSort", "title.desc": "titleSort%3Adesc",
|
||||||
"album_artist.asc": "artist.titleSort%2Calbum.titleSort%2Calbum.index%2Calbum.id%2Calbum.originallyAvailableAt",
|
"album_artist.asc": "artist.titleSort%2Calbum.titleSort%2Calbum.index%2Calbum.id%2Calbum.originallyAvailableAt",
|
||||||
"album_artist.desc": "artist.titleSort%3Adesc%2Calbum.titleSort%2Calbum.index%2Calbum.id%2Calbum.originallyAvailableAt",
|
"album_artist.desc": "artist.titleSort%3Adesc%2Calbum.titleSort%2Calbum.index%2Calbum.id%2Calbum.originallyAvailableAt",
|
||||||
|
"year.asc": "year", "year.desc": "year%3Adesc",
|
||||||
"originally_available.asc": "originallyAvailableAt", "originally_available.desc": "originallyAvailableAt%3Adesc",
|
"originally_available.asc": "originallyAvailableAt", "originally_available.desc": "originallyAvailableAt%3Adesc",
|
||||||
"release.asc": "originallyAvailableAt", "release.desc": "originallyAvailableAt%3Adesc",
|
"release.asc": "originallyAvailableAt", "release.desc": "originallyAvailableAt%3Adesc",
|
||||||
"critic_rating.asc": "rating", "critic_rating.desc": "rating%3Adesc",
|
"critic_rating.asc": "rating", "critic_rating.desc": "rating%3Adesc",
|
||||||
"audience_rating.asc": "audienceRating", "audience_rating.desc": "audienceRating%3Adesc",
|
|
||||||
"user_rating.asc": "userRating", "user_rating.desc": "userRating%3Adesc",
|
"user_rating.asc": "userRating", "user_rating.desc": "userRating%3Adesc",
|
||||||
"added.asc": "addedAt", "added.desc": "addedAt%3Adesc",
|
"added.asc": "addedAt", "added.desc": "addedAt%3Adesc",
|
||||||
"played.asc": "lastViewedAt", "played.desc": "lastViewedAt%3Adesc",
|
"played.asc": "lastViewedAt", "played.desc": "lastViewedAt%3Adesc",
|
||||||
|
@ -447,9 +447,12 @@ class Plex(Library):
|
||||||
def fetchItem(self, data):
|
def fetchItem(self, data):
|
||||||
return self.PlexServer.fetchItem(data)
|
return self.PlexServer.fetchItem(data)
|
||||||
|
|
||||||
def get_all(self):
|
def get_all(self, collection_level=None):
|
||||||
logger.info(f"Loading All {self.type}s from Library: {self.name}")
|
collection_type = collection_level if collection_level else self.Plex.TYPE
|
||||||
key = f"/library/sections/{self.Plex.key}/all?includeGuids=1&type={utils.searchType(self.Plex.TYPE)}"
|
if not collection_level:
|
||||||
|
collection_level = self.type
|
||||||
|
logger.info(f"Loading All {collection_level.capitalize()}s from Library: {self.name}")
|
||||||
|
key = f"/library/sections/{self.Plex.key}/all?includeGuids=1&type={utils.searchType(collection_type)}"
|
||||||
container_start = 0
|
container_start = 0
|
||||||
container_size = plexapi.X_PLEX_CONTAINER_SIZE
|
container_size = plexapi.X_PLEX_CONTAINER_SIZE
|
||||||
results = []
|
results = []
|
||||||
|
@ -457,7 +460,7 @@ class Plex(Library):
|
||||||
results.extend(self.fetchItems(key, container_start, container_size))
|
results.extend(self.fetchItems(key, container_start, container_size))
|
||||||
util.print_return(f"Loaded: {container_start}/{self.Plex._totalViewSize}")
|
util.print_return(f"Loaded: {container_start}/{self.Plex._totalViewSize}")
|
||||||
container_start += container_size
|
container_start += container_size
|
||||||
logger.info(util.adjust_space(f"Loaded {self.Plex._totalViewSize} {self.type}s"))
|
logger.info(util.adjust_space(f"Loaded {self.Plex._totalViewSize} {collection_level.capitalize()}s"))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
|
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
|
||||||
|
@ -530,6 +533,7 @@ class Plex(Library):
|
||||||
item.uploadArt(filepath=image.location)
|
item.uploadArt(filepath=image.location)
|
||||||
self.reload(item)
|
self.reload(item)
|
||||||
except BadRequest as e:
|
except BadRequest as e:
|
||||||
|
item.refresh()
|
||||||
raise Failed(e)
|
raise Failed(e)
|
||||||
|
|
||||||
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
|
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
|
||||||
|
@ -693,8 +697,8 @@ class Plex(Library):
|
||||||
def get_rating_keys(self, method, data):
|
def get_rating_keys(self, method, data):
|
||||||
items = []
|
items = []
|
||||||
if method == "plex_all":
|
if method == "plex_all":
|
||||||
logger.info(f"Processing Plex All {self.type}s")
|
logger.info(f"Processing Plex All {data.capitalize()}s")
|
||||||
items = self.get_all()
|
items = self.get_all(collection_level=data)
|
||||||
elif method == "plex_search":
|
elif method == "plex_search":
|
||||||
util.print_multiline(data[1], info=True)
|
util.print_multiline(data[1], info=True)
|
||||||
items = self.get_filter_items(data[2])
|
items = self.get_filter_items(data[2])
|
||||||
|
|
|
@ -227,10 +227,12 @@ def update_libraries(config):
|
||||||
logger.debug(f"Asset Directory: {ad}")
|
logger.debug(f"Asset Directory: {ad}")
|
||||||
logger.debug(f"Asset Folders: {library.asset_folders}")
|
logger.debug(f"Asset Folders: {library.asset_folders}")
|
||||||
logger.debug(f"Create Asset Folders: {library.create_asset_folders}")
|
logger.debug(f"Create Asset Folders: {library.create_asset_folders}")
|
||||||
|
logger.debug(f"Download URL Assets: {library.download_url_assets}")
|
||||||
logger.debug(f"Sync Mode: {library.sync_mode}")
|
logger.debug(f"Sync Mode: {library.sync_mode}")
|
||||||
logger.debug(f"Collection Minimum: {library.minimum_items}")
|
logger.debug(f"Collection Minimum: {library.minimum_items}")
|
||||||
logger.debug(f"Delete Below Minimum: {library.delete_below_minimum}")
|
logger.debug(f"Delete Below Minimum: {library.delete_below_minimum}")
|
||||||
logger.debug(f"Delete Not Scheduled: {library.delete_not_scheduled}")
|
logger.debug(f"Delete Not Scheduled: {library.delete_not_scheduled}")
|
||||||
|
logger.debug(f"Default Collection Order: {library.default_collection_order}")
|
||||||
logger.debug(f"Missing Only Released: {library.missing_only_released}")
|
logger.debug(f"Missing Only Released: {library.missing_only_released}")
|
||||||
logger.debug(f"Only Filter Missing: {library.only_filter_missing}")
|
logger.debug(f"Only Filter Missing: {library.only_filter_missing}")
|
||||||
logger.debug(f"Show Unmanaged: {library.show_unmanaged}")
|
logger.debug(f"Show Unmanaged: {library.show_unmanaged}")
|
||||||
|
|
Loading…
Reference in a new issue