Button Foto
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import express from 'express';
|
||||
import https from 'https';
|
||||
import { Readable } from 'node:stream';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fsPromises from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
import process from 'process';
|
||||
import { WebcamClient } from './webcamClient.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -27,6 +29,53 @@ app.get('/api/health', (req, res) => {
|
||||
res.json({ ok: true, mode: 'backend-proxy', webcamUrl: WEBCAM_URL || null, bodyTrackerUrl: BODYTRACKER_URL || null });
|
||||
});
|
||||
|
||||
// ── WebCam-Proxy ─────────────────────────────────────────────────────────────
|
||||
|
||||
/** Kameraliste mit Metadaten (inkl. calibrationUrl falls Kalibrierung vorhanden). */
|
||||
app.get('/api/webcam/cameras', async (req, res) => {
|
||||
if (!WEBCAM_URL) return res.status(501).json({ error: 'WEBCAM_URL ist nicht konfiguriert' });
|
||||
try {
|
||||
const wc = new WebcamClient(WEBCAM_URL);
|
||||
const data = await wc.getCameras();
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
console.error('webcam/cameras error:', err);
|
||||
return res.status(502).json({ error: 'WebCam-Fehler', details: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* HD-JPEG einer Kamera (per Default hires).
|
||||
* Streamt die JPEG-Antwort direkt durch — kein Buffering im Backend.
|
||||
* Query-Parameter: ?hires=false für Live-Auflösung.
|
||||
*/
|
||||
app.get('/api/webcam/snapshot/:id', async (req, res) => {
|
||||
if (!WEBCAM_URL) return res.status(501).json({ error: 'WEBCAM_URL ist nicht konfiguriert' });
|
||||
const hires = req.query.hires !== 'false';
|
||||
try {
|
||||
const wc = new WebcamClient(WEBCAM_URL);
|
||||
const upstream = await wc.getSnapshot(req.params.id, hires);
|
||||
|
||||
// Relevante Response-Header durchreichen
|
||||
res.setHeader('Content-Type', upstream.headers.get('content-type') || 'image/jpeg');
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
for (const header of ['x-camera-id', 'x-frame-width', 'x-timestamp', 'content-length']) {
|
||||
const val = upstream.headers.get(header);
|
||||
if (val) res.setHeader(header, val);
|
||||
}
|
||||
|
||||
const nodeStream = Readable.fromWeb(upstream.body);
|
||||
nodeStream.on('error', (err) => {
|
||||
console.error(`webcam/snapshot/${req.params.id} stream error:`, err);
|
||||
if (!res.headersSent) res.status(502).json({ error: 'Stream-Fehler' });
|
||||
});
|
||||
nodeStream.pipe(res);
|
||||
} catch (err) {
|
||||
console.error(`webcam/snapshot/${req.params.id} error:`, err);
|
||||
if (!res.headersSent) res.status(502).json({ error: 'WebCam-Fehler', details: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
async function findLatestSnapshotFile() {
|
||||
const files = await fsPromises.readdir(snapshotsDir);
|
||||
const entries = await Promise.all(
|
||||
|
||||
Reference in New Issue
Block a user