From 52ba73506f0c177a1e575f0f3aac59c96ced3c82 Mon Sep 17 00:00:00 2001 From: Honey Date: Sat, 23 May 2026 21:31:04 +0200 Subject: [PATCH] fix: SC album defaults to title, filter [Unknown Album] placeholder, fallback file search - SC resolve: strip yt-dlp placeholder albums (starting with '['), use track title as album for singles - edit-metadata: if Navidrome path stale, search music root recursively for file by name - Both single and playlist SC track handling updated Co-Authored-By: Claude Sonnet 4.6 --- backend/novasonic-server.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index d135e2e..935548d 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -46,6 +46,22 @@ if (!fs.existsSync(CONFIG.musicPath)) { fs.mkdirSync(CONFIG.musicPath, { recursive: true }); } +// Search for a file by exact name anywhere under a directory (max depth 5) +function _findFileRecursive(dir, name, depth = 0) { + if (depth > 5) return null; + try { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + if (entry.isDirectory()) { + const found = _findFileRecursive(path.join(dir, entry.name), name, depth + 1); + if (found) return found; + } else if (entry.name === name) { + return path.join(dir, entry.name); + } + } + } catch {} + return null; +} + // ─── QUEUE ──────────────────────────────────────────────────────────────────── let activeDownloads = 0; const downloadQueue = []; @@ -420,6 +436,7 @@ app.post('/api/soundcloud/resolve', async (req, res) => { artworkUrl: e.thumbnail || '', duration: e.duration || 0, genre: e.genre || '', + album: (e.album && !e.album.startsWith('[')) ? e.album : (e.title || ''), sourceUrl: e.url || e.webpage_url || '', })); res.json({ @@ -430,13 +447,16 @@ app.post('/api/soundcloud/resolve', async (req, res) => { tracks, }); } else { + // Filter yt-dlp placeholder values — treat them as empty + const scAlbum = (data.album && !data.album.startsWith('[')) ? data.album : ''; const track = { trackName: data.title || '', artistName: data.uploader || data.artist || '', artworkUrl: data.thumbnail || '', duration: data.duration || 0, genre: data.genre || '', - album: data.album || '', + // Use track title as album for singles with no real album + album: scAlbum || data.title || '', year: data.upload_date ? parseInt(data.upload_date.slice(0, 4), 10) : undefined, sourceUrl: url, }; @@ -516,7 +536,14 @@ app.post('/api/edit-metadata', async (req, res) => { // If not absolute, try relative to music root if (!path.isAbsolute(filePath)) filePath = path.join(CONFIG.musicPath, filePath); - if (!fs.existsSync(filePath)) return res.status(404).json({ error: `File not found: ${filePath}` }); + + // Fallback: if Navidrome path stale/wrong, search for the file by name under music root + if (!fs.existsSync(filePath)) { + const fileName = path.basename(filePath); + const found = _findFileRecursive(CONFIG.musicPath, fileName); + if (found) { filePath = found; } + else return res.status(404).json({ error: `File not found: ${filePath}` }); + } // Resolve artwork: base64 > URL let artFile = null;