diff --git a/definitions/base.js b/definitions/base.js
index 98c75748..2648b7ab 100644
--- a/definitions/base.js
+++ b/definitions/base.js
@@ -3425,6 +3425,24 @@ module.exports = function(s,config,lang){
field: lang['Probe Size'],
default: '32',
},
+ {
+ "name": "detail=detector_record_overlap",
+ "field": lang['Recording Overlap'],
+ "description": lang.fieldTextRecordingOverlap,
+ "default": "0",
+ "form-group-class-pre-layer": "h_rec_mtd_input h_rec_mtd_hot h_rec_mtd_sip",
+ "fieldType": "select",
+ "possible": [
+ {
+ "name": lang.No,
+ "value": "0"
+ },
+ {
+ "name": lang.Yes,
+ "value": "1"
+ }
+ ]
+ },
{
"fieldType": "div",
// style: `width:100%;background:#eceaea;border-radius:5px;color:#333;font-family:monospace`,
diff --git a/languages/en_CA.json b/languages/en_CA.json
index 7fe3db0c..3a16f1cb 100644
--- a/languages/en_CA.json
+++ b/languages/en_CA.json
@@ -931,6 +931,7 @@
"Account Settings": "Account Settings",
"How to Record": "How to Record",
"Trigger Record": "Trigger Record",
+ "Recording Overlap": "Recording Overlap",
"Recording Timeout": "Recording Timeout in Minutes",
"Timeout Reset on Next Motion": "Timeout Reset on Next Motion",
"Timeout Reset on Next Event": "Timeout Reset on Next Event",
@@ -1608,6 +1609,7 @@
"MQTT Client": "MQTT Client",
"Buffer Time from Event": "Buffer Time from Event",
"detected": "detected",
+ "fieldTextRecordingOverlap": "Allow multiple Event-Based Recordings to run in parallel. Only use this if you need to have a new recording started after each detector trigger.",
"fieldTextDetectorsSelected": "Select which detectors to send frames to.",
"fieldTextEventFilters": "Enable to have all Events honor your Event Filter rules.",
"fieldTextBufferTimeFromEvent": "The amount of seconds to record before the trigger happened. If this is consistently inaccurate you will need to look at the optimization guide or force encoding on the server.",
diff --git a/libs/events/utils.js b/libs/events/utils.js
index ba86a0a6..300f9770 100644
--- a/libs/events/utils.js
+++ b/libs/events/utils.js
@@ -533,32 +533,35 @@ module.exports = (s,config,lang) => {
const activeMonitor = s.group[groupKey].activeMonitors[monitorId]
const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
const monitorDetails = monitorConfig.details
+ const overlappingRecordings = monitorDetails.detector_record_overlap === '1'
if(monitorDetails.detector !== '1'){
return
}
- var detector_timeout
+ if(!overlappingRecordings && activeMonitor.eventBasedRecordingLastFileTime)fileTime = activeMonitor.eventBasedRecordingLastFileTime;
+ var detector_timeout;
if(!monitorDetails.detector_timeout||monitorDetails.detector_timeout===''){
detector_timeout = 10
}else{
detector_timeout = parseFloat(monitorDetails.detector_timeout)
}
- if(monitorDetails.watchdog_reset === '1' || !activeMonitor.eventBasedRecording.timeout){
- clearTimeout(activeMonitor.eventBasedRecording.timeout)
- activeMonitor.eventBasedRecording.timeout = setTimeout(function(){
- activeMonitor.eventBasedRecording.allowEnd = true
+ if(!activeMonitor.eventBasedRecording[fileTime])activeMonitor.eventBasedRecording[fileTime] = {};
+ if((!overlappingRecordings && monitorDetails.watchdog_reset === '1') || !activeMonitor.eventBasedRecording[fileTime].timeout){
+ clearTimeout(activeMonitor.eventBasedRecording[fileTime].timeout)
+ activeMonitor.eventBasedRecording[fileTime].timeout = setTimeout(function(){
+ activeMonitor.eventBasedRecording[fileTime].allowEnd = true
try{
- activeMonitor.eventBasedRecording.process.stdin.setEncoding('utf8')
- activeMonitor.eventBasedRecording.process.stdin.write('q')
+ activeMonitor.eventBasedRecording[fileTime].process.stdin.setEncoding('utf8')
+ activeMonitor.eventBasedRecording[fileTime].process.stdin.write('q')
}catch(err){
s.debugLog(err)
}
- activeMonitor.eventBasedRecording.process.kill('SIGINT')
- delete(activeMonitor.eventBasedRecording.timeout)
+ activeMonitor.eventBasedRecording[fileTime].process.kill('SIGINT')
+ delete(activeMonitor.eventBasedRecording[fileTime].timeout)
},detector_timeout * 1000 * 60)
}
- if(!activeMonitor.eventBasedRecording.process){
- activeMonitor.eventBasedRecording.allowEnd = false;
- activeMonitor.eventBasedRecording.lastFileTime = `${fileTime}`;
+ if(!activeMonitor.eventBasedRecording[fileTime].process){
+ activeMonitor.eventBasedRecording[fileTime].allowEnd = false;
+ activeMonitor.eventBasedRecordingLastFileTime = `${fileTime}`;
const runRecord = function(){
var ffmpegError = ''
var error
@@ -586,18 +589,18 @@ module.exports = (s,config,lang) => {
let LiveStartIndex = parseInt(secondsBefore / 2 + 1)
const ffmpegCommand = `-loglevel warning -live_start_index -${LiveStartIndex} -analyzeduration ${analyzeDuration} -probesize ${probeSize} -re -i "${s.dir.streams+groupKey+'/'+monitorId}/detectorStream.m3u8" ${outputMap}-movflags faststart -fflags +igndts -c:v copy -c:a aac -strict -2 -strftime 1 -y "${s.getVideoDirectory(monitorConfig) + filename}"`
s.debugLog(ffmpegCommand)
- activeMonitor.eventBasedRecording.process = spawn(
+ activeMonitor.eventBasedRecording[fileTime].process = spawn(
config.ffmpegDir,
splitForFFMPEG(ffmpegCommand)
)
- activeMonitor.eventBasedRecording.process.stderr.on('data',function(data){
+ activeMonitor.eventBasedRecording[fileTime].process.stderr.on('data',function(data){
s.userLog(d,{
type: logTitleText,
msg: data.toString()
})
})
- activeMonitor.eventBasedRecording.process.on('close',function(){
- if(!activeMonitor.eventBasedRecording.allowEnd){
+ activeMonitor.eventBasedRecording[fileTime].process.on('close',function(){
+ if(!activeMonitor.eventBasedRecording[fileTime].allowEnd){
s.userLog(d,{
type: logTitleText,
msg: lang["Detector Recording Process Exited Prematurely. Restarting."]
@@ -627,15 +630,15 @@ module.exports = (s,config,lang) => {
s.userLog(d,{
type: logTitleText,
msg: lang["Detector Recording Complete"]
- })
+ });
s.userLog(d,{
type: logTitleText,
msg: lang["Clear Recorder Process"]
- })
- delete(activeMonitor.eventBasedRecording.process)
- clearTimeout(activeMonitor.eventBasedRecording.timeout)
- delete(activeMonitor.eventBasedRecording.timeout)
+ });
+ if(!overlappingRecordings)delete(activeMonitor.eventBasedRecordingLastFileTime)
+ clearTimeout(activeMonitor.eventBasedRecording[fileTime].timeout)
clearTimeout(activeMonitor.recordingChecker)
+ delete(activeMonitor.eventBasedRecording[fileTime])
})
}
runRecord()
@@ -643,10 +646,13 @@ module.exports = (s,config,lang) => {
}
const closeEventBasedRecording = function(e){
const activeMonitor = s.group[e.ke].activeMonitors[e.id]
- if(activeMonitor.eventBasedRecording.process){
- clearTimeout(activeMonitor.eventBasedRecording.timeout)
- activeMonitor.eventBasedRecording.allowEnd = true
- activeMonitor.eventBasedRecording.process.kill('SIGTERM')
+ const eventBasedRecordings = activeMonitor.eventBasedRecording;
+ for(fileTime in eventBasedRecordings){
+ if(eventBasedRecordings[fileTime].process){
+ clearTimeout(eventBasedRecordings[fileTime].timeout)
+ eventBasedRecordings[fileTime].allowEnd = true
+ eventBasedRecordings[fileTime].process.kill('SIGTERM')
+ }
}
// var stackedProcesses = s.group[e.ke].activeMonitors[e.id].eventBasedRecording.stackable
// Object.keys(stackedProcesses).forEach(function(key){
diff --git a/libs/webServerPaths.js b/libs/webServerPaths.js
index 91d64083..8c20f4fc 100644
--- a/libs/webServerPaths.js
+++ b/libs/webServerPaths.js
@@ -957,6 +957,39 @@ module.exports = function(s,config,lang,app,io){
s.closeJsonResponse(res,response);
},res,req);
});
+ /**
+ * API : Get Active Event-Based Recording Info
+ */
+ app.get(config.webPaths.apiPrefix+':auth/eventRecordings/:ke/:id', function (req,res){
+ const response = {ok: false};
+ s.auth(req.params,async (user) => {
+ const groupKey = req.params.ke
+ const monitorId = req.params.id
+ const {
+ monitorPermissions,
+ monitorRestrictions,
+ } = s.getMonitorsPermitted(user.details,monitorId)
+ const {
+ isRestricted,
+ userPermissions,
+ apiKeyPermissions,
+ isRestrictedApiKey,
+ } = s.checkPermission(user)
+ if(
+ isRestrictedApiKey && apiKeyPermissions.control_monitors_disallowed ||
+ isRestricted && !monitorPermissions[`${monitorId}_monitors`]
+ ){
+ response.msg = user.lang['Not Permitted']
+ }else{
+ const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
+ const activeMonitor = s.group[groupKey].activeMonitors[monitorId]
+ const fileTimes = Object.keys(activeMonitor.eventBasedRecording)
+ response.fileTimes = fileTimes;
+ response.ok = true;
+ }
+ s.closeJsonResponse(res,response);
+ },res,req);
+ });
// /**
// * API : Merge Recorded Videos into one file
// */