import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { after, before, test } from 'node:test'; import { probe } from '../server/media.js'; const hasFfmpeg = (() => { try { execFileSync('ffmpeg', ['-version'], { stdio: 'ignore' }); return true; } catch { return false; } })(); let dir; before(() => { if (!hasFfmpeg) return; dir = fs.mkdtempSync(path.join(os.tmpdir(), 'fdc-media-')); const ffmpeg = (...args) => execFileSync('ffmpeg', ['-v', 'error', '-y', ...args]); ffmpeg('-f', 'lavfi', '-i', 'testsrc=size=320x180:rate=25', '-f', 'lavfi', '-i', 'sine', '-t', '2', '-c:v', 'libx264', '-c:a', 'aac', '-shortest', path.join(dir, 'quer.mp4')); // Wie ein Hochkant-Handyvideo: quer gespeichert, mit Drehung im Dateikopf ffmpeg('-i', path.join(dir, 'quer.mp4'), '-an', '-c', 'copy', '-metadata:s:v:0', 'rotate=90', path.join(dir, 'hochkant.mp4')); // Wie eine Browser-Aufnahme: WebM ohne Gesamtlänge im Kopf ffmpeg('-f', 'lavfi', '-i', 'sine', '-t', '2', '-c:a', 'libopus', '-f', 'webm', '-live', '1', path.join(dir, 'aufnahme.webm')); }); after(() => { if (dir) fs.rmSync(dir, { recursive: true, force: true }); }); test('ffprobe liefert Länge, Größe, Bildrate und Tonspur', { skip: !hasFfmpeg && 'ffmpeg fehlt' }, async () => { const media = await probe(path.join(dir, 'quer.mp4')); assert.ok(Math.abs(media.duration - 2) < 0.1); assert.equal(media.width, 320); assert.equal(media.height, 180); assert.equal(media.fps, 25); assert.equal(media.hasAudio, true); }); test('Gedrehte Videos werden hochkant erkannt', { skip: !hasFfmpeg && 'ffmpeg fehlt' }, async () => { const media = await probe(path.join(dir, 'hochkant.mp4')); assert.equal(Math.abs(media.rotation), 90); assert.equal(media.width, 180); assert.equal(media.height, 320); assert.equal(media.hasAudio, false); }); test('Datei ohne Video wird abgelehnt', { skip: !hasFfmpeg && 'ffmpeg fehlt' }, async () => { const file = path.join(dir, 'text.mp4'); fs.writeFileSync(file, 'kein Video'); await assert.rejects(probe(file)); }); test('Browser-Aufnahme ohne Längenangabe wird ausgemessen', { skip: !hasFfmpeg && 'ffmpeg fehlt' }, async () => { const media = await probe(path.join(dir, 'aufnahme.webm')); assert.equal(media.hasVideo, false); assert.equal(media.hasAudio, true); assert.ok(Math.abs(media.duration - 2) < 0.1, `Länge ${media.duration}`); });