diff --git a/definitions/base.js b/definitions/base.js
index ef70b982..630b6a83 100644
--- a/definitions/base.js
+++ b/definitions/base.js
@@ -4822,8 +4822,6 @@ module.exports = function(s,config,lang){
"name": "detail=audio_note",
"field": lang["Notification Sound"],
"description": lang["fieldTextAudioNote"],
- "default": "",
- "example": "",
"fieldType": "select",
"possible": s.listOfAudioFiles
},
@@ -4831,8 +4829,6 @@ module.exports = function(s,config,lang){
"name": "detail=audio_alert",
"field": lang["Alert Sound"],
"description": lang["fieldTextAudioAlert"],
- "default": "",
- "example": "",
"fieldType": "select",
"possible": s.listOfAudioFiles
},
@@ -4841,15 +4837,12 @@ module.exports = function(s,config,lang){
"field": lang["Alert Sound Delay"],
"description": lang["fieldTextAudioDelay"],
"default": "1",
- "example": "",
- "possible": ""
},
{
"name": "detail=event_mon_pop",
"field": lang["Popout Monitor on Event"],
"description": lang["fieldTextEventMonPop"],
"default": "en_CA",
- "example": "",
"fieldType": "select",
"possible": [
{
@@ -7449,6 +7442,7 @@ module.exports = function(s,config,lang){
streamBlockHudControlsHtml: `
+ ${lang['Add Marker']}
${lang['Test Object Event']}
${lang['Test Motion Event']}
`,
@@ -7689,6 +7683,18 @@ module.exports = function(s,config,lang){
attributes: 'shinobi-switch="dontShowDetection" ui-change-target=".dot" on-class="dot-green" off-class="dot-grey"',
color: 'grey',
},
+ {
+ label: lang[`Alert on Event`],
+ class: 'cursor-pointer',
+ attributes: 'shinobi-switch="alertOnEvent" ui-change-target=".dot" on-class="dot-green" off-class="dot-grey"',
+ color: 'grey',
+ },
+ {
+ label: lang[`Popout on Event`],
+ class: 'cursor-pointer',
+ attributes: 'shinobi-switch="popOnEvent" ui-change-target=".dot" on-class="dot-green" off-class="dot-grey"',
+ color: 'grey',
+ },
]
},
{
diff --git a/languages/en_CA.json b/languages/en_CA.json
index fd791e66..5f1b6966 100644
--- a/languages/en_CA.json
+++ b/languages/en_CA.json
@@ -748,6 +748,9 @@
"Rotate": "Rotate",
"Trigger Event": "Trigger Event",
"Test": "Test",
+ "Popout on Event": "Popout on Event",
+ "Alert on Event": "Alert on Event",
+ "Add Marker": "Add Marker",
"Test Object Event": "Test Object Event",
"Test Motion Event": "Test Motion Event",
"Primary Engine": "Primary Engine",
diff --git a/libs/basic.js b/libs/basic.js
index a12d8a69..4b63887f 100644
--- a/libs/basic.js
+++ b/libs/basic.js
@@ -207,28 +207,28 @@ module.exports = function(s,config){
}
return url
}
- s.file = function(x,e,callback){
+ s.file = async function(x,e,callback){
if(!e){e={}};
switch(x){
case'size':
return fs.statSync(e.filename)["size"];
break;
case'delete':
- if(!e){return false;}
- fs.rm(e,(err)=>{
- if(err){
- s.debugLog(err)
- if(s.isWin){
- exec('rd /s /q "' + e + '"',{detached: true},function(err){
- if(callback)callback(err)
- })
- }else{
- exec('rm -rf '+e,{detached: true},function(err){
- if(callback)callback(err)
- })
- }
+ if (!e) { return false; }
+ try{
+ return await fs.promises.rm(e, { force: true })
+ }catch(err){
+ s.debugLog(err)
+ if(s.isWin){
+ exec('rd /s /q "' + e + '"', { detached: true }, function (err) {
+ if (callback) callback(err)
+ })
+ }else{
+ exec('rm -rf ' + e, { detached: true }, function (err) {
+ if (callback) callback(err)
+ })
}
- })
+ }
break;
case'deleteFolder':
if(!e){return false;}
diff --git a/libs/events/utils.js b/libs/events/utils.js
index 03325bad..55c25bab 100644
--- a/libs/events/utils.js
+++ b/libs/events/utils.js
@@ -38,7 +38,7 @@ module.exports = (s,config,lang) => {
async function saveImageFromEvent(options,frameBuffer){
const monitorId = options.mid || options.id
const groupKey = options.ke
- if(imageSaveEventLock[groupKey + monitorId])return;
+ if(!frameBuffer || imageSaveEventLock[groupKey + monitorId])return;
const eventTime = options.time
const objectsFound = options.matrices
const monitorConfig = Object.assign({id: monitorId},s.group[groupKey].rawMonitorConfigurations[monitorId])
diff --git a/libs/monitor/utils.js b/libs/monitor/utils.js
index b2219791..80412166 100644
--- a/libs/monitor/utils.js
+++ b/libs/monitor/utils.js
@@ -748,6 +748,8 @@ module.exports = (s,config,lang) => {
})
}
function monitorIdle(e){
+ const monitorId = e.mid || e.id
+ const groupKey = e.ke
s.tx({f:'monitor_idle',mid:monitorId,ke:groupKey,time:s.formattedTime()},'GRP_'+groupKey);
s.userLog(e,{type:lang['Monitor Idling'],msg:lang.MonitorIdlingText});
s.sendMonitorStatus({
diff --git a/libs/timelapse.js b/libs/timelapse.js
index f5cd1f82..4a543e89 100644
--- a/libs/timelapse.js
+++ b/libs/timelapse.js
@@ -163,11 +163,11 @@ module.exports = function(s,config,lang,app,io){
limit: 1
},async function(){
s.setDiskUsedForGroup(e.ke,-(r.size / 1048576),'timelapseFrames')
- s.file('delete',e.fileLocation)
- const fileDirectory = getFileDirectory(folderPath);
- const folderIsEmpty = (await fs.promises.readdir(folderPath)).filter(file => file.indexOf('.jpg') > -1).length === 0;
+ await s.file('delete', e.fileLocation);
+ const fileDirectory = getFileDirectory(e.fileLocation);
+ const folderIsEmpty = (await fs.promises.readdir(fileDirectory)).filter(file => file.indexOf('.jpg') > -1).length === 0;
if(folderIsEmpty){
- await fs.rm(folderPath, { recursive: true })
+ await fs.rm(fileDirectory, { recursive: true })
}
})
}else{
diff --git a/package-lock.json b/package-lock.json
index 1aa65864..c7f2f079 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -31,7 +31,7 @@
"ldapauth-fork": "^5.0.2",
"marked": "^4.3.0",
"moment": "^2.29.4",
- "mp4frag": "^0.6.0",
+ "mp4frag": "^0.6.1",
"mqtt": "^4.3.7",
"mysql": "^2.18.1",
"mysql2": "^2.1.0",
@@ -5037,9 +5037,9 @@
}
},
"node_modules/mp4frag": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.0.tgz",
- "integrity": "sha512-MvBAaWkW94SSpam/QsCmbMi7+ZY2YHzAjj6Uno7AZ6qxH7gZstN+L3jFopdN5F3/5mRK25gvA4k0DVpCbDe7+g==",
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.1.tgz",
+ "integrity": "sha512-x2xVwVZqT+P1dmGLpBStS6Op6oownx2Q/6qh5ov3hOIH4rTNab0p6Gi/l+EliG0FKW9R6jA2eGr0vnHvJVMT9w==",
"engines": {
"node": ">=10"
}
@@ -11781,9 +11781,9 @@
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
},
"mp4frag": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.0.tgz",
- "integrity": "sha512-MvBAaWkW94SSpam/QsCmbMi7+ZY2YHzAjj6Uno7AZ6qxH7gZstN+L3jFopdN5F3/5mRK25gvA4k0DVpCbDe7+g=="
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.1.tgz",
+ "integrity": "sha512-x2xVwVZqT+P1dmGLpBStS6Op6oownx2Q/6qh5ov3hOIH4rTNab0p6Gi/l+EliG0FKW9R6jA2eGr0vnHvJVMT9w=="
},
"mqtt": {
"version": "4.3.7",
diff --git a/package.json b/package.json
index 69a54202..ee579d19 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"ldapauth-fork": "^5.0.2",
"marked": "^4.3.0",
"moment": "^2.29.4",
- "mp4frag": "^0.6.0",
+ "mp4frag": "^0.6.1",
"mqtt": "^4.3.7",
"mysql": "^2.18.1",
"mysql2": "^2.1.0",
diff --git a/web/assets/js/bs5.dashboard-base.js b/web/assets/js/bs5.dashboard-base.js
index 1e5f3077..d791a54a 100644
--- a/web/assets/js/bs5.dashboard-base.js
+++ b/web/assets/js/bs5.dashboard-base.js
@@ -1017,6 +1017,10 @@ function onDashboardReadyExecute(theAction){
function popImage(imageSrc){
$('body').append(`

`)
}
+function setSubmitButton(editorForm,text,icon,toggle){
+ var submitButtons = editorForm.find('[type="submit"]').prop('disabled',toggle)
+ submitButtons.html(` ${text}`)
+}
$(document).ready(function(){
onInitWebsocket(function(){
loadMonitorsIntoMemory(function(data){
diff --git a/web/assets/js/bs5.liveGrid.js b/web/assets/js/bs5.liveGrid.js
index 06c4a681..b0847009 100644
--- a/web/assets/js/bs5.liveGrid.js
+++ b/web/assets/js/bs5.liveGrid.js
@@ -963,6 +963,30 @@ function openAllLiveGridPlayers(){
openLiveGrid()
})
}
+function addMarkAsEvent(monitorId){
+ runTestDetectionTrigger(monitorId,{
+ "name":"Marker",
+ "reason":"marker",
+ "matrices": [
+ {
+ x: 0,
+ y: 0,
+ width: 1,
+ height: 1,
+ tag: 'Marked',
+ confidence: 100,
+ }
+ ]
+ });
+}
+function addMarkAsEventToAllOpenMonitors(){
+ $.each(loadedMonitors,function(n,monitor){
+ var monitorId = monitor.mid
+ if(liveGridPlayingNow[monitorId]){
+ addMarkAsEvent(monitorId)
+ }
+ })
+}
$(document).ready(function(e){
liveGrid
.on('dblclick','.stream-block',function(){
@@ -976,15 +1000,14 @@ $(document).ready(function(e){
.on('click','.launch-live-grid-monitor',function(){
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
if(isMobile){
- createLivePlayerTab(loadedMonitors[monitorId])
- }else{
- mainSocket.f({
- f: 'monitor',
- ff: 'watch_on',
- id: monitorId
- })
- openLiveGrid()
+ closeAllLiveGridPlayers()
}
+ mainSocket.f({
+ f: 'monitor',
+ ff: 'watch_on',
+ id: monitorId
+ })
+ openLiveGrid()
})
.on('click','.monitor-live-group-open',function(){
var monitorIds = $(this).attr('monitor-ids').split(',')
@@ -1086,6 +1109,11 @@ $(document).ready(function(e){
var monitorId = el.parents('[data-mid]').attr('data-mid')
runTestDetectionTrigger(monitorId)
})
+ .on('click','.run-monitor-detection-trigger-marker',function(){
+ var el = $(this)
+ var monitorId = el.parents('[data-mid]').attr('data-mid')
+ addMarkAsEvent(monitorId)
+ })
.on('click','.run-monitor-detection-trigger-test-motion',function(){
var el = $(this)
var monitorId = el.parents('[data-mid]').attr('data-mid')
@@ -1244,7 +1272,7 @@ $(document).ready(function(e){
}
playAudioAlert()
var monitorPop = monitorPops[monitorId]
- if($user.details.event_mon_pop === '1' && (!monitorPop || monitorPop.closed === true)){
+ if(window.popLiveOnEvent && (!monitorPop || monitorPop.closed === true)){
popOutMonitor(monitorId)
}
// console.log({
@@ -1292,12 +1320,28 @@ $(document).ready(function(e){
window.dontShowDetection = true
}
}
+ dashboardSwitchCallbacks.alertOnEvent = function(toggleState){
+ // audio_alert
+ if(toggleState !== 1){
+ window.audioAlertOnEvent = false
+ }else{
+ window.audioAlertOnEvent = true
+ }
+ }
+ dashboardSwitchCallbacks.popOnEvent = function(toggleState){
+ if($user.details.event_mon_pop === '1'){
+ window.popLiveOnEvent = true
+ }else if(toggleState !== 1){
+ window.popLiveOnEvent = false
+ }else{
+ window.popLiveOnEvent = true
+ }
+ }
dashboardSwitchCallbacks.monitorMuteAudio = function(toggleState){
var monitorMutes = dashboardOptions().monitorMutes || {}
$('.monitor_item video').each(function(n,vidEl){
var el = $(this)
var monitorId = el.parents('[data-mid]').attr('data-mid')
- console.log(monitorId,monitorMutes[monitorId])
if(toggleState === 1){
vidEl.muted = true
}else{
diff --git a/web/assets/js/bs5.liveGrid.keyboard.js b/web/assets/js/bs5.liveGrid.keyboard.js
new file mode 100644
index 00000000..6c32ee6d
--- /dev/null
+++ b/web/assets/js/bs5.liveGrid.keyboard.js
@@ -0,0 +1,41 @@
+function keyShortcutsForLiveGridUtils(enable) {
+ function cleanup(){
+ document.removeEventListener('keydown', keyShortcuts['liveGridUtils'].keydown);
+ document.removeEventListener('keyup', keyShortcuts['liveGridUtils'].keyup);
+ delete(keyShortcuts['liveGridUtils'])
+ }
+ if(enable){
+ let isKeyPressed = false;
+ function handleKeyboard(event){
+ if (isKeyPressed) {
+ return;
+ }
+ event.preventDefault();
+ switch(event.code){
+ case 'Enter':
+ addMarkAsEventToAllOpenMonitors()
+ break;
+ }
+ }
+ function handleKeyup(event) {
+ isKeyPressed = false;
+ }
+ keyShortcuts['liveGridUtils'] = {
+ keydown: handleKeyboard,
+ keyup: handleKeyup,
+ }
+ document.addEventListener('keydown', keyShortcuts['liveGridUtils'].keydown);
+ document.addEventListener('keyup', keyShortcuts['liveGridUtils'].keyup);
+ }else{
+ cleanup()
+ }
+}
+addOnTabOpen('liveGrid', function () {
+ keyShortcutsForLiveGridUtils(true)
+})
+addOnTabReopen('liveGrid', function () {
+ keyShortcutsForLiveGridUtils(true)
+})
+addOnTabAway('liveGrid', function () {
+ keyShortcutsForLiveGridUtils(false)
+})
diff --git a/web/assets/js/bs5.monitorSettings.js b/web/assets/js/bs5.monitorSettings.js
index 3460b46f..6f4f1ba4 100644
--- a/web/assets/js/bs5.monitorSettings.js
+++ b/web/assets/js/bs5.monitorSettings.js
@@ -758,10 +758,6 @@ monitorEditorWindow.on('change','[detail="auto_host"]',function(e){
}
})
editorForm.submit(function(e){
- function setSubmitButton(text,icon,toggle){
- var submitButtons = editorForm.find('[type="submit"]').prop('disabled',toggle)
- submitButtons.html(` ${text}`)
- }
e.preventDefault();
var validation = getMonitorEditFormFields()
if(!validation.ok){
@@ -770,7 +766,7 @@ editorForm.submit(function(e){
new PNotify({title:'Configuration Invalid',text:errorsFound.join('
'),type:'error'});
}
var monitorConfig = validation.monitorConfig
- setSubmitButton(lang[`Please Wait...`], `spinner fa-pulse`, true)
+ setSubmitButton(editorForm, lang[`Please Wait...`], `spinner fa-pulse`, true)
$.post(getApiPrefix()+'/configureMonitor/'+$user.ke+'/'+monitorConfig.mid,{data:JSON.stringify(monitorConfig)},function(d){
if(d.ok === false){
new PNotify({
@@ -780,7 +776,7 @@ editorForm.submit(function(e){
})
}
debugLog(d)
- setSubmitButton(lang.Save, `check`, false)
+ setSubmitButton(editorForm, lang.Save, `check`, false)
})
//
if(copySettingsSelector.val() === '1'){
diff --git a/web/assets/js/bs5.monitorStates.js b/web/assets/js/bs5.monitorStates.js
index acd15dfd..e5e59e4a 100644
--- a/web/assets/js/bs5.monitorStates.js
+++ b/web/assets/js/bs5.monitorStates.js
@@ -143,13 +143,14 @@ $(document).ready(function(){
var drawMonitor = function(preloadedData){
var MonitorSettings = definitions['Monitor Settings']
var html = ''
+ var monitorId = preloadedData ? preloadedData.mid : ''
Object.keys(MonitorSettings.blocks).forEach(function(blockKey){
var block = MonitorSettings.blocks[blockKey]
html += drawBlock(block,preloadedData)
})
var monitorSelect = ``
var fullHtml = `
diff --git a/web/assets/js/bs5.monitorsUtils.js b/web/assets/js/bs5.monitorsUtils.js
index fef182e1..f3257162 100644
--- a/web/assets/js/bs5.monitorsUtils.js
+++ b/web/assets/js/bs5.monitorsUtils.js
@@ -230,6 +230,9 @@ function toggleSubStream(monitorId,callback){
}
function playAudioAlert(){
var fileName = $user.details.audio_alert
+ if(window.audioAlertOnEvent && !fileName){
+ fileName = `alert.mp3`
+ }
if(fileName && window.soundAlarmed !== true){
window.soundAlarmed = true
var audio = new Audio(`libs/audio/${fileName}`)
diff --git a/web/assets/js/bs5.regionEditor.js b/web/assets/js/bs5.regionEditor.js
index edca3d2c..a420300c 100644
--- a/web/assets/js/bs5.regionEditor.js
+++ b/web/assets/js/bs5.regionEditor.js
@@ -113,13 +113,19 @@ $(document).ready(function(e){
});
monitorConfig.details.cords = JSON.stringify(regionCoordinates)
monitorConfig.details = JSON.stringify(monitorConfig.details)
+ setSubmitButton(regionEditorForm, lang[`Please Wait...`], `spinner fa-pulse`, true)
$.post(getApiPrefix(`configureMonitor`)+ '/' + monitorId,{
data: JSON.stringify(monitorConfig)
},function(d){
- debugLog(d)
- if(d.ok){
-
+ if(d.ok === false){
+ new PNotify({
+ title: lang['Action Failed'],
+ text: d.msg,
+ type: 'danger'
+ })
}
+ debugLog(d)
+ setSubmitButton(regionEditorForm, lang.Save, `check`, false)
})
}
var initiateRegionList = function(presetVal){
@@ -142,7 +148,7 @@ $(document).ready(function(e){
}
function setGridDisplayBasedOnFields(){
var isOn = accuracyModeToggle.val() === '1'
- var tileSize = tileSizeField.val()
+ var tileSize = tileSizeField.val() || 20
displayGridOverCanvas(isOn,tileSize)
}
function initLiveStream(monitorId){
diff --git a/web/assets/js/bs5.videos.js b/web/assets/js/bs5.videos.js
index 76b97d1b..b2eb9162 100644
--- a/web/assets/js/bs5.videos.js
+++ b/web/assets/js/bs5.videos.js
@@ -125,11 +125,11 @@ function getFrameOnVideoRow(percentageInward, video) {
};
}
- var closestFrame = frames.reduce(function(prev, curr) {
+ var closestFrame = frames.length > 0 ? frames.reduce(function(prev, curr) {
var prevDiff = Math.abs(timeAdded - new Date(prev.time));
var currDiff = Math.abs(timeAdded - new Date(curr.time));
return (prevDiff < currDiff) ? prev : curr;
- });
+ }) : null;
return {
timeInward: timeInward,
diff --git a/web/pages/blocks/footer.ejs b/web/pages/blocks/footer.ejs
index 8f24d096..a3f700b4 100644
--- a/web/pages/blocks/footer.ejs
+++ b/web/pages/blocks/footer.ejs
@@ -33,6 +33,7 @@
+