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", "postcss": "^8.4.38",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3", "prettier-plugin-svelte": "^3.2.3",
"svelte": "^4.2.19", "svelte": "^5.2.2",
"svelte-check": "^3.7.1", "svelte-check": "^3.7.1",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"vite-plugin-wasm": "^3.3.0", "vite-plugin-wasm": "^3.3.0",

View File

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { type ScriptItem, type LyricData } from '@alikia/aqualyrics'; import { type LyricData, type ScriptItem } from '@alikia/aqualyrics';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import LyricLine from './lyricLine.svelte'; import LyricLine from './lyricLine.svelte';
import createLyricsSearcher from '@core/lyrics/lyricSearcher'; import createLyricsSearcher from '@core/lyrics/lyricSearcher';
@ -15,38 +15,34 @@
document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden';
// Props // Props
export let originalLyrics: LyricData; let { originalLyrics, progress, player } : {
export let progress: number; originalLyrics: LyricData,
export let player: HTMLAudioElement | null; progress: number,
player: HTMLAudioElement | null
} = $props();
// States // States
let lyricLines: ScriptItem[] = []; let lyricLines: ScriptItem[] = $state([]);
let lyricExists = false; let lyricsContainer: HTMLDivElement | null = $state(null);
let lyricsContainer: HTMLDivElement | null; let debugMode = $state(false);
let debugMode = false; let nextUpdate = $state(0);
let nextUpdate = 0; let lastProgress = $state(0);
let lastProgress = 0; let showTranslation = $state(false);
let showTranslation = false; let scrollEventAdded = $state(false);
let scrollEventAdded = false; let scrolling = $state(false);
let scrolling = false; let scrollingTimeout: Timer | null = $state(null);
let scrollingTimeout: Timer; let lastY: number = $state(0); // For tracking touch movements
let lastY: number; // For tracking touch movements let lastTime: number = $state(0); // For tracking time between touch moves
let lastTime: number; // For tracking time between touch moves let velocityY = $state(0); // Vertical scroll velocity
let velocityY = 0; // Vertical scroll velocity let inertiaFrame: number = $state(0); // For storing the requestAnimationFrame reference
let inertiaFrame: number; // For storing the requestAnimationFrame reference
// References to lyric elements // References to lyric elements
let lyricElements: HTMLDivElement[] = []; let lyricElements: HTMLDivElement[] = $state([]);
let lyricComponents: LyricLine[] = []; let lyricComponents: LyricLine[] = $state([]);
let lyricTopList: number[] = []; let lyricTopList: number[] = $state([]);
let currentLyricIndex: number; let getLyricIndex = $derived(createLyricsSearcher(originalLyrics));
let currentLyricIndex = $derived(getLyricIndex(progress));
$: getLyricIndex = createLyricsSearcher(originalLyrics);
$: {
currentLyricIndex = getLyricIndex(progress);
}
function initLyricComponents() { function initLyricComponents() {
initLyricTopList(); initLyricTopList();
@ -88,18 +84,17 @@
} }
} }
$: { $effect(() => {
if (originalLyrics && originalLyrics.scripts) { if (!originalLyrics || !originalLyrics.scripts) return;
lyricExists = true; lyricLines = originalLyrics.scripts!;
lyricLines = originalLyrics.scripts!; });
} let initialized = $state(false);
} $effect(() => {
if (lyricComponents.length > 0 && !initialized) {
$: {
if (lyricComponents.length > 0) {
initLyricComponents(); initLyricComponents();
initialized = true;
} }
} });
function handleScroll(deltaY: number) { function handleScroll(deltaY: number) {
for (let i = 0; i < lyricElements.length; i++) { for (let i = 0; i < lyricElements.length; i++) {
@ -154,52 +149,50 @@
inertiaScroll(); inertiaScroll();
} }
$: { $effect(() => {
if (lyricsContainer && !scrollEventAdded) { if (!lyricsContainer || scrollEventAdded) return;
// Wheel event for desktop // Wheel event for desktop
lyricsContainer.addEventListener( lyricsContainer.addEventListener(
'wheel', 'wheel',
(e) => { (e) => {
e.preventDefault(); e.preventDefault();
const deltaY = e.deltaY; const deltaY = e.deltaY;
handleScroll(deltaY); handleScroll(deltaY);
}, },
{ passive: false } { passive: false }
); );
// Touch events for mobile // Touch events for mobile
lyricsContainer.addEventListener('touchstart', handleTouchStart, { passive: true }); lyricsContainer.addEventListener('touchstart', handleTouchStart, { passive: true });
lyricsContainer.addEventListener('touchmove', handleTouchMove, { passive: false }); lyricsContainer.addEventListener('touchmove', handleTouchMove, { passive: false });
lyricsContainer.addEventListener('touchend', handleTouchEnd, { passive: true }); 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 (Math.abs(lastProgress - progress) > 0.5) {
scrolling = false;
$: { }
if (lyricsContainer && lyricComponents.length > 0) { if (lastProgress - progress > 0) {
if (progress >= nextUpdate - 0.5 && !scrolling) { computeLayout();
computeLayout(); nextUpdate = progress;
} } else {
if (Math.abs(lastProgress - progress) > 0.5) { const lyricLength = originalLyrics.scripts!.length;
scrolling = false; const currentEnd = originalLyrics.scripts![currentLyricIndex].end;
} const nextStart = originalLyrics.scripts![Math.min(currentLyricIndex + 1, lyricLength - 1)].start;
if (lastProgress - progress > 0) { if (currentEnd !== nextStart) {
computeLayout(); nextUpdate = currentEnd;
nextUpdate = progress;
} else { } else {
const lyricLength = originalLyrics.scripts!.length; nextUpdate = nextStart;
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;
}
} }
} }
lastProgress = progress; lastProgress = progress;
} });
// $: { // $: {
// for (let i = 0; i < lyricElements.length; i++) { // for (let i = 0; i < lyricElements.length; i++) {
@ -243,32 +236,14 @@
player.currentTime = originalLyrics.scripts[lyricIndex].start; player.currentTime = originalLyrics.scripts[lyricIndex].start;
player.play(); 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> </script>
<svelte:window on:keydown={onKeyDown} /> <!--<svelte:window on:keydown={onKeyDown} />-->
{#if debugMode} {#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"> <span
{fps.toFixed(1)}fps, progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex} 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> </span>
{/if} {/if}

View File

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

View File

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

View File

@ -3,6 +3,8 @@
import getVersion from '@core/utils/getVersion'; import getVersion from '@core/utils/getVersion';
import toHumanSize from '@core/utils/humanSize'; import toHumanSize from '@core/utils/humanSize';
import localforage from '@core/utils/storage'; import localforage from '@core/utils/storage';
import { goto } from '$app/navigation';
interface Song { interface Song {
name: string; name: string;
singer?: string; singer?: string;
@ -58,7 +60,9 @@
<div> <div>
<ul class="mt-4 relative w-full"> <ul class="mt-4 relative w-full">
{#each idList as id} {#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 <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" 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} {/if}
</li> </li>
</a> </div>
{/each} {/each}
</ul> </ul>
</div> </div>
@ -83,7 +87,7 @@
</p> </p>
<a href="/import">导入音乐</a> <br /> <a href="/import">导入音乐</a> <br />
<button <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 class="text-white bg-red-500 px-4 py-2 mt-4 rounded-md">一键清除</button
> >
<h2 class="mt-4"><a href="/database/">音乐数据库</a></h2> <h2 class="mt-4"><a href="/database/">音乐数据库</a></h2>

View File

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