diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index 2dcc04f..7d8e517 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -388,20 +388,26 @@ function enqueue(task) { } // ─── SPOTIFY ────────────────────────────────────────────────────────────────── -let _spTok = null, _spTokExp = 0, _spCachedId = ''; +let _spTok = null, _spTokExp = 0; -async function getSpotifyToken(clientId, clientSecret) { - if (_spTok && clientId === _spCachedId && Date.now() < _spTokExp - 30000) return _spTok; - const creds = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); - const r = await fetch('https://accounts.spotify.com/api/token', { - method: 'POST', - headers: { Authorization: `Basic ${creds}`, 'Content-Type': 'application/x-www-form-urlencoded' }, - body: 'grant_type=client_credentials', - signal: AbortSignal.timeout(8000), - }); - if (!r.ok) throw new Error(`Spotify Auth fehlgeschlagen (${r.status}) — Client ID/Secret prüfen`); +// Uses Spotify's public web-player token — no account or Premium required +async function getSpotifyToken() { + if (_spTok && Date.now() < _spTokExp - 60000) return _spTok; + const r = await fetch( + 'https://open.spotify.com/get_access_token?reason=transport&productType=web_player', + { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', + Accept: 'application/json', + }, + signal: AbortSignal.timeout(8000), + } + ); + if (!r.ok) throw new Error(`Spotify public token fehlgeschlagen (${r.status})`); const d = await r.json(); - _spTok = d.access_token; _spTokExp = Date.now() + d.expires_in * 1000; _spCachedId = clientId; + if (!d.accessToken) throw new Error('Kein Spotify-Token erhalten — Spotify möglicherweise nicht erreichbar'); + _spTok = d.accessToken; + _spTokExp = d.accessTokenExpirationTimestampMs || (Date.now() + 3600000); return _spTok; } @@ -418,12 +424,11 @@ app.get('/api/health', (req, res) => { }); app.post('/api/spotify/resolve', async (req, res) => { - const { url, clientId, clientSecret } = req.body; - if (!url) return res.status(400).json({ error: 'url required' }); - if (!clientId || !clientSecret) return res.status(400).json({ error: 'Spotify credentials fehlen (clientId + clientSecret in Einstellungen eintragen)' }); + const { url } = req.body; + if (!url) return res.status(400).json({ error: 'url required' }); try { const { type, id } = parseSpotifyUrl(url); - const tok = await getSpotifyToken(clientId, clientSecret); + const tok = await getSpotifyToken(); const spH = { Authorization: `Bearer ${tok}` }; const spFetch = (u) => fetch(u, { headers: spH, signal: AbortSignal.timeout(10000) }); diff --git a/index.html b/index.html index 7df9fb5..fc571e2 100644 --- a/index.html +++ b/index.html @@ -46,15 +46,6 @@
Für Download-to-Server Funktion. Backend separat starten (novasonic-server.js)
-
- - -
Kostenlos unter developer.spotify.com/dashboard
-
-
- - -
@@ -352,7 +343,7 @@
1. Spotify Link für Track, Album oder Playlist einfügen
2. Metadaten werden direkt von Spotify geladen
3. Songs via yt-dlp herunterladen → direkt in Navidrome Library
-
Spotify Client ID + Secret in den Einstellungen → Discover APIs eintragen.
Kostenlos unter developer.spotify.com/dashboard
+
Kein Spotify-Account erforderlich — funktioniert direkt über das Backend.
-
- - -
Kostenlos unter developer.spotify.com/dashboard
-
-
- - -
Backend Status
diff --git a/src/ui.js b/src/ui.js index 9daa8c0..bbe1682 100644 --- a/src/ui.js +++ b/src/ui.js @@ -61,8 +61,6 @@ export function openSettings() { document.getElementById('s-pass').value = ''; document.getElementById('s-lastfm').value = S.cfg.lastfmKey || ''; document.getElementById('s-backend').value = S.cfg.backendUrl || ''; - document.getElementById('s-spotify-id').value = S.cfg.spotifyClientId || ''; - document.getElementById('s-spotify-secret').value = ''; document.getElementById('settings-modal').classList.add('open'); checkBackend(); } @@ -74,9 +72,6 @@ export function saveSettings() { if(pass) S.cfg.pass = pass; S.cfg.lastfmKey = document.getElementById('s-lastfm').value.trim(); S.cfg.backendUrl = document.getElementById('s-backend').value.trim().replace(/\/$/,''); - S.cfg.spotifyClientId = document.getElementById('s-spotify-id').value.trim(); - const spSec = document.getElementById('s-spotify-secret').value; - if (spSec) S.cfg.spotifyClientSecret = spSec; localStorage.setItem('ns_cfg', JSON.stringify(S.cfg)); closeSettings(); toast('✅ Gespeichert'); } diff --git a/src/views.js b/src/views.js index ea2a9b1..4b1f269 100644 --- a/src/views.js +++ b/src/views.js @@ -917,9 +917,7 @@ export function clearSpotifyPreview() { export async function resolveSpotifyLink() { const url = document.getElementById('spotify-link-input')?.value.trim(); if (!url) return; - if (!S.cfg.backendUrl) { toast('⚠ Backend URL in Einstellungen konfigurieren'); return; } - if (!S.cfg.spotifyClientId) { toast('⚠ Spotify Client ID in Einstellungen eintragen'); return; } - if (!S.cfg.spotifyClientSecret) { toast('⚠ Spotify Client Secret in Einstellungen eintragen'); return; } + if (!S.cfg.backendUrl) { toast('⚠ Backend URL in Einstellungen konfigurieren'); return; } const hint = document.getElementById('spotify-importer-hint'); const preview = document.getElementById('spotify-preview'); @@ -935,7 +933,7 @@ export async function resolveSpotifyLink() { const res = await fetch(`${S.cfg.backendUrl}/api/spotify/resolve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ url, clientId: S.cfg.spotifyClientId, clientSecret: S.cfg.spotifyClientSecret }), + body: JSON.stringify({ url }), }); if (!res.ok) { const err = await res.json().catch(() => ({}));