Skip to content

Commit

Permalink
v1.11.5 (#691)
Browse files Browse the repository at this point in the history
* ignore missing IP #677

* Autoplay related changes #690

* Version bump
  • Loading branch information
mrlt8 committed Jan 24, 2023
1 parent a46693c commit 20f218c
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 61 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ You can then use the web interface at `http://localhost:5000` where localhost is

See [basic usage](#basic-usage) for additional information.

## What's Changed in v1.11.5

- FIX: WebRTC - signaling URL to match request host. #684 Thanks @JA16122000!
- FIX: WebUI - don't start socket connection until play/don't autoplay if on-demand cam is NOT connected. #690
- NEW: WebUI - add toggle to switch between HLS/WebRTC.

## What's Changed in v1.11.4

- FIX: Switching between webrtc/hls was broken in the WebUI (`?webrtc`/`?hls`)
Expand Down
6 changes: 6 additions & 0 deletions app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## What's Changed in v1.11.5

- FIX: WebRTC - signaling URL to match request host. #684 Thanks @JA16122000!
- FIX: WebUI - don't start socket connection until play/don't autoplay if on-demand cam is NOT connected. #690
- NEW: WebUI - add toggle to switch between HLS/WebRTC.

## What's Changed in v1.11.4

- FIX: Switching between webrtc/hls was broken in the WebUI (`?webrtc`/`?hls`)
Expand Down
2 changes: 1 addition & 1 deletion app/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"slug": "docker-wyze-bridge",
"url": "https://github.com/mrlt8/docker-wyze-bridge",
"image": "mrlt8/wyze-bridge",
"version": "1.11.4",
"version": "1.11.5",
"arch": [
"armv7",
"aarch64",
Expand Down
52 changes: 44 additions & 8 deletions app/static/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ section {
flex: 1;
}

.tabs a,
.preview-toggle .button,
.card,
.navbar-menu,
.dropdown-content,
.dropdown-item,
.footer {
background-color: #363636;
color: #fff;
Expand All @@ -26,12 +24,14 @@ section {
margin-bottom: 0;
}

.dropdown-content,
.dropdown-item,
.content table {
color: #fff;
background-color: #292929;
}

.tabs.is-toggle a {
.preview-toggle .button {
border-color: #363636;
}

Expand All @@ -55,20 +55,20 @@ a:hover {
color: #1dd2af;
}

.tabs.is-toggle a:hover,
.preview-toggle .button:not(.is-active):hover,
.card-footer a:hover {
background-color: #292929;
border-color: #292929;
color: #009670;
}

.tabs.is-toggle li.is-active a {
.preview-toggle .button.is-active {
background-color: #00bc8c;
border-color: #00bc8c
}

.tabs.is-toggle li.is-active a:hover {
background-color: #00a077
.preview-toggle .button.is-active:hover {
background-color: #00a077;
}

code {
Expand Down Expand Up @@ -127,13 +127,49 @@ video {
top: 0;
}

video.webrtc.placeholder,
video.webrtc.placeholder+span,
.status .fa-circle-play,
.status .fa-circle-pause,
.status .fa-satellite-dish,
.fa-arrows-rotate {
cursor: pointer;
}

video,
video.webrtc+.fas {
display: block;
}

figure.image:hover>video.webrtc.placeholder {
transition: .3s ease;
background-color: transparent;
opacity: 0.8;
}

video.webrtc+i::before {
color: white;
font-size: 4rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-shadow: 2px 2px #444;
}

video.webrtc.placeholder+i::before {
content: "\f144";
}

video.webrtc.lost+i::before {
content: "\e560";
}

video.webrtc.lost,
video.webrtc.lost+i {
cursor: default;
}

.card-image:has([src$=".svg"]) {
background-color: #000;
}
Expand Down
75 changes: 57 additions & 18 deletions app/static/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function applyPreferences() {
sortOrder = sortOrder.replace(/\\054/g, ",").replace(/["]+/g, '')
setCookie("camera_order", sortOrder)
}
if (!sortOrder) { return; }
console.debug("applyPreferences camera_order", sortOrder);
const ids = sortOrder.split(",");
var cameras = [...document.querySelectorAll(".camera")];
Expand Down Expand Up @@ -439,15 +440,15 @@ document.addEventListener("DOMContentLoaded", () => {
sse.addEventListener("message", (e) => {
Object.entries(JSON.parse(e.data)).forEach(([cam, status]) => {
const statusIcon = document.querySelector(`#${cam} .status i.fas`);
const preview = document.querySelector(`#${cam} img.refresh_img`);
const preview = document.querySelector(`#${cam} img.refresh_img,video[data-cam='${cam}']`);
statusIcon.setAttribute("class", "fas")
statusIcon.parentElement.title = ""
if (preview) { preview.classList.remove("connected") }
if (status == "connected") {
statusIcon.classList.add("fa-circle-play", "has-text-success");
statusIcon.parentElement.title = "Click/tap to pause";
autoplay();
if (preview) { preview.classList.add("connected") }
autoplay();
let noPreview = document.querySelector(`#${cam} .no-preview`)
if (noPreview) {
let fig = noPreview.parentElement
Expand Down Expand Up @@ -572,29 +573,67 @@ document.addEventListener("DOMContentLoaded", () => {
})
toggleFullscreen()

// Load WS for WebRTC on demand
function loadWebRTC(video) {
if (!video.classList.contains("placeholder") || !video.classList.contains("connected")) { return }
let videoFormat = getCookie("video");
video.classList.remove("placeholder");
video.controls = true;
fetch(`signaling/${video.dataset.cam}?${videoFormat}`).then((resp) => resp.json()).then((data) => new Receiver(data));
}
// Click to load WebRTC
document.querySelectorAll("video.webrtc.placeholder").forEach((v) => {
v.parentElement.addEventListener("click", () => loadWebRTC(v), { once: true });
});
// Auto-play video
function autoplay(action) {
let videos = document.querySelectorAll('video');
if (action == "stop") {
if (action === "stop") {
videos.forEach(video => {
if (video.classList.contains("vjs-tech")) { videojs(video).pause() } else {
video.load();
video.controls = false;
video.classList.add("lost");
// show poster on lost connection
}
});
} else {
let autoPlay = getCookie("autoplay");
videos.forEach(video => {
if (video.classList.contains("vjs-tech")) { video = videojs(video); } else {
video.controls = true;
}
if (autoPlay) { video.play(); }
});
return;
}
let autoPlay = getCookie("autoplay");
videos.forEach(video => {
if (video.classList.contains("vjs-tech")) { video = videojs(video); } else {
video.classList.remove("lost");
}
if (autoPlay) {
if (video.classList.contains("webrtc")) {
loadWebRTC(video);
}
video.play();
}
});
}
document.querySelector("#enable-autoplay").addEventListener("change", box => {
setCookie("autoplay", box.target.checked);
autoplay();
// Change default video format for WebUI
document.querySelectorAll(".preview-toggle [data-action]").forEach((e) => {
e.addEventListener("click", () => {
let videoCookie = getCookie("show_video")
setCookie("show_video", "1");
switch (e.dataset.action) {
case "snapshot":
setCookie("show_video", "");
break;
case "autoplay":
let icon = e.querySelector("i.fas").classList;
let playCookie = !!getCookie("autoplay");
setCookie("autoplay", !playCookie);
if (playCookie) { icon.replace("fa-square-check", "fa-square"); return; }
icon.replace("fa-square", "fa-square-check")
if (videoCookie) { autoplay(); return; }
break;
case "webrtc":
case "hls":
case "kvs":
setCookie("video", e.dataset.action);
break;
}
window.location = window.location.pathname;
})
})

});
});
5 changes: 4 additions & 1 deletion app/static/webrtc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ class Receiver {

this.pc.ontrack = (evt) => {
console.log("new track: " + evt.track.kind);
document.querySelector(`video[data-cam='${this.signalJson.cam}']`).srcObject = evt.streams[0];
let vid = document.querySelector(`video[data-cam='${this.signalJson.cam}']`);
vid.srcObject = evt.streams[0];
vid.oncanplay = () => { vid.play() };

};
const direction = ("rss" in this.signalJson) ? "sendrecv" : "recvonly";
this.pc.addTransceiver("video", { "direction": direction });
Expand Down
70 changes: 40 additions & 30 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
{% if show_video %}
<link href="https://vjs.zencdn.net/7.19.2/video-js.css" rel="stylesheet" />
{% endif %}
<script src="{{ 'static/site.js' if hass else url_for('static', filename='site.js') }}"></script>
</head>

<body>
Expand Down Expand Up @@ -146,14 +145,16 @@
</header>
<div class="card-image has-text-centered">
<figure class="image">
{% if show_video and (camera.connected or (camera.on_demand and camera.enabled)) %}
{% if show_video and (camera.on_demand or camera.enabled) %}
{% if webrtc or (camera.webrtc and video_format == "kvs") %}
<video data-cam="{{cam_uri}}" class="webrtc loading-preview refresh_img" muted controls
playsinline {{ "autoplay" if autoplay }}
poster="{{camera.img_url or url_for('static',filename='loading.svg')}}"></video>
<video data-cam="{{cam_uri}}"
class="webrtc loading-preview refresh_img placeholder {{'connected' if camera.connected}}"
muted playsinline {{ "autoplay" if autoplay and camera.connected else 'preload=none' }}
poster="{{camera.img_url or url_for('static',filename='loading.svg' )}}"></video>
<i class="fas"></i>
{% else %}
<video-js id="video-{{cam_uri}}" class="video-js vjs-live vjs-big-play-centered" controls
muted playsinline preload={{"true" if autoplay and camera.connected else "false" }}
muted playsinline preload={{"auto" if autoplay and camera.connected else "none" }}
poster="{{camera.img_url or url_for('static',filename='loading.svg')}}"
data-cam="{{cam_uri}}"
data-setup='{"liveui": true, "fluid": true, "muted": true, "autoplay": {{'"muted"' if autoplay and camera.connected
Expand Down Expand Up @@ -245,27 +246,40 @@
</div>
{% endfor %}
</div>
<div class="tabs is-toggle is-toggle is-centered fs-display-none">
<ul>
<li {% if not show_video %}class="is-active" {% endif %}>
<a href="?snapshot">
<span class="icon is-small"><i class="fas fa-image"></i></span>
<span>Snapshot</span>
</a>
</li>
<li {% if show_video %}class="is-active" {% endif %}>
<a href="?video">
<div class="preview-toggle buttons is-centered fs-display-none">
<button data-action="snapshot" class="button {% if not show_video %} is-active{% endif %}">
<span class="icon is-small"><i class="fas fa-image"></i></span>
<span>Snapshot</span>
</button>
<div class="dropdown is-hoverable">
<div class="dropdown-trigger">
<button data-action="video" data-action="" class="button{% if show_video %} is-active{% endif %}"
aria-haspopup="true" aria-controls="video-menu">
<span class="icon is-small"><i class="fas fa-film"></i></span>
<span>Video</span>
</a>
</li>
</ul>
</div>
<div class="has-text-centered has-text-grey-light fs-display-none">
<label class="checkbox">
<input type="checkbox" id="enable-autoplay" {{"checked" if autoplay}}>
Autoplay
</label>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="video-menu" role="menu">
<div class="dropdown-content">
<a data-action="webrtc" class="dropdown-item" id="webrtc-toggle">
<span class="icon is-small"><i class="fas"></i></span>
WebRTC
</a>
<a data-action="hls" class="dropdown-item" id="hls-toggle">
<span class="icon is-small"><i class="fas"></i></span>
HLS
</a>
<hr class="dropdown-divider">
<a data-action="autoplay" class="dropdown-item" id="toggle-autoplay">
<span class="icon is-small"><i class="fas fa-square{{ '-check' if autoplay}}"></i></span>
auto-play
</a>
</div>
</div>
</div>
</div>
<div class="fullscreen">
<button class="button is-small">
Expand All @@ -288,14 +302,10 @@
</p>
</div>
</footer>
<script src="{{ 'static/site.js' if hass else url_for('static', filename='site.js') }}"></script>
{% if show_video %}
{% if webrtc or video_format =="kvs" %}
<script src="{{ 'static/webrtc.js' if hass else url_for('static', filename='webrtc.js') }}"></script>
<script>
document.querySelectorAll("video.webrtc").forEach((v) => {
fetch(`signaling/${v.dataset.cam}?{{ video_format }}`).then((resp) => resp.json()).then((data) => new Receiver(data))
})
</script>
{% endif %}
<script src="https://vjs.zencdn.net/7.21.1/video.min.js"></script>
{% endif %}
Expand Down
2 changes: 0 additions & 2 deletions app/wyzecam/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ def get_camera_list(auth_info: WyzeCredential) -> List[WyzeCamera]:
"thumbnails_url"
)

if not ip:
continue
if not mac:
continue
if not product_model:
Expand Down
2 changes: 1 addition & 1 deletion app/wyzecam/api_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class WyzeCamera(BaseModel):

p2p_id: Optional[str]
p2p_type: Optional[int]
ip: str
ip: Optional[int]
enr: Optional[str]
mac: str
product_model: str
Expand Down

0 comments on commit 20f218c

Please sign in to comment.