From 0f1e6ff5310898b13db75d38edc779a0d350218f Mon Sep 17 00:00:00 2001 From: Honey Date: Tue, 12 May 2026 18:18:50 +0200 Subject: [PATCH] refactor: remove dead code from backend and lib - Remove unused spotifyClientId/spotifyClientSecret from config - Remove AUDIO_EXTS from metadata exports (internal-only) - Remove tryYtdlp wrapper in ytdlp.js (direct spawnYtdlp calls) - Remove _spArtistName wrapper in server (direct _spAllArtists calls) - Fix stale comment: primary resolver is SpotipyFree, not curl_cffi Co-Authored-By: Claude Sonnet 4.6 --- backend/lib/config.js | 3 --- backend/lib/metadata.js | 2 +- backend/lib/ytdlp.js | 21 ++++++++++----------- backend/novasonic-server.js | 10 +++------- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/backend/lib/config.js b/backend/lib/config.js index 30ce49c..c6c951c 100644 --- a/backend/lib/config.js +++ b/backend/lib/config.js @@ -9,9 +9,6 @@ const CONFIG = { downloadBackend: (process.env.DOWNLOAD_BACKEND || 'auto').toLowerCase(), // squid.wtf quality: 'mp3' | 'flac' | 'hi-res' squidQuality: (process.env.SQUID_QUALITY || 'mp3').toLowerCase(), - // Spotify Developer credentials (Client Credentials Flow — free, no Premium needed) - spotifyClientId: process.env.SPOTIFY_CLIENT_ID || '', - spotifyClientSecret: process.env.SPOTIFY_CLIENT_SECRET || '', }; module.exports = CONFIG; diff --git a/backend/lib/metadata.js b/backend/lib/metadata.js index cb69877..33a5de6 100644 --- a/backend/lib/metadata.js +++ b/backend/lib/metadata.js @@ -138,6 +138,6 @@ async function searchItunesAlbumTracks(artist, album) { module.exports = { sanitize, navidromeArtist, - downloadArtwork, AUDIO_EXTS, findExistingTrack, + downloadArtwork, findExistingTrack, fetchLyrics, lookupItunesTrackMeta, fetchItunesTracks, searchItunesAlbumTracks, }; diff --git a/backend/lib/ytdlp.js b/backend/lib/ytdlp.js index 2c5326e..5d01c32 100644 --- a/backend/lib/ytdlp.js +++ b/backend/lib/ytdlp.js @@ -108,7 +108,6 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t const ytmUrl = `https://music.youtube.com/search?q=${encodeURIComponent(ytmQuery)}¶ms=${YTM_SONGS_PARAM}`; const expectedAudio = path.join(dir, `${trackPrefix}${safeTitle}.${CONFIG.audioFmt}`); const hasAudio = () => fs.existsSync(expectedAudio); - const tryYtdlp = async (args) => { await spawnYtdlp(args); }; // Fetch YTM search result URLs as a flat list (no channel expansion) and return only // actual video URLs (watch?v=…). This prevents yt-dlp from following an artist channel @@ -152,7 +151,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t const tryYtmSearch = async (maxItems, mfArgs) => { const urls = await getYtmVideoUrls(maxItems); if (!urls.length) return; - await tryYtdlp([...urls, '--max-downloads', '1', ...mfArgs, ...baseArgs]); + await spawnYtdlp([...urls, '--max-downloads', '1', ...mfArgs, ...baseArgs]); }; const variantFilter = buildVariantFilter(title); @@ -189,7 +188,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t if (!hasAudio()) { // 2. YT top-5 — strict: same filters including channel check log(jobId, '⚠️ Kein YTM-Treffer — Fallback zu YouTube…'); - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(dur, true, true), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(dur, true, true), ...baseArgs]); } if (!hasAudio()) { // 3. YTM top-10 — no channel check (label channels, etc.) @@ -198,7 +197,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 4. YT top-10 — no channel check - await tryYtdlp([`ytsearch10:${query}`, ...PI_FILTERED_10, ...mf(dur, true), ...baseArgs]); + await spawnYtdlp([`ytsearch10:${query}`, ...PI_FILTERED_10, ...mf(dur, true), ...baseArgs]); } if (!hasAudio()) { // 5. YTM top-5 — no duration check @@ -207,7 +206,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 6. YT top-5 — no duration check - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true), ...baseArgs]); } if (!hasAudio()) { // 7. YTM top-5 — title only (no variant filter) @@ -216,7 +215,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 8. YT top-5 — title only - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, false), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, false), ...baseArgs]); } if (!hasAudio()) { // 9. YTM — no filter at all, take first video result @@ -225,7 +224,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 10. YT — no filter - await tryYtdlp([`ytsearch1:${query}`, ...PI_UNFILTERED, ...baseArgs]); + await spawnYtdlp([`ytsearch1:${query}`, ...PI_UNFILTERED, ...baseArgs]); } } else { log(jobId, `🔍 Suche YT Music: "${query}"`); @@ -233,7 +232,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t await tryYtmSearch(5, mf(null, true, true)); if (!hasAudio()) { // 2. YT top-5 — strict - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true, true), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true, true), ...baseArgs]); } if (!hasAudio()) { // 3. YTM top-5 — no channel check @@ -241,7 +240,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 4. YT top-5 — no channel check - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, true), ...baseArgs]); } if (!hasAudio()) { // 5. YTM top-5 — title only @@ -250,7 +249,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 6. YT top-5 — title only - await tryYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, false), ...baseArgs]); + await spawnYtdlp([`ytsearch5:${query}`, ...PI_FILTERED, ...mf(null, false), ...baseArgs]); } if (!hasAudio()) { // 7. YTM — first video result, no filter @@ -259,7 +258,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t } if (!hasAudio()) { // 8. YT — no filter - await tryYtdlp([`ytsearch1:${query}`, ...PI_UNFILTERED, ...baseArgs]); + await spawnYtdlp([`ytsearch1:${query}`, ...PI_UNFILTERED, ...baseArgs]); } } diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index f7c82a4..537229d 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -296,10 +296,6 @@ function _spAllArtists(artistsRaw) { return arr.map(a => a?.profile?.name || a?.name || '').filter(Boolean).join(', '); } -function _spArtistName(artistsRaw) { - return _spAllArtists(artistsRaw); -} - function _spTrackItem(t, defaultAlbum, defaultArt, defaultAlbumArtist) { const trackName = t?.name || ''; const artist = _spAllArtists(t?.artists) || defaultAlbumArtist || ''; @@ -377,7 +373,7 @@ async function _resolveSpotifyViaSpotdl(url) { } async function _resolveSpotify(type, id, originalUrl) { - // Primary: curl_cffi Chrome-impersonation + TOTP (no rate limit bucket as api keys) + // Primary: SpotipyFree (SpotAPI + tls_client Chrome fingerprint, Spotify internal endpoints) try { console.log('[spotify] trying spotdl resolver'); return await _resolveSpotifyViaSpotdl(originalUrl); @@ -391,7 +387,7 @@ async function _resolveSpotify(type, id, originalUrl) { if (type === 'track') { const t = await _spApi(`/tracks/${id}`, token); - const artist = _spArtistName(t.artists); + const artist = _spAllArtists(t.artists); const artUrl = _spArtwork(t); return { type: 'track', name: t.name || '', artist, artworkUrl: artUrl, tracks: [_spTrackItem(t, t.album?.name, artUrl, artist)] }; @@ -399,7 +395,7 @@ async function _resolveSpotify(type, id, originalUrl) { if (type === 'album') { const album = await _spApi(`/albums/${id}`, token); - const artist = _spArtistName(album.artists); + const artist = _spAllArtists(album.artists); const artUrl = _spArtwork(album); const trackItems = await _spAllAlbumTracks(id, token); return { type: 'album', name: album.name || '', artist, artworkUrl: artUrl,