feat: romaji index for Japanese kanji song search
Backend: - Add /api/romaji-index endpoint using kuromoji morphological analyzer - Fetches all Navidrome songs, converts kanji → hiragana readings → romaji - Only indexes songs with Japanese characters; caches for 20 min - /api/romaji-index DELETE clears cache (force rebuild) Frontend: - fetchRomajiIndex() in api.js: lazy-fetches and caches the index - doLocalSearch: when query is romaji (ASCII), queries romaji index in parallel with Navidrome search3 and merges+deduplicates results Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
369a5e82b3
commit
aa239f8e6a
4 files changed
+176
-6
No files matched your search
+12
-2
@@ -6,6 +6,7 @@ import { playQueue, dlSongLocal, playPreview } from './player.js';
|
||||
import { showCtxMenu, openEditPlModal, openDlModal, closeSidebar, switchNavMode } from './ui.js';
|
||||
import { closeNowPlaying, closeNpMenu } from './nowplaying.js';
|
||||
import { makeCard, makeAlbumCard, makeSongItem, makeGlobalTrackItem, mkSection } from './components.js';
|
||||
import { fetchRomajiIndex } from './api.js';
|
||||
import { loadSpotifyImporter } from './spotify.js';
|
||||
|
||||
// ─── NAVIGATION HISTORY ───
|
||||
@@ -723,16 +724,25 @@ export async function doLocalSearch(q) {
|
||||
el.innerHTML = '<div class="spinner"></div>';
|
||||
try {
|
||||
const hiragana = await _romajiToHiragana(q);
|
||||
const [r, r2] = await Promise.all([
|
||||
const isRomaji = /^[a-z\s'-]+$/i.test(q.trim());
|
||||
const [r, r2, romajiIdx] = await Promise.all([
|
||||
api('search3', `&query=${encodeURIComponent(q)}&songCount=30&albumCount=10&artistCount=6`),
|
||||
hiragana ? api('search3', `&query=${encodeURIComponent(hiragana)}&songCount=20&albumCount=6&artistCount=4`) : Promise.resolve(null),
|
||||
isRomaji ? fetchRomajiIndex() : Promise.resolve(null),
|
||||
]);
|
||||
const res = r.searchResult3 || {};
|
||||
const res2 = r2?.searchResult3 || {};
|
||||
el.innerHTML = '';
|
||||
const artists = _mergeUniq(res.artist||[], res2.artist);
|
||||
const albums = _mergeUniq(res.album ||[], res2.album);
|
||||
const songs = _mergeUniq(res.song ||[], res2.song);
|
||||
|
||||
// Merge Navidrome results with romaji index matches
|
||||
const qLow = q.trim().toLowerCase();
|
||||
const romajiHits = romajiIdx
|
||||
? romajiIdx.filter(e => e.r.includes(qLow))
|
||||
: [];
|
||||
const songs = _mergeUniq(_mergeUniq(res.song||[], res2.song), romajiHits);
|
||||
|
||||
if(!artists.length && !albums.length && !songs.length) {
|
||||
el.innerHTML = '<div class="empty-state"><div class="icon">🔍</div><p>Keine Ergebnisse</p></div>'; return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user