Compare commits

...

2 Commits

3 changed files with 80 additions and 32 deletions

View File

@ -77,6 +77,7 @@
"@hono/swagger-ui": "0.5.3",
"@hono/zod-openapi": "1.2.1",
"@hono/zod-validator": "0.7.6",
"@indic-transliteration/sanscript": "1.3.3",
"@jellybrick/dbus-next": "0.10.3",
"@jellybrick/electron-better-web-request": "2.0.0",
"@jellybrick/mpris-service": "2.1.5",
@ -165,7 +166,7 @@
"eslint-plugin-import": "2.32.0",
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-solid": "0.14.5",
"glob": "13.0.0",
"glob": "13.0.2",
"node-gyp": "12.2.0",
"ts-morph": "27.0.2",
"typescript": "5.9.3",

76
pnpm-lock.yaml generated
View File

@ -78,6 +78,9 @@ importers:
'@hono/zod-validator':
specifier: 0.7.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':
specifier: 0.10.3
version: 0.10.3
@ -335,8 +338,8 @@ importers:
specifier: 0.14.5
version: 0.14.5(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
glob:
specifier: 13.0.0
version: 13.0.0
specifier: 13.0.2
version: 13.0.2
node-gyp:
specifier: 12.2.0
version: 12.2.0
@ -843,12 +846,18 @@ packages:
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
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':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.0':
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
'@isaacs/brace-expansion@5.0.1':
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
engines: {node: 20 || >=22}
'@isaacs/cliui@8.0.2':
@ -1297,9 +1306,6 @@ packages:
'@types/node@24.10.9':
resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==}
'@types/node@25.1.0':
resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==}
'@types/node@25.2.0':
resolution: {integrity: sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==}
@ -2692,16 +2698,16 @@ packages:
glob@11.1.0:
resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
engines: {node: 20 || >=22}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
glob@13.0.0:
resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
glob@13.0.2:
resolution: {integrity: sha512-035InabNu/c1lW0tzPhAgapKctblppqsKKG9ZaNzbr+gXwWMjXoiyGSyB9sArzrjG7jY+zntRq5ZSUYemrnWVQ==}
engines: {node: 20 || >=22}
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
global-agent@3.0.0:
resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
@ -3410,8 +3416,8 @@ packages:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
minimatch@10.1.1:
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
minimatch@10.1.2:
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
engines: {node: 20 || >=22}
minimatch@3.1.2:
@ -4338,6 +4344,9 @@ packages:
resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==}
engines: {node: '>=10'}
toml@2.3.6:
resolution: {integrity: sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==}
totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
@ -4871,7 +4880,7 @@ snapshots:
dependencies:
commander: 13.1.0
glob: 11.1.0
minimatch: 10.1.1
minimatch: 10.1.2
'@electron/fuses@1.8.0':
dependencies:
@ -5206,9 +5215,16 @@ snapshots:
'@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/brace-expansion@5.0.0':
'@isaacs/brace-expansion@5.0.1':
dependencies:
'@isaacs/balanced-match': 4.0.1
@ -5663,7 +5679,7 @@ snapshots:
'@ts-morph/common@0.28.1':
dependencies:
minimatch: 10.1.1
minimatch: 10.1.2
path-browserify: 1.0.1
tinyglobby: 0.2.15
@ -5697,7 +5713,7 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.2.0
'@types/keyv': 3.1.4
'@types/node': 25.1.0
'@types/node': 25.2.0
'@types/responselike': 1.0.3
'@types/debug@4.1.12':
@ -5728,7 +5744,7 @@ snapshots:
'@types/keyv@3.1.4':
dependencies:
'@types/node': 25.1.0
'@types/node': 25.2.0
'@types/ms@2.1.0': {}
@ -5738,10 +5754,6 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@types/node@25.1.0':
dependencies:
undici-types: 7.16.0
'@types/node@25.2.0':
dependencies:
undici-types: 7.16.0
@ -5754,7 +5766,7 @@ snapshots:
'@types/responselike@1.0.3':
dependencies:
'@types/node': 25.1.0
'@types/node': 25.2.0
'@types/semver@7.7.1': {}
@ -5771,7 +5783,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 25.1.0
'@types/node': 25.2.0
optional: true
'@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
@ -6034,7 +6046,7 @@ snapshots:
js-yaml: 4.1.1
json5: 2.2.3
lazy-val: 1.0.5
minimatch: 10.1.1
minimatch: 10.1.2
plist: 3.1.0
proper-lockfile: 4.1.2
resedit: 1.7.2
@ -6284,7 +6296,7 @@ snapshots:
dependencies:
'@npmcli/fs': 5.0.0
fs-minipass: 3.0.3
glob: 13.0.0
glob: 13.0.2
lru-cache: 11.2.5
minipass: 7.1.2
minipass-collect: 2.0.1
@ -7422,14 +7434,14 @@ snapshots:
dependencies:
foreground-child: 3.3.1
jackspeak: 4.1.1
minimatch: 10.1.1
minimatch: 10.1.2
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 2.0.1
glob@13.0.0:
glob@13.0.2:
dependencies:
minimatch: 10.1.1
minimatch: 10.1.2
minipass: 7.1.2
path-scurry: 2.0.1
@ -8124,9 +8136,9 @@ snapshots:
mimic-response@3.1.0: {}
minimatch@10.1.1:
minimatch@10.1.2:
dependencies:
'@isaacs/brace-expansion': 5.0.0
'@isaacs/brace-expansion': 5.0.1
minimatch@3.1.2:
dependencies:
@ -9085,6 +9097,8 @@ snapshots:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
toml@2.3.6: {}
totalist@3.0.1: {}
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 { lazy } from 'lazy-var';
import { detect } from 'tinyld';
import Sanscript from '@indic-transliteration/sanscript';
import { waitForElement } from '@/utils/wait-for-element';
import { LyricsRenderer, setIsVisible } from './renderer';
@ -155,6 +156,12 @@ const hasChinese = (lines: string[]) =>
const hasThai = (lines: string[]) =>
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) =>
(await kuroshiro.get()).convert(line, {
to: 'romaji',
@ -190,11 +197,35 @@ export const romanizeThai = (line: string) => {
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> = {
ja: romanizeJapanese,
ko: romanizeHangul,
zh: romanizeChinese,
th: romanizeThai,
bn: romanizeBengali,
hi: romanizeHindi,
};
export const romanize = async (line: string) => {
@ -210,6 +241,8 @@ export const romanize = async (line: string) => {
if (hasKorean([line])) line = romanizeHangul(line);
if (hasChinese([line])) line = romanizeChinese(line);
if (hasThai([line])) line = romanizeThai(line);
if (hasBengali([line])) line = romanizeBengali(line);
if (hasHindi([line])) line = romanizeHindi(line);
return line;
};