diff --git a/api/video/downloads.py b/api/video/downloads.py index 065d6638..6fd867ce 100644 --- a/api/video/downloads.py +++ b/api/video/downloads.py @@ -7,8 +7,12 @@ never share a folder or collide. The actual download fulfillment engine (wishlis 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) + - ``download_path`` : input folder a video download lands in (shared by all types) + - ``movies_path`` : Movies library (finished movies move here) + - ``tv_path`` : TV Shows library + - ``youtube_path`` : YouTube library (kept separate from real TV) + The engine routes a finished download to the path matching its type. (Legacy single + ``transfer_path`` is migrated into ``movies_path`` on first read.) 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 @@ -24,8 +28,9 @@ 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") +# Video-specific path keys (vs. the shared connection settings): one shared input +# folder + a separate library folder per content type. +_PATH_KEYS = ("download_path", "movies_path", "tv_path", "youtube_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. @@ -52,6 +57,8 @@ def register_routes(bp): 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} + if not out["movies_path"]: # migrate the legacy single transfer folder → Movies + out["movies_path"] = db.get_setting("transfer_path") or "" out.update(load_source(db)) # download_mode + hybrid_order return jsonify(out) diff --git a/tests/test_video_api.py b/tests/test_video_api.py index d711303e..fea9ee48 100644 --- a/tests/test_video_api.py +++ b/tests/test_video_api.py @@ -366,18 +366,24 @@ def test_downloads_config_save_load(tmp_path): app.register_blueprint(videoapi.create_video_blueprint(), url_prefix="/api/video") client = app.test_client() try: - # Defaults: empty folders, soulseek mode. + # Defaults: empty folders, soulseek mode. One shared input + per-type libraries. assert client.get("/api/video/downloads/config").get_json() == { - "download_path": "", "transfer_path": "", + "download_path": "", "movies_path": "", "tv_path": "", "youtube_path": "", "download_mode": "soulseek", "hybrid_order": ["soulseek"]} # Round-trips + persists to video.db (separate from any music config). client.post("/api/video/downloads/config", - json={"download_path": " /mnt/v/dl ", "transfer_path": "/mnt/v/lib", + json={"download_path": " /mnt/v/dl ", "movies_path": "/media/movies", + "tv_path": "/media/tv", "youtube_path": "/media/yt", "download_mode": "hybrid", "hybrid_order": ["torrent", "usenet"]}) assert client.get("/api/video/downloads/config").get_json() == { - "download_path": "/mnt/v/dl", "transfer_path": "/mnt/v/lib", # trimmed + "download_path": "/mnt/v/dl", "movies_path": "/media/movies", # trimmed + "tv_path": "/media/tv", "youtube_path": "/media/yt", "download_mode": "hybrid", "hybrid_order": ["torrent", "usenet"]} assert db.get_setting("download_path") == "/mnt/v/dl" + # Legacy single transfer_path migrates into Movies when movies_path is unset. + db.set_setting("movies_path", "") + db.set_setting("transfer_path", "/old/lib") + assert client.get("/api/video/downloads/config").get_json()["movies_path"] == "/old/lib" finally: videoapi._video_db = None diff --git a/webui/index.html b/webui/index.html index 39fcd772..94ff63d2 100644 --- a/webui/index.html +++ b/webui/index.html @@ -6017,15 +6017,24 @@