Projekte anlegen und Clips in Stücken hochladen
Ein Projekt hält die ausgewählten Clips samt Absender und Beschriftung. Videos kommen in Stücken bis 16 MB; die Größe der Teildatei ist der Stand, sodass ein abgebrochener Upload dort weitermacht. Nach dem letzten Stück liest ffprobe Länge, Größe, Drehung und Tonspur aus. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6f583c8f5b
commit
782d306cb1
7 files changed
+549
-2
No files matched your search
+47
-1
@@ -8,8 +8,9 @@ import {
|
||||
readCookie,
|
||||
verifyToken,
|
||||
} from './auth.js';
|
||||
import { HttpError, badRequest } from './http-error.js';
|
||||
|
||||
export function createApp({ config, secret }) {
|
||||
export function createApp({ config, secret, store }) {
|
||||
const app = express();
|
||||
app.disable('x-powered-by');
|
||||
app.set('trust proxy', true);
|
||||
@@ -55,7 +56,52 @@ export function createApp({ config, secret }) {
|
||||
next();
|
||||
});
|
||||
|
||||
const route = (handler) => (req, res, next) => Promise.resolve(handler(req, res)).catch(next);
|
||||
|
||||
app.get('/api/projects', route(async (req, res) => {
|
||||
res.json(await store.list());
|
||||
}));
|
||||
|
||||
app.post('/api/projects', route(async (req, res) => {
|
||||
res.status(201).json(await store.create(req.body ?? {}));
|
||||
}));
|
||||
|
||||
app.get('/api/projects/:id', route(async (req, res) => {
|
||||
res.json(await store.get(req.params.id));
|
||||
}));
|
||||
|
||||
app.delete('/api/projects/:id', route(async (req, res) => {
|
||||
await store.remove(req.params.id);
|
||||
res.status(204).end();
|
||||
}));
|
||||
|
||||
app.put('/api/projects/:id/clips/:index', route(async (req, res) => {
|
||||
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));
|
||||
}));
|
||||
|
||||
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));
|
||||
}));
|
||||
|
||||
app.use('/api', (req, res) => res.status(404).json({ error: 'Nicht gefunden.' }));
|
||||
|
||||
// eslint-disable-next-line no-unused-vars -- Express erkennt Fehlerbehandler an vier Parametern
|
||||
app.use((error, req, res, next) => {
|
||||
if (error instanceof HttpError) {
|
||||
return res.status(error.status).json({ error: error.message, ...error.details });
|
||||
}
|
||||
// Fehler aus express.json (kaputtes oder zu großes JSON)
|
||||
if (error.status >= 400 && error.status < 500) {
|
||||
return res.status(error.status).json({ error: 'Ungültige Anfrage.' });
|
||||
}
|
||||
// Der Browser hat den Upload abgebrochen; der Stand bleibt gültig.
|
||||
if (error.code === 'ERR_STREAM_PREMATURE_CLOSE') return;
|
||||
console.error(error);
|
||||
if (!res.headersSent) res.status(500).json({ error: 'Interner Fehler.' });
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
Reference in new issue
Block a user