Fix jellyfin sync config merging
This commit is contained in:
+2
-1
@@ -757,9 +757,10 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
const rootGroup = document.createElement("div");
|
||||
rootGroup.className = "browser-roots";
|
||||
for (const rootPath of roots) {
|
||||
const active = data.path === rootPath || String(data.path || "").startsWith(`${rootPath}/`);
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = `ghost${rootPath === data.path ? " active" : ""}`;
|
||||
button.className = `ghost${active ? " active" : ""}`;
|
||||
button.textContent = rootPath;
|
||||
button.addEventListener("click", () => loadPathBrowser(rootPath));
|
||||
rootGroup.appendChild(button);
|
||||
|
||||
+6
-3
@@ -629,14 +629,17 @@ class Handler(BaseHTTPRequestHandler):
|
||||
Handler.update_config(self, Handler.require_json_object(self, self.body_json()))
|
||||
elif parsed.path == "/api/config/jellyfin/sync":
|
||||
payload = Handler.require_json_object(self, self.body_json())
|
||||
current = Handler._context(self).get_config_snapshot()
|
||||
merged = dict(current)
|
||||
merged.update(payload)
|
||||
for key, label in (
|
||||
("download_dir", "download directory"),
|
||||
("jellyfin_tv_dir", "Jellyfin TV directory"),
|
||||
("jellyfin_movie_dir", "Jellyfin movie directory"),
|
||||
):
|
||||
if str(payload.get(key) or "").strip():
|
||||
Handler.validate_remote_path(self, payload[key], label)
|
||||
self.json(Handler._context(self).run_jellyfin_sync(payload))
|
||||
if str(merged.get(key) or "").strip():
|
||||
Handler.validate_remote_path(self, merged[key], label)
|
||||
self.json(Handler._context(self).run_jellyfin_sync(merged))
|
||||
elif parsed.path == "/api/config/webhook/test":
|
||||
payload = Handler.require_json_object(self, self.body_json())
|
||||
validate_discord_webhook_url(payload.get("discord_webhook_url"))
|
||||
|
||||
+36
-1
@@ -3023,11 +3023,45 @@ class HandlerRouteTests(unittest.TestCase):
|
||||
body = b'{"download_dir":"/tmp/example","jellyfin_sync_enabled":true,"jellyfin_tv_dir":"/tmp/jellyfin-tv","jellyfin_movie_dir":"/tmp/jellyfin-movies"}'
|
||||
handler = DummyHandler("/api/config/jellyfin/sync", body=body, content_length=len(body))
|
||||
payload = {"message": "Moved 1 watchlist entry to Jellyfin libraries.", "moved": 1, "total": 2, "items": []}
|
||||
handler.handler_context = mock.Mock(run_jellyfin_sync=mock.Mock(return_value=payload))
|
||||
handler.handler_context = mock.Mock(
|
||||
get_config_snapshot=mock.Mock(return_value={}),
|
||||
run_jellyfin_sync=mock.Mock(return_value=payload),
|
||||
http_error=APP.HttpError,
|
||||
)
|
||||
APP.Handler.do_POST(handler)
|
||||
self.assertEqual(handler.json_payload, payload)
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
|
||||
def test_jellyfin_sync_post_merges_partial_payload_with_saved_config(self):
|
||||
body = b'{"jellyfin_sync_enabled":true}'
|
||||
handler = DummyHandler("/api/config/jellyfin/sync", body=body, content_length=len(body))
|
||||
payload = {"message": "Moved 0 watchlist entries to Jellyfin libraries.", "moved": 0, "total": 0, "items": []}
|
||||
handler.handler_context = mock.Mock(
|
||||
get_config_snapshot=mock.Mock(
|
||||
return_value={
|
||||
"download_dir": "/tmp/example",
|
||||
"mode": "sub",
|
||||
"quality": "best",
|
||||
"jellyfin_sync_enabled": False,
|
||||
"jellyfin_tv_dir": "/tmp/jellyfin-tv",
|
||||
"jellyfin_movie_dir": "/tmp/jellyfin-movies",
|
||||
}
|
||||
),
|
||||
run_jellyfin_sync=mock.Mock(return_value=payload),
|
||||
)
|
||||
APP.Handler.do_POST(handler)
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
handler.handler_context.run_jellyfin_sync.assert_called_once_with(
|
||||
{
|
||||
"download_dir": "/tmp/example",
|
||||
"mode": "sub",
|
||||
"quality": "best",
|
||||
"jellyfin_sync_enabled": True,
|
||||
"jellyfin_tv_dir": "/tmp/jellyfin-tv",
|
||||
"jellyfin_movie_dir": "/tmp/jellyfin-movies",
|
||||
}
|
||||
)
|
||||
|
||||
def test_generic_handler_exception_skips_traceback_when_debug_disabled(self):
|
||||
handler = DummyHandler("/api/config")
|
||||
with mock.patch.object(http_handler, "debug_enabled", return_value=False), mock.patch.object(
|
||||
@@ -3105,6 +3139,7 @@ class TemplateHelperTests(unittest.TestCase):
|
||||
self.assertIn('id="pathBrowserOverlay"', APP.CONFIG_HTML)
|
||||
self.assertIn('/api/fs/browse?path=${encodeURIComponent(path || state.pathBrowser.path || "")}', APP.CONFIG_HTML)
|
||||
self.assertIn('rootGroup.className = "browser-roots";', APP.CONFIG_HTML)
|
||||
self.assertIn('const active = data.path === rootPath || String(data.path || "").startsWith(`${rootPath}/`);', APP.CONFIG_HTML)
|
||||
|
||||
def test_search_page_sends_watchlist_auto_download_series(self):
|
||||
self.assertIn('auto_download_series: $("seasonInput").value || "1"', APP.INDEX_HTML)
|
||||
|
||||
Reference in New Issue
Block a user