From 00eaf37dfa5be8d1eceeffec2e0ac6bb13ebfe32 Mon Sep 17 00:00:00 2001 From: meowarex Date: Fri, 27 Feb 2026 19:19:54 +1100 Subject: [PATCH] Added Romanized Lyrics --- plugins/radiant-lyrics-luna/src/Settings.tsx | 25 ++++++++++++++++++++ plugins/radiant-lyrics-luna/src/index.ts | 23 ++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/plugins/radiant-lyrics-luna/src/Settings.tsx b/plugins/radiant-lyrics-luna/src/Settings.tsx index 3a905ce..2253459 100644 --- a/plugins/radiant-lyrics-luna/src/Settings.tsx +++ b/plugins/radiant-lyrics-luna/src/Settings.tsx @@ -14,6 +14,8 @@ declare global { updateQualityProgressColor?: () => void; updateLyricsStyle?: () => void; updateLyricsStyleSetting?: (value: number) => void; + updateRomanizeLyrics?: () => void; + updateRomanizeLyricsSetting?: (checked: boolean) => void; } } @@ -49,6 +51,7 @@ export const settings = await ReactiveStore.getPluginStorage("RadiantLyrics", { bubbledLyrics: true, syllableLogging: false, lyricsFontSize: 100, + romanizeLyrics: false, }); export const Settings = () => { @@ -146,6 +149,16 @@ export const Settings = () => { const [qualityProgressColor, setQualityProgressColor] = React.useState( settings.qualityProgressColor, ); + const [romanizeLyrics, setRomanizeLyrics] = React.useState( + settings.romanizeLyrics, + ); + React.useEffect(() => { + window.updateRomanizeLyricsSetting = (checked: boolean) => + setRomanizeLyrics(checked); + return () => { + window.updateRomanizeLyricsSetting = undefined; + }; + }, []); // Derive props and override onChange to accept a broader first param type type BaseSwitchProps = React.ComponentProps; @@ -267,6 +280,18 @@ export const Settings = () => { } }} /> + { + settings.romanizeLyrics = checked; + setRomanizeLyrics(checked); + if (window.updateRomanizeLyrics) { + window.updateRomanizeLyrics(); + } + }} + /> => { - const cacheKey = `${title}\0${artist}\0${isrc ?? ""}`; + const cacheKey = `${title}\0${artist}\0${isrc ?? ""}\0${settings.romanizeLyrics ? "r" : ""}`; if (cachedLyricsKey === cacheKey) { sylLog(`[RL-Syllable] Cache hit for "${title}" by "${artist}"`); return cachedLyricsData; @@ -1460,6 +1462,7 @@ const fetchWordLyrics = async ( let params = `lyrics?title=${encodeURIComponent(title)}&artist=${encodeURIComponent(artist)}`; if (isrc) params += `&isrc=${encodeURIComponent(isrc)}`; + if (settings.romanizeLyrics) params += "&romanize=true"; const primaryUrls = [ `https://rl-api.atomix.one/${params}`, @@ -1811,6 +1814,9 @@ const buildWordSpans = (): { return span; }; + const useRomanized = settings.romanizeLyrics; + const sylDisplay = (s: WordTiming) => (useRomanized && s.romanized != null ? s.romanized : s.text); + // Group syllables into words: trailing whitespace in syl.text marks a word boundary const wordGroups: number[][] = []; let currentGroup: number[] = []; @@ -1829,7 +1835,7 @@ const buildWordSpans = (): { const bgSyls = splitBg ? syllabus.filter(s => s.isBackground) : []; if (mainSyls.length > 0) { - const text = mainSyls.map(s => s.text).join("").trim(); + const text = mainSyls.map(s => sylDisplay(s)).join("").trim(); const first = mainSyls[0]; const last = mainSyls[mainSyls.length - 1]; const span = makeSpan(text, first.time, false); @@ -1837,7 +1843,7 @@ const buildWordSpans = (): { lineWords.push({ el: span, start: first.time, end: last.time + last.duration, duration: (last.time + last.duration) - first.time }); } if (bgSyls.length > 0 && bgContainer) { - const text = bgSyls.map(s => s.text).join("").trim().replace(/[()]/g, ""); + const text = bgSyls.map(s => sylDisplay(s)).join("").trim().replace(/[()]/g, ""); const first = bgSyls[0]; const last = bgSyls[bgSyls.length - 1]; const span = makeSpan(text, first.time, true); @@ -1855,7 +1861,7 @@ const buildWordSpans = (): { const groupSpans: HTMLSpanElement[] = []; for (const si of group) { const syl = syllabus[si]; - const span = makeSpan(syl.text.trimEnd(), wordStartMs, syl.isBackground); + const span = makeSpan(sylDisplay(syl).trimEnd(), wordStartMs, syl.isBackground); span.addEventListener("mouseenter", () => { for (const s of groupSpans) s.classList.add("rl-wbw-word-hover"); }); @@ -1868,7 +1874,7 @@ const buildWordSpans = (): { targetWords.push(entry); } } else { - const mergedText = group.map(si => syllabus[si].text.trimEnd()).join(""); + const mergedText = group.map(si => sylDisplay(syllabus[si]).trimEnd()).join(""); const first = syllabus[group[0]]; const last = syllabus[group[group.length - 1]]; const start = first.time; @@ -2553,6 +2559,13 @@ const updateLyricsStyleFromSettings = (): void => { }; (window as any).updateLyricsStyle = updateLyricsStyleFromSettings; +const updateRomanizeLyricsFromSettings = (): void => { + cachedLyricsKey = null; + cachedLyricsData = null; + toggle(); +}; +(window as any).updateRomanizeLyrics = updateRomanizeLyricsFromSettings; + // Update lyrics on track change (wipe cache for new song) onGlobalTrackChange(() => { cachedLyricsKey = null;