The slskd CONNECTION settings (URL, API key, search timeout + buffer, min delay, min peer speed, max peer queue, download timeout, auto-clear) are genuinely shared — one slskd instance serves both sides — so the video Downloads tab surfaces them and they read/write the app-wide config_manager soulseek.* keys, NOT video.db. Changing them on the video side changes them for Music too (labeled 'shared with Music'). Deliberately EXCLUDES the music download/transfer paths and source mode/quality — those stay video-specific (video.db, phases 1-3). The block shows only when soulseek is the active/primary source (or in the hybrid chain). The 'Indexers & Downloaders' tab is already fully shared (no video override — only data-stg='downloads' is hidden). - /api/video/downloads/slskd GET/POST over config_manager (config.settings — shared app config, not music code; the isolation test still passes). - video-settings.js loadSlskd/saveSlskd (minutes↔seconds for the timeout), gated by soulseekActive(), wired into onPageShown + the save chain. 68 video API tests green (incl. the no-music-imports guard + a shared-slskd test that asserts it writes soulseek.* but never the video paths). Completes the Downloads-tab settings batch (folders, quality profile, source/hybrid, shared slskd).
97 lines
4.3 KiB
Python
97 lines
4.3 KiB
Python
"""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})
|