diff --git a/package.json b/package.json
index 9ea2937..eb179b2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "aquavox",
- "version": "2.9.1",
+ "version": "2.9.2",
"private": false,
"module": "index.ts",
"type": "module",
diff --git a/packages/core/components/lyrics/lyricLine.svelte b/packages/core/components/lyrics/lyricLine.svelte
index e521e62..9556d2a 100644
--- a/packages/core/components/lyrics/lyricLine.svelte
+++ b/packages/core/components/lyrics/lyricLine.svelte
@@ -3,9 +3,11 @@
import type { LyricWord, ScriptItem } from '@core/lyrics/type';
import type { LyricPos } from './type';
import type { Spring } from '@core/graphics/spring/spring';
+ import userAdjustingProgress from '@core/state/userAdjustingProgress';
const viewportWidth = document.documentElement.clientWidth;
const blurRatio = viewportWidth > 640 ? 1.2 : 1.4;
+ const scrollDuration = 0.2;
export let line: ScriptItem;
export let index: number;
@@ -23,6 +25,10 @@
let positionY: number = 0;
let blur = 0;
let stopped = false;
+ let we_are_scrolling = false;
+ let scrollTarget: number | undefined = undefined;
+ let scrollFrom: number | undefined = undefined;
+ let scrollingStartTime: number | undefined = undefined;
let lastPosX: number | undefined = undefined;
let lastPosY: number | undefined = undefined;
let lastUpdateY: number | undefined = undefined;
@@ -39,7 +45,7 @@
time = (new Date().getTime() - lastUpdateY) / 1000;
springY.update(time);
positionY = springY.getCurrentPosition();
- if (!springY.arrived() && !stopped) {
+ if (!springY.arrived() && !stopped && !we_are_scrolling) {
requestAnimationFrame(updateY);
}
lastUpdateY = new Date().getTime();
@@ -87,6 +93,7 @@
blurRadius = Math.min(offset * blurRatio, 16);
}
if (scrolling) blurRadius = 0;
+ if ($userAdjustingProgress) blurRadius = 0;
blur = blurRadius
}
}
@@ -107,6 +114,26 @@
lastPosY = pos.y;
};
+ function updateScroll(timestamp: number) {
+ const elapsedTime = (new Date().getTime() - scrollingStartTime!) / 1000;
+ const percentage = Math.min(elapsedTime / scrollDuration, 1);
+ positionY = scrollFrom! + (scrollTarget! - scrollFrom!) * percentage;
+ if (percentage < 1) {
+ requestAnimationFrame(updateScroll);
+ }
+ }
+
+ export const scrollTo = (targetY: number) => {
+ scrollFrom = positionY;
+ scrollTarget = targetY;
+ scrollingStartTime = new Date().getTime();
+ we_are_scrolling = true;
+ requestAnimationFrame(updateScroll);
+ springY!.setPosition(targetY);
+ we_are_scrolling = false;
+ };
+
+
export const getInfo = () => {
return {
x: positionX,
diff --git a/packages/core/components/lyrics/newLyrics.svelte b/packages/core/components/lyrics/newLyrics.svelte
index ce8694b..c3539cf 100644
--- a/packages/core/components/lyrics/newLyrics.svelte
+++ b/packages/core/components/lyrics/newLyrics.svelte
@@ -3,7 +3,7 @@
import { onMount } from 'svelte';
import LyricLine from './lyricLine.svelte';
import createLyricsSearcher from '@core/lyrics/lyricSearcher';
- import { createRule } from 'eslint-plugin-svelte/lib/utils';
+ import userAdjustingProgress from '@core/state/userAdjustingProgress';
// constants
const viewportHeight = document.documentElement.clientHeight;
@@ -48,7 +48,8 @@
function initLyricComponents() {
initLyricTopList();
for (let i = 0; i < lyricComponents.length; i++) {
- lyricComponents[i].init({ x: 0, y: lyricTopList[i] });
+ const currentLyric = lyricComponents[i];
+ currentLyric.init({ x: 0, y: lyricTopList[i] });
}
}
@@ -85,6 +86,16 @@
}
}
+ function seekForward() {
+ if (!originalLyrics.scripts) return;
+ const relativeOrigin = lyricTopList[currentLyricIndex] - currentLyricTop;
+ for (let i = 0; i < lyricElements.length; i++) {
+ const currentLyricComponent = lyricComponents[i];
+ currentLyricComponent.scrollTo(lyricTopList[i] - relativeOrigin);
+ }
+ lastSeekForward = new Date().getTime();
+ }
+
$effect(() => {
if (!originalLyrics || !originalLyrics.scripts) return;
lyricLines = originalLyrics.scripts!;
@@ -171,69 +182,40 @@
scrollEventAdded = true;
});
- let lastTriggered = $state(0);
let lastEventLyricIndex = $state(0);
let lastEventProgress = $state(0);
+ let lastSeekForward = $state(0);
$effect(() => {
- const progressDelta = progress - lastEventProgress;
- const deltaInRange = 0 <= progressDelta && progressDelta <= 0.15;
- const deltaTooBig = progressDelta > 0.15;
- const deltaIsNegative = progressDelta < 0;
- const lyricChanged = currentLyricIndex !== lastEventLyricIndex;
- const lyricIndexDeltaTooBig = Math.abs(currentLyricIndex - lastEventLyricIndex) > 1;
- if (lyricChanged && !lyricIndexDeltaTooBig && deltaInRange) {
- console.log("Event: regular move");
- }
- else if (deltaTooBig && lyricChanged) {
- console.log("Event: seek forward");
- }
- else if (deltaIsNegative && lyricChanged) {
- console.log("Event: seek backward");
- }
- lastEventLyricIndex = currentLyricIndex;
- lastEventProgress = progress;
- });
+ const progressDelta = progress - lastEventProgress;
+ const deltaInRange = 0 <= progressDelta && progressDelta <= 0.15;
+ const deltaTooBig = progressDelta > 0.15;
+ const deltaIsNegative = progressDelta < 0;
+ const lyricChanged = currentLyricIndex !== lastEventLyricIndex;
+ const lyricIndexDeltaTooBig = Math.abs(currentLyricIndex - lastEventLyricIndex) > 1;
- $effect(() => {
- if (!lyricsContainer || lyricComponents.length < 0) return;
- if (progress >= nextUpdate - 0.5 && !scrolling) {
+ lastEventLyricIndex = currentLyricIndex;
+ lastEventProgress = progress;
+ if (!lyricChanged) return;
+ if (!lyricIndexDeltaTooBig && deltaInRange) {
+ console.log("Event: regular move");
+ console.log(new Date().getTime() , lastSeekForward);
computeLayout();
}
- 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 {
- nextUpdate = nextStart;
+ else if ($userAdjustingProgress) {
+ if (deltaTooBig && lyricChanged) {
+ console.log("Event: seek forward");
+ seekForward();
+ } else if (deltaIsNegative && lyricChanged) {
+ console.log("Event: seek backward");
+ seekForward();
}
}
- lastProgress = progress;
+ else {
+ console.log("Event: regular move");
+ computeLayout();
+ }
});
- // $: {
- // for (let i = 0; i < lyricElements.length; i++) {
- // const s = originalLyrics.scripts![i].start;
- // const t = originalLyrics.scripts![i].end;
- // // Explain:
- // // The `currentLyricIndex` is also used for locating & layout computing,
- // // so when the current progress is in the interlude between two lyrics,
- // // `currentLyricIndex` still needs to have a valid value to ensure that
- // // the style and scrolling position are calculated correctly.
- // // But in that situation, the “current lyric index” does not exist.
- // const isCurrent = i == currentLyricIndex && s <= progress && progress <= t;
- // const currentLyricComponent = lyricComponents[i];
- // currentLyricComponent.setCurrent(isCurrent);
- // }
- // }
-
onMount(() => {
// Initialize
if (localStorage.getItem('debugMode') == null) {
@@ -258,16 +240,17 @@
function lyricClick(lyricIndex: number) {
if (player === null || originalLyrics.scripts === undefined) return;
player.currentTime = originalLyrics.scripts[lyricIndex].start;
+ userAdjustingProgress.set(false);
player.play();
}
-
+
{#if debugMode}
- progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}
+ progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}, uap: {$userAdjustingProgress}
{/if}