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 @@ +