Fix share page progress bar updates.

Track playback position locally so the /play progress slider and time display advance reliably, including pause/resume, scrubbing, and end-of-track behavior.
This commit is contained in:
b1rdmania
2025-12-26 19:32:55 +00:00
parent 7deb7bd4d9
commit 5e90b9e5d5
+30 -5
View File
@@ -111,6 +111,8 @@ async function main(): Promise<void> {
let progressInterval: number | null = null;
let durationSec = 0;
let resumeProgress = 0;
let playStartMs: number | null = null; // performance.now() at audio time=0 (minus offset)
let playOffsetSec = 0; // last known playback position in seconds
try {
const buf = await midiService.fetchMIDI(u);
@@ -133,16 +135,25 @@ async function main(): Promise<void> {
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
function getLocalCurrentTime(): number {
if (!durationSec) return 0;
if (!isPlaying || playStartMs === null) return Math.max(0, Math.min(durationSec, playOffsetSec));
const t = (performance.now() - playStartMs) / 1000;
return Math.max(0, Math.min(durationSec, t));
}
function updateProgress(): void {
const progress = motifEngine.getProgress();
const current = motifEngine.getCurrentTime();
const current = getLocalCurrentTime();
const progress = durationSec > 0 ? current / durationSec : 0;
progressBar.value = (progress * 100).toString();
progressFill.style.width = `${progress * 100}%`;
currentTimeEl.textContent = formatTime(current);
// Auto-pause at end
if (durationSec > 0 && progress >= 0.999) {
if (durationSec > 0 && current >= durationSec - 0.05) {
resumeProgress = 0;
playOffsetSec = 0;
playStartMs = null;
motifEngine.stop();
setUiPlaying(false);
stopProgressUpdates();
@@ -174,14 +185,17 @@ async function main(): Promise<void> {
if (!isGenerated) {
resumeProgress = p;
progressFill.style.width = `${p * 100}%`;
currentTimeEl.textContent = formatTime(p * Math.max(0, durationSec));
currentTimeEl.textContent = durationSec > 0 ? formatTime(p * durationSec) : '0:00';
return;
}
if (isPlaying) {
playOffsetSec = p * durationSec;
playStartMs = performance.now() - playOffsetSec * 1000;
motifEngine.seek(p);
updateProgress();
} else {
resumeProgress = p;
playOffsetSec = p * durationSec;
progressFill.style.width = `${p * 100}%`;
currentTimeEl.textContent = formatTime(p * durationSec);
}
@@ -194,7 +208,10 @@ async function main(): Promise<void> {
// Pause (implemented as stop + remembered position)
if (isPlaying) {
resumeProgress = motifEngine.getProgress();
const current = getLocalCurrentTime();
resumeProgress = durationSec > 0 ? current / durationSec : 0;
playOffsetSec = current;
playStartMs = null;
motifEngine.stop();
setUiPlaying(false);
stopProgressUpdates();
@@ -215,15 +232,23 @@ async function main(): Promise<void> {
durationEl.textContent = formatTime(durationSec);
progressContainer.style.display = 'block';
isGenerated = true;
// If user scrubbed before play, carry that into seconds now that we know duration.
playOffsetSec = resumeProgress * durationSec;
}
setUiPlaying(true);
await motifEngine.play();
// Seek to remembered position (for pause/resume and scrub-before-play)
if (durationSec > 0 && playOffsetSec > 0) {
resumeProgress = playOffsetSec / durationSec;
}
if (resumeProgress > 0) motifEngine.seek(resumeProgress);
// Local progress tracking
playStartMs = performance.now() - playOffsetSec * 1000;
startProgressUpdates();
} catch (e) {
setUiPlaying(false);
playStartMs = null;
stopProgressUpdates();
}
});