Add first live-view flow from the camera wall

This commit is contained in:
OpenClaw
2026-04-19 02:49:52 +00:00
parent 85fddca6ea
commit 79b3b33f85
5 changed files with 129 additions and 1 deletions

View File

@@ -2,13 +2,21 @@ sub init()
m.top.setFocus(true)
m.backend = m.top.findNode("backend")
m.status = m.top.findNode("status")
m.help = m.top.findNode("help")
m.refreshTimer = m.top.findNode("refreshTimer")
m.liveVideo = m.top.findNode("liveVideo")
m.cameraPosters = [
m.top.findNode("poster1"),
m.top.findNode("poster2"),
m.top.findNode("poster3"),
m.top.findNode("poster4")
]
m.cameraFrames = [
m.top.findNode("frame1"),
m.top.findNode("frame2"),
m.top.findNode("frame3"),
m.top.findNode("frame4")
]
m.cameraNodes = [
m.top.findNode("cam1"),
m.top.findNode("cam2"),
@@ -16,6 +24,8 @@ sub init()
m.top.findNode("cam4")
]
m.refreshToken = 0
m.selectedIndex = 0
m.isLiveView = false
loadConfig()
end sub
@@ -48,6 +58,7 @@ sub loadConfig()
m.refreshTimer.control = "start"
renderCameras()
updateSelection()
end sub
sub renderCameras()
@@ -74,10 +85,93 @@ sub renderCameras()
end sub
sub onRefreshTimerFire()
if m.isLiveView then
return
end if
m.refreshToken = m.refreshToken + 1
renderCameras()
end sub
function onKeyEvent(key as String, press as Boolean) as Boolean
if not press then
return false
end if
lower = LCase(key)
if m.isLiveView then
if lower = "back" then
closeLiveView()
return true
end if
return false
end if
if lower = "right" and m.selectedIndex mod 2 = 0 and m.selectedIndex + 1 < m.config.cameras.count() then
m.selectedIndex = m.selectedIndex + 1
updateSelection()
return true
else if lower = "left" and m.selectedIndex mod 2 = 1 then
m.selectedIndex = m.selectedIndex - 1
updateSelection()
return true
else if lower = "down" and m.selectedIndex < 2 and m.selectedIndex + 2 < m.config.cameras.count() then
m.selectedIndex = m.selectedIndex + 2
updateSelection()
return true
else if lower = "up" and m.selectedIndex >= 2 then
m.selectedIndex = m.selectedIndex - 2
updateSelection()
return true
else if lower = "ok" then
openLiveView()
return true
end if
return false
end function
sub updateSelection()
for i = 0 to m.cameraFrames.count() - 1
if i = m.selectedIndex then
m.cameraFrames[i].color = "0x2EA043FF"
else
m.cameraFrames[i].color = "0x1F262DFF"
end if
end for
end sub
sub openLiveView()
if m.config = invalid or not m.config.doesExist("cameras") or m.selectedIndex >= m.config.cameras.count() then
return
end if
camera = m.config.cameras[m.selectedIndex]
liveUrl = buildLiveUrl(m.config, camera)
content = CreateObject("roSGNode", "ContentNode")
content.url = liveUrl
content.streamformat = "hls"
content.title = camera.name
m.liveVideo.content = content
m.liveVideo.visible = true
m.liveVideo.control = "play"
m.isLiveView = true
m.status.text = "Live view: " + camera.name
m.help.text = "Press Back to return to the snapshot wall."
end sub
sub closeLiveView()
m.liveVideo.control = "stop"
m.liveVideo.visible = false
m.isLiveView = false
m.status.text = "Refreshing every " + m.refreshTimer.duration.toStr() + "s"
m.help.text = "Use arrows to choose a camera. Press OK for live view. Press Back to return."
m.top.setFocus(true)
end sub
function buildSnapshotUrl(config as Object, camera as Object) as String
if not config.doesExist("backend") or not config.backend.doesExist("baseUrl") then
return ""
@@ -112,3 +206,20 @@ function addCacheBust(url as String) as String
return url + "?cb=" + token
end function
function buildLiveUrl(config as Object, camera as Object) as String
if not config.doesExist("live") or not config.live.doesExist("baseUrl") or not camera.doesExist("frigateCamera") then
return ""
end if
baseUrl = config.live.baseUrl
path = "/api/stream.m3u8?src=" + camera.frigateCamera
if right(baseUrl, 1) = "/" and left(path, 1) = "/" then
return left(baseUrl, len(baseUrl) - 1) + path
else if right(baseUrl, 1) <> "/" and left(path, 1) <> "/" then
return baseUrl + "/" + path
end if
return baseUrl + path
end function