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:
ferdi2goandClaude Opus 5.5 committed 2026-09-29 10:48:53 +00:00
1 parent d7102d04a4
commit 72e4b8ab7a
6 files changed
+340 -45

No files matched your search

+30 -3
View File
@@ -75,15 +75,42 @@ export function createApp({ config, secret, store }) {
res.status(204).end();
}));
app.put('/api/projects/:id/clips/:index', route(async (req, res) => {
const readOffset = (req) => {
const offset = Number(req.query.offset);
if (!Number.isSafeInteger(offset) || offset < 0) throw badRequest('Ungültiger Offset.');
res.json(await store.appendChunk(req.params.id, req.params.index, offset, req));
return offset;
};
app.patch('/api/projects/:id/settings', route(async (req, res) => {
res.json(await store.updateSettings(req.params.id, req.body));
}));
app.put('/api/projects/:id/clips/:index', route(async (req, res) => {
const target = { type: 'clip', index: req.params.index };
res.json(await store.appendChunk(req.params.id, target, readOffset(req), req));
}));
app.get('/api/projects/:id/clips/:index/file', route(async (req, res) => {
const project = await store.get(req.params.id);
res.sendFile(store.clipPath(project, req.params.index));
res.sendFile(store.readyPath(project, { type: 'clip', index: req.params.index }));
}));
app.post('/api/projects/:id/assets/:slot', route(async (req, res) => {
res.status(201).json(await store.createAsset(req.params.id, req.params.slot, req.body));
}));
app.put('/api/projects/:id/assets/:slot', route(async (req, res) => {
const target = { type: 'asset', slot: req.params.slot };
res.json(await store.appendChunk(req.params.id, target, readOffset(req), req));
}));
app.delete('/api/projects/:id/assets/:slot', route(async (req, res) => {
res.json(await store.removeAsset(req.params.id, req.params.slot));
}));
app.get('/api/projects/:id/assets/:slot/file', route(async (req, res) => {
const project = await store.get(req.params.id);
res.sendFile(store.readyPath(project, { type: 'asset', slot: req.params.slot }));
}));
app.use('/api', (req, res) => res.status(404).json({ error: 'Nicht gefunden.' }));