From 29e8789312b57b0551296e04f8de93f4f080c906 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 10 Sep 2026 22:30:35 +0200 Subject: [PATCH] Keep waveform out of compact player --- e2e/reproductor.e2e.ts | 19 -- .../components/player/BarraProgreso.svelte | 237 ++---------------- .../components/player/BarraReproductor.svelte | 10 +- src/lib/player/pista.ts | 2 - src/lib/player/player.svelte.ts | 2 - 5 files changed, 22 insertions(+), 248 deletions(-) diff --git a/e2e/reproductor.e2e.ts b/e2e/reproductor.e2e.ts index 02793b0..a4ef941 100644 --- a/e2e/reproductor.e2e.ts +++ b/e2e/reproductor.e2e.ts @@ -68,23 +68,4 @@ test.describe('Reproductor', () => { await cola.getByRole('button', { name: /El último tren/ }).click(); await expect(temaEnBarra(page, 'el-ultimo-tren')).toBeVisible(); }); - - test('dibuja la onda precalculada sin descargar otro audio', async ({ page }) => { - await page.goto('/albumes/cupido-sin-flechas'); - - const respuesta = page.waitForResponse((r) => - new URL(r.url()).pathname.endsWith( - '/ondas/cupido-sin-flechas/01-amame-esta-noche-nada-mas.json' - ) - ); - await page.getByRole('button', { name: 'Reproducir', exact: true }).first().click(); - - const onda = page.getByRole('region', { name: 'Reproductor' }).locator('[data-forma-onda]'); - await expect(onda).toBeVisible(); - expect((await respuesta).status()).toBe(200); - // Un único trazo por estado (pendiente y escuchado), no cientos de nodos - // que hubiera que actualizar en cada cuadro de la reproducción. - await expect(onda.locator('path')).toHaveCount(2); - expect((await onda.locator('path').first().getAttribute('d'))?.match(/M/g)).toHaveLength(128); - }); }); diff --git a/src/lib/components/player/BarraProgreso.svelte b/src/lib/components/player/BarraProgreso.svelte index e6e02bb..66fb522 100644 --- a/src/lib/components/player/BarraProgreso.svelte +++ b/src/lib/components/player/BarraProgreso.svelte @@ -15,64 +15,18 @@ tiempo: number; duracion: number; onbuscar: (segundos: number) => void; - /** JSON de amplitudes precalculadas. Sin él queda el carril convencional. */ - onda?: string; /** Desactiva la barra cuando no hay nada cargado. */ activa?: boolean; } - let { tiempo, duracion, onbuscar, onda, activa = true }: Props = $props(); + let { tiempo, duracion, onbuscar, activa = true }: Props = $props(); let arrastrando = $state(false); let valorLocal = $state(0); - let picos = $state([]); const maximo = $derived(duracion > 0 ? duracion : 0); const mostrado = $derived(arrastrando ? valorLocal : Math.min(tiempo, maximo)); const porcentaje = $derived(maximo > 0 ? (mostrado / maximo) * 100 : 0); - const anchoOnda = $derived(Math.max(1, picos.length * 2)); - const trazo = $derived( - picos - .map((pico, i) => { - const amplitud = Math.max(4, Math.round((pico / 255) * 88)); - const arriba = (100 - amplitud) / 2; - return `M${i * 2 + 1} ${arriba}V${arriba + amplitud}`; - }) - .join('') - ); - - /** Un archivo mal formado no debe romper el control de reproducción. */ - function leerPicos(datos: unknown): number[] { - if (!datos || typeof datos !== 'object') return []; - const candidatos = (datos as { picos?: unknown }).picos; - if (!Array.isArray(candidatos) || candidatos.length === 0 || candidatos.length > 512) return []; - return candidatos.every( - (valor) => Number.isInteger(valor) && Number(valor) >= 0 && Number(valor) <= 255 - ) - ? (candidatos as number[]) - : []; - } - - /* - * Se carga solo la onda de la pista actual. Cambiar de tema cancela la - * petición anterior y el caché HTTP hace que volver a ella no cueste nada. - * El fallo es silencioso porque debajo queda el input de rango de siempre. - */ - $effect(() => { - const fuente = onda; - picos = []; - if (!fuente) return; - - const controlador = new AbortController(); - void fetch(fuente, { signal: controlador.signal, cache: 'force-cache' }) - .then((respuesta) => (respuesta.ok ? respuesta.json() : undefined)) - .then((datos) => { - if (!controlador.signal.aborted) picos = leerPicos(datos); - }) - .catch(() => {}); - - return () => controlador.abort(); - }); function alMover(evento: Event & { currentTarget: HTMLInputElement }) { arrastrando = true; @@ -88,39 +42,20 @@
-
- {#if picos.length > 0} - - {:else if onda} - - - {/if} - - -
+
@@ -141,77 +76,14 @@ text-align: center; } - .carril { - position: relative; - flex: 1; - min-width: 0; - } - - .carril.con-onda { - height: 2.5rem; - padding: 0.2rem 0.35rem; - border: 1px solid var(--c-border); - border-radius: 0.7rem; - overflow: hidden; - } - - .carril.con-onda:focus-within { - border-color: var(--c-focus); - box-shadow: 0 0 0 2px color-mix(in oklab, var(--c-focus) 45%, transparent); - } - - .carril.apagado { - opacity: 0.5; - } - - .onda { - display: block; - width: 100%; - height: 100%; - overflow: visible; - } - - .onda path { - fill: none; - stroke-width: 1.35; - stroke-linecap: round; - vector-effect: non-scaling-stroke; - } - - .onda-pendiente { - stroke: color-mix(in oklab, var(--c-text-muted) 88%, transparent); - } - - .onda-escuchada { - stroke: var(--c-accent); - clip-path: inset(0 calc(100% - var(--avance)) 0 0); - } - - .reserva { - position: absolute; - inset-inline: 0.35rem; - top: 50%; - height: 2px; - background: var(--c-bg-sunken); - transform: translateY(-50%); - } - .pista { - display: block; - width: 100%; + flex: 1; appearance: none; height: 1rem; background: transparent; cursor: pointer; } - .con-onda .pista { - position: absolute; - inset: 0; - height: 100%; - margin: 0; - } - .pista:disabled { cursor: default; opacity: 0.5; @@ -222,7 +94,7 @@ * unica forma de tener "parte reproducida" en un input range sin duplicar * elementos. */ - .carril:not(.con-onda) .pista::-webkit-slider-runnable-track { + .pista::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; /* @@ -238,7 +110,7 @@ ); } - .carril:not(.con-onda) .pista::-moz-range-track { + .pista::-moz-range-track { height: 4px; border-radius: 2px; /* @@ -254,7 +126,7 @@ ); } - .carril:not(.con-onda) .pista::-webkit-slider-thumb { + .pista::-webkit-slider-thumb { appearance: none; width: 12px; height: 12px; @@ -264,80 +136,11 @@ border: none; } - .carril:not(.con-onda) .pista::-moz-range-thumb { + .pista::-moz-range-thumb { width: 12px; height: 12px; border-radius: 50%; background: var(--c-accent); border: none; } - - /* - * El input sigue cubriendo toda la onda —teclado, ratón y tacto continúan - * siendo nativos—, pero su carril y su pulgar no tapan el dibujo. - */ - .con-onda .pista::-webkit-slider-runnable-track { - height: 100%; - background: transparent; - } - - .con-onda .pista::-moz-range-track { - height: 100%; - background: transparent; - } - - .con-onda .pista::-webkit-slider-thumb { - appearance: none; - width: 0.8rem; - height: 100%; - margin: 0; - background: transparent; - border: none; - } - - .con-onda .pista::-moz-range-thumb { - width: 0.8rem; - height: 100%; - background: transparent; - border: none; - } - - .pista:focus-visible { - outline: 2px solid var(--c-focus); - outline-offset: 2px; - border-radius: var(--radius-boton); - } - - .con-onda .pista:focus-visible { - /* El foco lo pinta el contenedor; aquí quedaría recortado por la onda. */ - outline: none; - } - - @media (max-width: 48rem) { - .progreso { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--sp-1) var(--sp-2); - } - - .tiempo { - grid-row: 1; - min-width: 0; - text-align: left; - } - - .tiempo:last-child { - grid-column: 2; - text-align: right; - } - - .carril { - grid-column: 1 / -1; - grid-row: 2; - } - - .carril.con-onda { - height: 4rem; - } - } diff --git a/src/lib/components/player/BarraReproductor.svelte b/src/lib/components/player/BarraReproductor.svelte index 61a0064..1e20bd0 100644 --- a/src/lib/components/player/BarraReproductor.svelte +++ b/src/lib/components/player/BarraReproductor.svelte @@ -111,18 +111,13 @@ {/if} diff --git a/src/lib/player/pista.ts b/src/lib/player/pista.ts index b28f8ec..6822cb6 100644 --- a/src/lib/player/pista.ts +++ b/src/lib/player/pista.ts @@ -43,7 +43,6 @@ export function aPista(cancion: Cancion): PistaReproductor { cancionSlug: cancion.slug, titulo: cancion.titulo, audio: cancion.audio ?? '', - onda: cancion.onda, duracion: cancion.duracion, ...contexto(cancion) }; @@ -61,7 +60,6 @@ export function aPistaDeVersion(cancion: Cancion, version: VersionMusical): Pist cancionSlug: cancion.slug, titulo: `${cancion.titulo} · ${version.nombre}`, audio: version.audio ?? '', - onda: version.onda, duracion: version.duracion, ...contexto(cancion) }; diff --git a/src/lib/player/player.svelte.ts b/src/lib/player/player.svelte.ts index 5c44d72..f867141 100644 --- a/src/lib/player/player.svelte.ts +++ b/src/lib/player/player.svelte.ts @@ -33,8 +33,6 @@ export interface PistaReproductor { titulo: string; /** URL pública de la canción completa en calidad de escucha. */ audio: string; - /** Resumen ligero de amplitudes que dibuja el buscador del reproductor. */ - onda?: string; albumTitulo: string; albumSlug: string; portada: string;