From 5bcb8b09a809e9700bbecbc94dde6b0f922fb77c Mon Sep 17 00:00:00 2001 From: Honey Date: Sun, 17 May 2026 21:26:46 +0200 Subject: [PATCH] fix: romaji index routes moved after app init + kuromoji in root package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app.get/delete for /api/romaji-index were placed before const app = express() causing ReferenceError on startup — moved into the ROUTES section - kuromoji moved from backend/package.json to root package.json so Docker picks it up during the existing npm install step - Fixed dicPath resolution to use path.dirname(require.resolve(...)) Co-Authored-By: Claude Sonnet 4.6 --- backend/novasonic-server.js | 83 +++++++++++++++++++------------------ package.json | 3 ++ 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index b8cfcaf..31049d1 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -26,7 +26,8 @@ const { downloadTrack, downloadAlbumTracks } = require('./lib/downloader'); let _tokenizer = null; try { const kuromoji = require('kuromoji'); - kuromoji.builder({ dicPath: path.join(require.resolve('kuromoji'), '../../dict') }) + const dicPath = path.join(path.dirname(require.resolve('kuromoji')), '..', 'dict'); + kuromoji.builder({ dicPath }) .build((err, t) => { if (err) console.warn('⚠️ kuromoji failed to load:', err.message); else { _tokenizer = t; console.log('✅ kuromoji tokenizer ready'); } @@ -113,46 +114,6 @@ async function _fetchNdSongs(ndUrl, user, pass) { return songs; } -// GET /api/romaji-index?ndUrl=...&user=...&pass=... -app.get('/api/romaji-index', async (req, res) => { - const { ndUrl, user, pass } = req.query; - if (!ndUrl || !user || !pass) return res.status(400).json({ error: 'missing params' }); - if (!_tokenizer) return res.status(503).json({ error: 'tokenizer not ready — try again in a few seconds' }); - - const key = `${ndUrl}|${user}`; - const cached = _romajiCache.get(key); - if (cached && Date.now() - cached.ts < ROMAJI_TTL) return res.json(cached.index); - - try { - const songs = await _fetchNdSongs(ndUrl, user, pass); - const index = songs - .filter(s => JP_RE.test(s.title) || JP_RE.test(s.artist) || JP_RE.test(s.album)) - .map(s => ({ - id: s.id, - r: [_toRomaji(s.title), _toRomaji(s.artist), _toRomaji(s.album)].join(' '), - title: s.title, - artist: s.artist || '', - album: s.album || '', - coverArt: s.coverArt || '', - duration: s.duration || 0, - albumId: s.albumId || '', - artistId: s.artistId || '', - })); - _romajiCache.set(key, { ts: Date.now(), index }); - console.log(`✅ Romaji index built: ${index.length} JP songs (${songs.length} total)`); - res.json(index); - } catch (e) { - console.error('Romaji index error:', e); - res.status(500).json({ error: e.message }); - } -}); - -// DELETE /api/romaji-index — force rebuild on next request -app.delete('/api/romaji-index', (req, res) => { - _romajiCache.clear(); - res.json({ ok: true }); -}); - // ─── INIT ───────────────────────────────────────────────────────────────────── const app = express(); app.use((req, res, next) => { @@ -204,6 +165,46 @@ function parseSpotifyUrl(url) { // ─── ROUTES ────────────────────────────────────────────────────────────────── +// GET /api/romaji-index?ndUrl=...&user=...&pass=... +app.get('/api/romaji-index', async (req, res) => { + const { ndUrl, user, pass } = req.query; + if (!ndUrl || !user || !pass) return res.status(400).json({ error: 'missing params' }); + if (!_tokenizer) return res.status(503).json({ error: 'tokenizer not ready — try again in a few seconds' }); + + const key = `${ndUrl}|${user}`; + const cached = _romajiCache.get(key); + if (cached && Date.now() - cached.ts < ROMAJI_TTL) return res.json(cached.index); + + try { + const songs = await _fetchNdSongs(ndUrl, user, pass); + const index = songs + .filter(s => JP_RE.test(s.title) || JP_RE.test(s.artist) || JP_RE.test(s.album)) + .map(s => ({ + id: s.id, + r: [_toRomaji(s.title), _toRomaji(s.artist), _toRomaji(s.album)].join(' '), + title: s.title, + artist: s.artist || '', + album: s.album || '', + coverArt: s.coverArt || '', + duration: s.duration || 0, + albumId: s.albumId || '', + artistId: s.artistId || '', + })); + _romajiCache.set(key, { ts: Date.now(), index }); + console.log(`✅ Romaji index built: ${index.length} JP songs (${songs.length} total)`); + res.json(index); + } catch (e) { + console.error('Romaji index error:', e); + res.status(500).json({ error: e.message }); + } +}); + +// DELETE /api/romaji-index — force rebuild on next request +app.delete('/api/romaji-index', (req, res) => { + _romajiCache.clear(); + res.json({ ok: true }); +}); + app.post('/api/spotify/track-artwork', async (req, res) => { const tracks = req.body.tracks || []; if (!tracks.length) return res.json({ results: [] }); diff --git a/package.json b/package.json index 1525efe..b581ae0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,9 @@ "preview": "vite preview", "icons": "node scripts/gen-icons.mjs" }, + "dependencies": { + "kuromoji": "^0.1.2" + }, "devDependencies": { "sharp": "^0.34.5", "vite": "^5.4.0"