fix: resolve Japanese-path songs stored as romaji files

When Navidrome has a Japanese path in its DB but the file was saved with
a romaji filename by the download pipeline, the existing fallback chain
compared the Japanese title stem against romaji filenames and always
failed. Added _findFileByStemOrRomaji which converts the stem via
romajiForStorage before the final recursive search, covering all three
endpoints: edit-metadata, delete-song, song-sorttags.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-29 01:30:04 +02:00
1 parent 07b8114cae
commit 52451f5086
1 file changed
+16 -3
+16 -3
View File
@@ -116,6 +116,19 @@ function _findFileByStem(dir, titleStem, depth = 0) {
return null; return null;
} }
// Like _findFileByStem but also tries a romaji-converted stem.
// Handles the case where Navidrome has a Japanese path in its DB but the file
// on disk was stored with a romaji filename by the download pipeline.
function _findFileByStemOrRomaji(dir, stem) {
const direct = _findFileByStem(dir, stem);
if (direct) return direct;
try {
const rt = (romajiForStorage(stem) || '').toLowerCase().trim();
if (rt && rt !== stem) return _findFileByStem(dir, rt);
} catch {}
return null;
}
// ─── QUEUE ──────────────────────────────────────────────────────────────────── // ─── QUEUE ────────────────────────────────────────────────────────────────────
let activeDownloads = 0; let activeDownloads = 0;
const downloadQueue = []; const downloadQueue = [];
@@ -730,7 +743,7 @@ app.get('/api/song-sorttags', async (req, res) => {
const found = rebased const found = rebased
|| _findFileRecursive(CONFIG.musicPath, fileName) || _findFileRecursive(CONFIG.musicPath, fileName)
|| _findFileInDir(rebasedDir || path.dirname(filePath), fileName) || _findFileInDir(rebasedDir || path.dirname(filePath), fileName)
|| _findFileByStem(CONFIG.musicPath, titleStem); || _findFileByStemOrRomaji(CONFIG.musicPath, titleStem);
if (found) filePath = found; else return res.status(404).json({ error: 'File not found' }); if (found) filePath = found; else return res.status(404).json({ error: 'File not found' });
} }
try { try {
@@ -865,7 +878,7 @@ app.post('/api/edit-metadata', async (req, res) => {
const found = rebased const found = rebased
|| _findFileRecursive(CONFIG.musicPath, fileName) || _findFileRecursive(CONFIG.musicPath, fileName)
|| _findFileInDir(rebasedDir || originalDir, fileName) || _findFileInDir(rebasedDir || originalDir, fileName)
|| _findFileByStem(CONFIG.musicPath, titleStem); || _findFileByStemOrRomaji(CONFIG.musicPath, titleStem);
if (found) { filePath = found; } if (found) { filePath = found; }
else return res.status(404).json({ error: `File not found: ${filePath} (music root: ${CONFIG.musicPath})` }); else return res.status(404).json({ error: `File not found: ${filePath} (music root: ${CONFIG.musicPath})` });
} }
@@ -1053,7 +1066,7 @@ app.post('/api/delete-song', async (req, res) => {
const found = _rebasePath(filePath, CONFIG.musicPath) const found = _rebasePath(filePath, CONFIG.musicPath)
|| _findFileRecursive(CONFIG.musicPath, fileName) || _findFileRecursive(CONFIG.musicPath, fileName)
|| _findFileInDir(path.dirname(filePath), fileName) || _findFileInDir(path.dirname(filePath), fileName)
|| _findFileByStem(CONFIG.musicPath, titleStem); || _findFileByStemOrRomaji(CONFIG.musicPath, titleStem);
if (found) filePath = found; if (found) filePath = found;
else return res.status(404).json({ error: 'File not found on disk' }); else return res.status(404).json({ error: 'File not found on disk' });
} }