strix

A simple web UI for motion
git clone https://www.brianlane.com/git/strix
Log | Files | Refs | LICENSE

commit b73611102b1a704892a0256e89d1b68359ef1b40
parent 6f9645b1427b5e2d286ee7bb18536a92ddeca840
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Sat, 26 Feb 2022 15:48:50 -0800

Add a page to display all events for a selected camera.

Clicking on a thumbnail now takes you to the new page, with the selected
video playing. Clicking on any of the thumbnails on the page will jump
back to the top and play the selected event.

TODO: Make the playback smaller, and scroll the bottom independent from
the video player at the top.

Diffstat:
Asrc/strix/ui/events.html | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/strix/ui/index.html | 2+-
Msrc/strix/ui/style.css | 12++++++++++++
3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/src/strix/ui/events.html b/src/strix/ui/events.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset=UTF-8> + <meta name="viewport" content="width=device-width"> + <title>Strix - Motion Camera UI - Camera Events</title> + <link href="/style.css" rel="stylesheet" type="text/css" /> +</head> +<body> + <div id="viewer"> + <video controls autoplay=false playsinline=true></video> + </div> + <div id="calendar"></div> + <div id="events"></div> + + +<script type="text/javascript"> +var camera_events; + +function nice_time_string(time_str) { + var d = new Date(time_str); + // DoW Mo Day Year + var fields = d.toDateString().split(" "); + return fields.slice(0,3).join(" ") + " " + d.toLocaleTimeString(); +} + +function get_all_events(camera_name) { + // The API returns the events with the oldest one first in the .events list + fetch("/api/events/"+camera_name+"?limit=0") + .then(resp => resp.json()) + .then(data => { + // Save for onclick actions + camera_events = data.events[camera_name]; + var events = document.querySelector("#events"); + // Try to get the size of the thumbnail images + let oneImg = document.createElement("img"); + oneImg.onload = function() { + width = this.width; + height = this.height; + html = data.events[camera_name].map(event => { + let alt = nice_time_string(event.start); + return `<img class="thumbnail" + onclick="javascript:load_viewer('${event.video}');" + title="${alt}" + loading="lazy" + width=${width} + height=${height} + src="${event.thumbnail}" />` + }).reverse().join("\n"); + events.innerHTML = html; + } + // Load the 1st thumbnail, triggering onload for it + oneImg.src = data.events[camera_name][0].thumbnail; + }); +} + +function load_viewer(event) { + scroll(0,0); + + // Set the viewere to the event video + var viewer = document.querySelector("#viewer video"); + viewer.src = event; + viewer.autoplay = true; + +} + +function setup_page() { + let params = new URLSearchParams(document.location.search); + let camera = params.get("camera"); + if (camera == null) { + return; + } + let event = params.get("event"); + + // Get the events for this camera from the API server and populate the page + get_all_events(camera); + + // Load the viewer with the event, if one was selected + if (event != null) { + load_viewer(event); + } +} + +setup_page(); +</script> +</body> +</html> diff --git a/src/strix/ui/index.html b/src/strix/ui/index.html @@ -40,7 +40,7 @@ function get_events(camera_name, offset, limit) { var videos = Array.from(document.querySelectorAll("#"+camera_name+" td.thumbnails div > a")) videos.forEach(video => { event = data.events[camera_name][idx]; - video.href=event.video; + video.href="events.html?camera="+camera_name+"&event="+event.video; video.title=nice_time_string(event.start); img = video.firstChild; img.src = event.thumbnail; diff --git a/src/strix/ui/style.css b/src/strix/ui/style.css @@ -14,6 +14,17 @@ body { } } +#viewer { +} + +video { + width: 100%; + height: 100%; +} + +#events { +} + td.prev,td.next { background: white; border: 1px solid; @@ -33,6 +44,7 @@ td.prev:hover,td.next:hover { img.thumbnail { width: 20%; + height: auto; display: block; float: left; }