Added scheduler logic

This commit is contained in:
David Maisonave
2024-08-07 22:05:03 -04:00
parent 5d7d4bc80d
commit 3d7aa6333c
4 changed files with 69 additions and 16 deletions

View File

@@ -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. 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 ### 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 stashapp-tools --upgrade`
- `pip install pyYAML` - `pip install pyYAML`
- `pip install watchdog` - `pip install watchdog`
- `pip install schedule`
### Installation ### Installation
- Follow **Requirements** instructions. - Follow **Requirements** instructions.

View File

@@ -3,13 +3,10 @@
# Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor # 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. # Note: To call this script outside of Stash, pass --url and the Stash URL.
# Example: python filemonitor.py --url http://localhost:9999 # Example: python filemonitor.py --url http://localhost:9999
import os import os, time, pathlib, argparse
import time
import pathlib
import argparse
from StashPluginHelper import StashPluginHelper 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/ 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 threading import Lock, Condition
from multiprocessing import shared_memory from multiprocessing import shared_memory
from filemonitor_config import config # Import settings from filemonitor_config.py from filemonitor_config import config # Import settings from filemonitor_config.py
@@ -72,20 +69,51 @@ STASHPATHSCONFIG = plugin.STASH_CONFIGURATION['stashes']
stashPaths = [] stashPaths = []
for item in STASHPATHSCONFIG: for item in STASHPATHSCONFIG:
stashPaths.append(item["path"]) stashPaths.append(item["path"])
stashPaths.append(SPECIAL_FILE_DIR)
plugin.Trace(f"(stashPaths={stashPaths})") plugin.Trace(f"(stashPaths={stashPaths})")
if plugin.DRY_RUN: if plugin.DRY_RUN:
plugin.Log("Dry run mode is enabled.") plugin.Log("Dry run mode is enabled.")
plugin.Trace(f"(SCAN_MODIFIED={SCAN_MODIFIED}) (SCAN_ON_ANY_EVENT={SCAN_ON_ANY_EVENT}) (RECURSIVE={RECURSIVE})") 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 StopLibraryMonitorWaitingInTaskQueue = False
JobIdInTheQue = 0 JobIdInTheQue = 0
def isJobWaitingToRun(): def isJobWaitingToRun():
global StopLibraryMonitorWaitingInTaskQueue global StopLibraryMonitorWaitingInTaskQueue
global JobIdInTheQue global JobIdInTheQue
global FileMonitorPluginIsOnTaskQue
FileMonitorPluginIsOnTaskQue = False
jobIsWaiting = False
i = 1 i = 1
while i < 999: while True:
jobDetails = plugin.STASH_INTERFACE.find_job(i) jobDetails = plugin.STASH_INTERFACE.find_job(i)
if jobDetails: if jobDetails:
plugin.Trace(f"(Job ID({i})={jobDetails})") plugin.Trace(f"(Job ID({i})={jobDetails})")
@@ -93,13 +121,15 @@ def isJobWaitingToRun():
if jobDetails['description'] == "Running plugin task: Stop Library Monitor": if jobDetails['description'] == "Running plugin task: Stop Library Monitor":
StopLibraryMonitorWaitingInTaskQueue = True StopLibraryMonitorWaitingInTaskQueue = True
JobIdInTheQue = i JobIdInTheQue = i
return True jobIsWaiting = True
elif jobDetails['status'] == "RUNNING" and jobDetails['description'] == "Running plugin task: Start Library Monitor":
FileMonitorPluginIsOnTaskQue = True
else: else:
plugin.Trace(f"Last job {i}") plugin.Trace(f"Last job {i}")
break break
i += 1 i += 1
JobIdInTheQue = 0 JobIdInTheQue = 0
return False return jobIsWaiting
if plugin.CALLED_AS_STASH_PLUGIN: if plugin.CALLED_AS_STASH_PLUGIN:
plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})") plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})")
@@ -188,6 +218,7 @@ def start_library_monitor():
for path in stashPaths: for path in stashPaths:
observer.schedule(event_handler, path, recursive=RECURSIVE) observer.schedule(event_handler, path, recursive=RECURSIVE)
plugin.Trace(f"Observing {path}") plugin.Trace(f"Observing {path}")
observer.schedule(event_handler, SPECIAL_FILE_DIR, recursive=RECURSIVE)
observer.start() observer.start()
JobIsRunning = False JobIsRunning = False
PutPluginBackOnTaskQueAndExit = False PutPluginBackOnTaskQueAndExit = False
@@ -198,9 +229,12 @@ def start_library_monitor():
with mutex: with mutex:
while not shouldUpdate: while not shouldUpdate:
if plugin.CALLED_AS_STASH_PLUGIN and isJobWaitingToRun(): 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.") if FileMonitorPluginIsOnTaskQue:
JobIsRunning = True plugin.Log(f"Another task (JobID={JobIdInTheQue}) is waiting on the queue. Will restart FileMonitor to allow other task to run.")
break JobIsRunning = True
break
else:
plugin.Warn("Not restarting because FileMonitor is no longer on Task Queue")
if shm_buffer[0] != CONTINUE_RUNNING_SIG: if shm_buffer[0] != CONTINUE_RUNNING_SIG:
plugin.Log(f"Breaking out of loop. (shm_buffer[0]={shm_buffer[0]})") plugin.Log(f"Breaking out of loop. (shm_buffer[0]={shm_buffer[0]})")
break break
@@ -229,7 +263,7 @@ def start_library_monitor():
plugin.STASH_INTERFACE.metadata_clean(paths=TmpTargetPaths, dry_run=plugin.DRY_RUN) plugin.STASH_INTERFACE.metadata_clean(paths=TmpTargetPaths, dry_run=plugin.DRY_RUN)
if RUN_GENERATE_CONTENT: if RUN_GENERATE_CONTENT:
plugin.STASH_INTERFACE.metadata_generate() 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 PutPluginBackOnTaskQueAndExit = True
else: else:
plugin.Trace("Nothing to scan.") plugin.Trace("Nothing to scan.")

View File

@@ -1,6 +1,6 @@
name: FileMonitor name: FileMonitor
description: Monitors the Stash library folders, and updates Stash if any changes occurs in the Stash library paths. 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 url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor
settings: settings:
recursiveDisabled: recursiveDisabled:

View File

@@ -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. # 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, "scanModified": False,
# Timeout in seconds. This is how often it will check if another job (Task) is in the queue. # 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 # Enable to exit FileMonitor by creating special file in plugin folder\working
"createSpecFileToExit": True, "createSpecFileToExit": True,
# Enable to delete special file imediately after it's created in stop process # 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. # Enable to run metadata clean task after file deletion.
"runCleanAfterDelete": False, "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. # When enabled, if CREATE flag is triggered, DupFileManager task is called if the plugin is installed.
"onCreateCallDupFileManager": False, # Not yet implemented!!!! "onCreateCallDupFileManager": False, # Not yet implemented!!!!