Added function ExecutePythonScript

Added logic to the scheduler to be able to call other scripts and perform command line calls.
This commit is contained in:
David Maisonave
2024-08-12 05:54:47 -04:00
parent c70f1c9af0
commit 95d644cda0
6 changed files with 151 additions and 133 deletions

2
plugins/.gitignore vendored
View File

@@ -34,6 +34,8 @@ renamefile_settings.cpython-310.pyc
/DeleteMe /DeleteMe
/ATestPlugin /ATestPlugin
/FileMonitor/working /FileMonitor/working
test_script_hello_world.py
MyDummyFileFrom_test_script_hello_world.txt
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.

View File

@@ -1,4 +1,4 @@
# FileMonitor: Ver 0.7.7 (By David Maisonave) # FileMonitor: Ver 0.7.8 (By David Maisonave)
FileMonitor is a [Stash](https://github.com/stashapp/stash) plugin with the following two main features: FileMonitor is a [Stash](https://github.com/stashapp/stash) plugin with the following two main features:
- Updates Stash when any file changes occurs in the Stash library. - Updates Stash when any file changes occurs in the Stash library.
- **Task Scheduler**: Runs scheduled task based on the scheduler configuration in filemonitor_config.py. - **Task Scheduler**: Runs scheduled task based on the scheduler configuration in filemonitor_config.py.

View File

@@ -1,12 +1,7 @@
import stashapi.log as stashLog # stashapi.log by default for error and critical logging import stashapi.log as stashLog # stashapi.log by default for error and critical logging
from stashapi.stashapp import StashInterface from stashapi.stashapp import StashInterface
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
import inspect import inspect, sys, os, pathlib, logging, json
import sys
import os
import pathlib
import logging
import json
import __main__ import __main__
# StashPluginHelper (By David Maisonave aka Axter) # StashPluginHelper (By David Maisonave aka Axter)
@@ -61,7 +56,7 @@ class StashPluginHelper:
STDIN_READ = None STDIN_READ = None
FRAGMENT_SERVER = None FRAGMENT_SERVER = None
logger = None logger = None
traceOncePreviousHits = [] logLinePreviousHits = []
# Prefix message value # Prefix message value
LEV_TRACE = "TRACE: " LEV_TRACE = "TRACE: "
@@ -218,7 +213,7 @@ class StashPluginHelper:
def Trace(self, logMsg = "", printTo = 0, logAlways = False, lineNo = -1): def Trace(self, logMsg = "", printTo = 0, logAlways = False, lineNo = -1):
if printTo == 0: printTo = self.LOG_TO_FILE if printTo == 0: printTo = self.LOG_TO_FILE
if lineNo == -1: if lineNo == -1:
lineNo = lineNo = inspect.currentframe().f_back.f_lineno lineNo = inspect.currentframe().f_back.f_lineno
logLev = logging.INFO if logAlways else logging.DEBUG logLev = logging.INFO if logAlways else logging.DEBUG
if self.DEBUG_TRACING or logAlways: if self.DEBUG_TRACING or logAlways:
if logMsg == "": if logMsg == "":
@@ -227,28 +222,24 @@ class StashPluginHelper:
# Log once per session. Only logs the first time called from a particular line number in the code. # Log once per session. Only logs the first time called from a particular line number in the code.
def TraceOnce(self, logMsg = "", printTo = 0, logAlways = False): def TraceOnce(self, logMsg = "", printTo = 0, logAlways = False):
if printTo == 0: printTo = self.LOG_TO_FILE
lineNo = inspect.currentframe().f_back.f_lineno lineNo = inspect.currentframe().f_back.f_lineno
logLev = logging.INFO if logAlways else logging.DEBUG
if self.DEBUG_TRACING or logAlways: if self.DEBUG_TRACING or logAlways:
FuncAndLineNo = f"{inspect.currentframe().f_back.f_code.co_name}:{lineNo}" FuncAndLineNo = f"{inspect.currentframe().f_back.f_code.co_name}:{lineNo}"
if FuncAndLineNo in self.traceOncePreviousHits: if FuncAndLineNo in self.logLinePreviousHits:
return return
self.traceOncePreviousHits.append(FuncAndLineNo) self.logLinePreviousHits.append(FuncAndLineNo)
if logMsg == "": self.Trace(logMsg, printTo, logAlways, lineNo)
logMsg = f"Line number {lineNo}..."
self.Log(logMsg, printTo, logLev, lineNo)
# Log INFO on first call, then do Trace on remaining calls. # Log INFO on first call, then do Trace on remaining calls.
def LogOnce(self, logMsg = "", printTo = 0, logAlways = False, traceOnRemainingCalls = True): def LogOnce(self, logMsg = "", printTo = 0, logAlways = False, traceOnRemainingCalls = True):
if printTo == 0: printTo = self.LOG_TO_FILE if printTo == 0: printTo = self.LOG_TO_FILE
lineNo = inspect.currentframe().f_back.f_lineno lineNo = inspect.currentframe().f_back.f_lineno
FuncAndLineNo = f"{inspect.currentframe().f_back.f_code.co_name}:{lineNo}" FuncAndLineNo = f"{inspect.currentframe().f_back.f_code.co_name}:{lineNo}"
if FuncAndLineNo in self.traceOncePreviousHits: if FuncAndLineNo in self.logLinePreviousHits:
if traceOnRemainingCalls: if traceOnRemainingCalls:
self.Trace(logMsg, printTo, logAlways, lineNo) self.Trace(logMsg, printTo, logAlways, lineNo)
else: else:
self.traceOncePreviousHits.append(FuncAndLineNo) self.logLinePreviousHits.append(FuncAndLineNo)
self.Log(logMsg, printTo, logging.INFO, lineNo) self.Log(logMsg, printTo, logging.INFO, lineNo)
def Warn(self, logMsg, printTo = 0): def Warn(self, logMsg, printTo = 0):
@@ -268,6 +259,26 @@ class StashPluginHelper:
self.Log(f"StashPluginHelper Status: (CALLED_AS_STASH_PLUGIN={self.CALLED_AS_STASH_PLUGIN}), (RUNNING_IN_COMMAND_LINE_MODE={self.RUNNING_IN_COMMAND_LINE_MODE}), (DEBUG_TRACING={self.DEBUG_TRACING}), (DRY_RUN={self.DRY_RUN}), (PLUGIN_ID={self.PLUGIN_ID}), (PLUGIN_TASK_NAME={self.PLUGIN_TASK_NAME}), (STASH_URL={self.STASH_URL}), (MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME})", self.Log(f"StashPluginHelper Status: (CALLED_AS_STASH_PLUGIN={self.CALLED_AS_STASH_PLUGIN}), (RUNNING_IN_COMMAND_LINE_MODE={self.RUNNING_IN_COMMAND_LINE_MODE}), (DEBUG_TRACING={self.DEBUG_TRACING}), (DRY_RUN={self.DRY_RUN}), (PLUGIN_ID={self.PLUGIN_ID}), (PLUGIN_TASK_NAME={self.PLUGIN_TASK_NAME}), (STASH_URL={self.STASH_URL}), (MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME})",
printTo, logLevel, lineNo) printTo, logLevel, lineNo)
def ExecuteProcess(self, args):
import platform, subprocess
is_windows = any(platform.win32_ver())
pid = None
self.Trace(f"is_windows={is_windows} args={args}")
if is_windows:
self.Trace("Executing process using Windows DETACHED_PROCESS")
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen(args,creationflags=DETACHED_PROCESS, shell=True).pid
else:
self.Trace("Executing process using normal Popen")
pid = subprocess.Popen(args).pid
self.Trace(f"pid={pid}")
return pid
def ExecutePythonScript(self, args):
PythonExe = f"{sys.executable}"
argsWithPython = [f"{PythonExe}"] + args
return self.ExecuteProcess(argsWithPython)
# Extends class StashInterface with functions which are not yet in the class # Extends class StashInterface with functions which are not yet in the class
class ExtendStashInterface(StashInterface): class ExtendStashInterface(StashInterface):
def metadata_autotag(self, paths:list=[], dry_run=False): def metadata_autotag(self, paths:list=[], dry_run=False):

View File

@@ -31,8 +31,8 @@ if parse_args.quit:
settings = { settings = {
"recursiveDisabled": False, "recursiveDisabled": False,
"turnOnScheduler": False, "turnOnScheduler": False,
"zzdebugTracing": False, "zmaximumBackups": 0,
"zzdryRun": False, "zzdebugTracing": False
} }
plugin = StashPluginHelper( plugin = StashPluginHelper(
stash_url=parse_args.stash_url, stash_url=parse_args.stash_url,
@@ -79,7 +79,7 @@ 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})")
StartFileMonitorAsAPluginTaskName = "Run as a Plugin" StartFileMonitorAsAPluginTaskName = "Monitor as a Plugin"
StartFileMonitorAsAServiceTaskName = "Start Library Monitor Service" StartFileMonitorAsAServiceTaskName = "Start Library Monitor Service"
FileMonitorPluginIsOnTaskQue = plugin.CALLED_AS_STASH_PLUGIN FileMonitorPluginIsOnTaskQue = plugin.CALLED_AS_STASH_PLUGIN
StopLibraryMonitorWaitingInTaskQueue = False StopLibraryMonitorWaitingInTaskQueue = False
@@ -105,88 +105,105 @@ def isJobWaitingToRun():
if plugin.CALLED_AS_STASH_PLUGIN: if plugin.CALLED_AS_STASH_PLUGIN:
plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})") plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})")
def trimDbFiles(dbPath, maxFiles):
if not os.path.exists(dbPath) or len(dbPath) < 5: # For safety and security, short path not supported.
return
dbFiles = sorted(os.listdir(dbPath))
n = len(dbFiles)
for i in range(0, n-maxFiles):
dbFilePath = f"{dbPath}{os.sep}{dbFiles[i]}"
plugin.Log(f"Removing file {dbFilePath}")
os.remove(dbFilePath)
# Reoccurring scheduler code class StashScheduler: # Stash Scheduler
# ToDo: Change the following functions into a class called reoccurringScheduler def __init__(self):
def runTask(task): import schedule # pip install schedule # https://github.com/dbader/schedule
import datetime dayOfTheWeek = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
plugin.Trace(f"Running task {task}") for task in plugin.pluginConfig['task_reoccurring_scheduler']:
if 'monthly' in task: if 'hours' in task and task['hours'] > 0:
dayOfTheMonth = datetime.datetime.today().day plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['hours']} hours interval")
FirstAllowedDate = ((task['monthly'] - 1) * 7) + 1 schedule.every(task['hours']).hours.do(self.runTask, task)
LastAllowedDate = task['monthly'] * 7 elif 'minutes' in task and task['minutes'] > 0:
if dayOfTheMonth < FirstAllowedDate or dayOfTheMonth > LastAllowedDate: plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['minutes']} minutes interval")
plugin.Log(f"Skipping task {task['task']} because today is not the right {task['weekday']} of the month. Target range is between {FirstAllowedDate} and {LastAllowedDate}.") schedule.every(task['minutes']).minutes.do(self.runTask, task)
elif 'days' in task and task['days'] > 0: # Left here for backward compatibility, but should use weekday logic instead.
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['days']} days interval")
schedule.every(task['days']).days.do(self.runTask, task)
elif 'weekday' in task and task['weekday'].lower() in dayOfTheWeek and 'time' in task:
if 'monthly' in task:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' monthly on number {task['monthly']} {task['weekday']} at {task['time']}")
else:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' (weekly) every {task['weekday']} at {task['time']}")
if task['weekday'].lower() == "monday":
schedule.every().monday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "tuesday":
schedule.every().tuesday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "wednesday":
schedule.every().wednesday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "thursday":
schedule.every().thursday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "friday":
schedule.every().friday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "saturday":
schedule.every().saturday.at(task['time']).do(self.runTask, task)
elif task['weekday'].lower() == "sunday":
schedule.every().sunday.at(task['time']).do(self.runTask, task)
self.checkSchedulePending()
def runTask(self, task):
import datetime
plugin.Trace(f"Running task {task}")
if 'monthly' in task:
dayOfTheMonth = datetime.datetime.today().day
FirstAllowedDate = ((task['monthly'] - 1) * 7) + 1
LastAllowedDate = task['monthly'] * 7
if dayOfTheMonth < FirstAllowedDate or dayOfTheMonth > LastAllowedDate:
plugin.Log(f"Skipping task {task['task']} because today is not the right {task['weekday']} of the month. Target range is between {FirstAllowedDate} and {LastAllowedDate}.")
return
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.LogOnce("Note: Backup task does not get listed in the Task Queue, but user can verify that it started by looking in the Stash log file as an INFO level log line.")
plugin.STASH_INTERFACE.backup_database()
if plugin.pluginSettings['zmaximumBackups'] > 1 and 'backupDirectoryPath' in plugin.STASH_CONFIGURATION:
if len(plugin.STASH_CONFIGURATION['backupDirectoryPath']) > 4 and os.path.exists(plugin.STASH_CONFIGURATION['backupDirectoryPath']):
plugin.LogOnce(f"Checking quantity of DB backups if path {plugin.STASH_CONFIGURATION['backupDirectoryPath']} exceeds {plugin.pluginSettings['zmaximumBackups']} backup files.")
self.trimDbFiles(plugin.STASH_CONFIGURATION['backupDirectoryPath'], plugin.pluginSettings['zmaximumBackups'])
elif task['task'] == "Scan":
plugin.STASH_INTERFACE.metadata_scan(paths=stashPaths)
elif task['task'] == "Auto Tag":
plugin.STASH_INTERFACE.metadata_autotag(paths=stashPaths, dry_run=plugin.DRY_RUN)
elif task['task'] == "Optimise Database":
plugin.STASH_INTERFACE.optimise_database()
elif task['task'] == "python":
script = task['script'].replace("<plugin_path>", f"{pathlib.Path(__file__).resolve().parent}{os.sep}")
plugin.Log(f"Executing python script {script}.")
args = [script]
if len(task['args']) > 0:
args = args + [task['args']]
plugin.ExecutePythonScript(args)
elif task['task'] == "execute":
cmd = task['command'].replace("<plugin_path>", f"{pathlib.Path(__file__).resolve().parent}{os.sep}")
plugin.Log(f"Executing command {cmd}.")
args = [cmd]
if len(task['args']) > 0:
args = args + [task['args']]
plugin.ExecuteProcess(args)
else:
# ToDo: Add code to check if plugin is installed.
plugin.Trace(f"Running plugin task pluginID={task['pluginId']}, task name = {task['task']}")
plugin.STASH_INTERFACE.run_plugin_task(plugin_id=task['pluginId'], task_name=task['task'])
def trimDbFiles(self, dbPath, maxFiles):
if not os.path.exists(dbPath):
plugin.LogOnce(f"Exiting trimDbFiles, because path {dbPath} does not exists.")
return return
if task['task'] == "Clean": if len(dbPath) < 5: # For safety and security, short path not supported.
plugin.STASH_INTERFACE.metadata_clean(paths=stashPaths, dry_run=plugin.DRY_RUN) plugin.LogOnce(f"Exiting trimDbFiles, because path {dbPath} is to short. Len={len(dbPath)}. Path string must be at least 5 characters in length.")
elif task['task'] == "Generate": return
plugin.STASH_INTERFACE.metadata_generate() dbFiles = sorted(os.listdir(dbPath))
elif task['task'] == "Backup": n = len(dbFiles)
plugin.LogOnce("Note: Backup task does not get listed in the Task Queue, but user can verify that it started by looking in the Stash log file as an INFO level log line.") for i in range(0, n-maxFiles):
plugin.STASH_INTERFACE.backup_database() dbFilePath = f"{dbPath}{os.sep}{dbFiles[i]}"
if plugin.pluginConfig['BackupsMax'] > 0 and plugin.pluginConfig['BackupDatabasePath'] != "" and os.path.exists(plugin.pluginConfig['BackupDatabasePath']): plugin.Warn(f"Deleting file {dbFilePath}")
plugin.Log("Checking quantity of DB backups.") os.remove(dbFilePath)
trimDbFiles(plugin.pluginConfig['BackupDatabasePath'], plugin.pluginConfig['BackupsMax'])
elif task['task'] == "Scan": def checkSchedulePending(self):
plugin.STASH_INTERFACE.metadata_scan(paths=stashPaths) import schedule # pip install schedule # https://github.com/dbader/schedule
elif task['task'] == "Auto Tag": schedule.run_pending()
plugin.STASH_INTERFACE.metadata_autotag(paths=stashPaths, dry_run=plugin.DRY_RUN)
elif task['task'] == "Optimise Database":
plugin.STASH_INTERFACE.optimise_database()
else:
# ToDo: Add code to check if plugin is installed.
plugin.Trace(f"Running plugin task pluginID={task['pluginId']}, task name = {task['task']}")
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
# ToDo: Extend schedule class so it works persistently (remember schedule between restarts)
# Or replace schedule with apscheduler https://github.com/agronholm/apscheduler
dayOfTheWeek = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
for task in plugin.pluginConfig['task_reoccurring_scheduler']:
if 'hours' in task and task['hours'] > 0:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['hours']} hours interval")
schedule.every(task['hours']).hours.do(runTask, task)
elif 'minutes' in task and task['minutes'] > 0:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['minutes']} minutes interval")
schedule.every(task['minutes']).minutes.do(runTask, task)
elif 'days' in task and task['days'] > 0:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' at {task['days']} days interval")
schedule.every(task['days']).days.do(runTask, task)
elif 'weekday' in task and task['weekday'].lower() in dayOfTheWeek and 'time' in task:
if 'monthly' in task:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' monthly on number {task['monthly']} {task['weekday']} at {task['time']}")
else:
plugin.Log(f"Adding to reoccurring scheduler task '{task['task']}' (weekly) every {task['weekday']} at {task['time']}")
if task['weekday'].lower() == "monday":
schedule.every().monday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "tuesday":
schedule.every().tuesday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "wednesday":
schedule.every().wednesday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "thursday":
schedule.every().thursday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "friday":
schedule.every().friday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "saturday":
schedule.every().saturday.at(task['time']).do(runTask, task)
elif task['weekday'].lower() == "sunday":
schedule.every().sunday.at(task['time']).do(runTask, task)
def checkSchedulePending():
import schedule # pip install schedule # https://github.com/dbader/schedule
schedule.run_pending()
if plugin.pluginSettings['turnOnScheduler']:
reoccurringScheduler()
def start_library_monitor(): def start_library_monitor():
global shouldUpdate global shouldUpdate
@@ -203,7 +220,7 @@ def start_library_monitor():
shm_buffer[0] = CONTINUE_RUNNING_SIG shm_buffer[0] = CONTINUE_RUNNING_SIG
plugin.Trace(f"Shared memory map opended, and flag set to {shm_buffer[0]}") plugin.Trace(f"Shared memory map opended, and flag set to {shm_buffer[0]}")
RunCleanMetadata = False RunCleanMetadata = False
stashScheduler = StashScheduler() if plugin.pluginSettings['turnOnScheduler'] else None
event_handler = watchdog.events.FileSystemEventHandler() event_handler = watchdog.events.FileSystemEventHandler()
def on_created(event): def on_created(event):
global shouldUpdate global shouldUpdate
@@ -294,7 +311,7 @@ def start_library_monitor():
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
if plugin.pluginSettings['turnOnScheduler']: if plugin.pluginSettings['turnOnScheduler']:
checkSchedulePending() stashScheduler.checkSchedulePending()
plugin.LogOnce("Waiting for a file change-trigger.") plugin.LogOnce("Waiting for a file change-trigger.")
signal.wait(timeout=SIGNAL_TIMEOUT) signal.wait(timeout=SIGNAL_TIMEOUT)
if plugin.pluginSettings['turnOnScheduler'] and not shouldUpdate: if plugin.pluginSettings['turnOnScheduler'] and not shouldUpdate:
@@ -376,8 +393,6 @@ def stop_library_monitor():
shm_a.unlink() # Call unlink only once to release the shared memory shm_a.unlink() # Call unlink only once to release the shared memory
def start_library_monitor_service(): def start_library_monitor_service():
import subprocess
import platform
# First check if FileMonitor is already running # First check if FileMonitor is already running
try: try:
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=4) shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=4)
@@ -387,20 +402,9 @@ def start_library_monitor_service():
return return
except: except:
pass pass
plugin.Trace("FileMonitor is not running, so safe to start it as a service.") plugin.Trace("FileMonitor is not running, so it's safe to start it as a service.")
is_windows = any(platform.win32_ver()) args = [f"{pathlib.Path(__file__).resolve().parent}{os.sep}filemonitor.py", '--url', f"{plugin.STASH_URL}"]
PythonExe = f"{sys.executable}" plugin.ExecutePythonScript(args)
# PythonExe = PythonExe.replace("python.exe", "pythonw.exe")
args = [f"{PythonExe}", f"{pathlib.Path(__file__).resolve().parent}{os.sep}filemonitor.py", '--url', f"{plugin.STASH_URL}"]
plugin.Trace(f"args={args}")
if is_windows:
plugin.Trace("Executing process using Windows DETACHED_PROCESS")
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen(args,creationflags=DETACHED_PROCESS, shell=True).pid
else:
plugin.Trace("Executing process using normal Popen")
pid = subprocess.Popen(args).pid
plugin.Trace(f"pid={pid}")
if parse_args.stop or parse_args.restart or plugin.PLUGIN_TASK_NAME == "stop_library_monitor": if parse_args.stop or parse_args.restart or plugin.PLUGIN_TASK_NAME == "stop_library_monitor":
stop_library_monitor() stop_library_monitor()

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.7.7 version: 0.7.8
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:
@@ -11,13 +11,13 @@ settings:
displayName: Scheduler displayName: Scheduler
description: Enable to turn on the scheduler. See filemonitor_config.py for more details. description: Enable to turn on the scheduler. See filemonitor_config.py for more details.
type: BOOLEAN type: BOOLEAN
zmaximumBackups:
displayName: Max DB Backups
description: When value greater than 1, will trim the number of database backup files to set value. Requires [Scheduler] enabled and backupDirectoryPath populated with path length longer than 4.
type: NUMBER
zzdebugTracing: zzdebugTracing:
displayName: Debug Tracing displayName: Debug Tracing
description: (Default=false) [***For Advanced Users***] Enable debug tracing. When enabled, additional tracing logging is added to Stash\plugins\FileMonitor\filemonitor.log description: Enable debug tracing. When enabled, additional tracing logging is added to Stash\plugins\FileMonitor\filemonitor.log
type: BOOLEAN
zzdryRun:
displayName: Dry Run
description: Enable to run script in [Dry Run] mode. In this mode, Stash does NOT call meta_scan, and only logs the action it would have taken.
type: BOOLEAN type: BOOLEAN
exec: exec:
- python - python
@@ -25,14 +25,14 @@ exec:
interface: raw interface: raw
tasks: tasks:
- name: Start Library Monitor Service - name: Start Library Monitor Service
description: Run as a SERVICE to monitors paths in Stash library for media file changes, and updates Stash. Recommended start method. description: Run [Library Monitor] as a SERVICE to update Stash with any media file changes.
defaultArgs: defaultArgs:
mode: start_library_monitor_service mode: start_library_monitor_service
- name: Stop Library Monitor - name: Stop Library Monitor
description: Stops library monitoring within 2 minute. description: Stops library monitoring within 2 minute.
defaultArgs: defaultArgs:
mode: stop_library_monitor mode: stop_library_monitor
- name: Run as a Plugin - name: Monitor as a Plugin
description: Run [Library Monitor] as a plugin (*not recommended method*) description: Run [Library Monitor] as a plugin (*not recommended method*)
defaultArgs: defaultArgs:
mode: start_library_monitor mode: start_library_monitor

View File

@@ -42,16 +42,17 @@ config = {
# Example monthly method. # Example monthly method.
{"task" : "Backup", "weekday" : "sunday", "time" : "01:00", "monthly" : 2}, # Backup -> [Backup] 2nd sunday of the month at 1AM (01:00) {"task" : "Backup", "weekday" : "sunday", "time" : "01:00", "monthly" : 2}, # Backup -> [Backup] 2nd sunday of the month at 1AM (01:00)
# The following is a place holder for a plugin. # Example task for calling another Stash plugin, which needs plugin name and plugin ID.
{"task" : "PluginButtonName_Here", "pluginId" : "PluginId_Here", "hours" : 0}, # The zero frequency value makes this task disabled. {"task" : "PluginButtonName_Here", "pluginId" : "PluginId_Here", "hours" : 0}, # The zero frequency value makes this task disabled.
# Add additional plugin task here. # Add additional plugin task here.
# Example task to call a python script
{"task" : "python", "script" : "<plugin_path>test_script_hello_world.py", "args" : "--MyArguments Hello", "minutes" : 0},
# Example task to execute a command
{"task" : "execute", "command" : "C:\\MyPath\\HelloWorld.bat", "args" : "", "hours" : 0},
], ],
# Maximum backups to keep. When scheduler is enabled, and the Backup runs, delete older backups after reaching maximum backups.
"BackupsMax" : 12, # Only works if BackupDatabasePath is properly populated.
# The BACKUP database path. ToDo: Implement code to automate fetching this value
"BackupDatabasePath" : "C:\\Users\\admin3\\.stash\\DbBackup", # Example populated path
# 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!!!!