strix

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

index.html (4604B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset=UTF-8>
      5     <meta name="viewport" content="width=device-width">
      6     <title>Strix - Motion Camera UI</title>
      7     <link href="/style.css" rel="stylesheet" type="text/css" />
      8 </head>
      9 <body>
     10 <div id="live-feeds">
     11 </div>
     12 <script type="text/javascript">
     13 var cameras = [];
     14 
     15 function set_feed_href() {
     16     var feeds = Array.from(document.querySelectorAll(".feed-href"));
     17     feeds.forEach(feed => {
     18         feed.href = "//" + location.hostname + ":" + feed.attributes["data-port"].value;
     19     });
     20 }
     21 
     22 function set_feed_src() {
     23     var feeds = Array.from(document.querySelectorAll(".feed-src"));
     24     feeds.forEach(feed => {
     25         feed.src = "//" + location.hostname + ":" + feed.attributes["data-port"].value + "/video.mjpeg?rand=" + Math.random();
     26     });
     27 }
     28 
     29 function get_events(camera_name, offset, limit) {
     30     // The API returns the events with the oldest one first in the .events list
     31     fetch("/api/events/"+camera_name+"?offset="+offset+"&limit="+limit)
     32         .then(resp => resp.json())
     33         .then(data => {
     34             var idx = 0;
     35             var videos = Array.from(document.querySelectorAll("#"+camera_name+" td.thumbnails div > a"))
     36             videos.forEach(video => {
     37                 event = data.events[camera_name][idx];
     38                 video.href="events.html?camera="+camera_name+"&event="+event.video;
     39                 video.title=event.title;
     40                 img = video.firstChild;
     41                 img.src = event.thumbnail;
     42                 idx++;
     43             });
     44         });
     45 }
     46 
     47 function prev_events(e) {
     48     // e.target.offsetParent.ParentNode.id has the CameraX class
     49     // Not too sure how reliable that is...
     50     let camera_name = e.target.offsetParent.parentNode.id;
     51     event_offsets.set(camera_name, event_offsets.get(camera_name) + 5);
     52     get_events(camera_name, event_offsets.get(camera_name), 5);
     53 
     54 }
     55 
     56 function next_events(e) {
     57     let camera_name = e.target.offsetParent.parentNode.id;
     58     if(event_offsets.get(camera_name) >=5) {
     59         event_offsets.set(camera_name, event_offsets.get(camera_name) - 5);
     60     } else {
     61         event_offsets.set(camera_name, 0);
     62     }
     63     get_events(camera_name, event_offsets.get(camera_name), 5);
     64 }
     65 
     66 // Update all thumbnails that haven't been changed by the user
     67 function update_events() {
     68     cameras.map(camera => {
     69         var camera_name = camera[0];
     70         if (event_offsets.get(camera_name) == 0) {
     71             get_events(camera_name, 0, 5);
     72         }
     73     });
     74 }
     75 
     76 function setup_page() {
     77     event_offsets = new Map();
     78 
     79     // Setup the camera HTML
     80     var live_feeds = document.querySelector("#live-feeds");
     81     var html = cameras.map(camera => {
     82         var camera_name = camera[0];
     83         var port = camera[1];
     84         return `<div class="feed" id="${camera_name}">
     85             <table>
     86             <tr><a href="" class="feed-href" data-port="${port}"><img src="#" class="feed-src" data-port="${port}"></a></tr>
     87             <tr class="controls">
     88             <td class="prev">&lt</td>
     89             <td class="thumbnails"><div>
     90             <a class="video" target="video" href="/"><img class="thumbnail" src="/" /></a><a class="video" target="video" href="/"><img class="thumbnail" src="/" /></a><a class="video" target="video" href="/"><img class="thumbnail" src="/" /></a><a class="video" target="video" href="/"><img class="thumbnail" src="/" /></a><a class="video" target="video" href="/"><img class="thumbnail" src="/" /></a>
     91             </div></td>
     92             <td class="next">&gt</td></tr>
     93             </table>
     94             </div>`;
     95     }).join("");
     96     live_feeds.innerHTML = html;
     97 
     98     set_feed_href();
     99     set_feed_src();
    100 
    101     var prev_buttons = Array.from(document.querySelectorAll(".prev"));
    102     prev_buttons.forEach(button => button.addEventListener("click", prev_events));
    103     var next_buttons = Array.from(document.querySelectorAll(".next"));
    104     next_buttons.forEach(button => button.addEventListener("click", next_events));
    105 
    106     // Grab the initial events for each camera
    107     cameras.map(camera => {
    108         var camera_name = camera[0];
    109         var port = camera[1];
    110         event_offsets.set(camera_name, 0);
    111         get_events(camera_name, 0, 5);
    112     });
    113 
    114     // Update un-modified thumbnails every 30 seconds
    115     setInterval(update_events, 30 * 1000);
    116 }
    117 
    118 // First thing to do is get the list of cameras, then setup the page.
    119 fetch("/api/cameras/list")
    120     .then(resp => resp.json())
    121     .then(data => {
    122         // This is a global variable, used by several functions
    123         cameras = data.cameras;
    124         setup_page();
    125     });
    126 </script>
    127 </body>
    128 </html>