ref: migrating to Svelte 5

This commit is contained in:
alikia2x (寒寒) 2024-11-17 19:21:26 +08:00
parent 57de9f426f
commit 93855a3f61
Signed by: alikia2x
GPG Key ID: 56209E0CCD8420C6
7 changed files with 85 additions and 111 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -26,7 +26,7 @@
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3",
"svelte": "^4.2.19",
"svelte": "^5.2.2",
"svelte-check": "^3.7.1",
"typescript": "^5.4.5",
"vite-plugin-wasm": "^3.3.0",

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { type ScriptItem, type LyricData } from '@alikia/aqualyrics';
import { type LyricData, type ScriptItem } from '@alikia/aqualyrics';
import { onMount } from 'svelte';
import LyricLine from './lyricLine.svelte';
import createLyricsSearcher from '@core/lyrics/lyricSearcher';
@ -15,38 +15,34 @@
document.body.style.overflow = 'hidden';
// Props
export let originalLyrics: LyricData;
export let progress: number;
export let player: HTMLAudioElement | null;
let { originalLyrics, progress, player } : {
originalLyrics: LyricData,
progress: number,
player: HTMLAudioElement | null
} = $props();
// States
let lyricLines: ScriptItem[] = [];
let lyricExists = false;
let lyricsContainer: HTMLDivElement | null;
let debugMode = false;
let nextUpdate = 0;
let lastProgress = 0;
let showTranslation = false;
let scrollEventAdded = false;
let scrolling = false;
let scrollingTimeout: Timer;
let lastY: number; // For tracking touch movements
let lastTime: number; // For tracking time between touch moves
let velocityY = 0; // Vertical scroll velocity
let inertiaFrame: number; // For storing the requestAnimationFrame reference
let lyricLines: ScriptItem[] = $state([]);
let lyricsContainer: HTMLDivElement | null = $state(null);
let debugMode = $state(false);
let nextUpdate = $state(0);
let lastProgress = $state(0);
let showTranslation = $state(false);
let scrollEventAdded = $state(false);
let scrolling = $state(false);
let scrollingTimeout: Timer | null = $state(null);
let lastY: number = $state(0); // For tracking touch movements
let lastTime: number = $state(0); // For tracking time between touch moves
let velocityY = $state(0); // Vertical scroll velocity
let inertiaFrame: number = $state(0); // For storing the requestAnimationFrame reference
// References to lyric elements
let lyricElements: HTMLDivElement[] = [];
let lyricComponents: LyricLine[] = [];
let lyricTopList: number[] = [];
let lyricElements: HTMLDivElement[] = $state([]);
let lyricComponents: LyricLine[] = $state([]);
let lyricTopList: number[] = $state([]);
let currentLyricIndex: number;
$: getLyricIndex = createLyricsSearcher(originalLyrics);
$: {
currentLyricIndex = getLyricIndex(progress);
}
let getLyricIndex = $derived(createLyricsSearcher(originalLyrics));
let currentLyricIndex = $derived(getLyricIndex(progress));
function initLyricComponents() {
initLyricTopList();
@ -88,18 +84,17 @@
}
}
$: {
if (originalLyrics && originalLyrics.scripts) {
lyricExists = true;
lyricLines = originalLyrics.scripts!;
}
}
$: {
if (lyricComponents.length > 0) {
$effect(() => {
if (!originalLyrics || !originalLyrics.scripts) return;
lyricLines = originalLyrics.scripts!;
});
let initialized = $state(false);
$effect(() => {
if (lyricComponents.length > 0 && !initialized) {
initLyricComponents();
initialized = true;
}
}
});
function handleScroll(deltaY: number) {
for (let i = 0; i < lyricElements.length; i++) {
@ -154,52 +149,50 @@
inertiaScroll();
}
$: {
if (lyricsContainer && !scrollEventAdded) {
// Wheel event for desktop
lyricsContainer.addEventListener(
'wheel',
(e) => {
e.preventDefault();
const deltaY = e.deltaY;
handleScroll(deltaY);
},
{ passive: false }
);
$effect(() => {
if (!lyricsContainer || scrollEventAdded) return;
// Wheel event for desktop
lyricsContainer.addEventListener(
'wheel',
(e) => {
e.preventDefault();
const deltaY = e.deltaY;
handleScroll(deltaY);
},
{ passive: false }
);
// Touch events for mobile
lyricsContainer.addEventListener('touchstart', handleTouchStart, { passive: true });
lyricsContainer.addEventListener('touchmove', handleTouchMove, { passive: false });
lyricsContainer.addEventListener('touchend', handleTouchEnd, { passive: true });
// Touch events for mobile
lyricsContainer.addEventListener('touchstart', handleTouchStart, { passive: true });
lyricsContainer.addEventListener('touchmove', handleTouchMove, { passive: false });
lyricsContainer.addEventListener('touchend', handleTouchEnd, { passive: true });
scrollEventAdded = true;
scrollEventAdded = true;
});
$effect(() => {
if (!lyricsContainer || lyricComponents.length < 0) return;
if (progress >= nextUpdate - 0.5 && !scrolling) {
computeLayout();
}
}
$: {
if (lyricsContainer && lyricComponents.length > 0) {
if (progress >= nextUpdate - 0.5 && !scrolling) {
computeLayout();
}
if (Math.abs(lastProgress - progress) > 0.5) {
scrolling = false;
}
if (lastProgress - progress > 0) {
computeLayout();
nextUpdate = progress;
if (Math.abs(lastProgress - progress) > 0.5) {
scrolling = false;
}
if (lastProgress - progress > 0) {
computeLayout();
nextUpdate = progress;
} else {
const lyricLength = originalLyrics.scripts!.length;
const currentEnd = originalLyrics.scripts![currentLyricIndex].end;
const nextStart = originalLyrics.scripts![Math.min(currentLyricIndex + 1, lyricLength - 1)].start;
if (currentEnd !== nextStart) {
nextUpdate = currentEnd;
} else {
const lyricLength = originalLyrics.scripts!.length;
const currentEnd = originalLyrics.scripts![currentLyricIndex].end;
const nextStart = originalLyrics.scripts![Math.min(currentLyricIndex + 1, lyricLength - 1)].start;
if (currentEnd !== nextStart) {
nextUpdate = currentEnd;
} else {
nextUpdate = nextStart;
}
nextUpdate = nextStart;
}
}
lastProgress = progress;
}
});
// $: {
// for (let i = 0; i < lyricElements.length; i++) {
@ -243,32 +236,14 @@
player.currentTime = originalLyrics.scripts[lyricIndex].start;
player.play();
}
let lastFPSTime = performance.now();
let frameCount = 0;
let fps = 0;
function calculateFPS(t: number) {
// 计算时间差
const deltaTime = t - lastFPSTime;
frameCount ++;
if (frameCount % 5 == 0) {
fps = 1000 / deltaTime;
}
lastFPSTime = t;
// 请求下一帧
requestAnimationFrame(calculateFPS);
}
// 开始检测帧率
requestAnimationFrame(calculateFPS);
</script>
<svelte:window on:keydown={onKeyDown} />
<!--<svelte:window on:keydown={onKeyDown} />-->
{#if debugMode}
<span class="text-white text-lg absolute z-50 px-2 py-0.5 m-2 rounded-3xl bg-white bg-opacity-20 backdrop-blur-lg right-0 font-mono">
{fps.toFixed(1)}fps, progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}
<span
class="text-white text-lg absolute z-50 px-2 py-0.5 m-2 rounded-3xl bg-white bg-opacity-20 backdrop-blur-lg right-0 font-mono">
progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}
</span>
{/if}

View File

@ -18,7 +18,7 @@
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3",
"svelte": "^4.2.19",
"svelte": "^5.2.2",
"svelte-check": "^3.7.1",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",

View File

@ -26,7 +26,7 @@
"postcss": "^8.4.49",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.8",
"svelte": "^4.2.19",
"svelte": "^5.2.2",
"svelte-check": "^3.8.6",
"tailwindcss": "^3.4.15",
"typescript": "^5.6.3",

View File

@ -3,6 +3,8 @@
import getVersion from '@core/utils/getVersion';
import toHumanSize from '@core/utils/humanSize';
import localforage from '@core/utils/storage';
import { goto } from '$app/navigation';
interface Song {
name: string;
singer?: string;
@ -58,7 +60,9 @@
<div>
<ul class="mt-4 relative w-full">
{#each idList as id}
<a class="!no-underline !text-black dark:!text-white" href={`/play/${id}`}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="!no-underline !text-black dark:!text-white" onclick={() => goto(`/play/${id}`)}>
<li
class="relative my-4 p-4 duration-150 bg-zinc-200 hover:bg-zinc-300 dark:bg-zinc-700 dark:hover:bg-zinc-600 rounded-lg"
>
@ -73,7 +77,7 @@
/>
{/if}
</li>
</a>
</div>
{/each}
</ul>
</div>
@ -83,7 +87,7 @@
</p>
<a href="/import">导入音乐</a> <br />
<button
on:click={() => window.confirm('确定要删除本地数据库中所有内容吗?') && clear()}
onclick={() => window.confirm('确定要删除本地数据库中所有内容吗?') && clear()}
class="text-white bg-red-500 px-4 py-2 mt-4 rounded-md">一键清除</button
>
<h2 class="mt-4"><a href="/database/">音乐数据库</a></h2>

View File

@ -87,12 +87,9 @@
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 计算新的宽度和高度确保宽度至少为1200px
let newWidth = img.width;
let newHeight = img.height;
console.log(newWidth)
if (newWidth < 1200) {
newWidth = 1200;
newHeight = (img.height * 1200) / img.width;
@ -101,14 +98,12 @@
canvas.width = newWidth;
canvas.height = newHeight;
// 绘制放大后的图片到canvas
ctx!.drawImage(img, 0, 0, newWidth, newHeight);
// 将canvas内容转换为Blob
canvas.toBlob(function (blob) {
const path = URL.createObjectURL(blob!);
coverPath.set(path);
}, 'image/jpeg'); // 你可以根据需要更改图片格式
}, 'image/jpeg');
prepared.push('cover');
};