mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
#468 added metadata_backup library operation
This commit is contained in:
parent
ce7a432424
commit
e2de5ae19e
8 changed files with 203 additions and 101 deletions
|
@ -558,6 +558,7 @@ class ConfigFile:
|
|||
"radarr_remove_by_tag": None,
|
||||
"sonarr_remove_by_tag": None,
|
||||
"mass_collection_mode": None,
|
||||
"metadata_backup": None,
|
||||
"genre_collections": None
|
||||
}
|
||||
display_name = f"{params['name']} ({params['mapping_name']})" if lib and "library_name" in lib and lib["library_name"] else params["mapping_name"]
|
||||
|
@ -641,6 +642,18 @@ class ConfigFile:
|
|||
params["mass_collection_mode"] = util.check_collection_mode(lib["operations"]["mass_collection_mode"])
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
if "metadata_backup" in lib["operations"]:
|
||||
params["metadata_backup"] = {
|
||||
"path": os.path.join(default_dir, f"{str(library_name)}_Metadata_Backup.yml"),
|
||||
"exclude": [],
|
||||
"sync_tags": False,
|
||||
"add_blank_entries": True
|
||||
}
|
||||
if lib["operations"]["metadata_backup"] and isinstance(lib["operations"]["metadata_backup"], dict):
|
||||
params["metadata_backup"]["path"] = check_for_attribute(lib["operations"]["metadata_backup"], "path", var_type="path", default=params["metadata_backup"]["path"], save=False)
|
||||
params["metadata_backup"]["exclude"] = check_for_attribute(lib["operations"]["metadata_backup"], "exclude", var_type="comma_list", default_is_none=True, save=False)
|
||||
params["metadata_backup"]["sync_tags"] = check_for_attribute(lib["operations"]["metadata_backup"], "sync_tags", var_type="bool", default=False, save=False)
|
||||
params["metadata_backup"]["add_blank_entries"] = check_for_attribute(lib["operations"]["metadata_backup"], "add_blank_entries", var_type="bool", default=True, save=False)
|
||||
if "tmdb_collections" in lib["operations"]:
|
||||
params["tmdb_collections"] = {
|
||||
"exclude_ids": [],
|
||||
|
|
|
@ -76,6 +76,7 @@ class Library(ABC):
|
|||
self.sonarr_add_all_existing = params["sonarr_add_all_existing"]
|
||||
self.sonarr_remove_by_tag = params["sonarr_remove_by_tag"]
|
||||
self.mass_collection_mode = params["mass_collection_mode"]
|
||||
self.metadata_backup = params["metadata_backup"]
|
||||
self.tmdb_collections = params["tmdb_collections"]
|
||||
self.genre_collections = params["genre_collections"]
|
||||
self.genre_mapper = params["genre_mapper"]
|
||||
|
@ -89,8 +90,9 @@ class Library(ABC):
|
|||
self.status = {}
|
||||
|
||||
self.items_library_operation = self.assets_for_all or self.mass_genre_update or self.mass_audience_rating_update \
|
||||
or self.mass_critic_rating_update or self.mass_trakt_rating_update or self.genre_mapper \
|
||||
or self.tmdb_collections or self.radarr_add_all_existing or self.sonarr_add_all_existing
|
||||
or self.mass_critic_rating_update or self.mass_trakt_rating_update or self.genre_mapper \
|
||||
or self.tmdb_collections or self.radarr_add_all_existing or self.sonarr_add_all_existing \
|
||||
or self.metadata_backup
|
||||
self.library_operation = self.items_library_operation or self.delete_unmanaged_collections or self.delete_collections_with_less \
|
||||
or self.radarr_remove_by_tag or self.sonarr_remove_by_tag or self.mass_collection_mode \
|
||||
or self.genre_collections or self.show_unmanaged
|
||||
|
|
|
@ -9,19 +9,6 @@ logger = logging.getLogger("Plex Meta Manager")
|
|||
|
||||
github_base = "https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager-Configs/master/"
|
||||
|
||||
advance_tags_to_edit = {
|
||||
"Movie": ["metadata_language", "use_original_title"],
|
||||
"Show": ["episode_sorting", "keep_episodes", "delete_episodes", "season_display", "episode_ordering",
|
||||
"metadata_language", "use_original_title"],
|
||||
"Artist": ["album_sorting"]
|
||||
}
|
||||
|
||||
tags_to_edit = {
|
||||
"Movie": ["genre", "label", "collection", "country", "director", "producer", "writer"],
|
||||
"Show": ["genre", "label", "collection"],
|
||||
"Artist": ["genre", "style", "mood", "country", "collection", "similar_artist"]
|
||||
}
|
||||
|
||||
def get_dict(attribute, attr_data, check_list=None):
|
||||
if check_list is None:
|
||||
check_list = []
|
||||
|
@ -33,9 +20,9 @@ def get_dict(attribute, attr_data, check_list=None):
|
|||
if _name in check_list:
|
||||
logger.warning(f"Config Warning: Skipping duplicate {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name}")
|
||||
elif _data is None:
|
||||
logger.error(f"Config Error: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} has no data")
|
||||
logger.warning(f"Config Warning: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} has no data")
|
||||
elif not isinstance(_data, dict):
|
||||
logger.error(f"Config Error: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} must be a dictionary")
|
||||
logger.warning(f"Config Warning: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} must be a dictionary")
|
||||
else:
|
||||
new_dict[str(_name)] = _data
|
||||
return new_dict
|
||||
|
@ -435,11 +422,11 @@ class MetadataFile(DataFile):
|
|||
edits = {}
|
||||
add_edit("title", item, meta, methods, value=title)
|
||||
add_edit("sort_title", item, meta, methods, key="titleSort")
|
||||
add_edit("user_rating", item, meta, methods, key="userRating", var_type="float")
|
||||
if not self.library.is_music:
|
||||
add_edit("originally_available", item, meta, methods, key="originallyAvailableAt", value=originally_available, var_type="date")
|
||||
add_edit("critic_rating", item, meta, methods, value=rating, key="rating", var_type="float")
|
||||
add_edit("audience_rating", item, meta, methods, key="audienceRating", var_type="float")
|
||||
add_edit("user_rating", item, meta, methods, key="userRating", var_type="float")
|
||||
add_edit("content_rating", item, meta, methods, key="contentRating")
|
||||
add_edit("original_title", item, meta, methods, key="originalTitle", value=original_title)
|
||||
add_edit("studio", item, meta, methods, value=studio)
|
||||
|
@ -450,12 +437,12 @@ class MetadataFile(DataFile):
|
|||
|
||||
advance_edits = {}
|
||||
prefs = [p.id for p in item.preferences()]
|
||||
for advance_edit in advance_tags_to_edit[self.library.type]:
|
||||
key, options = plex.item_advance_keys[f"item_{advance_edit}"]
|
||||
for advance_edit in util.advance_tags_to_edit[self.library.type]:
|
||||
if advance_edit in methods:
|
||||
if advance_edit in ["metadata_language", "use_original_title"] and self.library.agent not in plex.new_plex_agents:
|
||||
logger.error(f"Metadata Error: {advance_edit} attribute only works for with the New Plex Movie Agent and New Plex TV Agent")
|
||||
elif meta[methods[advance_edit]]:
|
||||
key, options = plex.item_advance_keys[f"item_{advance_edit}"]
|
||||
method_data = str(meta[methods[advance_edit]]).lower()
|
||||
if method_data not in options:
|
||||
logger.error(f"Metadata Error: {meta[methods[advance_edit]]} {advance_edit} attribute invalid")
|
||||
|
@ -467,7 +454,7 @@ class MetadataFile(DataFile):
|
|||
if self.library.edit_item(item, mapping_name, self.library.type, advance_edits, advanced=True):
|
||||
updated = True
|
||||
|
||||
for tag_edit in tags_to_edit[self.library.type]:
|
||||
for tag_edit in util.tags_to_edit[self.library.type]:
|
||||
if self.edit_tags(tag_edit, item, meta, methods, extra=genres if tag_edit == "genre" else None):
|
||||
updated = True
|
||||
|
||||
|
@ -495,24 +482,10 @@ class MetadataFile(DataFile):
|
|||
logger.error(f"Metadata Error: Season: {season_id} not found")
|
||||
continue
|
||||
season_methods = {sm.lower(): sm for sm in season_dict}
|
||||
|
||||
if "title" in season_methods and season_dict[season_methods["title"]]:
|
||||
title = season_dict[season_methods["title"]]
|
||||
else:
|
||||
title = season.title
|
||||
if "sub" in season_methods:
|
||||
if season_dict[season_methods["sub"]] is None:
|
||||
logger.error("Metadata Error: sub attribute is blank")
|
||||
elif season_dict[season_methods["sub"]] is True and "(SUB)" not in title:
|
||||
title = f"{title} (SUB)"
|
||||
elif season_dict[season_methods["sub"]] is False and title.endswith(" (SUB)"):
|
||||
title = title[:-6]
|
||||
else:
|
||||
logger.error("Metadata Error: sub attribute must be True or False")
|
||||
|
||||
edits = {}
|
||||
add_edit("title", season, season_dict, season_methods, value=title)
|
||||
add_edit("title", season, season_dict, season_methods)
|
||||
add_edit("summary", season, season_dict, season_methods)
|
||||
add_edit("user_rating", season, season_dict, season_methods, key="userRating", var_type="float")
|
||||
if self.library.edit_item(season, season_id, "Season", edits):
|
||||
updated = True
|
||||
self.set_images(season, season_dict, season_methods)
|
||||
|
@ -538,24 +511,12 @@ class MetadataFile(DataFile):
|
|||
logger.error(f"Metadata Error: Episode {episode_str} in Season {season_id} not found")
|
||||
continue
|
||||
episode_methods = {em.lower(): em for em in episode_dict}
|
||||
|
||||
if "title" in episode_methods and episode_dict[episode_methods["title"]]:
|
||||
title = episode_dict[episode_methods["title"]]
|
||||
else:
|
||||
title = episode.title
|
||||
if "sub" in episode_dict:
|
||||
if episode_dict[episode_methods["sub"]] is None:
|
||||
logger.error("Metadata Error: sub attribute is blank")
|
||||
elif episode_dict[episode_methods["sub"]] is True and "(SUB)" not in title:
|
||||
title = f"{title} (SUB)"
|
||||
elif episode_dict[episode_methods["sub"]] is False and title.endswith(" (SUB)"):
|
||||
title = title[:-6]
|
||||
else:
|
||||
logger.error("Metadata Error: sub attribute must be True or False")
|
||||
edits = {}
|
||||
add_edit("title", episode, episode_dict, episode_methods, value=title)
|
||||
add_edit("title", episode, episode_dict, episode_methods)
|
||||
add_edit("sort_title", episode, episode_dict, episode_methods, key="titleSort")
|
||||
add_edit("rating", episode, episode_dict, episode_methods, var_type="float")
|
||||
add_edit("critic_rating", episode, episode_dict, episode_methods, key="rating", var_type="float")
|
||||
add_edit("audience_rating", episode, episode_dict, episode_methods, key="audienceRating", var_type="float")
|
||||
add_edit("user_rating", episode, episode_dict, episode_methods, key="userRating", var_type="float")
|
||||
add_edit("originally_available", episode, episode_dict, episode_methods, key="originallyAvailableAt", var_type="date")
|
||||
add_edit("summary", episode, episode_dict, episode_methods)
|
||||
if self.library.edit_item(episode, f"{episode_str} in Season: {season_id}", "Episode", edits):
|
||||
|
@ -589,24 +550,12 @@ class MetadataFile(DataFile):
|
|||
logger.error(f"Metadata Error: episode {episode_id} of season {season_id} not found")
|
||||
continue
|
||||
episode_methods = {em.lower(): em for em in episode_dict}
|
||||
|
||||
if "title" in episode_methods and episode_dict[episode_methods["title"]]:
|
||||
title = episode_dict[episode_methods["title"]]
|
||||
else:
|
||||
title = episode.title
|
||||
if "sub" in episode_dict:
|
||||
if episode_dict[episode_methods["sub"]] is None:
|
||||
logger.error("Metadata Error: sub attribute is blank")
|
||||
elif episode_dict[episode_methods["sub"]] is True and "(SUB)" not in title:
|
||||
title = f"{title} (SUB)"
|
||||
elif episode_dict[episode_methods["sub"]] is False and title.endswith(" (SUB)"):
|
||||
title = title[:-6]
|
||||
else:
|
||||
logger.error("Metadata Error: sub attribute must be True or False")
|
||||
edits = {}
|
||||
add_edit("title", episode, episode_dict, episode_methods, value=title)
|
||||
add_edit("title", episode, episode_dict, episode_methods)
|
||||
add_edit("sort_title", episode, episode_dict, episode_methods, key="titleSort")
|
||||
add_edit("rating", episode, episode_dict, episode_methods, var_type="float")
|
||||
add_edit("critic_rating", episode, episode_dict, episode_methods, key="rating", var_type="float")
|
||||
add_edit("audience_rating", episode, episode_dict, episode_methods, key="audienceRating", var_type="float")
|
||||
add_edit("user_rating", episode, episode_dict, episode_methods, key="userRating", var_type="float")
|
||||
add_edit("originally_available", episode, episode_dict, episode_methods, key="originallyAvailableAt", var_type="date")
|
||||
add_edit("summary", episode, episode_dict, episode_methods)
|
||||
if self.library.edit_item(episode, f"{season_id} Episode: {episode_id}", "Season", edits):
|
||||
|
@ -643,7 +592,8 @@ class MetadataFile(DataFile):
|
|||
edits = {}
|
||||
add_edit("title", album, album_dict, album_methods, value=title)
|
||||
add_edit("sort_title", album, album_dict, album_methods, key="titleSort")
|
||||
add_edit("rating", album, album_dict, album_methods, var_type="float")
|
||||
add_edit("critic_rating", album, album_dict, album_methods, key="rating", var_type="float")
|
||||
add_edit("user_rating", album, album_dict, album_methods, key="userRating", var_type="float")
|
||||
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("summary", album, album_dict, album_methods)
|
||||
|
@ -684,7 +634,7 @@ class MetadataFile(DataFile):
|
|||
title = track.title
|
||||
edits = {}
|
||||
add_edit("title", track, track_dict, track_methods, value=title)
|
||||
add_edit("rating", track, track_dict, track_methods, var_type="float")
|
||||
add_edit("user_rating", track, track_dict, track_methods, key="userRating", var_type="float")
|
||||
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("original_artist", track, track_dict, track_methods, key="originalTitle")
|
||||
|
|
112
modules/plex.py
112
modules/plex.py
|
@ -1,15 +1,16 @@
|
|||
import logging, os, plexapi, requests
|
||||
from datetime import datetime
|
||||
from modules import builder, util
|
||||
from modules.library import Library
|
||||
from modules.util import Failed, ImageData
|
||||
from PIL import Image
|
||||
from plexapi import utils
|
||||
from plexapi.audio import Artist
|
||||
from plexapi.audio import Artist, Track, Album
|
||||
from plexapi.exceptions import BadRequest, NotFound, Unauthorized
|
||||
from plexapi.collection import Collection
|
||||
from plexapi.playlist import Playlist
|
||||
from plexapi.server import PlexServer
|
||||
from plexapi.video import Movie, Show
|
||||
from plexapi.video import Movie, Show, Season, Episode
|
||||
from retrying import retry
|
||||
from urllib import parse
|
||||
from xml.etree.ElementTree import ParseError
|
||||
|
@ -111,8 +112,8 @@ modifier_translation = {
|
|||
"": "", ".not": "!", ".is": "%3D", ".isnot": "!%3D", ".gt": "%3E%3E", ".gte": "%3E", ".lt": "%3C%3C", ".lte": "%3C",
|
||||
".before": "%3C%3C", ".after": "%3E%3E", ".begins": "%3C", ".ends": "%3E"
|
||||
}
|
||||
episode_sorting_options = {"default": "-1", "oldest": "0", "newest": "1"}
|
||||
album_sorting_options = {"default": -1, "newest": 0, "oldest": 1, "name": 2}
|
||||
episode_sorting_options = {"default": -1, "oldest": 0, "newest": 1}
|
||||
keep_episodes_options = {"all": 0, "5_latest": 5, "3_latest": 3, "latest": 1, "past_3": -3, "past_7": -7, "past_30": -30}
|
||||
delete_episodes_options = {"never": 0, "day": 1, "week": 7, "refresh": 100}
|
||||
season_display_options = {"default": -1, "show": 0, "hide": 1}
|
||||
|
@ -987,3 +988,108 @@ class Plex(Library):
|
|||
elif isinstance(item, (Movie, Show)) and not poster and not background and self.show_missing_assets:
|
||||
logger.warning(f"Asset Warning: No poster or background found in an assets folder for '{name}'")
|
||||
return None, None, found_folder
|
||||
|
||||
def get_ids(self, item):
|
||||
tmdb_id = None
|
||||
tvdb_id = None
|
||||
imdb_id = None
|
||||
if self.config.Cache:
|
||||
t_id, i_id, guid_media_type, _ = self.config.Cache.query_guid_map(item.guid)
|
||||
if t_id:
|
||||
if "movie" in guid_media_type:
|
||||
tmdb_id = t_id[0]
|
||||
else:
|
||||
tvdb_id = t_id[0]
|
||||
if i_id:
|
||||
imdb_id = i_id[0]
|
||||
if not tmdb_id and not tvdb_id:
|
||||
tmdb_id = self.get_tmdb_from_map(item)
|
||||
if not tmdb_id and not tvdb_id and self.is_show:
|
||||
tvdb_id = self.get_tvdb_from_map(item)
|
||||
return tmdb_id, tvdb_id, imdb_id
|
||||
|
||||
def get_locked_attributes(self, item, titles=None):
|
||||
attrs = {}
|
||||
fields = {f.name: f for f in item.fields if f.locked}
|
||||
if isinstance(item, (Movie, Show)) and titles and titles.count(item.title) > 1:
|
||||
map_key = f"{item.title} ({item.year})"
|
||||
attrs["title"] = item.title
|
||||
attrs["year"] = item.year
|
||||
elif isinstance(item, (Season, Episode, Track)) and item.index:
|
||||
map_key = int(item.index)
|
||||
else:
|
||||
map_key = item.title
|
||||
|
||||
if "title" in fields:
|
||||
if isinstance(item, (Movie, Show)):
|
||||
tmdb_id, tvdb_id, imdb_id = self.get_ids(item)
|
||||
tmdb_item = self.config.TMDb.get_item(item, tmdb_id, tvdb_id, imdb_id, is_movie=isinstance(item, Movie))
|
||||
if tmdb_item:
|
||||
attrs["alt_title"] = tmdb_item.title
|
||||
elif isinstance(item, (Season, Episode, Track)):
|
||||
attrs["title"] = item.title
|
||||
|
||||
def check_field(plex_key, pmm_key, var_key=None):
|
||||
if plex_key in fields and pmm_key not in self.metadata_backup["exclude"]:
|
||||
if not var_key:
|
||||
var_key = plex_key
|
||||
if hasattr(item, var_key):
|
||||
plex_value = getattr(item, var_key)
|
||||
if isinstance(plex_value, list):
|
||||
plex_tags = [t.tag for t in plex_value]
|
||||
if len(plex_tags) > 0 or self.metadata_backup["sync_tags"]:
|
||||
attrs[f"{pmm_key}.sync" if self.metadata_backup["sync_tags"] else pmm_key] = None if not plex_tags else plex_tags[0] if len(plex_tags) == 1 else plex_tags
|
||||
elif isinstance(plex_value, datetime):
|
||||
attrs[pmm_key] = datetime.strftime(plex_value, "%Y-%m-%d")
|
||||
else:
|
||||
attrs[pmm_key] = plex_value
|
||||
|
||||
check_field("titleSort", "sort_title")
|
||||
check_field("originalTitle", "original_artist" if self.is_music else "original_title")
|
||||
check_field("originallyAvailableAt", "originally_available")
|
||||
check_field("contentRating", "content_rating")
|
||||
check_field("userRating", "user_rating")
|
||||
check_field("audienceRating", "audience_rating")
|
||||
check_field("rating", "critic_rating")
|
||||
check_field("studio", "record_label" if self.is_music else "studio")
|
||||
check_field("tagline", "tagline")
|
||||
check_field("summary", "summary")
|
||||
check_field("index", "track")
|
||||
check_field("parentIndex", "disc")
|
||||
check_field("director", "director", var_key="directors")
|
||||
check_field("country", "country", var_key="countries")
|
||||
check_field("genre", "genre", var_key="genres")
|
||||
check_field("writer", "writer", var_key="writers")
|
||||
check_field("producer", "producer", var_key="producers")
|
||||
check_field("collection", "collection", var_key="collections")
|
||||
check_field("label", "label", var_key="labels")
|
||||
check_field("mood", "mood", var_key="moods")
|
||||
check_field("style", "style", var_key="styles")
|
||||
check_field("similar", "similar_artist")
|
||||
for advance_edit in util.advance_tags_to_edit[self.type]:
|
||||
key, options = item_advance_keys[f"item_{advance_edit}"]
|
||||
if advance_edit in self.metadata_backup["exclude"] or not hasattr(item, key):
|
||||
continue
|
||||
keys = {v: k for k, v in options.items()}
|
||||
if keys[getattr(item, key)] not in ["default", "all", "never"]:
|
||||
attrs[advance_edit] = keys[getattr(item, key)]
|
||||
|
||||
def _recur(sub):
|
||||
sub_items = {}
|
||||
for sub_item in getattr(item, sub)():
|
||||
sub_item_key, sub_item_attrs = self.get_locked_attributes(sub_item)
|
||||
if sub_item_attrs:
|
||||
sub_items[sub_item_key] = sub_item_attrs
|
||||
if sub_items:
|
||||
attrs[sub] = sub_items
|
||||
|
||||
if isinstance(item, Show):
|
||||
_recur("seasons")
|
||||
elif isinstance(item, Season):
|
||||
_recur("episodes")
|
||||
elif isinstance(item, Artist):
|
||||
_recur("albums")
|
||||
elif isinstance(item, Album):
|
||||
_recur("tracks")
|
||||
|
||||
return map_key, attrs if attrs else None
|
||||
|
|
|
@ -238,3 +238,20 @@ class TMDb:
|
|||
if len(ids) > 0:
|
||||
logger.info(f"Processing {pretty}: ({tmdb_id}) {tmdb_name} ({len(ids)} Item{'' if len(ids) == 1 else 's'})")
|
||||
return ids
|
||||
|
||||
def get_item(self, item, tmdb_id, tvdb_id, imdb_id, is_movie=True):
|
||||
tmdb_item = None
|
||||
if tvdb_id and not tmdb_id:
|
||||
tmdb_id = self.config.Convert.tvdb_to_tmdb(tvdb_id)
|
||||
if imdb_id and not tmdb_id:
|
||||
_id, _type = self.config.Convert.imdb_to_tmdb(imdb_id)
|
||||
if _id and ((_type == "movie" and is_movie) or (_type == "show" and not is_movie)):
|
||||
tmdb_id = _id
|
||||
if tmdb_id:
|
||||
try:
|
||||
tmdb_item = self.get_movie(tmdb_id) if is_movie else self.get_show(tmdb_id)
|
||||
except Failed as e:
|
||||
logger.error(util.adjust_space(str(e)))
|
||||
else:
|
||||
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TMDb ID for Guid: {item.guid}"))
|
||||
return tmdb_item
|
||||
|
|
|
@ -75,6 +75,18 @@ collection_mode_options = {
|
|||
"hide_items": "hideItems", "hideitems": "hideItems",
|
||||
"show_items": "showItems", "showitems": "showItems"
|
||||
}
|
||||
advance_tags_to_edit = {
|
||||
"Movie": ["metadata_language", "use_original_title"],
|
||||
"Show": ["episode_sorting", "keep_episodes", "delete_episodes", "season_display", "episode_ordering",
|
||||
"metadata_language", "use_original_title"],
|
||||
"Artist": ["album_sorting"]
|
||||
}
|
||||
|
||||
tags_to_edit = {
|
||||
"Movie": ["genre", "label", "collection", "country", "director", "producer", "writer"],
|
||||
"Show": ["genre", "label", "collection"],
|
||||
"Artist": ["genre", "style", "mood", "country", "collection", "similar_artist"]
|
||||
}
|
||||
|
||||
def tab_new_lines(data):
|
||||
return str(data).replace("\n", "\n ") if "\n" in str(data) else str(data)
|
||||
|
|
|
@ -12,6 +12,7 @@ try:
|
|||
from modules.util import Failed, NotScheduled
|
||||
from plexapi.exceptions import NotFound
|
||||
from plexapi.video import Show, Season
|
||||
from ruamel import yaml
|
||||
except ModuleNotFoundError:
|
||||
print("Requirements Error: Requirements are not installed")
|
||||
sys.exit(0)
|
||||
|
@ -445,7 +446,8 @@ def library_operations(config, library):
|
|||
logger.debug(f"TMDb Collections: {library.tmdb_collections}")
|
||||
logger.debug(f"Genre Collections: {library.genre_collections}")
|
||||
logger.debug(f"Genre Mapper: {library.genre_mapper}")
|
||||
logger.debug(f"TMDb Operation: {library.items_library_operation}")
|
||||
logger.debug(f"Metadata Backup: {library.metadata_backup}")
|
||||
logger.debug(f"Item Operation: {library.items_library_operation}")
|
||||
|
||||
if library.split_duplicates:
|
||||
items = library.search(**{"duplicate": True})
|
||||
|
@ -469,22 +471,7 @@ def library_operations(config, library):
|
|||
util.print_return(f"Processing: {i}/{len(items)} {item.title}")
|
||||
if library.assets_for_all:
|
||||
library.find_assets(item)
|
||||
tmdb_id = None
|
||||
tvdb_id = None
|
||||
imdb_id = None
|
||||
if config.Cache:
|
||||
t_id, i_id, guid_media_type, _ = config.Cache.query_guid_map(item.guid)
|
||||
if t_id:
|
||||
if "movie" in guid_media_type:
|
||||
tmdb_id = t_id[0]
|
||||
else:
|
||||
tvdb_id = t_id[0]
|
||||
if i_id:
|
||||
imdb_id = i_id[0]
|
||||
if not tmdb_id and not tvdb_id:
|
||||
tmdb_id = library.get_tmdb_from_map(item)
|
||||
if not tmdb_id and not tvdb_id and library.is_show:
|
||||
tvdb_id = library.get_tvdb_from_map(item)
|
||||
tmdb_id, tvdb_id, imdb_id = library.get_ids(item)
|
||||
|
||||
if library.mass_trakt_rating_update:
|
||||
try:
|
||||
|
@ -512,15 +499,7 @@ def library_operations(config, library):
|
|||
|
||||
tmdb_item = None
|
||||
if library.tmdb_collections or library.mass_genre_update == "tmdb" or library.mass_audience_rating_update == "tmdb" or library.mass_critic_rating_update == "tmdb":
|
||||
if tvdb_id and not tmdb_id:
|
||||
tmdb_id = config.Convert.tvdb_to_tmdb(tvdb_id)
|
||||
if tmdb_id:
|
||||
try:
|
||||
tmdb_item = config.TMDb.get_movie(tmdb_id) if library.is_movie else config.TMDb.get_show(tmdb_id)
|
||||
except Failed as e:
|
||||
logger.error(util.adjust_space(str(e)))
|
||||
else:
|
||||
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TMDb ID for Guid: {item.guid}"))
|
||||
tmdb_item = config.TMDb.get_item(item, tmdb_id, tvdb_id, imdb_id, is_movie=library.is_movie)
|
||||
|
||||
omdb_item = None
|
||||
if library.mass_genre_update in ["omdb", "imdb"] or library.mass_audience_rating_update in ["omdb", "imdb"] or library.mass_critic_rating_update in ["omdb", "imdb"]:
|
||||
|
@ -713,6 +692,29 @@ def library_operations(config, library):
|
|||
for col in unmanaged_collections:
|
||||
library.find_assets(col)
|
||||
|
||||
if library.metadata_backup:
|
||||
logger.info("")
|
||||
util.separator(f"Metadata Backup for {library.name} Library", space=False, border=False)
|
||||
logger.info("")
|
||||
logger.info(f"Metadata Backup Path: {library.metadata_backup['path']}")
|
||||
logger.info("")
|
||||
meta = {}
|
||||
items = library.get_all()
|
||||
titles = [i.title for i in items]
|
||||
for i, item in enumerate(items, 1):
|
||||
util.print_return(f"Processing: {i}/{len(items)} {item.title}")
|
||||
map_key, attrs = library.get_locked_attributes(item, titles)
|
||||
if attrs or library.metadata_backup["add_blank_entries"]:
|
||||
meta[map_key] = attrs
|
||||
util.print_end()
|
||||
with open(library.metadata_backup["path"], "w"):
|
||||
pass
|
||||
try:
|
||||
yaml.round_trip_dump({"metadata": meta}, open(library.metadata_backup["path"], "w", encoding="utf-8"))
|
||||
logger.info(f"{len(meta)} {library.type.capitalize()}{'s' if len(meta) > 1 else ''} Backed Up")
|
||||
except yaml.scanner.ScannerError as e:
|
||||
util.print_multiline(f"YAML Error: {util.tab_new_lines(e)}", error=True)
|
||||
|
||||
def run_collection(config, library, metadata, requested_collections):
|
||||
logger.info("")
|
||||
for mapping_name, collection_attrs in requested_collections.items():
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
PlexAPI==4.9.1
|
||||
tmdbapis==0.1.8
|
||||
tmdbapis==0.1.9
|
||||
arrapi==1.3.1
|
||||
lxml==4.7.1
|
||||
requests==2.27.1
|
||||
|
|
Loading…
Reference in a new issue