From a47b2be177caa6bbafa919a31a79c758dff6d646 Mon Sep 17 00:00:00 2001 From: Honey Date: Sun, 17 May 2026 21:03:42 +0200 Subject: [PATCH] feat: romaji search for Japanese songs via wanakana MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When search input is pure ASCII (romaji), converts it to hiragana in parallel using wanakana and merges both result sets. Deduplicates by ID so no double entries. Helps find artists/songs tagged with hiragana in sort fields (e.g. 'inabakumori' → 'いなばくもり'). Co-Authored-By: Claude Sonnet 4.6 --- src/views.js | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/views.js b/src/views.js index 03056c8..295edaf 100644 --- a/src/views.js +++ b/src/views.js @@ -692,6 +692,24 @@ export async function loadRandom() { } catch(e) { el.innerHTML = `

${e.message}

`; } } +// ─── ROMAJI → HIRAGANA (lazy-loaded) ─── +let _wanakana = null; +async function _romajiToHiragana(q) { + // Only attempt conversion if query is pure ASCII (likely romaji) + if (!/^[a-z\s'-]+$/i.test(q.trim())) return null; + try { + if (!_wanakana) _wanakana = await import('https://cdn.jsdelivr.net/npm/wanakana@5/esm/wanakana.js'); + const h = _wanakana.toHiragana(q.trim(), { passRomaji: false }); + // If conversion produced actual hiragana (not just the same ASCII), use it + return /[぀-ゟ]/.test(h) ? h : null; + } catch { return null; } +} + +function _mergeUniq(a, b) { + const seen = new Set(a.map(x => x.id)); + return [...a, ...(b || []).filter(x => !seen.has(x.id))]; +} + // ─── LOCAL SEARCH ─── export function onLocalSearch(val) { clearTimeout(S.searchTimer); @@ -704,10 +722,17 @@ export async function doLocalSearch(q) { const el = document.getElementById('search-results'); el.innerHTML = '
'; try { - const r = await api('search3', `&query=${encodeURIComponent(q)}&songCount=30&albumCount=10&artistCount=6`); - const res = r.searchResult3 || {}; + const hiragana = await _romajiToHiragana(q); + const [r, r2] = 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), + ]); + const res = r.searchResult3 || {}; + const res2 = r2?.searchResult3 || {}; el.innerHTML = ''; - const artists = res.artist||[], albums = res.album||[], songs = res.song||[]; + const artists = _mergeUniq(res.artist||[], res2.artist); + const albums = _mergeUniq(res.album ||[], res2.album); + const songs = _mergeUniq(res.song ||[], res2.song); if(!artists.length && !albums.length && !songs.length) { el.innerHTML = '
🔍

Keine Ergebnisse

'; return; }