"""Video-side download SETTINGS (isolated). Persists the video download configuration in video.db's ``video_settings`` KV table — fully separate from the music ``soulseek.*`` paths so the two libraries never share a folder or collide. The actual download fulfillment engine (wishlist → search → grab) is a later roadmap phase; these endpoints just store/serve the config the Settings → Downloads tab edits. Keys persisted here (all under video.db): - ``download_path`` : input folder a video download lands in - ``transfer_path`` : output folder finished video files move to (video library) Connection settings that are genuinely SHARED with music (the slskd instance, the torrent/usenet clients, Prowlarr indexers) are NOT stored here — those live in the music config_manager and are surfaced on the shared Indexers tab + shared slskd block (a deliberate shared boundary, since they're one physical resource). """ from __future__ import annotations from flask import jsonify, request from utils.logging_config import get_logger logger = get_logger("video_api.downloads") # Video-specific path keys (vs. the shared connection settings). _PATH_KEYS = ("download_path", "transfer_path") # slskd CONNECTION settings genuinely SHARED with music — one slskd instance serves # both sides, so these live in the app-wide config_manager (soulseek.*), NOT video.db. # Deliberately excludes the music download/transfer PATHS and source mode/quality — # those are video-specific (stored in video.db). Maps the video field name -> the # shared config key + default. (config_manager is shared app config, not music code.) _SLSKD_KEYS = { "slskd_url": ("soulseek.slskd_url", "http://localhost:5030"), "api_key": ("soulseek.api_key", ""), "search_timeout": ("soulseek.search_timeout", 60), "search_timeout_buffer": ("soulseek.search_timeout_buffer", 15), "search_min_delay_seconds": ("soulseek.search_min_delay_seconds", 0), "min_peer_upload_speed": ("soulseek.min_peer_upload_speed", 0), "max_peer_queue": ("soulseek.max_peer_queue", 0), "download_timeout": ("soulseek.download_timeout", 600), # seconds (UI shows minutes) "auto_clear_searches": ("soulseek.auto_clear_searches", True), } def register_routes(bp): @bp.route("/downloads/config", methods=["GET"]) def video_downloads_config(): from . import get_video_db from core.video.download_config import load as load_source db = get_video_db() out = {k: db.get_setting(k) or "" for k in _PATH_KEYS} out.update(load_source(db)) # download_mode + hybrid_order return jsonify(out) @bp.route("/downloads/config", methods=["POST"]) def video_downloads_config_save(): from . import get_video_db from core.video.download_config import save as save_source db = get_video_db() body = request.get_json(silent=True) or {} for key in _PATH_KEYS: if key in body: db.set_setting(key, (str(body.get(key) or "")).strip()) save_source(db, body) # download_mode + hybrid_order (validated) return jsonify({"status": "saved"}) @bp.route("/downloads/quality", methods=["GET"]) def video_quality_profile(): from . import get_video_db from core.video.quality_profile import load return jsonify(load(get_video_db())) @bp.route("/downloads/quality", methods=["POST"]) def video_quality_profile_save(): from . import get_video_db from core.video.quality_profile import save body = request.get_json(silent=True) or {} return jsonify(save(get_video_db(), body)) @bp.route("/downloads/slskd", methods=["GET"]) def video_slskd_config(): # SHARED with music — same slskd instance. Reads the app-wide config_manager. from config.settings import config_manager return jsonify({k: config_manager.get(cfg, default) for k, (cfg, default) in _SLSKD_KEYS.items()}) @bp.route("/downloads/slskd", methods=["POST"]) def video_slskd_config_save(): from config.settings import config_manager body = request.get_json(silent=True) or {} for k, (cfg, _default) in _SLSKD_KEYS.items(): if k in body: config_manager.set(cfg, body.get(k)) return jsonify({"status": "saved", "shared": True})