fix: real camera online status — checks latest.jpg modification time

This commit is contained in:
Claus Lohmar 2026-08-10 07:03:31 +01:00
parent dc15b8ffd4
commit 953360d251
2 changed files with 21 additions and 3 deletions

22
api.go
View file

@ -13,6 +13,7 @@ import (
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"os" "os"
"path/filepath"
"strings" "strings"
"time" "time"
) )
@ -27,9 +28,19 @@ func (s *Server) handleCameras(w http.ResponseWriter, r *http.Request) {
statuses := make([]CameraStatus, 0, len(s.appConfig.Cameras)) statuses := make([]CameraStatus, 0, len(s.appConfig.Cameras))
for _, cam := range s.appConfig.Cameras { for _, cam := range s.appConfig.Cameras {
online := false
// Check if latest.jpg was recently updated.
camDir := cam.Name
if camDir == "" {
camDir = cam.ID
}
snapFile := filepath.Join(s.appConfig.Storage.RecordingsPath, camDir, "latest.jpg")
if info, err := os.Stat(snapFile); err == nil {
online = time.Since(info.ModTime()) < 10*time.Second
}
statuses = append(statuses, CameraStatus{ statuses = append(statuses, CameraStatus{
CameraConfig: cam, CameraConfig: cam,
Online: false, // TODO: real stream health check in M2 Online: online,
Uptime: "n/a", Uptime: "n/a",
Streams: 0, Streams: 0,
}) })
@ -56,9 +67,16 @@ func (s *Server) handleCameraByID(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
online := false
camDir := cam.Name
if camDir == "" { camDir = cam.ID }
snapFile := filepath.Join(s.appConfig.Storage.RecordingsPath, camDir, "latest.jpg")
if info, err := os.Stat(snapFile); err == nil {
online = time.Since(info.ModTime()) < 10*time.Second
}
status := CameraStatus{ status := CameraStatus{
CameraConfig: *cam, CameraConfig: *cam,
Online: false, Online: online,
Uptime: "n/a", Uptime: "n/a",
Streams: 0, Streams: 0,
} }

View file

@ -104,7 +104,7 @@ function renderLiveGrid() {
<img src="${snapURL}" class="grid-snap" loading="lazy" <img src="${snapURL}" class="grid-snap" loading="lazy"
onerror="this.parentElement.classList.add('offline')" onerror="this.parentElement.classList.add('offline')"
style="width:100%;height:100%;object-fit:cover;position:absolute;inset:0" alt="${cam.name}"> style="width:100%;height:100%;object-fit:cover;position:absolute;inset:0" alt="${cam.name}">
<span class="tile-status online"></span> <span class="tile-status ${cam.online ? 'online' : 'offline'}"></span>
<span class="tile-label">${cam.name}</span> <span class="tile-label">${cam.name}</span>
`; `;
tile.addEventListener('click', () => openFocus(cam)); tile.addEventListener('click', () => openFocus(cam));