This commit is contained in:
meisnate12 2022-01-10 20:23:56 -05:00
parent 6c98aac971
commit 42b4666c1c
8 changed files with 140 additions and 50 deletions

View file

@ -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)

View file

@ -1 +1 @@
1.14.1-develop1722 1.15.0

View file

@ -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:

View file

@ -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:

View file

@ -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):

View file

@ -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):

View file

@ -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])

View file

@ -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}")