]> www.vanbest.org Git - motioneye-debian/commitdiff
added webhook/command support for media file creation; most of the
authorCalin Crisan <ccrisan@gmail.com>
Fri, 27 Nov 2015 18:31:27 +0000 (20:31 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Fri, 27 Nov 2015 18:37:09 +0000 (20:37 +0200)
settings panel logic ported to html

motioneye/__init__.py
motioneye/config.py
motioneye/static/css/ui.css
motioneye/static/js/main.js
motioneye/templates/main.html

index b081463876c7bd5888bbb92e9144bb2afde4a577..425492f6927000ddac81bb155679fa37bbf411d1 100644 (file)
@@ -1,2 +1,2 @@
 
-VERSION = "0.29rc1"
+VERSION = "0.29rc1-git"
index 2d653fe4aefe4558762c762c829282dc73b1bb69..d056171696e1fc83a1fc99245b76b4f3e1cf9f5b 100644 (file)
@@ -576,8 +576,6 @@ def rem_camera(camera_id):
 
 def main_ui_to_dict(ui):
     data = {
-        '@enabled': ui['enabled'],
-        
         '@show_advanced': ui['show_advanced'],
         '@admin_username': ui['admin_username'],
         '@admin_password': ui['admin_password'],
@@ -597,8 +595,6 @@ def main_ui_to_dict(ui):
 
 def main_dict_to_ui(data):
     ui = {
-        'enabled': data['@enabled'],
-        
         'show_advanced': data['@show_advanced'],
         'admin_username': data['@admin_username'],
         'admin_password': data['@admin_password'],
@@ -904,10 +900,36 @@ def motion_camera_ui_to_dict(ui, old_config=None):
     
     # movie end
     on_movie_end = ['%(script)s movie_end %%t %%f' % {'script': meyectl.find_command('relayevent')}]
+    
+    if ui['web_hook_storage_enabled']:
+        url = re.sub('\\s', '+', ui['web_hook_storage_url'])
+
+        on_movie_end.append("%(script)s '%(method)s' '%(url)s'" % {
+                'script': meyectl.find_command('webhook'),
+                'method': ui['web_hook_storage_http_method'],
+                'url': url})
+
+    if ui['command_storage_enabled']:
+        commands = ui['command_storage_exec'].split(';')
+        on_movie_end += [c.strip() for c in commands]
+
     data['on_movie_end'] = '; '.join(on_movie_end)
     
     # picture save
     on_picture_save = ['%(script)s picture_save %%t %%f' % {'script': meyectl.find_command('relayevent')}]
+    
+    if ui['web_hook_storage_enabled']:
+        url = re.sub('\\s', '+', ui['web_hook_storage_url'])
+
+        on_picture_save.append("%(script)s '%(method)s' '%(url)s'" % {
+                'script': meyectl.find_command('webhook'),
+                'method': ui['web_hook_storage_http_method'],
+                'url': url})
+
+    if ui['command_storage_enabled']:
+        commands = ui['command_storage_exec'].split(';')
+        on_picture_save += [c.strip() for c in commands]
+
     data['on_picture_save'] = '; '.join(on_picture_save)
 
     # additional configs
@@ -963,6 +985,8 @@ def motion_camera_dict_to_ui(data):
         'upload_username': data['@upload_username'],
         'upload_password': data['@upload_password'],
         'upload_authorization_key': '', # needed, otherwise the field is hidden
+        'web_hook_storage_enabled': False,
+        'command_storage_enabled': False,
 
         # text overlay
         'text_overlay': False,
@@ -1204,7 +1228,7 @@ def motion_camera_dict_to_ui(data):
         ui['sunday_from'], ui['sunday_to'] = days[6].split('-')
         ui['working_schedule_type'] = data['@working_schedule_type']
     
-    # event start    
+    # event start
     on_event_start = data.get('on_event_start') or []
     if on_event_start:
         on_event_start = [e.strip() for e in on_event_start.split(';')]
@@ -1251,6 +1275,33 @@ def motion_camera_dict_to_ui(data):
         ui['command_notifications_enabled'] = True
         ui['command_notifications_exec'] = '; '.join(command_notifications)
 
+    # movie end
+    on_movie_end = data.get('on_movie_end') or []
+    if on_movie_end:
+        on_movie_end = [e.strip() for e in on_movie_end.split(';')]
+
+    command_storage = []
+    for e in on_movie_end:
+        if e.count('webhook'):
+            e = shlex.split(e)
+
+            if len(e) < 3:
+                continue
+
+            ui['web_hook_storage_enabled'] = True 
+            ui['web_hook_storage_http_method'] = e[-2]
+            ui['web_hook_storage_url'] = e[-1]
+
+        elif e.count('relayevent') or e.count('eventrelay.py'):
+            continue # ignore internal relay script
+
+        else: # custom command
+            command_storage.append(e)
+    
+    if command_storage: 
+        ui['command_storage_enabled'] = True
+        ui['command_storage_exec'] = '; '.join(command_storage)
+
     # additional configs
     for name, value in data.iteritems():
         if not name.startswith('@_'):
index a33a0dbc2d9361ad6281ce08f3dc15d0695d2667..d8c6a42a806b144e5608495721f9c0f876cab702 100644 (file)
@@ -148,14 +148,17 @@ textarea.styled {
 }
 
 input[type=password].styled:FOCUS,
-input[type=text].styled:FOCUS {
+input[type=text].styled:FOCUS,
+textarea.styled:FOCUS {
     background-color: #414141;
 }
 
 input[type=password].styled:HOVER,
 input[type=password].styled:FOCUS,
 input[type=text].styled:HOVER,
-input[type=text].styled:FOCUS {
+input[type=text].styled:FOCUS,
+textarea.styled:HOVER,
+textarea.styled:FOCUS {
     border-color: #3498db;
     color: white;
 }
index e6f9cc0c6e094c27e1fb19b623e689e9bceeb442..9a8a9cbcba674f2855f49368aca653cf5bb1e02f 100644 (file)
@@ -617,27 +617,23 @@ function initUI() {
     }
 
     /* ui elements that enable/disable other ui elements */
-    $('#motionEyeSwitch').change(updateConfigUI);
     $('#showAdvancedSwitch').change(updateConfigUI);
     $('#storageDeviceSelect').change(updateConfigUI);
     $('#resolutionSelect').change(updateConfigUI);
-    $('#leftTextSelect').change(updateConfigUI);
-    $('#rightTextSelect').change(updateConfigUI);
+    $('#leftTextTypeSelect').change(updateConfigUI);
+    $('#rightTextTypeSelect').change(updateConfigUI);
     $('#captureModeSelect').change(updateConfigUI);
     $('#autoNoiseDetectSwitch').change(updateConfigUI);
-    $('#videoDeviceSwitch').change(checkMinimizeSection).change(updateConfigUI);
-    $('#textOverlaySwitch').change(checkMinimizeSection).change(updateConfigUI);
-    $('#videoStreamingSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#videoDeviceEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#textOverlayEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#videoStreamingEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
     $('#streamingServerResizeSwitch').change(updateConfigUI);
-    $('#stillImagesSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#stillImagesEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
     $('#preservePicturesSelect').change(updateConfigUI);
-    $('#moviesSwitch').change(checkMinimizeSection).change(updateConfigUI);
-    $('#motionDetectionSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#moviesEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#motionDetectionEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
     $('#preserveMoviesSelect').change(updateConfigUI);
-    $('#emailNotificationsSwitch').change(updateConfigUI);
-    $('#webHookNotificationsSwitch').change(updateConfigUI);
-    $('#commandNotificationsSwitch').change(updateConfigUI);
-    $('#workingScheduleSwitch').change(checkMinimizeSection).change(updateConfigUI);
+    $('#workingScheduleEnabledSwitch').change(checkMinimizeSection).change(updateConfigUI);
     
     $('#mondayEnabledSwitch').change(updateConfigUI);
     $('#tuesdayEnabledSwitch').change(updateConfigUI);
@@ -890,19 +886,13 @@ function updateConfigUI() {
         }
     });
 
-    /* general enable switch */
-    var motionEyeEnabled = $('#motionEyeSwitch').get(0).checked;
-    if (!motionEyeEnabled) {
-        objs.not($('#motionEyeSwitch').parents('div').get(0)).each(markHideLogic);
-    }
-    
     if ($('#cameraSelect').find('option').length < 2) { /* no camera configured */
-        $('#videoDeviceSwitch').parent().each(markHideLogic);
-        $('#videoDeviceSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
+        $('#videoDeviceEnabledSwitch').parent().each(markHideLogic);
+        $('#videoDeviceEnabledSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
     }
     
-    if ($('#videoDeviceSwitch')[0].error) { /* config error */
-        $('#videoDeviceSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
+    if ($('#videoDeviceEnabledSwitch')[0].error) { /* config error */
+        $('#videoDeviceEnabledSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
     }
         
     /* advanced settings */
@@ -916,109 +906,41 @@ function updateConfigUI() {
         $('#resolutionSelect').parents('tr:eq(0)').each(markHideLogic);
     }
 
-    /* storage device */
-    if ($('#storageDeviceSelect').val() !== 'network-share') {
-        $('#networkServerEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#networkUsernameEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#networkPasswordEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#networkShareNameEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-    
-    /* text */
-    if ($('#leftTextSelect').val() !== 'custom-text') {
-        $('#leftTextEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-    if ($('#rightTextSelect').val() !== 'custom-text') {
-        $('#rightTextEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-    
-    /* still images capture mode */
-    if ($('#captureModeSelect').val() !== 'interval-snapshots') {
-        $('#snapshotIntervalEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-    
-    /* auto noise level */
-    if ($('#autoNoiseDetectSwitch').get(0).checked) {
-        $('#noiseLevelSlider').parents('tr:eq(0)').each(markHideLogic);
-    }
-    
     /* video device switch */
-    if (!$('#videoDeviceSwitch').get(0).checked) {
-        $('#videoDeviceSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
+    if (!$('#videoDeviceEnabledSwitch').get(0).checked) {
+        $('#videoDeviceEnabledSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
     }
     
     /* text overlay switch */
-    if (!$('#textOverlaySwitch').get(0).checked) {
-        $('#textOverlaySwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
-    }
-    
-    /* video streaming */
-    if (!$('#videoStreamingSwitch').get(0).checked) {
-        $('#videoStreamingSwitch').parent().next('table.settings').find('tr.settings-item').not('.localhost-streaming').each(markHideLogic);
-    }
-    if (!$('#streamingServerResizeSwitch').get(0).checked) {
-        $('#streamingResolutionSlider').parents('tr:eq(0)').each(markHideLogic);
+    if (!$('#textOverlayEnabledSwitch').get(0).checked) {
+        $('#textOverlayEnabledSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
     }
     
     /* still images switch */
-    if (!$('#stillImagesSwitch').get(0).checked) {
-        $('#stillImagesSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
-    }
-    
-    /* preserve pictures */
-    if ($('#preservePicturesSelect').val() != '-1') {
-        $('#picturesLifetimeEntry').parents('tr:eq(0)').each(markHideLogic);
+    if (!$('#stillImagesEnabledSwitch').get(0).checked) {
+        $('#stillImagesEnabledSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
     }
     
     /* movies switch */
-    if (!$('#moviesSwitch').get(0).checked) {
-        $('#moviesSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
-    }
-    
-    /* preserve movies */
-    if ($('#preserveMoviesSelect').val() != '-1') {
-        $('#moviesLifetimeEntry').parents('tr:eq(0)').each(markHideLogic);
+    if (!$('#moviesEnabledSwitch').get(0).checked) {
+        $('#moviesEnabledSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
     }
     
     /* motion detection switch */
-    if (!$('#motionDetectionSwitch').get(0).checked) {
-        $('#motionDetectionSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
-        
-        /* hide the entire notifications section */
-        $('#emailNotificationsSwitch').parents('table.settings').prev().each(markHideLogic);
-        $('#emailNotificationsSwitch').parents('table.settings').each(markHideLogic);
+    if (!$('#motionDetectionEnabledSwitch').get(0).checked) {
+        $('#motionDetectionEnabledSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
         
-        /* hide the entire working schedule section */
-        $('#workingScheduleSwitch').parent().each(markHideLogic);
-        $('#workingScheduleSwitch').parent().next('table.settings').each(markHideLogic);
+        /* hide the entire working schedule section,
+         * as its switch button prevents hiding it automatically */
+        $('#workingScheduleEnabledSwitch').parent().each(markHideLogic);
     }
     
-    /* event notifications */
-    if (!$('#emailNotificationsSwitch').get(0).checked) {
-        $('#emailAddressesEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#smtpServerEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#smtpPortEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#smtpAccountEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#smtpPasswordEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#smtpTlsSwitch').parents('tr:eq(0)').each(markHideLogic);
-        $('#emailPictureTimeSpanEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-    
-    if (!$('#webHookNotificationsSwitch').get(0).checked) {
-        $('#webHookUrlEntry').parents('tr:eq(0)').each(markHideLogic);
-        $('#webHookHttpMethodSelect').parents('tr:eq(0)').each(markHideLogic);
-    }
-
-    if (!$('#commandNotificationsSwitch').get(0).checked) {
-        $('#commandNotificationsEntry').parents('tr:eq(0)').each(markHideLogic);
-    }
-
     /* working schedule */
-    if (!$('#workingScheduleSwitch').get(0).checked) {
-        $('#workingScheduleSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
+    if (!$('#workingScheduleEnabledSwitch').get(0).checked) {
+        $('#workingScheduleEnabledSwitch').parent().next('table.settings').find('tr.settings-item').each(markHideLogic);
     }
     
-    /* additional configs */
+    /* html dependencies */
     $('tr[depends]').each(function () {
         var $tr = $(this);
         var depends = $tr.attr('depends').split(' ');
@@ -1198,8 +1120,6 @@ function configUiValid() {
 
 function mainUi2Dict() {
     var dict = {
-        'enabled': $('#motionEyeSwitch')[0].checked,
-        
         'show_advanced': $('#showAdvancedSwitch')[0].checked,
         'admin_username': $('#adminUsernameEntry').val(),
         'admin_password': $('#adminPasswordEntry').val(),
@@ -1266,8 +1186,6 @@ function dict2MainUi(dict) {
         }
     }
     
-    $('#motionEyeSwitch')[0].checked = dict['enabled'];
-    
     $('#showAdvancedSwitch')[0].checked = dict['show_advanced']; markHideIfNull('show_advanced', 'showAdvancedSwitch');
     $('#adminUsernameEntry').val(dict['admin_username']); markHideIfNull('admin_username', 'adminUsernameEntry');
     $('#adminPasswordEntry').val(dict['admin_password']); markHideIfNull('admin_password', 'adminPasswordEntry');
@@ -1320,14 +1238,14 @@ function dict2MainUi(dict) {
 }
 
 function cameraUi2Dict() {
-    if ($('#videoDeviceSwitch')[0].error) { /* config error */
+    if ($('#videoDeviceEnabledSwitch')[0].error) { /* config error */
         return {
-            'enabled': $('#videoDeviceSwitch')[0].checked,
+            'enabled': $('#videoDeviceEnabledSwitch')[0].checked,
         };
     }
     
     var dict = {
-        'enabled': $('#videoDeviceSwitch')[0].checked,
+        'enabled': $('#videoDeviceEnabledSwitch')[0].checked,
         'name': $('#deviceNameEntry').val(),
         'proto': $('#deviceTypeEntry')[0].proto,
         
@@ -1374,16 +1292,21 @@ function cameraUi2Dict() {
         'upload_username': $('#uploadUsernameEntry').val(),
         'upload_password': $('#uploadPasswordEntry').val(),
         'upload_authorization_key': $('#uploadAuthorizationKeyEntry').val(),
-        
+        'web_hook_storage_enabled': $('#webHookStorageEnabledSwitch')[0].checked,
+        'web_hook_storage_url': $('#webHookStorageUrlEntry').val(),
+        'web_hook_storage_http_method': $('#webHookStorageHttpMethodSelect').val(),
+        'command_storage_enabled': $('#commandStorageEnabledSwitch')[0].checked,
+        'command_storage_exec': $('#commandStorageEntry').val(),
+
         /* text overlay */
-        'text_overlay': $('#textOverlaySwitch')[0].checked,
-        'left_text': $('#leftTextSelect').val(),
+        'text_overlay': $('#textOverlayEnabledSwitch')[0].checked,
+        'left_text': $('#leftTextTypeSelect').val(),
         'custom_left_text': $('#leftTextEntry').val(),
-        'right_text': $('#rightTextSelect').val(),
+        'right_text': $('#rightTextTypeSelect').val(),
         'custom_right_text': $('#rightTextEntry').val(),
         
         /* video streaming */
-        'video_streaming': $('#videoStreamingSwitch')[0].checked,
+        'video_streaming': $('#videoStreamingEnabledSwitch')[0].checked,
         'streaming_framerate': $('#streamingFramerateSlider').val(),
         'streaming_quality': $('#streamingQualitySlider').val(),
         'streaming_resolution': $('#streamingResolutionSlider').val(),
@@ -1393,7 +1316,7 @@ function cameraUi2Dict() {
         'streaming_motion': $('#streamingMotion')[0].checked,
         
         /* still images */
-        'still_images': $('#stillImagesSwitch')[0].checked,
+        'still_images': $('#stillImagesEnabledSwitch')[0].checked,
         'image_file_name': $('#imageFileNameEntry').val(),
         'image_quality': $('#imageQualitySlider').val(),
         'capture_mode': $('#captureModeSelect').val(),
@@ -1401,7 +1324,7 @@ function cameraUi2Dict() {
         'preserve_pictures': $('#preservePicturesSelect').val() >= 0 ? $('#preservePicturesSelect').val() : $('#picturesLifetimeEntry').val(),
         
         /* movies */
-        'movies': $('#moviesSwitch')[0].checked,
+        'movies': $('#moviesEnabledSwitch')[0].checked,
         'movie_file_name': $('#movieFileNameEntry').val(),
         'movie_quality': $('#movieQualitySlider').val(),
         'recording_mode': $('#recordingModeSelect').val(),
@@ -1409,7 +1332,7 @@ function cameraUi2Dict() {
         'preserve_movies': $('#preserveMoviesSelect').val() >= 0 ? $('#preserveMoviesSelect').val() : $('#moviesLifetimeEntry').val(),
         
         /* motion detection */
-        'motion_detection': $('#motionDetectionSwitch')[0].checked,
+        'motion_detection': $('#motionDetectionEnabledSwitch')[0].checked,
         'show_frame_changes': $('#showFrameChangesSwitch')[0].checked,
         'frame_change_threshold': $('#frameChangeThresholdSlider').val(),
         'auto_noise_detect': $('#autoNoiseDetectSwitch')[0].checked,
@@ -1421,7 +1344,7 @@ function cameraUi2Dict() {
         'minimum_motion_frames': $('#minimumMotionFramesEntry').val(),
         
         /* motion notifications */
-        'email_notifications_enabled': $('#emailNotificationsSwitch')[0].checked,
+        'email_notifications_enabled': $('#emailNotificationsEnabledSwitch')[0].checked,
         'email_notifications_addresses': $('#emailAddressesEntry').val(),
         'email_notifications_smtp_server': $('#smtpServerEntry').val(),
         'email_notifications_smtp_port': $('#smtpPortEntry').val(),
@@ -1429,14 +1352,14 @@ function cameraUi2Dict() {
         'email_notifications_smtp_password': $('#smtpPasswordEntry').val(),
         'email_notifications_smtp_tls': $('#smtpTlsSwitch')[0].checked,
         'email_notifications_picture_time_span': $('#emailPictureTimeSpanEntry').val(),
-        'web_hook_notifications_enabled': $('#webHookNotificationsSwitch')[0].checked,
-        'web_hook_notifications_url': $('#webHookUrlEntry').val(),
-        'web_hook_notifications_http_method': $('#webHookHttpMethodSelect').val(),
-        'command_notifications_enabled': $('#commandNotificationsSwitch')[0].checked,
+        'web_hook_notifications_enabled': $('#webHookNotificationsEnabledSwitch')[0].checked,
+        'web_hook_notifications_url': $('#webHookNotificationsUrlEntry').val(),
+        'web_hook_notifications_http_method': $('#webHookNotificationsHttpMethodSelect').val(),
+        'command_notifications_enabled': $('#commandNotificationsEnabledSwitch')[0].checked,
         'command_notifications_exec': $('#commandNotificationsEntry').val(),
         
         /* working schedule */
-        'working_schedule': $('#workingScheduleSwitch')[0].checked,
+        'working_schedule': $('#workingScheduleEnabledSwitch')[0].checked,
         'monday_from': $('#mondayEnabledSwitch')[0].checked ? $('#mondayFromEntry').val() : '',
         'monday_to':$('#mondayEnabledSwitch')[0].checked ? $('#mondayToEntry').val() : '',
         'tuesday_from': $('#tuesdayEnabledSwitch')[0].checked ? $('#tuesdayFromEntry').val() : '',
@@ -1530,14 +1453,14 @@ function dict2CameraUi(dict) {
     if (dict == null) {
         /* errors while getting the configuration */
         
-        $('#videoDeviceSwitch')[0].error = true;
-        $('#videoDeviceSwitch')[0].checked = true; /* so that the user can explicitly disable the camera */
+        $('#videoDeviceEnabledSwitch')[0].error = true;
+        $('#videoDeviceEnabledSwitch')[0].checked = true; /* so that the user can explicitly disable the camera */
         updateConfigUI();
         
         return;
     }
     else {
-        $('#videoDeviceSwitch')[0].error = false;
+        $('#videoDeviceEnabledSwitch')[0].error = false;
     }
 
     function markHideIfNull(field, elemId) {
@@ -1576,7 +1499,7 @@ function dict2CameraUi(dict) {
             break;
     }
     
-    $('#videoDeviceSwitch')[0].checked = dict['enabled']; markHideIfNull('enabled', 'videoDeviceSwitch');
+    $('#videoDeviceEnabledSwitch')[0].checked = dict['enabled']; markHideIfNull('enabled', 'videoDeviceEnabledSwitch');
     $('#deviceNameEntry').val(dict['name']); markHideIfNull('name', 'deviceNameEntry');
     $('#deviceUrlEntry').val(dict['device_url']); markHideIfNull('device_url', 'deviceUrlEntry');
     $('#deviceTypeEntry').val(prettyType); markHideIfNull(!prettyType, 'deviceTypeEntry');
@@ -1662,15 +1585,22 @@ function dict2CameraUi(dict) {
     $('#uploadPasswordEntry').val(dict['upload_password']); markHideIfNull('upload_password', 'uploadPasswordEntry');
     $('#uploadAuthorizationKeyEntry').val(dict['upload_authorization_key']); markHideIfNull('upload_authorization_key', 'uploadAuthorizationKeyEntry');
 
+    $('#webHookStorageEnabledSwitch')[0].checked = dict['web_hook_storage_enabled']; markHideIfNull('web_hook_storage_enabled', 'webHookStorageEnabledSwitch');
+    $('#webHookStorageUrlEntry').val(dict['web_hook_storage_url']);
+    $('#webHookStorageHttpMethodSelect').val(dict['web_hook_storage_http_method']);
+
+    $('#commandStorageEnabledSwitch')[0].checked = dict['command_storage_enabled']; markHideIfNull('command_storage_enabled', 'commandstorageSwitch');
+    $('#commandStorageEntry').val(dict['command_storage_exec']);
+
     /* text overlay */
-    $('#textOverlaySwitch')[0].checked = dict['text_overlay']; markHideIfNull('text_overlay', 'textOverlaySwitch');
-    $('#leftTextSelect').val(dict['left_text']); markHideIfNull('left_text', 'leftTextSelect');
+    $('#textOverlayEnabledSwitch')[0].checked = dict['text_overlay']; markHideIfNull('text_overlay', 'textOverlayEnabledSwitch');
+    $('#leftTextTypeSelect').val(dict['left_text']); markHideIfNull('left_text', 'leftTextTypeSelect');
     $('#leftTextEntry').val(dict['custom_left_text']); markHideIfNull('custom_left_text', 'leftTextEntry');
-    $('#rightTextSelect').val(dict['right_text']); markHideIfNull('right_text', 'rightTextSelect');
+    $('#rightTextTypeSelect').val(dict['right_text']); markHideIfNull('right_text', 'rightTextTypeSelect');
     $('#rightTextEntry').val(dict['custom_right_text']); markHideIfNull('custom_right_text', 'rightTextEntry');
     
     /* video streaming */
-    $('#videoStreamingSwitch')[0].checked = dict['video_streaming']; markHideIfNull('video_streaming', 'videoStreamingSwitch');
+    $('#videoStreamingEnabledSwitch')[0].checked = dict['video_streaming']; markHideIfNull('video_streaming', 'videoStreamingEnabledSwitch');
     $('#streamingFramerateSlider').val(dict['streaming_framerate']); markHideIfNull('streaming_framerate', 'streamingFramerateSlider');
     $('#streamingQualitySlider').val(dict['streaming_quality']); markHideIfNull('streaming_quality', 'streamingQualitySlider');
     $('#streamingResolutionSlider').val(dict['streaming_resolution']); markHideIfNull('streaming_resolution', 'streamingResolutionSlider');
@@ -1710,9 +1640,9 @@ function dict2CameraUi(dict) {
     $('#streamingSnapshotUrlEntry').val(snapshotUrl); markHideIfNull(!snapshotUrl, 'streamingSnapshotUrlEntry');
     $('#streamingMjpgUrlEntry').val(mjpgUrl); markHideIfNull(!mjpgUrl, 'streamingMjpgUrlEntry');
     $('#streamingEmbedUrlEntry').val(embedUrl); markHideIfNull(!embedUrl, 'streamingEmbedUrlEntry');
-    
+
     /* still images */
-    $('#stillImagesSwitch')[0].checked = dict['still_images']; markHideIfNull('still_images', 'stillImagesSwitch');
+    $('#stillImagesEnabledSwitch')[0].checked = dict['still_images']; markHideIfNull('still_images', 'stillImagesEnabledSwitch');
     $('#imageFileNameEntry').val(dict['image_file_name']); markHideIfNull('image_file_name', 'imageFileNameEntry');
     $('#imageQualitySlider').val(dict['image_quality']); markHideIfNull('image_quality', 'imageQualitySlider');
     $('#captureModeSelect').val(dict['capture_mode']); markHideIfNull('capture_mode', 'captureModeSelect');
@@ -1725,7 +1655,7 @@ function dict2CameraUi(dict) {
     $('#picturesLifetimeEntry').val(dict['preserve_pictures']); markHideIfNull('preserve_pictures', 'picturesLifetimeEntry');
     
     /* movies */
-    $('#moviesSwitch')[0].checked = dict['movies']; markHideIfNull('movies', 'moviesSwitch');
+    $('#moviesEnabledSwitch')[0].checked = dict['movies']; markHideIfNull('movies', 'moviesEnabledSwitch');
     $('#movieFileNameEntry').val(dict['movie_file_name']); markHideIfNull('movie_file_name', 'movieFileNameEntry');
     $('#movieQualitySlider').val(dict['movie_quality']); markHideIfNull('movie_quality', 'movieQualitySlider');
     $('#recordingModeSelect').val(dict['recording_mode']); markHideIfNull('recording_mode', 'recordingModeSelect');
@@ -1738,7 +1668,7 @@ function dict2CameraUi(dict) {
     $('#moviesLifetimeEntry').val(dict['preserve_movies']); markHideIfNull('preserve_movies', 'moviesLifetimeEntry');
     
     /* motion detection */
-    $('#motionDetectionSwitch')[0].checked = dict['motion_detection']; markHideIfNull('motion_detection', 'motionDetectionSwitch');
+    $('#motionDetectionEnabledSwitch')[0].checked = dict['motion_detection']; markHideIfNull('motion_detection', 'motionDetectionEnabledSwitch');
     $('#showFrameChangesSwitch')[0].checked = dict['show_frame_changes']; markHideIfNull('show_frame_changes', 'showFrameChangesSwitch');
     $('#frameChangeThresholdSlider').val(dict['frame_change_threshold']); markHideIfNull('frame_change_threshold', 'frameChangeThresholdSlider');
     $('#autoNoiseDetectSwitch')[0].checked = dict['auto_noise_detect']; markHideIfNull('auto_noise_detect', 'autoNoiseDetectSwitch');
@@ -1750,7 +1680,7 @@ function dict2CameraUi(dict) {
     $('#minimumMotionFramesEntry').val(dict['minimum_motion_frames']); markHideIfNull('minimum_motion_frames', 'minimumMotionFramesEntry');
     
     /* motion notifications */
-    $('#emailNotificationsSwitch')[0].checked = dict['email_notifications_enabled']; markHideIfNull('email_notifications_enabled', 'emailNotificationsSwitch');
+    $('#emailNotificationsEnabledSwitch')[0].checked = dict['email_notifications_enabled']; markHideIfNull('email_notifications_enabled', 'emailNotificationsEnabledSwitch');
     $('#emailAddressesEntry').val(dict['email_notifications_addresses']);
     $('#smtpServerEntry').val(dict['email_notifications_smtp_server']);
     $('#smtpPortEntry').val(dict['email_notifications_smtp_port']);
@@ -1758,14 +1688,16 @@ function dict2CameraUi(dict) {
     $('#smtpPasswordEntry').val(dict['email_notifications_smtp_password']);
     $('#smtpTlsSwitch')[0].checked = dict['email_notifications_smtp_tls'];
     $('#emailPictureTimeSpanEntry').val(dict['email_notifications_picture_time_span']);
-    $('#webHookNotificationsSwitch')[0].checked = dict['web_hook_notifications_enabled']; markHideIfNull('web_hook_notifications_enabled', 'webHookNotificationsSwitch');
-    $('#webHookUrlEntry').val(dict['web_hook_notifications_url']);
-    $('#webHookHttpMethodSelect').val(dict['web_hook_notifications_http_method']);
-    $('#commandNotificationsSwitch')[0].checked = dict['command_notifications_enabled']; markHideIfNull('command_notifications_enabled', 'commandNotificationsSwitch');
+    
+    $('#webHookNotificationsEnabledSwitch')[0].checked = dict['web_hook_notifications_enabled']; markHideIfNull('web_hook_notifications_enabled', 'webHookNotificationsEnabledSwitch');
+    $('#webHookNotificationsUrlEntry').val(dict['web_hook_notifications_url']);
+    $('#webHookNotificationsHttpMethodSelect').val(dict['web_hook_notifications_http_method']);
+    
+    $('#commandNotificationsEnabledSwitch')[0].checked = dict['command_notifications_enabled']; markHideIfNull('command_notifications_enabled', 'commandNotificationsEnabledSwitch');
     $('#commandNotificationsEntry').val(dict['command_notifications_exec']);
 
     /* working schedule */
-    $('#workingScheduleSwitch')[0].checked = dict['working_schedule']; markHideIfNull('working_schedule', 'workingScheduleSwitch');
+    $('#workingScheduleEnabledSwitch')[0].checked = dict['working_schedule']; markHideIfNull('working_schedule', 'workingScheduleEnabledSwitch');
     $('#mondayEnabledSwitch')[0].checked = Boolean(dict['monday_from'] && dict['monday_to']); markHideIfNull('monday_from', 'mondayEnabledSwitch');
     $('#mondayFromEntry').val(dict['monday_from']); markHideIfNull('monday_from', 'mondayFromEntry');
     $('#mondayToEntry').val(dict['monday_to']); markHideIfNull('monday_to', 'mondayToEntry');
@@ -2853,10 +2785,6 @@ function runPictureDialog(entries, pos, mediaType) {
 }
 
 function runAddCameraDialog() {
-    if (!$('#motionEyeSwitch')[0].checked) {
-        return runAlertDialog('Please enable motionEye first!');
-    }
-    
     if (Object.keys(pushConfigs).length) {
         return runAlertDialog('Please apply the modified settings first!');
     }
@@ -2875,7 +2803,7 @@ function runAddCameraDialog() {
                 '</tr>' +
                 '<tr class="motioneye netcam mjpeg">' +
                     '<td class="dialog-item-label"><span class="dialog-item-label">URL</span></td>' +
-                    '<td class="dialog-item-value"><input type="text" class="styled" id="urlEntry" placeholder="http://example.com:8080/cams/..."></td>' +
+                    '<td class="dialog-item-value"><input type="text" class="styled" id="urlEntry" placeholder="http://example.com:8765/cams/..."></td>' +
                     '<td><span class="help-mark" title="the camera URL (e.g. http://example.com:8080/cam/)">?</span></td>' +
                 '</tr>' +
                 '<tr class="motioneye netcam mjpeg">' +
@@ -3859,7 +3787,7 @@ function recreateCameraFrames(cameras) {
             addCameraFrameUi(camera);
         }
         
-        if ($('#cameraSelect').find('option').length < 2 && isAdmin() && $('#motionEyeSwitch')[0].checked) {
+        if ($('#cameraSelect').find('option').length < 2 && isAdmin()) {
             /* invite the user to add a camera */
             var addCameraLink = $('<div class="add-camera-message">' + 
                     '<a href="javascript:runAddCameraDialog()">You have not configured any camera yet. Click here to add one...</a></div>');
index 9187ef3cb2ffe534c6d44657a23ee1df5d9ad8fe..bbc9458a918c52efcb3e80a1c41ecb6c88615dcb 100644 (file)
@@ -1,11 +1,11 @@
 {% extends "base.html" %}
 
-{% macro config_item(config) -%}
+{% macro config_item(config, depends="") -%}
     <tr class="settings-item additional-config {% if config['advanced'] %}advanced-setting{% endif %}"
             {% if config.get('reboot') and enable_reboot %}reboot="true"{% endif %}
             {% if config.get('required') %}required="true"{% endif %}
             {% if config.get('strip') %}strip="true"{% endif %}
-            {% if config.get('depends') %}depends="{{' '.join(config['depends'])}}"{% endif %}
+            {% if config.get('depends') %}depends="{{' '.join(config['depends'])}}{% if depends %} {{depends}}{% endif %}"{% endif %}
             {% if config.get('min') is not none %}min="{{config['min']}}"{% endif %}
             {% if config.get('max') is not none %}max="{{config['max']}}"{% endif %}
             {% if config.get('floating') %}floating="true"{% endif %}
                 
                 <!-- General Settings -->
                 <div class="settings-section-title">
-                    <input type="checkbox" class="styled section general main-config" id="motionEyeSwitch">
                     <span class="help-mark" title="general settings, not related to any camera">?</span>
                     <a class="settings-section-title">General Settings</a>
                     <span class="minimize open"></span>
                 
                 <!-- Video Device -->
                 <div class="settings-section-title">
-                    <input type="checkbox" class="styled section device camera-config" id="videoDeviceSwitch">
+                    <input type="checkbox" class="styled section device camera-config" id="videoDeviceEnabledSwitch">
                     <span class="help-mark" title="enable this if you want to use this camera device">?</span>
                     <a class="settings-section-title">Video Device</a>
                     <span class="minimize open"></span>
                         </td>
                         <td><span class="help-mark" title="indicates the storage device where the image and video files will be saved">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="storageDevice=network-share" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Network Server</span></td>
                         <td class="settings-item-value"><input type="text" class="styled storage camera-config" id="networkServerEntry"></td>
                         <td><span class="help-mark" title="the address of the network server (IP address or hostname)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="storageDevice=network-share" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Share Name</span></td>
                         <td class="settings-item-value"><input type="text" class="styled storage camera-config" id="networkShareNameEntry"></td>
                         <td><span class="help-mark" title="the name of the network share">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" strip="true">
+                    <tr class="settings-item advanced-setting" depends="storageDevice=network-share" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Share Username</span></td>
                         <td class="settings-item-value"><input type="text" class="styled storage camera-config" id="networkUsernameEntry"></td>
                         <td><span class="help-mark" title="the username to be supplied when accessing the network share (leave empty if no username is required)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" strip="true">
+                    <tr class="settings-item advanced-setting" depends="storageDevice=network-share" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Share Password</span></td>
                         <td class="settings-item-value"><input type="password" class="styled storage camera-config" id="networkPasswordEntry"></td>
                         <td><span class="help-mark" title="the password required by the network share (leave empty if no password is required)">?</span></td>
                         <td class="settings-item-value"><div class="button normal-button test-button" id="uploadTestButton">Test Service</div></td>
                         <td><span class="help-mark" title="click this button to test the upload service after you have filled in the required details">?</span></td>
                     </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td colspan="100"><div class="settings-item-separator"></div></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Call A Web Hook</span></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled storage camera-config" id="webHookStorageEnabledSwitch"></td>
+                        <td><span class="help-mark" title="enable this if you want a URL to be requested after a media file is created">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting" required="true" depends="webHookStorageEnabled" strip="true">
+                        <td class="settings-item-label"><span class="settings-item-label">Web Hook URL</span></td>
+                        <td class="settings-item-value"><input type="text" class="styled storage camera-config" id="webHookStorageUrlEntry" placeholder="e.g. http://example.com/notify/"></td>
+                        <td><span class="help-mark" title="a URL to be requested when motion is detected; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %f = file path">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting" depends="webHookStorageEnabled">
+                        <td class="settings-item-label"><span class="settings-item-label">HTTP Method</span></td>
+                        <td class="settings-item-value">
+                            <select class="styled storage camera-config" id="webHookStorageHttpMethodSelect">
+                                <option value="GET">GET</option>
+                                <option value="POST">POST (query)</option>
+                                <option value="POSTf">POST (form)</option>
+                                <option value="POSTj">POST (json)</option>
+                            </select>
+                        </td>
+                        <td><span class="help-mark" title="the HTTP method to use when requesting the web hook URL (the given URL-encoded parameters will in fact be transmitted as indicated here)">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td colspan="100"><div class="settings-item-separator"></div></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Run A Command</span></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled storage camera-config" id="commandStorageEnabledSwitch"></td>
+                        <td><span class="help-mark" title="enable this if you want to execute a command after a media file is created">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting" required="true" depends="commandStorageEnabled" strip="true">
+                        <td class="settings-item-label"><span class="settings-item-label">Command</span></td>
+                        <td class="settings-item-value"><input type="text" class="styled storage camera-config" id="commandStorageEntry" placeholder="command..."></td>
+                        <td><span class="help-mark" title="a command to be executed after a media file is created; multiple commands can be separated by a semicolon; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %f = file path">?</span></td>
+                    </tr>
                     {% for config in camera_sections.get('storage', {}).get('configs', []) %}
                         {{config_item(config)}}
                     {% endfor %}
                 
                 <!-- Text Overlay -->
                 <div class="settings-section-title advanced-setting">
-                    <input type="checkbox" class="styled section text-overlay camera-config" id="textOverlaySwitch">
+                    <input type="checkbox" class="styled section text-overlay camera-config" id="textOverlayEnabledSwitch">
                     <span class="help-mark" title="choose what information is displayed on the captured frames">?</span>
                     <a class="settings-section-title">Text Overlay</a>
                     <span class="minimize"></span>
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Left Text</span></td>
                         <td class="settings-item-value">
-                            <select class="styled text-overlay camera-config" id="leftTextSelect">
+                            <select class="styled text-overlay camera-config" id="leftTextTypeSelect">
                                 <option value="camera-name">Camera Name</option>
                                 <option value="timestamp">Timestamp</option>
                                 <option value="custom-text">Custom Text</option>
                         </td>
                         <td><span class="help-mark" title="sets the text displayed on the movies and images, on the lower left corner">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="leftTextType=custom-text" strip="true">
                         <td class="settings-item-label"></td>
                         <td class="settings-item-value"><input type="text" class="styled text-overlay camera-config" id="leftTextEntry" placeholder="custom text..."></td>
                         <td><span class="help-mark" title="sets a custom left text; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %T = HH:MM:SS, %q = frame number, \n = new line">?</span></td>
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Right Text</span></td>
                         <td class="settings-item-value">
-                            <select class="styled text-overlay camera-config" id="rightTextSelect">
+                            <select class="styled text-overlay camera-config" id="rightTextTypeSelect">
                                 <option value="camera-name">Camera Name</option>
                                 <option value="timestamp">Timestamp</option>
                                 <option value="custom-text">Custom Text</option>
                         </td>
                         <td><span class="help-mark" title="sets the text displayed on the movies and images, on the lower right corner">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="rightTextType=custom-text" strip="true">
                         <td class="settings-item-label"></td>
                         <td class="settings-item-value"><input type="text" class="styled text-overlay camera-config" id="rightTextEntry" placeholder="custom text..."></td>
                         <td><span class="help-mark" title="sets a custom right text; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %T = HH:MM:SS, %q = frame number, \n = new line">?</span></td>
 
                 <!-- Video Streaming -->
                 <div class="settings-section-title" minimize-switch-independent="true">
-                    <input type="checkbox" class="styled section streaming camera-config" id="videoStreamingSwitch">
+                    <input type="checkbox" class="styled section streaming camera-config" id="videoStreamingEnabledSwitch">
                     <span class="help-mark" title="enable this if you want video streaming for this camera">?</span>
                     <a class="settings-section-title">Video Streaming</a>
                     <span class="minimize"></span>
                 </div>
                 <table class="settings">
-                    <tr class="settings-item advanced-setting localhost-streaming" min="1" max="30" snap="0" ticks="1|5|10|15|20|25|30" decimals="0">
+                    <tr class="settings-item advanced-setting" min="1" max="30" snap="0" ticks="1|5|10|15|20|25|30" decimals="0">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming Frame Rate</span></td>
                         <td class="settings-item-value"><input type="text" class="range styled streaming camera-config" id="streamingFramerateSlider"></td>
                         <td><span class="help-mark" title="sets the number of frames transmitted every second on the live streaming">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting localhost-streaming" min="0" max="100" snap="2" ticksnum="5" decimals="0" unit="%">
+                    <tr class="settings-item advanced-setting" min="0" max="100" snap="2" ticksnum="5" decimals="0" unit="%">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming Quality</span></td>
                         <td class="settings-item-value"><input type="text" class="range styled streaming camera-config" id="streamingQualitySlider"></td>
                         <td><span class="help-mark" title="sets the live streaming quality (higher values produce a better video quality but require more bandwidth)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting localhost-streaming">
+                    <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming Image Resizing</span></td>
                         <td class="settings-item-value"><input type="checkbox" class="styled streaming camera-config" id="streamingServerResizeSwitch"></td>
                         <td><span class="help-mark" title="when this is enabled, the images are resized before they are sent to the browser (disable when running on a slow CPU)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting localhost-streaming" min="0" max="100" snap="2" ticksnum="5" decimals="0" unit="%">
+                    <tr class="settings-item advanced-setting" min="0" max="100" snap="2" ticksnum="5" decimals="0" unit="%" depends="streamingServerResize">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming Resolution</span></td>
                         <td class="settings-item-value"><input type="text" class="range styled streaming camera-config" id="streamingResolutionSlider"></td>
                         <td><span class="help-mark" title="the streaming resolution given as percent of the video device resolution (higher values produce better video quality but require more bandwidth)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" min="1024" max="65535" required="true">
+                    <tr class="settings-item advanced-setting" min="1024" max="65535" depends="videoStreamingEnabled" required="true">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming Port</span></td>
                         <td class="settings-item-value"><input type="text" class="styled streaming camera-config" id="streamingPortEntry"></td>
                         <td><span class="help-mark" title="sets the TCP port on which the webcam streaming server listens">?</span></td>
                     </tr>
                     {% if not old_motion %}
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="videoStreamingEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Authentication Mode</span></td>
                         <td class="settings-item-value">
                             <select class="styled streaming camera-config" id="streamingAuthModeSelect">
                         <td><span class="help-mark" title="the authentication mode to use when accessing the stream (use Basic instead of Digest if you encounter issues with third party apps)">?</span></td>
                     </tr>
                     {% endif %}
-                    <tr class="settings-item advanced-setting localhost-streaming">
+                    <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Motion Optimization</span></td>
                         <td class="settings-item-value"><input type="checkbox" class="styled streaming camera-config" id="streamingMotion"></td>
                         <td><span class="help-mark" title="enable this if you want a lower frame rate for the live streaming when no motion is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="videoStreamingEnabled">
                         <td colspan="100"><div class="settings-item-separator"></div></td>
                     </tr>
-                    <tr class="settings-item advanced-setting localhost-streaming">
+                    <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Snapshot URL</span></td>
                         <td class="settings-item-value"><input type="text" class="styled streaming camera-config" id="streamingSnapshotUrlEntry" readonly="readonly"></td>
                         <td><span class="help-mark" title="a URL that provides a JPEG image with the most recent snapshot of the camera">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="videoStreamingEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Streaming URL</span></td>
                         <td class="settings-item-value"><input type="text" class="styled streaming camera-config" id="streamingMjpgUrlEntry" readonly="readonly"></td>
                         <td><span class="help-mark" title="a URL that provides a MJPEG stream of the camera (there is no password protection for this URL!)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting localhost-streaming">
+                    <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Embed URL</span></td>
                         <td class="settings-item-value"><input type="text" class="styled streaming camera-config" id="streamingEmbedUrlEntry" readonly="readonly"></td>
                         <td><span class="help-mark" title="a URL that provides a minimal HTML document containing the camera frame, ready to be embedded">?</span></td>
                 
                 <!-- Still Images -->
                 <div class="settings-section-title">
-                    <input type="checkbox" class="styled section still-images camera-config" id="stillImagesSwitch">
+                    <input type="checkbox" class="styled section still-images camera-config" id="stillImagesEnabledSwitch">
                     <span class="help-mark" title="enable this if you want to capture still images (pictures)">?</span>
                     <a class="settings-section-title">Still Images</a>
                     <span class="minimize"></span>
                         </td>
                         <td><span class="help-mark" title="sets the image capture mode: Motion Triggered = an image captured whenever motion is detected, Interval Snapshots = an image captured every x seconds, All Frames = saves each frame to an image file">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" min="1" max="86400" required="true">
+                    <tr class="settings-item advanced-setting" min="1" max="86400" required="true" depends="captureMode=interval-snapshots">
                         <td class="settings-item-label"><span class="settings-item-label">Snapshot Interval</span></td>
                         <td class="settings-item-value"><input type="text" class="styled number still-images camera-config" id="snapshotIntervalEntry"><span class="settings-item-unit">seconds</span></td>
                         <td><span class="help-mark" title="sets the interval (in seconds) for the snapshots">?</span></td>
                         </td>
                         <td><span class="help-mark" title="images older than the specified duration are automatically deleted to free up storage space">?</span></td>
                     </tr>
-                    <tr class="settings-item" min="1" max="3650" required="true">
+                    <tr class="settings-item" min="1" max="3650" depends="preservePictures=-1" required="true">
                         <td class="settings-item-label"><span class="settings-item-label">Pictures Lifetime</span></td>
                         <td class="settings-item-value"><input type="text" class="styled number still-images camera-config" id="picturesLifetimeEntry"><span class="settings-item-unit">days</span></td>
                         <td><span class="help-mark" title="sets the number of days after which the pictures will be deleted automatically">?</span></td>
                 
                 <!-- Movies -->
                 <div class="settings-section-title">
-                    <input type="checkbox" class="styled section movies camera-config" id="moviesSwitch">
+                    <input type="checkbox" class="styled section movies camera-config" id="moviesEnabledSwitch">
                     <span class="help-mark" title="enable this if you want to record movies">?</span>
                     <a class="settings-section-title">Movies</a>
                     <span class="minimize"></span>
                         </td>
                         <td><span class="help-mark" title="movies older than the specified duration are automatically deleted to free up storage space">?</span></td>
                     </tr>
-                    <tr class="settings-item" min="1" max="3650" required="true">
+                    <tr class="settings-item" min="1" max="3650" depends="preserveMovies=-1" required="true">
                         <td class="settings-item-label"><span class="settings-item-label">Movies Lifetime</span></td>
                         <td class="settings-item-value"><input type="text" class="styled number movies camera-config" id="moviesLifetimeEntry"><span class="settings-item-unit">days</span></td>
                         <td><span class="help-mark" title="sets the number of days after which the movies will be deleted automatically">?</span></td>
 
                 <!-- Motion Detection -->
                 <div class="settings-section-title advanced-setting">
-                    <input type="checkbox" class="styled section motion-detection camera-config" id="motionDetectionSwitch">
+                    <input type="checkbox" class="styled section motion-detection camera-config" id="motionDetectionEnabledSwitch">
                     <span class="help-mark" title="enable this to use and configure the motion detection mechanism">?</span>
                     <a class="settings-section-title">Motion Detection</a>
                     <span class="minimize"></span>
                         <td class="settings-item-value"><input type="checkbox" class="styled motion-detection camera-config" id="autoNoiseDetectSwitch"></td>
                         <td><span class="help-mark" title="enable this to automatically adjust the noise level">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" min="0" max="25" snap="0" ticksnum="6" decimals="0" unit="%">
+                    <tr class="settings-item advanced-setting" min="0" max="25" snap="0" ticksnum="6" decimals="0" unit="%" depends="!autoNoiseDetect">
                         <td class="settings-item-label"><span class="settings-item-label">Noise Level</span></td>
                         <td class="settings-item-value"><input type="text" class="range styled motion-detection camera-config" id="noiseLevelSlider"></td>
                         <td><span class="help-mark" title="manually sets the noise level to a fixed value">?</span></td>
                     <span class="minimize"></span>
                 </div>
                 <table class="settings">
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Send An Email</span></td>
-                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="emailNotificationsSwitch"></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="emailNotificationsEnabledSwitch"></td>
                         <td><span class="help-mark" title="enable this if you want to receive an email whenever a motion event is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="emailNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Email Addresses</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="emailAddressesEntry" placeholder="email addresses..."></td>
                         <td><span class="help-mark" title="email addresses (separated by comma) that are added here will receive notifications whenever a motion event is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="emailNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">SMTP Server</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="smtpServerEntry" placeholder="e.g. smtp.gmail.com"></td>
                         <td><span class="help-mark" title="enter the hostname or IP address of your SMTP server (for Gmail use smtp.gmail.com)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" min="1" max="65535" required="true">
+                    <tr class="settings-item advanced-setting" min="1" max="65535" depends="emailNotificationsEnabled motionDetectionEnabled" required="true">
                         <td class="settings-item-label"><span class="settings-item-label">SMTP Port</span></td>
                         <td class="settings-item-value"><input type="text" class="styled number notifications camera-config" id="smtpPortEntry" placeholder="e.g. 587"></td>
                         <td><span class="help-mark" title="enter the port used by your SMTP server (usually 465 for non-TLS connections and 587 for TLS connections)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" strip="true">
+                    <tr class="settings-item advanced-setting" depends="emailNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">SMTP Account</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="smtpAccountEntry" placeholder="account@gmail.com..."></td>
                         <td><span class="help-mark" title="enter your SMTP account (normally your email address)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" strip="true">
+                    <tr class="settings-item advanced-setting" depends="emailNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">SMTP Password</span></td>
                         <td class="settings-item-value"><input type="password" class="styled notifications camera-config" id="smtpPasswordEntry"></td>
                         <td><span class="help-mark" title="enter your SMTP account password (for Gmail use your Google password or an app-specific generated password)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="emailNotificationsEnabled motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Use TLS</span></td>
                         <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="smtpTlsSwitch"></td>
                         <td><span class="help-mark" title="enable this if your SMTP server requires TLS (Gmail needs this to be enabled)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" min="0" max="60" required="true">
+                    <tr class="settings-item advanced-setting" min="0" max="60" required="true" depends="emailNotificationsEnabled motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Attached Pictures Time Span</span></td>
                         <td class="settings-item-value"><input type="text" class="number styled notifications camera-config" id="emailPictureTimeSpanEntry"><span class="settings-item-unit">seconds</span></td>
                         <td><span class="help-mark" title="defines the picture search time interval to use when creating email attachments (higher values generate emails with more pictures at the cost of an increased notification delay); set to 0 to disable picture attachments">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="motionDetectionEnabled">
                         <td colspan="100"><div class="settings-item-separator"></div></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Call A Web Hook</span></td>
-                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="webHookNotificationsSwitch"></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="webHookNotificationsEnabledSwitch"></td>
                         <td><span class="help-mark" title="enable this if you want a URL to be requested whenever a motion event is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="webHookNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Web Hook URL</span></td>
-                        <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="webHookUrlEntry" placeholder="e.g. http://example.com/notify/"></td>
+                        <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="webHookNotificationsUrlEntry" placeholder="e.g. http://example.com/notify/"></td>
                         <td><span class="help-mark" title="a URL to be requested when motion is detected; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %q = frame number">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="webHookNotificationsEnabled motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">HTTP Method</span></td>
                         <td class="settings-item-value">
-                            <select class="styled notifications camera-config" id="webHookHttpMethodSelect">
+                            <select class="styled notifications camera-config" id="webHookNotificationsHttpMethodSelect">
                                 <option value="GET">GET</option>
                                 <option value="POST">POST (query)</option>
                                 <option value="POSTf">POST (form)</option>
                         </td>
                         <td><span class="help-mark" title="the HTTP method to use when requesting the web hook URL (the given URL-encoded parameters will in fact be transmitted as indicated here)">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="motionDetectionEnabled">
                         <td colspan="100"><div class="settings-item-separator"></div></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
+                    <tr class="settings-item advanced-setting" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Run A Command</span></td>
-                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="commandNotificationsSwitch"></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled notifications camera-config" id="commandNotificationsEnabledSwitch"></td>
                         <td><span class="help-mark" title="enable this if you want to execute a command whenever a motion event is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting" required="true" strip="true">
+                    <tr class="settings-item advanced-setting" required="true" depends="commandNotificationsEnabled motionDetectionEnabled" strip="true">
                         <td class="settings-item-label"><span class="settings-item-label">Command</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications camera-config" id="commandNotificationsEntry" placeholder="command..."></td>
                         <td><span class="help-mark" title="a command to be executed when motion is detected; multiple commands can be separated by a semicolon; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %q = frame number">?</span></td>
                     </tr>
                     {% for config in camera_sections.get('notifications', {}).get('configs', []) %}
-                        {{config_item(config)}}
+                        {{config_item(config, "motionDetectionEnabled")}}
                     {% endfor %}
                 </table>
 
                 <!-- Working Schedule -->
-                <div class="settings-section-title">
-                    <input type="checkbox" class="styled section working-schedule camera-config" id="workingScheduleSwitch">
+                <div class="settings-section-title" depends="motionDetectionEnabled">
+                    <input type="checkbox" class="styled section working-schedule camera-config" id="workingScheduleEnabledSwitch">
                     <span class="help-mark" title="enable this if you want to define a weekly working schedule for motion detection">?</span>
                     <a class="settings-section-title">Working Schedule</a>
                     <span class="minimize"></span>
                 </div>
                 <table class="settings">
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Monday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="mondayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Mondays">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Tuesday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="tuesdayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Tuesdays">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Wednesday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="wednesdayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Wednesdays">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Thursday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="thursdayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Thursdays">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Friday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="fridayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Friday">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Saturday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="saturdayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Saturday">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Sunday</span></td>
                         <td class="settings-item-value">
                             <input type="checkbox" class="styled working-schedule camera-config" id="sundayEnabledSwitch">
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Sunday">?</span></td>
                     </tr>
-                    <tr class="settings-item">
+                    <tr class="settings-item" depends="motionDetectionEnabled">
                         <td class="settings-item-label"><span class="settings-item-label">Detect Motion</span></td>
                         <td class="settings-item-value">
                             <select class="styled working-schedule camera-config" id="workingScheduleTypeSelect">
                         <td><span class="help-mark" title="sets whether motion detection should be active during or outside the working schedule">?</span></td>
                     </tr>
                     {% for config in camera_sections.get('working-schedule', {}).get('configs', []) %}
-                        {{config_item(config)}}
+                        {{config_item(config, "motionDetectionEnabled")}}
                     {% endfor %}
                 </table>