diff --git a/frontend/src/lib/components/player/SeekBar.svelte b/frontend/src/lib/components/player/SeekBar.svelte
index deebf69..1b5fcc5 100644
--- a/frontend/src/lib/components/player/SeekBar.svelte
+++ b/frontend/src/lib/components/player/SeekBar.svelte
@@ -19,11 +19,11 @@
class="group relative h-1.5 flex-1 cursor-pointer rounded-full bg-[var(--mf-track)] transition-[height] hover:h-2"
>
diff --git a/frontend/src/lib/player/player.svelte.ts b/frontend/src/lib/player/player.svelte.ts
index 0601fe7..5e701fc 100644
--- a/frontend/src/lib/player/player.svelte.ts
+++ b/frontend/src/lib/player/player.svelte.ts
@@ -61,6 +61,7 @@ class PlayerState {
#audio: HTMLAudioElement | null = null;
#loadToken = 0;
#accentCache = new Map();
+ #rafId: number | null = null;
current = $derived(this.tracks.find((t) => t.id === this.currentId) ?? EMPTY);
accent = $derived(this.accentColor ?? accentForHue(this.current.hue));
@@ -79,15 +80,22 @@ class PlayerState {
const audio = new Audio();
audio.preload = 'auto';
audio.volume = this.volume / 100;
- audio.addEventListener('timeupdate', () => {
- this.progress = audio.currentTime;
- });
audio.addEventListener('durationchange', () => this.#syncDuration(audio.duration));
audio.addEventListener('loadedmetadata', () => this.#syncDuration(audio.duration));
- audio.addEventListener('play', () => (this.playing = true));
- audio.addEventListener('pause', () => (this.playing = false));
- audio.addEventListener('ended', () => this.next());
+ audio.addEventListener('play', () => {
+ this.playing = true;
+ this.#startProgressLoop();
+ });
+ audio.addEventListener('pause', () => {
+ this.playing = false;
+ this.#stopProgressLoop();
+ });
+ audio.addEventListener('ended', () => {
+ this.#stopProgressLoop();
+ this.next();
+ });
audio.addEventListener('error', () => {
+ this.#stopProgressLoop();
this.loading = false;
this.playing = false;
this.error = 'No se pudo reproducir la pista.';
@@ -96,6 +104,24 @@ class PlayerState {
return audio;
}
+ #tickProgress = () => {
+ const audio = this.#audio;
+ if (!audio) return;
+ this.progress = audio.currentTime;
+ this.#rafId = requestAnimationFrame(this.#tickProgress);
+ };
+
+ #startProgressLoop() {
+ if (this.#rafId !== null) return;
+ this.#rafId = requestAnimationFrame(this.#tickProgress);
+ }
+
+ #stopProgressLoop() {
+ if (this.#rafId === null) return;
+ cancelAnimationFrame(this.#rafId);
+ this.#rafId = null;
+ }
+
#syncDuration(value: number) {
if (!Number.isFinite(value) || value <= 0) return;
const id = this.currentId;