116 lines
4.3 KiB
JavaScript
116 lines
4.3 KiB
JavaScript
'use strict';
|
||
|
||
// go2rtc Player-Modi – Fallback-Reihenfolge: WebRTC → MSE → MJPEG
|
||
const MODE = 'webrtc,mse,mjpeg';
|
||
|
||
// ── Logging (Browser DevTools → Console → F12) ───────────────────────────────
|
||
const P = '[WebcamViewer]';
|
||
const log = (c, m) => console.log(`${P}[${c}] ${m}`);
|
||
const warn = (c, m) => console.warn(`${P}[${c}] ⚠ ${m}`);
|
||
const logErr = (c, m, e) => console.error(`${P}[${c}] ✗ ${m}`, e ?? '');
|
||
|
||
// ── Snapshot aller Kameras gleichzeitig ──────────────────────────────────────
|
||
// Auflösung = was go2rtc im MJPEG-Stream hält (aktuell 640×480 gemäss Config).
|
||
// Für höhere Auflösung: in go2rtc.yaml einen separaten Hi-Res-Stream definieren
|
||
// und hier auf dessen /api/frame.jpeg?src=cam0_hires zeigen.
|
||
function snapshotAll(camIds) {
|
||
const ts = Date.now();
|
||
log('snap', `Snapshot alle Kameras: ${camIds.join(', ')}`);
|
||
camIds.forEach(id => {
|
||
const a = document.createElement('a');
|
||
a.href = `/api/snapshot/${id}`;
|
||
a.download = `${id}_${ts}.jpg`;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
});
|
||
}
|
||
|
||
// ── Kamera-View aufbauen ─────────────────────────────────────────────────────
|
||
function buildCamera(camId, go2rtcPort, container) {
|
||
const wsUrl = `ws://${location.hostname}:${go2rtcPort}/api/ws?src=${encodeURIComponent(camId)}`;
|
||
log(camId, `View erstellt mode="${MODE}" ws=${wsUrl}`);
|
||
|
||
const box = document.createElement('div');
|
||
box.className = 'cam-box';
|
||
|
||
const stream = document.createElement('video-stream');
|
||
stream.mode = MODE;
|
||
|
||
stream.addEventListener('play', () => log(camId, '▶ spielt'), true);
|
||
stream.addEventListener('playing', () => log(camId, '▶ Bild läuft'), true);
|
||
stream.addEventListener('pause', () => warn(camId, 'pausiert'), true);
|
||
stream.addEventListener('stalled', () => warn(camId, 'stalled (keine Daten)'), true);
|
||
stream.addEventListener('waiting', () => warn(camId, 'waiting (Buffer leer)'), true);
|
||
stream.addEventListener('error', (e) => logErr(camId, 'Video-Fehler', e), true);
|
||
|
||
log(camId, `Verbinde WebSocket → ${wsUrl}`);
|
||
stream.src = wsUrl;
|
||
|
||
box.appendChild(stream);
|
||
|
||
const label = document.createElement('div');
|
||
label.className = 'cam-label';
|
||
label.textContent = camId;
|
||
box.appendChild(label);
|
||
|
||
container.appendChild(box);
|
||
}
|
||
|
||
// ── Init ─────────────────────────────────────────────────────────────────────
|
||
async function init() {
|
||
log('init', 'Starte...');
|
||
|
||
let go2rtcPort = 1984;
|
||
try {
|
||
const r = await fetch('/config.json');
|
||
const d = await r.json();
|
||
go2rtcPort = d.go2rtcPort ?? 1984;
|
||
log('init', `go2rtc WS-Port: ${go2rtcPort}`);
|
||
} catch (e) {
|
||
warn('init', `Konnte /config.json nicht laden, nehme Port ${go2rtcPort}`);
|
||
}
|
||
|
||
try {
|
||
await customElements.whenDefined('video-stream');
|
||
log('init', '<video-stream> definiert');
|
||
} catch (e) {
|
||
logErr('init', '<video-stream> nicht geladen – /video-stream.js erreichbar?', e);
|
||
return;
|
||
}
|
||
|
||
const container = document.getElementById('cameras');
|
||
const statusText = document.getElementById('statusText');
|
||
|
||
let cams = [];
|
||
try {
|
||
const r = await fetch('/api/snapshot');
|
||
log('init', `/api/snapshot → HTTP ${r.status}`);
|
||
if (r.ok) {
|
||
const d = await r.json();
|
||
cams = (d.cameras ?? []).map(c => c.id);
|
||
log('init', `Kameras: ${cams.join(', ') || '(keine)'}`);
|
||
}
|
||
} catch (e) {
|
||
logErr('init', '/api/snapshot Fehler – Fallback', e);
|
||
}
|
||
|
||
if (cams.length === 0) {
|
||
warn('init', 'Fallback auf cam0, cam1');
|
||
cams = ['cam0', 'cam1'];
|
||
}
|
||
|
||
// Globaler Snapshot-Button in der Header-Bar verdrahten
|
||
const snapAllBtn = document.getElementById('snapAllBtn');
|
||
if (snapAllBtn) {
|
||
snapAllBtn.onclick = () => snapshotAll(cams);
|
||
snapAllBtn.disabled = false;
|
||
}
|
||
|
||
cams.forEach(id => buildCamera(id, go2rtcPort, container));
|
||
statusText.textContent = `${cams.length} Kamera${cams.length !== 1 ? 's' : ''} · WebRTC`;
|
||
log('init', 'Fertig');
|
||
}
|
||
|
||
init();
|