aquavox/src/lib/components/newLyrics.svelte
2024-08-02 03:16:01 +08:00

125 lines
3.8 KiB
Svelte

<script lang="ts">
import { onDestroy } from 'svelte';
import {
LyricPlayer as CoreLyricPlayer,
type LyricLineMouseEvent,
type LyricLine,
type spring
} from '@applemusic-like-lyrics/core';
export let disabled: boolean = false;
export let playing: boolean = true;
export let alignAnchor: 'top' | 'bottom' | 'center' = 'center';
export let alignPosition: number = 0.5;
export let enableSpring: boolean = true;
export let enableBlur: boolean = true;
export let enableScale: boolean = true;
export let hidePassedLines: boolean = false;
export let lyricLines: LyricLine[] = [];
export let currentTime: number = 0;
export let linePosXSpringParams: Partial<spring.SpringParams> = {};
export let linePosYSpringParams: Partial<spring.SpringParams> = {};
export let lineScaleSpringParams: Partial<spring.SpringParams> = {};
export let bottomLine: Node = document.createElement('div');
export let onLyricLineClick: (line: LyricLineMouseEvent) => void = () => {};
export let onLyricLineContextMenu: (line: LyricLineMouseEvent) => void = () => {};
export let lyricPlayer: CoreLyricPlayer;
let className;
export { className as class };
let lyricsElement: HTMLDivElement | null;
let bottomLineElement: HTMLDivElement | null;
let animationCanceled = false;
let animationLastTime = -1;
let lineClickHandler: (e: Event) => void;
let contextMenuHandler: (e: Event) => void;
$: {
if (playing) {
lyricPlayer.resume();
} else {
lyricPlayer.pause();
}
}
const onFrame = (time: number) => {
if (animationCanceled) return;
if (animationLastTime === -1) {
animationLastTime = time;
}
lyricPlayer.update(time - animationLastTime);
animationLastTime = time;
requestAnimationFrame(onFrame);
};
const startAnimation = () => {
animationCanceled = false;
animationLastTime = -1;
requestAnimationFrame(onFrame);
};
const stopAnimation = () => {
animationCanceled = true;
};
$: {
if (!disabled) {
startAnimation();
} else {
stopAnimation();
}
}
$: {
if (lyricsElement) {
lyricsElement.appendChild(lyricPlayer.getElement());
}
if (bottomLineElement) {
lyricPlayer.getBottomLineElement().appendChild(bottomLine);
}
}
$: {
lyricPlayer.setAlignAnchor(alignAnchor);
lyricPlayer.setAlignPosition(alignPosition);
lyricPlayer.setEnableSpring(enableSpring);
lyricPlayer.setEnableScale(enableScale);
lyricPlayer.setEnableBlur(enableBlur);
lyricPlayer.setLinePosXSpringParams(linePosXSpringParams);
lyricPlayer.setLinePosYSpringParams(linePosYSpringParams);
lyricPlayer.setLineScaleSpringParams(lineScaleSpringParams);
lyricPlayer.setHidePassedLines(hidePassedLines);
}
$: {
lyricPlayer.setLyricLines(lyricLines);
lyricPlayer.update();
}
$: {
lyricPlayer.setCurrentTime(currentTime);
}
$: {
lineClickHandler = (e: Event) => onLyricLineClick(e as LyricLineMouseEvent);
lyricPlayer.addEventListener('line-click', lineClickHandler);
}
$: {
contextMenuHandler = (e: Event) => onLyricLineContextMenu(e as LyricLineMouseEvent);
lyricPlayer.addEventListener('line-contextmenu', contextMenuHandler);
}
onDestroy(() => {
animationCanceled = true;
lyricPlayer.dispose();
lyricPlayer.removeEventListener('line-contextmenu', contextMenuHandler);
lyricPlayer.removeEventListener('line-click', lineClickHandler);
});
</script>
<div bind:this={lyricsElement} class={className}></div>
<div bind:this={bottomLineElement}></div>