Update watcher.py

This commit is contained in:
TylerCG 2025-09-13 21:49:56 -04:00
parent 35917c506e
commit b546e73a1f

View File

@ -1,61 +1,103 @@
#!/usr/bin/env python3
import sys
import time
import threading
import os import os
import subprocess import subprocess
import time
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler 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" DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
MERGE_ALL = os.environ.get("MERGE_ALL", "false").lower() == "true"
class NewBookHandler(FileSystemEventHandler): class WatcherHandler(FileSystemEventHandler):
def on_created(self, event): def __init__(self):
if DEBUG: super().__init__()
print(f"📂 [DEBUG] Created: {event.src_path} (dir={event.is_directory})") self.debounce_timers = {} # path -> Timer
if event.is_directory: self.processed_folders = set() # already processed folders
self.process_new_dir(event.src_path)
def on_moved(self, event): def on_any_event(self, event):
if DEBUG: # Print all events
print(f"📂 [DEBUG] Moved: {event.src_path}{event.dest_path} (dir={event.is_directory})") if event.event_type == "moved":
if event.is_directory: print(f"{'DIR' if event.is_directory else 'FILE'} MOVED: {event.src_path} -> {event.dest_path}")
self.process_new_dir(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): # Only schedule processing for directories
if DEBUG: if event.is_directory and event.event_type in ("created", "moved", "modified"):
print(f"📂 [DEBUG] Modified: {event.src_path} (dir={event.is_directory})") 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): def schedule_process(self, path):
if DEBUG: """Debounce processing of a folder."""
print(f"📂 [DEBUG] Deleted: {event.src_path} (dir={event.is_directory})") 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): 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 = [ m4b_files = [
f for f in os.listdir(path) 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 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: if DEBUG:
print(f"⚠️ [DEBUG] Skipping {path}, only {len(m4b_files)} file(s).") print(f"❌ No .m4b files in {path}, skipping")
return return
book_name = os.path.basename(path) # Avoid re-processing the same folder
print(f"📕 New book detected: {book_name} at {path} ({len(m4b_files)} file(s))") 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__": # Run main.py -da
print(f"👀 Watching {WATCH_DIR} for new books...") 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() observer = Observer()
event_handler = NewBookHandler() observer.schedule(event_handler, watch_path, recursive=True)
observer.schedule(event_handler, WATCH_DIR, recursive=True)
observer.start() observer.start()
print(f"👀 Watching: {watch_path}")
try: try:
while True: while True:
time.sleep(1) time.sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
observer.stop() observer.stop()
observer.join() observer.join()
if __name__ == "__main__":
main()