Einstellungen und Zusatzdateien für den Schnitt ablegen
Intro, Outro, Backing Track und Voice-overs pro Clip laufen über denselben Upload in Stücken wie die Clips. Die Schnitt-Einstellungen werden feldweise geprüft; ffprobe akzeptiert jetzt auch reine Tonspuren. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d7102d04a4
commit
72e4b8ab7a
6 files changed
+340
-45
No files matched your search
+47
-1
@@ -11,7 +11,7 @@ let baseUrl;
|
||||
let cookie;
|
||||
let dataDir;
|
||||
|
||||
const fakeMedia = { duration: 42, width: 1080, height: 1920, rotation: 0, fps: 30, hasAudio: true };
|
||||
const fakeMedia = { duration: 42, hasVideo: true, width: 1080, height: 1920, rotation: 0, fps: 30, hasAudio: true };
|
||||
|
||||
before(async () => {
|
||||
dataDir = await fs.mkdtemp(path.join(os.tmpdir(), 'fdc-test-'));
|
||||
@@ -141,3 +141,49 @@ test('Projekt löschen entfernt die Dateien', async () => {
|
||||
assert.equal((await call('GET', `projects/${project.id}`)).status, 404);
|
||||
await assert.rejects(fs.stat(path.join(dataDir, 'projects', project.id)));
|
||||
});
|
||||
|
||||
test('Einstellungen speichern und prüfen', async () => {
|
||||
const project = await createProject([clip('a.mp4', 5), clip('b.mp4', 5)]);
|
||||
assert.equal(project.settings.muteClips, true);
|
||||
|
||||
let res = await call('PATCH', `projects/${project.id}/settings`, { music: { enabled: true, volume: 40 } });
|
||||
const updated = await res.json();
|
||||
assert.deepEqual(updated.settings.music, { enabled: true, volume: 40 });
|
||||
|
||||
res = await call('PATCH', `projects/${project.id}/settings`, { excluded: [5] });
|
||||
assert.equal(res.status, 400);
|
||||
});
|
||||
|
||||
test('Zusatzdateien anmelden, hochladen, ersetzen und löschen', async () => {
|
||||
const project = await createProject([clip('a.mp4', 5)]);
|
||||
const base = `projects/${project.id}/assets`;
|
||||
|
||||
// Falscher Dateityp für den Platz
|
||||
assert.equal((await call('POST', `${base}/music`, { file: 'intro.txt', size: 4 })).status, 400);
|
||||
// Unbekannter Platz und Voice-over zu einem Clip, den es nicht gibt
|
||||
assert.equal((await call('POST', `${base}/abspann`, { file: 'a.mp3', size: 4 })).status, 404);
|
||||
assert.equal((await call('POST', `${base}/voice-3`, { file: 'a.webm', size: 4 })).status, 404);
|
||||
|
||||
let res = await call('POST', `${base}/voice-0`, { file: 'aufnahme.webm', size: 4 });
|
||||
assert.equal(res.status, 201);
|
||||
assert.equal((await res.json()).assets['voice-0'].status, 'pending');
|
||||
|
||||
const put = (slot, offset, text) =>
|
||||
call('PUT', `${base}/${slot}?offset=${offset}`, new TextEncoder().encode(text), {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
});
|
||||
res = await put('voice-0', 0, 'stim');
|
||||
assert.equal((await res.json()).status, 'ready');
|
||||
assert.equal(await (await call('GET', `${base}/voice-0/file`)).text(), 'stim');
|
||||
|
||||
// Ersetzen verwirft die alte Datei
|
||||
await call('POST', `${base}/voice-0`, { file: 'neu.m4a', size: 3 });
|
||||
const replaced = await (await call('GET', `projects/${project.id}`)).json();
|
||||
assert.equal(replaced.assets['voice-0'].file, 'neu.m4a');
|
||||
assert.equal(replaced.assets['voice-0'].received, 0);
|
||||
const files = await fs.readdir(path.join(dataDir, 'projects', project.id, 'assets'));
|
||||
assert.deepEqual(files, []);
|
||||
|
||||
res = await call('DELETE', `${base}/voice-0`);
|
||||
assert.deepEqual((await res.json()).assets, {});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import { defaultSettings, mergeSettings } from '../server/settings.js';
|
||||
|
||||
test('Vorgaben: beschleunigen und stummschalten an, Intro, Outro und Musik aus', () => {
|
||||
const settings = defaultSettings();
|
||||
assert.equal(settings.speedUp, true);
|
||||
assert.equal(settings.muteClips, true);
|
||||
assert.equal(settings.intro.enabled, false);
|
||||
assert.equal(settings.music.volume, 60);
|
||||
});
|
||||
|
||||
test('Teiländerungen lassen den Rest stehen', () => {
|
||||
const merged = mergeSettings(defaultSettings(), { music: { volume: 35 } }, 5);
|
||||
assert.equal(merged.music.volume, 35);
|
||||
assert.equal(merged.music.enabled, false);
|
||||
assert.equal(merged.intro.volume, 100);
|
||||
});
|
||||
|
||||
test('Voice-over-Lautstärke pro Clip und ausgeschlossene Clips', () => {
|
||||
const merged = mergeSettings(defaultSettings(), { voiceVolumes: { 2: 80 }, excluded: [3, 1, 3] }, 5);
|
||||
assert.deepEqual(merged.voiceVolumes, { 2: 80 });
|
||||
assert.deepEqual(merged.excluded, [1, 3]);
|
||||
});
|
||||
|
||||
test('Ungültige Werte werden abgelehnt', () => {
|
||||
const invalid = [
|
||||
{ music: { volume: 101 } },
|
||||
{ clipVolume: -1 },
|
||||
{ clipVolume: 50.5 },
|
||||
{ speedUp: 'ja' },
|
||||
{ voiceVolumes: { 9: 50 } },
|
||||
{ excluded: [7] },
|
||||
[],
|
||||
];
|
||||
for (const patch of invalid) {
|
||||
assert.throws(() => mergeSettings(defaultSettings(), patch, 5), { status: 400 });
|
||||
}
|
||||
});
|
||||
|
||||
test('Unbekannte Felder werden ignoriert', () => {
|
||||
const merged = mergeSettings(defaultSettings(), { hacker: true, intro: { enabled: true, file: '/etc/passwd' } }, 1);
|
||||
assert.equal(merged.hacker, undefined);
|
||||
assert.equal(merged.intro.file, undefined);
|
||||
assert.equal(merged.intro.enabled, true);
|
||||
});
|
||||
Reference in new issue
Block a user