From 3d7aa6333c4c8d83d56a44787f516f9005283a48 Mon Sep 17 00:00:00 2001 From: David Maisonave <47364845+David-Maisonave@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:05:03 -0400 Subject: [PATCH] Added scheduler logic --- plugins/FileMonitor/README.md | 3 +- plugins/FileMonitor/filemonitor.py | 60 ++++++++++++++++++----- plugins/FileMonitor/filemonitor.yml | 2 +- plugins/FileMonitor/filemonitor_config.py | 20 +++++++- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/plugins/FileMonitor/README.md b/plugins/FileMonitor/README.md index 736565e..642d12f 100644 --- a/plugins/FileMonitor/README.md +++ b/plugins/FileMonitor/README.md @@ -1,4 +1,4 @@ -# FileMonitor: Ver 0.6.0 (By David Maisonave) +# FileMonitor: Ver 0.6.1 (By David Maisonave) FileMonitor is a [Stash](https://github.com/stashapp/stash) plugin which updates Stash if any changes occurs in the Stash library paths. ### Using FileMonitor as a plugin @@ -24,6 +24,7 @@ FileMonitor is a [Stash](https://github.com/stashapp/stash) plugin which updates - `pip install stashapp-tools --upgrade` - `pip install pyYAML` - `pip install watchdog` + - `pip install schedule` ### Installation - Follow **Requirements** instructions. diff --git a/plugins/FileMonitor/filemonitor.py b/plugins/FileMonitor/filemonitor.py index cd5780e..5941978 100644 --- a/plugins/FileMonitor/filemonitor.py +++ b/plugins/FileMonitor/filemonitor.py @@ -3,13 +3,10 @@ # Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor # Note: To call this script outside of Stash, pass --url and the Stash URL. # Example: python filemonitor.py --url http://localhost:9999 -import os -import time -import pathlib -import argparse +import os, time, pathlib, argparse from StashPluginHelper import StashPluginHelper -from watchdog.observers import Observer # This is also needed for event attributes import watchdog # pip install watchdog # https://pythonhosted.org/watchdog/ +from watchdog.observers import Observer # This is also needed for event attributes from threading import Lock, Condition from multiprocessing import shared_memory from filemonitor_config import config # Import settings from filemonitor_config.py @@ -72,20 +69,51 @@ STASHPATHSCONFIG = plugin.STASH_CONFIGURATION['stashes'] stashPaths = [] for item in STASHPATHSCONFIG: stashPaths.append(item["path"]) -stashPaths.append(SPECIAL_FILE_DIR) plugin.Trace(f"(stashPaths={stashPaths})") if plugin.DRY_RUN: plugin.Log("Dry run mode is enabled.") plugin.Trace(f"(SCAN_MODIFIED={SCAN_MODIFIED}) (SCAN_ON_ANY_EVENT={SCAN_ON_ANY_EVENT}) (RECURSIVE={RECURSIVE})") +# ToDo: Add logic here for reoccurring scheduler +def runTask(task): + if task['task'] == "Clean": + plugin.STASH_INTERFACE.metadata_clean(paths=stashPaths, dry_run=plugin.DRY_RUN) + elif task['task'] == "Generate": + plugin.STASH_INTERFACE.metadata_generate() + elif task['task'] == "Backup": + plugin.STASH_INTERFACE.call_GQL("mutation { backupDatabase(input: {download: false})}") + elif task['task'] == "Scan": + plugin.STASH_INTERFACE.metadata_scan(paths=stashPaths) + # elif task['task'] == "Create Tags": + # plugin.STASH_INTERFACE.run_plugin_task(plugin_id="pathParser", task_name="Create Tags") + elif task['task'] == "Auto Tag": + plugin.Warn("Auto Tag is not implemented!!!") + else: + plugin.STASH_INTERFACE.run_plugin_task(plugin_id=task['pluginId'], task_name=task['task']) + + +def reoccurringScheduler(): + import schedule # pip install schedule # https://github.com/dbader/schedule + for task in plugin.pluginConfig['task_reoccurring_scheduler']: + if task['hours'] > 0: + plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['hours']} hour(s) interval") + schedule.every(task['hours']).hours.do(runTask, task) + +if plugin.pluginConfig['turnOnScheduler']: + reoccurringScheduler() + +FileMonitorPluginIsOnTaskQue = plugin.CALLED_AS_STASH_PLUGIN StopLibraryMonitorWaitingInTaskQueue = False JobIdInTheQue = 0 def isJobWaitingToRun(): global StopLibraryMonitorWaitingInTaskQueue global JobIdInTheQue + global FileMonitorPluginIsOnTaskQue + FileMonitorPluginIsOnTaskQue = False + jobIsWaiting = False i = 1 - while i < 999: + while True: jobDetails = plugin.STASH_INTERFACE.find_job(i) if jobDetails: plugin.Trace(f"(Job ID({i})={jobDetails})") @@ -93,13 +121,15 @@ def isJobWaitingToRun(): if jobDetails['description'] == "Running plugin task: Stop Library Monitor": StopLibraryMonitorWaitingInTaskQueue = True JobIdInTheQue = i - return True + jobIsWaiting = True + elif jobDetails['status'] == "RUNNING" and jobDetails['description'] == "Running plugin task: Start Library Monitor": + FileMonitorPluginIsOnTaskQue = True else: plugin.Trace(f"Last job {i}") break i += 1 JobIdInTheQue = 0 - return False + return jobIsWaiting if plugin.CALLED_AS_STASH_PLUGIN: plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})") @@ -188,6 +218,7 @@ def start_library_monitor(): for path in stashPaths: observer.schedule(event_handler, path, recursive=RECURSIVE) plugin.Trace(f"Observing {path}") + observer.schedule(event_handler, SPECIAL_FILE_DIR, recursive=RECURSIVE) observer.start() JobIsRunning = False PutPluginBackOnTaskQueAndExit = False @@ -198,9 +229,12 @@ def start_library_monitor(): with mutex: while not shouldUpdate: if plugin.CALLED_AS_STASH_PLUGIN and isJobWaitingToRun(): - plugin.Log(f"Another task (JobID={JobIdInTheQue}) is waiting on the queue. Will restart FileMonitor to allow other task to run.") - JobIsRunning = True - break + if FileMonitorPluginIsOnTaskQue: + plugin.Log(f"Another task (JobID={JobIdInTheQue}) is waiting on the queue. Will restart FileMonitor to allow other task to run.") + JobIsRunning = True + break + else: + plugin.Warn("Not restarting because FileMonitor is no longer on Task Queue") if shm_buffer[0] != CONTINUE_RUNNING_SIG: plugin.Log(f"Breaking out of loop. (shm_buffer[0]={shm_buffer[0]})") break @@ -229,7 +263,7 @@ def start_library_monitor(): plugin.STASH_INTERFACE.metadata_clean(paths=TmpTargetPaths, dry_run=plugin.DRY_RUN) if RUN_GENERATE_CONTENT: plugin.STASH_INTERFACE.metadata_generate() - if plugin.CALLED_AS_STASH_PLUGIN and shm_buffer[0] == CONTINUE_RUNNING_SIG: + if plugin.CALLED_AS_STASH_PLUGIN and shm_buffer[0] == CONTINUE_RUNNING_SIG and FileMonitorPluginIsOnTaskQue: PutPluginBackOnTaskQueAndExit = True else: plugin.Trace("Nothing to scan.") diff --git a/plugins/FileMonitor/filemonitor.yml b/plugins/FileMonitor/filemonitor.yml index f9d07d0..23b7f96 100644 --- a/plugins/FileMonitor/filemonitor.yml +++ b/plugins/FileMonitor/filemonitor.yml @@ -1,6 +1,6 @@ name: FileMonitor description: Monitors the Stash library folders, and updates Stash if any changes occurs in the Stash library paths. -version: 0.6.0 +version: 0.6.1 url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor settings: recursiveDisabled: diff --git a/plugins/FileMonitor/filemonitor_config.py b/plugins/FileMonitor/filemonitor_config.py index 57b3a46..a9816a3 100644 --- a/plugins/FileMonitor/filemonitor_config.py +++ b/plugins/FileMonitor/filemonitor_config.py @@ -9,7 +9,7 @@ config = { # Enable to monitor changes in file system for modification flag. This option is NOT needed for Windows, because on Windows changes are triggered via CREATE, DELETE, and MOVE flags. Other OS may differ. "scanModified": False, # Timeout in seconds. This is how often it will check if another job (Task) is in the queue. - "timeOut": 60, # Not needed when running in command line mode. + "timeOut": 15, # Not needed when running in command line mode. # Enable to exit FileMonitor by creating special file in plugin folder\working "createSpecFileToExit": True, # Enable to delete special file imediately after it's created in stop process @@ -17,6 +17,24 @@ config = { # Enable to run metadata clean task after file deletion. "runCleanAfterDelete": False, + # Enable to turn on scheduler_task_list + "turnOnScheduler": True, + # Reoccurring scheduler task list. To activate schedule, change number from zero to the number of hours interval + "task_reoccurring_scheduler": [ + # Example: To perform a 'Clean' task every 48 hours, change zero to 48 + # Hours Conversion: 24=Daily, 168=Weekly, 720=Monthly, 1440=Bi-Monthly, 2160=Quarterly, 8760=Yearly + {"task" : "Clean", "hours" : 48}, # Maintenance Clean (every 2 days) + {"task" : "Generate", "hours" : 168}, # Generated Content (Weekly) + {"task" : "Backup", "hours" : 720}, # Backup Backup (Monthly) + {"task" : "Scan", "hours" : 168}, # Library Scan (Weekly) + # {"task" : "Create Tags", "hours" : 24},# Requires plugin [Path Parser] + {"task" : "Create Tags", "pluginId" : "pathParser", "hours" : 24}, # Requires plugin [Path Parser] + {"task" : "Auto Tag", "hours" : 0}, # !!! Not yet implemented!!! + {"task" : "MyTaskHere", "pluginId" : "MyPluginId", "hours" : 0}, # Place holder for custom task. + ], + # Maximum backups to keep. When scheduler is enabled, and the Backup runs, delete older backups after reaching maximum backups. + "BackupsMax" : 6, # Not yet implemented!!! + # When enabled, if CREATE flag is triggered, DupFileManager task is called if the plugin is installed. "onCreateCallDupFileManager": False, # Not yet implemented!!!!