diff --git a/package.json b/package.json index 70058383fc..73edf8b490 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@jellybrick/electron-better-web-request": "2.0.0", "@jellybrick/mpris-service": "2.2.0", "@mdui/icons": "1.0.3", + "@mediapipe/tasks-text": "^0.10.35", "@skyra/jaro-winkler": "1.1.1", "@xhayper/discord-rpc": "1.3.4", "async-mutex": "0.5.0", @@ -114,7 +115,6 @@ "solid-js": "1.9.13", "solid-styled-components": "0.28.5", "solid-transition-group": "0.3.0", - "tinyld": "1.3.4", "virtua": "0.49.1", "vudio": "2.1.1", "youtubei.js": "17.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 056c50a2de..47ef56b8e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@mdui/icons': specifier: 1.0.3 version: 1.0.3 + '@mediapipe/tasks-text': + specifier: ^0.10.35 + version: 0.10.35 '@skyra/jaro-winkler': specifier: 1.1.1 version: 1.1.1 @@ -219,9 +222,6 @@ importers: solid-transition-group: specifier: 0.3.0 version: 0.3.0(solid-js@1.9.13) - tinyld: - specifier: 1.3.4 - version: 1.3.4 virtua: specifier: 0.49.1 version: 0.49.1(solid-js@1.9.13) @@ -878,6 +878,9 @@ packages: '@mdui/shared@1.0.8': resolution: {integrity: sha512-YY863fjHBuk8KtiO4uLDm1YyIVdGrWv4xUxfv8jP32WqIQBkSTbV7HN8jnKXXIej0NFP7pU89yGr4GJYzVszPg==} + '@mediapipe/tasks-text@0.10.35': + resolution: {integrity: sha512-BlRWXZAHakqtAos8hNgSU0jy4mh60R9ewzwckS3q2nV7Q/7L65otCtoDrgslRBhlfbElfcHbHQXKRahlMRCf4Q==} + '@msgpack/msgpack@2.8.0': resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} engines: {node: '>= 10'} @@ -3772,11 +3775,6 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyld@1.3.4: - resolution: {integrity: sha512-u26CNoaInA4XpDU+8s/6Cq8xHc2T5M4fXB3ICfXPokUQoLzmPgSZU02TAkFwFMJCWTjk53gtkS8pETTreZwCqw==} - engines: {node: '>= 12.10.0', npm: '>= 6.12.0', yarn: '>= 1.20.0'} - hasBin: true - tinypool@2.1.0: resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} engines: {node: ^20.0.0 || >=22.0.0} @@ -4724,6 +4722,8 @@ snapshots: ssr-window: 5.0.1 tslib: 2.8.1 + '@mediapipe/tasks-text@0.10.35': {} + '@msgpack/msgpack@2.8.0': {} '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': @@ -7502,8 +7502,6 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinyld@1.3.4: {} - tinypool@2.1.0: {} tldts-core@7.4.3: {} diff --git a/src/pear-desktop.ts b/src/pear-desktop.ts index b5ace4e1fe..f546172f3f 100644 --- a/src/pear-desktop.ts +++ b/src/pear-desktop.ts @@ -39,3 +39,8 @@ declare module '*.css?inline' { export default css; } +declare module '*.tflite?url' { + const url: string; + + export default url; +} diff --git a/src/plugins/synced-lyrics/language-detector.ts b/src/plugins/synced-lyrics/language-detector.ts new file mode 100644 index 0000000000..a60d0d3d13 --- /dev/null +++ b/src/plugins/synced-lyrics/language-detector.ts @@ -0,0 +1,38 @@ +import { + FilesetResolver, + LanguageDetector, +} from '@mediapipe/tasks-text'; +import lazyVar from 'lazy-var'; + +import modelAssetPath from './language_detector.tflite?url'; + +const WASM_BASE = + 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-text@0.10.35/wasm/'; + +const languageDetector = lazyVar.lazy(async () => { + const wasmFileset = await FilesetResolver.forTextTasks(WASM_BASE); + return LanguageDetector.createFromOptions(wasmFileset, { + baseOptions: { + modelAssetPath, + }, + maxResults: 1, + }); +}); + +export async function detectLanguage( + text: string, +): Promise { + const trimmed = text.trim(); + if (!trimmed) return undefined; + + try { + const detector = await languageDetector.get(); + const result = detector.detect(trimmed); + const top = result.languages[0]; + if (!top) return undefined; + + return top.languageCode.split('-')[0]; + } catch { + return undefined; + } +} diff --git a/src/plugins/synced-lyrics/language_detector.tflite b/src/plugins/synced-lyrics/language_detector.tflite new file mode 100644 index 0000000000..39634228bb Binary files /dev/null and b/src/plugins/synced-lyrics/language_detector.tflite differ diff --git a/src/plugins/synced-lyrics/renderer/utils.tsx b/src/plugins/synced-lyrics/renderer/utils.tsx index dd0811138b..01cd3cab14 100644 --- a/src/plugins/synced-lyrics/renderer/utils.tsx +++ b/src/plugins/synced-lyrics/renderer/utils.tsx @@ -8,9 +8,8 @@ import KuromojiAnalyzer from 'kuroshiro-analyzer-kuromoji'; import lazyVar from 'lazy-var'; import { pinyin } from 'pinyin-pro'; import { render } from 'solid-js/web'; -import { detect } from 'tinyld'; - import { waitForElement } from '@/utils/wait-for-element'; +import { detectLanguage } from '../language-detector'; import { LyricsRenderer, setIsVisible } from './renderer'; @@ -245,9 +244,9 @@ const handlers: Record Promise | string> = { }; export const romanize = async (line: string) => { - const lang = detect(line); + const lang = await detectLanguage(line); - const handler = handlers[lang]; + const handler = lang && handlers[lang]; if (handler) { return handler(line); }