diff --git a/StashPluginHelper/StashPluginHelper.py b/StashPluginHelper/StashPluginHelper.py index b8bc35d..1896800 100644 --- a/StashPluginHelper/StashPluginHelper.py +++ b/StashPluginHelper/StashPluginHelper.py @@ -102,7 +102,7 @@ class StashPluginHelper: if stash_url and len(stash_url): self.STASH_URL = stash_url self.MAIN_SCRIPT_NAME = mainScriptName if mainScriptName != "" else __main__.__file__ self.PLUGIN_ID = pluginID if pluginID != "" else pathlib.Path(self.MAIN_SCRIPT_NAME).stem.lower() - print(f"self.MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME}, self.PLUGIN_ID={self.PLUGIN_ID}", file=sys.stderr) + # print(f"self.MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME}, self.PLUGIN_ID={self.PLUGIN_ID}", file=sys.stderr) self.LOG_FILE_NAME = logFilePath if logFilePath != "" else f"{pathlib.Path(self.MAIN_SCRIPT_NAME).resolve().parent}{os.sep}{pathlib.Path(self.MAIN_SCRIPT_NAME).stem}.log" self.LOG_FILE_DIR = pathlib.Path(self.LOG_FILE_NAME).resolve().parent RFH = RotatingFileHandler( diff --git a/plugins/.gitignore b/plugins/.gitignore index 0492246..14e9df5 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -33,6 +33,7 @@ renamefile_settings.cpython-310.pyc /WindowsSymbolicLinkCleaner /DeleteMe /ATestPlugin +/FileMonitor/working ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/plugins/FileMonitor/StashPluginHelper.py b/plugins/FileMonitor/StashPluginHelper.py index b8bc35d..1896800 100644 --- a/plugins/FileMonitor/StashPluginHelper.py +++ b/plugins/FileMonitor/StashPluginHelper.py @@ -102,7 +102,7 @@ class StashPluginHelper: if stash_url and len(stash_url): self.STASH_URL = stash_url self.MAIN_SCRIPT_NAME = mainScriptName if mainScriptName != "" else __main__.__file__ self.PLUGIN_ID = pluginID if pluginID != "" else pathlib.Path(self.MAIN_SCRIPT_NAME).stem.lower() - print(f"self.MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME}, self.PLUGIN_ID={self.PLUGIN_ID}", file=sys.stderr) + # print(f"self.MAIN_SCRIPT_NAME={self.MAIN_SCRIPT_NAME}, self.PLUGIN_ID={self.PLUGIN_ID}", file=sys.stderr) self.LOG_FILE_NAME = logFilePath if logFilePath != "" else f"{pathlib.Path(self.MAIN_SCRIPT_NAME).resolve().parent}{os.sep}{pathlib.Path(self.MAIN_SCRIPT_NAME).stem}.log" self.LOG_FILE_DIR = pathlib.Path(self.LOG_FILE_NAME).resolve().parent RFH = RotatingFileHandler( diff --git a/plugins/FileMonitor/filemonitor.py b/plugins/FileMonitor/filemonitor.py index e6c065f..4695b4d 100644 --- a/plugins/FileMonitor/filemonitor.py +++ b/plugins/FileMonitor/filemonitor.py @@ -22,8 +22,15 @@ parser.add_argument('--url', '-u', dest='stash_url', type=str, help='Add Stash U parser.add_argument('--trace', '-t', dest='trace', action='store_true', help='Enables debug trace mode.') parser.add_argument('--stop', '-s', dest='stop', action='store_true', help='Stop (kill) a running FileMonitor task.') parser.add_argument('--restart', '-r', dest='restart', action='store_true', help='Restart FileMonitor.') +parser.add_argument('--silent', '--quit', '-q', dest='quit', action='store_true', help='Run in silent mode. No output to console or stderr. Use this when running from pythonw.exe') parse_args = parser.parse_args() +logToErrSet = 0 +logToNormSet = 0 +if parse_args.quit: + logToErrSet = 1 + logToNormSet = 1 + settings = { "recursiveDisabled": False, "zzdebugTracing": False, @@ -33,7 +40,10 @@ plugin = StashPluginHelper( stash_url=parse_args.stash_url, debugTracing=parse_args.trace, settings=settings, - config=config) + config=config, + logToErrSet=logToErrSet, + logToNormSet=logToNormSet + ) plugin.Status() plugin.Log(f"\nStarting (__file__={__file__}) (plugin.CALLED_AS_STASH_PLUGIN={plugin.CALLED_AS_STASH_PLUGIN}) (plugin.DEBUG_TRACING={plugin.DEBUG_TRACING}) (plugin.DRY_RUN={plugin.DRY_RUN}) (plugin.PLUGIN_TASK_NAME={plugin.PLUGIN_TASK_NAME})************************************************") @@ -69,6 +79,22 @@ 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})") +def isJobWaitingToRun(): + i = 1 + while i < 999: + jobDetails = plugin.STASH_INTERFACE.find_job(i) + if jobDetails: + plugin.Trace(f"(Job ID({i})={jobDetails})") + if jobDetails['status'] == "READY" and jobDetails['description'] != "Running plugin task: Start Library Monitor": + return i + else: + plugin.Trace(f"Last job {i}") + break + i += 1 + return 0 + +plugin.Trace(f"isJobWaitingToRun() = {isJobWaitingToRun()})") + def start_library_monitor(): global shouldUpdate global TargetPaths @@ -154,6 +180,8 @@ def start_library_monitor(): observer.schedule(event_handler, path, recursive=RECURSIVE) plugin.Trace(f"Observing {path}") observer.start() + JobIsRunning = False + PutPluginBackOnTaskQueAndExit = False plugin.Trace("Starting loop") try: while True: @@ -161,11 +189,19 @@ def start_library_monitor(): with mutex: while not shouldUpdate: plugin.Trace("Wait start") - signal.wait(timeout=SIGNAL_TIMEOUT) + if plugin.CALLED_AS_STASH_PLUGIN: + signal.wait(timeout=SIGNAL_TIMEOUT) + else: + signal.wait() plugin.Trace("Wait end") if shm_buffer[0] != CONTINUE_RUNNING_SIG: plugin.Log(f"Breaking out of loop. (shm_buffer[0]={shm_buffer[0]})") break + JobIdInTheQue = isJobWaitingToRun() + if plugin.CALLED_AS_STASH_PLUGIN and JobIdInTheQue: + plugin.Log(f"Another task (JobID={JobIdInTheQue}) is waiting on the queue. Will restart FileMonitor to allow other task to run.") + JobIsRunning = True + shouldUpdate = True shouldUpdate = False TmpTargetPaths = [] for TargetPath in TargetPaths: @@ -186,16 +222,19 @@ def start_library_monitor(): if RUN_GENERATE_CONTENT: plugin.STASH_INTERFACE.metadata_generate() if plugin.CALLED_AS_STASH_PLUGIN and shm_buffer[0] == CONTINUE_RUNNING_SIG: - plugin.STASH_INTERFACE.run_plugin_task(plugin_id=plugin.PLUGIN_ID, task_name="Start Library Monitor") - plugin.Trace("Exiting plugin so that metadata_scan task can run.") - return + PutPluginBackOnTaskQueAndExit = True else: plugin.Trace("Nothing to scan.") - if shm_buffer[0] != CONTINUE_RUNNING_SIG: + + if shm_buffer[0] != CONTINUE_RUNNING_SIG: plugin.Log(f"Exiting Change File Monitor. (shm_buffer[0]={shm_buffer[0]})") shm_a.close() shm_a.unlink() # Call unlink only once to release the shared memory raise KeyboardInterrupt + elif JobIsRunning or PutPluginBackOnTaskQueAndExit: + plugin.STASH_INTERFACE.run_plugin_task(plugin_id=plugin.PLUGIN_ID, task_name="Start Library Monitor") + plugin.Trace("Exiting plugin so that other task can run.") + return except KeyboardInterrupt: observer.stop() plugin.Trace("Stopping observer") diff --git a/plugins/FileMonitor/filemonitor_config.py b/plugins/FileMonitor/filemonitor_config.py index 2cf62d9..57b3a46 100644 --- a/plugins/FileMonitor/filemonitor_config.py +++ b/plugins/FileMonitor/filemonitor_config.py @@ -8,8 +8,8 @@ config = { "onAnyEvent": False, # 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 a stop signal is sent. - "timeOut": 3600, + # 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. # 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