from __future__ import annotations import argparse import os import signal import subprocess import time from common import touch_ready, wait_for_tcp def write_config(profile: str, data_dir: str, port: int) -> None: cfg_dir = os.path.join(profile, "qBittorrent", "config") os.makedirs(cfg_dir, exist_ok=True) # qBittorrent stores settings in an INI-like file with escaped keys. # These disable internet/discovery paths and fix the peer port. with open(os.path.join(cfg_dir, "qBittorrent.conf"), "w", encoding="utf-8") as f: f.write(f"""[BitTorrent] Session\\AddTorrentPaused=false Session\\BTProtocol=TCP Session\\DHTEnabled=false Session\\DefaultSavePath={data_dir} Session\\DisableAutoTMMByDefault=true Session\\LSDEnabled=false Session\\PeXEnabled=false Session\\Port={port} Session\\QueueingSystemEnabled=false Session\\UPnP=false [LegalNotice] Accepted=true [Preferences] WebUI\\Enabled=false """) def main() -> int: ap = argparse.ArgumentParser(description="Seed a fixture with qBittorrent-nox.") ap.add_argument("--torrent", required=True) ap.add_argument("--data", required=True) ap.add_argument("--port", type=int, required=True) args = ap.parse_args() profile = "/tmp/qbt-profile" write_config(profile, args.data, args.port) cmd = [ "qbittorrent-nox", f"--profile={profile}", "--configuration=interop", f"--torrenting-port={args.port}", f"--save-path={args.data}", "--add-paused=false", "--skip-dialog=true", "--skip-hash-check", args.torrent, ] proc = subprocess.Popen(cmd) stop = False def _stop(signum, frame): nonlocal stop stop = True proc.terminate() signal.signal(signal.SIGTERM, _stop) signal.signal(signal.SIGINT, _stop) try: wait_for_tcp("127.0.0.1", args.port, timeout=45) if proc.poll() is not None: return proc.returncode or 1 touch_ready() print(f"qBittorrent seeding on {args.port}", flush=True) while not stop and proc.poll() is None: time.sleep(1) return proc.returncode or 0 finally: if proc.poll() is None: proc.terminate() try: proc.wait(timeout=10) except subprocess.TimeoutExpired: proc.kill() if __name__ == "__main__": raise SystemExit(main())