]> www.vanbest.org Git - motioneye-debian/commitdiff
add camera dialog improvements
authorCalin Crisan <ccrisan@gmail.com>
Thu, 16 Jul 2015 14:20:50 +0000 (17:20 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Thu, 16 Jul 2015 14:20:50 +0000 (17:20 +0300)
src/handlers.py
src/remote.py
src/server.py
static/css/ui.css
static/js/main.js
static/js/ui.js

index 56b99e32dbe2628c6721f6cf9bbbeb10ceb2b0bf..2a2cfe365d610cb45c369c2ba083106e2ee2be2e 100644 (file)
@@ -171,11 +171,8 @@ class ConfigHandler(BaseHandler):
             self.get_config(camera_id)
             
         elif op == 'list':
-            self.list_cameras()
+            self.list()
         
-        elif op == 'list_devices':
-            self.list_devices()
-            
         elif op == 'backup':
             self.backup()
         
@@ -484,7 +481,7 @@ class ConfigHandler(BaseHandler):
             self.finish_json({'error': True})
 
     @BaseHandler.auth()
-    def list_cameras(self):
+    def list(self):
         logging.debug('listing cameras')
 
         proto = self.get_data().get('proto')        
@@ -497,7 +494,7 @@ class ConfigHandler(BaseHandler):
                     cameras = [c for c in cameras if c.get('enabled')]
                     self.finish_json({'cameras': cameras})
 
-            remote.list_cameras(self.get_data(), on_response)
+            remote.list(self.get_data(), on_response)
         
         elif proto == 'netcam':
             def on_response(cameras=None, error=None):
@@ -518,7 +515,20 @@ class ConfigHandler(BaseHandler):
                     self.finish_json({'cameras': cameras})
             
             utils.test_mjpeg_url(self.get_data(), auth_modes=['basic', 'digest'], allow_jpeg=False, callback=on_response)
-                
+        
+        elif proto == 'v4l2':
+            logging.debug('listing v4l2 devices')
+            
+            configured_devices = set()
+            for camera_id in config.get_camera_ids():
+                data = config.get_camera(camera_id)
+                if utils.v4l2_camera(data):
+                    configured_devices.add(data['videodevice'])
+
+            cameras = [{'id': d[0], 'name': d[1]} for d in v4l2ctl.list_devices() if d[0] not in configured_devices]
+            
+            self.finish_json({'cameras': cameras})
+
         else:  # assuming local motionEye camera listing
             cameras = []
             camera_ids = config.get_camera_ids()
@@ -588,21 +598,6 @@ class ConfigHandler(BaseHandler):
             if length[0] == 0:        
                 self.finish_json({'cameras': []})
 
-    @BaseHandler.auth(admin=True)
-    def list_devices(self):
-        logging.debug('listing devices')
-        
-        configured_devices = {}
-        for camera_id in config.get_camera_ids():
-            data = config.get_camera(camera_id)
-            if utils.v4l2_camera(data):
-                configured_devices[data['videodevice']] = True
-
-        devices = [{'uri': d[0], 'name': d[1], 'configured': d[0] in configured_devices}
-                for d in v4l2ctl.list_devices()]
-        
-        self.finish_json({'devices': devices})
-    
     @BaseHandler.auth(admin=True)
     def add_camera(self):
         logging.debug('adding new camera')
index 0bab9525ca0ae8be09137d06dafe4becbc7f40fa..a10599a32970c225baf50c4fb901e35c554c1058 100644 (file)
@@ -111,7 +111,7 @@ def _remote_params(local_config):
             local_config.get('@remote_camera_id', local_config.get('remote_camera_id')))
 
 
-def list_cameras(local_config, callback):
+def list(local_config, callback):
     scheme, host, port, username, password, uri, _ = _remote_params(local_config)
     
     logging.debug('listing remote cameras on %(url)s' % {
index 92581983afb3af3734b9e71039478ae9cc114254..623b9a403e5a1c7e3b57b5696e1a4f77a9627228 100644 (file)
@@ -43,7 +43,7 @@ application = Application(
         (r'^/$', handlers.MainHandler),
         (r'^/config/main/(?P<op>set|get)/?$', handlers.ConfigHandler),
         (r'^/config/(?P<camera_id>\d+)/(?P<op>get|set|rem|set_preview)/?$', handlers.ConfigHandler),
-        (r'^/config/(?P<op>add|list|list_devices|backup|restore)/?$', handlers.ConfigHandler),
+        (r'^/config/(?P<op>add|list|backup|restore)/?$', handlers.ConfigHandler),
         (r'^/picture/(?P<camera_id>\d+)/(?P<op>current|list|frame)/?$', handlers.PictureHandler),
         (r'^/picture/(?P<camera_id>\d+)/(?P<op>download|preview|delete)/(?P<filename>.+?)/?$', handlers.PictureHandler),
         (r'^/picture/(?P<camera_id>\d+)/(?P<op>zipped|timelapse|delete_all)/(?P<group>.+?)/?$', handlers.PictureHandler),
index 3a5a2af99a733d011ed72183f9597223922ddd60..e3eb78c552b58bb1f2935062757dfd6f899f3fe6 100644 (file)
@@ -165,8 +165,9 @@ input[type=text].number {
 
 input[type=text].error,
 input[type=password].error,
-input[type=file].error {
-    background-image: url(../img/validation-error.svg);
+input[type=file].error,
+select.error {
+    background-image: url(../img/validation-error.svg) !important;
     background-position: center right;
     background-repeat: no-repeat;
 }
index 290b6e0a712915a47d58b130911219603a7e14f6..2aab33f3d09e2b216d6b28896cda3da81af6ebec 100644 (file)
@@ -2652,9 +2652,14 @@ function runAddCameraDialog() {
     var content = 
             $('<table class="add-camera-dialog">' +
                 '<tr>' +
-                    '<td class="dialog-item-label"><span class="dialog-item-label">Device</span></td>' +
-                    '<td class="dialog-item-value"><select class="styled" id="deviceSelect"></select></td>' +
-                    '<td><span class="help-mark" title="the device type you wish to add">?</span></td>' +
+                    '<td class="dialog-item-label"><span class="dialog-item-label">Camera Type</span></td>' +
+                    '<td class="dialog-item-value"><select class="styled" id="typeSelect">' +
+                        '<option value="v4l2">Local Camera</option>' +
+                        '<option value="netcam">Network Camera</option>' +
+                        '<option value="motioneye">Remote motionEye Camera</option>' +
+                        '<option value="mjpeg">Simple MJPEG Camera</option>' +
+                    '</select></td>' +
+                    '<td><span class="help-mark" title="the type of camera you wish to add">?</span></td>' +
                 '</tr>' +
                 '<tr class="motioneye netcam mjpeg">' +
                     '<td class="dialog-item-label"><span class="dialog-item-label">URL</span></td>' +
@@ -2671,21 +2676,21 @@ function runAddCameraDialog() {
                     '<td class="dialog-item-value"><input type="password" class="styled" id="passwordEntry" placeholder="password..."></td>' +
                     '<td><span class="help-mark" title="the password for the URL, if required">?</span></td>' +
                 '</tr>' +
-                '<tr class="motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg">' +
                     '<td class="dialog-item-label"><span class="dialog-item-label">Camera</span></td>' +
                     '<td class="dialog-item-value"><select class="styled" id="addCameraSelect"></select><span id="cameraMsgLabel"></span></td>' +
                     '<td><span class="help-mark" title="the camera you wish to add">?</span></td>' +
                 '</tr>' +
-                '<tr class="motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg">' +
                     '<td colspan="100"><div class="dialog-item-separator"></div></td>' +
                 '</tr>' +
-                '<tr class="motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg">' +
                     '<td class="dialog-item-value" colspan="100"><div id="addCameraInfo"></div></td>' +
                 '</tr>' +
             '</table>');
     
     /* collect ui widgets */
-    var deviceSelect = content.find('#deviceSelect');
+    var typeSelect = content.find('#typeSelect');
     var urlEntry = content.find('#urlEntry');
     var usernameEntry = content.find('#usernameEntry');
     var passwordEntry = content.find('#passwordEntry');
@@ -2696,23 +2701,22 @@ function runAddCameraDialog() {
     /* make validators */
     makeUrlValidator(urlEntry, true);
     makeTextValidator(usernameEntry, false);
-    makeTextValidator(deviceSelect, false);
+    makeTextValidator(typeSelect, false);
     makeComboValidator(addCameraSelect, true);
     
     /* ui interaction */
     function updateUi() {
-        content.find('tr.motioneye, tr.netcam, tr.mjpeg').css('display', 'none');
+        content.find('tr.v4l2, tr.motioneye, tr.netcam, tr.mjpeg').css('display', 'none');
 
-        if (deviceSelect.val() == 'motioneye') {
+        if (typeSelect.val() == 'motioneye') {
             content.find('tr.motioneye').css('display', 'table-row');
-            addCameraSelect.hide();
             usernameEntry.val('admin');
             usernameEntry.attr('readonly', 'readonly');
             addCameraInfo.html(
                     'Remote motionEye cameras are cameras installed behind another motionEye server. ' +
                     'Adding them here will allow you to view and manage them remotely.');
         }
-        else if (deviceSelect.val() == 'netcam') {
+        else if (typeSelect.val() == 'netcam') {
             usernameEntry.removeAttr('readonly');
             
             /* make sure there is one trailing slash so that
@@ -2724,12 +2728,11 @@ function runAddCameraDialog() {
             }
 
             content.find('tr.netcam').css('display', 'table-row');
-            addCameraSelect.hide();
             addCameraInfo.html(
                     'Network cameras (or IP cameras) are devices that natively stream MJPEG videos or plain JPEG images. ' +
                     "Consult your device's manual to find out the correct MJPEG (or JPEG) URL.");
         }
-        else if (deviceSelect.val() == 'mjpeg') {
+        else if (typeSelect.val() == 'mjpeg') {
             usernameEntry.removeAttr('readonly');
             
             /* make sure there is one trailing slash so that
@@ -2741,43 +2744,48 @@ function runAddCameraDialog() {
             }
 
             content.find('tr.mjpeg').css('display', 'table-row');
-            addCameraSelect.hide();
             addCameraInfo.html(
                     'Adding your device as a simple MJPEG camera instead of as a network camera will improve the framerate, ' +
                     'but no motion detection, picture capturing or movie recording will be available for it. ' +
                     'The camera must be accessible to both your server and your browser. ' +
                     'This type of camera is not compatible with Internet Explorer.');
         }
+        else { /* assuming v4l2 */
+            content.find('tr.v4l2').css('display', 'table-row');
+            addCameraInfo.html(
+                    'Local cameras are camera devices that are connected directly to your motionEye system. ' +
+                    'These are usually USB webcams or board-specific cameras.');
+        }
         
         updateModalDialogPosition();
-        addCameraSelect.html('');
         
         /* re-validate all the validators */
         content.find('.validator').each(function () {
             this.validate();
         });
         
-        if (content.is(':visible') && uiValid() && (deviceSelect.val() in {'motioneye': 1, 'netcam': 1, 'mjpeg': 1})) {
-            fetchRemoteCameras();
+        if (uiValid()) {
+            listCameras();
         }
     }
     
     function uiValid(includeCameraSelect) {
-        /* re-validate all the validators */
-        content.find('.validator').each(function () {
-            this.validate();
-        });
-        
-        var valid = true;
         var query = content.find('input, select');
         if (!includeCameraSelect) {
             query = query.not('#addCameraSelect');
         }
         else {
-            if (cameraMsgLabel.html()) {
+            if (cameraMsgLabel.html() || !addCameraSelect.val()) {
                 return false;
             }
         }
+
+        /* re-validate all the validators */
+        content.find('.validator').each(function () {
+            this.validate();
+        });
+        
+        var valid = true;
         query.each(function () {
             if (this.invalid) {
                 valid = false;
@@ -2821,17 +2829,21 @@ function runAddCameraDialog() {
         };
     }
     
-    function fetchRemoteCameras() {
+    function listCameras() {
         var progress = $('<div style="text-align: center; margin: 2px;"><img src="' + staticUrl + 'img/small-progress.gif"></div>');
         
+        addCameraSelect.html('');
         addCameraSelect.hide();
         addCameraSelect.parent().find('div').remove(); /* remove any previous progress div */
         addCameraSelect.before(progress);
         
-        var data = splitCameraUrl(urlEntry.val());
+        var data = {};
+        if (urlEntry.is(':visible') && urlEntry.val()) {
+            data = splitCameraUrl(urlEntry.val());
+        }
         data.username = usernameEntry.val();
         data.password = passwordEntry.val();
-        data.proto = deviceSelect.val();
+        data.proto = typeSelect.val();
         
         cameraMsgLabel.html('');
         
@@ -2854,91 +2866,72 @@ function runAddCameraDialog() {
                 addCameraSelect.append('<option value="' + info.id + '">' + info.name + '</option>');
             });
             
+            if (!data.cameras || !data.cameras.length) {
+                addCameraSelect.append('<option value="">(no cameras)</option>');
+            }
+            
             addCameraSelect.show();
+            addCameraSelect[0].validate();
         });
     }
     
-    deviceSelect.change(updateUi);
+    typeSelect.change(updateUi);
     urlEntry.change(updateUi);
     usernameEntry.change(updateUi);
     passwordEntry.change(updateUi);
     updateUi();
     
-    showModalDialog('<div class="modal-progress"></div>');
-    
-    /* fetch the available devices */
-    ajax('GET', baseUri + 'config/list_devices/', null, function (data) {
-        if (data == null || data.error) {
-            hideModalDialog();
-            showErrorMessage(data && data.error);
-            return;
-        }
-        
-        /* add available devices */
-        data.devices.forEach(function (device) {
-            if (!device.configured) {
-                deviceSelect.append('<option value="' + device.uri + '">' + device.name + '</option>');
+    runModalDialog({
+        title: 'Add Camera...',
+        closeButton: true,
+        buttons: 'okcancel',
+        content: content,
+        onOk: function () {
+            if (!uiValid(true)) {
+                return false;
             }
-        });
-        
-        deviceSelect.append('<option value="netcam">Network camera...</option>');
-        deviceSelect.append('<option value="motioneye">Remote motionEye camera...</option>');
-        deviceSelect.append('<option value="mjpeg">Simple MJPEG camera...</option>');
-        
-        updateUi();
-        
-        runModalDialog({
-            title: 'Add Camera...',
-            closeButton: true,
-            buttons: 'okcancel',
-            content: content,
-            onOk: function () {
-                if (!uiValid(true)) {
-                    return false;
-                }
 
-                var data = {};
-                
-                if (deviceSelect.val() == 'motioneye') {
-                    data = splitCameraUrl(urlEntry.val());
-                    data.proto = 'motioneye';
-                    data.username = usernameEntry.val();
-                    data.password = passwordEntry.val();
-                    data.remote_camera_id = addCameraSelect.val();
-                }
-                else if (deviceSelect.val() == 'netcam') {
-                    data = splitCameraUrl(urlEntry.val());
-                    data.username = usernameEntry.val();
-                    data.password = passwordEntry.val();
-                    data.proto = 'netcam';
-                }
-                else if (deviceSelect.val() == 'mjpeg') {
-                    data = splitCameraUrl(urlEntry.val());
-                    data.username = usernameEntry.val();
-                    data.password = passwordEntry.val();
-                    data.proto = 'mjpeg';
-                }
-                else { /* assuming v4l2 */
-                    data.proto = 'v4l2';
-                    data.uri = deviceSelect.val();
-                }
-
-                beginProgress();
-                ajax('POST', baseUri + 'config/add/', data, function (data) {
-                    endProgress();
+            var data = {};
+            
+            if (typeSelect.val() == 'motioneye') {
+                data = splitCameraUrl(urlEntry.val());
+                data.proto = 'motioneye';
+                data.username = usernameEntry.val();
+                data.password = passwordEntry.val();
+                data.remote_camera_id = addCameraSelect.val();
+            }
+            else if (typeSelect.val() == 'netcam') {
+                data = splitCameraUrl(urlEntry.val());
+                data.username = usernameEntry.val();
+                data.password = passwordEntry.val();
+                data.proto = 'netcam';
+            }
+            else if (typeSelect.val() == 'mjpeg') {
+                data = splitCameraUrl(urlEntry.val());
+                data.username = usernameEntry.val();
+                data.password = passwordEntry.val();
+                data.proto = 'mjpeg';
+            }
+            else { /* assuming v4l2 */
+                data.proto = 'v4l2';
+                data.uri = addCameraSelect.val();
+            }
+
+            beginProgress();
+            ajax('POST', baseUri + 'config/add/', data, function (data) {
+                endProgress();
 
-                    if (data == null || data.error) {
-                        showErrorMessage(data && data.error);
-                        return;
-                    }
-                    
-                    var cameraOption = $('#cameraSelect').find('option[value=add]');
-                    cameraOption.before('<option value="' + data.id + '">' + data.name + '</option>');
-                    $('#cameraSelect').val(data.id).change();
-                    recreateCameraFrames();
-                });
-            }
-        });
+                if (data == null || data.error) {
+                    showErrorMessage(data && data.error);
+                    return;
+                }
+                
+                var cameraOption = $('#cameraSelect').find('option[value=add]');
+                cameraOption.before('<option value="' + data.id + '">' + data.name + '</option>');
+                $('#cameraSelect').val(data.id).change();
+                recreateCameraFrames();
+            });
+        }
     });
 }
 
index 4aefc592ebf34b491e6cddaeaf0db14027484f57..7dfa9bbdfc1e58c6802a8b1ac64d5f74af71c1c1 100644 (file)
@@ -885,7 +885,7 @@ function makeModalDialogButtons(buttonsInfo) {
             var oldClick = info.click;
             info.click = function () {
                 if (oldClick() == false) {
-                    return;
+                    return false;
                 }
                 
                 hideModalDialog();