var monitorEditorSelectedMonitor = null $(document).ready(function(e){ //Monitor Editor var monitorEditorWindow = $('#tab-monitorSettings') var monitorEditorTitle = $('#tab-monitorSettings-title') var monitorsForCopy = $('#copy_settings_monitors') var monitorSectionInputMaps = $('#monSectionInputMaps') var monitorStreamChannels = $('#monSectionStreamChannels') var monSectionPresets = $('#monSectionPresets') var copySettingsSelector = $('#copy_settings') var monitorPresetsSelection = $('#monitorPresetsSelection') var monitorPresetsNameField = $('#monitorPresetsName') var monitorsList = monitorEditorWindow.find('.monitors_list') var editorForm = monitorEditorWindow.find('form') var tagsInput = monitorEditorWindow.find('[name="tags"]') var triggerTagsInput = monitorEditorWindow.find('[detail=det_trigger_tags]') var fieldsLoaded = {} var sections = {} var loadedPresets = {} function generateDefaultMonitorSettings(){ var eventFilterId = generateId(5) return { "mode": "start", "mid": generateId(), "name": "Some Stream", "type": "h264", "host": "", "port": "", "path": "/", "height": "480", "width": "640", "ext": "mp4", "protocol": "http", "fps": "1", "details": { "max_keep_days": "", "notes": "", "dir": "", "rtmp_key": "", "auto_host_enable": "1", "auto_host": "", "rtsp_transport": "tcp", "muser": "", "mpass": "", "port_force": "0", "fatal_max": "0", "skip_ping": null, "is_onvif": null, "onvif_port": "", "primary_input": "0", "aduration": "1000000000", "probesize": "1000000000", "stream_loop": "0", "sfps": "", "accelerator": "0", "hwaccel": "auto", "hwaccel_vcodec": "", "hwaccel_device": "", "use_coprocessor": null, "stream_type": "hls", "stream_flv_type": "http", "stream_flv_maxLatency": "", "stream_mjpeg_clients": "", "stream_vcodec": "copy", "stream_acodec": "no", "hls_time": "2", "hls_list_size": "3", "preset_stream": "ultrafast", "signal_check": "10", "signal_check_log": "0", "stream_quality": "15", "stream_fps": "2", "stream_scale_x": "", "stream_scale_y": "", "rotate_stream": "no", "svf": "", "tv_channel": "0", "tv_channel_id": "", "tv_channel_group_title": "", "stream_timestamp": "0", "stream_timestamp_font": "", "stream_timestamp_font_size": "", "stream_timestamp_color": "", "stream_timestamp_box_color": "", "stream_timestamp_x": "", "stream_timestamp_y": "", "stream_watermark": "0", "stream_watermark_location": "", "stream_watermark_position": "tr", "snap": "0", "snap_fps": "", "snap_scale_x": "", "snap_scale_y": "", "snap_vf": "", "vcodec": "copy", "crf": "1", "acodec": "no", "record_scale_y": "", "record_scale_x": "", "cutoff": "15", "rotate_record": "no", "vf": "", "timestamp": "0", "timestamp_font": "", "timestamp_font_size": "10", "timestamp_color": "white", "timestamp_box_color": "0x00000000@1", "timestamp_x": "(w-tw)/2", "timestamp_y": "0", "watermark": "0", "watermark_location": "", "watermark_position": "tr", "record_timelapse": null, "record_timelapse_mp4": null, "record_timelapse_fps": null, "record_timelapse_scale_x": "", "record_timelapse_scale_y": "", "record_timelapse_vf": "", "record_timelapse_watermark": null, "record_timelapse_watermark_location": "", "record_timelapse_watermark_position": null, "cust_input": "", "cust_stream": "", "cust_snap": "", "cust_record": "", "cust_detect": "", "cust_sip_record": "", "custom_output": "", "detector": "0", "detector_http_api": null, "detector_send_frames": "1", "detector_lock_timeout": "", "detector_save": "1", "detector_fps": "", "detector_scale_x": "640", "detector_scale_y": "480", "detector_record_method": "sip", "detector_trigger": "1", "detector_timeout": "0.5", "detector_send_video_length": "", "watchdog_reset": "1", "detector_delete_motionless_videos": "0", "det_trigger_tags": "", "detector_webhook": "0", "detector_webhook_url": "", "detector_webhook_method": null, "detector_command_enable": "0", "detector_command": "", "detector_command_timeout": "", "detector_mail": "0", "detector_mail_timeout": "", "detector_discordbot": null, "detector_discordbot_send_video": null, "detector_discordbot_timeout": "", "use_detector_filters": "0", "use_detector_filters_object": "1", "cords": "[]", "detector_filters": { [eventFilterId]: { "id": eventFilterId, "enabled": "1", "filter_name": "Standard Object Detection Filter", "where": [ { "p1": "tag", "p2": "!indexOf", "p3": "person", "p4": "&&" }, { "p1": "tag", "p2": "!indexOf", "p3": "car", "p4": "&&" }, { "p1": "tag", "p2": "!indexOf", "p3": "truck", "p4": "&&" } ], "actions": { "halt": "1", "save": "", "indifference": "", "webhook": "", "command": "", "record": "", "emailClient": "", "global_webhook": "" } } }, "detector_pam": "1", "detector_show_matrix": null, "detector_sensitivity": "", "detector_max_sensitivity": "", "detector_threshold": "1", "detector_color_threshold": "", "detector_frame": "0", "detector_noise_filter": null, "detector_noise_filter_range": "", "detector_notrigger": "0", "detector_notrigger_mail": "0", "detector_notrigger_timeout": "", "detector_audio": null, "detector_audio_min_db": "", "detector_audio_max_db": "", "detector_use_detect_object": "0", "detector_send_frames_object": null, "detector_obj_region": null, "detector_use_motion": "1", "detector_fps_object": "", "detector_scale_x_object": "", "detector_scale_y_object": "", "detector_lisence_plate": "0", "detector_lisence_plate_country": "us", "detector_buffer_vcodec": "auto", "detector_buffer_acodec": null, "detector_buffer_fps": "", "detector_buffer_hls_time": "", "detector_buffer_hls_list_size": "", "detector_buffer_start_number": "", "detector_buffer_live_start_index": "", "control": "0", "control_base_url": "", "control_url_method": null, "control_digest_auth": null, "control_stop": "0", "control_url_stop_timeout": "", "control_url_center": "", "control_url_left": "", "control_url_left_stop": "", "control_url_right": "", "control_url_right_stop": "", "control_url_up": "", "control_url_up_stop": "", "control_url_down": "", "control_url_down_stop": "", "control_url_enable_nv": "", "control_url_disable_nv": "", "control_url_zoom_out": "", "control_url_zoom_out_stop": "", "control_url_zoom_in": "", "control_url_zoom_in_stop": "", "loglevel": "warning", "sqllog": "0", "detector_cascades": "", "stream_channels": "", "input_maps": "", "input_map_choices": "", "substream": { "input": { "type": "h264", "fulladdress": "", "sfps": "", "aduration": "", "probesize": "", "stream_loop": null, "rtsp_transport": "", "accelerator": "0", "hwaccel": null, "hwaccel_vcodec": "", "hwaccel_device": "", "cust_input": "" }, "output": { "stream_type": "hls", "rtmp_server_url": "", "rtmp_stream_key": "", "stream_mjpeg_clients": "", "stream_vcodec": "copy", "stream_acodec": "no", "hls_time": "", "hls_list_size": "", "preset_stream": "", "stream_quality": "", "stream_v_br": "", "stream_a_br": "", "stream_fps": "", "stream_scale_x": "640", "stream_scale_y": "480", "stream_rotate": null, "svf": "", "cust_stream": "" } } } } } var getHumanizedMonitorConfig = function(monitor){ var humanizedMonitorKeys = {} $.each(monitor,function(key,value){ if(key === 'details'){ humanizedMonitorKeys.details = {} $.each(value,function(key,value){ humanizedMonitorKeys.details[fieldsLoaded[`detail=${key}`] && fieldsLoaded[`detail=${key}`].field ? fieldsLoaded[`detail=${key}`].field + ` (${key})` : key] = value }) }else{ humanizedMonitorKeys[fieldsLoaded[key] && fieldsLoaded[key].field ? fieldsLoaded[key].field : key] = value } }) return humanizedMonitorKeys } var getSelectedMonitorInfo = function(){ var groupKey = monitorEditorWindow.attr('data-ke') var monitorId = monitorEditorWindow.attr('data-mid') return { ke: groupKey, mid: monitorId, auth: $user.auth_token, } } var differentiateMonitorConfig = function(firstConfig,secondConfig){ console.log(firstConfig,secondConfig) var diffedConfig = {} var firstConfigEditable = Object.assign(firstConfig,{details:safeJsonParse(firstConfig.details)}) var secondConfigEditable = Object.assign(secondConfig,{details:safeJsonParse(secondConfig.details)}) var theDiff = diffObject(firstConfigEditable,secondConfigEditable) console.log(theDiff) return theDiff } var copyMonitorSettingsToSelected = function(monitorConfig){ var monitorDetails = safeJsonParse(monitorConfig.details); var copyMonitors = monitorsForCopy.val().filter((monitorId) => { return monitorConfig.mid !== monitorId }); var chosenSections = []; var chosenMonitors = {}; if(!copyMonitors||copyMonitors.length===0){ new PNotify({title:lang['No Monitors Selected'],text:lang.monSavedButNotCopied}) return } monitorEditorWindow.find('[copy]').each(function(n,v){ var el = $(v) if(el.val() === '1'){ chosenSections.push(el.attr('copy')) } }) var alterSettings = function(settingsToAlter,monitor){ monitor.details = safeJsonParse(monitor.details); var searchElements = [] if(settingsToAlter.indexOf('field=') > -1){ var splitSettingsToAlter = settingsToAlter.split('=') if(splitSettingsToAlter[1] === 'detail' && splitSettingsToAlter[2]){ searchElements = monitorEditorWindow.find(`[detail="${splitSettingsToAlter[2]}"]`) }else{ searchElements = monitorEditorWindow.find(`[name="${splitSettingsToAlter[1]}"]`) } }else{ searchElements = monitorEditorWindow.find(settingsToAlter).find('input,select,textarea') } searchElements.each(function(n,v){ var el = $(v); var name = el.attr('name') var detail = el.attr('detail') var value switch(true){ case !!name: var value = monitorConfig[name] monitor[name] = value; break; case !!detail: detail = detail.replace('"','') var value = monitorDetails[detail] monitor.details[detail] = value; break; } }) monitor.details = JSON.stringify(monitor.details); return monitor; } $.each(copyMonitors,function(n,id){ var monitor if(monitorConfig.id === id)return; if(id === '$New'){ monitor = generateDefaultMonitorSettings(); //connection monitor.name = monitorConfig.name+' - '+monitor.mid monitor.type = monitorConfig.type monitor.protocol = monitorConfig.protocol monitor.host = monitorConfig.host monitor.port = monitorConfig.port monitor.path = monitorConfig.path monitor.details.fatal_max = monitorDetails.fatal_max monitor.details.port_force = monitorDetails.port_force monitor.details.muser = monitorDetails.muser monitor.details.password = monitorDetails.password monitor.details.rtsp_transport = monitorDetails.rtsp_transport monitor.details.auto_host = monitorDetails.auto_host monitor.details.auto_host_enable = monitorDetails.auto_host_enable //input monitor.details.aduration = monitorDetails.aduration monitor.details.probesize = monitorDetails.probesize monitor.details.stream_loop = monitorDetails.stream_loop monitor.details.sfps = monitorDetails.sfps monitor.details.accelerator = monitorDetails.accelerator monitor.details.hwaccel = monitorDetails.hwaccel monitor.details.hwaccel_vcodec = monitorDetails.hwaccel_vcodec monitor.details.hwaccel_device = monitorDetails.hwaccel_device }else{ monitor = Object.assign({},loadedMonitors[id]); } $.each(chosenSections,function(n,section){ monitor = alterSettings(section,monitor) }) $.post(getApiPrefix()+'/configureMonitor/'+$user.ke+'/'+monitor.mid,{data:JSON.stringify(monitor)},function(d){ debugLog(d) }) chosenMonitors[monitor.mid] = monitor; }) } window.getMonitorEditFormFields = function(){ var response = {ok: true} var monitorConfig = editorForm.serializeObject() var errorsFound = [] $.each(monitorConfig,function(n,v){monitorConfig[n]=v.trim()}); $.each(['fps','width','height','port'],function(n,key){ monitorConfig[key] = !isNaN(monitorConfig[key]) ? parseFloat(monitorConfig[key]) : monitorConfig[key] }) monitorConfig.mid = monitorConfig.mid.replace(/[^\w\s]/gi,'').replace(/ /g,'') if(monitorConfig.mid.length < 3){errorsFound.push('Monitor ID too short')} if(monitorConfig.port == ''){ if(monitorConfig.protocol === 'https'){ monitorConfig.port = 443 }else{ monitorConfig.port = 80 } } if(monitorConfig.name == ''){errorsFound.push('Monitor Name cannot be blank')} //edit details monitorConfig.details = safeJsonParse(monitorConfig.details) monitorConfig.details.substream = getSubStreamChannelFields() monitorConfig.details.input_map_choices = monitorSectionInputMapsave() // TODO : Input Maps and Stream Channels (does old way at the moment) // if(monitorConfig.protocol=='rtsp'){monitorConfig.ext='mp4',monitorConfig.type='rtsp'} if(errorsFound.length > 0){ response.ok = false response.errors = errorsFound return response; } response.monitorConfig = monitorConfig return response } function drawMonitorSettingsSubMenu(){ drawSubMenuItems('monitorSettings',definitions['Monitor Settings']) } function getAdditionalInputMapFields(tempID,channelId){ var fieldInfo = monitorSettingsAdditionalInputMapFieldHtml.replaceAll('$[TEMP_ID]',tempID).replaceAll('$[NUMBER]',channelId) return fieldInfo } function getAdditionalStreamChannelFields(tempID,channelId){ var fieldInfo = monitorSettingsAdditionalStreamChannelFieldHtml.replaceAll('$[TEMP_ID]',tempID).replaceAll('$[NUMBER]',channelId) return fieldInfo } addOnTabOpen('monitorSettings', function () { setFieldVisibility() drawMonitorSettingsSubMenu() }) addOnTabReopen('monitorSettings', function () { setFieldVisibility() drawMonitorSettingsSubMenu() }) function drawInputMapHtml(options){ var tmp = '' var tempID = generateId() options = options ? options : {} if(!options.channel){ var numberOfChannelsDrawn = $('#monSectionInputMaps .input-map').length options.channel = numberOfChannelsDrawn+1 } tmp+=getAdditionalInputMapFields(tempID,options.channel) monitorSectionInputMaps.append(tmp) monitorSectionInputMaps.find('.input-map').last().find('[map-detail="aduration"]').change() return tempID; } function drawStreamChannelHtml(options){ var tmp = '' var tempID = generateId() options = options ? options : {} if(!options.channel){ var numberOfChannelsDrawn = $('#monSectionStreamChannels .stream-channel').length options.channel=numberOfChannelsDrawn } tmp+=`${getAdditionalStreamChannelFields(tempID,options.channel)}` monitorStreamChannels.append(tmp) monitorStreamChannels.find('.stream-channel').last().find('[channel-detail="stream_vcodec"]').change() return tempID; } function replaceMap(string,mapNumber){ var newString = string.split(':') newString[0] = `${mapNumber}` return newString.join(':') } function replaceMapInName(string,mapNumber){ var newString = string.split('(') newString[1] = replaceMap(newString[1],mapNumber) var lastIndex = newString.length - 1 if(!newString[lastIndex].endsWith(')')){ newString[lastIndex] = newString + ')' } return newString.join('(') } function buildMapSelectorOptionsBasedOnAddedMaps(){ var baseOptionSet = definitions['Monitor Settings'].blocks.Input.info.find((item) => {return item.name === 'detail=primary_input'}).possible var newOptGroup = [baseOptionSet] var addedInputMaps = monitorEditorWindow.find('.input-map') $.each(addedInputMaps,function(n){ var mapNumber = n + 1 var newOptionSet = [] $.each(baseOptionSet,function(nn,option){ newOptionSet.push({ "name": replaceMapInName(option.name,mapNumber), "value": replaceMap(option.value,mapNumber) }) }) newOptGroup[mapNumber] = newOptionSet }) return newOptGroup } function drawInputMapSelectorHtml(options,parent){ if(!options.map)options.map = ''; var availableInputMapSelections = buildMapSelectorOptionsBasedOnAddedMaps() var html = `
` parent.prepend(html) } function importIntoMonitorEditor(options){ var monitorConfig = options.values || options var monitorId = monitorConfig.mid var monitorDetails = safeJsonParse(monitorConfig.details); var monitorTags = monitorConfig.tags ? monitorConfig.tags.split(',') : [] var monitorGroups = monitorDetails.groups ? safeJsonParse(monitorDetails.groups) : [] monitorTags = monitorTags.concat(monitorGroups) loadMonitorGroupTriggerList() $.get(getApiPrefix()+'/hls/'+monitorConfig.ke+'/'+monitorConfig.mid+'/detectorStream.m3u8',function(data){ $('#monEditBufferPreview').html(data) }) tagsInput.tagsinput('removeAll'); monitorTags.forEach((tag) => { tagsInput.tagsinput('add',tag); }); monitorEditorWindow.find('.edit_id').text(monitorConfig.mid); monitorEditorWindow.attr('data-mid',monitorConfig.mid).attr('data-ke',monitorConfig.ke) $.each(monitorConfig,function(n,v){ monitorEditorWindow.find('[name="'+n+'"]').val(v).change() }) //get maps monitorSectionInputMaps.empty() if(monitorDetails.input_maps && monitorDetails.input_maps !== ''){ var input_maps = safeJsonParse(monitorDetails.input_maps) if(input_maps.length > 0){ showInputMappingFields() $.each(input_maps,function(n,v){ var tempID = drawInputMapHtml() var parent = $('#monSectionMap'+tempID) $.each(v,function(m,b){ parent.find('[map-detail="'+m+'"]').val(b).change() }) }) }else{ showInputMappingFields(false) } } //get channels monitorStreamChannels.empty() if(monitorDetails.stream_channels&&monitorDetails.stream_channels!==''){ var stream_channels try{ stream_channels = safeJsonParse(monitorDetails.stream_channels) }catch(er){ stream_channels = monitorDetails.stream_channels; } $.each(stream_channels,function(n,v){ var tempID = drawStreamChannelHtml() var parent = $('#monSectionChannel'+tempID) $.each(v,function(m,b){ parent.find('[channel-detail="'+m+'"]').val(b) }) }) } //get map choices for outputs monitorEditorWindow.find('[input-mapping] .choices').empty() if(monitorDetails.input_map_choices&&monitorDetails.input_map_choices!==''){ var input_map_choices try{ input_map_choices = safeJsonParse(monitorDetails.input_map_choices) }catch(er){ input_map_choices = monitorDetails.input_map_choices; } $.each(input_map_choices,function(n,v){ $.each(safeJsonParse(v),function(m,b){ var parent = $('[input-mapping="'+n+'"] .choices') drawInputMapSelectorHtml(b,parent) }) }) } // substream $.each(['input','output'],function(n,direction){ // detail-substream-input // detail-substream-output var keyName = `detail-substream-${direction}` monitorEditorWindow.find(`[${keyName}]`).each(function(n,el){ var key = $(el).attr(keyName); var value = monitorDetails.substream && monitorDetails.substream[direction] ? monitorDetails.substream[direction][key] : '' monitorEditorWindow.find(`[${keyName}="${key}"]`).val(value).change(); }) }) // monitorEditorWindow.find('[detail]').each(function(n,v){ v=$(v).attr('detail');if(!monitorDetails[v]){monitorDetails[v]=''} }) $.each(monitorDetails,function(n,v){ var theVal = v; if(v instanceof Object){ theVal = JSON.stringify(v); } monitorEditorWindow.find('[detail="'+n+'"]').val(theVal).change(); }); $.each(monitorDetails,function(n,v){ try{ var variable=safeJsonParse(v) }catch(err){ var variable=v } if(variable instanceof Object){ $('[detailContainer="'+n+'"][detailObject]').prop('checked',false) $('[detailContainer="'+n+'"][detailObject]').parents('.mdl-js-switch').removeClass('is-checked') if(variable instanceof Array){ $.each(variable,function(m,b,parentOfObject){ $('[detailContainer="'+n+'"][detailObject="'+b+'"]').prop('checked',true) parentOfObject=$('[detailContainer="'+n+'"][detailObject="'+b+'"]').parents('.mdl-js-switch') parentOfObject.addClass('is-checked') }) }else{ $.each(variable,function(m,b){ if(typeof b ==='string'){ $('[detailContainer="'+n+'"][detailObject="'+m+'"]').val(b).change() }else{ $('[detailContainer="'+n+'"][detailObject="'+m+'"]').prop('checked',true) parentOfObject=$('[detailContainer="'+n+'"][detailObject="'+m+'"]').parents('.mdl-js-switch') parentOfObject.addClass('is-checked') } }) } } }); copySettingsSelector.val('0').change() var tmp = ''; $.each(loadedMonitors,function(n,monitor){ if(monitor.ke === $user.ke){ tmp += createOptionHtml({ value: monitor.mid, label: monitor.name }) } }) monitorsForCopy.find('optgroup').html(tmp) setFieldVisibility() drawMonitorSettingsSubMenu() } //parse "Automatic" field in "Input" Section monitorEditorWindow.on('change','.auto_host_fill input,.auto_host_fill select',function(e){ var theSwitch = monitorEditorWindow.find('[detail="auto_host_enable"]').val() if(!theSwitch||theSwitch===''){ theSwitch='1' } if(theSwitch==='1'){ return } if(monitorEditorWindow.find('[name="host"]').val() !== ''){ monitorEditorWindow.find('[detail="auto_host"]').val(buildMonitorURL()) } }) monitorEditorWindow.on('change','[detail="auto_host"]',function(e){ var isRTSP = false var inputType = monitorEditorWindow.find('[name="type"]').val() var url = $(this).val() var theSwitch = monitorEditorWindow.find('[detail="auto_host_enable"]') var disabled = theSwitch.val() if(!disabled||disabled===''){ //if no value, then probably old version of monitor config. Set to Manual to avoid confusion. disabled='0' theSwitch.val('0').change() } if(disabled==='0'){ return } if(inputType === 'local'){ monitorEditorWindow.find('[name="path"]').val(url).change() }else{ var urlSplitByDots = url.split('.') var has = function(query,searchIn){if(!searchIn){searchIn=url;};return url.indexOf(query)>-1} var protocol = url.split('://')[0] console.log(url.split('://')) //switch RTSP, RTMP and RTMPS to parse URL if(has('rtsp://')){ isRTSP = true; url = url.replace('rtsp://','http://') } if(has('rtmp://')){ isRTMP = true; url = url.replace('rtmp://','http://') } if(has('rtmps://')){ isRTMPS = true; url = url.replace('rtmps://','http://') } //parse URL var parsedURL = document.createElement('a'); parsedURL.href = url; var pathname = parsedURL.pathname if(url.indexOf('?') > -1){ pathname += '?'+url.split('?')[1] } monitorEditorWindow.find('[name="protocol"]').val(protocol).change() if(isRTSP){ monitorEditorWindow.find('[detail="rtsp_transport"]').val('tcp').change() monitorEditorWindow.find('[detail="aduration"]').val(1000000).change() monitorEditorWindow.find('[detail="probesize"]').val(1000000).change() } monitorEditorWindow.find('[detail="muser"]').val(parsedURL.username).change() monitorEditorWindow.find('[detail="mpass"]').val(parsedURL.password).change() monitorEditorWindow.find('[name="host"]').val(parsedURL.hostname).change() monitorEditorWindow.find('[name="port"]').val(parsedURL.port).change() monitorEditorWindow.find('[name="path"]').val(pathname).change() delete(parsedURL) } }) 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){ var errorsFound = validation.errors $.sM.e.find('.msg').html(errorsFound.join('