Live Counter get total count per batch
This commit is contained in:
1 parent
fe220504fd
commit
e3ae89de3d
4 files changed
+82
-1
No files matched your search
@@ -98,6 +98,7 @@ api: GET /api/live-video → MJPEG stream from shared-memory JPEG
|
||||
api: GET / → recounting HTML
|
||||
api: GET /api/live-progress → proxy to LIVE_API_URL:/api/current-batch
|
||||
api: GET /api/recount-progress → proxy to RECOUNT_API_URL:/api/current-batch
|
||||
api: GET /api/batch-result?file=<path> → parse `batch_NN_YYYYMMDD_HHmmSS.mp4`, query live API for count
|
||||
api: GET /api/mp4-files → [ {name, path, size, mtime} ... ]
|
||||
api: POST /api/start-recount {path} → configure go2rtc stream, return {stream_url}
|
||||
api: POST /api/stop-recount → tear down go2rtc stream
|
||||
|
||||
@@ -5,6 +5,7 @@ lists OUTPUT_DIR MP4 files, streams via go2rtc for preview.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import requests
|
||||
from datetime import datetime
|
||||
@@ -34,6 +35,18 @@ FLASK_DEBUG = os.getenv("FLASK_DEBUG", "false").lower() == "true"
|
||||
_http_session = requests.Session()
|
||||
_http_session.timeout = 3
|
||||
|
||||
_FILENAME_RE = re.compile(r"batch_(\d+)_(\d{8})_\d{6}\.mp4")
|
||||
|
||||
|
||||
def _parse_filename(filename):
|
||||
m = _FILENAME_RE.match(filename)
|
||||
if m:
|
||||
batch_num = int(m.group(1))
|
||||
date_str = m.group(2)
|
||||
date_formatted = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
|
||||
return batch_num, date_formatted
|
||||
return None, None
|
||||
|
||||
|
||||
def _api_get(base_url, path, default=None):
|
||||
try:
|
||||
@@ -107,6 +120,32 @@ def start_recount():
|
||||
return jsonify({"success": True, "stream_url": stream_url, "file": Path(mp4_path).name})
|
||||
|
||||
|
||||
@app.route("/api/batch-result")
|
||||
def api_batch_result():
|
||||
fpath = request.args.get("file", "")
|
||||
filename = Path(fpath).name
|
||||
batch_num, date_str = _parse_filename(filename)
|
||||
if batch_num is None:
|
||||
return jsonify({"success": False, "error": "Cannot parse batch number from filename"}), 200
|
||||
|
||||
data = _api_get(LIVE_API_URL, f"/api/day-detail/{date_str}")
|
||||
if not data:
|
||||
return jsonify({"success": False, "error": "Live API unreachable"}), 200
|
||||
|
||||
for b in data.get("batches", []):
|
||||
if b.get("batch_number") == batch_num:
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"batch_number": batch_num,
|
||||
"date": date_str,
|
||||
"count": b["count"],
|
||||
"start_time": b.get("start_time"),
|
||||
"end_time": b.get("end_time"),
|
||||
})
|
||||
|
||||
return jsonify({"success": False, "error": f"Batch #{batch_num} not found on {date_str}"}), 200
|
||||
|
||||
|
||||
@app.route("/api/stop-recount", methods=["POST"])
|
||||
def stop_recount():
|
||||
try:
|
||||
|
||||
@@ -4,3 +4,4 @@ opencv-python
|
||||
flask
|
||||
python-dotenv
|
||||
openpyxl
|
||||
requests
|
||||
@@ -356,6 +356,22 @@
|
||||
<div class="counter-status disconnected" id="live-status">
|
||||
waiting...
|
||||
</div>
|
||||
<div class="batch-result" id="batch-result" style="display:none;margin-top:16px;padding:12px;border-top:1px solid var(--divider);">
|
||||
<div style="font-size:9px;color:var(--text-secondary);letter-spacing:1px;text-transform:uppercase;margin-bottom:6px;">
|
||||
Selected Batch Result
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:center;gap:32px;">
|
||||
<div>
|
||||
<div style="font-size:8px;color:var(--text-secondary);letter-spacing:1px;">BATCH</div>
|
||||
<div style="font-family:'Orbitron',sans-serif;font-size:20px;font-weight:700;color:var(--accent);" id="br-batch">--</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size:8px;color:var(--text-secondary);letter-spacing:1px;">COUNT</div>
|
||||
<div style="font-family:'Orbitron',sans-serif;font-size:20px;font-weight:700;color:var(--accent4);" id="br-count">--</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:9px;color:var(--text-secondary);margin-top:6px;" id="br-date">--</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
@@ -467,7 +483,31 @@ function selectFile(path, name) {
|
||||
selectedFile = path;
|
||||
document.getElementById('btn-start').disabled = false;
|
||||
document.getElementById('stream-file-name').textContent = name;
|
||||
loadFiles(); // refresh selection
|
||||
loadFiles();
|
||||
loadBatchResult(path);
|
||||
}
|
||||
|
||||
async function loadBatchResult(filePath) {
|
||||
const el = document.getElementById('batch-result');
|
||||
if (!filePath) {
|
||||
el.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetch('/api/batch-result?file=' + encodeURIComponent(filePath));
|
||||
const data = await res.json();
|
||||
if (!data.success) {
|
||||
el.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
document.getElementById('br-batch').textContent = '#' + data.batch_number;
|
||||
document.getElementById('br-count').textContent = data.count.toLocaleString();
|
||||
document.getElementById('br-date').textContent = data.date;
|
||||
el.style.display = 'block';
|
||||
} catch (err) {
|
||||
console.error('Failed to load batch result:', err);
|
||||
el.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function formatSize(bytes) {
|
||||
|
||||
Reference in new issue
Block a user