diff --git a/repair.py b/repair.py index 16eacf5..080e39d 100644 --- a/repair.py +++ b/repair.py @@ -30,6 +30,7 @@ def parseInterval(intervalStr): parser.add_argument('--run-interval', type=str, default=repair['runInterval'], help='Optional interval in smart format (e.g. 1w2d3h4m5s) to run the repair process.') parser.add_argument('--mode', type=str, choices=['symlink', 'file'], default='symlink', help='Choose repair mode: `symlink` or `file`. `symlink` to repair broken symlinks and `file` to repair missing files.') parser.add_argument('--include-unmonitored', action='store_true', help='Include unmonitored media in the repair process') +parser.add_argument('--safety-check-script', type=str, default=repair['safetyCheckScript'], help='Python code to be evaluated and return boolean for whether torrent mount is working or not. mountTorrentsPath will be replaced by Realdebrid/Torbox mount path.') args = parser.parse_args() _print = print @@ -54,6 +55,14 @@ def print(*values: object): print(f"Invalid interval format for run interval: {args.run_interval}") exit(1) +def safety_check(mountTorrentsPath): + try: + safety_check_passed = eval(args.safety_check_script, {"os": os, "mountTorrentsPath": mountTorrentsPath}) + return safety_check_passed + except Exception as e: + print(f"Error checking torrent mount or evaluating safety check script [{safety_check_script}] for mount path [{mountTorrentsPath}] : exception: {e}") + return False + def main(): print("Collecting media...") sonarr = Sonarr() @@ -67,6 +76,15 @@ def main(): getItems = lambda media, childId: arr.getFiles(media=media, childId=childId) if args.mode == 'symlink' else arr.getHistory(media=media, childId=childId, includeGrandchildDetails=True) childrenIds = media.childrenIds if args.include_unmonitored else media.monitoredChildrenIds + # perform a "Safety check" to make sure that the torrents folder is mounted to prevent deleting everything in *arrs + # we do this inside of the loop because the mount could drop at any time; so, best to check with each iteration + if ((realdebrid['enabled'] and not safety_check(realdebrid['mountTorrentsPath'])) or (torbox['enabled'] and not safety_check(torbox['mountTorrentsPath']))): + print(f"Safety check failed: couldn't verify torrent folder is mounted") + discordError(f"[{args.mode}] An error occurred while processing {media.title}: Safety check failed: couldn't verify torrent folder is mounted") + if repairIntervalSeconds > 0: + time.sleep(repairIntervalSeconds) + continue + for childId in childrenIds: brokenItems = [] childItems = list(getItems(media=media, childId=childId)) diff --git a/shared/shared.py b/shared/shared.py index b496f47..55c3edb 100644 --- a/shared/shared.py +++ b/shared/shared.py @@ -96,7 +96,8 @@ def stringEnvParser(value): repair = { 'repairInterval': env.string('REPAIR_REPAIR_INTERVAL', default=None), - 'runInterval': env.string('REPAIR_RUN_INTERVAL', default=None) + 'runInterval': env.string('REPAIR_RUN_INTERVAL', default=None), + 'safetyCheckScript': env.string('SAFETY_CHECK_SCRIPT', default='len([name for name in os.listdir(mountTorrentsPath) if os.path.isdir(os.path.join(mountTorrentsPath, name))]) > 0') } plexHeaders = {