mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-22 12:33:10 +00:00
add run_again mode #65
This commit is contained in:
parent
601117402c
commit
b30f8182be
5 changed files with 120 additions and 13 deletions
|
@ -16,6 +16,7 @@ settings: # Can be individually specified
|
||||||
show_filtered: false
|
show_filtered: false
|
||||||
show_missing: true
|
show_missing: true
|
||||||
save_missing: true
|
save_missing: true
|
||||||
|
run_again_delay: 2
|
||||||
plex: # Can be individually specified per library as well
|
plex: # Can be individually specified per library as well
|
||||||
url: http://192.168.1.12:32400
|
url: http://192.168.1.12:32400
|
||||||
token: ####################
|
token: ####################
|
||||||
|
|
|
@ -2,6 +2,8 @@ import glob, logging, os, re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from modules import util
|
from modules import util
|
||||||
from modules.util import Failed
|
from modules.util import Failed
|
||||||
|
from plexapi.collection import Collections
|
||||||
|
from plexapi.exceptions import BadRequest, NotFound
|
||||||
|
|
||||||
logger = logging.getLogger("Plex Meta Manager")
|
logger = logging.getLogger("Plex Meta Manager")
|
||||||
|
|
||||||
|
@ -17,12 +19,15 @@ class CollectionBuilder:
|
||||||
"show_missing": library.show_missing,
|
"show_missing": library.show_missing,
|
||||||
"save_missing": library.save_missing
|
"save_missing": library.save_missing
|
||||||
}
|
}
|
||||||
|
self.missing_movies = []
|
||||||
|
self.missing_shows = []
|
||||||
self.methods = []
|
self.methods = []
|
||||||
self.filters = []
|
self.filters = []
|
||||||
self.posters = {}
|
self.posters = {}
|
||||||
self.backgrounds = {}
|
self.backgrounds = {}
|
||||||
self.summaries = {}
|
self.summaries = {}
|
||||||
self.schedule = ""
|
self.schedule = ""
|
||||||
|
self.rating_key_map = {}
|
||||||
current_time = datetime.now()
|
current_time = datetime.now()
|
||||||
current_year = current_time.year
|
current_year = current_time.year
|
||||||
|
|
||||||
|
@ -168,12 +173,7 @@ class CollectionBuilder:
|
||||||
logger.info(f"Scanning {self.name} Collection")
|
logger.info(f"Scanning {self.name} Collection")
|
||||||
|
|
||||||
self.collectionless = "plex_collectionless" in data
|
self.collectionless = "plex_collectionless" in data
|
||||||
|
self.run_again = "run_again" in data
|
||||||
self.sync = self.library.sync_mode == "sync"
|
|
||||||
if "sync_mode" in data:
|
|
||||||
if not data["sync_mode"]: logger.warning(f"Collection Warning: sync_mode attribute is blank using general: {self.library.sync_mode}")
|
|
||||||
elif data["sync_mode"] not in ["append", "sync"]: logger.warning(f"Collection Warning: {self.library.sync_mode} sync_mode invalid using general: {data['sync_mode']}")
|
|
||||||
else: self.sync = data["sync_mode"] == "sync"
|
|
||||||
|
|
||||||
if "tmdb_person" in data:
|
if "tmdb_person" in data:
|
||||||
if data["tmdb_person"]:
|
if data["tmdb_person"]:
|
||||||
|
@ -252,6 +252,9 @@ class CollectionBuilder:
|
||||||
elif method_name == "label_sync_mode":
|
elif method_name == "label_sync_mode":
|
||||||
if data[m] in ["append", "sync"]: self.details[method_name] = data[m]
|
if data[m] in ["append", "sync"]: self.details[method_name] = data[m]
|
||||||
else: raise Failed("Collection Error: label_sync_mode attribute must be either 'append' or 'sync'")
|
else: raise Failed("Collection Error: label_sync_mode attribute must be either 'append' or 'sync'")
|
||||||
|
elif method_name == "sync_mode":
|
||||||
|
if data[m] in ["append", "sync"]: self.details[method_name] = data[m]
|
||||||
|
else: raise Failed("Collection Error: sync_mode attribute must be either 'append' or 'sync'")
|
||||||
elif method_name in ["arr_tag", "label"]:
|
elif method_name in ["arr_tag", "label"]:
|
||||||
self.details[method_name] = util.get_list(data[m])
|
self.details[method_name] = util.get_list(data[m])
|
||||||
elif method_name in util.boolean_details:
|
elif method_name in util.boolean_details:
|
||||||
|
@ -524,6 +527,12 @@ class CollectionBuilder:
|
||||||
else:
|
else:
|
||||||
raise Failed(f"Collection Error: {m} attribute is blank")
|
raise Failed(f"Collection Error: {m} attribute is blank")
|
||||||
|
|
||||||
|
self.sync = self.library.sync_mode == "sync"
|
||||||
|
if "sync_mode" in data:
|
||||||
|
if not data["sync_mode"]: logger.warning(f"Collection Warning: sync_mode attribute is blank using general: {self.library.sync_mode}")
|
||||||
|
elif data["sync_mode"] not in ["append", "sync"]: logger.warning(f"Collection Warning: {self.library.sync_mode} sync_mode invalid using general: {data['sync_mode']}")
|
||||||
|
else: self.sync = data["sync_mode"] == "sync"
|
||||||
|
|
||||||
self.do_arr = False
|
self.do_arr = False
|
||||||
if self.library.Radarr:
|
if self.library.Radarr:
|
||||||
self.do_arr = self.details["add_to_arr"] if "add_to_arr" in self.details else self.library.Radarr.add
|
self.do_arr = self.details["add_to_arr"] if "add_to_arr" in self.details else self.library.Radarr.add
|
||||||
|
@ -654,6 +663,8 @@ class CollectionBuilder:
|
||||||
self.library.add_missing(collection_name, missing_movies_with_names, True)
|
self.library.add_missing(collection_name, missing_movies_with_names, True)
|
||||||
if self.do_arr and self.library.Radarr:
|
if self.do_arr and self.library.Radarr:
|
||||||
self.library.Radarr.add_tmdb([missing_id for title, missing_id in missing_movies_with_names], tag=self.details["arr_tag"])
|
self.library.Radarr.add_tmdb([missing_id for title, missing_id in missing_movies_with_names], tag=self.details["arr_tag"])
|
||||||
|
if self.run_again:
|
||||||
|
self.missing_movies.extend([missing_id for title, missing_id in missing_movies_with_names])
|
||||||
if len(missing_shows) > 0 and self.library.is_show:
|
if len(missing_shows) > 0 and self.library.is_show:
|
||||||
missing_shows_with_names = []
|
missing_shows_with_names = []
|
||||||
for missing_id in missing_shows:
|
for missing_id in missing_shows:
|
||||||
|
@ -675,12 +686,14 @@ class CollectionBuilder:
|
||||||
if self.details["show_missing"] is True:
|
if self.details["show_missing"] is True:
|
||||||
logger.info(f"{collection_name} Collection | ? | {title} (TVDB: {missing_id})")
|
logger.info(f"{collection_name} Collection | ? | {title} (TVDB: {missing_id})")
|
||||||
elif self.details["show_filtered"] is True:
|
elif self.details["show_filtered"] is True:
|
||||||
logger.info(f"{collection_name} Collection | X | {title} (TMDb: {missing_id})")
|
logger.info(f"{collection_name} Collection | X | {title} (TVDb: {missing_id})")
|
||||||
logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing")
|
logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing")
|
||||||
if self.details["save_missing"] is True:
|
if self.details["save_missing"] is True:
|
||||||
self.library.add_missing(collection_name, missing_shows_with_names, False)
|
self.library.add_missing(collection_name, missing_shows_with_names, False)
|
||||||
if self.do_arr and self.library.Sonarr:
|
if self.do_arr and self.library.Sonarr:
|
||||||
self.library.Sonarr.add_tvdb([missing_id for title, missing_id in missing_shows_with_names], tag=self.details["arr_tag"])
|
self.library.Sonarr.add_tvdb([missing_id for title, missing_id in missing_shows_with_names], tag=self.details["arr_tag"])
|
||||||
|
if self.run_again:
|
||||||
|
self.missing_shows.extend([missing_id for title, missing_id in missing_shows_with_names])
|
||||||
|
|
||||||
if self.sync and items_found > 0:
|
if self.sync and items_found > 0:
|
||||||
logger.info("")
|
logger.info("")
|
||||||
|
@ -786,12 +799,12 @@ class CollectionBuilder:
|
||||||
|
|
||||||
def set_image(image_method, images, is_background=False):
|
def set_image(image_method, images, is_background=False):
|
||||||
if image_method in ['file_poster', 'asset_directory']:
|
if image_method in ['file_poster', 'asset_directory']:
|
||||||
if is_background: collection.uploadArt(url=images[image_method])
|
|
||||||
else: collection.uploadPoster(url=images[image_method])
|
|
||||||
image_location = "File"
|
|
||||||
else:
|
|
||||||
if is_background: collection.uploadArt(filepath=images[image_method])
|
if is_background: collection.uploadArt(filepath=images[image_method])
|
||||||
else: collection.uploadPoster(filepath=images[image_method])
|
else: collection.uploadPoster(filepath=images[image_method])
|
||||||
|
image_location = "File"
|
||||||
|
else:
|
||||||
|
if is_background: collection.uploadArt(url=images[image_method])
|
||||||
|
else: collection.uploadPoster(url=images[image_method])
|
||||||
image_location = "URL"
|
image_location = "URL"
|
||||||
logger.info(f"Detail: {image_method} updated collection {'background' if is_background else 'poster'} to [{image_location}] {images[image_method]}")
|
logger.info(f"Detail: {image_method} updated collection {'background' if is_background else 'poster'} to [{image_location}] {images[image_method]}")
|
||||||
|
|
||||||
|
@ -826,3 +839,51 @@ class CollectionBuilder:
|
||||||
elif "tmdb_movie_details" in self.backgrounds: set_image("tmdb_movie", self.backgrounds, is_background=True)
|
elif "tmdb_movie_details" in self.backgrounds: set_image("tmdb_movie", self.backgrounds, is_background=True)
|
||||||
elif "tmdb_show_details" in self.backgrounds: set_image("tmdb_show", self.backgrounds, is_background=True)
|
elif "tmdb_show_details" in self.backgrounds: set_image("tmdb_show", self.backgrounds, is_background=True)
|
||||||
else: logger.info("No background to update")
|
else: logger.info("No background to update")
|
||||||
|
|
||||||
|
def run_collections_again(self, library, collection_obj, movie_map, show_map):
|
||||||
|
collection_items = collection_obj.items() if isinstance(collection_obj, Collections) else []
|
||||||
|
name = collection_obj.title if isinstance(collection_obj, Collections) else collection_obj
|
||||||
|
rating_keys = [movie_map[mm] for mm in self.missing_movies if mm in movie_map]
|
||||||
|
if library.is_show:
|
||||||
|
rating_keys.extend([show_map[sm] for sm in self.missing_shows if sm in show_map])
|
||||||
|
|
||||||
|
if len(rating_keys) > 0:
|
||||||
|
for rating_key in rating_keys:
|
||||||
|
try:
|
||||||
|
current = library.fetchItem(int(rating_key))
|
||||||
|
except (BadRequest, NotFound):
|
||||||
|
logger.error(f"Plex Error: Item {rating_key} not found")
|
||||||
|
continue
|
||||||
|
if current in collection_items:
|
||||||
|
logger.info(f"{name} Collection | = | {current.title}")
|
||||||
|
else:
|
||||||
|
current.addCollection(name)
|
||||||
|
logger.info(f"{name} Collection | + | {current.title}")
|
||||||
|
logger.info(f"{len(rating_keys)} {'Movie' if library.is_movie else 'Show'}{'s' if len(rating_keys) > 1 else ''} Processed")
|
||||||
|
|
||||||
|
if len(self.missing_movies) > 0:
|
||||||
|
logger.info("")
|
||||||
|
for missing_id in self.missing_movies:
|
||||||
|
if missing_id not in movie_map:
|
||||||
|
try:
|
||||||
|
movie = self.config.TMDb.get_movie(missing_id)
|
||||||
|
except Failed as e:
|
||||||
|
logger.error(e)
|
||||||
|
continue
|
||||||
|
if self.details["show_missing"] is True:
|
||||||
|
logger.info(f"{name} Collection | ? | {movie.title} (TMDb: {missing_id})")
|
||||||
|
logger.info("")
|
||||||
|
logger.info(f"{len(self.missing_movies)} Movie{'s' if len(self.missing_movies) > 1 else ''} Missing")
|
||||||
|
|
||||||
|
if len(self.missing_shows) > 0 and library.is_show:
|
||||||
|
logger.info("")
|
||||||
|
for missing_id in self.missing_shows:
|
||||||
|
if missing_id not in show_map:
|
||||||
|
try:
|
||||||
|
title = str(self.config.TVDb.get_series(self.library.Plex.language, tvdb_id=missing_id).title.encode("ascii", "replace").decode())
|
||||||
|
except Failed as e:
|
||||||
|
logger.error(e)
|
||||||
|
continue
|
||||||
|
if self.details["show_missing"] is True:
|
||||||
|
logger.info(f"{name} Collection | ? | {title} (TVDb: {missing_id})")
|
||||||
|
logger.info(f"{len(self.missing_shows)} Show{'s' if len(self.missing_shows) > 1 else ''} Missing")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import logging, os, re, requests
|
import logging, os, re, requests, time
|
||||||
from modules import util
|
from modules import util
|
||||||
from modules.anidb import AniDBAPI
|
from modules.anidb import AniDBAPI
|
||||||
from modules.builder import CollectionBuilder
|
from modules.builder import CollectionBuilder
|
||||||
|
@ -152,6 +152,7 @@ class Config:
|
||||||
self.general["show_filtered"] = check_for_attribute(self.data, "show_filtered", parent="settings", var_type="bool", default=False)
|
self.general["show_filtered"] = check_for_attribute(self.data, "show_filtered", parent="settings", var_type="bool", default=False)
|
||||||
self.general["show_missing"] = check_for_attribute(self.data, "show_missing", parent="settings", var_type="bool", default=True)
|
self.general["show_missing"] = check_for_attribute(self.data, "show_missing", parent="settings", var_type="bool", default=True)
|
||||||
self.general["save_missing"] = check_for_attribute(self.data, "save_missing", parent="settings", var_type="bool", default=True)
|
self.general["save_missing"] = check_for_attribute(self.data, "save_missing", parent="settings", var_type="bool", default=True)
|
||||||
|
self.general["run_again_delay"] = check_for_attribute(self.data, "run_again_delay", parent="settings", var_type="int", default=0)
|
||||||
|
|
||||||
util.separator()
|
util.separator()
|
||||||
|
|
||||||
|
@ -414,9 +415,13 @@ class Config:
|
||||||
|
|
||||||
builder.update_details(plex_collection)
|
builder.update_details(plex_collection)
|
||||||
|
|
||||||
|
if builder.run_again and (len(builder.missing_movies) > 0 or len(builder.missing_shows) > 0):
|
||||||
|
library.run_again.append(builder)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
util.print_stacktrace()
|
util.print_stacktrace()
|
||||||
logger.error(f"Unknown Error: {e}")
|
logger.error(f"Unknown Error: {e}")
|
||||||
|
|
||||||
if library.show_unmanaged is True and not test and not requested_collections:
|
if library.show_unmanaged is True and not test and not requested_collections:
|
||||||
logger.info("")
|
logger.info("")
|
||||||
util.separator(f"Unmanaged Collections in {library.name} Library")
|
util.separator(f"Unmanaged Collections in {library.name} Library")
|
||||||
|
@ -432,6 +437,44 @@ class Config:
|
||||||
logger.info("")
|
logger.info("")
|
||||||
logger.error("No collection to update")
|
logger.error("No collection to update")
|
||||||
|
|
||||||
|
has_run_again = False
|
||||||
|
for library in self.libraries:
|
||||||
|
if library.run_again:
|
||||||
|
has_run_again = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if has_run_again:
|
||||||
|
logger.info("")
|
||||||
|
util.separator("Run Again")
|
||||||
|
logger.info("")
|
||||||
|
length = 0
|
||||||
|
for x in range(1, self.general["run_again_delay"] + 1):
|
||||||
|
length = util.print_return(length, f"Waiting to run again in {self.general['run_again_delay'] - x + 1} minutes")
|
||||||
|
for y in range(60):
|
||||||
|
time.sleep(1)
|
||||||
|
util.print_end(length)
|
||||||
|
for library in self.libraries:
|
||||||
|
if library.run_again:
|
||||||
|
os.environ["PLEXAPI_PLEXAPI_TIMEOUT"] = str(library.timeout)
|
||||||
|
logger.info("")
|
||||||
|
util.separator(f"{library.name} Library Run Again")
|
||||||
|
logger.info("")
|
||||||
|
collections = {c: library.collections[c] for c in util.get_list(requested_collections) if c in library.collections} if requested_collections else library.collections
|
||||||
|
if collections:
|
||||||
|
util.separator(f"Mapping {library.name} Library")
|
||||||
|
logger.info("")
|
||||||
|
movie_map, show_map = self.map_guids(library)
|
||||||
|
for builder in library.run_again:
|
||||||
|
logger.info("")
|
||||||
|
util.separator(f"{builder.name} Collection")
|
||||||
|
logger.info("")
|
||||||
|
try:
|
||||||
|
collection_obj = library.get_collection(builder.name)
|
||||||
|
except Failed as e:
|
||||||
|
util.print_multiline(e, error=True)
|
||||||
|
continue
|
||||||
|
builder.run_collections_again(library, collection_obj, movie_map, show_map)
|
||||||
|
|
||||||
def map_guids(self, library):
|
def map_guids(self, library):
|
||||||
movie_map = {}
|
movie_map = {}
|
||||||
show_map = {}
|
show_map = {}
|
||||||
|
|
|
@ -63,6 +63,7 @@ class PlexAPI:
|
||||||
self.plex = params["plex"]
|
self.plex = params["plex"]
|
||||||
self.timeout = params["plex"]["timeout"]
|
self.timeout = params["plex"]["timeout"]
|
||||||
self.missing = {}
|
self.missing = {}
|
||||||
|
self.run_again = []
|
||||||
|
|
||||||
def add_Radarr(self, Radarr):
|
def add_Radarr(self, Radarr):
|
||||||
self.Radarr = Radarr
|
self.Radarr = Radarr
|
||||||
|
|
|
@ -264,6 +264,7 @@ collectionless_lists = [
|
||||||
"name_mapping", "label", "label_sync_mode"
|
"name_mapping", "label", "label_sync_mode"
|
||||||
]
|
]
|
||||||
other_attributes = [
|
other_attributes = [
|
||||||
|
"run_again",
|
||||||
"schedule",
|
"schedule",
|
||||||
"sync_mode",
|
"sync_mode",
|
||||||
"template",
|
"template",
|
||||||
|
|
Loading…
Reference in a new issue