added webhooks

pull/431/head
meisnate12 3 years ago
parent cc8f925afc
commit 9312c5ec35

@ -34,9 +34,12 @@ settings: # Can be individually specified
missing_only_released: false
collection_minimum: 1
delete_below_minimum: true
notifiarr_collection_creation: false
notifiarr_collection_addition: false
notifiarr_collection_removing: false
error_webhooks:
run_start_webhooks:
run_end_webhooks:
collection_creation_webhooks:
collection_addition_webhooks:
collection_removing_webhooks:
tvdb_language: eng
plex: # Can be individually specified per library as well
url: http://192.168.1.12:32400
@ -78,7 +81,6 @@ omdb:
apikey: ########
notifiarr:
apikey: ####################################
error_notification: true
trakt:
client_id: ################################################################
client_secret: ################################################################

@ -78,15 +78,16 @@ summary_details = [
poster_details = ["url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "file_poster"]
background_details = ["url_background", "tmdb_background", "tvdb_background", "file_background"]
boolean_details = [
"visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing", "missing_only_released",
"delete_below_minimum", "notifiarr_collection_creation", "notifiarr_collection_addition", "notifiarr_collection_removing"
"visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing",
"missing_only_released", "delete_below_minimum"
]
string_details = ["sort_title", "content_rating", "name_mapping"]
ignored_details = [
"smart_filter", "smart_label", "smart_url", "run_again", "schedule", "sync_mode", "template", "test",
"tmdb_person", "build_collection", "collection_order", "collection_level", "validate_builders", "collection_name"
]
details = ["collection_mode", "collection_order", "collection_level", "collection_minimum", "label"] + boolean_details + string_details
notification_details = ["collection_creation_webhooks", "collection_addition_webhooks", "collection_removing_webhooks"]
details = ["collection_mode", "collection_order", "collection_level", "collection_minimum", "label"] + boolean_details + string_details + notification_details
collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \
poster_details + background_details + summary_details + string_details
item_details = ["item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay", "item_assets", "revert_overlay", "item_refresh"] + list(plex.item_advance_keys.keys())
@ -176,9 +177,9 @@ class CollectionBuilder:
"missing_only_released": self.library.missing_only_released,
"create_asset_folders": self.library.create_asset_folders,
"delete_below_minimum": self.library.delete_below_minimum,
"notifiarr_collection_creation": self.library.notifiarr_collection_creation,
"notifiarr_collection_addition": self.library.notifiarr_collection_addition,
"notifiarr_collection_removing": self.library.notifiarr_collection_removing,
"collection_creation_webhooks": self.library.collection_creation_webhooks,
"collection_addition_webhooks": self.library.collection_addition_webhooks,
"collection_removing_webhooks": self.library.collection_removing_webhooks,
}
self.item_details = {}
self.radarr_details = {}
@ -193,8 +194,8 @@ class CollectionBuilder:
self.filtered_keys = {}
self.run_again_movies = []
self.run_again_shows = []
self.notifiarr_additions = []
self.notifiarr_removals = []
self.notification_additions = []
self.notification_removals = []
self.items = []
self.posters = {}
self.backgrounds = {}
@ -551,7 +552,6 @@ class CollectionBuilder:
elif not self.library.Sonarr and "sonarr" in method_name: raise Failed(f"Collection Error: {method_final} requires Sonarr to be configured")
elif not self.library.Tautulli and "tautulli" in method_name: raise Failed(f"Collection Error: {method_final} requires Tautulli to be configured")
elif not self.config.MyAnimeList and "mal" in method_name: raise Failed(f"Collection Error: {method_final} requires MyAnimeList to be configured")
elif not self.library.Notifiarr and "notifiarr" in method_name: raise Failed(f"Collection Error: {method_final} requires Notifiarr to be configured")
elif self.library.is_movie and method_name in show_only_builders: raise Failed(f"Collection Error: {method_final} attribute only works for show libraries")
elif self.library.is_show and method_name in movie_only_builders: raise Failed(f"Collection Error: {method_final} attribute only works for movie libraries")
elif self.library.is_show and method_name in plex.movie_only_searches: raise Failed(f"Collection Error: {method_final} plex search only works for movie libraries")
@ -709,6 +709,8 @@ class CollectionBuilder:
self.details["label.sync"] = util.get_list(method_data)
else:
self.details[method_final] = util.get_list(method_data)
elif method_name in notification_details:
self.details[method_name] = util.parse(method_name, method_data, datatype="list")
elif method_name in boolean_details:
default = self.details[method_name] if method_name in self.details else None
self.details[method_name] = util.parse(method_name, method_data, datatype="bool", default=default)
@ -1485,6 +1487,7 @@ class CollectionBuilder:
def add_to_collection(self):
name, collection_items = self.library.get_collection_name_and_items(self.obj if self.obj else self.name, self.smart_label_collection)
total = len(self.rating_keys)
amount_added = 0
for i, item in enumerate(self.rating_keys, 1):
try:
current = self.fetch_item(item)
@ -1497,41 +1500,44 @@ class CollectionBuilder:
self.plex_map[current.ratingKey] = None
else:
self.library.alter_collection(current, name, smart_label_collection=self.smart_label_collection)
if self.details["notifiarr_collection_addition"]:
amount_added += 1
if self.details["collection_addition_webhooks"]:
if self.library.is_movie and current.ratingKey in self.library.movie_rating_key_map:
add_id = self.library.movie_rating_key_map[current.ratingKey]
elif self.library.is_show and current.ratingKey in self.library.show_rating_key_map:
add_id = self.library.show_rating_key_map[current.ratingKey]
else:
add_id = None
self.notifiarr_additions.append({"title": current.title, "id": add_id})
self.notification_additions.append({"title": current.title, "id": add_id})
util.print_end()
logger.info("")
logger.info(f"{total} {self.collection_level.capitalize()}{'s' if total > 1 else ''} Processed")
return amount_added
def sync_collection(self):
count_removed = 0
amount_removed = 0
for ratingKey, item in self.plex_map.items():
if item is not None:
if count_removed == 0:
if amount_removed == 0:
logger.info("")
util.separator(f"Removed from {self.name} Collection", space=False, border=False)
logger.info("")
self.library.reload(item)
logger.info(f"{self.name} Collection | - | {self.item_title(item)}")
self.library.alter_collection(item, self.name, smart_label_collection=self.smart_label_collection, add=False)
if self.details["notifiarr_collection_removing"]:
if self.details["collection_removing_webhooks"]:
if self.library.is_movie and item.ratingKey in self.library.movie_rating_key_map:
remove_id = self.library.movie_rating_key_map[item.ratingKey]
elif self.library.is_show and item.ratingKey in self.library.show_rating_key_map:
remove_id = self.library.show_rating_key_map[item.ratingKey]
else:
remove_id = None
self.notifiarr_removals.append({"title": item.title, "id": remove_id})
count_removed += 1
if count_removed > 0:
self.notification_removals.append({"title": item.title, "id": remove_id})
amount_removed += 1
if amount_removed > 0:
logger.info("")
logger.info(f"{count_removed} {self.collection_level.capitalize()}{'s' if count_removed == 1 else ''} Removed")
logger.info(f"{amount_removed} {self.collection_level.capitalize()}{'s' if amount_removed == 1 else ''} Removed")
return amount_removed
def check_tmdb_filter(self, item_id, is_movie, item=None, check_released=False):
if self.tmdb_filters or check_released:
@ -1653,6 +1659,8 @@ class CollectionBuilder:
return True
def run_missing(self):
added_to_radarr = 0
added_to_sonarr = 0
if len(self.missing_movies) > 0:
missing_movies_with_names = []
for missing_id in self.missing_movies:
@ -1679,7 +1687,7 @@ class CollectionBuilder:
if self.library.Radarr:
if self.radarr_details["add"]:
try:
self.library.Radarr.add_tmdb(missing_tmdb_ids, **self.radarr_details)
added_to_radarr += self.library.Radarr.add_tmdb(missing_tmdb_ids, **self.radarr_details)
except Failed as e:
logger.error(e)
if "item_radarr_tag" in self.item_details:
@ -1714,7 +1722,7 @@ class CollectionBuilder:
if self.library.Sonarr:
if self.sonarr_details["add"]:
try:
self.library.Sonarr.add_tvdb(missing_tvdb_ids, **self.sonarr_details)
added_to_sonarr += self.library.Sonarr.add_tvdb(missing_tvdb_ids, **self.sonarr_details)
except Failed as e:
logger.error(e)
if "item_sonarr_tag" in self.item_details:
@ -1727,6 +1735,7 @@ class CollectionBuilder:
if len(self.missing_parts) > 0 and self.library.is_show and self.details["save_missing"] is True:
for missing in self.missing_parts:
logger.info(f"{self.name} Collection | X | {missing}")
return added_to_radarr, added_to_sonarr
def item_title(self, item):
if self.collection_level == "season":
@ -2034,16 +2043,17 @@ class CollectionBuilder:
def send_notifications(self):
if self.obj and (
(self.details["notifiarr_collection_creation"] and self.created) or
(self.details["notifiarr_collection_addition"] and len(self.notifiarr_additions) > 0) or
(self.details["notifiarr_collection_removing"] and len(self.notifiarr_removals) > 0)
(self.details["collection_creation_webhooks"] and self.created) or
(self.details["collection_addition_webhooks"] and len(self.notification_additions) > 0) or
(self.details["collection_removing_webhooks"] and len(self.notification_removals) > 0)
):
self.obj.reload()
self.library.Notifiarr.plex_collection(
self.library.Webhooks.collection_hooks(
self.details["collection_creation_webhooks"] + self.details["collection_addition_webhooks"] + self.details["collection_removing_webhooks"],
self.obj,
created=self.created,
additions=self.notifiarr_additions,
removals=self.notifiarr_removals
additions=self.notification_additions,
removals=self.notification_removals
)
def run_collections_again(self):
@ -2051,7 +2061,7 @@ class CollectionBuilder:
name, collection_items = self.library.get_collection_name_and_items(self.obj, self.smart_label_collection)
self.created = False
rating_keys = []
self.notifiarr_additions = []
self.notification_additions = []
for mm in self.run_again_movies:
if mm in self.library.movie_map:
rating_keys.extend(self.library.movie_map[mm])
@ -2077,7 +2087,7 @@ class CollectionBuilder:
add_id = self.library.show_rating_key_map[current.ratingKey]
else:
add_id = None
self.notifiarr_additions.append({"title": current.title, "id": add_id})
self.notification_additions.append({"title": current.title, "id": add_id})
self.send_notifications()
logger.info(f"{len(rating_keys)} {self.collection_level.capitalize()}{'s' if len(rating_keys) > 1 else ''} Processed")

@ -10,7 +10,7 @@ from modules.icheckmovies import ICheckMovies
from modules.imdb import IMDb
from modules.letterboxd import Letterboxd
from modules.mal import MyAnimeList
from modules.notifiarr import NotifiarrFactory
from modules.notifiarr import Notifiarr
from modules.omdb import OMDb
from modules.plex import Plex
from modules.radarr import Radarr
@ -21,6 +21,7 @@ from modules.tmdb import TMDb
from modules.trakt import Trakt
from modules.tvdb import TVDb
from modules.util import Failed
from modules.webhooks import Webhooks
from retrying import retry
from ruamel import yaml
@ -135,9 +136,9 @@ class Config:
elif var_type == "path":
if os.path.exists(os.path.abspath(data[attribute])): return data[attribute]
else: message = f"Path {os.path.abspath(data[attribute])} does not exist"
elif var_type == "list": return util.get_list(data[attribute])
elif var_type == "list": return util.get_list(data[attribute], split=False)
elif var_type == "list_path":
temp_list = [p for p in util.get_list(data[attribute], split=True) if os.path.exists(os.path.abspath(p))]
temp_list = [p for p in util.get_list(data[attribute], split=False) if os.path.exists(os.path.abspath(p))]
if len(temp_list) > 0: return temp_list
else: message = "No Paths exist"
elif var_type == "lower_list": return util.get_list(data[attribute], lower=True)
@ -190,9 +191,12 @@ class Config:
"create_asset_folders": check_for_attribute(self.data, "create_asset_folders", parent="settings", var_type="bool", default=False),
"collection_minimum": check_for_attribute(self.data, "collection_minimum", parent="settings", var_type="int", default=1),
"delete_below_minimum": check_for_attribute(self.data, "delete_below_minimum", parent="settings", var_type="bool", default=False),
"notifiarr_collection_creation": check_for_attribute(self.data, "notifiarr_collection_creation", parent="settings", var_type="bool", default=False),
"notifiarr_collection_addition": check_for_attribute(self.data, "notifiarr_collection_addition", parent="settings", var_type="bool", default=False),
"notifiarr_collection_removing": check_for_attribute(self.data, "notifiarr_collection_removing", parent="settings", var_type="bool", default=False),
"error_webhooks": check_for_attribute(self.data, "error_webhooks", parent="settings", var_type="list", default_is_none=True),
"run_start_webhooks": check_for_attribute(self.data, "run_start_webhooks", parent="settings", var_type="list", default_is_none=True),
"run_end_webhooks": check_for_attribute(self.data, "run_end_webhooks", parent="settings", var_type="list", default_is_none=True),
"collection_creation_webhooks": check_for_attribute(self.data, "collection_creation_webhooks", parent="settings", var_type="list", default_is_none=True),
"collection_addition_webhooks": check_for_attribute(self.data, "collection_addition_webhooks", parent="settings", var_type="list", default_is_none=True),
"collection_removing_webhooks": check_for_attribute(self.data, "collection_removing_webhooks", parent="settings", var_type="list", default_is_none=True),
"tvdb_language": check_for_attribute(self.data, "tvdb_language", parent="settings", default="default")
}
if self.general["cache"]:
@ -207,9 +211,8 @@ class Config:
if "notifiarr" in self.data:
logger.info("Connecting to Notifiarr...")
try:
self.NotifiarrFactory = NotifiarrFactory(self, {
self.NotifiarrFactory = Notifiarr(self, {
"apikey": check_for_attribute(self.data, "apikey", parent="notifiarr", throw=True),
"error_notification": check_for_attribute(self.data, "error_notification", parent="notifiarr", var_type="bool", default=True),
"develop": check_for_attribute(self.data, "develop", parent="notifiarr", var_type="bool", default=False, do_print=False, save=False),
"test": check_for_attribute(self.data, "test", parent="notifiarr", var_type="bool", default=False, do_print=False, save=False)
})
@ -219,6 +222,9 @@ class Config:
else:
logger.warning("notifiarr attribute not found")
self.Webhooks = Webhooks(self, self.general, notifiarr=self.NotifiarrFactory)
self.Webhooks.start_time_hooks(self.run_start_time)
self.errors = []
util.separator()
@ -389,9 +395,10 @@ class Config:
params["create_asset_folders"] = check_for_attribute(lib, "create_asset_folders", parent="settings", var_type="bool", default=self.general["create_asset_folders"], do_print=False, save=False)
params["collection_minimum"] = check_for_attribute(lib, "collection_minimum", parent="settings", var_type="int", default=self.general["collection_minimum"], do_print=False, save=False)
params["delete_below_minimum"] = check_for_attribute(lib, "delete_below_minimum", parent="settings", var_type="bool", default=self.general["delete_below_minimum"], do_print=False, save=False)
params["notifiarr_collection_creation"] = check_for_attribute(lib, "notifiarr_collection_creation", parent="settings", var_type="bool", default=self.general["notifiarr_collection_creation"], do_print=False, save=False)
params["notifiarr_collection_addition"] = check_for_attribute(lib, "notifiarr_collection_addition", parent="settings", var_type="bool", default=self.general["notifiarr_collection_addition"], do_print=False, save=False)
params["notifiarr_collection_removing"] = check_for_attribute(lib, "notifiarr_collection_removing", parent="settings", var_type="bool", default=self.general["notifiarr_collection_removing"], do_print=False, save=False)
params["error_webhooks"] = check_for_attribute(lib, "error_webhooks", parent="settings", var_type="list", default=self.general["error_webhooks"], do_print=False, save=False)
params["collection_creation_webhooks"] = check_for_attribute(lib, "collection_creation_webhooks", parent="settings", var_type="list", default=self.general["collection_creation_webhooks"], do_print=False, save=False)
params["collection_addition_webhooks"] = check_for_attribute(lib, "collection_addition_webhooks", parent="settings", var_type="list", default=self.general["collection_addition_webhooks"], do_print=False, save=False)
params["collection_removing_webhooks"] = check_for_attribute(lib, "collection_removing_webhooks", parent="settings", var_type="list", default=self.general["collection_removing_webhooks"], do_print=False, save=False)
params["assets_for_all"] = check_for_attribute(lib, "assets_for_all", var_type="bool", default=assets_for_all, save=False, do_print=lib and "assets_for_all" in lib)
params["delete_unmanaged_collections"] = check_for_attribute(lib, "delete_unmanaged_collections", var_type="bool", default=False, save=False, do_print=lib and "delete_unmanaged_collections" in lib)
@ -545,7 +552,7 @@ class Config:
logger.info("")
logger.info(f"{display_name} library's Tautulli Connection {'Failed' if library.Tautulli is None else 'Successful'}")
library.Notifiarr = self.NotifiarrFactory.getNotifiarr(library) if self.NotifiarrFactory else None
library.Webhooks = Webhooks(self, {"error_webhooks": library.error_webhooks}, library=library, notifiarr=self.NotifiarrFactory)
logger.info("")
self.libraries.append(library)
@ -566,11 +573,8 @@ class Config:
raise
def notify(self, text, library=None, collection=None, critical=True):
if self.NotifiarrFactory:
if not isinstance(text, list):
text = [text]
for t in text:
self.NotifiarrFactory.error(t, library=library, collection=collection, critical=critical)
for error in util.get_list(text, split=False):
self.Webhooks.error_hooks(error, library=library, collection=collection, critical=critical)
def get_html(self, url, headers=None, params=None):
return html.fromstring(self.get(url, headers=headers, params=params).content)

@ -13,6 +13,7 @@ class Library(ABC):
self.Radarr = None
self.Sonarr = None
self.Tautulli = None
self.Webhooks = None
self.Notifiarr = None
self.collections = []
self.metadatas = []
@ -57,9 +58,10 @@ class Library(ABC):
self.sonarr_add_all = params["sonarr_add_all"]
self.collection_minimum = params["collection_minimum"]
self.delete_below_minimum = params["delete_below_minimum"]
self.notifiarr_collection_creation = params["notifiarr_collection_creation"]
self.notifiarr_collection_addition = params["notifiarr_collection_addition"]
self.notifiarr_collection_removing = params["notifiarr_collection_removing"]
self.error_webhooks = params["error_webhooks"]
self.collection_creation_webhooks = params["collection_creation_webhooks"]
self.collection_addition_webhooks = params["collection_addition_webhooks"]
self.collection_removing_webhooks = params["collection_removing_webhooks"]
self.split_duplicates = params["split_duplicates"] # TODO: Here or just in Plex?
self.clean_bundles = params["plex"]["clean_bundles"] # TODO: Here or just in Plex?
self.empty_trash = params["plex"]["empty_trash"] # TODO: Here or just in Plex?
@ -182,6 +184,9 @@ class Library(ABC):
self.config.Cache.update_image_map(item.ratingKey, f"{self.image_table_name}_backgrounds", item.art, background.compare)
def notify(self, text, collection=None, critical=True):
for error in util.get_list(text, split=False):
self.Webhooks.error_hooks(error, library=self, collection=collection, critical=critical)
self.config.notify(text, library=self, collection=collection, critical=critical)
@abstractmethod

@ -7,70 +7,25 @@ logger = logging.getLogger("Plex Meta Manager")
base_url = "https://notifiarr.com/api/v1/"
dev_url = "https://dev.notifiarr.com/api/v1/"
class NotifiarrBase:
def __init__(self, config, apikey, develop, test, error_notification):
self.config = config
self.apikey = apikey
self.develop = develop
self.test = test
self.error_notification = error_notification
def _request(self, path, json=None, params=None):
url = f"{dev_url if self.develop else base_url}" + \
("notification/test" if self.test else f"{path}{self.apikey}")
logger.debug(url.replace(self.apikey, "APIKEY"))
response = self.config.get(url, json=json, params={"event": "pmm"} if self.test else params)
class Notifiarr:
def __init__(self, config, params):
self.config = config
self.apikey = params["apikey"]
self.develop = params["develop"]
self.test = params["test"]
url, _ = self.get_url("user/validate/")
response = self.config.get(url)
response_json = response.json()
if self.develop or self.test:
logger.debug(json)
logger.debug("")
logger.debug(response_json)
if response.status_code >= 400 or ("result" in response_json and response_json["result"] == "error"):
logger.debug(f"Response: {response_json}")
raise Failed(f"({response.status_code} [{response.reason}]) {response_json}")
return response_json
def error(self, text, library=None, collection=None, critical=True):
if self.error_notification:
json = {"error": str(text), "critical": critical}
if library:
json["server_name"] = library.PlexServer.friendlyName
json["library_name"] = library.name
if collection:
json["collection"] = str(collection)
self._request("notification/plex/", json=json, params={"event": "collections"})
class NotifiarrFactory(NotifiarrBase):
def __init__(self, config, params):
super().__init__(config, params["apikey"], params["develop"], params["test"], params["error_notification"])
if not params["test"] and not self._request("user/validate/")["details"]["response"]:
if not params["test"] and not response_json["details"]["response"]:
raise Failed("Notifiarr Error: Invalid apikey")
def getNotifiarr(self, library):
return Notifiarr(self.config, library, self.apikey, self.develop, self.test, self.error_notification)
class Notifiarr(NotifiarrBase):
def __init__(self, config, library, apikey, develop, test, error_notification):
super().__init__(config, apikey, develop, test, error_notification)
self.library = library
def get_url(self, path):
url = f"{dev_url if self.develop else base_url}{'notification/test' if self.test else f'{path}{self.apikey}'}"
logger.debug(url.replace(self.apikey, "APIKEY"))
params = {"event": "pmm" if self.test else "collections"}
return url, params
def plex_collection(self, collection, created=False, additions=None, removals=None):
thumb = None
if collection.thumb and next((f for f in collection.fields if f.name == "thumb"), None):
thumb = self.config.get_image_encoded(f"{self.library.url}{collection.thumb}?X-Plex-Token={self.library.token}")
art = None
if collection.art and next((f for f in collection.fields if f.name == "art"), None):
art = self.config.get_image_encoded(f"{self.library.url}{collection.art}?X-Plex-Token={self.library.token}")
json = {
"server_name": self.library.PlexServer.friendlyName,
"library_name": self.library.name,
"type": "movie" if self.library.is_movie else "show",
"collection": collection.title,
"created": created,
"poster": thumb,
"background": art
}
if additions:
json["additions"] = additions
if removals:
json["removals"] = removals
self._request("notification/plex/", json=json, params={"event": "collections"})

@ -61,6 +61,8 @@ class Radarr:
for tmdb_id in invalid:
logger.info(f"Invalid TMDb ID | {tmdb_id}")
return len(added)
def edit_tags(self, tmdb_ids, tags, apply_tags):
logger.info("")
logger.info(f"{apply_tags_translation[apply_tags].capitalize()} Radarr Tags: {tags}")

@ -87,6 +87,8 @@ class Sonarr:
logger.info("")
logger.info(f"Invalid TVDb ID | {tvdb_id}")
return len(added)
def edit_tags(self, tvdb_ids, tags, apply_tags):
logger.info("")
logger.info(f"{apply_tags_translation[apply_tags].capitalize()} Sonarr Tags: {tags}")

@ -304,7 +304,7 @@ def parse(attribute, data, datatype=None, methods=None, parent=None, default=Non
value = data[methods[attribute]] if methods and attribute in methods else data
if datatype == "list":
if methods and attribute in methods and data[methods[attribute]]:
if value:
return [v for v in value if v] if isinstance(value, list) else [str(value)]
return []
elif datatype == "dictlist":

@ -0,0 +1,83 @@
import logging
from modules.util import Failed
logger = logging.getLogger("Plex Meta Manager")
class Webhooks:
def __init__(self, config, system_webhooks, library=None, notifiarr=None):
self.config = config
self.error_webhooks = system_webhooks["error_webhooks"] if "error_webhooks" in system_webhooks else []
self.run_start_webhooks = system_webhooks["run_start_webhooks"] if "run_start_webhooks" in system_webhooks else []
self.run_end_webhooks = system_webhooks["run_end_webhooks"] if "run_end_webhooks" in system_webhooks else []
self.library = library
self.notifiarr = notifiarr
def _request(self, webhooks, json):
if self.config.trace_mode:
logger.debug("")
logger.debug(f"JSON: {json}")
for webhook in webhooks:
if self.config.trace_mode:
logger.debug(f"Webhook: {webhook}")
if webhook == "notifiarr":
url, params = self.notifiarr.get_url("notification/plex/")
response = self.config.get(url, json=json, params=params)
else:
response = self.config.post(webhook, json=json)
response_json = response.json()
if self.config.trace_mode:
logger.debug(f"Response: {response_json}")
if response.status_code >= 400 or ("result" in response_json and response_json["result"] == "error"):
raise Failed(f"({response.status_code} [{response.reason}]) {response_json}")
def start_time_hooks(self, start_time):
if self.run_start_webhooks:
self._request(self.run_start_webhooks, {"start_time": start_time})
def end_time_hooks(self, start_time, run_time, stats):
if self.run_end_webhooks:
self._request(self.run_end_webhooks, {
"start_time": start_time,
"run_time": run_time,
"collections_created": stats["created"],
"collections_modified": stats["modified"],
"collections_deleted": stats["deleted"],
"items_added": stats["added"],
"items_removed": stats["removed"],
"added_to_radarr": stats["radarr"],
"added_to_sonarr": stats["sonarr"],
})
def error_hooks(self, text, library=None, collection=None, critical=True):
if self.error_webhooks:
json = {"error": str(text), "critical": critical}
if library:
json["server_name"] = library.PlexServer.friendlyName
json["library_name"] = library.name
if collection:
json["collection"] = str(collection)
self._request(self.error_webhooks, json)
def collection_hooks(self, webhooks, collection, created=False, additions=None, removals=None):
if self.library:
thumb = None
if collection.thumb and next((f for f in collection.fields if f.name == "thumb"), None):
thumb = self.config.get_image_encoded(f"{self.library.url}{collection.thumb}?X-Plex-Token={self.library.token}")
art = None
if collection.art and next((f for f in collection.fields if f.name == "art"), None):
art = self.config.get_image_encoded(f"{self.library.url}{collection.art}?X-Plex-Token={self.library.token}")
json = {
"server_name": self.library.PlexServer.friendlyName,
"library_name": self.library.name,
"type": "movie" if self.library.is_movie else "show",
"collection": collection.title,
"created": created,
"poster": thumb,
"background": art
}
if additions:
json["additions"] = additions
if removals:
json["removals"] = removals
self._request(webhooks, json)

@ -63,6 +63,7 @@ times = get_arg("PMM_TIME", args.times)
divider = get_arg("PMM_DIVIDER", args.divider)
screen_width = get_arg("PMM_WIDTH", args.width)
config_file = get_arg("PMM_CONFIG", args.config)
stats = {}
util.separating_character = divider[0]
@ -133,6 +134,9 @@ def start(attrs):
if "time" not in attrs:
attrs["time"] = start_time.strftime("%H:%M")
util.separator(f"Starting {start_type}Run")
config = None
global stats
stats = {"created": 0, "modified": 0, "deleted": 0, "added": 0, "removed": 0, "radarr": 0, "sonarr": 0}
try:
config = Config(default_dir, attrs)
except Exception as e:
@ -146,10 +150,14 @@ def start(attrs):
util.print_stacktrace()
util.print_multiline(e, critical=True)
logger.info("")
util.separator(f"Finished {start_type}Run\nRun Time: {str(datetime.now() - start_time).split('.')[0]}")
run_time = str(datetime.now() - start_time).split('.')[0]
if config:
config.Webhooks.end_time_hooks(start_time, run_time, stats)
util.separator(f"Finished {start_type}Run\nRun Time: {run_time}")
logger.removeHandler(file_handler)
def update_libraries(config):
global stats
for library in config.libraries:
try:
os.makedirs(os.path.join(default_dir, "logs", library.mapping_name, "collections"), exist_ok=True)
@ -460,6 +468,7 @@ def mass_metadata(config, library, items=None):
logger.error(e)
def run_collection(config, library, metadata, requested_collections):
global stats
logger.info("")
for mapping_name, collection_attrs in requested_collections.items():
collection_start = datetime.now()
@ -520,6 +529,8 @@ def run_collection(config, library, metadata, requested_collections):
logger.info("")
util.print_multiline(builder.smart_filter_details, info=True)
items_added = 0
items_removed = 0
if not builder.smart_url:
logger.info("")
logger.info(f"Sync Mode: {'sync' if builder.sync else 'append'}")
@ -535,14 +546,18 @@ def run_collection(config, library, metadata, requested_collections):
logger.info("")
util.separator(f"Adding to {mapping_name} Collection", space=False, border=False)
logger.info("")
builder.add_to_collection()
items_added = builder.add_to_collection()
stats["added"] += items_added
items_removed = 0
if builder.sync:
builder.sync_collection()
items_removed = builder.sync_collection()
stats["removed"] += items_removed
elif len(builder.rating_keys) < builder.minimum and builder.build_collection:
logger.info("")
logger.info(f"Collection Minimum: {builder.minimum} not met for {mapping_name} Collection")
if builder.details["delete_below_minimum"] and builder.obj:
builder.delete_collection()
stats["deleted"] += 1
logger.info("")
logger.info(f"Collection {builder.obj.title} deleted")
@ -551,12 +566,18 @@ def run_collection(config, library, metadata, requested_collections):
logger.info("")
util.separator(f"Missing from Library", space=False, border=False)
logger.info("")
builder.run_missing()
radarr_add, sonarr_add = builder.run_missing()
stats["radarr"] += radarr_add
stats["sonarr"] += sonarr_add
run_item_details = True
if builder.build_collection:
try:
builder.load_collection()
if builder.created:
stats["created"] += 1
elif items_added > 0 or items_removed > 0:
stats["modified"] += 1
except Failed:
util.print_stacktrace()
run_item_details = False

Loading…
Cancel
Save