Standbild

This commit is contained in:
chk
2026-06-07 10:42:28 +02:00
parent faccbf55ce
commit d3e45262ce
6 changed files with 155 additions and 19 deletions

View File

@@ -79,6 +79,15 @@
color: #444; font-size: 0.82rem; letter-spacing: 0.04em;
}
/* Snapshot-Modus: gross+fett über dem Einzelbild */
.single-pic-banner {
position: absolute; top: 0; left: 0; right: 0; z-index: 3;
text-align: center; padding: 8px 4px;
font-size: 1.15rem; font-weight: bold; letter-spacing: 0.06em;
text-transform: uppercase;
color: #fc6; background: rgba(0,0,0,.72);
}
/* Hi-Res-Test-Button (Phase 1) links neben dem Ein/Aus-Schalter */
.cam-hdtest {
position: absolute; top: 5px; right: 40px; z-index: 2;

View File

@@ -38,6 +38,37 @@ function stopStream(cam) {
log(cam.id, 'Live aus');
}
// ── Snapshot-Modus (stream:false): alle 5 s ein Einzelbild ──────────────────
// Kein Video der Server öffnet das Gerät pro Snapshot kurz (one-shot). Fehler
// (z. B. Gerät gerade durch HD-Grab belegt) werden still übersprungen, das letzte
// gute Bild bleibt stehen.
const SNAPSHOT_INTERVAL_MS = 5000;
async function fetchSnapshot(cam) {
if (!cam.snapshotActive) return;
try {
const r = await fetch(`/api/snapshot/${encodeURIComponent(cam.id)}?t=${Date.now()}`,
{ signal: AbortSignal.timeout(8000) });
if (!r.ok) { setInfo(cam, `Snapshot-Fehler (HTTP ${r.status})`, 'warn'); return; }
const blob = await r.blob();
const url = URL.createObjectURL(blob);
cam.img.src = url;
if (cam.lastBlobUrl) URL.revokeObjectURL(cam.lastBlobUrl);
cam.lastBlobUrl = url;
setInfo(cam, `Einzelbild · ${new Date().toLocaleTimeString()}`, 'ok');
} catch (_e) {
setInfo(cam, 'Snapshot-Timeout', 'warn');
}
}
function startSnapshotMode(cam) {
cam.snapshotActive = true;
setInfo(cam, 'Einzelbild lädt…', '');
fetchSnapshot(cam); // sofort das erste Bild
cam.snapTimer = setInterval(() => fetchSnapshot(cam), SNAPSHOT_INTERVAL_MS);
log(cam.id, `Snapshot-Modus (alle ${SNAPSHOT_INTERVAL_MS / 1000} s)`);
}
// ── HD-Snapshot ───────────────────────────────────────────────────────────────
async function runHiresGrab(cam) {
if (cam.busy) return;
@@ -144,11 +175,21 @@ function buildCamera(camMeta, container) {
box.appendChild(toggle);
startStream(cam);
} else {
const placeholder = document.createElement('div');
placeholder.className = 'cam-img cam-placeholder';
placeholder.textContent = 'Kein Live-Stream';
hd.title = 'Hi-Res-Snapshot (1280×960) Download';
box.appendChild(placeholder);
// Snapshot-Modus: grosser Banner + Einzelbild, das alle 5 s aktualisiert wird.
const banner = document.createElement('div');
banner.className = 'single-pic-banner';
banner.textContent = 'Single Picture no Video';
const img = document.createElement('img');
img.className = 'cam-img';
img.alt = labelText;
cam.img = img;
hd.title = 'Hi-Res-Snapshot Download';
box.appendChild(banner);
box.appendChild(img);
startSnapshotMode(cam);
}
box.appendChild(label);