mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-17 13:12:07 +00:00
feat(synced-lyrics): add new "spacer" (#3742)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@ -93,47 +93,23 @@ export const menu = async (
|
|||||||
toolTip: t('plugins.synced-lyrics.menu.default-text-string.tooltip'),
|
toolTip: t('plugins.synced-lyrics.menu.default-text-string.tooltip'),
|
||||||
type: 'submenu',
|
type: 'submenu',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{ label: '♪', value: '♪' },
|
||||||
label: '♪',
|
{ label: '" "', value: ' ' },
|
||||||
type: 'radio',
|
{ label: '...', value: ['.', '..', '...'] },
|
||||||
checked: config.defaultTextString === '♪',
|
{ label: '•••', value: ['•', '••', '•••'] },
|
||||||
click() {
|
{ label: '———', value: '———' },
|
||||||
ctx.setConfig({
|
].map(({ label, value }) => ({
|
||||||
defaultTextString: '♪',
|
label,
|
||||||
});
|
type: 'radio',
|
||||||
},
|
checked:
|
||||||
|
typeof value === 'string'
|
||||||
|
? config.defaultTextString === value
|
||||||
|
: JSON.stringify(config.defaultTextString) ===
|
||||||
|
JSON.stringify(value),
|
||||||
|
click() {
|
||||||
|
ctx.setConfig({ defaultTextString: value });
|
||||||
},
|
},
|
||||||
{
|
})),
|
||||||
label: '" "',
|
|
||||||
type: 'radio',
|
|
||||||
checked: config.defaultTextString === ' ',
|
|
||||||
click() {
|
|
||||||
ctx.setConfig({
|
|
||||||
defaultTextString: ' ',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '...',
|
|
||||||
type: 'radio',
|
|
||||||
checked: config.defaultTextString === '...',
|
|
||||||
click() {
|
|
||||||
ctx.setConfig({
|
|
||||||
defaultTextString: '...',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '———',
|
|
||||||
type: 'radio',
|
|
||||||
checked: config.defaultTextString === '———',
|
|
||||||
click() {
|
|
||||||
ctx.setConfig({
|
|
||||||
defaultTextString: '———',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('plugins.synced-lyrics.menu.romanization.label'),
|
label: t('plugins.synced-lyrics.menu.romanization.label'),
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { createEffect, createMemo, For, Show, createSignal } from 'solid-js';
|
import { createEffect, For, Show, createSignal, createMemo } from 'solid-js';
|
||||||
|
|
||||||
import { type VirtualizerHandle } from 'virtua/solid';
|
import { type VirtualizerHandle } from 'virtua/solid';
|
||||||
|
|
||||||
import { type LineLyrics } from '@/plugins/synced-lyrics/types';
|
import { type LineLyrics } from '@/plugins/synced-lyrics/types';
|
||||||
|
|
||||||
import { config } from '../renderer';
|
import { config, currentTime } from '../renderer';
|
||||||
import { _ytAPI } from '..';
|
import { _ytAPI } from '..';
|
||||||
|
|
||||||
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
||||||
@ -17,37 +17,84 @@ interface SyncedLineProps {
|
|||||||
status: 'upcoming' | 'current' | 'previous';
|
status: 'upcoming' | 'current' | 'previous';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SyncedLine = (props: SyncedLineProps) => {
|
const EmptyLine = (props: SyncedLineProps) => {
|
||||||
const text = createMemo(() => {
|
const states = createMemo(() => {
|
||||||
if (!props.line.text.trim()) {
|
const defaultText = config()?.defaultTextString ?? '';
|
||||||
return config()?.defaultTextString ?? '';
|
return Array.isArray(defaultText) ? defaultText : [defaultText];
|
||||||
}
|
|
||||||
|
|
||||||
return props.line.text;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [romanization, setRomanization] = createSignal('');
|
const index = createMemo(() => {
|
||||||
|
const progress = currentTime() - props.line.timeInMs;
|
||||||
|
const total = props.line.duration;
|
||||||
|
|
||||||
|
const percentage = Math.min(1, progress / total);
|
||||||
|
return Math.max(0, Math.floor((states().length - 1) * percentage));
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={`synced-line ${props.status}`}
|
||||||
|
onClick={() => {
|
||||||
|
_ytAPI?.seekTo((props.line.timeInMs + 10) / 1000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="description ytmusic-description-shelf-renderer" dir="auto">
|
||||||
|
<yt-formatted-string
|
||||||
|
text={{
|
||||||
|
runs: [
|
||||||
|
{
|
||||||
|
text: config()?.showTimeCodes ? `[${props.line.time}] ` : '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="text-lyrics">
|
||||||
|
<span>
|
||||||
|
<span>
|
||||||
|
<Show
|
||||||
|
fallback={
|
||||||
|
<yt-formatted-string
|
||||||
|
text={{ runs: [{ text: states()[0] }] }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
when={states().length > 1}
|
||||||
|
>
|
||||||
|
<yt-formatted-string
|
||||||
|
text={{
|
||||||
|
runs: [
|
||||||
|
{
|
||||||
|
text: states().at(
|
||||||
|
props.status === 'current' ? index() : -1,
|
||||||
|
)!,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SyncedLine = (props: SyncedLineProps) => {
|
||||||
|
const text = createMemo(() => props.line.text.trim());
|
||||||
|
|
||||||
|
const [romanization, setRomanization] = createSignal('');
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
const input = canonicalize(text());
|
||||||
if (!config()?.romanization) return;
|
if (!config()?.romanization) return;
|
||||||
|
|
||||||
const input = canonicalize(text());
|
|
||||||
romanize(input).then((result) => {
|
romanize(input).then((result) => {
|
||||||
setRomanization(canonicalize(result));
|
setRomanization(canonicalize(result));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show fallback={<EmptyLine {...props} />} when={text()}>
|
||||||
fallback={
|
|
||||||
<yt-formatted-string
|
|
||||||
text={{
|
|
||||||
runs: [{ text: '' }],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
when={text()}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class={`synced-line ${props.status}`}
|
class={`synced-line ${props.status}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export type SyncedLyricsPluginConfig = {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
preciseTiming: boolean;
|
preciseTiming: boolean;
|
||||||
showTimeCodes: boolean;
|
showTimeCodes: boolean;
|
||||||
defaultTextString: string;
|
defaultTextString: string | string[];
|
||||||
showLyricsEvenIfInexact: boolean;
|
showLyricsEvenIfInexact: boolean;
|
||||||
lineEffect: LineEffect;
|
lineEffect: LineEffect;
|
||||||
romanization: boolean;
|
romanization: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user