I have a task to show a surveillance camera stream inside a popup: there’s a button with a photo; when I click it, a popup opens where a WebRTC stream from the camera is displayed. The problem is that if I enable autoplay on oh-video, the stream keeps playing even when the popup is closed (I can even hear the audio). If I disable autoplay and use the “hack” that GPT suggested, it starts when the popup opens, but randomly. How do people solve this seemingly trivial task? Here is the poorly working solution from GPT:
uid: home-sidebar
tags: []
props: {}
timestamp: Dec 24, 2025, 2:11:30 AM
component: div
config: {}
slots:
default:
- component: widget:button
config:
background: /static/snapshots/EntryGateDoorbell_snapshot.jpg
description: Вхід
popup: "#EntryGateDoorbell"
- component: widget:button
config:
background: /static/snapshots/ParkingCamera_snapshot.jpg
description: Парковка
popup: "#ParkingCamera"
- component: f7-popup
config:
1opened: =(items["EntryGateDoorbell_Ring"].state == 'OPEN') ? true:false
id: EntryGateDoorbell
push: true
swipeToClose: true
top: true
slots:
default:
- component: div
config:
id: EntryGateDoorbell2
slots:
default:
- component: f7-navbar
config:
title: Хвіртка
slots:
default:
- component: f7-nav-right
slots:
default:
- component: f7-link
config:
iconMaterial: close
popupClose: true
- component: oh-video
config:
action: '=device.android ? "url" : ""'
actionUrl: unifi-protect://deeplink_v1/home/dashboard/
hideControls: false
item: EntryGateDoorbell_RTS
playerType: webrtc
posterItem: EntryGateDoorbell_Image
sendAudio: true
startManually: true
style:
min-height: 200px
width: 100%
- component: widget:button
config:
bgcolorOFF: orange
buttonitem: EntryGate_Control
compact: true
confirmation: Справді відкрити?
description: Хвіртку
icon: material:lock_open
itemname: Відкрити
- component: f7-popup
config:
id: ParkingCamera
opened: =(items["ParkingGate_Opened"].state == 'OPEN') ? true:false
push: true
swipeToClose: true
top: true
slots:
default:
- component: div
config:
id: ParkingCamera2
slots:
default:
- component: f7-navbar
config:
title: Парковка
slots:
default:
- component: f7-nav-right
slots:
default:
- component: f7-link
config:
iconMaterial: close
popupClose: true
- component: oh-video
config:
action: '=device.android ? "url" : ""'
actionUrl: unifi-protect://deeplink_v1/home/dashboard/
hideControls: false
item: ParkingCamera_RTS
playerType: webrtc
posterItem: ParkingCamera_Image
startManually: true
style:
min-height: 200px
width: 100%
- component: widget:button
config:
bgcolorOFF: red
buttonitem: ParkingGate_Control
compact: true
confirmation: Справді відкрити?
description: Ворота
icon: material:lock_open
itemname: Відкрити
visible: =items["ParkingGate_Opened"].state == "CLOSED"
- component: widget:button
config:
bgcolorOFF: green
buttonitem: ParkingGate_Control
compact: true
confirmation: Справді закрити?
description: Ворота
icon: material:lock_outline
itemname: Закрити
visible: =items["ParkingGate_Opened"].state != "CLOSED"
- component: script
config:
text: |
(function () {
function init(id) {
let popup = document.getElementById(id);
if (!popup || popup.__webrtcHooked) return;
popup.__webrtcHooked = true;
popup.addEventListener('popup:open', (e) => {
const v = e.target.querySelector('video');
if (v) {
console.log('+');
v.play().catch((e) => {
console.log(e)
});
const s = v.srcObject;
if (s && typeof s.getTracks === 'function') {
s.getTracks().forEach(t => t.enabled = true);
}
}
});
popup.addEventListener('popup:closed', (e) => {
const v = e.target.querySelector('video');
if (!v) return;
v.pause();
const s = v.srcObject;
if (s && typeof s.getTracks === 'function') {
s.getTracks().forEach(t => t.enabled = false);
}
});
};
init('EntryGateDoorbell');
init('ParkingCamera');
})();