mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-03-09 21:03:55 +00:00
Compare commits
2 Commits
e3ea6da365
...
54d4400955
| Author | SHA1 | Date | |
|---|---|---|---|
| 54d4400955 | |||
| 208e57bdd3 |
@ -89,6 +89,7 @@
|
||||
"bgutils-js": "3.2.0",
|
||||
"butterchurn": "3.0.0-beta.5",
|
||||
"butterchurn-presets": "3.0.0-beta.4",
|
||||
"chinese-conv": "^4.0.0",
|
||||
"color": "5.0.3",
|
||||
"conf": "15.0.2",
|
||||
"custom-electron-prompt": "1.6.1",
|
||||
@ -109,7 +110,7 @@
|
||||
"hono": "4.11.7",
|
||||
"howler": "2.2.4",
|
||||
"html-to-text": "9.0.5",
|
||||
"i18next": "25.8.0",
|
||||
"i18next": "25.8.7",
|
||||
"jimp": "1.6.0",
|
||||
"keyboardevent-from-electron-accelerator": "2.0.0",
|
||||
"keyboardevents-areequal": "0.2.2",
|
||||
@ -121,6 +122,7 @@
|
||||
"node-html-parser": "7.0.2",
|
||||
"node-id3": "0.2.9",
|
||||
"peerjs": "1.5.5",
|
||||
"pinyin-pro": "^3.27.0",
|
||||
"semver": "7.7.3",
|
||||
"serve": "14.2.5",
|
||||
"socks": "2.8.7",
|
||||
@ -129,7 +131,6 @@
|
||||
"solid-js": "1.9.11",
|
||||
"solid-styled-components": "0.28.5",
|
||||
"solid-transition-group": "0.3.0",
|
||||
"tiny-pinyin": "1.3.2",
|
||||
"tinyld": "1.3.4",
|
||||
"virtua": "0.48.5",
|
||||
"vudio": "2.1.1",
|
||||
|
||||
54
pnpm-lock.yaml
generated
54
pnpm-lock.yaml
generated
@ -114,6 +114,9 @@ importers:
|
||||
butterchurn-presets:
|
||||
specifier: 3.0.0-beta.4
|
||||
version: 3.0.0-beta.4
|
||||
chinese-conv:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
color:
|
||||
specifier: 5.0.3
|
||||
version: 5.0.3
|
||||
@ -175,8 +178,8 @@ importers:
|
||||
specifier: 9.0.5
|
||||
version: 9.0.5
|
||||
i18next:
|
||||
specifier: 25.8.0
|
||||
version: 25.8.0(typescript@5.9.3)
|
||||
specifier: 25.8.7
|
||||
version: 25.8.7(typescript@5.9.3)
|
||||
jimp:
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0
|
||||
@ -210,6 +213,9 @@ importers:
|
||||
peerjs:
|
||||
specifier: 1.5.5
|
||||
version: 1.5.5
|
||||
pinyin-pro:
|
||||
specifier: ^3.27.0
|
||||
version: 3.27.0
|
||||
semver:
|
||||
specifier: 7.7.3
|
||||
version: 7.7.3
|
||||
@ -234,9 +240,6 @@ importers:
|
||||
solid-transition-group:
|
||||
specifier: 0.3.0
|
||||
version: 0.3.0(solid-js@1.9.11)
|
||||
tiny-pinyin:
|
||||
specifier: 1.3.2
|
||||
version: 1.3.2
|
||||
tinyld:
|
||||
specifier: 1.3.4
|
||||
version: 1.3.4
|
||||
@ -1306,9 +1309,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==}
|
||||
|
||||
@ -1830,6 +1830,10 @@ packages:
|
||||
resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==}
|
||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||
|
||||
chinese-conv@4.0.0:
|
||||
resolution: {integrity: sha512-PVBMzvv6CtX1cubaDXfxYscIdbOAHPuY/E2vnfJIzOACX+xIW4NRKRlNsZVI2p5KxGsXyUp7tVHfvQlqZ4yx/w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
||||
chownr@3.0.0:
|
||||
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
|
||||
engines: {node: '>=18'}
|
||||
@ -2701,16 +2705,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==}
|
||||
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==}
|
||||
@ -2826,8 +2830,8 @@ packages:
|
||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||
engines: {node: '>=10.17.0'}
|
||||
|
||||
i18next@25.8.0:
|
||||
resolution: {integrity: sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==}
|
||||
i18next@25.8.7:
|
||||
resolution: {integrity: sha512-ttxxc5+67S/0hhoeVdEgc1lRklZhdfcUSEPp1//uUG2NB88X3667gRsDar+ZWQFdysnOsnb32bcoMsa4mtzhkQ==}
|
||||
peerDependencies:
|
||||
typescript: ^5
|
||||
peerDependenciesMeta:
|
||||
@ -3740,6 +3744,9 @@ packages:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pinyin-pro@3.27.0:
|
||||
resolution: {integrity: sha512-Osdgjwe7Rm17N2paDMM47yW+jUIUH3+0RGo8QP39ZTLpTaJVDK0T58hOLaMQJbcMmAebVuK2ePunTEVEx1clNQ==}
|
||||
|
||||
pixelmatch@5.3.0:
|
||||
resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==}
|
||||
hasBin: true
|
||||
@ -4308,9 +4315,6 @@ packages:
|
||||
tiny-async-pool@1.3.0:
|
||||
resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==}
|
||||
|
||||
tiny-pinyin@1.3.2:
|
||||
resolution: {integrity: sha512-uHNGu4evFt/8eNLldazeAM1M8JrMc1jshhJJfVRARTN3yT8HEEibofeQ7QETWQ5ISBjd6fKtTVBCC/+mGS6FpA==}
|
||||
|
||||
tiny-typed-emitter@2.1.0:
|
||||
resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==}
|
||||
|
||||
@ -5716,7 +5720,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':
|
||||
@ -5747,7 +5751,7 @@ snapshots:
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 25.1.0
|
||||
'@types/node': 25.2.0
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
@ -5757,10 +5761,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
|
||||
@ -5773,7 +5773,7 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 25.1.0
|
||||
'@types/node': 25.2.0
|
||||
|
||||
'@types/semver@7.7.1': {}
|
||||
|
||||
@ -5790,7 +5790,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)':
|
||||
@ -6359,6 +6359,8 @@ snapshots:
|
||||
|
||||
chalk@5.0.1: {}
|
||||
|
||||
chinese-conv@4.0.0: {}
|
||||
|
||||
chownr@3.0.0: {}
|
||||
|
||||
chromium-pickle-js@0.2.0: {}
|
||||
@ -7597,7 +7599,7 @@ snapshots:
|
||||
|
||||
human-signals@2.1.0: {}
|
||||
|
||||
i18next@25.8.0(typescript@5.9.3):
|
||||
i18next@25.8.7(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.6
|
||||
optionalDependencies:
|
||||
@ -8458,6 +8460,8 @@ snapshots:
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
pinyin-pro@3.27.0: {}
|
||||
|
||||
pixelmatch@5.3.0:
|
||||
dependencies:
|
||||
pngjs: 6.0.0
|
||||
@ -9070,8 +9074,6 @@ snapshots:
|
||||
dependencies:
|
||||
semver: 5.7.2
|
||||
|
||||
tiny-pinyin@1.3.2: {}
|
||||
|
||||
tiny-typed-emitter@2.1.0: {}
|
||||
|
||||
tinycolor2@1.6.0: {}
|
||||
|
||||
@ -891,6 +891,24 @@
|
||||
"show-time-codes": {
|
||||
"label": "Show time codes",
|
||||
"tooltip": "Show the time codes next to the lyrics"
|
||||
},
|
||||
"convert-chinese-character": {
|
||||
"label": "Convert Chinese character",
|
||||
"submenu": {
|
||||
"disabled": {
|
||||
"label": "Disabled",
|
||||
"tooltip": "Disable Chinese character conversion"
|
||||
},
|
||||
"simplified-to-traditional": {
|
||||
"label": "Simplified to Traditional",
|
||||
"tooltip": "Convert Simplified Chinese to Traditional Chinese"
|
||||
},
|
||||
"traditional-to-simplified": {
|
||||
"label": "Traditional to Simplified",
|
||||
"tooltip": "Convert Traditional Chinese to Simplified Chinese"
|
||||
}
|
||||
},
|
||||
"tooltip": "Convert Chinese character to Traditional or Simplified"
|
||||
}
|
||||
},
|
||||
"name": "Synced Lyrics",
|
||||
|
||||
@ -153,6 +153,62 @@ export const menu = async (
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('plugins.synced-lyrics.menu.convert-chinese-character.label'),
|
||||
toolTip: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.tooltip',
|
||||
),
|
||||
type: 'submenu',
|
||||
submenu: [
|
||||
{
|
||||
label: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.disabled.label',
|
||||
),
|
||||
toolTip: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.disabled.tooltip',
|
||||
),
|
||||
type: 'radio',
|
||||
checked:
|
||||
config.convertChineseCharacter === 'disabled' ||
|
||||
config.convertChineseCharacter === undefined,
|
||||
click() {
|
||||
ctx.setConfig({
|
||||
convertChineseCharacter: 'disabled',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.simplified-to-traditional.label',
|
||||
),
|
||||
toolTip: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.simplified-to-traditional.tooltip',
|
||||
),
|
||||
type: 'radio',
|
||||
checked: config.convertChineseCharacter === 'simplifiedToTraditional',
|
||||
click() {
|
||||
ctx.setConfig({
|
||||
convertChineseCharacter: 'simplifiedToTraditional',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.traditional-to-simplified.label',
|
||||
),
|
||||
toolTip: t(
|
||||
'plugins.synced-lyrics.menu.convert-chinese-character.submenu.traditional-to-simplified.tooltip',
|
||||
),
|
||||
type: 'radio',
|
||||
checked: config.convertChineseCharacter === 'traditionalToSimplified',
|
||||
click() {
|
||||
ctx.setConfig({
|
||||
convertChineseCharacter: 'traditionalToSimplified',
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: t('plugins.synced-lyrics.menu.show-time-codes.label'),
|
||||
toolTip: t('plugins.synced-lyrics.menu.show-time-codes.tooltip'),
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import { createEffect, createSignal, Show } from 'solid-js';
|
||||
import { createEffect, createMemo, createSignal, Show } from 'solid-js';
|
||||
|
||||
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
||||
import {
|
||||
canonicalize,
|
||||
convertChineseCharacter,
|
||||
romanize,
|
||||
simplifyUnicode,
|
||||
} from '../utils';
|
||||
import { config } from '../renderer';
|
||||
|
||||
interface PlainLyricsProps {
|
||||
@ -9,11 +14,19 @@ interface PlainLyricsProps {
|
||||
|
||||
export const PlainLyrics = (props: PlainLyricsProps) => {
|
||||
const [romanization, setRomanization] = createSignal('');
|
||||
const text = createMemo(() => {
|
||||
let line = props.line;
|
||||
const convertChineseText = config()?.convertChineseCharacter;
|
||||
if (convertChineseText && convertChineseText !== 'disabled') {
|
||||
line = convertChineseCharacter(line, convertChineseText);
|
||||
}
|
||||
return line;
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
if (!config()?.romanization) return;
|
||||
|
||||
const input = canonicalize(props.line);
|
||||
const input = canonicalize(text());
|
||||
romanize(input).then((result) => {
|
||||
setRomanization(canonicalize(result));
|
||||
});
|
||||
@ -31,13 +44,13 @@ export const PlainLyrics = (props: PlainLyricsProps) => {
|
||||
>
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [{ text: props.line }],
|
||||
runs: [{ text: text() }],
|
||||
}}
|
||||
/>
|
||||
<Show
|
||||
when={
|
||||
config()?.romanization &&
|
||||
simplifyUnicode(props.line) !== simplifyUnicode(romanization())
|
||||
simplifyUnicode(text()) !== simplifyUnicode(romanization())
|
||||
}
|
||||
>
|
||||
<yt-formatted-string
|
||||
|
||||
@ -7,7 +7,12 @@ import { type LineLyrics } from '@/plugins/synced-lyrics/types';
|
||||
import { config, currentTime } from '../renderer';
|
||||
import { _ytAPI } from '..';
|
||||
|
||||
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
||||
import {
|
||||
canonicalize,
|
||||
convertChineseCharacter,
|
||||
romanize,
|
||||
simplifyUnicode,
|
||||
} from '../utils';
|
||||
|
||||
interface SyncedLineProps {
|
||||
scroller: VirtualizerHandle;
|
||||
@ -81,7 +86,14 @@ const EmptyLine = (props: SyncedLineProps) => {
|
||||
};
|
||||
|
||||
export const SyncedLine = (props: SyncedLineProps) => {
|
||||
const text = createMemo(() => props.line.text.trim());
|
||||
const text = createMemo(() => {
|
||||
let line = props.line.text;
|
||||
const convertChineseText = config()?.convertChineseCharacter;
|
||||
if (convertChineseText && convertChineseText !== 'disabled') {
|
||||
line = convertChineseCharacter(line, convertChineseText);
|
||||
}
|
||||
return line.trim();
|
||||
});
|
||||
|
||||
const [romanization, setRomanization] = createSignal('');
|
||||
createEffect(() => {
|
||||
|
||||
@ -3,10 +3,11 @@ import KuromojiAnalyzer from 'kuroshiro-analyzer-kuromoji';
|
||||
import Kuroshiro from 'kuroshiro';
|
||||
import { romanize as esHangulRomanize } from 'es-hangul';
|
||||
import hanja from 'hanja';
|
||||
import * as pinyin from 'tiny-pinyin';
|
||||
import { pinyin } from 'pinyin-pro';
|
||||
import { romanize as romanizeThaiFrag } from '@dehoist/romanize-thai';
|
||||
import { lazy } from 'lazy-var';
|
||||
import { detect } from 'tinyld';
|
||||
import { sify, tify } from 'chinese-conv';
|
||||
import Sanscript from '@indic-transliteration/sanscript';
|
||||
|
||||
import { waitForElement } from '@/utils/wait-for-element';
|
||||
@ -85,6 +86,20 @@ export const canonicalize = (text: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const convertChineseCharacter = (
|
||||
text: string,
|
||||
mode: 'simplifiedToTraditional' | 'traditionalToSimplified',
|
||||
) => {
|
||||
if (!hasChinese([text])) return text;
|
||||
|
||||
switch (mode) {
|
||||
case 'simplifiedToTraditional':
|
||||
return tify(text);
|
||||
case 'traditionalToSimplified':
|
||||
return sify(text);
|
||||
}
|
||||
};
|
||||
|
||||
export const simplifyUnicode = (text?: string) =>
|
||||
text
|
||||
? text
|
||||
@ -172,9 +187,9 @@ export const romanizeHangul = (line: string) =>
|
||||
esHangulRomanize(hanja.translate(line, 'SUBSTITUTION'));
|
||||
|
||||
export const romanizeChinese = (line: string) => {
|
||||
return line.replaceAll(/[\u4E00-\u9FFF]+/g, (match) =>
|
||||
pinyin.convertToPinyin(match, ' ', true),
|
||||
);
|
||||
return line.replaceAll(/[\u4E00-\u9FFF]+/g, (match) => {
|
||||
return pinyin(match, { separator: ' ' });
|
||||
});
|
||||
};
|
||||
|
||||
const thaiSegmenter = Intl.Segmenter.supportedLocalesOf('th').includes('th')
|
||||
|
||||
@ -10,6 +10,10 @@ export type SyncedLyricsPluginConfig = {
|
||||
showLyricsEvenIfInexact: boolean;
|
||||
lineEffect: LineEffect;
|
||||
romanization: boolean;
|
||||
convertChineseCharacter?:
|
||||
| 'simplifiedToTraditional'
|
||||
| 'traditionalToSimplified'
|
||||
| 'disabled';
|
||||
};
|
||||
|
||||
export type LineLyricsStatus = 'previous' | 'current' | 'upcoming';
|
||||
|
||||
Reference in New Issue
Block a user