AI_Photographer/Web/direct_camera.js
2026-04-12 18:52:37 +04:00

128 lines
5.2 KiB
JavaScript

(function () {
function restartPreview() {
const img = document.getElementById("preview_img");
if (!img) {
return;
}
img.src = `/preview.mjpg?t=${Date.now()}`;
}
function setResolutionInputs(width, height, fps) {
document.getElementById("width_input").value = String(width || "");
document.getElementById("height_input").value = String(height || "");
document.getElementById("fps_input").value = String(fps || "");
const preset = `${width}x${height}@${fps}`;
const sel = document.getElementById("resolution_select");
const hasPreset = Array.from(sel.options).some((opt) => opt.value === preset);
sel.value = hasPreset ? preset : "";
}
async function api(path) {
const response = await fetch(path);
if (!response.ok) {
throw new Error(await response.text());
}
return response.json();
}
function fmtBytes(n) {
if (n < 1024) {
return `${n} B`;
}
if (n < 1024 * 1024) {
return `${(n / 1024).toFixed(1)} KB`;
}
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
}
async function refreshAll() {
const [health, photos] = await Promise.all([api("/api/health"), api("/api/photos")]);
const camera = health.camera || {};
const widthInput = document.getElementById("width_input");
if (widthInput.dataset.initialized !== "1") {
setResolutionInputs(camera.requested_width, camera.requested_height, camera.requested_fps);
widthInput.dataset.initialized = "1";
}
document.getElementById("status").textContent = camera.ok
? `Camera OK\nSource: ${camera.source}\nBackend: ${camera.backend}\nActive: ${camera.profile || "-"}\nRequested: ${camera.requested_profile}\nPreferred RS Serial: ${camera.preferred_realsense_serial || "-"}\nConfig RS Serial: ${camera.config_realsense_serial || "-"}\nFallback RS Serial: ${camera.configured_realsense_serial || "-"}\nActive RS Serial: ${camera.realsense_serial || "-"}\nSamples: ${photos.items.length}`
: `Camera not ready\nSource: ${camera.source}\nRequested: ${camera.requested_profile}\nPreferred RS Serial: ${camera.preferred_realsense_serial || "-"}\nConfig RS Serial: ${camera.config_realsense_serial || "-"}\nFallback RS Serial: ${camera.configured_realsense_serial || "-"}\nActive RS Serial: ${camera.realsense_serial || "-"}\nError: ${camera.last_error || "-"}`;
document.getElementById("camera_status").textContent = JSON.stringify(health, null, 2);
const gallery = document.getElementById("gallery");
gallery.innerHTML = "";
for (const item of photos.items) {
const card = document.createElement("article");
card.className = "card";
card.innerHTML = `
<img class="thumb" src="/samples/${encodeURIComponent(item.name)}?t=${Date.now()}" alt="">
<div class="name">${item.name}</div>
<div class="meta">${fmtBytes(item.size)}</div>
<div class="row">
<a class="btn secondary" href="/api/download?name=${encodeURIComponent(item.name)}">Download</a>
<button class="danger" data-name="${item.name}">Delete</button>
</div>
`;
gallery.appendChild(card);
}
gallery.querySelectorAll("button.danger").forEach((btn) => {
btn.addEventListener("click", async () => {
const { name } = btn.dataset;
await api(`/api/delete?name=${encodeURIComponent(name)}`);
await refreshAll();
});
});
}
document.getElementById("capture_btn").addEventListener("click", async () => {
const status = document.getElementById("status");
status.textContent = "Capturing...";
try {
const resp = await api("/api/capture");
status.textContent = `Saved: ${resp.name}`;
await refreshAll();
} catch (e) {
status.textContent = `Capture failed\n${e.message}`;
}
});
document.getElementById("resolution_select").addEventListener("change", (e) => {
const value = e.target.value;
const match = value.match(/^(\d+)x(\d+)@(\d+)$/);
if (!match) {
return;
}
setResolutionInputs(Number(match[1]), Number(match[2]), Number(match[3]));
});
document.getElementById("apply_resolution_btn").addEventListener("click", async () => {
const width = Number(document.getElementById("width_input").value);
const height = Number(document.getElementById("height_input").value);
const fps = Number(document.getElementById("fps_input").value);
const status = document.getElementById("status");
status.textContent = `Applying resolution ${width}x${height}@${fps}...`;
try {
const resp = await api(
`/api/set_resolution?width=${encodeURIComponent(width)}&height=${encodeURIComponent(height)}&fps=${encodeURIComponent(fps)}`
);
const camera = resp.camera || {};
setResolutionInputs(camera.requested_width, camera.requested_height, camera.requested_fps);
restartPreview();
await refreshAll();
} catch (e) {
status.textContent = `Resolution change failed\n${e.message}`;
}
});
document.getElementById("refresh_btn").addEventListener("click", refreshAll);
refreshAll().catch((e) => {
document.getElementById("status").textContent = String(e);
});
setInterval(() => {
refreshAll().catch(() => {});
}, 10000);
})();