""" main.py ======= Container entry point. Watches the mounted Suwayomi download directory and, after a quiet period, triggers SuwayomiMover (which also runs the Kavita person sync for every processed series). Mount points (Docker) --------------------- /mnt/suwayomi -> Suwayomi downloads (read/write, sources deleted) /mnt/kavita -> Kavita library (read/write, CBZs written here) Environment variables --------------------- Required: KAVITA_URL base URL of the Kavita server, e.g. http://kavita:5000 KAVITA_API_KEY Kavita API key (Settings → User → API key) Optional: SUWAYOMI_PATH default /mnt/suwayomi KAVITA_PATH default /mnt/kavita LANGUAGE default en SETTLE_SECONDS default 600 (10-minute quiet window) REQUEST_TIMEOUT default 30 DELETE_SOURCE default true (delete source folders after pack) """ from __future__ import annotations import os import signal import sys from pathlib import Path # Make src/ importable when running as `python main.py`. sys.path.insert(0, str(Path(__file__).resolve().parent / "src")) from src.SuwayomiMover import SuwayomiMover # noqa: E402 from src.SuwayomiFolderWatcher import SuwayomiFolderWatcher # noqa: E402 def _env_str(name: str, default: "str | None" = None, required: bool = False) -> "str | None": value = os.environ.get(name, default) if required and not value: print(f"[main] missing required env var: {name}", flush=True) sys.exit(2) return value def _env_int(name: str, default: int) -> int: raw = os.environ.get(name) if raw is None or raw == "": return default try: return int(raw) except ValueError: print(f"[main] {name}={raw!r} is not a valid integer; " f"falling back to {default}", flush=True) return default def _env_bool(name: str, default: bool) -> bool: raw = os.environ.get(name) if raw is None: return default return raw.strip().lower() in ("1", "true", "yes", "y", "on") def main() -> int: suwayomi_path = _env_str("SUWAYOMI_PATH", "/mnt/suwayomi") kavita_path = _env_str("KAVITA_PATH", "/mnt/kavita") kavita_url = _env_str("KAVITA_URL", required=True) kavita_api_key = _env_str("KAVITA_API_KEY", required=True) language = _env_str("LANGUAGE", "en") or "en" settle_seconds = _env_int("SETTLE_SECONDS", 600) request_timeout = _env_int("REQUEST_TIMEOUT", 30) delete_source = _env_bool("DELETE_SOURCE", True) print(f"[main] suwayomi = {suwayomi_path}", flush=True) print(f"[main] kavita = {kavita_path}", flush=True) print(f"[main] kavita url= {kavita_url}", flush=True) print(f"[main] settle = {settle_seconds}s", flush=True) print(f"[main] language = {language}", flush=True) print(f"[main] delete src= {delete_source}", flush=True) mover = SuwayomiMover( suwayomi_path, kavita_path, kavita_base_url=kavita_url, kavita_api_key=kavita_api_key, language=language, request_timeout=request_timeout, delete_source=delete_source, ) watcher = SuwayomiFolderWatcher( suwayomi_path, mover, settle_seconds=settle_seconds) def shutdown(signum, _frame): print(f"[main] received signal {signum}", flush=True) watcher.stop() signal.signal(signal.SIGTERM, shutdown) signal.signal(signal.SIGINT, shutdown) watcher.start() watcher.wait() # blocks until stop() is called via a signal return 0 if __name__ == "__main__": sys.exit(main())