import { describe, expect, it } from 'vitest'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { argumentosDeEscucha, argumentosDeOnda, aSlug, claveCanonica, claveDeEscucha, claveDeOnda, comoDuracion, enLaBandeja, recorrerMasters, resumirPicos } from './medios.mjs'; describe('claveCanonica', () => { it('agrupa por disco y numera como la pista', () => { const clave = claveCanonica( { album: 'dos-orillas', numero: 3 }, 'media-verdad', 'subidas/loquesea.mp3', '' ); expect(clave).toBe('dos-orillas/03-media-verdad.mp3'); }); it('manda a singles lo que no tiene disco', () => { // Un tema suelto no ocupa ninguna posición, así que no lleva número. const clave = claveCanonica({}, 'dorina', 'subidas/Senza Paura - Dorina.mp3', ''); expect(clave).toBe('singles/dorina.mp3'); }); it('distingue las alternativas musicales del arreglo principal', () => { const clave = claveCanonica( { album: 'como-si-nada', numero: 1 }, 'como-si-nada', 'subidas/orq.mp3', '-orquestal' ); expect(clave).toBe('como-si-nada/01-como-si-nada-orquestal.mp3'); }); it('conserva la extensión, en minúsculas', () => { expect(claveCanonica({}, 'dorina', 'subidas/DORINA.WAV', '')).toBe('singles/dorina.wav'); }); it('no numera un single aunque traiga número', () => { // El número solo tiene sentido dentro de un disco; el esquema lo ignora, // y el nombre del archivo tiene que decir lo mismo. expect(claveCanonica({ numero: 4 }, 'dorina', 'subidas/x.mp3', '')).toBe('singles/dorina.mp3'); }); }); describe('enLaBandeja', () => { it('reconoce lo que acaba de subir el panel', () => { expect(enLaBandeja('subidas/Senza Paura - Dorina.mp3')).toBe(true); // El panel puede escribir la clave con barra inicial. expect(enLaBandeja('/subidas/dorina.mp3')).toBe(true); }); it('deja en paz lo que ya está colocado', () => { expect(enLaBandeja('singles/dorina.mp3')).toBe(false); // Un disco que se llamara así no debe confundirse con la bandeja. expect(enLaBandeja('subidas-de-tono/01-tema.mp3')).toBe(false); }); }); describe('comoDuracion', () => { it('escribe m:ss como lo espera el esquema', () => { expect(comoDuracion(277.752)).toBe('4:38'); expect(comoDuracion(65)).toBe('1:05'); expect(comoDuracion(600)).toBe('10:00'); }); }); describe('aSlug', () => { it('coincide con el del esquema', () => { expect(aSlug('Vals criollo peruano')).toBe('vals-criollo-peruano'); expect(aSlug('Versión orquestal')).toBe('version-orquestal'); }); }); describe('escucha protegida', () => { it('incluye los másteres importados sin Markdown y omite la bandeja', () => { const raiz = fs.mkdtempSync(path.join(os.tmpdir(), 'senzapaura-medios-')); try { fs.mkdirSync(path.join(raiz, 'album'), { recursive: true }); fs.mkdirSync(path.join(raiz, 'subidas'), { recursive: true }); fs.writeFileSync(path.join(raiz, 'album', '01-tema.mp3'), 'master'); fs.writeFileSync(path.join(raiz, 'album', 'nota.txt'), 'no es audio'); fs.writeFileSync(path.join(raiz, 'subidas', 'pendiente.mp3'), 'pendiente'); expect(recorrerMasters(raiz).map((p) => path.relative(raiz, p))).toEqual([ path.join('album', '01-tema.mp3') ]); } finally { fs.rmSync(raiz, { recursive: true, force: true }); } }); it('conserva la jerarquía y normaliza el formato', () => { expect(claveDeEscucha('disco/01-tema.wav')).toBe('disco/01-tema.mp3'); }); it('codifica la canción completa a menor calidad', () => { const args = argumentosDeEscucha( 'media/audio/singles/dorina.wav', 'media/escucha/singles/dorina.mp3' ); expect(args).not.toContain('-ss'); expect(args).not.toContain('-t'); expect(args).toContain('libmp3lame'); expect(args).toContain('96k'); expect(args.at(-1)).toBe('media/escucha/singles/dorina.mp3'); }); }); describe('forma de onda', () => { it('conserva la jerarquía y cambia el audio por JSON', () => { expect(claveDeOnda('disco/01-tema.wav')).toBe('disco/01-tema.json'); }); it('decodifica a PCM mono ligero', () => { const args = argumentosDeOnda('media/escucha/disco/01-tema.mp3'); expect(args).toContain('1'); expect(args).toContain('8000'); expect(args).toContain('s16le'); expect(args.at(-1)).toBe('pipe:1'); }); it('resume amplitudes, conserva silencios y normaliza el nivel', () => { const pcm = Buffer.alloc(800); // Cuatro bloques: silencio, pasaje suave y dos pasajes fuertes. for (let i = 100; i < 200; i++) pcm.writeInt16LE(1_000, i * 2); for (let i = 200; i < 400; i++) pcm.writeInt16LE(i % 2 ? 10_000 : -10_000, i * 2); const picos = resumirPicos(pcm, 4); expect(picos).toHaveLength(4); expect(picos[0]).toBe(0); expect(picos[1]).toBeGreaterThan(0); expect(picos[1]).toBeLessThan(picos[2]); expect(picos[2]).toBe(255); expect(picos[3]).toBe(255); }); it('devuelve la anchura pedida incluso para un audio vacío', () => { expect(resumirPicos(Buffer.alloc(0), 3)).toEqual([0, 0, 0]); }); });