fix(lyrics): render Japanese kanji with correct JP glyphs (#571)

This commit is contained in:
Dorian Gironde 2026-04-19 14:52:08 +02:00 committed by edideaur
parent 20cf96bbd9
commit 37b7cf84d9
2 changed files with 35 additions and 17 deletions

View file

@ -51,6 +51,19 @@ function trackHasAsianText(track) {
return containsAsianText(title) || containsAsianText(artist); return containsAsianText(title) || containsAsianText(artist);
} }
// Hiragana (3040-309F) or Katakana (30A0-30FF) = unambiguously Japanese
function containsJapaneseKana(text) {
if (!text) return false;
return /[\u3040-\u309F\u30A0-\u30FF]/.test(text);
}
function trackIsJapanese(track) {
if (!track) return false;
const title = track.title || '';
const artist = getTrackArtists(track) || '';
return containsJapaneseKana(title) || containsJapaneseKana(artist);
}
function cleanTrackerSearch(text) { function cleanTrackerSearch(text) {
if (!text) return ''; if (!text) return '';
// chud emojis will NOT be tolerated in my precious genius lyrics worker // chud emojis will NOT be tolerated in my precious genius lyrics worker
@ -598,6 +611,10 @@ export class LyricsManager {
clearTimeout(this.observerTimeout); clearTimeout(this.observerTimeout);
} }
this.observerTimeout = setTimeout(async () => { this.observerTimeout = setTimeout(async () => {
if (amLyricsElement.getAttribute('lang') !== 'ja') {
const text = (amLyricsElement.shadowRoot || amLyricsElement).textContent || '';
if (containsJapaneseKana(text)) amLyricsElement.setAttribute('lang', 'ja');
}
if (this.isRomajiMode) { if (this.isRomajiMode) {
await this.convertLyricsContent(amLyricsElement); await this.convertLyricsContent(amLyricsElement);
} }
@ -1104,6 +1121,7 @@ async function renderLyricsComponent(container, track, audioPlayer, lyricsManage
amLyrics.setAttribute('hover-background-color', 'color-mix(in srgb, var(--primary) 16%, transparent)'); amLyrics.setAttribute('hover-background-color', 'color-mix(in srgb, var(--primary) 16%, transparent)');
amLyrics.setAttribute('autoscroll', ''); amLyrics.setAttribute('autoscroll', '');
amLyrics.setAttribute('interpolate', ''); amLyrics.setAttribute('interpolate', '');
if (trackIsJapanese(track)) amLyrics.setAttribute('lang', 'ja');
amLyrics.style.height = '100%'; amLyrics.style.height = '100%';
amLyrics.style.width = '100%'; amLyrics.style.width = '100%';

View file

@ -2,12 +2,12 @@
color-scheme: light dark; color-scheme: light dark;
--font-family: --font-family:
'Inter', 'Noto Sans', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans HK', 'Noto Sans JP', 'Noto Sans KR', 'Inter', 'Noto Sans', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic', meiryo, 'Noto Sans JP',
'Noto Sans Hebrew', 'Noto Sans Arabic', 'Noto Sans Devanagari', 'Noto Sans Bengali', 'Noto Sans Thai', 'Noto Sans KR', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans HK', 'Noto Sans Hebrew', 'Noto Sans Arabic',
'Noto Sans Tamil', 'Noto Sans Telugu', 'Noto Sans Gujarati', 'Noto Sans Kannada', 'Noto Sans Malayalam', 'Noto Sans Devanagari', 'Noto Sans Bengali', 'Noto Sans Thai', 'Noto Sans Tamil', 'Noto Sans Telugu',
'Noto Sans Sinhala', 'Noto Sans Khmer', 'Noto Sans Lao', 'Noto Sans Myanmar', 'Noto Sans Georgian', 'Noto Sans Gujarati', 'Noto Sans Kannada', 'Noto Sans Malayalam', 'Noto Sans Sinhala', 'Noto Sans Khmer',
'Noto Sans Armenian', 'Noto Sans Ethiopic', system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Noto Sans Lao', 'Noto Sans Myanmar', 'Noto Sans Georgian', 'Noto Sans Armenian', 'Noto Sans Ethiopic',
sans-serif; system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, sans-serif;
--font-size-scale: 100%; --font-size-scale: 100%;
--text-xs: 0.75rem; --text-xs: 0.75rem;
--text-sm: 0.875rem; --text-sm: 0.875rem;
@ -5698,9 +5698,11 @@ input:checked + .slider::before {
container-name: sidepanel; container-name: sidepanel;
} }
/* Force Japanese font shaping so kanji like 刀 render as Japanese glyphs, not simplified Chinese */ am-lyrics[song-title] {
am-lyrics { font-family:
font-language-override: 'JA'; 'SF Pro Display', Inter, 'Noto Sans', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic', meiryo,
'Noto Sans JP', 'Noto Sans KR', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans HK', 'Noto Sans Hebrew',
'Noto Sans Arabic', system-ui, sans-serif;
} }
@container sidepanel (min-width: 500px) { @container sidepanel (min-width: 500px) {
@ -10981,14 +10983,12 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
height: 100%; height: 100%;
width: 100%; width: 100%;
font-family: font-family:
'SF Pro Display', Inter, 'Noto Sans', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans HK', 'Noto Sans JP', 'SF Pro Display', Inter, 'Noto Sans', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic', meiryo,
'Noto Sans KR', 'Noto Sans Hebrew', 'Noto Sans Arabic', 'Noto Sans Devanagari', 'Noto Sans Bengali', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans HK', 'Noto Sans Hebrew',
'Noto Sans Thai', 'Noto Sans Tamil', 'Noto Sans Telugu', 'Noto Sans Gujarati', 'Noto Sans Kannada', 'Noto Sans Arabic', 'Noto Sans Devanagari', 'Noto Sans Bengali', 'Noto Sans Thai', 'Noto Sans Tamil',
'Noto Sans Malayalam', 'Noto Sans Sinhala', 'Noto Sans Khmer', 'Noto Sans Lao', 'Noto Sans Myanmar', 'Noto Sans Telugu', 'Noto Sans Gujarati', 'Noto Sans Kannada', 'Noto Sans Malayalam', 'Noto Sans Sinhala',
'Noto Sans Georgian', 'Noto Sans Armenian', 'Noto Sans Ethiopic', system-ui, sans-serif; 'Noto Sans Khmer', 'Noto Sans Lao', 'Noto Sans Myanmar', 'Noto Sans Georgian', 'Noto Sans Armenian',
'Noto Sans Ethiopic', system-ui, sans-serif;
/* Force Japanese font shaping so kanji like 刀 render as Japanese, not simplified Chinese */
font-language-override: 'JA';
--lyplus-font-size-base: clamp(34px, 3vw, 52px); --lyplus-font-size-base: clamp(34px, 3vw, 52px);
--lyplus-padding-line: 8px; --lyplus-padding-line: 8px;