From b546e73a1f7f785762850e7fcd267ae42eb82cbd Mon Sep 17 00:00:00 2001 From: TylerCG <117808427+TylerCG@users.noreply.github.com> Date: Sat, 13 Sep 2025 21:49:56 -0400 Subject: [PATCH] Update watcher.py --- watcher.py | 102 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/watcher.py b/watcher.py index e3070a5..b00744a 100644 --- a/watcher.py +++ b/watcher.py @@ -1,61 +1,103 @@ +#!/usr/bin/env python3 +import sys +import time +import threading import os import subprocess -import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler -WATCH_DIR = "/data" +DEBOUNCE_DELAY = 2 # seconds to wait after last modification DEBUG = os.environ.get("DEBUG", "false").lower() == "true" -MERGE_ALL = os.environ.get("MERGE_ALL", "false").lower() == "true" -class NewBookHandler(FileSystemEventHandler): - def on_created(self, event): - if DEBUG: - print(f"📂 [DEBUG] Created: {event.src_path} (dir={event.is_directory})") - if event.is_directory: - self.process_new_dir(event.src_path) +class WatcherHandler(FileSystemEventHandler): + def __init__(self): + super().__init__() + self.debounce_timers = {} # path -> Timer + self.processed_folders = set() # already processed folders - def on_moved(self, event): - if DEBUG: - print(f"📂 [DEBUG] Moved: {event.src_path} → {event.dest_path} (dir={event.is_directory})") - if event.is_directory: - self.process_new_dir(event.dest_path) + def on_any_event(self, event): + # Print all events + if event.event_type == "moved": + print(f"{'DIR' if event.is_directory else 'FILE'} MOVED: {event.src_path} -> {event.dest_path}") + else: + print(f"{'DIR' if event.is_directory else 'FILE'} {event.event_type.upper()}: {event.src_path}") - def on_modified(self, event): - if DEBUG: - print(f"📂 [DEBUG] Modified: {event.src_path} (dir={event.is_directory})") + # Only schedule processing for directories + if event.is_directory and event.event_type in ("created", "moved", "modified"): + path_to_process = event.dest_path if event.event_type == "moved" else event.src_path + self.schedule_process(path_to_process) - def on_deleted(self, event): - if DEBUG: - print(f"📂 [DEBUG] Deleted: {event.src_path} (dir={event.is_directory})") + def schedule_process(self, path): + """Debounce processing of a folder.""" + if path in self.debounce_timers: + self.debounce_timers[path].cancel() + + timer = threading.Timer(DEBOUNCE_DELAY, self.process_new_dir, args=[path]) + self.debounce_timers[path] = timer + timer.start() def process_new_dir(self, path): - # find .m4b files in this new book directory + """Called after folder is stable for DEBOUNCE_DELAY seconds.""" + if path in self.debounce_timers: + del self.debounce_timers[path] + + if not os.path.exists(path): + if DEBUG: + print(f"⚠️ Skipping {path}, folder no longer exists") + return + + # Check if folder has .m4b files m4b_files = [ f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) and f.lower().endswith(".m4b") and not f.startswith("._") ] - if MERGE_ALL and len(m4b_files) <= 1: + if not m4b_files: if DEBUG: - print(f"⚠️ [DEBUG] Skipping {path}, only {len(m4b_files)} file(s).") + print(f"❌ No .m4b files in {path}, skipping") return - book_name = os.path.basename(path) - print(f"📕 New book detected: {book_name} at {path} ({len(m4b_files)} file(s))") + # Avoid re-processing the same folder + if path in self.processed_folders: + if DEBUG: + print(f"⚠️ Folder already processed: {path}") + return + self.processed_folders.add(path) - subprocess.run(["python3", "main.py", "-da", path], check=True) + print(f"📂 Folder ready: {path} contains {len(m4b_files)} .m4b file(s)") -if __name__ == "__main__": - print(f"👀 Watching {WATCH_DIR} for new books...") + # Run main.py -da + try: + subprocess.run(["python3", "main.py", "-da", path], check=True) + print(f"✅ Processed folder: {path}") + except subprocess.CalledProcessError as e: + print(f"❌ Error processing folder {path}: {e}") + +def main(): + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} /path/to/watch") + sys.exit(1) + + watch_path = sys.argv[1] + + if not os.path.exists(watch_path): + print(f"❌ Path does not exist: {watch_path}") + sys.exit(1) + + event_handler = WatcherHandler() observer = Observer() - event_handler = NewBookHandler() - observer.schedule(event_handler, WATCH_DIR, recursive=True) + observer.schedule(event_handler, watch_path, recursive=True) observer.start() + print(f"👀 Watching: {watch_path}") try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() + + +if __name__ == "__main__": + main()