feat(synced-lyrics): Added Hindi & Bengali romanization support for lyrics (#3933)

Co-authored-by: pranjol <pranjol@pranjols-iMac-Pro.local>
This commit is contained in:
Pranjol
2026-02-11 04:30:36 +05:30
committed by GitHub
parent 3f1ceca39c
commit e2f1ff50dd
3 changed files with 55 additions and 0 deletions

View File

@ -77,6 +77,7 @@
"@hono/swagger-ui": "0.5.3", "@hono/swagger-ui": "0.5.3",
"@hono/zod-openapi": "1.2.1", "@hono/zod-openapi": "1.2.1",
"@hono/zod-validator": "0.7.6", "@hono/zod-validator": "0.7.6",
"@indic-transliteration/sanscript": "1.3.3",
"@jellybrick/dbus-next": "0.10.3", "@jellybrick/dbus-next": "0.10.3",
"@jellybrick/electron-better-web-request": "2.0.0", "@jellybrick/electron-better-web-request": "2.0.0",
"@jellybrick/mpris-service": "2.1.5", "@jellybrick/mpris-service": "2.1.5",

21
pnpm-lock.yaml generated
View File

@ -78,6 +78,9 @@ importers:
'@hono/zod-validator': '@hono/zod-validator':
specifier: 0.7.6 specifier: 0.7.6
version: 0.7.6(hono@4.11.7)(zod@4.3.6) version: 0.7.6(hono@4.11.7)(zod@4.3.6)
'@indic-transliteration/sanscript':
specifier: 1.3.3
version: 1.3.3
'@jellybrick/dbus-next': '@jellybrick/dbus-next':
specifier: 0.10.3 specifier: 0.10.3
version: 0.10.3 version: 0.10.3
@ -843,6 +846,12 @@ packages:
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
engines: {node: '>=18.18'} engines: {node: '>=18.18'}
'@indic-transliteration/common_maps@1.0.5':
resolution: {integrity: sha512-XbWDA5AXGE+Nh4uGr/yN9ZM8avRBy4F1KQL+DLgQGOdsQ390lcW4fga0NSjg4C/rOpMd0rHZv2YFV3Bq3UbpkQ==}
'@indic-transliteration/sanscript@1.3.3':
resolution: {integrity: sha512-zNGeARmQTPIlubwgEhl/JumpwTPHrdT/cNsQeCL+G67SQmjJe3qRnMIYghXiVt7+KDso/pU1Ky2ZfD/RBISfJQ==}
'@isaacs/balanced-match@4.0.1': '@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
@ -4338,6 +4347,9 @@ packages:
resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
toml@2.3.6:
resolution: {integrity: sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==}
totalist@3.0.1: totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -5206,6 +5218,13 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {} '@humanwhocodes/retry@0.4.3': {}
'@indic-transliteration/common_maps@1.0.5': {}
'@indic-transliteration/sanscript@1.3.3':
dependencies:
'@indic-transliteration/common_maps': 1.0.5
toml: 2.3.6
'@isaacs/balanced-match@4.0.1': {} '@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0': '@isaacs/brace-expansion@5.0.0':
@ -9085,6 +9104,8 @@ snapshots:
'@tokenizer/token': 0.3.0 '@tokenizer/token': 0.3.0
ieee754: 1.2.1 ieee754: 1.2.1
toml@2.3.6: {}
totalist@3.0.1: {} totalist@3.0.1: {}
truncate-utf8-bytes@1.0.2: truncate-utf8-bytes@1.0.2:

View File

@ -7,6 +7,7 @@ import * as pinyin from 'tiny-pinyin';
import { romanize as romanizeThaiFrag } from '@dehoist/romanize-thai'; import { romanize as romanizeThaiFrag } from '@dehoist/romanize-thai';
import { lazy } from 'lazy-var'; import { lazy } from 'lazy-var';
import { detect } from 'tinyld'; import { detect } from 'tinyld';
import Sanscript from '@indic-transliteration/sanscript';
import { waitForElement } from '@/utils/wait-for-element'; import { waitForElement } from '@/utils/wait-for-element';
import { LyricsRenderer, setIsVisible } from './renderer'; import { LyricsRenderer, setIsVisible } from './renderer';
@ -155,6 +156,12 @@ const hasChinese = (lines: string[]) =>
const hasThai = (lines: string[]) => const hasThai = (lines: string[]) =>
lines.some((line) => /[\u0E00-\u0E7F]+/.test(line)); lines.some((line) => /[\u0E00-\u0E7F]+/.test(line));
const hasBengali = (lines: string[]) =>
lines.some((line) => /[\u0980-\u09FF]+/.test(line));
const hasHindi = (lines: string[]) =>
lines.some((line) => /[\u0900-\u097F]+/.test(line));
export const romanizeJapanese = async (line: string) => export const romanizeJapanese = async (line: string) =>
(await kuroshiro.get()).convert(line, { (await kuroshiro.get()).convert(line, {
to: 'romaji', to: 'romaji',
@ -190,11 +197,35 @@ export const romanizeThai = (line: string) => {
return latin; return latin;
}; };
export const romanizeBengali = (line: string) => {
try {
let out = Sanscript.t(line, 'bengali', 'iast');
out = out.normalize('NFD');
out = out.replace(/[\u0300-\u036f]/g, '');
out = out.replace(/[\u09BC\u09BE-\u09CD]/g, '');
return out.toLowerCase();
} catch {
return line;
}
};
export const romanizeHindi = (line: string) => {
try {
let out = Sanscript.t(line, 'devanagari', 'iast');
out = out.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); // strip accents
return out.replace(/[^a-zA-Z\s]/g, '') || line; // remove any remaining symbols
} catch {
return line;
}
};
const handlers: Record<string, (line: string) => Promise<string> | string> = { const handlers: Record<string, (line: string) => Promise<string> | string> = {
ja: romanizeJapanese, ja: romanizeJapanese,
ko: romanizeHangul, ko: romanizeHangul,
zh: romanizeChinese, zh: romanizeChinese,
th: romanizeThai, th: romanizeThai,
bn: romanizeBengali,
hi: romanizeHindi,
}; };
export const romanize = async (line: string) => { export const romanize = async (line: string) => {
@ -210,6 +241,8 @@ export const romanize = async (line: string) => {
if (hasKorean([line])) line = romanizeHangul(line); if (hasKorean([line])) line = romanizeHangul(line);
if (hasChinese([line])) line = romanizeChinese(line); if (hasChinese([line])) line = romanizeChinese(line);
if (hasThai([line])) line = romanizeThai(line); if (hasThai([line])) line = romanizeThai(line);
if (hasBengali([line])) line = romanizeBengali(line);
if (hasHindi([line])) line = romanizeHindi(line);
return line; return line;
}; };