aboutsummaryrefslogtreecommitdiff
path: root/templates/client.html
diff options
context:
space:
mode:
Diffstat (limited to 'templates/client.html')
-rw-r--r--templates/client.html173
1 files changed, 173 insertions, 0 deletions
diff --git a/templates/client.html b/templates/client.html
new file mode 100644
index 0000000..785fbcf
--- /dev/null
+++ b/templates/client.html
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Client {{ client_id }} - Camera Streams</title>
+ <link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}">
+ <style>
+ .camera-stream { display: inline-block; margin: 10px; }
+ video { border: 1px solid #333; }
+ </style>
+</head>
+<body>
+ <h1>Camera Streams for client: {{ client_id }}</h1>
+ <div class="streams-container">
+ {% for camera_id in camera_ids %}
+ <div class="camera-stream">
+ <h2>Camera: {{ camera_id }}</h2>
+ <img
+ id="video-{{ camera_id }}"
+ width="640"
+ height="480" />
+ <div>
+ <h3>Modify Camera Name</h3>
+ <input
+ type="text"
+ id="new-name-{{ camera_id }}"
+ placeholder="New Name"
+ required pattern= "^\S+$"
+ title="No whitespace allowed.">
+ <button onclick="sendConfig('{{ camera_id }}', 'modify_camera_name')">Send</button>
+ </div>
+ <div>
+ <h3>Modify Camera Threshold</h3>
+ <input
+ type="number"
+ id="threshold-value-{{ camera_id }}"
+ placeholder="Threshold"
+ required step="1"
+ min="0"
+ inputmode="numeric"
+ title="Enter a non-negative integer.">
+ <button onclick="sendConfig('{{ camera_id }}', 'modify_camera_threshold')">Send</button>
+ </div>
+ <div>
+ <h3>Modify Camera Grace Period</h3>
+ <input
+ type="number"
+ id="grace-value-{{ camera_id }}"
+ placeholder="Grace Period"
+ required step="1"
+ min="0"
+ inputmode="numeric"
+ title="Enter a non-negative integer.">
+ <button onclick="sendConfig('{{ camera_id }}', 'modify_camera_grace_pd')">Send</button>
+ </div>
+ <div>
+ <h3>Recorded Videos for {{ camera_id }}</h3>
+ <ul id="video-list-{{ camera_id }}" class="scroll-box">
+ {% for filename, video_url, timestamp in client_videos[camera_id] %}
+ <li><a href="{{ video_url }}">{{ filename }}</a> ({{ timestamp }})</li>
+ <!-- <h3>video file: {{ filename }}</h3>
+ <video src="{{ video_url }}" type="video/ogg" width="320" height="240" controls></video>
+ <hr4>creation: {{ timestamp }}</h3>
+ -->
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+ {% endfor %}
+<!--
+ <div>
+ <h3>Add Camera</h3>
+ <input type="text" id="add-name" placeholder="Camera Name">
+ <input type="text" id="add-address" placeholder="Address">
+ <button onclick="sendConfig('add_camera')">Send</button>
+ </div>
+-->
+ <div>
+ <h3>Remove Camera</h3>
+ <input
+ type="text"
+ id="remove-name"
+ placeholder="Camera Name"
+ required pattern="^\S+$"
+ title="No whitespace allowed.">
+ <button onclick="sendConfig('remove_camera')">Send</button>
+ </div>
+ </div>
+ <script>
+ const wsMap = {};
+ {% for camera_id in camera_ids %}
+ // For each camera, open a WebSocket and update the corresponding <img>
+ (function() {
+ const cameraId = '{{ camera_id }}';
+ const ws = new WebSocket('ws://' + window.location.host + '/ws/{{ client_id }}/' + cameraId);
+ let currentUrl = null;
+ ws.onmessage = function(event) {
+ let image = document.getElementById('video-' + cameraId);
+ if (currentUrl) {
+ URL.revokeObjectURL(currentUrl);
+ }
+ currentUrl = URL.createObjectURL(event.data);
+ image.src = currentUrl;
+ };
+ ws.onclose = function(event) {
+ console.log('WebSocket closed for camera ' + cameraId + ':', event);
+ };
+ ws.onerror = function(event) {
+ console.log('WebSocket error for camera ' + cameraId + ':', event);
+ };
+ window.addEventListener('beforeunload', function() {
+ ws.close();
+ });
+ wsMap[cameraId] = ws;
+ })();
+ // FIXME: Move to a separate function
+ // For each camera, open a WebSocket to receive notificationf about new videos
+ // (function() {
+ // const cameraId = '{{ camera_id }}';
+ // const wsVideos = new WebSocket('ws://' + window.location.host + '/ws/{{ client_id }}/' + cameraId + '/videos');
+ // wsVideos.onmessage = function(event) {
+ // let videoFilename = event.data;
+ // console.log('New video available for camera ' + cameraId + ': ' + videoFilename);
+ // // On new video notification,
+ // };
+ // })();
+ {% endfor %}
+
+ function sendConfig(cameraId, type) {
+ let msg = {};
+ switch(type) {
+ case 'modify_camera_name':
+ msg[type] = [
+ document.getElementById('new-name-' + cameraId).value
+ ];
+ break;
+ case 'modify_camera_threshold':
+ msg[type] = [
+ document.getElementById('threshold-value-' + cameraId).value
+ ];
+ break;
+ case 'modify_camera_grace_pd':
+ msg[type] = [
+ parseInt(document.getElementById('grace-value-' + cameraId).value)
+ ];
+ break;
+ case 'modify_camera_address':
+ msg[type] = [
+ document.getElementById('address-value-' + cameraId).value
+ ];
+ break;
+ // case 'add_camera':
+ // msg[type] = [
+ // document.getElementById('add-name').value,
+ // document.getElementById('add-address').value
+ // ];
+ // break;
+ case 'remove_camera':
+ msg[type] = [
+ document.getElementById('remove-name').value
+ ];
+ break;
+ }
+ const ws = wsMap[cameraId] && wsMap[cameraId] ? wsMap[cameraId] : Object.values(wsMap)[0];
+ if (ws && ws.readyState === WebSocket.OPEN) {
+ console.log("Sending message:", msg, "on ws:", ws);
+ ws.send(JSON.stringify(msg));
+ } else {
+ alert('WebSocket is not open for camera ' + cameraId);
+ }
+ }
+ </script>
+</body>
+</html>