mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-15 20:31:46 +00:00
134 lines
3.7 KiB
TypeScript
134 lines
3.7 KiB
TypeScript
import { createEffect, createMemo, For, Show, createSignal } from 'solid-js';
|
|
|
|
import { type VirtualizerHandle } from 'virtua/solid';
|
|
|
|
import { type LineLyrics } from '@/plugins/synced-lyrics/types';
|
|
|
|
import { config } from '../renderer';
|
|
import { _ytAPI } from '..';
|
|
|
|
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
|
|
|
interface SyncedLineProps {
|
|
scroller: VirtualizerHandle;
|
|
index: number;
|
|
|
|
line: LineLyrics;
|
|
status: 'upcoming' | 'current' | 'previous';
|
|
}
|
|
|
|
export const SyncedLine = (props: SyncedLineProps) => {
|
|
const text = createMemo(() => {
|
|
if (!props.line.text.trim()) {
|
|
return config()?.defaultTextString ?? '';
|
|
}
|
|
|
|
return props.line.text;
|
|
});
|
|
|
|
const [romanization, setRomanization] = createSignal('');
|
|
|
|
createEffect(() => {
|
|
if (!config()?.romanization) return;
|
|
|
|
const input = canonicalize(text());
|
|
romanize(input).then((result) => {
|
|
setRomanization(canonicalize(result));
|
|
});
|
|
});
|
|
|
|
return (
|
|
<Show
|
|
fallback={
|
|
<yt-formatted-string
|
|
text={{
|
|
runs: [{ text: '' }],
|
|
}}
|
|
/>
|
|
}
|
|
when={text()}
|
|
>
|
|
<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"
|
|
ref={(div: HTMLDivElement) => {
|
|
// TODO: Investigate the animation, even though the duration is properly set, all lines have the same animation duration
|
|
div.style.setProperty(
|
|
'--lyrics-duration',
|
|
`${props.line.duration / 1000}s`,
|
|
'important',
|
|
);
|
|
}}
|
|
style={{ 'display': 'flex', 'flex-direction': 'column' }}
|
|
>
|
|
<span>
|
|
<For each={text().split(' ')}>
|
|
{(word, index) => {
|
|
return (
|
|
<span
|
|
style={{
|
|
'transition-delay': `${index() * 0.05}s`,
|
|
'animation-delay': `${index() * 0.05}s`,
|
|
}}
|
|
>
|
|
<yt-formatted-string
|
|
text={{
|
|
runs: [{ text: `${word} ` }],
|
|
}}
|
|
/>
|
|
</span>
|
|
);
|
|
}}
|
|
</For>
|
|
</span>
|
|
|
|
<Show
|
|
when={
|
|
config()?.romanization &&
|
|
simplifyUnicode(text()) !== simplifyUnicode(romanization())
|
|
}
|
|
>
|
|
<span class="romaji">
|
|
<For each={romanization().split(' ')}>
|
|
{(word, index) => {
|
|
return (
|
|
<span
|
|
style={{
|
|
'transition-delay': `${index() * 0.05}s`,
|
|
'animation-delay': `${index() * 0.05}s`,
|
|
}}
|
|
>
|
|
<yt-formatted-string
|
|
text={{
|
|
runs: [{ text: `${word} ` }],
|
|
}}
|
|
/>
|
|
</span>
|
|
);
|
|
}}
|
|
</For>
|
|
</span>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Show>
|
|
);
|
|
};
|