Setup-Zuordnung korrigiert (cam2/cam3), Button 'Setup alle', Stream nach Setup neu laden
This commit is contained in:
1 parent
70b63cb215
commit
7c80b3402e
2 files changed
+27
-8
No files matched your search
+1
-1
@@ -5,7 +5,7 @@ CAMERA_cam2=http://IP:PORT/pfad
|
|||||||
CAMERA_cam3=http://IP:PORT/pfad
|
CAMERA_cam3=http://IP:PORT/pfad
|
||||||
|
|
||||||
# Optional: Konfigurations-URL pro Kamera (Button "Setup" im Frontend), z.B. ESP32-CAM Auflösung
|
# Optional: Konfigurations-URL pro Kamera (Button "Setup" im Frontend), z.B. ESP32-CAM Auflösung
|
||||||
#SETUP_cam1=http://IP/control?var=framesize&val=11
|
#SETUP_cam2=http://IP/control?var=framesize&val=11
|
||||||
|
|
||||||
PORT=8000
|
PORT=8000
|
||||||
# Optional: Login (nur sinnvoll mit HTTPS in Zoraxy)
|
# Optional: Login (nur sinnvoll mit HTTPS in Zoraxy)
|
||||||
|
|||||||
+26
-7
@@ -61,6 +61,7 @@ main{padding:22px;max-width:1800px;margin:0 auto}
|
|||||||
<header>
|
<header>
|
||||||
<h1><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 7l-7 5 7 5V7z"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg><a id="home">Webcams</a></h1>
|
<h1><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 7l-7 5 7 5V7z"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg><a id="home">Webcams</a></h1>
|
||||||
<span class="sp"></span>
|
<span class="sp"></span>
|
||||||
|
<button class="btn" id="setupAll" hidden><span>Setup alle</span></button>
|
||||||
<span class="pill" id="count"></span>
|
<span class="pill" id="count"></span>
|
||||||
<span class="pill" id="clock"></span>
|
<span class="pill" id="clock"></span>
|
||||||
</header>
|
</header>
|
||||||
@@ -72,6 +73,7 @@ const app = document.getElementById("app");
|
|||||||
document.getElementById("home").href = ROOT;
|
document.getElementById("home").href = ROOT;
|
||||||
const banner = document.getElementById("banner");
|
const banner = document.getElementById("banner");
|
||||||
const tiles = {};
|
const tiles = {};
|
||||||
|
let setupNames = [];
|
||||||
let order = [], visible = true;
|
let order = [], visible = true;
|
||||||
|
|
||||||
const el = (tag, cls, text) => {
|
const el = (tag, cls, text) => {
|
||||||
@@ -88,6 +90,15 @@ const ICONS = {
|
|||||||
};
|
};
|
||||||
const icon = k => { const s = document.createElementNS("http://www.w3.org/2000/svg", "svg"); s.setAttribute("viewBox", "0 0 24 24"); s.setAttribute("fill", "none"); s.setAttribute("stroke", "currentColor"); s.setAttribute("stroke-width", "2"); s.setAttribute("stroke-linecap", "round"); s.setAttribute("stroke-linejoin", "round"); s.innerHTML = ICONS[k]; return s; };
|
const icon = k => { const s = document.createElementNS("http://www.w3.org/2000/svg", "svg"); s.setAttribute("viewBox", "0 0 24 24"); s.setAttribute("fill", "none"); s.setAttribute("stroke", "currentColor"); s.setAttribute("stroke-width", "2"); s.setAttribute("stroke-linecap", "round"); s.setAttribute("stroke-linejoin", "round"); s.innerHTML = ICONS[k]; return s; };
|
||||||
const btn = (label, ic, fn, cls) => { const b = el("button", "btn" + (cls ? " " + cls : "")); b.title = label; b.append(icon(ic), el("span", "", label)); b.onclick = fn; return b; };
|
const btn = (label, ic, fn, cls) => { const b = el("button", "btn" + (cls ? " " + cls : "")); b.title = label; b.append(icon(ic), el("span", "", label)); b.onclick = fn; return b; };
|
||||||
|
const setupAllBtn = document.getElementById("setupAll");
|
||||||
|
setupAllBtn.prepend(icon("cog"));
|
||||||
|
setupAllBtn.onclick = async () => {
|
||||||
|
setupAllBtn.disabled = true;
|
||||||
|
const label = setupAllBtn.querySelector("span");
|
||||||
|
const res = await Promise.all(setupNames.map(runSetup));
|
||||||
|
label.textContent = res.every(Boolean) ? "Gesendet ✓" : "Fehler ✗";
|
||||||
|
setTimeout(() => { label.textContent = "Setup alle"; setupAllBtn.disabled = false; }, 2500);
|
||||||
|
};
|
||||||
|
|
||||||
// mode: "live" = MJPEG-Stream, "thumb" = Einzelbild im Intervall
|
// mode: "live" = MJPEG-Stream, "thumb" = Einzelbild im Intervall
|
||||||
function makeTile(name, mode, hasSetup) {
|
function makeTile(name, mode, hasSetup) {
|
||||||
@@ -115,13 +126,7 @@ function makeTile(name, mode, hasSetup) {
|
|||||||
const setup = btn("Setup", "cog", async () => {
|
const setup = btn("Setup", "cog", async () => {
|
||||||
setup.disabled = true;
|
setup.disabled = true;
|
||||||
const label = setup.querySelector("span");
|
const label = setup.querySelector("span");
|
||||||
try {
|
label.textContent = (await runSetup(name)) ? "Gesendet ✓" : "Fehler ✗";
|
||||||
const r = await fetch(ROOT + name + "/setup", { method: "POST" });
|
|
||||||
if (!r.ok) throw new Error(r.status);
|
|
||||||
label.textContent = "Gesendet ✓";
|
|
||||||
} catch (e) {
|
|
||||||
label.textContent = "Fehler ✗";
|
|
||||||
}
|
|
||||||
setTimeout(() => { label.textContent = "Setup"; setup.disabled = false; }, 2500);
|
setTimeout(() => { label.textContent = "Setup"; setup.disabled = false; }, 2500);
|
||||||
}, "alt");
|
}, "alt");
|
||||||
actions.append(setup);
|
actions.append(setup);
|
||||||
@@ -140,6 +145,18 @@ function makeTile(name, mode, hasSetup) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runSetup(name) {
|
||||||
|
try {
|
||||||
|
const r = await fetch(ROOT + name + "/setup", { method: "POST" });
|
||||||
|
if (!r.ok) throw new Error(r.status);
|
||||||
|
// Kamera startet den Stream mit neuer Auflösung; Bild kurz danach neu laden
|
||||||
|
setTimeout(() => tiles[name] && connect(tiles[name]), 800);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function connect(o) {
|
function connect(o) {
|
||||||
clearTimeout(o.retry);
|
clearTimeout(o.retry);
|
||||||
clearInterval(o.timer);
|
clearInterval(o.timer);
|
||||||
@@ -192,6 +209,8 @@ async function poll() {
|
|||||||
if (names.join() !== order.join()) build(data.cameras);
|
if (names.join() !== order.join()) build(data.cameras);
|
||||||
data.cameras.forEach(c => setOnline(tiles[c.name], c.online));
|
data.cameras.forEach(c => setOnline(tiles[c.name], c.online));
|
||||||
const n = data.cameras.filter(c => c.online).length;
|
const n = data.cameras.filter(c => c.online).length;
|
||||||
|
setupNames = data.cameras.filter(c => c.setup).map(c => c.name);
|
||||||
|
setupAllBtn.hidden = !setupNames.length;
|
||||||
document.getElementById("count").innerHTML = "<b>" + n + "</b> / " + data.cameras.length + " online";
|
document.getElementById("count").innerHTML = "<b>" + n + "</b> / " + data.cameras.length + " online";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
banner.style.display = "block";
|
banner.style.display = "block";
|
||||||
|
|||||||
Reference in new issue
Block a user