From a50e5a59d96822c5db7c8e5ab511216524f043f7 Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Mon, 17 Nov 2025 22:20:30 -0800 Subject: [PATCH] include listenbrainz on settings page --- config/config.example.json | 3 +++ web_server.py | 30 ++++++++++++++++++++++++++++++ webui/index.html | 15 ++++++++++++++- webui/static/script.js | 6 ++++++ webui/static/style.css | 7 ++++++- 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/config/config.example.json b/config/config.example.json index eed0e198..fb4952c5 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -46,5 +46,8 @@ }, "playlist_sync": { "create_backup": true + }, + "listenbrainz": { + "token": "LISTENBRAINZ_TOKEN" } } \ No newline at end of file diff --git a/web_server.py b/web_server.py index 39dc3615..caccb852 100644 --- a/web_server.py +++ b/web_server.py @@ -1361,6 +1361,34 @@ def run_service_test(service, test_config): return True, "Successfully connected to slskd." else: return False, "Could not connect to slskd. Check URL and API Key." + elif service == "listenbrainz": + token = test_config.get('token', '') + + if not token: + return False, "Missing ListenBrainz user token." + + try: + # Test ListenBrainz API by validating the token + url = "https://api.listenbrainz.org/1/validate-token" + headers = { + 'Authorization': f'Token {token}' + } + response = requests.get(url, headers=headers, timeout=5) + + if response.status_code == 200: + data = response.json() + if data.get('valid'): + username = data.get('user_name', 'Unknown') + return True, f"Successfully connected to ListenBrainz! Connected as: {username}" + else: + return False, "Invalid ListenBrainz token." + elif response.status_code == 401: + return False, "Invalid ListenBrainz token (unauthorized)." + else: + return False, f"Could not connect to ListenBrainz (HTTP {response.status_code})" + + except Exception as e: + return False, f"ListenBrainz connection error: {str(e)}" return False, "Unknown service." except AttributeError as e: # This specifically catches the error you reported for Jellyfin @@ -2048,6 +2076,8 @@ def test_connection_endpoint(): elif service == 'soulseek': # Soulseek doesn't use cache, but update anyway for consistency print("✅ Soulseek test successful") + elif service == 'listenbrainz': + print("✅ ListenBrainz test successful") # Add activity for connection test if success: diff --git a/webui/index.html b/webui/index.html index 03cc9298..13dcdc47 100644 --- a/webui/index.html +++ b/webui/index.html @@ -2248,12 +2248,25 @@ - + + +
+

ListenBrainz

+
+ + +
+
+
Get your token from ListenBrainz Settings
+
+
+
+
diff --git a/webui/static/script.js b/webui/static/script.js index c8b40bb0..59212a59 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -1467,6 +1467,9 @@ async function loadSettingsData() { document.getElementById('soulseek-url').value = settings.soulseek?.slskd_url || ''; document.getElementById('soulseek-api-key').value = settings.soulseek?.api_key || ''; + // Populate ListenBrainz settings + document.getElementById('listenbrainz-token').value = settings.listenbrainz?.token || ''; + // Populate Download settings (right column) document.getElementById('download-path').value = settings.soulseek?.download_path || './downloads'; document.getElementById('transfer-path').value = settings.soulseek?.transfer_path || './Transfer'; @@ -1775,6 +1778,9 @@ async function saveSettings() { download_path: document.getElementById('download-path').value, transfer_path: document.getElementById('transfer-path').value }, + listenbrainz: { + token: document.getElementById('listenbrainz-token').value + }, database: { max_workers: parseInt(document.getElementById('max-workers').value) }, diff --git a/webui/static/style.css b/webui/static/style.css index 6fbfc17d..d5dde329 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -1094,6 +1094,10 @@ body { color: #5dade2; } +.listenbrainz-title { + color: #eb743b; +} + /* Server Toggle Buttons */ .server-toggle-container { display: flex; @@ -1593,7 +1597,8 @@ body { .api-test-buttons .test-button { flex: 1; - min-width: 80px; + min-width: 120px; + max-width: calc(33.333% - 6px); } /* Server Test Section */