Merge pull request #4062 from IgorA100/patch-135

When viewing in a cycle, move to the next stream without reloading Watch page
This commit is contained in:
Isaac Connor
2024-06-07 15:54:13 -04:00
committed by GitHub
6 changed files with 364 additions and 240 deletions

View File

@@ -495,7 +495,7 @@ public static function getStatuses() {
unset($args['zones']);
$streamSrc .= '?'.http_build_query($args, '', $querySep);
$this->streamSrc = $streamSrc;
return $streamSrc;
} // end function getStreamSrc

View File

@@ -469,18 +469,6 @@ body.sticky #content {
* Generic useful classes, especially with mootools
*/
.hidden {
display: none;
}
.hidden-shift {
position: absolute !important; left: -999em !important;
}
.invisible {
visibility: hidden;
}
.nowrap {
white-space: nowrap;
}
@@ -1129,3 +1117,18 @@ html::-webkit-scrollbar-thumb, div::-webkit-scrollbar-thumb, nav::-webkit-scroll
width: 100%;
}
}
/* +++ This block should always be located at the end! */
.hidden {
display: none;
}
.hidden-shift {
position: absolute !important; left: -999em !important;
}
.invisible {
visibility: hidden;
}
/* --- This block should always be located at the end! */

View File

@@ -1152,9 +1152,13 @@ function stringToNumber(str) {
return parseInt(str.replace(/\D/g, ''));
}
const font = new FontFaceObserver('Material Icons', {weight: 400});
font.load().then(function() {
$j('.material-icons').css('display', 'inline-block');
}, function() {
$j('.material-icons').css('display', 'inline-block');
});
function loadFontFaceObserver() {
const font = new FontFaceObserver('Material Icons', {weight: 400});
font.load().then(function() {
$j('.material-icons').css('display', 'inline-block');
}, function() {
$j('.material-icons').css('display', 'inline-block');
});
}
loadFontFaceObserver();

View File

@@ -8,6 +8,7 @@ var sidebarControls = $j('#ptzControls');
var wrapperMonitor = $j('#wrapperMonitor');
var filterQuery = '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId;
var idle = 0;
var monitorStream = false; /* Stream is not started */
var classSidebarL = 'col-sm-3'; /* id="sidebar" */
var classSidebarR = 'col-sm-2'; /* id="ptzControls" */
@@ -132,36 +133,11 @@ function showPtzControls() {
showMode = 'control';
}
function changeSize() {
var width = $j('#width').val();
var height = $j('#height').val();
//monitorStream.setScale('0', width, height);
monitorsSetScale(monitorId);
//$j('#scale').val('0');
$j('#sidebar ul').height($j('#wrapperMonitor').height()-$j('#cycleButtons').height());
//setCookie('zmWatchScale', '0');
setCookie('zmWatchWidth', width);
setCookie('zmWatchHeight', height);
} // end function changeSize()
function changeScale() {
const scale = $j('#scale').val();
setCookie('zmWatchScaleNew'+monitorId, scale);
setCookie('zmCycleScale', scale);
monitorsSetScale(monitorId);
/*
const scale = $j('#scale').val();
setCookie('zmWatchScale'+monitorId, scale);
$j('#width').val('auto');
$j('#height').val('auto');
setCookie('zmCycleScale', scale);
setCookie('zmWatchWidth', 'auto');
setCookie('zmWatchHeight', 'auto');
setScale();
*/
}
function changeStreamQuality() {
@@ -170,22 +146,6 @@ function changeStreamQuality() {
monitorsSetScale(monitorId);
}
// Implement current scale, as opposed to changing it
function setScale() {
/*
const scale = $j('#scale').val();
//monitorStream.setScale(scale, $j('#width').val(), $j('#height').val());
monitorsSetScale(monitorId);
// Always turn it off, we will re-add it below. I don't know if you can add a callback multiple
// times and what the consequences would be
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
if (scale == '0') {
$j(window).on('resize', endOfResize); //remove resize handler when Scale to Fit is not active
changeSize();
}
*/
} // end function changeScale
function getStreamCmdResponse(respObj, respText) {
watchdogOk('stream');
streamCmdTimer = clearTimeout(streamCmdTimer);
@@ -335,10 +295,14 @@ function streamCmdPause(action) {
}
function onPlay() {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'active');
//monitorStream.setup_onplay(onPlay); //IgorA100 Added for testing, but probably not required
//setButtonState('pauseBtn', 'inactive');
//setButtonState('playBtn', 'active');
setButtonStateWatch('pauseBtn', 'inactive');
setButtonStateWatch('stopBtn', 'inactive');
setButtonStateWatch('playBtn', 'unavail');
if (monitorStream.status.delayed == true) {
setButtonState('stopBtn', 'inactive');
//setButtonState('stopBtn', 'inactive');
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
@@ -346,7 +310,7 @@ function onPlay() {
setButtonState('fastRevBtn', 'inactive');
}
} else {
setButtonState('stopBtn', 'unavail');
//setButtonState('stopBtn', 'unavail');
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail');
@@ -359,14 +323,21 @@ function onPlay() {
function streamCmdPlay(action) {
onPlay();
if (action) {
monitorStream.streamCommand(CMD_PLAY);
if (monitorStream.started) {
//Stream was on pause
monitorStream.streamCommand(CMD_PLAY);
} else {
//Stream has been stopped
monitorStream.start();
}
}
}
function streamCmdStop(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'unavail');
setButtonState('stopBtn', 'active');
monitorStream.onplay = false; //Without this line, "onPlay" is triggered immediately due to "if (this.onplay) this.onplay();" in MonitorStream.js
//setButtonState('pauseBtn', 'inactive');
//setButtonState('playBtn', 'unavail');
//setButtonState('stopBtn', 'active');
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail');
@@ -374,10 +345,14 @@ function streamCmdStop(action) {
setButtonState('fastRevBtn', 'unavail');
}
if (action) {
monitorStream.streamCommand(CMD_STOP);
//monitorStream.streamCommand(CMD_STOP);
monitorStream.kill();
}
setButtonState('stopBtn', 'unavail');
setButtonState('playBtn', 'active');
//setButtonState('stopBtn', 'unavail');
//setButtonState('playBtn', 'active');
setButtonStateWatch('playBtn', 'inactive');
setButtonStateWatch('stopBtn', 'unavail');
setButtonStateWatch('pauseBtn', 'unavail');
}
function streamCmdFastFwd(action) {
@@ -620,9 +595,18 @@ function fetchImage(streamImage) {
}
function handleClick(event) {
const targetId = event.target.id;
if (targetId.indexOf("nav-link") >= 0) { //Navigation through monitors
cycleStop(event.target);
const oldId = stringToNumber(document.querySelector('[id ^= "liveStream"]').id);
const newId = stringToNumber(targetId);
streamReStart(oldId, newId);
} else if (event.target.closest('#dvrControls')) { //Controls DVR
cyclePause();
}
if (panZoomEnabled) {
//event.preventDefault();
if (event.target.id) {
if (targetId) {
//We are looking for an object with an ID, because there may be another element in the button.
var obj = event.target;
} else {
@@ -909,92 +893,7 @@ function controlSetClicked() {
}
}
function streamStart() {
monitorStream = new MonitorStream(monitorData[monIdx]);
monitorStream.setBottomElement(document.getElementById('dvrControls'));
// Start the fps and status updates. give a random delay so that we don't assault the server
//monitorStream.setScale($j('#scale').val(), $j('#width').val(), $j('#height').val());
monitorsSetScale(monitorId);
monitorStream.start();
if (streamMode == 'single') {
monitorStream.setup_onclick(fetchImage);
} else {
monitorStream.setup_onclick(handleClick);
monitorStream.setup_onmove(handleMove);
}
monitorStream.setup_onpause(onPause);
monitorStream.setup_onplay(onPlay);
monitorStream.setup_onalarm(refresh_events_table);
monitorStream.setButton('enableAlarmButton', enableAlmBtn);
monitorStream.setButton('forceAlarmButton', forceAlmBtn);
monitorStream.setButton('zoomOutButton', $j('zoomOutBtn'));
if (canEdit.Monitors) {
// Will be enabled by streamStatus ajax
enableAlmBtn.on('click', cmdAlarm);
forceAlmBtn.on('click', cmdForce);
} else {
forceAlmBtn.prop('title', forceAlmBtn.prop('title') + ': disabled because cannot edit Monitors');
enableAlmBtn.prop('title', enableAlmBtn.prop('title') + ': disabled because cannot edit Monitors');
}
/*
if (streamMode == 'single') {
statusCmdTimer = setTimeout(statusCmdQuery, 200);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'status');
} else {
streamCmdTimer = setTimeout(streamCmdQuery, 200);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream');
}
if (canStream || (streamMode == 'single')) {
var streamImg = $j('#imageFeed img');
if (!streamImg) streamImg = $j('#imageFeed object');
if (!streamImg) {
console.error('No streamImg found for imageFeed');
} else {
if (streamMode == 'single') {
streamImg.click(streamImg, fetchImage);
setInterval(fetchImage, imageRefreshTimeout, $j('#imageFeed img'));
} else {
streamImg.click(function(event) {
handleClick(event);
});
streamImg.on("error", function(thing) {
console.log("Error loading image");
console.log(thing);
setInterval(fetchImage, 100, $j('#imageFeed img'));
});
}
} // end if have streamImg
} // streamMode native or single
*/
}
function initPage() {
// +++ Support of old ZoomPan algorithm
var useOldZoomPan = getCookie('zmUseOldZoomPan');
const btnZoomOutBtn = document.getElementById('zoomOutBtn'); //Zoom out button below Frame. She may not
if (useOldZoomPan) {
panZoomEnabled = false;
if (btnZoomOutBtn) {
btnZoomOutBtn.classList.remove("hidden");
}
} else {
if (btnZoomOutBtn) {
btnZoomOutBtn.classList.add("hidden");
}
}
$j("#use-old-zoom-pan").click(function() {
useOldZoomPan = this.checked;
setCookie('zmUseOldZoomPan', this.checked);
location.reload();
});
document.getElementById('use-old-zoom-pan').checked = useOldZoomPan;
// --- Support of old ZoomPan algorithm
zmPanZoom.init();
function streamPrepareStart(monitor=null) {
if (canView.Control) {
// Load the settings modal into the DOM
if (monitorType == 'Local') getSettingsModal();
@@ -1011,7 +910,7 @@ function initPage() {
}
if ((monitorType != 'WebSite') && monitorData.length) {
streamStart();
streamStart(monitor);
if (window.history.length == 1) {
$j('#closeControl').html('');
}
@@ -1052,6 +951,163 @@ function initPage() {
setInterval(reloadWebSite, monitorRefresh*1000);
}
// Manage the generate Edit button
bindButton('#editBtn', 'click', null, function onEditClick(evt) {
evt.preventDefault();
window.location.assign("?view=monitor&mid="+monitorId);
});
const el = document.querySelector('.imageFeed');
el.addEventListener('mouseenter', handleMouseEnter);
el.addEventListener('mouseleave', handleMouseLeave);
const i = setInterval(function() {
if (document.querySelector('[id ^= "liveStream"]').offsetHeight > 20) {
//You need to wait until the image appears.
clearInterval(i);
document.getElementById('monitor').classList.remove('hidden-shift');
monitorsSetScale(monitorId);
}
}, 100);
setButtonStateWatch('stopBtn', 'active');
}
function handleMouseEnter(event) {
//Displaying "Scale" and other buttons at the top of the monitor image
const id = stringToNumber(this.id);
$j('#button_zoom' + id).stop(true, true).slideDown('fast');
}
function handleMouseLeave(event) {
const id = stringToNumber(this.id);
$j('#button_zoom' + id).stop(true, true).slideUp('fast');
}
function streamStart(monitor = null) {
if (monitor) {
monitorStream = new MonitorStream(monitor);
} else {
monitorStream = new MonitorStream(monitorData[monIdx]);
}
monitorStream.setBottomElement(document.getElementById('dvrControls'));
// Start the fps and status updates. give a random delay so that we don't assault the server
//monitorStream.setScale($j('#scale').val(), $j('#width').val(), $j('#height').val());
//monitorsSetScale(monitorId);
monitorStream.start();
if (streamMode == 'single') {
monitorStream.setup_onclick(fetchImage);
} else {
monitorStream.setup_onclick(handleClick);
monitorStream.setup_onmove(handleMove);
}
monitorStream.setup_onpause(onPause);
monitorStream.setup_onplay(onPlay);
monitorStream.setup_onalarm(refresh_events_table);
monitorStream.setButton('enableAlarmButton', enableAlmBtn);
monitorStream.setButton('forceAlarmButton', forceAlmBtn);
monitorStream.setButton('zoomOutButton', $j('zoomOutBtn'));
if (canEdit.Monitors) {
// Will be enabled by streamStatus ajax
enableAlmBtn.on('click', cmdAlarm);
forceAlmBtn.on('click', cmdForce);
} else {
forceAlmBtn.prop('title', forceAlmBtn.prop('title') + ': disabled because cannot edit Monitors');
enableAlmBtn.prop('title', enableAlmBtn.prop('title') + ': disabled because cannot edit Monitors');
}
}
function streamReStart(oldId, newId) {
document.getElementById('monitor').classList.add('hidden-shift');
const el = document.querySelector('.imageFeed');
const newMonitorName = document.getElementById('nav-item-cycle'+newId).querySelector('a').textContent;
const currentMonitor = monitorData.find((o) => {
return parseInt(o["id"]) === newId;
});
const url = new URL(document.location.href);
monitorId = newId;
filterQuery = '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId;
document.querySelector('title').textContent = newMonitorName;
url.searchParams.set('mid', monitorId);
history.pushState(null, "", url);
zmPanZoom.action('disable', {id: oldId});
if (monitorStream) {
monitorStream.kill();
}
el.removeEventListener('mouseenter', handleMouseEnter);
el.removeEventListener('mouseleave', handleMouseLeave);
//Change main monitor block
document.getElementById('monitor').innerHTML = currentMonitor.streamHTML;
//Change active element of the navigation menu
document.getElementById('nav-item-cycle'+oldId).querySelector('a').classList.remove("active");
document.getElementById('nav-item-cycle'+newId).querySelector('a').classList.add("active");
//Set global variables from the current monitor
monitorWidth = currentMonitor.monitorWidth;
monitorHeight = currentMonitor.monitorHeight;
monitorType = currentMonitor.monitorType;
monitorRefresh = currentMonitor.monitorRefresh;
monitorStreamReplayBuffer = currentMonitor.monitorStreamReplayBuffer;
monitorControllable = currentMonitor.monitorControllable;
streamMode = currentMonitor.streamMode;
table.bootstrapTable('destroy');
streamPrepareStart(currentMonitor);
applyMonitorControllable(currentMonitor);
zmPanZoom.init();
loadFontFaceObserver();
//document.getElementById('monitor').classList.remove('hidden-shift');
}
function applyMonitorControllable(currentMonitor) {
if (currentMonitor.monitorControllable) {
const ptzShow = getCookie('ptzShow');
document.getElementById('ptzToggle').classList.remove("hidden");
sidebarControls.html(currentMonitor.ptzControls);
if (ptzShow) {
sidebarControls.show();
document.getElementById('ptzToggle').classList.remove("btn-secondary");
document.getElementById('ptzToggle').classList.add("btn-primary");
} else {
sidebarControls.hide();
document.getElementById('ptzToggle').classList.remove("btn-primary");
document.getElementById('ptzToggle').classList.add("btn-secondary");
}
} else {
document.getElementById('ptzToggle').classList.add("hidden");
sidebarControls.html('');
sidebarControls.hide();
}
changeObjectClass();
}
function initPage() {
// +++ Support of old ZoomPan algorithm
var useOldZoomPan = getCookie('zmUseOldZoomPan');
const btnZoomOutBtn = document.getElementById('zoomOutBtn'); //Zoom out button below Frame. She may not
if (useOldZoomPan) {
panZoomEnabled = false;
if (btnZoomOutBtn) {
btnZoomOutBtn.classList.remove("hidden");
}
} else {
if (btnZoomOutBtn) {
btnZoomOutBtn.classList.add("hidden");
}
}
$j("#use-old-zoom-pan").click(function() {
useOldZoomPan = this.checked;
setCookie('zmUseOldZoomPan', this.checked);
location.reload();
});
document.getElementById('use-old-zoom-pan').checked = useOldZoomPan;
// --- Support of old ZoomPan algorithm
zmPanZoom.init();
// Manage the BACK button
bindButton('#backBtn', 'click', null, function onBackClick(evt) {
evt.preventDefault();
@@ -1073,12 +1129,6 @@ function initPage() {
$j('#settingsModal').modal('show');
});
// Manage the generate Edit button
bindButton('#editBtn', 'click', null, function onEditClick(evt) {
evt.preventDefault();
window.location.assign("?view=monitor&mid="+monitorId);
});
bindButton('#cyclePlayBtn', 'click', null, cycleStart);
bindButton('#cyclePauseBtn', 'click', null, cyclePause);
bindButton('#cycleNextBtn', 'click', null, cycleNext);
@@ -1119,17 +1169,6 @@ function initPage() {
}
}, 10*1000);
}
$j(".imageFeed").hover(
//Displaying "Scale" and other buttons at the top of the monitor image
function() {
const id = stringToNumber(this.id);
$j('#button_zoom' + id).stop(true, true).slideDown('fast');
},
function() {
const id = stringToNumber(this.id);
$j('#button_zoom' + id).stop(true, true).slideUp('fast');
}
);
setInterval(() => {
//Updating Scale. When quickly scrolling the mouse wheel or quickly pressing Zoom In/Out, you should not set Scale very often.
@@ -1137,11 +1176,18 @@ function initPage() {
monitorsSetScale(monitorId);
updateScale = false;
}
}, 500);
}, 300);
document.getElementById('monitor').classList.remove('hidden-shift');
document.addEventListener('click', function(event) {
handleClick(event);
});
//document.getElementById('monitor').classList.remove('hidden-shift');
changeObjectClass();
changeSize();
streamPrepareStart();
if (monitorStream) {
applyMonitorControllable(monitorStream);
}
} // initPage
function watchFullscreen() {
@@ -1159,7 +1205,10 @@ function watchFullscreen() {
}
function watchAllEvents() {
window.location.replace(document.getElementById('allEventsBtn').getAttribute('data-url'));
const currentMonitor = monitorData.find((o) => {
return parseInt(o["id"]) === monitorId;
});
window.location.replace(currentMonitor.urlForAllEvents);
}
var intervalId;
@@ -1181,13 +1230,20 @@ function cyclePause() {
}
function cycleStart() {
secondsToCycle = $j('#cyclePeriod').val();
if (secondsToCycle == 0) secondsToCycle = $j('#cyclePeriod').val();
intervalId = setInterval(nextCycleView, 1000);
cycle = true;
$j('#cyclePauseBtn').show();
$j('#cyclePlayBtn').hide();
}
function cycleStop(target) {
secondsToCycle = 0;
monIdx = target.getAttribute('data-monIdx');
$j('#secondsToCycle').text('');
cyclePause();
}
function cycleNext() {
monIdx ++;
if (monIdx >= monitorData.length) {
@@ -1198,7 +1254,19 @@ function cycleNext() {
}
clearInterval(intervalId);
monitorStream.kill();
window.location.replace('?view=watch&cycle='+cycle+'&mid='+monitorData[monIdx].id+'&mode='+mode);
// +++ Start next monitor
let oldId;
if (monIdx == 0) {
oldId = monitorData[monitorData.length-1].id;
} else {
oldId = monitorData[monIdx-1].id;
}
const newId = monitorData[monIdx].id;
streamReStart(oldId, newId);
cycleStart();
// --- Start next monitor
//window.location.replace('?view=watch&cycle='+cycle+'&mid='+monitorData[monIdx].id+'&mode='+mode);
}
function cyclePrev() {
@@ -1210,8 +1278,21 @@ function cyclePrev() {
console.log('No monitorData for ' + monIdx);
}
clearInterval(intervalId);
monitorStream.stop();
window.location.replace('?view=watch&cycle='+cycle+'&mid='+monitorData[monIdx].id+'&mode='+mode);
//monitorStream.stop();
monitorStream.kill();
// +++ Start previous monitor
let oldId;
if (monIdx == monitorData.length - 1) {
oldId = monitorData[0].id;
} else {
oldId = monitorData[monIdx+1].id;
}
const newId = monitorData[monIdx].id;
streamReStart(oldId, newId);
cycleStart();
// --- Start previous monitors
//window.location.replace('?view=watch&cycle='+cycle+'&mid='+monitorData[monIdx].id+'&mode='+mode);
}
function cyclePeriodChange() {
@@ -1230,7 +1311,7 @@ function cycleToggle(e) {
button.toggleClass('btn-secondary');
button.toggleClass('btn-primary');
changeObjectClass();
changeSize();
monitorsSetScale(monitorId);
}
function ptzToggle(e) {
@@ -1245,7 +1326,7 @@ function ptzToggle(e) {
button.toggleClass('btn-secondary');
button.toggleClass('btn-primary');
changeObjectClass();
changeSize();
monitorsSetScale(monitorId);
}
function changeRate(e) {
@@ -1310,16 +1391,20 @@ function panZoomOut(el) {
function monitorsSetScale(id=null) {
//This function will probably need to be moved to the main JS file, because now used on Watch & Montage pages
if (id || typeof monitorStream !== 'undefined') {
//monitorStream used on Watch page.
if (monitorStream) {
if (monitorStream !== false) {
//monitorStream used on Watch page.
var curentMonitor = monitorStream;
} else {
} else if (typeof monitors !== 'undefined') {
//used on Montage, Watch & Event page.
var curentMonitor = monitors.find((o) => {
return parseInt(o["id"]) === id;
});
} else {
//Stream is missing
return;
}
//const el = document.getElementById('liveStream'+id);
if (panZoomEnabled) {
if (panZoomEnabled && zmPanZoom.panZoom[id]) {
var panZoomScale = zmPanZoom.panZoom[id].getScale();
} else {
var panZoomScale = 1;
@@ -1450,12 +1535,30 @@ document.onvisibilitychange = () => {
TimerHideShow = clearTimeout(TimerHideShow);
TimerHideShow = setTimeout(function() {
//Stop monitor when closing or hiding page
monitorStream.kill();
if (monitorStream) {
monitorStream.kill();
}
}, 15*1000);
} else {
//Start monitor when show page
if (!monitorStream.started) {
if (monitorStream && !monitorStream.started) {
monitorStream.start();
}
}
};
function setButtonStateWatch(element_id, btnClass) {
//Temporary function so as not to break anything else, because analysis of the setButtonState function in skin.js is required,
//and also review the logic of the buttons and more (if (this.onplay) this.onplay() in MonitorStream.js) var element = document.getElementById(element_id);
var element = document.getElementById(element_id);
if ( element ) {
element.className = btnClass;
if (btnClass == 'unavail') {
element.disabled = true;
} else {
element.disabled = false;
}
} else {
console.log('Element was null or not found in setButtonState. id:'+element_id);
}
}

View File

@@ -3,6 +3,7 @@
global $nextMid;
global $options;
global $monitors;
global $monitorsExtraData;
global $streamMode;
global $showPtzControls;
global $monitor;
@@ -53,7 +54,17 @@ monitorData[monitorData.length] = {
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $m->Id() ?>' );},
'type': '<?php echo $m->Type() ?>',
'refresh': '<?php echo $m->Refresh() ?>',
'janus_pin': '<?php echo $m->Janus_Pin() ?>'
'janus_pin': '<?php echo $m->Janus_Pin() ?>',
'streamHTML': '<?php echo str_replace(array("\r\n", "\r", "\n"), '', $monitorsExtraData[$m->Id()]['StreamHTML']) ?>',
'urlForAllEvents': '<?php echo $monitorsExtraData[$m->Id()]['urlForAllEvents'] ?>',
'ptzControls': '<?php echo str_replace(array("\r\n", "\r", "\n"), '', $monitorsExtraData[$m->Id()]['ptzControls']) ?>',
'monitorWidth': parseInt('<?php echo $m->ViewWidth() ?>'),
'monitorHeight': parseInt('<?php echo $m->ViewHeight() ?>'),
'monitorType': '<?php echo $m->Type() ?>',
'monitorRefresh': '<?php echo $m->Refresh() ?>',
'monitorStreamReplayBuffer': parseInt('<?php echo $m->StreamReplayBuffer() ?>'),
'monitorControllable': <?php echo $m->Controllable()?'true':'false' ?>,
'streamMode': '<?php echo getStreamModeMonitor($m) ?>'
};
<?php
} // end foreach monitor

View File

@@ -103,7 +103,15 @@ if (!$cycle and isset($_COOKIE['zmCycleShow'])) {
$showCycle = $_COOKIE['zmCycleShow'] == 'true';
}
#Whether to show the controls button
$hasPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' );
$hasPtzControls = false;
foreach ($monitors as $m) {
if (( ZM_OPT_CONTROL && $m->Controllable() && canView('Control') && $m->Type() != 'WebSite' )) {
//If there is control for at least one camera, then we display the block.
$hasPtzControls = true;
}
}
//$hasPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' );
$showPtzControls = false;
if ($hasPtzControls) {
$showPtzControls = true;
@@ -198,14 +206,19 @@ if (
) {
$options['scale'] = 0;
}
if ($monitor->JanusEnabled()) {
$streamMode = 'janus';
} else if ($monitor->RTSP2WebEnabled()) {
$streamMode = $monitor->RTSP2WebType();
} else {
$streamMode = getStreamMode();
function getStreamModeMonitor($monitor) {
if ($monitor->JanusEnabled()) {
$streamMode = 'janus';
} else if ($monitor->RTSP2WebEnabled()) {
$streamMode = $monitor->RTSP2WebType();
} else {
$streamMode = getStreamMode();
}
return $streamMode;
}
$streamMode = getStreamModeMonitor($monitor);
noCacheHeaders();
xhtmlHeaders(__FILE__, $monitor->Name().' - '.translate('Feed'));
getBodyTopHTML();
@@ -332,8 +345,32 @@ echo htmlSelect('cyclePeriod', $cyclePeriodOptions, $period, array('id'=>'cycleP
</div>
<ul class="nav nav-pills flex-column">
<?php
if ($monitor->Type() != 'WebSite') {
$options['state'] = true;
}
$monitorsExtraData = [];
$monitorJanusUsed = false;
$dataMonIdx=0;
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>';
$monitorsExtraData[$m->Id()]['StreamHTML'] = $m->getStreamHTML($options);
$monitorsExtraData[$m->Id()]['urlForAllEvents'] = "?view=events&page=1&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Battr%5D=Monitor&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bop%5D=%3D&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bval%5D=".$m->Id()."&filter%5BQuery%5D%5Bsort_asc%5D=1&filter%5BQuery%5D%5Bsort_field%5D=StartDateTime&filter%5BQuery%5D%5Bskip_locked%5D=&filter%5BQuery%5D%5Blimit%5D=0";
if ($m->JanusEnabled()) {
$monitorJanusUsed = true;
}
$monitorsExtraData[$m->Id()]['ptzControls'] = '';
if ($hasPtzControls) {
foreach ( getSkinIncludes('includes/control_functions.php') as $includeFile )
require_once $includeFile;
$ptzControls = ptzControls($m);
$monitorsExtraData[$m->Id()]['ptzControls'] = $ptzControls;
}
echo '<li id="nav-item-cycle'.$m->Id().'" class="nav-item"><a id="nav-link'.$m->Id().'" class="nav-link'.( $m->Id() == $monitor->Id() ? ' active' : '' ).'" data-monIdx='.$dataMonIdx++.' href="#">'.$m->Name().'</a></li>';
}
if ($monitorJanusUsed) {
?>
<script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script>
<script src="/javascript/janus/janus.js"></script>
<?php
}
?>
</ul>
@@ -342,66 +379,43 @@ echo htmlSelect('cyclePeriod', $cyclePeriodOptions, $period, array('id'=>'cycleP
<div id="monitor" class="monitor hidden-shift"
>
<?php
if ($monitor->Type() != 'WebSite') {
$options['state'] = true;
}
echo $monitor->getStreamHTML($options);
?>
</div><!-- id="Monitor" -->
<?php
if ($monitor->Type() != 'WebSite') {
?>
<div class="buttons" id="dvrControls">
<!--
<button type="button" id="getImageBtn" title="<?php echo translate('Download Image') ?>"/>
-->
<?php
if ($streamMode == 'jpeg') {
if ($monitor->StreamReplayBuffer() != 0) {
?>
<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>
</button>
<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_left</i>
</button>
<?php
}
?>
<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>
</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">
<i class="material-icons md-18">stop</i>
</button>
<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>
</button>
<?php
if ($monitor->StreamReplayBuffer() != 0) {
?>
<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>
</button>
<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>
</button>
<?php
}
?>
<button type="button" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" data-on-click="zoomOutClick">
<i class="material-icons md-18">zoom_out</i>
</button>
<?php
} // end if streamMode==jpeg
?>
</div><!--dvrControls-->
<?php } // end if $monitor->Type() != 'WebSite' ?>
<div class="buttons" id="extButton">
<button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen">
<i class="material-icons md-18">fullscreen</i>
</button>
<button type="button" id="allEventsBtn" title="<?php echo translate('All Events') ?>" class="avail" data-on-click="watchAllEvents" data-url="?view=events&page=1&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Battr%5D=Monitor&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bop%5D=%3D&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bval%5D=<?php echo $monitor->Id()?>&filter%5BQuery%5D%5Bsort_asc%5D=1&filter%5BQuery%5D%5Bsort_field%5D=StartDateTime&filter%5BQuery%5D%5Bskip_locked%5D=&filter%5BQuery%5D%5Blimit%5D=0"><?php echo translate('All Events') ?>
<button type="button" id="allEventsBtn" title="<?php echo translate('All Events') ?>" class="avail" data-on-click="watchAllEvents"><?php echo translate('All Events') ?>
</button>
</div>
</div><!-- id="wrapperMonitor" -->
@@ -409,12 +423,9 @@ if ($streamMode == 'jpeg') {
<!-- START Control -->
<?php
if ( $hasPtzControls ) {
foreach ( getSkinIncludes('includes/control_functions.php') as $includeFile )
require_once $includeFile;
?>
<div id="ptzControls" class="col-sm-2 ptzControls"<?php echo $showPtzControls ? '' : ' style="display:none;"'?>>
<?php echo ptzControls($monitor) ?>
</div>
<div id="ptzControls" class="col-sm-2 ptzControls"<?php echo $showPtzControls ? '' : ' style="display:none;"'?>>
</div>
<?php
}
?>
@@ -479,14 +490,6 @@ if ( canView('Events') && ($monitor->Type() != 'WebSite') ) {
</div>
</div>
<?php
if ( $monitor->JanusEnabled() ) {
?>
<script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script>
<script src="/javascript/janus/janus.js"></script>
<?php
}
?>
<?php
if ( $monitor->RTSP2WebEnabled() and $monitor->RTSP2WebType == "HLS") {
?>
<script src="<?php echo cache_bust('js/hls.js') ?>"></script>