Auto-on live preview when recount starts (all recounting templates)

This commit is contained in:
proitlab committed 2026-08-10 09:53:55 +07:00
1 parent 6043197d72
commit 6be017c4f0
5 files changed
+82 -20

No files matched your search

+2
View File
@@ -159,6 +159,7 @@ V18: .env missing → scripts fail at import (os.getenv falls back to defaults,
V19: stream reconnect → reset motion detection state (prev_gray = None)
V20: reset → delete STATE_FILE + touch {SHM_DIR}/.reset; batch_store._check_reset_signal() watches marker & clears in-memory state before next crossing
V21: upload filename batch_XX_YYYYMMDD_HHmmSS.mp4 → batch# + date parsed; batch-result queries /api/day-detail/<YYYY-MM-DD> on live API
V22: preview auto-on when recount running — enablePreview() on START RECOUNT + applyState streaming branch; manual toggle overrides; img.onerror retries cache-busted src while streaming
```
## §T — Tasks
@@ -181,6 +182,7 @@ T13|x|add template system — DASHBOARD_TEMPLATE env var selects dashboard.html|
T14|x|harden reset API — separate SHM marker creation from state file cleanup; return 500 on SHM failure|V20
T15|x|add upload recounting dashboard — MP4 upload, progress bar, RECOUNT_CMD replay|V21
T16|x|add cross-dashboard header links — UPLOAD_DASHBOARD_URL (live→upload) & LIVE_DASHBOARD_URL (upload→live)|I.config
T17|x|auto-on live preview when recount running — enablePreview() on START + applyState; onerror retry while streaming|V22
```
## §B — Bugs
+20 -5
View File
@@ -483,6 +483,7 @@ function applyState(data) {
document.getElementById('video-status').innerHTML =
'<span style="width:6px;height:6px;border-radius:50%;background:var(--accent4);box-shadow:0 0 6px var(--accent4);animation:blink 1.5s ease-in-out infinite;"></span> streaming ' + (data.file_name || '');
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
loadBatchResult(data.file);
} else if (data.file && selectedFile === data.file) {
@@ -669,6 +670,7 @@ async function startRecount() {
document.getElementById('video-status').innerHTML =
'<span style="width:6px;height:6px;border-radius:50%;background:var(--accent4);box-shadow:0 0 6px var(--accent4);animation:blink 1.5s ease-in-out infinite;"></span> streaming ' + data.file;
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
} catch (err) {
alert('Error: ' + err.message);
btnStart.disabled = false;
@@ -732,11 +734,7 @@ function togglePreview() {
btn.textContent = 'STREAM OFF';
btn.classList.remove('active');
} else {
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
enablePreview();
}
}
@@ -751,6 +749,23 @@ function resetVideoToggle() {
btn.classList.remove('active');
}
function enablePreview() {
const btn = document.getElementById('videoToggle');
const img = document.getElementById('stream-img');
const placeholder = document.getElementById('video-placeholder');
if (!streamUrl) return;
img.onerror = function() {
if (streaming && streamUrl) {
img.src = streamUrl + '?' + Date.now();
}
};
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
}
let lastRecountCount = null;
let lastRecountTime = null;
+20 -5
View File
@@ -405,6 +405,7 @@ function applyState(data) {
document.getElementById('video-status').innerHTML =
'<span style="width:5px;height:5px;background:var(--success);display:inline-block;"></span> streaming ' + (data.file_name || '');
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
loadBatchResult(data.file);
} else if (data.file && selectedFile === data.file) {
@@ -595,6 +596,7 @@ async function startRecount() {
document.getElementById('video-status').innerHTML =
'<span style="width:5px;height:5px;background:var(--success);display:inline-block;"></span> streaming ' + data.file;
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
} catch (err) {
alert('Error: ' + err.message);
btnStart.disabled = false;
@@ -655,11 +657,7 @@ function togglePreview() {
btn.textContent = 'STREAM OFF';
btn.classList.remove('active');
} else {
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
enablePreview();
}
}
@@ -674,6 +672,23 @@ function resetVideoToggle() {
btn.classList.remove('active');
}
function enablePreview() {
const btn = document.getElementById('videoToggle');
const img = document.getElementById('stream-img');
const placeholder = document.getElementById('video-placeholder');
if (!streamUrl) return;
img.onerror = function() {
if (streaming && streamUrl) {
img.src = streamUrl + '?' + Date.now();
}
};
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
}
// --- Recount counter ---
let lastRecountCount = null;
+20 -5
View File
@@ -782,6 +782,7 @@ async function startRecount() {
document.getElementById('video-status').innerHTML =
'<span style="width:6px;height:6px;border-radius:50%;background:var(--accent4);box-shadow:0 0 6px var(--accent4);animation:blink 1.5s ease-in-out infinite;"></span> streaming ' + data.file;
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
} catch (err) {
alert('Error: ' + err.message);
btnStart.disabled = false;
@@ -845,11 +846,7 @@ function togglePreview() {
btn.textContent = 'STREAM OFF';
btn.classList.remove('active');
} else {
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
enablePreview();
}
}
@@ -864,6 +861,23 @@ function resetVideoToggle() {
btn.classList.remove('active');
}
function enablePreview() {
var btn = document.getElementById('videoToggle');
var img = document.getElementById('stream-img');
var placeholder = document.getElementById('video-placeholder');
if (!streamUrl) return;
img.onerror = function() {
if (streaming && streamUrl) {
img.src = streamUrl + '?' + Date.now();
}
};
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
}
async function syncState() {
try {
var res = await fetch('/api/state');
@@ -888,6 +902,7 @@ function applyState(data) {
document.getElementById('video-status').innerHTML =
'<span style="width:6px;height:6px;border-radius:50%;background:var(--accent4);box-shadow:0 0 6px var(--accent4);animation:blink 1.5s ease-in-out infinite;"></span> streaming ' + (data.file_name || '');
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
loadBatchResult(data.file);
} else if (data.file && selectedFile === data.file) {
+20 -5
View File
@@ -661,6 +661,7 @@ async function startRecount() {
document.getElementById('video-status').innerHTML =
'<span style="width:5px;height:5px;background:var(--success);display:inline-block;"></span> streaming ' + data.file;
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
} catch (err) {
alert('Error: ' + err.message);
btnStart.disabled = false;
@@ -724,11 +725,7 @@ function togglePreview() {
btn.textContent = 'STREAM OFF';
btn.classList.remove('active');
} else {
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
enablePreview();
}
}
@@ -743,6 +740,23 @@ function resetVideoToggle() {
btn.classList.remove('active');
}
function enablePreview() {
var btn = document.getElementById('videoToggle');
var img = document.getElementById('stream-img');
var placeholder = document.getElementById('video-placeholder');
if (!streamUrl) return;
img.onerror = function() {
if (streaming && streamUrl) {
img.src = streamUrl + '?' + Date.now();
}
};
img.src = streamUrl + '?' + Date.now();
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
btn.textContent = 'STREAM ON';
btn.classList.add('active');
}
async function syncState() {
try {
var res = await fetch('/api/state');
@@ -767,6 +781,7 @@ function applyState(data) {
document.getElementById('video-status').innerHTML =
'<span style="width:5px;height:5px;background:var(--success);display:inline-block;"></span> streaming ' + (data.file_name || '');
document.getElementById('video-status').className = 'video-status connected';
enablePreview();
loadBatchResult(data.file);
} else if (data.file && selectedFile === data.file) {