`
+ const newWidth = widthRatio * matrix.width;
+ const newHeight = heightRatio * matrix.height;
+ if(drawTrails)html += `
`
+ if(matrix.tag)html += `
${matrix.tag}${!isNaN(matrix.id) ? ` ${matrix.id}`: ''} (${matrix.confidence.toFixed(2) || 0})`
if(matrix.notice)html += `
${matrix.notice}
`;
if(matrix.missingNear && matrix.missingNear.length > 0){
html += `
Missing Near
${matrix.missingRecently.map(item => `${item.tag} (${item.id}) by ${item.missedNear.tag} (${item.missedNear.id})`).join(', ')}
`;
@@ -728,7 +750,7 @@ function drawMatrices(event,options){
if(matrix.nearBy){
html += `
`
matrix.nearBy.forEach((nearMatrix) => {
- html += `
${nearMatrix.tag} ${nearMatrix.id} (${nearMatrix.overlapPercent}%)
`
+ html += `
${nearMatrix.tag} ${nearMatrix.id} (${nearMatrix.overlapPercent.toFixed(2)}%)
`
});
html += `
`
}
@@ -740,7 +762,19 @@ function drawMatrices(event,options){
}
$.each(event.details.matrices, processMatrix);
$.each(moreMatrices, processMatrix);
- theContainer.append(html)
+ var addedEls = theContainer.append(html)
+ if(autoRemoveTimeout){
+ addedEls = addedEls.find('.fresh-detected-object').removeClass('fresh-detected-object')
+ setTimeout(function(){
+ addedEls.remove()
+ }, autoRemoveTimeout);
+ }
+ if(drawTrails){
+ var addedTrails = theContainer.find('.fresh-detected-trail').removeClass('fresh-detected-trail')
+ setTimeout(function(){
+ addedTrails.remove()
+ }, 5000);
+ }
}
function setMonitorCountOnUI(){
$('.cameraCount').text(Object.keys(loadedMonitors).length)
diff --git a/web/assets/js/bs5.onvifScanner.js b/web/assets/js/bs5.onvifScanner.js
index f39221d1..170ed056 100644
--- a/web/assets/js/bs5.onvifScanner.js
+++ b/web/assets/js/bs5.onvifScanner.js
@@ -4,6 +4,8 @@ $(document).ready(function(e){
var loadedResultsByIp = {}
var monitorEditorWindow = $('#tab-monitorSettings')
var onvifScannerWindow = $('#tab-onvifScanner')
+ var onvifScannerStartButton = onvifScannerWindow.find('.start-scan')
+ var onvifScannerStopButton = onvifScannerWindow.find('.stop-scan')
var onvifScannerResultPane = onvifScannerWindow.find('.onvif_result')
var onvifScannerErrorResultPane = onvifScannerWindow.find('.onvif_result_error')
var scanForm = onvifScannerWindow.find('form');
@@ -30,86 +32,97 @@ $(document).ready(function(e){
var html = buildSubMenuItems(allFound)
sideMenuList.html(html)
}
- var setAsLoading = function(appearance){
+ var showStopButton = function(appearance){
if(appearance){
- onvifScannerWindow.find('._loading').show()
- onvifScannerWindow.find('[type="submit"]').prop('disabled',true)
+ onvifScannerStartButton.addClass('d-none')
+ onvifScannerStopButton.removeClass('d-none')
}else{
- onvifScannerWindow.find('._loading').hide()
- onvifScannerWindow.find('[type="submit"]').prop('disabled',false)
+ onvifScannerStartButton.removeClass('d-none')
+ onvifScannerStopButton.addClass('d-none')
}
}
- function drawProbeResult(options){
- if(!options.error){
- var currentUsername = onvifScannerWindow.find('[name="user"]').val()
- var currentPassword = onvifScannerWindow.find('[name="pass"]').val()
- var tempID = generateId()
- var info = options.info ? jsonToHtmlBlock(options.info) : ''
- var streamUrl = ''
- var launchWebPage = `target="_blank" href="http${options.port == 443 ? 's' : ''}://${options.ip}:${options.port}"`
- if(options.uri){
- streamUrl = options.uri
- }
- var theLocation = getLocationFromUri(options.uri)
- var pathLocation = theLocation.location
- var monitorConfigPartial = {
- name: pathLocation.hostname,
- mid: tempID + `${options.port}`,
- host: pathLocation.hostname,
- port: pathLocation.port,
- path: pathLocation.pathname + (pathLocation.search && pathLocation.search !== '?' ? pathLocation.search : ''),
- protocol: theLocation.protocol,
- details: {
- auto_host: addCredentialsToUri(streamUrl,currentUsername,currentPassword),
- muser: currentUsername,
- mpass: currentPassword,
- is_onvif: '1',
- onvif_port: options.port,
- },
- }
- if(options.isPTZ){
- monitorConfigPartial.details = Object.assign(monitorConfigPartial.details,{
- control: '1',
- control_url_method: 'ONVIF',
- control_stop: '1',
- })
- }
- var monitorAlreadyAdded = isOnvifRowAlreadyALoadedMonitor(monitorConfigPartial)
- if(monitorAlreadyAdded){
- monitorConfigPartial.mid = monitorAlreadyAdded.mid;
- }
- var monitorId = monitorConfigPartial.mid
- loadedResults[monitorId] = monitorConfigPartial;
- loadedResultsByIp[monitorConfigPartial.host] = monitorConfigPartial;
- onvifScannerResultPane.append(`
-
-
-
-
-
${info}
-
${streamUrl}
-
-
-
-
- `)
- onvifScannerWindow.find('._notfound').remove()
- setAsLoading(false)
- drawFoundCamerasSubMenu()
+
+ function drawDeviceTableRow(device, gotAccess){
+ var ip = device.ip;
+ var el = onvifScannerResultPane.find(`[scan-item="${ip}"]`)
+ var hasError = !!device.error;
+ var uriText = !hasError ? device.uri ? device.uri.split('?')[0] : '' : device.error;
+ var statusColor = hasError ? 'red' : 'green';
+ var snapShot = device.snapShot;
+ // console.log(ip, device.error, hasError)
+ if(gotAccess)loadMonitorConfigFromResult(device)
+ if(el.length === 0){
+ var html = `
+
+
+
+
${ip}
${uriText}
+
${!hasError ? makeButton({text: lang.Copy, class:'copy', color: 'primary'}) : ''}
+
+
`
+ onvifScannerResultPane.append(html)
}else{
- if(!loadedResultsByIp[options.ip]){
- onvifScannerErrorResultPane.append(`
-
-
${options.ip}:${options.port}
-
${options.error}
-
-
- `)
+ var copyButton = el.find('.copy-button');
+ var imgEl = el.find('.scan-item-img');
+ if(hasError){
+ copyButton.empty()
+ imgEl.removeClass('copy cursor-pointer')
+ }else{
+ copyButton.html(makeButton({text: lang.Copy, class:'copy', color: 'primary'}))
+ imgEl.addClass('copy cursor-pointer')
}
+ if(snapShot){
+ imgEl.css('background-image', `url("data:image/jpeg;base64,${snapShot}")`)
+ }else{
+ imgEl.css('background-image', '')
+ }
+ imgEl.css('background-color', statusColor)
+ el.find('.uri').text(uriText)
+ el.find('.card').css('border-color', statusColor)
+ el.find('.fa-circle').css('color', statusColor)
}
}
+ function loadMonitorConfigFromResult(options){
+ var monitorId = removeSpecialCharacters(options.ip)
+ var currentUsername = options.user
+ var currentPassword = options.pass
+ var streamUrl = ''
+ var launchWebPage = `target="_blank" href="http${options.port == 443 ? 's' : ''}://${options.ip}:${options.port}"`
+ if(options.uri){
+ streamUrl = options.uri
+ }
+ var theLocation = getLocationFromUri(options.uri)
+ var pathLocation = theLocation.location
+ var monitorConfigPartial = {
+ name: pathLocation.hostname,
+ mid: monitorId,
+ host: pathLocation.hostname,
+ port: pathLocation.port,
+ path: pathLocation.pathname + (pathLocation.search && pathLocation.search !== '?' ? pathLocation.search : ''),
+ protocol: theLocation.protocol,
+ details: {
+ auto_host: addCredentialsToUri(streamUrl,currentUsername,currentPassword),
+ muser: currentUsername,
+ mpass: currentPassword,
+ is_onvif: '1',
+ onvif_port: options.port,
+ },
+ }
+ if(options.isPTZ){
+ monitorConfigPartial.details = Object.assign(monitorConfigPartial.details,{
+ control: '1',
+ control_url_method: 'ONVIF',
+ control_stop: '1',
+ })
+ }
+ var monitorAlreadyAdded = isOnvifRowAlreadyALoadedMonitor(monitorConfigPartial)
+ if(monitorAlreadyAdded){
+ monitorConfigPartial.mid = monitorAlreadyAdded.mid;
+ }
+ loadedResults[monitorId] = monitorConfigPartial;
+ loadedResultsByIp[monitorConfigPartial.host] = monitorConfigPartial;
+ return monitorConfigPartial
+ }
function isOnvifRowAlreadyALoadedMonitor(onvifRow){
var matches = null;
$.each(loadedMonitors,function(n,monitor){
@@ -174,7 +187,7 @@ $(document).ready(function(e){
var form = el.serializeObject();
onvifScannerResultPane.empty();
onvifScannerErrorResultPane.empty();
- setAsLoading(true)
+ showStopButton(true)
mainSocket.f({
f: 'onvif',
ip: form.ip,
@@ -184,34 +197,80 @@ $(document).ready(function(e){
});
clearTimeout(checkTimeout)
checkTimeout = setTimeout(function(){
- if(onvifScannerResultPane.find('.card').length === 0){
- setAsLoading(false)
+ if(onvifScannerResultPane.find('[scan-item]').length === 0){
+ showStopButton(false)
onvifScannerResultPane.append(`
${lang.sorryNothingWasFound}
`)
}
},5000)
return false;
});
- onvifScannerWindow.on('click','.copy',function(){
+ onvifScannerWindow.on('click','.copy',function(e){
+ e.preventDefault()
openMonitorEditorPage()
- var el = $(this).parents('[onvif_row]');
- var id = el.attr('onvif_row');
- var onvifRecord = loadedResults[id];
+ var el = $(this).parents('[scan-item]');
+ var id = el.attr('scan-item');
+ var onvifRecord = loadedResultsByIp[id];
var streamURL = onvifRecord.details.auto_host
writeToMonitorSettingsWindow(onvifRecord)
})
onvifScannerWindow.on('click','.add-all',function(){
filterOutMonitorsThatAreAlreadyAdded(loadedResults,function(importableCameras){
- $.each(importableCameras,function(n,camera){
- // console.log(camera)
- postMonitor(camera)
- })
+ const numberOfCameras = importableCameras.length
+ if(numberOfCameras === 0){
+ new PNotify({
+ title: lang["ONVIF Scanner"],
+ text: lang.sorryNothingWasFound,
+ type: 'danger',
+ })
+ }else{
+ $.confirm.create({
+ title: lang['Add Cameras'],
+ body: `
${lang.addAllCamerasText.replace('9001', numberOfCameras)}
${importableCameras.map(item => `- ${item.host}
`).join('')}
`,
+ clickOptions: {
+ class: 'btn-success',
+ title: lang.Add,
+ },
+ clickCallback: function(){
+ $.each(importableCameras,function(n,camera){
+ // console.log(camera)
+ postMonitor(camera)
+ })
+ }
+ })
+ }
})
})
+ onvifScannerWindow.on('click','.stop-scan',function(){
+ mainSocket.f({ f: 'onvif_stop' });
+ })
+
loadLocalOptions()
+ onInitWebsocket(function (){
+ mainSocket.f({ f: 'onvif_scan_reconnect' });
+ })
onWebSocketEvent(function (d){
switch(d.f){
case'onvif':
- drawProbeResult(d)
+ try{
+ drawDeviceTableRow(d, d.ff !== 'failed_capture' && !d.failedConnection);
+ }catch(err){
+ console.error(err)
+ }
+ break;
+ case'onvif_scan_current':
+ console.log(d)
+ if(d.isScanning){
+ showStopButton(true)
+ }else{
+ showStopButton(false)
+ }
+ d.devices.forEach(device => {
+ console.log('onvif_scan_current', device)
+ drawDeviceTableRow(device, !device.error && !d.failedConnection)
+ });
+ break;
+ case'onvif_scan_complete':
+ showStopButton(false)
break;
}
})
diff --git a/web/assets/js/bs5.timeline.js b/web/assets/js/bs5.timeline.js
index c1c6a947..d9456fb3 100644
--- a/web/assets/js/bs5.timeline.js
+++ b/web/assets/js/bs5.timeline.js
@@ -8,6 +8,7 @@ $(document).ready(function(){
var timeStripObjectSearchInput = $('#timeline-video-object-search');
var dateSelector = $('#timeline-date-selector');
var sideMenuList = $(`#side-menu-link-timeline ul`)
+ var monitorList = $(`#timeline-monitor-list`)
var playToggles = timeStripControls.find('[timeline-action="playpause"]')
var speedButtons = timeStripControls.find('[timeline-action="speed"]')
var gridSizeButtons = timeStripControls.find('[timeline-action="gridSize"]')
@@ -50,6 +51,8 @@ $(document).ready(function(){
var dateRangeChanging = false
var lastDateChecked = new Date(0)
var monitorSelectionElements = []
+ var sideMenuListMissing = sideMenuList.length === 0;
+ var selectingMonitorList = (sideMenuListMissing ? monitorList : sideMenuList);
function setLoadingMask(turnOn){
if(turnOn){
if(theWindow.find('.loading-mask').length === 0){
@@ -441,7 +444,7 @@ $(document).ready(function(){
function setVideoInCanvas(newVideo){
var monitorId = newVideo.mid
var container = getVideoContainerInCanvas(newVideo)
- .removeClass('no-video').find('.film').html(`
`)
+ .removeClass('no-video').find('.film').html(`
`)
var vidEl = getVideoElInCanvas(newVideo)
var objectContainer = getObjectContainerInCanvas(newVideo)
vidEl.playbackRate = timelineSpeed
@@ -821,15 +824,16 @@ $(document).ready(function(){
})
})
var html = buildSubMenuItems(allFound)
- sideMenuList.html(html)
- monitorSelectionElements = sideMenuList.find('.timeline-selectMonitor')
+ if(!sideMenuListMissing)sideMenuList.html(html)
+ monitorList.html(html)
+ monitorSelectionElements = selectingMonitorList.find('.timeline-selectMonitor')
}
async function setSideMenuMonitorVisualSelection(){
var getForAllMonitors = timeStripSelectedMonitors.length === 0;
monitorSelectionElements.find('.dot').removeClass('dot-green')
if(!getForAllMonitors){
timeStripSelectedMonitors.forEach((monitorId) => {
- sideMenuList.find(`[data-mid="${monitorId}"] .dot`).addClass('dot-green')
+ selectingMonitorList.find(`[data-mid="${monitorId}"] .dot`).addClass('dot-green')
})
}
}
@@ -928,7 +932,7 @@ $(document).ready(function(){
refreshTimeline()
}
}
- sideMenuList.on('click','[timeline-menu-action]',function(){
+ function monitorSelectorController(){
var el = $(this)
var type = el.attr('timeline-menu-action')
switch(type){
@@ -957,7 +961,9 @@ $(document).ready(function(){
}
break;
}
- })
+ }
+ monitorList.on('click','[timeline-menu-action]', monitorSelectorController)
+ sideMenuList.on('click','[timeline-menu-action]', monitorSelectorController)
timelineActionButtons.click(function(){
var el = $(this)
var type = el.attr('timeline-action')
diff --git a/web/assets/js/bs5.videos.buttons.js b/web/assets/js/bs5.videos.buttons.js
new file mode 100644
index 00000000..963308ce
--- /dev/null
+++ b/web/assets/js/bs5.videos.buttons.js
@@ -0,0 +1,155 @@
+onWebSocketEvent(function(d){
+ switch(d.f){
+ case'video_edit':case'video_archive':
+ var video = loadedVideosInMemory[`${d.mid}${d.time}${d.type}`]
+ if(video){
+ let filename = `${formattedTimeForFilename(convertTZ(d.time),false,`YYYY-MM-DDTHH-mm-ss`)}.${video.ext || 'mp4'}`
+ loadedVideosInMemory[`${d.mid}${d.time}${d.type}`].status = d.status
+ $(`[data-mid="${d.mid}"][data-filename="${filename}"]`).attr('data-status',d.status);
+ }
+ break;
+ case'video_delete':
+ $('[file="'+d.filename+'"][mid="'+d.mid+'"]:not(.modal)').remove();
+ $('[data-file="'+d.filename+'"][data-mid="'+d.mid+'"]:not(.modal)').remove();
+ $('[data-time-formed="'+(new Date(d.time))+'"][data-mid="'+d.mid+'"]:not(.modal)').remove();
+ var videoPlayerId = getVideoPlayerTabId(d)
+ if(tabTree.name === videoPlayerId){
+ goBackOneTab()
+ }
+ deleteTab(videoPlayerId)
+ break;
+ }
+})
+$(document).ready(function(){
+ $('body')
+ .on('click','.open-video',function(e){
+ e.preventDefault()
+ var _this = this;
+ var {
+ monitorId,
+ videoTime,
+ video,
+ } = getVideoInfoFromEl(_this)
+ createVideoPlayerTab(video)
+ setVideoStatus(video)
+ return false;
+ })
+ .on('click','[video-time-seeked-video-position]',function(){
+ var el = $(this)
+ var monitorId = el.attr('data-mid')
+ var videoTime = el.attr('video-time-seeked-video-position')
+ var timeInward = (parseInt(el.attr('video-slice-seeked')) / 1000) - 2
+ var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
+ timeInward = timeInward < 0 ? 0 : timeInward
+ createVideoPlayerTab(video,timeInward)
+ })
+ .on('click','.delete-video',function(e){
+ e.preventDefault()
+ var el = $(this).parents('[data-mid]')
+ var monitorId = el.attr('data-mid')
+ var videoTime = el.attr('data-time')
+ var type = el.attr('data-type')
+ var video = loadedVideosInMemory[`${monitorId}${videoTime}${type}`]
+ var videoSet = video.videoSet
+ var ext = video.filename.split('.')
+ ext = ext[ext.length - 1]
+ var isCloudVideo = videoSet === 'cloudVideos'
+ var videoEndpoint = getApiPrefix(videoSet || 'videos') + '/' + video.mid + '/' + video.filename
+ var endpointType = isCloudVideo ? `?type=${video.type}` : ''
+ $.confirm.create({
+ title: lang["Delete Video"] + ' : ' + video.filename,
+ body: `${lang.DeleteVideoMsg}
`,
+ clickOptions: {
+ title: '
' + lang.Delete,
+ class: 'btn-danger btn-sm'
+ },
+ clickCallback: function(){
+ $.getJSON(videoEndpoint + '/delete' + endpointType,function(data){
+ if(data.ok){
+ console.log('Video Deleted')
+ }else{
+ console.log('Video Not Deleted',data,videoEndpoint + endpointType)
+ }
+ })
+ }
+ });
+ return false;
+ })
+ .on('click','.compress-video',function(e){
+ e.preventDefault()
+ var el = $(this).parents('[data-mid]')
+ var monitorId = el.attr('data-mid')
+ var videoTime = el.attr('data-time')
+ var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
+ var ext = video.filename.split('.')
+ ext = ext[ext.length - 1]
+ var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
+ $.confirm.create({
+ title: lang["Compress"] + ' : ' + video.filename,
+ body: `${lang.CompressVideoMsg}
`,
+ clickOptions: {
+ title: '
' + lang.Compress,
+ class: 'btn-primary btn-sm'
+ },
+ clickCallback: function(){
+ compressVideo(video)
+ }
+ });
+ return false;
+ })
+ .on('click','.archive-video',function(e){
+ e.preventDefault()
+ var el = $(this).parents('[data-mid]')
+ var monitorId = el.attr('data-mid')
+ var videoTime = el.attr('data-time')
+ var unarchive = $(this).hasClass('status-archived')
+ var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
+ var ext = video.filename.split('.')
+ ext = ext[ext.length - 1]
+ var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
+ if(unarchive){
+ unarchiveVideo(video)
+ }else{
+ // $.confirm.create({
+ // title: lang["Archive"] + ' : ' + video.filename,
+ // body: `${lang.ArchiveVideoMsg}
`,
+ // clickOptions: {
+ // title: '
' + lang.Archive,
+ // class: 'btn-primary btn-sm'
+ // },
+ // clickCallback: function(){
+ archiveVideo(video)
+ // }
+ // });
+ }
+ return false;
+ })
+ .on('click','.fix-video',function(e){
+ e.preventDefault()
+ var el = $(this).parents('[data-mid]')
+ var monitorId = el.attr('data-mid')
+ var videoTime = el.attr('data-time')
+ var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
+ var ext = video.filename.split('.')
+ ext = ext[ext.length - 1]
+ var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
+ $.confirm.create({
+ title: lang["Fix Video"] + ' : ' + video.filename,
+ body: `${lang.FixVideoMsg}
`,
+ clickOptions: {
+ title: '
' + lang.Fix,
+ class: 'btn-danger btn-sm'
+ },
+ clickCallback: function(){
+ $.getJSON(videoEndpoint + '/fix',function(data){
+ if(data.ok){
+ console.log('Video Fixed')
+ }else{
+ console.log('Video Not Fixed',data,videoEndpoint)
+ }
+ })
+ }
+ });
+ return false;
+ })
+})
diff --git a/web/assets/js/bs5.videos.js b/web/assets/js/bs5.videos.js
index 83ff0d36..a91a31a6 100644
--- a/web/assets/js/bs5.videos.js
+++ b/web/assets/js/bs5.videos.js
@@ -658,158 +658,3 @@ function getDisplayDimensions(videoElement) {
videoHeight: displayHeight,
};
}
-onWebSocketEvent(function(d){
- switch(d.f){
- case'video_edit':case'video_archive':
- var video = loadedVideosInMemory[`${d.mid}${d.time}${d.type}`]
- if(video){
- let filename = `${formattedTimeForFilename(convertTZ(d.time),false,`YYYY-MM-DDTHH-mm-ss`)}.${video.ext || 'mp4'}`
- loadedVideosInMemory[`${d.mid}${d.time}${d.type}`].status = d.status
- $(`[data-mid="${d.mid}"][data-filename="${filename}"]`).attr('data-status',d.status);
- }
- break;
- case'video_delete':
- $('[file="'+d.filename+'"][mid="'+d.mid+'"]:not(.modal)').remove();
- $('[data-file="'+d.filename+'"][data-mid="'+d.mid+'"]:not(.modal)').remove();
- $('[data-time-formed="'+(new Date(d.time))+'"][data-mid="'+d.mid+'"]:not(.modal)').remove();
- var videoPlayerId = getVideoPlayerTabId(d)
- if(tabTree.name === videoPlayerId){
- goBackOneTab()
- }
- deleteTab(videoPlayerId)
- break;
- }
-})
-$(document).ready(function(){
- $('body')
- .on('click','.open-video',function(e){
- e.preventDefault()
- var _this = this;
- var {
- monitorId,
- videoTime,
- video,
- } = getVideoInfoFromEl(_this)
- createVideoPlayerTab(video)
- setVideoStatus(video)
- return false;
- })
- .on('click','[video-time-seeked-video-position]',function(){
- var el = $(this)
- var monitorId = el.attr('data-mid')
- var videoTime = el.attr('video-time-seeked-video-position')
- var timeInward = (parseInt(el.attr('video-slice-seeked')) / 1000) - 2
- var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
- timeInward = timeInward < 0 ? 0 : timeInward
- createVideoPlayerTab(video,timeInward)
- })
- .on('click','.delete-video',function(e){
- e.preventDefault()
- var el = $(this).parents('[data-mid]')
- var monitorId = el.attr('data-mid')
- var videoTime = el.attr('data-time')
- var type = el.attr('data-type')
- var video = loadedVideosInMemory[`${monitorId}${videoTime}${type}`]
- var videoSet = video.videoSet
- var ext = video.filename.split('.')
- ext = ext[ext.length - 1]
- var isCloudVideo = videoSet === 'cloudVideos'
- var videoEndpoint = getApiPrefix(videoSet || 'videos') + '/' + video.mid + '/' + video.filename
- var endpointType = isCloudVideo ? `?type=${video.type}` : ''
- $.confirm.create({
- title: lang["Delete Video"] + ' : ' + video.filename,
- body: `${lang.DeleteVideoMsg}
`,
- clickOptions: {
- title: '
' + lang.Delete,
- class: 'btn-danger btn-sm'
- },
- clickCallback: function(){
- $.getJSON(videoEndpoint + '/delete' + endpointType,function(data){
- if(data.ok){
- console.log('Video Deleted')
- }else{
- console.log('Video Not Deleted',data,videoEndpoint + endpointType)
- }
- })
- }
- });
- return false;
- })
- .on('click','.compress-video',function(e){
- e.preventDefault()
- var el = $(this).parents('[data-mid]')
- var monitorId = el.attr('data-mid')
- var videoTime = el.attr('data-time')
- var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
- var ext = video.filename.split('.')
- ext = ext[ext.length - 1]
- var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
- $.confirm.create({
- title: lang["Compress"] + ' : ' + video.filename,
- body: `${lang.CompressVideoMsg}
`,
- clickOptions: {
- title: '
' + lang.Compress,
- class: 'btn-primary btn-sm'
- },
- clickCallback: function(){
- compressVideo(video)
- }
- });
- return false;
- })
- .on('click','.archive-video',function(e){
- e.preventDefault()
- var el = $(this).parents('[data-mid]')
- var monitorId = el.attr('data-mid')
- var videoTime = el.attr('data-time')
- var unarchive = $(this).hasClass('status-archived')
- var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
- var ext = video.filename.split('.')
- ext = ext[ext.length - 1]
- var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
- if(unarchive){
- unarchiveVideo(video)
- }else{
- // $.confirm.create({
- // title: lang["Archive"] + ' : ' + video.filename,
- // body: `${lang.ArchiveVideoMsg}
`,
- // clickOptions: {
- // title: '
' + lang.Archive,
- // class: 'btn-primary btn-sm'
- // },
- // clickCallback: function(){
- archiveVideo(video)
- // }
- // });
- }
- return false;
- })
- .on('click','.fix-video',function(e){
- e.preventDefault()
- var el = $(this).parents('[data-mid]')
- var monitorId = el.attr('data-mid')
- var videoTime = el.attr('data-time')
- var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
- var ext = video.filename.split('.')
- ext = ext[ext.length - 1]
- var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
- $.confirm.create({
- title: lang["Fix Video"] + ' : ' + video.filename,
- body: `${lang.FixVideoMsg}
`,
- clickOptions: {
- title: '
' + lang.Fix,
- class: 'btn-danger btn-sm'
- },
- clickCallback: function(){
- $.getJSON(videoEndpoint + '/fix',function(data){
- if(data.ok){
- console.log('Video Fixed')
- }else{
- console.log('Video Not Fixed',data,videoEndpoint)
- }
- })
- }
- });
- return false;
- })
-})
diff --git a/web/assets/js/bs5.wallvideoview.js b/web/assets/js/bs5.wallvideoview.js
new file mode 100644
index 00000000..2693a160
--- /dev/null
+++ b/web/assets/js/bs5.wallvideoview.js
@@ -0,0 +1,21 @@
+function createVideoPlayerTab(video){
+ // not real one, dummy for wallvideoview.
+ var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
+ $.confirm.create({
+ title: lang["Download"],
+ body: `
${loadedMonitors[video.mid].name}
${video.time}`,
+ clickOptions: {
+ title: '
' + lang.Download,
+ class: 'btn-success btn-sm'
+ },
+ clickCallback: function(){
+ downloadFile(videoEndpoint, video.filename)
+ }
+ });
+}
+$(document).ready(function(){
+ loadMonitorsIntoMemory(function(data){
+ openTab('timeline')
+ onDashboardReadyExecute()
+ })
+})
diff --git a/web/assets/js/bs5.wallview.js b/web/assets/js/bs5.wallview.js
new file mode 100644
index 00000000..8beb50cf
--- /dev/null
+++ b/web/assets/js/bs5.wallview.js
@@ -0,0 +1,299 @@
+var loadedMonitors = {}
+var selectedMonitors = {}
+var selectedMonitorsCount = 0
+$(document).ready(function(){
+ PNotify.prototype.options.styling = "fontawesome";
+ var wallViewMonitorList = $('#wallview-monitorList')
+ var wallViewControls = $('#wallview-controls')
+ var wallViewCanvas = $('#wallview-canvas')
+ var wallViewInfoScreen = $('#wallview-info-screen')
+ var theWindow = $(window);
+ var lastWindowWidth = theWindow.width()
+ var lastWindowHeight = theWindow.height()
+ function featureIsActivated(showNotice){
+ if(userHasSubscribed){
+ return true
+ }else{
+ if(showNotice){
+ new PNotify({
+ title: lang.activationRequired,
+ text: lang.featureRequiresActivationText,
+ type: 'warning'
+ })
+ }
+ return false
+ }
+ }
+ function createWallViewWindow(windowName){
+ var el = $(document)
+ var width = el.width()
+ var height = el.height()
+ window.open(getApiPrefix() + '/wallview/' + groupKey + (windowName ? '?window=' + windowName : ''), 'wallview_'+windowName, 'height='+height+',width='+width)
+ }
+ function getApiPrefix(innerPart){
+ return `${urlPrefix}${authKey}${innerPart ? `/${innerPart}/${groupKey}` : ''}`
+ }
+ function getWindowName(){
+ const urlParams = new URLSearchParams(window.location.search);
+ const theWindowChoice = urlParams.get('window');
+ return theWindowChoice || '1'
+ }
+ function drawMonitorListItem(monitor){
+ wallViewMonitorList.append(`
${monitor.name}`)
+ }
+ function drawMonitorList(){
+ return new Promise((resolve) => {
+ $.get(getApiPrefix('monitor'),function(monitors){
+ $.each(monitors, function(n,monitor){
+ if(monitor.mode !== 'stop' && monitor.mode !== 'idle'){
+ loadedMonitors[monitor.mid] = monitor;
+ drawMonitorListItem(monitor)
+ }
+ })
+ resolve(monitors)
+ })
+ })
+ }
+
+ function getMonitorListItem(monitorId){
+ return wallViewMonitorList.find(`[select-monitor="${monitorId}"]`)
+ }
+
+ function selectMonitor(monitorId, css){
+ css = css || {};
+ var isSelected = selectedMonitors[monitorId]
+ if(isSelected)return;
+ var numberOfSelected = Object.keys(selectedMonitors)
+ if(numberOfSelected > 3 && !featureIsActivated(true)){
+ return
+ }
+ ++selectedMonitorsCount
+ selectedMonitors[monitorId] = Object.assign({}, loadedMonitors[monitorId]);
+ wallViewCanvas.append(`
`)
+ wallViewCanvas.find(`[live-stream="${monitorId}"]`)
+ .draggable({
+ grid: [40, 40],
+ snap: '#wallview-canvas',
+ containment: "window",
+ stop: function(){
+ saveLayout()
+ }
+ })
+ .resizable({
+ grid: [40, 40],
+ snap: '#wallview-container',
+ stop: function(){
+ saveLayout()
+ }
+ });
+ getMonitorListItem(monitorId).addClass('active')
+ }
+ function deselectMonitor(monitorId){
+ --selectedMonitorsCount
+ delete(selectedMonitors[monitorId])
+ var monitorItem = wallViewCanvas.find(`[live-stream="${monitorId}"]`);
+ monitorItem.find('iframe').attr('src','about:blank')
+ monitorItem.remove()
+ getMonitorListItem(monitorId).removeClass('active')
+ }
+
+ function getCurrentLayout(){
+ var layout = []
+ wallViewCanvas.find('.wallview-video').each(function(n,v){
+ var el = $(v)
+ var monitorId = el.attr('live-stream')
+ var position = el.position()
+ layout.push({
+ monitorId,
+ css: {
+ left: position.left,
+ top: position.top,
+ width: el.width(),
+ height: el.height(),
+ }
+ })
+ })
+ return layout
+ }
+
+ function saveLayout(){
+ var windowName = getWindowName();
+ var layouts = getAllLayouts();
+ var layout = getCurrentLayout();
+ var saveContainer = {
+ layout,
+ windowInnerWidth: window.innerWidth,
+ windowInnerHeight: window.innerHeight,
+ }
+ layouts[windowName] = saveContainer;
+ localStorage.setItem('windowLayouts', JSON.stringify(layouts));
+ }
+
+ function getAllLayouts(){
+ return JSON.parse(localStorage.getItem(`windowLayouts`) || '{}');
+ }
+
+ function getLayout(full){
+ var windowName = getWindowName();
+ var saveContainer = getAllLayouts()[windowName]
+ if(full)return saveContainer || { layout: [] };
+ var layout = saveContainer.layout || []
+ return layout;
+ }
+
+ function resetWindowDimensions(){
+ var saveContainer = getLayout(true);
+ if(saveContainer.windowInnerWidth && saveContainer.windowInnerHeight){
+ var widthDiff = window.outerWidth - window.innerWidth;
+ var heightDiff = window.outerHeight - window.innerHeight;
+ lastWindowWidth = saveContainer.windowInnerWidth
+ lastWindowHeight = saveContainer.windowInnerHeight
+ window.resizeTo(saveContainer.windowInnerWidth + widthDiff, saveContainer.windowInnerHeight + heightDiff);
+ }
+ }
+
+ function loadSavedLayout(){
+ var saveContainer = getLayout(true);
+ resetWindowDimensions()
+ saveContainer.layout.forEach(function({ monitorId, css }, n){
+ selectMonitor(monitorId, css);
+ });
+ displayInfoScreen();
+ }
+
+ function displayInfoScreen(){
+ if(selectedMonitorsCount === 0){
+ wallViewInfoScreen.css('display','flex')
+ }else{
+ wallViewInfoScreen.hide()
+ }
+ }
+ function resizeMonitorItem({ monitorId, css }, oldWidth, oldHeight, newWidth, newHeight){
+ var monitorItem = wallViewCanvas.find(`[live-stream="${monitorId}"]`);
+ var newCss = rescaleMatrix(css, oldWidth, oldHeight, newWidth, newHeight)
+ monitorItem.css(newCss)
+ }
+ function rescaleMatrix(matrix, oldWidth, oldHeight, newWidth, newHeight) {
+ const scaleX = newWidth / oldWidth;
+ const scaleY = newHeight / oldHeight;
+
+ return {
+ left: matrix.left * scaleX,
+ top: matrix.top * scaleY,
+ width: matrix.width * scaleX,
+ height: matrix.height * scaleY
+ };
+ }
+
+ function onWindowResize(){
+ var currentWindowWidth = theWindow.width()
+ var currentWindowHeight = theWindow.height()
+ var layout = getCurrentLayout();
+ for(item of layout){
+ resizeMonitorItem(item,lastWindowWidth,lastWindowHeight,currentWindowWidth,currentWindowHeight)
+ }
+ lastWindowWidth = currentWindowWidth
+ lastWindowHeight = currentWindowHeight
+ }
+
+ function autoPlaceCurrentMonitorItems() {
+ const wallviewVideos = wallViewCanvas.find('.wallview-video');
+ const totalItems = wallviewVideos.length;
+
+ let numRows, numCols;
+
+ if (totalItems === 6 || totalItems === 5) {
+ numCols = 3;
+ numRows = 2;
+ } else {
+ numRows = Math.ceil(Math.sqrt(totalItems));
+ numCols = Math.ceil(totalItems / numRows);
+ }
+
+ const containerWidth = wallViewCanvas.width();
+ const containerHeight = wallViewCanvas.height();
+ const itemWidth = containerWidth / numCols;
+ const itemHeight = containerHeight / numRows;
+
+ wallviewVideos.each(function(index, element) {
+ const row = Math.floor(index / numCols);
+ const col = index % numCols;
+
+ $(element).css({
+ left: col * itemWidth,
+ top: row * itemHeight,
+ width: itemWidth,
+ height: itemHeight
+ });
+ });
+ }
+
+ function openAllMonitors(){
+ $.each(loadedMonitors,function(monitorId, monitor){
+ selectMonitor(monitorId)
+ })
+ autoPlaceCurrentMonitorItems()
+ displayInfoScreen()
+ saveLayout()
+ }
+
+ function closeAllMonitors(){
+ $.each(loadedMonitors,function(monitorId, monitor){
+ deselectMonitor(monitorId)
+ })
+ displayInfoScreen()
+ saveLayout()
+ }
+
+ drawMonitorList().then(() => {
+ loadSavedLayout()
+ setTimeout(() => {
+ theWindow.resize(() => {
+ onWindowResize()
+ saveLayout()
+ })
+ },500)
+ })
+ $('body')
+ .on('click', '[select-monitor]', function(e){
+ e.preventDefault()
+ var el = $(this);
+ var monitorId = el.attr('select-monitor')
+ var isSelected = selectedMonitors[monitorId]
+ if(isSelected){
+ deselectMonitor(monitorId)
+ }else{
+ selectMonitor(monitorId)
+ }
+ displayInfoScreen()
+ saveLayout()
+ })
+ .on('click', '.open-wallview', function(e){
+ e.preventDefault()
+ var windowName = getWindowName();
+ if(isNaN(windowName)){
+ windowName = windowName + '2'
+ }else{
+ windowName = `${parseInt(windowName) + 1}`
+ }
+ createWallViewWindow(windowName)
+ })
+ .on('click', '.wallview-autoplace', function(e){
+ e.preventDefault()
+ autoPlaceCurrentMonitorItems()
+ saveLayout()
+ })
+ .on('click', '.wallview-item-close', function(e){
+ e.preventDefault()
+ var monitorId = $(this).parents('[live-stream]').attr('live-stream')
+ deselectMonitor(monitorId)
+ })
+ .on('click', '.wallview-open-all', function(e){
+ e.preventDefault()
+ openAllMonitors()
+ })
+ .on('click', '.wallview-close-all', function(e){
+ e.preventDefault()
+ closeAllMonitors()
+ })
+})
diff --git a/web/assets/js/super.easyRemoteAccess.js b/web/assets/js/super.easyRemoteAccess.js
index a9e8b2ca..d356d270 100644
--- a/web/assets/js/super.easyRemoteAccess.js
+++ b/web/assets/js/super.easyRemoteAccess.js
@@ -7,7 +7,6 @@ $(document).ready(function(){
var remoteDashboardLinkButton = easyRemoteAccessTab.find('.remote-dashboard-link')
var loadingRegistration = false
var statusConnections = {}
- var currentlyRegisteredP2PServer = currentlySelectedP2PServerId ? currentlySelectedP2PServerId + '' : undefined
function copyToClipboard(str) {
const el = document.createElement('textarea');
el.value = str;
@@ -72,37 +71,11 @@ $(document).ready(function(){
loadingRegistration = false
easyRemoteAccessTab.find('.remote-dashboard-link').html(`
` + lang['Open Remote Dashboard'])
easyRemoteAccessTab.find('.remote-dashboard-link-copy').html(`
` + lang['Copy Remote Link'])
- displayCurrentlySelectedInternally()
- }
- function displayCurrentlySelectedInternally(){
- var selectedServer = p2pServerList[currentlyRegisteredP2PServer]
- if(selectedServer){
- var key = selectedServer.key
- var cardEl = easyRemoteAccessTab.find(`[drawn-id="${key}"]`)
- easyRemoteAccessTab.find(`[drawn-id].selected`).removeClass('selected')
- cardEl.addClass('selected')
- setCurrentRemoteLink()
- }
}
function makeHostLink(selectedServer,apiKey){
var href = `https://${selectedServer.host}:${selectedServer.webPort == 80 ? 443 : selectedServer.webPort}/s/${apiKey}/`
return href
}
- function setCurrentRemoteLink(){
- var apiKey = easyRemoteAccessForm.find('[name="p2pApiKey"]').val()
- var selectedServer = p2pServerList[currentlyRegisteredP2PServer]
- console.log(selectedServer,currentlySelectedP2PServerId,p2pServerList)
- if(selectedServer && selectedServer.host){
- var href = makeHostLink(selectedServer,apiKey)
- remoteDashboardLinkButton.attr('href',href)
- }else{
- new PNotify({
- type: 'warning',
- title: lang['P2P Server Not Selected'],
- text: lang.p2pServerNotSelectedText,
- })
- }
- }
function beginAllStatusConnections(){
$.each(p2pServerList,function(key,server){
server.key = key
@@ -127,6 +100,14 @@ $(document).ready(function(){
toggleAffected.hide()
}
}
+ function getSelectedServers(){
+ var theArray = [];
+ $(`[drawn-id].active`).each(function(){
+ var theKey = $(this).attr('drawn-id')
+ theArray.push(theKey)
+ })
+ return theArray
+ }
p2pEnabledSwitch.change(setVisibilityForList)
easyRemoteAccessTab.find('.submit').click(function(){
easyRemoteAccessForm.submit()
@@ -135,39 +116,51 @@ $(document).ready(function(){
e.preventDefault()
var formValues = $(this).serializeObject()
disableForm()
- formValues.p2pHostSelected = currentlySelectedP2PServerId
+ // formValues.p2pHostSelected = currentlySelectedP2PServerId
+ formValues.p2pHostMultiSelected = getSelectedServers()
console.log(formValues)
$.post(superApiPrefix + $user.sessionKey + '/p2p/save',{
data: JSON.stringify(formValues)
},function(data){
console.log(data)
if(data.ok){
- currentlyRegisteredP2PServer = currentlySelectedP2PServerId + ''
new PNotify({
type: 'success',
title: lang['P2P Settings Applied'],
text: lang.p2pSettingsText1,
})
- setCurrentRemoteLink()
setTimeout(enableForm,5000)
}
})
return false
})
- easyRemoteAccessForm.on('click','[drawn-id]',function(){
+ easyRemoteAccessTab.on('click','.activate-remote-selection',function(e){
+ e.preventDefault()
var el = $(this)
- var p2pServerId = el.attr('drawn-id')
- easyRemoteAccessForm.find('[drawn-id]').removeClass('active')
- el.addClass('active')
- currentlySelectedP2PServerId = p2pServerId
+ var parent = el.parents('[drawn-id]')
+ var drawnId = parent.attr('drawn-id')
+ var alreadyActive = parent.hasClass('active')
+ var selectedServer = p2pServerList[drawnId]
+ var isWss = selectedServer.p2pPort == 443
+ console.log(selectedServer)
+ if(alreadyActive){
+ parent.removeClass('active')
+ }else{
+ parent.addClass('active')
+ const drawnIdToDisable = isWss ? drawnId.replace('-ssl','') : `${drawnId}-ssl`
+ console.log(drawnIdToDisable)
+ easyRemoteAccessTab.find(`[drawn-id="${drawnIdToDisable}"]`).removeClass('active')
+ }
+ return false;
})
easyRemoteAccessTab.on('click','.remote-dashboard-link-copy',function(e){
e.preventDefault()
if(!loadingRegistration){
+ var parent = $(this).parents('[drawn-id]')
+ var drawnId = parent.attr('drawn-id')
var apiKey = easyRemoteAccessForm.find('[name="p2pApiKey"]').val()
- var selectedServer = p2pServerList[currentlyRegisteredP2PServer]
- console.log(selectedServer,currentlySelectedP2PServerId,p2pServerList)
- if(selectedServer && selectedServer.host){
+ var selectedServer = p2pServerList[drawnId]
+ if(parent.hasClass('active') && selectedServer && selectedServer.host){
var href = makeHostLink(selectedServer,apiKey)
copyToClipboard(href)
new PNotify({
@@ -183,8 +176,24 @@ $(document).ready(function(){
})
}
}
+ e.stopPropagation()
+ return false;
+ })
+ easyRemoteAccessTab.on('click','.remote-dashboard-link',function(e){
+ e.preventDefault()
+ if(!loadingRegistration){
+ var parent = $(this).parents('[drawn-id]')
+ var drawnId = parent.attr('drawn-id')
+ var apiKey = easyRemoteAccessForm.find('[name="p2pApiKey"]').val()
+ var selectedServer = p2pServerList[drawnId]
+ console.log(selectedServer,parent.hasClass('active'),parent.length)
+ if(parent.hasClass('active') && selectedServer && selectedServer.host){
+ var href = makeHostLink(selectedServer,apiKey)
+ window.open(href, '_blank').focus();
+ }
+ }
+ e.stopPropagation()
return false;
})
setVisibilityForList()
- displayCurrentlySelectedInternally()
})
diff --git a/web/pages/blocks/easyRemoteAccess.ejs b/web/pages/blocks/easyRemoteAccess.ejs
index 09683f74..5aa9cdee 100644
--- a/web/pages/blocks/easyRemoteAccess.ejs
+++ b/web/pages/blocks/easyRemoteAccess.ejs
@@ -1,5 +1,7 @@
-<% const p2pServerList = config.p2pServerList || {}
- const selectedServer = p2pServerList[config.p2pHostSelected]
+<%
+ const p2pServerList = config.p2pServerList || {}
+ const selectedServers = config.p2pHostMultiSelected
+ const multipleSelected = selectedServers instanceof Array && selectedServers.length > 0;
%>
diff --git a/web/pages/blocks/footer.ejs b/web/pages/blocks/footer.ejs
index ae6b1857..98611724 100644
--- a/web/pages/blocks/footer.ejs
+++ b/web/pages/blocks/footer.ejs
@@ -21,12 +21,15 @@
+
+
+
diff --git a/web/pages/blocks/home/monitorSettings.ejs b/web/pages/blocks/home/monitorSettings.ejs
index 8ec8b6e5..64b28dc9 100644
--- a/web/pages/blocks/home/monitorSettings.ejs
+++ b/web/pages/blocks/home/monitorSettings.ejs
@@ -42,12 +42,16 @@
diff --git a/web/pages/blocks/loginTokenAddLDAP.ejs b/web/pages/blocks/loginTokenAddLDAP.ejs
index cfd6f81d..69db0ec3 100644
--- a/web/pages/blocks/loginTokenAddLDAP.ejs
+++ b/web/pages/blocks/loginTokenAddLDAP.ejs
@@ -17,10 +17,7 @@
var buildOptions
%>
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/pages/wallview.ejs b/web/pages/wallview.ejs
new file mode 100644
index 00000000..204b6dc3
--- /dev/null
+++ b/web/pages/wallview.ejs
@@ -0,0 +1,78 @@
+
+<%
+ var forceUrlPrefix
+ var urlPrefix = ``
+ var targetPort = config.ssl && config.ssl.port && protocol === 'https' ? config.ssl.port : config.port
+ var addonsEnabled = {}
+ var rawAddonList = decodeURI(data.addon || '').split('|');
+ rawAddonList.forEach(function(piece){
+ var pieceParts = piece.split('=');
+ var key = pieceParts[0];
+ var value = pieceParts[1] || true;
+ addonsEnabled[key] = value;
+ });
+ function getAddon(addonTag){
+ return addonsEnabled[addonTag];
+ }
+ var streamWidth = parseInt(getAddon('width')) || 640
+ var streamHeight = parseInt(getAddon('height')) || 480
+ var hasGUI = getAddon('gui')
+ var isFullscreen = getAddon('fullscreen')
+ var isRelativeUrl = getAddon('relative')
+ if(forceUrlPrefix){
+ urlPrefix = forceUrlPrefix
+ }else if(isRelativeUrl){
+ urlPrefix = ''
+ }else if(config.baseURL){
+ urlPrefix = config.baseURL
+ }else if(!targetPort || targetPort === '' || targetPort == 80 || targetPort == 443){
+ urlPrefix = baseUrl
+ }else{
+ urlPrefix = `${baseUrl}:${targetPort}`
+ }
+ if(urlPrefix.endsWith('/') === false){
+ urlPrefix += '/'
+ }
+ var originalURL = `${urlPrefix}`
+%>
+<%- include('blocks/header-favicon') %>
+
+
+
+
+
+
+
+