Merge cycle functionality into watch view. Add period dropdown, countdown timer, toggle the sidebar. Fix auth on statusAjax, and don't use status ajax unless we are in still mode. Apply some min-width to fps so they don't jump around. Only update their content if it has changed (fewer browser renders).

This commit is contained in:
Isaac Connor 2021-12-10 15:34:35 -05:00
parent 7bc46ba7a8
commit 5d8db0a320
4 changed files with 482 additions and 195 deletions

View File

@ -1,6 +1,8 @@
#header { #header {
display: flex; }
justify-content: space-between;
#sidebar {
min-width: 140px;
} }
#menuControls { #menuControls {
@ -19,19 +21,22 @@
#monitorStatus { #monitorStatus {
margin: 4px auto; margin: 4px auto;
text-align: center; text-align: center;
} display: inline-block;
#monitorStatus #enableDisableAlarms {
float: left;
}
#monitorStatus #forceCancelAlarm {
float: right;
} }
#monitorStatus #monitorState { #monitorStatus #monitorState {
} }
#replayStatus {
margin: 3px 0 2px;
text-align: center;
display: inline-block;
}
#replayStatus > span {
padding: 0 4px;
}
#dvrControls { #dvrControls {
margin-top: 3px; margin-top: 3px;
margin-bottom: 2px; margin-bottom: 2px;
@ -67,15 +72,6 @@
cursor: default; cursor: default;
} }
#replayStatus {
margin: 3px 0 2px;
text-align: center;
clear: both;
}
#replayStatus > span {
padding: 0 4px;
}
#events { #events {
margin: 0 auto; margin: 0 auto;
@ -116,3 +112,22 @@ span.alert {
background-color: #DCDCDC; background-color: #DCDCDC;
} }
.controlHeader {
width: 100%;
}
#viewingFPS,
#captureFPS,
#analysisFPS
{
display: inline-block;
}
#stateValue,
#viewingFPSValue,
#captureFPSValue,
#analysisFPSValue
{
display: inline-block;
min-width: 40px;
text-align: right;
}

View File

@ -44,7 +44,7 @@ function ajaxRequest(params) {
data.view = 'request'; data.view = 'request';
data.request = 'watch'; data.request = 'watch';
data.mid = monitorId; data.mid = monitorId;
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
$j.getJSON(thisUrl, data) $j.getJSON(thisUrl, data)
.done(function(data) { .done(function(data) {
@ -94,8 +94,48 @@ function showPtzControls() {
showMode = 'control'; showMode = 'control';
} }
function changeSize() {
var width = $j('#width').val();
var height = $j('#height').val();
// Scale the frame
monitor_frame = $j('#imageFeed');
if (!monitor_frame) {
console.log('Error finding frame');
return;
}
if (width) monitor_frame.css('width', width);
if (height) monitor_frame.css('height', height);
var streamImg = document.getElementById('liveStream'+monitorData[monIdx].id);
if (streamImg) {
if (streamImg.nodeName == 'IMG') {
let src = streamImg.src;
streamImg.src = '';
src = src.replace(/width=[\.\d]+/i, 'width='+parseInt(width));
src = src.replace(/height=[\.\d]+/i, 'height='+parseInt(height));
src = src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
streamImg.src = src;
}
streamImg.style.width = width ? width : null;
streamImg.style.height = height ? height : null;
} else {
console.log('Did not find liveStream'+monitorData[monIdx].id);
}
$j('#scale').val('');
setCookie('zmCycleScale', '', 3600);
setCookie('zmCycleWidth', width, 3600);
setCookie('zmCycleHeight', height, 3600);
} // end function changeSize()
function changeScale() { function changeScale() {
var scale = $j('#scale').val(); var scale = $j('#scale').val();
$j('#width').val('auto');
$j('#height').val('auto');
setCookie('zmCycleScale', scale, 3600);
setCookie('zmCycleWidth', 'auto', 3600);
setCookie('zmCycleHeight', 'auto', 3600);
var newWidth; var newWidth;
var newHeight; var newHeight;
var autoScale; var autoScale;
@ -104,7 +144,7 @@ function changeScale() {
// times and what the consequences would be // times and what the consequences would be
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active $j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
if (scale == '0' || scale == 'auto') { if (scale == '0' || scale == 'auto') {
var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus')); const newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
newWidth = newSize.width; newWidth = newSize.width;
newHeight = newSize.height; newHeight = newSize.height;
autoScale = newSize.autoScale; autoScale = newSize.autoScale;
@ -118,16 +158,18 @@ function changeScale() {
var streamImg = $j('#liveStream'+monitorId); var streamImg = $j('#liveStream'+monitorId);
if (streamImg) { if (streamImg) {
var oldSrc = streamImg.attr('src'); if (streamImg.nodeName == 'IMG') {
streamImg.attr('src', ''); const oldSrc = streamImg.attr('src');
// This is so that we don't waste bandwidth and let the browser do all the scaling. streamImg.attr('src', '');
if (autoScale > 100) autoScale = 100; // This is so that we don't waste bandwidth and let the browser do all the scaling.
if (scale > 100) scale = 100; if (autoScale > 100) autoScale = 100;
var newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+((scale == 'auto' || scale == '0') ? autoScale : scale)); if (scale > 100) scale = 100;
const newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+((scale == 'auto' || scale == '0') ? autoScale : scale));
streamImg.width(newWidth); streamImg.width(newWidth);
streamImg.height(newHeight); streamImg.height(newHeight);
streamImg.attr('src', newSrc); streamImg.attr('src', newSrc);
}
} else { } else {
console.error('No element found for liveStream'+monitorId); console.error('No element found for liveStream'+monitorId);
} }
@ -200,9 +242,15 @@ function getStreamCmdResponse(respObj, respText) {
// The get status command can get backed up, in which case we won't be able to get the semaphore and will exit. // The get status command can get backed up, in which case we won't be able to get the semaphore and will exit.
if (respObj.status) { if (respObj.status) {
streamStatus = respObj.status; streamStatus = respObj.status;
$j('#fpsValue').text(streamStatus.fps); if ($j('#viewingFPSValue').text() != streamStatus.fps) {
$j('#capturefpsValue').text(streamStatus.capturefps); $j('#viewingFPSValue').text(streamStatus.fps);
$j('#analysisfpsValue').text(streamStatus.analysisfps); }
if ($j('#captureFPSValue').text() != streamStatus.capturefps) {
$j('#captureFPSValue').text(streamStatus.capturefps);
}
if ($j('#analysisFPSValue').text() != streamStatus.analysisfps) {
$j('#analysisFPSValue').text(streamStatus.analysisfps);
}
setAlarmState(streamStatus.state); setAlarmState(streamStatus.state);
@ -287,31 +335,19 @@ function getStreamCmdResponse(respObj, respText) {
// Try to reload the image stream. // Try to reload the image stream.
var streamImg = $j('#liveStream'+monitorId); var streamImg = $j('#liveStream'+monitorId);
if (streamImg) { if (streamImg) {
var oldSrc = streamImg.attr('src'); const oldSrc = streamImg.attr('src');
var newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth); if (oldSrc) {
if (oldSrc != newSrc) { const newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
streamImg.attr('src', newSrc); if (oldSrc != newSrc) {
table.bootstrapTable('refresh'); streamImg.attr('src', newSrc);
table.bootstrapTable('refresh');
}
} }
} }
} // end if have a new auth hash } // end if have a new auth hash
} // end if respObj.status } // end if respObj.status
} else { } else {
checkStreamForErrors('getStreamCmdResponse', respObj);//log them checkStreamForErrors('getStreamCmdResponse', respObj);//log them
// Try to reload the image stream.
// If it's an auth error, we should reload the whole page.
console.log("have error");
//window.location.reload();
var streamImg = $j('#liveStream'+monitorId);
if (streamImg) {
var oldSrc = streamImg.attr('src');
var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
streamImg.attr('src', newSrc);
console.log('Changing livestream src to ' + newSrc);
} else {
console.log('Unable to find streamImg liveStream');
}
} }
var streamCmdTimeout = statusRefreshTimeout; var streamCmdTimeout = statusRefreshTimeout;
@ -368,6 +404,7 @@ function streamCmdPlay(action) {
} }
function streamCmdReq(data) { function streamCmdReq(data) {
if (auth_hash) data.auth = auth_hash;
$j.getJSON(monitorUrl + '?view=request&request=stream&connkey='+connKey, data) $j.getJSON(monitorUrl + '?view=request&request=stream&connkey='+connKey, data)
.done(getStreamCmdResponse) .done(getStreamCmdResponse)
.fail(getStreamCmdError); .fail(getStreamCmdError);
@ -386,10 +423,7 @@ function streamCmdStop(action) {
setButtonState('fastRevBtn', 'unavail'); setButtonState('fastRevBtn', 'unavail');
} }
if (action) { if (action) {
var data = {}; streamCmdReq({command: CMD_STOP});
if (auth_hash) data.auth = auth_hash;
data.command = CMD_STOP;
streamCmdReq(data);
} }
setButtonState('stopBtn', 'unavail'); setButtonState('stopBtn', 'unavail');
setButtonState('playBtn', 'active'); setButtonState('playBtn', 'active');
@ -407,7 +441,6 @@ function streamCmdFastFwd(action) {
} }
if (action) { if (action) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTFWD; data.command = CMD_FASTFWD;
streamCmdReq(data); streamCmdReq(data);
} }
@ -425,7 +458,6 @@ function streamCmdSlowFwd(action) {
} }
if (action) { if (action) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWFWD; data.command = CMD_SLOWFWD;
streamCmdReq(data); streamCmdReq(data);
} }
@ -447,7 +479,6 @@ function streamCmdSlowRev(action) {
} }
if (action) { if (action) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWREV; data.command = CMD_SLOWREV;
streamCmdReq(data); streamCmdReq(data);
} }
@ -469,7 +500,6 @@ function streamCmdFastRev(action) {
} }
if (action) { if (action) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTREV; data.command = CMD_FASTREV;
streamCmdReq(data); streamCmdReq(data);
} }
@ -477,7 +507,6 @@ function streamCmdFastRev(action) {
function streamCmdZoomIn(x, y) { function streamCmdZoomIn(x, y) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.x = x; data.x = x;
data.y = y; data.y = y;
data.command = CMD_ZOOMIN; data.command = CMD_ZOOMIN;
@ -486,14 +515,12 @@ function streamCmdZoomIn(x, y) {
function streamCmdZoomOut() { function streamCmdZoomOut() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_ZOOMOUT; data.command = CMD_ZOOMOUT;
streamCmdReq(data); streamCmdReq(data);
} }
function streamCmdScale(scale) { function streamCmdScale(scale) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SCALE; data.command = CMD_SCALE;
data.scale = scale; data.scale = scale;
streamCmdReq(data); streamCmdReq(data);
@ -501,7 +528,6 @@ function streamCmdScale(scale) {
function streamCmdPan(x, y) { function streamCmdPan(x, y) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.x = x; data.x = x;
data.y = y; data.y = y;
data.command = CMD_PAN; data.command = CMD_PAN;
@ -510,11 +536,11 @@ function streamCmdPan(x, y) {
function streamCmdQuery() { function streamCmdQuery() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = CMD_QUERY; data.command = CMD_QUERY;
streamCmdReq(data); streamCmdReq(data);
} }
/* getStatusCmd is used when not streaming, since there is no persistent zms */
function getStatusCmdResponse(respObj, respText) { function getStatusCmdResponse(respObj, respText) {
watchdogOk('status'); watchdogOk('status');
if (statusCmdTimer) { if (statusCmdTimer) {
@ -522,32 +548,33 @@ function getStatusCmdResponse(respObj, respText) {
} }
if (respObj.result == 'Ok') { if (respObj.result == 'Ok') {
$j('#fpsValue').text(respObj.monitor.FrameRate); $j('#captureFPSValue').text(respObj.monitor.FrameRate);
setAlarmState(respObj.monitor.Status); setAlarmState(respObj.monitor.Status);
} else { } else {
checkStreamForErrors('getStatusCmdResponse', respObj); checkStreamForErrors('getStatusCmdResponse', respObj);
} }
var statusCmdTimeout = statusRefreshTimeout; var statusCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { if (alarmState == STATE_ALARM || alarmState == STATE_ALERT) {
statusCmdTimeout = statusCmdTimeout/5; statusCmdTimeout = statusCmdTimeout/5;
} }
statusCmdTimer = setTimeout(statusCmdQuery, statusCmdTimeout); statusCmdTimer = setTimeout(statusCmdQuery, statusCmdTimeout);
} }
function statusCmdQuery() { function statusCmdQuery() {
$j.getJSON(monitorUrl + '?view=request&request=status&entity=monitor&element[]=Status&element[]=FrameRate&id='+monitorId) $j.getJSON(monitorUrl + '?view=request&request=status&entity=monitor&element[]=Status&element[]=FrameRate&id='+monitorId+'&'+auth_relay)
.done(getStatusCmdResponse) .done(getStatusCmdResponse)
.fail(logAjaxFail); .fail(logAjaxFail);
streamCmdTimer = null; statusCmdTimer = null;
} }
function alarmCmdReq(data) { function alarmCmdReq(data) {
if (auth_hash) data.auth = auth_hash;
$j.getJSON(monitorUrl + '?view=request&request=alarm&id='+monitorId, data) $j.getJSON(monitorUrl + '?view=request&request=alarm&id='+monitorId, data)
.done(getAlarmCmdResponse) .done(getAlarmCmdResponse)
.fail(function(jqxhr, textStatus, error) { .fail(function(jqxhr, textStatus, error) {
if ( textStatus === "timeout" ) { if (textStatus === 'timeout') {
streamCmdQuery(); streamCmdQuery();
} else { } else {
logAjaxFail(jqxhr, textStatus, error); logAjaxFail(jqxhr, textStatus, error);
@ -561,14 +588,12 @@ function getAlarmCmdResponse(respObj, respText) {
function cmdDisableAlarms() { function cmdDisableAlarms() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = 'disableAlarms'; data.command = 'disableAlarms';
alarmCmdReq(data); alarmCmdReq(data);
} }
function cmdEnableAlarms() { function cmdEnableAlarms() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = 'enableAlarms'; data.command = 'enableAlarms';
alarmCmdReq(data); alarmCmdReq(data);
} }
@ -583,7 +608,6 @@ function cmdAlarm() {
function cmdForceAlarm() { function cmdForceAlarm() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = 'forceAlarm'; data.command = 'forceAlarm';
alarmCmdReq(data); alarmCmdReq(data);
if (window.event) window.event.preventDefault(); if (window.event) window.event.preventDefault();
@ -591,7 +615,6 @@ function cmdForceAlarm() {
function cmdCancelForcedAlarm() { function cmdCancelForcedAlarm() {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.command = 'cancelForcedAlarm'; data.command = 'cancelForcedAlarm';
alarmCmdReq(data); alarmCmdReq(data);
if (window.event) window.event.preventDefault(); if (window.event) window.event.preventDefault();
@ -607,6 +630,7 @@ function cmdForce() {
} }
function controlReq(data) { function controlReq(data) {
if (auth_hash) data.auth = auth_hash;
$j.getJSON(monitorUrl + '?view=request&request=control&id='+monitorId, data) $j.getJSON(monitorUrl + '?view=request&request=control&id='+monitorId, data)
.done(getControlResponse) .done(getControlResponse)
.fail(logAjaxFail); .fail(logAjaxFail);
@ -639,16 +663,16 @@ function controlCmd(event) {
var data = {}; var data = {};
if (event && (xtell || ytell)) { if (event && (xtell || ytell)) {
var target = event.target; const target = event.target;
var offset = $j(target).offset(); const offset = $j(target).offset();
var width = $j(target).width(); const width = $j(target).width();
var height = $j(target).height(); const height = $j(target).height();
var x = event.pageX - offset.left; const x = event.pageX - offset.left;
var y = event.pageY - offset.top; const y = event.pageY - offset.top;
if (xtell) { if (xtell) {
var xge = parseInt((x*100)/width); let xge = parseInt((x*100)/width);
if (xtell == -1) { if (xtell == -1) {
xge = 100 - xge; xge = 100 - xge;
} else if (xtell == 2) { } else if (xtell == 2) {
@ -657,7 +681,7 @@ function controlCmd(event) {
data.xge = xge; data.xge = xge;
} }
if (ytell) { if (ytell) {
var yge = parseInt((y*100)/height); let yge = parseInt((y*100)/height);
if (ytell == -1) { if (ytell == -1) {
yge = 100 - yge; yge = 100 - yge;
} else if (ytell == 2) { } else if (ytell == 2) {
@ -667,7 +691,6 @@ function controlCmd(event) {
} }
} }
if (auth_hash) data.auth = auth_hash;
data.control = control; data.control = control;
controlReq(data); controlReq(data);
@ -678,7 +701,6 @@ function controlCmd(event) {
function controlCmdImage(x, y) { function controlCmdImage(x, y) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.scale = scale; data.scale = scale;
data.control = imageControlMode; data.control = imageControlMode;
data.x = x; data.x = x;
@ -768,7 +790,6 @@ function reloadWebSite() {
function updatePresetLabels() { function updatePresetLabels() {
var lblNdx = $j('#ctrlPresetForm option:selected').val(); var lblNdx = $j('#ctrlPresetForm option:selected').val();
$j('#newLabel').val(labels[lblNdx]); $j('#newLabel').val(labels[lblNdx]);
} }
@ -878,7 +899,7 @@ function initPage() {
// Load the PTZ Preset modal into the DOM // Load the PTZ Preset modal into the DOM
if (monitorControllable) getCtrlPresetModal(); if (monitorControllable) getCtrlPresetModal();
// Load the settings modal into the DOM // Load the settings modal into the DOM
if (monitorType == "Local") getSettingsModal(); if (monitorType == 'Local') getSettingsModal();
} }
if (monitorType != 'WebSite') { if (monitorType != 'WebSite') {
@ -886,15 +907,12 @@ function initPage() {
statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout); statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'status'); setInterval(watchdogCheck, statusRefreshTimeout*2, 'status');
} else { } else {
streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream'); setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream');
} }
if (canStreamNative || (streamMode == 'single')) { if (canStreamNative || (streamMode == 'single')) {
var streamImg = $j('#imageFeed img'); var streamImg = $j('#imageFeed img');
if (!streamImg) { if (!streamImg) streamImg = $j('#imageFeed object');
streamImg = $j('#imageFeed object');
}
if (!streamImg) { if (!streamImg) {
console.error('No streamImg found for imageFeed'); console.error('No streamImg found for imageFeed');
} else { } else {
@ -905,6 +923,10 @@ function initPage() {
streamImg.click(function(event) { streamImg.click(function(event) {
handleClick(event); handleClick(event);
}); });
streamImg.on("error", function(thing) {
console.log("Error loading image");
console.log(thing);
});
} }
} // end if have streamImg } // end if have streamImg
} // streamMode native or single } // streamMode native or single
@ -944,6 +966,18 @@ function initPage() {
$j('#settingsModal').modal('show'); $j('#settingsModal').modal('show');
}); });
bindButton('#cyclePlayBtn', 'click', null, cycleStart);
bindButton('#cyclePauseBtn', 'click', null, cyclePause);
bindButton('#cycleNextBtn', 'click', null, cycleNext);
bindButton('#cyclePrevBtn', 'click', null, cyclePrev);
bindButton('#cycleToggle', 'click', null, cycleToggle);
bindButton('#cyclePeriod', 'change', null, cyclePeriodChange);
if (cycle) {
cycleStart();
} else {
cyclePause();
}
// Only enable the settings button for local cameras // Only enable the settings button for local cameras
settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local'))); settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local')));
@ -972,7 +1006,6 @@ function initPage() {
function watchFullscreen() { function watchFullscreen() {
const btn = document.getElementById('fullscreenBtn'); const btn = document.getElementById('fullscreenBtn');
console.log(btn);
if (btn.firstElementChild.innerHTML=='fullscreen') { if (btn.firstElementChild.innerHTML=='fullscreen') {
const content = document.getElementById('content'); const content = document.getElementById('content');
openFullscreen(content); openFullscreen(content);
@ -985,5 +1018,70 @@ function watchFullscreen() {
} }
} }
var intervalId;
var secondsToCycle = 0;
function nextCycleView() {
secondsToCycle --;
if (secondsToCycle<=0) {
window.location.replace('?view=watch&mid='+nextMid+'&mode='+mode+'&cycle=true');
}
$j('#secondsToCycle').text(secondsToCycle);
}
function cyclePause() {
clearInterval(intervalId);
$j('#cyclePauseBtn').hide();
$j('#cyclePlayBtn').show();
}
function cycleStart() {
secondsToCycle = $j('#cyclePeriod').val();
intervalId = setInterval(nextCycleView, 1000);
$j('#cyclePauseBtn').show();
$j('#cyclePlayBtn').hide();
}
function cycleNext() {
monIdx ++;
if (monIdx >= monitorData.length) {
monIdx = 0;
}
if (!monitorData[monIdx]) {
console.log('No monitorData for ' + monIdx);
}
window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode);
}
function cyclePrev() {
monIdx --;
if (monIdx < 0) {
monIdx = monitorData.length - 1;
}
if (!monitorData[monIdx]) {
console.log('No monitorData for ' + monIdx);
}
window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode);
}
function cyclePeriodChange() {
const cyclePeriodSelect = $j('#cyclePeriod');
secondsToCycle = cyclePeriodSelect.val();
setCookie('zmCyclePeriod', secondsToCycle, 3600);
}
function cycleToggle(e) {
sidebar = $j('#sidebar');
button = $j('#cycleToggle');
if (sidebar.is(":visible")) {
sidebar.hide();
setCookie('zmCycleShow', false, 3600);
} else {
sidebar.show();
setCookie('zmCycleShow', true, 3600);
}
button.toggleClass('btn-secondary');
button.toggleClass('btn-primary');
}
// Kick everything off // Kick everything off
$j(document).ready(initPage); $j(document).ready(initPage);

View File

@ -1,21 +1,20 @@
<?php <?php
global $monIdx;
global $nextMid;
global $options;
global $monitors;
global $streamMode; global $streamMode;
global $showPtzControls; global $showPtzControls;
global $connkey; global $connkey;
global $monitor; global $monitor;
global $scale; global $scale;
global $labels; global $labels;
global $cycle;
?> ?>
// //
// Import constants // Import constants
// //
var deleteString = "<?php echo translate('Delete') ?>";
var enableAlarmsStr = "<?php echo translate('EnableAlarms') ?>";
var disableAlarmsStr = "<?php echo translate('DisableAlarms') ?>";
var forceAlarmStr = "<?php echo translate('ForceAlarm') ?>";
var cancelForcedAlarmStr = "<?php echo translate('CancelForcedAlarm') ?>";
var CMD_NONE = <?php echo CMD_NONE ?>; var CMD_NONE = <?php echo CMD_NONE ?>;
var CMD_PAUSE = <?php echo CMD_PAUSE ?>; var CMD_PAUSE = <?php echo CMD_PAUSE ?>;
@ -34,14 +33,13 @@ var CMD_NEXT = <?php echo CMD_NEXT ?>;
var CMD_SEEK = <?php echo CMD_SEEK ?>; var CMD_SEEK = <?php echo CMD_SEEK ?>;
var CMD_QUERY = <?php echo CMD_QUERY ?>; var CMD_QUERY = <?php echo CMD_QUERY ?>;
var SCALE_BASE = <?php echo SCALE_BASE ?>;
var SOUND_ON_ALARM = <?php echo ZM_WEB_SOUND_ON_ALARM ?>; var SOUND_ON_ALARM = <?php echo ZM_WEB_SOUND_ON_ALARM ?>;
var POPUP_ON_ALARM = <?php echo ZM_WEB_POPUP_ON_ALARM ?>; var POPUP_ON_ALARM = <?php echo ZM_WEB_POPUP_ON_ALARM ?>;
var LIST_THUMBS = <?php echo ZM_WEB_LIST_THUMBS?'true':'false' ?>; var LIST_THUMBS = <?php echo ZM_WEB_LIST_THUMBS?'true':'false' ?>;
var streamMode = "<?php echo $streamMode ?>"; var streamMode = "<?php echo $streamMode ?>";
var showMode = "<?php echo ($showPtzControls && !empty($control))?"control":"events" ?>"; var showMode = "<?php echo ($showPtzControls && !empty($control))?"control":"events" ?>";
var cycle = <?php echo $cycle ? 'true' : 'false' ?>;
var connKey = '<?php echo $connkey ?>'; var connKey = '<?php echo $connkey ?>';
var maxDisplayEvents = <?php echo 2 * MAX_EVENTS ?>; var maxDisplayEvents = <?php echo 2 * MAX_EVENTS ?>;
@ -55,6 +53,28 @@ var monitorRefresh = '<?php echo $monitor->Refresh() ?>';
var monitorStreamReplayBuffer = <?php echo $monitor->StreamReplayBuffer() ?>; var monitorStreamReplayBuffer = <?php echo $monitor->StreamReplayBuffer() ?>;
var monitorControllable = <?php echo $monitor->Controllable()?'true':'false' ?>; var monitorControllable = <?php echo $monitor->Controllable()?'true':'false' ?>;
var monIdx = '<?php echo $monIdx; ?>';
var nextMid = "<?php echo isset($nextMid)?$nextMid:'' ?>";
var mode = "<?php echo $options['mode'] ?>";
var monitorData = new Array();
<?php
foreach ($monitors as $monitor) {
?>
monitorData[monitorData.length] = {
'id': <?php echo $monitor->Id() ?>,
'width': <?php echo $monitor->ViewWidth() ?>,
'height':<?php echo $monitor->ViewHeight() ?>,
'url': '<?php echo $monitor->UrlToIndex() ?>',
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $monitor->Id() ?>' );},
'type': '<?php echo $monitor->Type() ?>',
'refresh': '<?php echo $monitor->Refresh() ?>'
};
<?php
} // end foreach monitor
?>
var SCALE_BASE = <?php echo SCALE_BASE ?>;
var scale = '<?php echo $scale ?>'; var scale = '<?php echo $scale ?>';
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>; var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
@ -63,17 +83,16 @@ var imageRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_IMAGE ?>;
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>; var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
<?php var imageControlMode = '<?php
$control = $monitor->Control(); $control = $monitor->Control();
if ( $control->CanMoveMap() ) { ?> if ($control->CanMoveMap()) {
var imageControlMode = "moveMap"; echo 'moveMap';
<?php } elseif ( $control->CanMoveRel() ) { ?> } else if ($control->CanMoveRel()) {
var imageControlMode = "movePseudoMap"; echo 'movePseudoMap';
<?php } elseif ( $control->CanMoveCon() ) { ?> } else if ($control->CanMoveCon()) {
var imageControlMode = "moveConMap"; echo 'moveConMap';
<?php } else { ?> }
var imageControlMode = null; ?>';
<?php } ?>
var refreshApplet = <?php echo (canStreamApplet() && $streamMode == "jpeg")?'true':'false' ?>; var refreshApplet = <?php echo (canStreamApplet() && $streamMode == "jpeg")?'true':'false' ?>;
var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>; var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>;
@ -81,17 +100,18 @@ var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>;
var labels = new Array(); var labels = new Array();
<?php <?php
$labels = array(); $labels = array();
foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, array( $monitor->Id() ) ) as $row ) { foreach (dbFetchAll('SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, array($monitor->Id())) as $row) {
$labels[$row['Preset']] = $row['Label']; $label = $labels[$row['Preset']] = $row['Label'];
} echo 'labels['. validInt($index) .'] = '.validJsStr($label).'\'';
foreach ($labels as $index=>$label) {
?>
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
<?php
} }
?> ?>
var deleteString = "<?php echo translate('Delete') ?>";
var enableAlarmsStr = "<?php echo translate('EnableAlarms') ?>";
var disableAlarmsStr = "<?php echo translate('DisableAlarms') ?>";
var forceAlarmStr = "<?php echo translate('ForceAlarm') ?>";
var cancelForcedAlarmStr = "<?php echo translate('CancelForcedAlarm') ?>";
var translate = { var translate = {
"seconds": "<?php echo translate('seconds') ?>",
"Fullscreen": "<?php echo translate('Fullscreen') ?>", "Fullscreen": "<?php echo translate('Fullscreen') ?>",
"Exit Fullscreen": "<?php echo translate('Exit Fullscreen') ?>", "Exit Fullscreen": "<?php echo translate('Exit Fullscreen') ?>",
}; };

View File

@ -18,143 +18,296 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
if ( !canView('Stream') ) { if (!canView('Stream')) {
$view = 'error'; $view = 'error';
return; return;
} }
require_once('includes/Monitor.php');
ob_start();
include('_monitor_filters.php');
$filterbar = ob_get_contents();
ob_end_clean();
if ( !isset($_REQUEST['mid']) ) {
$view = 'error';
return;
}
// This is for input sanitation // This is for input sanitation
$mid = intval($_REQUEST['mid']); $mid = isset($_REQUEST['mid']) ? intval($_REQUEST['mid']) : 0;
if ( !visibleMonitor($mid) ) {
$widths = array(
'auto' => translate('auto'),
'100%' => '100%',
'160px' => '160px',
'320px' => '320px',
'352px' => '352px',
'640px' => '640px',
'1280px' => '1280px',
'1920px' => '1920px'
);
$heights = array(
'auto' => translate('auto'),
'240px' => '240px',
'480px' => '480px',
'720px' => '720px',
'1080px' => '1080px',
);
$monitors = array();
$monitor_index = 0;
foreach ($displayMonitors as &$row) {
if ($row['Function'] == 'None') continue;
if ($mid and ($row['Id'] == $mid)) $monitor_index = count($monitors);
$monitors[] = new ZM\Monitor($row);
if (!isset($widths[$row['Width'].'px'])) {
$widths[$row['Width'].'px'] = $row['Width'].'px';
}
if (!isset($heights[$row['Height'].'px'])) {
$heights[$row['Height'].'px'] = $row['Height'].'px';
}
unset($row);
} # end foreach Monitor
if (!$mid) {
$mid = $monitors[0]->Id();
$monitor_index = 0;
}
if (!visibleMonitor($mid)) {
$view = 'error'; $view = 'error';
return; return;
} }
require_once('includes/Monitor.php');
$monitor = new ZM\Monitor($mid); $monitor = new ZM\Monitor($mid);
$nextMid = ($monitor_index == count($monitors)-1) ? $monitors[0]->Id() : $monitors[$monitor_index+1]->Id();
$cycle = isset($_REQUEST['cycle']) and ($_REQUEST['cycle'] == 'true');
$showCycle = $cycle;
ZM\Error("Show cycle: $showCycle");
if (isset($_COOKIE['zmCycleShow'])) {
$showCycle = $_COOKIE['zmCycleShow'] == 'true';
ZM\Error("Show cycle: $showCycle");
} else {
ZM\Error("Show cycle: not set");
}
#Whether to show the controls button #Whether to show the controls button
$showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' ); $showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' );
if ( isset($_REQUEST['scale']) ) { $options = array();
if (empty($_REQUEST['mode'])) {
$options['mode'] = canStream() ? 'stream' : 'still';
} else {
$options['mode'] = validHtmlStr($_REQUEST['mode']);
}
zm_session_start();
$period = ZM_WEB_REFRESH_CYCLE;
if (isset($_REQUEST['period'])) {
$period = validInt($_REQUEST['period']);
} else if (isset($_COOKIE['zmCyclePeriod'])) {
$period = validInt($_COOKIE['zmCyclePeriod']);
}
if (isset($_REQUEST['scale'])) {
$scale = validInt($_REQUEST['scale']); $scale = validInt($_REQUEST['scale']);
} else if ( isset($_COOKIE['zmWatchScale'.$mid]) ) { } else if ( isset($_COOKIE['zmWatchScale'.$mid]) ) {
$scale = $_COOKIE['zmWatchScale'.$mid]; $scale = $_COOKIE['zmWatchScale'.$mid];
} else { } else {
$scale = $monitor->DefaultScale(); $scale = $monitor->DefaultScale();
} }
$options['scale'] = $scale;
if (isset($_REQUEST['width'])) {
$options['width'] = validInt($_REQUEST['width']);
} else if ( isset($_COOKIE['zmCycleWidth']) and $_COOKIE['zmCycleWidth'] ) {
$_SESSION['zmCycleWidth'] = $options['width'] = $_COOKIE['zmCycleWidth'];
#} elseif ( isset($_SESSION['zmCycleWidth']) and $_SESSION['zmCycleWidth'] ) {
#$options['width'] = $_SESSION['zmCycleWidth'];
} else {
$options['width'] = '';
}
if (isset($_REQUEST['height'])) {
$options['height'] =validInt($_REQUEST['height']);
} else if (isset($_COOKIE['zmCycleHeight']) and $_COOKIE['zmCycleHeight']) {
$_SESSION['zmCycleHeight'] = $options['height'] = $_COOKIE['zmCycleHeight'];
#else if ( isset($_SESSION['zmCycleHeight']) and $_SESSION['zmCycleHeight'] )
#$options['height'] = $_SESSION['zmCycleHeight'];
} else {
$options['height'] = '';
}
session_write_close();
$connkey = generateConnKey(); $connkey = generateConnKey();
$streamMode = getStreamMode(); $streamMode = getStreamMode();
$popup = ((isset($_REQUEST['popup'])) && ($_REQUEST['popup'] == 1));
noCacheHeaders(); noCacheHeaders();
xhtmlHeaders(__FILE__, $monitor->Name().' - '.translate('Feed')); xhtmlHeaders(__FILE__, $monitor->Name().' - '.translate('Feed'));
?> ?>
<body> <body>
<?php echo getNavBarHTML() ?> <?php echo getNavBarHTML() ?>
<div id="header">
<div class="controlHeader">
<form method="get">
<input type="hidden" name="view" value="watch"/>
<?php echo $filterbar ?>
</form>
</div>
<div class="d-flex flex-row justify-content-between px-3 py-1"> <div class="d-flex flex-row justify-content-between px-3 py-1">
<div> <div id="navButtons">
<button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button> <button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
<button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button> <button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
<button type="button" id="settingsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Settings') ?>" disabled><i class="fa fa-sliders"></i></button> <button type="button" id="settingsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Settings') ?>" disabled><i class="fa fa-sliders"></i></button>
<button type="button" id="enableAlmBtn" class="btn btn-normal" data-on-click="cmdAlarm" data-toggle="tooltip" data-placement="top" title="<?php echo translate('DisableAlarms') ?>" disabled><i class="fa fa-bell"></i></button> <button type="button" id="enableAlmBtn" class="btn btn-normal" data-on-click="cmdAlarm" data-toggle="tooltip" data-placement="top" title="<?php echo translate('DisableAlarms') ?>" disabled><i class="fa fa-bell"></i></button>
<button type="button" id="forceAlmBtn" class="btn btn-danger" data-on-click="cmdForce" data-toggle="tooltip" data-placement="top" title="<?php echo translate('ForceAlarm') ?>" disabled><i class="fa fa-exclamation-circle"></i></button> <button type="button" id="forceAlmBtn" class="btn btn-danger" data-on-click="cmdForce" data-toggle="tooltip" data-placement="top" title="<?php echo translate('ForceAlarm') ?>" disabled><i class="fa fa-exclamation-circle"></i></button>
</div> </div>
<div id="headerButtons">
<div> <!--
<h2><?php echo makeLink('?view=monitor&amp;mid='.$monitor->Id(), validHtmlStr($monitor->Name()), canEdit('Monitors')) ?></h2> <?php if ( $options['mode'] == 'stream' ) { ?>
<a href="?view=<?php echo $view ?>&amp;mode=still&amp;mid=<?php echo $monitor ? $monitor->Id() : '' ?>"><?php echo translate('Stills') ?></a>
<?php } else { ?>
<a href="?view=<?php echo $view ?>&amp;mode=stream&amp;mid=<?php echo $monitor ? $monitor->Id() : '' ?>"><?php echo translate('Stream') ?></a>
<?php } ?>
-->
<button type="button" id="cycleToggle" class="btn <?php echo $showCycle ? 'btn-primary':'btn-secondary'?>" title="<?php echo translate('Toggle cycle sidebar')?>">
<span class="material-icons md-18">view_carousel</span>
</button>
</div> </div>
<div id="sizeControl">
<div> <span id="widthControl">
<?php echo translate('Scale').': '.htmlSelect('scale', $scales, $scale, array('id'=>'scale')); ?> <label><?php echo translate('Width') ?>:</label>
</div> <?php echo htmlSelect('width', $widths, $options['width'], array('id'=>'width', 'data-on-change-this'=>'changeSize') ); ?>
</div> </span>
<span id="heightControl">
<label><?php echo translate('Height') ?>:</label>
<?php echo htmlSelect('height', $heights, $options['height'], array('id'=>'height', 'data-on-change-this'=>'changeSize') ); ?>
</span>
<span id="scaleControl">
<label><?php echo translate('Scale') ?>:</label>
<?php echo htmlSelect('scale', $scales, $options['scale'], array('id'=>'scale', 'data-on-change-this'=>'changeScale') ); ?>
</span>
</div><!--sizeControl-->
</div><!--control header-->
</div><!--header-->
<?php <?php
if ( $monitor->Status() != 'Connected' and $monitor->Type() != 'WebSite' ) { if ( $monitor->Status() != 'Connected' and $monitor->Type() != 'WebSite' ) {
echo '<div class="warning">Monitor is not capturing. We will be unable to provide an image</div>'; echo '<div class="warning">Monitor is not capturing. We will be unable to provide an image</div>';
} }
?> ?>
<div id="content"> <div class="container-fluid h-100">
<div id="imageFeed" <div class="row flex-nowrap h-100" id="content">
<nav id="sidebar" class="h-100"<?php echo $showCycle?'':' style="display:none;"'?>>
<div id="cycleButtons" class="buttons">
<?php <?php
if ( $streamMode == 'jpeg' ) { $seconds = translate('seconds');
$minute = translate('minute');
$minutes = translate('minutes');
$cyclePeriodOptions = array(
10 => '10 '.$seconds,
30 => '30 '.$seconds,
60 => '1 '.$minute,
120 => '2 '.$minutes,
300 => '5 '.$minutes,
);
if (!isset($cyclePeriodOptions[ZM_WEB_REFRESH_CYCLE])) {
$cyclePeriodOptions[ZM_WEB_REFRESH_CYCLE] = ZM_WEB_REFRESH_CYCLE.' '.$seconds;
}
echo htmlSelect('cyclePeriod', $cyclePeriodOptions, $period, array('id'=>'cyclePeriod'));
?>
<span id="secondsToCycle"></span><br/>
<button type="button" id="cyclePrevBtn" title="<?php echo translate('PreviousMonitor') ?>">
<i class="material-icons md-18">skip_previous</i>
</button>
<button type="button" id="cyclePauseBtn" title="<?php echo translate('PauseCycle') ?>">
<i class="material-icons md-18">pause</i>
</button>
<button type="button" id="cyclePlayBtn" title="<?php echo translate('PlayCycle') ?>">
<i class="material-icons md-18">play_arrow</i>
</button>
<button type="button" id="cycleNextBtn" title="<?php echo translate('NextMonitor') ?>">
<i class="material-icons md-18">skip_next</i>
</button>
</div>
<ul class="nav nav-pills flex-column h-100">
<?php
foreach ($monitors as $m) {
echo '<li class="nav-item"><a class="nav-link'.( $m->Id() == $monitor->Id() ? ' active' : '' ).'" href="?view=watch&amp;mid='.$m->Id().'">'.$m->Name().'</a></li>';
}
?>
</ul>
</nav>
<div class="container-fluid col-sm-offset-2 h-100 pr-0">
<div id="imageFeed"
<?php
if ($streamMode == 'jpeg') {
echo 'title="Click to zoom, shift click to pan, ctrl click to zoom out"'; echo 'title="Click to zoom, shift click to pan, ctrl click to zoom out"';
} }
?> ?>
><?php echo getStreamHTML($monitor, array('scale'=>$scale)); ?></div> ><?php echo getStreamHTML($monitor, array('scale'=>$scale)); ?>
<?php if ( $monitor->Type() != 'WebSite' ) { ?>
<div id="monitorStatus">
<div id="monitorState">
<?php echo translate('State') ?>:
<span id="stateValue"></span> -
<span title="<?php echo translate('Viewing FPS')?>"><span id="fpsValue"></span> fps</span>
<span title="<?php echo translate('Capturing FPS')?>"><span id="capturefpsValue"></span> fps</span>
<?php if ( $monitor->Function() == 'Modect' or $monitor->Function() == 'Mocord' ) { ?>
<span title="<?php echo translate('Analysis FPS')?>"><span id="analysisfpsValue"></span> fps</span>
<?php } ?>
</div> </div>
</div>
<div id="dvrControls"> <?php if ($monitor->Type() != 'WebSite') { ?>
<div id="monitorStatus">
<div id="monitorState">
<span><?php echo translate('State') ?>:<span id="stateValue"></span></span>
<span id="viewingFPS" title="<?php echo translate('Viewing FPS')?>"><span id="viewingFPSValue"></span> fps</span>
<span id="captureFPS" title="<?php echo translate('Capturing FPS')?>"><span id="captureFPSValue"></span> fps</span>
<?php if ( $monitor->Function() == 'Modect' or $monitor->Function() == 'Mocord' ) { ?>
<span id="analysisFPS" title="<?php echo translate('Analysis FPS')?>"><span id="analysisFPSValue"></span> fps</span>
<?php } ?>
</div>
</div>
<div id="replayStatus"<?php echo $streamMode=="single" ? ' class="hidden"' : '' ?>>
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue"></span></span>
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"></span>x</span>
<span id="delay"><?php echo translate('Delay') ?>: <span id="delayValue"></span>s</span>
<span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span>
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
</div>
<div class="buttons">
<div id="dvrControls">
<?php <?php
if ( $streamMode == 'jpeg' ) { if ($streamMode == 'jpeg') {
if ( $monitor->StreamReplayBuffer() != 0 ) { if ($monitor->StreamReplayBuffer() != 0) {
?> ?>
<button type="button" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdFastRev"> <button type="button" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdFastRev">
<i class="material-icons md-18">fast_rewind</i> <i class="material-icons md-18">fast_rewind</i>
</button> </button>
<button type="button" id="slowRevBtn" title="<?php echo translate('StepBack') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdSlowRev"> <button type="button" id="slowRevBtn" title="<?php echo translate('StepBack') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdSlowRev">
<i class="material-icons md-18">chevron_right</i> <i class="material-icons md-18">chevron_right</i>
</button> </button>
<?php <?php
} }
?> ?>
<button type="button" id="pauseBtn" title="<?php echo translate('Pause') ?>" class="inactive" data-on-click-true="streamCmdPause"> <button type="button" id="pauseBtn" title="<?php echo translate('Pause') ?>" class="inactive" data-on-click-true="streamCmdPause">
<i class="material-icons md-18">pause</i> <i class="material-icons md-18">pause</i>
</button> </button>
<button type="button" id="stopBtn" title="<?php echo translate('Stop') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdStop" style="display:none;"> <button type="button" id="stopBtn" title="<?php echo translate('Stop') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdStop" style="display:none;">
<i class="material-icons md-18">stop</i> <i class="material-icons md-18">stop</i>
</button> </button>
<button type="button" id="playBtn" title="<?php echo translate('Play') ?>" class="active" disabled="disabled" data-on-click-true="streamCmdPlay"> <button type="button" id="playBtn" title="<?php echo translate('Play') ?>" class="active" disabled="disabled" data-on-click-true="streamCmdPlay">
<i class="material-icons md-18">play_arrow</i> <i class="material-icons md-18">play_arrow</i>
</button> </button>
<?php <?php
if ( $monitor->StreamReplayBuffer() != 0 ) { if ($monitor->StreamReplayBuffer() != 0) {
?> ?>
<button type="button" id="slowFwdBtn" title="<?php echo translate('StepForward') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdSlowFwd"> <button type="button" id="slowFwdBtn" title="<?php echo translate('StepForward') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdSlowFwd">
<i class="material-icons md-18">chevron_right</i> <i class="material-icons md-18">chevron_right</i>
</button> </button>
<button type="button" id="fastFwdBtn" title="<?php echo translate('FastForward') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdFastFwd"> <button type="button" id="fastFwdBtn" title="<?php echo translate('FastForward') ?>" class="unavail" disabled="disabled" data-on-click-true="streamCmdFastFwd">
<i class="material-icons md-18">fast_forward</i> <i class="material-icons md-18">fast_forward</i>
</button> </button>
<?php <?php
} }
?> ?>
<button type="button" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" data-on-click="streamCmdZoomOut"> <button type="button" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" data-on-click="streamCmdZoomOut">
<i class="material-icons md-18">zoom_out</i> <i class="material-icons md-18">zoom_out</i>
</button> </button>
<button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen"> <button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen">
<i class="material-icons md-18">fullscreen</i> <i class="material-icons md-18">fullscreen</i>
</button> </button>
<?php <?php
} // end if streamMode==jpeg } // end if streamMode==jpeg
?> ?>
</div> </div><!--dvrButtons-->
<div id="replayStatus"<?php echo $streamMode=="single" ? ' class="hidden"' : '' ?>>
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue"></span></span>
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"></span>x</span>
<span id="delay"><?php echo translate('Delay') ?>: <span id="delayValue"></span>s</span>
<span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span>
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
</div> </div>
<?php } // end if $monitor->Type() != 'WebSite' ?> <?php } // end if $monitor->Type() != 'WebSite' ?>
<?php <?php
@ -208,6 +361,7 @@ if ( canView('Events') && ($monitor->Type() != 'WebSite') ) {
</table> </table>
</div> </div>
</div>
<?php <?php
} }
if ( ZM_WEB_SOUND_ON_ALARM ) { if ( ZM_WEB_SOUND_ON_ALARM ) {