configuration refactoring
authorCalin Crisan <ccrisan@gmail.com>
Sun, 12 Jan 2014 16:16:23 +0000 (18:16 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Sun, 12 Jan 2014 16:40:25 +0000 (18:40 +0200)
src/config.py
src/handlers.py
src/remote.py
src/utils.py
static/js/main.js

index 5a8a69c099c26ef3f9778562c103ba655394c4b4..75f63cfb7fe7bb83fbb7b1163393ca75daceb34f 100644 (file)
@@ -77,18 +77,18 @@ def get_main(as_lines=False):
     if as_lines:
         return lines
     
-    data = _conf_to_dict(lines, list_names=['thread'])
-    _set_default_motion(data)
+    main_config = _conf_to_dict(lines, list_names=['thread'])
+    _set_default_motion(main_config)
     
-    _main_config_cache = data
+    _main_config_cache = main_config
     
-    return data
+    return main_config
 
 
-def set_main(data):
+def set_main(main_config):
     global _main_config_cache
     
-    _set_default_motion(data)
+    _set_default_motion(main_config)
     
     config_file_path = os.path.join(settings.CONF_PATH, _MAIN_CONFIG_FILE_NAME)
     
@@ -96,8 +96,8 @@ def set_main(data):
     lines = get_main(as_lines=True)
     
     # preserve the threads
-    if 'thread' not in data:
-        threads = data.setdefault('thread', [])
+    if 'thread' not in main_config:
+        threads = main_config.setdefault('thread', [])
         for line in lines:
             match = re.match('^\s*thread\s+([a-zA-Z0-9.\-]+)', line)
             if match:
@@ -115,7 +115,7 @@ def set_main(data):
         
         raise
     
-    lines = _dict_to_conf(lines, data, list_names=['thread'])
+    lines = _dict_to_conf(lines, main_config, list_names=['thread'])
     
     try:
         file.writelines([l + '\n' for l in lines])
@@ -129,9 +129,9 @@ def set_main(data):
     finally:
         file.close()
 
-    _main_config_cache = data
+    _main_config_cache = main_config
 
-    return data
+    return main_config
 
 
 def get_camera_ids():
@@ -214,52 +214,52 @@ def get_camera(camera_id, as_lines=False):
     if as_lines:
         return lines
         
-    data = _conf_to_dict(lines)
+    camera_config = _conf_to_dict(lines)
     
-    data.setdefault('@proto', 'v4l2')
+    camera_config.setdefault('@proto', 'v4l2')
     
     # determine the enabled status
-    if data['@proto'] == 'v4l2':
+    if camera_config['@proto'] == 'v4l2':
         main_config = get_main()
         threads = main_config.get('thread', [])
-        data['@enabled'] = _CAMERA_CONFIG_FILE_NAME % {'id': camera_id} in threads
-        data['@id'] = camera_id
+        camera_config['@enabled'] = _CAMERA_CONFIG_FILE_NAME % {'id': camera_id} in threads
+        camera_config['@id'] = camera_id
 
-        _set_default_motion_camera(camera_id, data)
+        _set_default_motion_camera(camera_id, camera_config)
     
     if _camera_config_cache is None:
         _camera_config_cache = {}
     
-    _camera_config_cache[camera_id] = data
+    _camera_config_cache[camera_id] = camera_config
     
-    return data
+    return camera_config
 
 
-def set_camera(camera_id, data):
+def set_camera(camera_id, camera_config):
     global _camera_config_cache
     
-    if data['@proto'] == 'v4l2':
-        _set_default_motion_camera(camera_id, data)
+    if camera_config['@proto'] == 'v4l2':
+        _set_default_motion_camera(camera_id, camera_config)
         
         # set the enabled status in main config
         main_config = get_main()
         threads = main_config.setdefault('thread', [])
         config_file_name = _CAMERA_CONFIG_FILE_NAME % {'id': camera_id}
-        if data['@enabled'] and config_file_name not in threads:
+        if camera_config['@enabled'] and config_file_name not in threads:
             threads.append(config_file_name)
                 
-        elif not data['@enabled']:
+        elif not camera_config['@enabled']:
             threads = [t for t in threads if t != config_file_name]
 
         main_config['thread'] = threads
         
-        data['@id'] = camera_id
+        camera_config['@id'] = camera_id
         
         set_main(main_config)
         
         # try to create the target_dir
         try:
-            os.makedirs(data['target_dir'])
+            os.makedirs(camera_config['target_dir'])
         
         except OSError as e:
             if e.errno != errno.EEXIST:
@@ -286,7 +286,7 @@ def set_camera(camera_id, data):
         
         raise
     
-    lines = _dict_to_conf(lines, data)
+    lines = _dict_to_conf(lines, camera_config)
     
     try:
         file.writelines([l + '\n' for l in lines])
@@ -303,9 +303,9 @@ def set_camera(camera_id, data):
     if _camera_config_cache is None:
         _camera_config_cache = {}
     
-    _camera_config_cache[camera_id] = data
+    _camera_config_cache[camera_id] = camera_config
     
-    return data
+    return camera_config
 
 
 def add_camera(device_details):
@@ -330,7 +330,7 @@ def add_camera(device_details):
     
     if proto == 'v4l2':
         data['@name'] = 'Camera' + str(camera_id)
-        data['videodevice'] = device_details['device']
+        data['videodevice'] = device_details['device_uri']
         if 'width' in device_details:
             data['width'] = device_details['width']
             data['height'] = device_details['height']
@@ -415,7 +415,7 @@ def camera_ui_to_dict(ui):
         '@name': ui['name'],
         '@enabled': ui['enabled'],
         '@proto': ui['proto'],
-        'videodevice': ui['device'],
+        'videodevice': ui['device_uri'],
         'lightswitch': int(ui['light_switch_detect']) * 5,
         'auto_brightness': ui['auto_brightness'],
         'width': int(ui['resolution'].split('x')[0]),
@@ -565,24 +565,15 @@ def camera_ui_to_dict(ui):
     
 
 def camera_dict_to_ui(data):
-    if data['@proto'] == 'v4l2':
-        device_uri = data['videodevice']
-        usage = utils.get_disk_usage(data['target_dir'])
-        if usage:
-            disk_used, disk_total = usage
-        
-        else:
-            disk_used, disk_total = 0, 0
+    usage = utils.get_disk_usage(data['target_dir'])
+    if usage:
+        disk_used, disk_total = usage
     
     else:
-        device_uri = '%(host)s:%(port)s/config/%(camera_id)s' % {
-                'username': data['@username'],
-                'password': '***',
-                'host': data['@host'],
-                'port': data['@port'],
-                'camera_id': data['@remote_camera_id']}
-        
-        disk_used, disk_total = data['disk_used'], data['disk_total']
+        disk_used, disk_total = 0, 0
+    
+    resolutions = v4l2ctl.list_resolutions(data['videodevice'])
+    resolutions = [(str(w) + 'x' + str(h)) for (w, h) in resolutions]
     
     ui = {
         # device
@@ -590,10 +581,13 @@ def camera_dict_to_ui(data):
         'enabled': data['@enabled'],
         'id': data['@id'],
         'proto': data['@proto'],
-        'device': device_uri,
+        'host': data.get('@host', ''),
+        'port': data.get('@port', ''),
+        'device_uri': data['videodevice'],
         'light_switch_detect': data['lightswitch'] > 0,
         'auto_brightness': data['auto_brightness'],
         'resolution': str(data['width']) + 'x' + str(data['height']),
+        'available_resolutions': resolutions,
         'framerate': int(data['framerate']),
         'rotation': int(data['rotate']),
         
@@ -662,51 +656,37 @@ def camera_dict_to_ui(data):
     # the brightness & co. keys in the ui dictionary
     # indicate the presence of these controls
     # we must call v4l2ctl functions to determine the available controls    
-    if ui['proto'] == 'v4l2':
-        brightness = v4l2ctl.get_brightness(ui['device'])
-        if brightness is not None: # has brightness control
-            if data.get('brightness', 0) != 0:
-                ui['brightness'] = brightness
-                    
-            else:
-                ui['brightness'] = 50
-            
-        contrast = v4l2ctl.get_contrast(ui['device'])
-        if contrast is not None: # has contrast control
-            if data.get('contrast', 0) != 0:
-                ui['contrast'] = contrast
-            
-            else:
-                ui['contrast'] = 50
-            
-        saturation = v4l2ctl.get_saturation(ui['device'])
-        if saturation is not None: # has saturation control
-            if data.get('saturation', 0) != 0:
-                ui['saturation'] = saturation
-            
-            else:
-                ui['saturation'] = 50
-            
-        hue = v4l2ctl.get_hue(ui['device'])
-        if hue is not None: # has hue control
-            if data.get('hue', 0) != 0:
-                ui['hue'] = hue
-            
-            else:
-                ui['hue'] = 50
-            
-    else: # remote
-        if 'brightness' in data:
-            ui['brightness'] = data['brightness']
-
-        if 'contrast' in data:
-            ui['contrast'] = data['contrast']
-
-        if 'saturation' in data:
-            ui['saturation'] = data['saturation']
-
-        if 'hue' in data:
-            ui['hue'] = data['hue']
+    brightness = v4l2ctl.get_brightness(ui['device_uri'])
+    if brightness is not None: # has brightness control
+        if data.get('brightness', 0) != 0:
+            ui['brightness'] = brightness
+                
+        else:
+            ui['brightness'] = 50
+        
+    contrast = v4l2ctl.get_contrast(ui['device_uri'])
+    if contrast is not None: # has contrast control
+        if data.get('contrast', 0) != 0:
+            ui['contrast'] = contrast
+        
+        else:
+            ui['contrast'] = 50
+        
+    saturation = v4l2ctl.get_saturation(ui['device_uri'])
+    if saturation is not None: # has saturation control
+        if data.get('saturation', 0) != 0:
+            ui['saturation'] = saturation
+        
+        else:
+            ui['saturation'] = 50
+        
+    hue = v4l2ctl.get_hue(ui['device_uri'])
+    if hue is not None: # has hue control
+        if data.get('hue', 0) != 0:
+            ui['hue'] = hue
+        
+        else:
+            ui['hue'] = 50
 
     text_left = data['text_left']
     text_right = data['text_right'] 
index 9cd5a4ec16630a85543ccad33b4b68ca78bae4d6..81e86de6fce931aa8e19f06bb0dad373fa4c505e 100644 (file)
@@ -29,6 +29,7 @@ import remote
 import settings
 import template
 import update
+import utils
 import v4l2ctl
 
 
@@ -162,40 +163,22 @@ class ConfigHandler(BaseHandler):
             if camera_id not in config.get_camera_ids():
                 raise HTTPError(404, 'no such camera')
             
-            camera_config = config.get_camera(camera_id)
-            if camera_config['@proto'] != 'v4l2':
+            local_config = config.get_camera(camera_id)
+            if local_config['@proto'] != 'v4l2':
                 def on_response(remote_ui_config):
-                    camera_url = remote.make_remote_camera_url(
-                            camera_config.get('@host'),
-                            camera_config.get('@port'),
-                            camera_config.get('@remote_camera_id'))
-                    
-                    camera_full_url = camera_config['@proto'] + '://' + camera_url
-                    
                     if remote_ui_config is None:
                         return self.finish_json({'error': 'Failed to get remote camera configuration for %(url)s.' % {
-                                'url': camera_full_url}})
+                                'url': utils.make_camera_url(local_config)}})
                     
-                    for key, value in camera_config.items():
+                    for key, value in local_config.items():
                         remote_ui_config[key.replace('@', '')] = value
                     
-                    remote_ui_config['device'] = camera_url
-                    
                     self.finish_json(remote_ui_config)
                 
-                remote.get_config(
-                        camera_config.get('@host'),
-                        camera_config.get('@port'),
-                        camera_config.get('@username'),
-                        camera_config.get('@password'),
-                        camera_config.get('@remote_camera_id'), on_response)
+                remote.get_config(local_config, on_response)
             
             else:
-                ui_config = config.camera_dict_to_ui(camera_config)
-                
-                resolutions = v4l2ctl.list_resolutions(camera_config['videodevice'])
-                resolutions = [(str(w) + 'x' + str(h)) for (w, h) in resolutions]
-                ui_config['available_resolutions'] = resolutions
+                ui_config = config.camera_dict_to_ui(local_config)
                     
                 self.finish_json(ui_config)
             
@@ -237,37 +220,33 @@ class ConfigHandler(BaseHandler):
             if camera_id not in camera_ids:
                 raise HTTPError(404, 'no such camera')
             
-            camera_config = config.get_camera(camera_id)
-            if camera_config['@proto'] == 'v4l2':
-                ui_config.setdefault('device', camera_config.get('videodevice', ''))
-                ui_config.setdefault('proto', camera_config['@proto'])
-                ui_config.setdefault('enabled', camera_config['@enabled'])
+            local_config = config.get_camera(camera_id)
+            if local_config['@proto'] == 'v4l2':
+#                 ui_config.setdefault('device', local_config.get('videodevice', '')) TODO needed?
+#                 ui_config.setdefault('proto', local_config['@proto'])
+#                 ui_config.setdefault('enabled', local_config['@enabled'])
                 
-                camera_config = config.camera_ui_to_dict(ui_config)
-                config.set_camera(camera_id, camera_config)
+                local_config = config.camera_ui_to_dict(ui_config)
+                config.set_camera(camera_id, local_config)
                 
             else:  # remote camera
                 # update the camera locally
-                camera_config['@enabled'] = ui_config['enabled']
-                config.set_camera(camera_id, camera_config)
+                local_config['@enabled'] = ui_config['enabled']
+                config.set_camera(camera_id, local_config)
                 
-                # when the camera_config supplied has only the enabled state,
+                # when the local_config supplied has only the enabled state,
                 # the camera was probably disabled due to errors
 
-                if camera_config.has_key('device'):
+                if ui_config.has_key('device_uri'):
                     # remove the fields that should not get to the remote side
-                    del ui_config['device']
+                    del ui_config['device_uri']
                     del ui_config['proto']
+                    del ui_config['host']
+                    del ui_config['port']
                     del ui_config['enabled']
                     
                     try:
-                        remote.set_config(
-                                camera_config.get('@host'),
-                                camera_config.get('@port'),
-                                camera_config.get('@username'),
-                                camera_config.get('@password'),
-                                camera_config.get('@remote_camera_id'),
-                                ui_config)
+                        remote.set_config(local_config, ui_config)
                         
                     except Exception as e:
                         logging.error('failed to set remote camera config: %(msg)s' % {'msg': unicode(e)})
@@ -294,7 +273,7 @@ class ConfigHandler(BaseHandler):
                 
                 reload = True 
 
-        motionctl.restart()
+        motionctl.restart() # TODO should not be restarted unless a local camera was changed
         
         if not no_finish:
             self.finish_json()
@@ -349,24 +328,13 @@ class ConfigHandler(BaseHandler):
                 else:
                     self.finish_json()
             
-            remote.set_preview(
-                    camera_config['@host'],
-                    camera_config['@port'],
-                    camera_config['@username'],
-                    camera_config['@password'],
-                    camera_config['@remote_camera_id'],
-                    controls, on_response)
+            remote.set_preview(camera_config, controls, on_response)
 
     @BaseHandler.auth()
     def list_cameras(self):
         logging.debug('listing cameras')
-
-        host = self.get_argument('host', None)
-        port = self.get_argument('port', None)
-        username = self.get_argument('username', None)
-        password = self.get_argument('password', None)
         
-        if host:  # remote listing
+        if 'host' in self.get_data():  # remote listing
             def on_response(cameras):
                 if cameras is None:
                     self.finish_json({'error': 'Failed to list remote cameras.'})
@@ -374,7 +342,7 @@ class ConfigHandler(BaseHandler):
                 else:
                     self.finish_json({'cameras': cameras})
             
-            cameras = remote.list_cameras(host, port, username, password, on_response)
+            cameras = remote.list_cameras(self.get_data(), on_response)
                 
         else:  # local listing
             cameras = []
@@ -388,18 +356,12 @@ class ConfigHandler(BaseHandler):
                     cameras.sort(key=lambda c: c['id'])
                     self.finish_json({'cameras': cameras})
                     
-            def on_response_builder(camera_id, camera_config):
+            def on_response_builder(camera_id, local_config):
                 def on_response(remote_ui_config):
                     if remote_ui_config is None:
-                        camera_url = remote.make_remote_camera_url(
-                                camera_config.get('@host'),
-                                camera_config.get('@port'),
-                                camera_config.get('@remote_camera_id'),
-                                camera_config.get('@proto'))
-                        
                         cameras.append({
                             'id': camera_id,
-                            'name': '&lt;' + camera_url + '&gt;',
+                            'name': '&lt;' + utils.make_camera_url(local_config) + '&gt;',
                             'enabled': False,
                             'streaming_framerate': 1,
                             'framerate': 1
@@ -407,7 +369,7 @@ class ConfigHandler(BaseHandler):
                     
                     else:
                         remote_ui_config['id'] = camera_id
-                        remote_ui_config['enabled'] = camera_config['@enabled']  # override the enabled status
+                        remote_ui_config['enabled'] = local_config['@enabled']  # override the enabled status
                         cameras.append(remote_ui_config)
                         
                     check_finished()
@@ -415,19 +377,14 @@ class ConfigHandler(BaseHandler):
                 return on_response
             
             for camera_id in camera_ids:
-                camera_config = config.get_camera(camera_id)
-                if camera_config['@proto'] == 'v4l2':
-                    ui_config = config.camera_dict_to_ui(camera_config)
+                local_config = config.get_camera(camera_id)
+                if local_config['@proto'] == 'v4l2':
+                    ui_config = config.camera_dict_to_ui(local_config)
                     cameras.append(ui_config)
                     check_finished()
 
                 else:  # remote camera
-                    remote.get_config(
-                            camera_config.get('@host'),
-                            camera_config.get('@port'),
-                            camera_config.get('@username'),
-                            camera_config.get('@password'),
-                            camera_config.get('@remote_camera_id'), on_response_builder(camera_id, camera_config))
+                    remote.get_config(local_config, on_response_builder(camera_id, local_config))
             
             if length[0] == 0:        
                 self.finish_json({'cameras': []})
@@ -442,7 +399,7 @@ class ConfigHandler(BaseHandler):
             if data['@proto'] == 'v4l2':
                 configured_devices[data['videodevice']] = True
 
-        devices = [{'device': d[0], 'name': d[1], 'configured': d[0] in configured_devices}
+        devices = [{'device_uri': d[0], 'name': d[1], 'configured': d[0] in configured_devices}
                 for d in v4l2ctl.list_devices()]
         
         self.finish_json({'devices': devices})
@@ -462,7 +419,7 @@ class ConfigHandler(BaseHandler):
         proto = device_details['proto']
         if proto == 'v4l2':
             # find a suitable resolution
-            for (w, h) in v4l2ctl.list_resolutions(device_details['device']):
+            for (w, h) in v4l2ctl.list_resolutions(device_details['device_uri']):
                 if w > 300:
                     device_details['width'] = w
                     device_details['height'] = h
@@ -482,9 +439,6 @@ class ConfigHandler(BaseHandler):
             motionctl.restart()
             
             ui_config = config.camera_dict_to_ui(camera_config)
-            resolutions = v4l2ctl.list_resolutions(camera_config['videodevice'])
-            resolutions = [(str(w) + 'x' + str(h)) for (w, h) in resolutions]
-            ui_config['available_resolutions'] = resolutions
             
             self.finish_json(ui_config)
         
@@ -492,22 +446,13 @@ class ConfigHandler(BaseHandler):
             def on_response(remote_ui_config):
                 if remote_ui_config is None:
                     self.finish_json({'error': True})
+
+                for key, value in camera_config.items():
+                    remote_ui_config[key.replace('@', '')] = value
                 
-                tmp_config = config.camera_ui_to_dict(remote_ui_config)
-                tmp_config.update(camera_config)
-                tmp_config['disk_used'] = remote_ui_config['disk_used']
-                tmp_config['disk_total'] = remote_ui_config['disk_total']
-                ui_config = config.camera_dict_to_ui(tmp_config)
-                ui_config['available_resolutions'] = remote_ui_config['available_resolutions']
+                self.finish_json(remote_ui_config)
                 
-                self.finish_json(ui_config)
-                
-            remote.get_config(
-                    device_details.get('host'),
-                    device_details.get('port'),
-                    device_details.get('username'),
-                    device_details.get('password'),
-                    device_details.get('remote_camera_id'), on_response)
+            remote.get_config(device_details, on_response)
     
     @BaseHandler.auth(admin=True)
     def rem_camera(self, camera_id):
@@ -579,15 +524,7 @@ class PictureHandler(BaseHandler):
                 
                 self.finish(picture)
             
-            remote.get_current_picture(
-                    camera_config['@host'],
-                    camera_config['@port'],
-                    camera_config['@username'],
-                    camera_config['@password'],
-                    camera_config['@remote_camera_id'],
-                    on_response,
-                    width=width,
-                    height=height)
+            remote.get_current_picture(camera_config, on_response, width=width, height=height)
 
     @BaseHandler.auth()
     def list(self, camera_id):
@@ -599,27 +536,13 @@ class PictureHandler(BaseHandler):
         camera_config = config.get_camera(camera_id)
         if camera_config['@proto'] != 'v4l2':
             def on_response(remote_list):
-                camera_url = remote.make_remote_camera_url(
-                        camera_config.get('@host'),
-                        camera_config.get('@port'),
-                        camera_config.get('@remote_camera_id'))
-
-                camera_full_url = camera_config['@proto'] + '://' + camera_url
-
                 if remote_list is None:
                     return self.finish_json({'error': 'Failed to get picture list for %(url)s.' % {
-                            'url': camera_full_url}})
+                            'url': utils.make_camera_url(camera_config)}})
 
                 self.finish_json(remote_list)
             
-            remote.list_media(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'), on_response,
-                    media_type='picture',
-                    prefix=self.get_argument('prefix', None))
+            remote.list_media(camera_config, on_response, media_type='picture', prefix=self.get_argument('prefix', None))
         
         else:
             def on_media_list(media_list):
@@ -645,16 +568,9 @@ class PictureHandler(BaseHandler):
         camera_config = config.get_camera(camera_id)
         if camera_config['@proto'] != 'v4l2':
             def on_response(response):
-                camera_url = remote.make_remote_camera_url(
-                        camera_config.get('@host'),
-                        camera_config.get('@port'),
-                        camera_config.get('@remote_camera_id'))
-                
-                camera_full_url = camera_config['@proto'] + '://' + camera_url
-                
                 if response is None:
                     return self.finish_json({'error': 'Failed to download picture from %(url)s.' % {
-                            'url': camera_full_url}})
+                            'url': utils.make_camera_url(camera_config)}})
 
                 pretty_filename = os.path.basename(filename) # no camera name available w/o additional request
                 self.set_header('Content-Type', 'image/jpeg')
@@ -662,15 +578,7 @@ class PictureHandler(BaseHandler):
                 
                 self.finish(response)
 
-            remote.get_media_content(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'),
-                    on_response,
-                    filename=filename,
-                    media_type='picture')
+            remote.get_media_content(camera_config, on_response, filename=filename, media_type='picture')
             
         else:
             content = mediafiles.get_media_content(camera_config, filename, 'picture')
@@ -702,15 +610,7 @@ class PictureHandler(BaseHandler):
                 
                 self.finish(content)
             
-            remote.get_media_preview(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'),
-                    on_response,
-                    filename=filename,
-                    media_type='picture',
+            remote.get_media_preview(camera_config, on_response, filename=filename, media_type='picture',
                     width=self.get_argument('width', None),
                     height=self.get_argument('height', None))
         
@@ -759,27 +659,13 @@ class MovieHandler(BaseHandler):
         camera_config = config.get_camera(camera_id)
         if camera_config['@proto'] != 'v4l2':
             def on_response(remote_list):
-                camera_url = remote.make_remote_camera_url(
-                        camera_config.get('@host'),
-                        camera_config.get('@port'),
-                        camera_config.get('@remote_camera_id'))
-
-                camera_full_url = camera_config['@proto'] + '://' + camera_url
-
                 if remote_list is None:
                     return self.finish_json({'error': 'Failed to get movie list for %(url)s.' % {
-                            'url': camera_full_url}})
+                            'url': utils.make_camera_url(camera_config)}})
 
                 self.finish_json(remote_list)
             
-            remote.list_media(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'), on_response,
-                    media_type='movie',
-                    prefix=self.get_argument('prefix', None))
+            remote.list_media(camera_config, on_response, media_type='movie', prefix=self.get_argument('prefix', None))
         
         else:
             def on_media_list(media_list):
@@ -805,16 +691,9 @@ class MovieHandler(BaseHandler):
         camera_config = config.get_camera(camera_id)
         if camera_config['@proto'] != 'v4l2':
             def on_response(response):
-                camera_url = remote.make_remote_camera_url(
-                        camera_config.get('@host'),
-                        camera_config.get('@port'),
-                        camera_config.get('@remote_camera_id'))
-                
-                camera_full_url = camera_config['@proto'] + '://' + camera_url
-                
                 if response is None:
                     return self.finish_json({'error': 'Failed to download movie from %(url)s.' % {
-                            'url': camera_full_url}})
+                            'url': utils.make_camera_url(camera_config)}})
 
                 pretty_filename = os.path.basename(filename) # no camera name available w/o additional request
                 self.set_header('Content-Type', 'video/mpeg')
@@ -822,15 +701,7 @@ class MovieHandler(BaseHandler):
                 
                 self.finish(response)
 
-            remote.get_media_content(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'),
-                    on_response,
-                    filename=filename,
-                    media_type='movie')
+            remote.get_media_content(camera_config, on_response, filename=filename, media_type='movie')
             
         else:
             content = mediafiles.get_media_content(camera_config, filename, 'movie')
@@ -861,15 +732,7 @@ class MovieHandler(BaseHandler):
 
                 self.finish(content)
             
-            remote.get_media_preview(
-                    camera_config.get('@host'),
-                    camera_config.get('@port'),
-                    camera_config.get('@username'),
-                    camera_config.get('@password'),
-                    camera_config.get('@remote_camera_id'),
-                    on_response,
-                    filename=filename,
-                    media_type='movie',
+            remote.get_media_preview(camera_config, on_response, filename=filename, media_type='movie',
                     width=self.get_argument('width', None),
                     height=self.get_argument('height', None))
         
index 856326e602f81fe018a40f065b05c706eb584450..cbcde73cfa79d15c3a7eec94e12fe8f3d3ea5bc6 100644 (file)
@@ -39,19 +39,16 @@ def _make_request(host, port, username, password, uri, method='GET', data=None,
     return request
 
 
-def make_remote_camera_url(host, port, camera_id, proto=''):
-    if proto:
-        proto += '://'
-        
-    return '%(proto)s%(host)s:%(port)s/config/%(camera_id)s' % {
-        'host': host,
-        'port': port,
-        'camera_id': camera_id,
-        'proto': proto
-    }
+def make_camera_uri(camera_id):
+    return '/config/%(camera_id)s' % {'camera_id': camera_id}
 
 
-def list_cameras(host, port, username, password, callback):
+def list_cameras(local_config, callback):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    
     logging.debug('listing remote cameras on %(host)s:%(port)s' % {
             'host': host,
             'port': port})
@@ -84,7 +81,13 @@ def list_cameras(host, port, username, password, callback):
     http_client.fetch(request, on_response)
     
 
-def get_config(host, port, username, password, camera_id, callback):
+def get_config(local_config, callback):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+     
     logging.debug('getting config for remote camera %(id)s on %(host)s:%(port)s' % {
             'id': camera_id,
             'host': host,
@@ -112,6 +115,10 @@ def get_config(host, port, username, password, camera_id, callback):
                     'msg': unicode(e)})
             
             return callback(None)
+        
+        response['host'] = host
+        response['port'] = port
+        response['device_uri'] = make_camera_uri(camera_id)
             
         callback(response)
     
@@ -119,15 +126,21 @@ def get_config(host, port, username, password, camera_id, callback):
     http_client.fetch(request, on_response)
     
 
-def set_config(host, port, username, password, camera_id, data):
+def set_config(local_config, camera_config):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('setting config for remote camera %(id)s on %(host)s:%(port)s' % {
             'id': camera_id,
             'host': host,
             'port': port})
     
-    data = json.dumps(data)
+    camera_config = json.dumps(camera_config)
     
-    request = _make_request(host, port, username, password, '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=data)
+    request = _make_request(host, port, username, password, '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=camera_config)
     
     try:
         http_client = HTTPClient()
@@ -145,7 +158,13 @@ def set_config(host, port, username, password, camera_id, data):
         raise
 
 
-def set_preview(host, port, username, password, camera_id, controls, callback):
+def set_preview(local_config, controls, callback):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('setting preview for remote camera %(id)s on %(host)s:%(port)s' % {
             'id': camera_id,
             'host': host,
@@ -171,7 +190,13 @@ def set_preview(host, port, username, password, camera_id, controls, callback):
     http_client.fetch(request, on_response)
 
 
-def get_current_picture(host, port, username, password, camera_id, callback, width, height):
+def get_current_picture(local_config, callback, width, height):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('getting current picture for remote camera %(id)s on %(host)s:%(port)s' % {
             'id': camera_id,
             'host': host,
@@ -203,7 +228,13 @@ def get_current_picture(host, port, username, password, camera_id, callback, wid
     http_client.fetch(request, on_response)
 
 
-def list_media(host, port, username, password, camera_id, callback, media_type, prefix=None):
+def list_media(local_config, callback, media_type, prefix=None):
+    host = local_config.get('@host', local_config.get('host')) 
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('getting media list for remote camera %(id)s on %(host)s:%(port)s' % {
             'id': camera_id,
             'host': host,
@@ -243,7 +274,13 @@ def list_media(host, port, username, password, camera_id, callback, media_type,
     http_client.fetch(request, on_response)
 
 
-def get_media_content(host, port, username, password, camera_id, callback, filename, media_type):
+def get_media_content(local_config, callback, filename, media_type):
+    host = local_config.get('@host', local_config.get('host'))
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('downloading file %(filename)s of remote camera %(id)s on %(host)s:%(port)s' % {
             'filename': filename,
             'id': camera_id,
@@ -274,7 +311,13 @@ def get_media_content(host, port, username, password, camera_id, callback, filen
     http_client.fetch(request, on_response)
 
 
-def get_media_preview(host, port, username, password, camera_id, callback, filename, media_type, width, height):
+def get_media_preview(local_config, callback, filename, media_type, width, height):
+    host = local_config.get('@host', local_config.get('host'))
+    port = local_config.get('@port', local_config.get('port'))
+    username = local_config.get('@username', local_config.get('username'))
+    password = local_config.get('@password', local_config.get('password'))
+    camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))
+    
     logging.debug('getting file preview for %(filename)s of remote camera %(id)s on %(host)s:%(port)s' % {
             'filename': filename,
             'id': camera_id,
index d6fff8ac085a58baf6674423e689a287b1806fb7..30645966741bcc719bb55787ef71184dd6211924 100644 (file)
@@ -19,6 +19,8 @@ import datetime
 import logging
 import os
 
+import remote
+
 
 def pretty_date_time(date_time, tzinfo=None):
     if date_time is None:
@@ -206,3 +208,12 @@ def get_disk_usage(path):
     used_size = total_size - free_size
     
     return (used_size, total_size)
+
+
+def make_camera_url(config):
+    proto = config.get('proto', config.get('@proto', ''))
+    host = config.get('host', config.get('@host', ''))
+    port = config.get('port', config.get('@port', ''))
+    device_uri = config.get('device_uri', config.get('videodevice', remote.make_camera_uri(config.get('@remote_camera_id'))))
+    
+    return proto + '://' + host + (str(port) + ':' if port else '') + device_uri
index d8abd0347f944bbf7a8e5fbe0f734f7e3b50adc5..a8043090289a68d474b789bc80691fa557d605ae 100644 (file)
@@ -251,7 +251,7 @@ function initUI() {
             updateConfigUi();
         }
         else {
-            showProgress();
+            beginProgress();
             fetchCurrentCameraConfig(endProgress);
         }
     });
@@ -508,12 +508,24 @@ function cameraUi2Dict() {
         };
     }
     
+    var deviceUrl = $('#deviceEntry').val();
+    var parts = deviceUrl.split('://');
+    var proto = parts[0];
+    parts = parts[1].split('/');
+    var hostPort = parts[0];
+    var deviceUri = '/' + parts.slice(1).join('/');
+    parts = hostPort.split(':');
+    var host = parts[0];
+    var port = parts[1] || '';
+    
     var dict = {
         /* video device */
         'enabled': $('#videoDeviceSwitch')[0].checked,
         'name': $('#deviceNameEntry').val(),
-        'proto': $('#deviceEntry').val().split('://')[0],
-        'device': $('#deviceEntry').val().split('://')[1],
+        'proto': proto,
+        'host': host,
+        'port': port,
+        'device_uri': deviceUri,
         'light_switch_detect': $('#lightSwitchDetectSwitch')[0].checked,
         'auto_brightness': $('#autoBrightnessSwitch')[0].checked,
         'resolution': $('#resolutionSelect').val(),
@@ -624,7 +636,7 @@ function dict2CameraUi(dict) {
     /* video device */
     $('#videoDeviceSwitch')[0].checked = dict['enabled'];
     $('#deviceNameEntry').val(dict['name']);
-    $('#deviceEntry').val(dict['proto'] + '://' + dict['device']);
+    $('#deviceEntry').val(dict['proto'] + '://' + dict['host'] + (dict['port'] ? ':' + dict['port'] : '') + dict['device_uri']);
     $('#lightSwitchDetectSwitch')[0].checked = dict['light_switch_detect'];
     $('#autoBrightnessSwitch')[0].checked = dict['auto_brightness'];
     
@@ -722,26 +734,14 @@ function dict2CameraUi(dict) {
 }
 
     
-    /* apply button */
-
-function showApply() {
-    var applyButton = $('#applyButton');
-    
-    applyButton.html('Apply');
-    applyButton.css('display', 'inline-block');
-    applyButton.removeClass('progress');
-    setTimeout(function () {
-        applyButton.css('opacity', '1');
-    }, 10);
-}
+    /* progress */
 
-function showProgress() {
+function beginProgress(cameraIds) {
     if (inProgress) {
         return; /* already in progress */
     }
 
     inProgress = true;
-    refreshDisabled++;
     
     /* replace the main page message with a progress indicator */
     $('div.add-camera-message').html('<img class="main-loading-progress" src="' + staticUrl + 'img/main-loading-progress.gif">');
@@ -750,30 +750,25 @@ function showProgress() {
     $('#applyButton').html('<img class="apply-progress" src="' + staticUrl + 'img/apply-progress.gif">');
     
     /* show the camera progress indicators */
-    $('div.camera-progress').css('opacity', '0.5');
+    if (cameraIds) {
+        cameraIds.forEach(function (cameraId) {
+            $('div.camera-frame#' + cameraId + ' div.camera-progress').css('opacity', '0.5');
+        });
+    }
+    else {
+        $('div.camera-progress').css('opacity', '0.5');
+    }
     
     /* remove the settings progress lock */
     $('div.settings-progress').css('width', '100%').css('opacity', '0.9');
 }
 
-function hideApply() {
-    var applyButton = $('#applyButton');
-    
-    applyButton.css('opacity', '0');
-    applyButton.removeClass('progress');
-    
-    setTimeout(function () {
-        applyButton.css('display', 'none');
-    }, 500);
-}
-
 function endProgress() {
     if (!inProgress) {
         return; /* not in progress */
     }
     
     inProgress = false;
-    refreshDisabled--;
     
     /* remove any existing message on the main page */
     $('div.add-camera-message').remove();
@@ -797,6 +792,31 @@ function endProgress() {
     }, 500);
 }
 
+
+    /* apply button */
+
+function showApply() {
+    var applyButton = $('#applyButton');
+    
+    applyButton.html('Apply');
+    applyButton.css('display', 'inline-block');
+    applyButton.removeClass('progress');
+    setTimeout(function () {
+        applyButton.css('opacity', '1');
+    }, 10);
+}
+
+function hideApply() {
+    var applyButton = $('#applyButton');
+    
+    applyButton.css('opacity', '0');
+    applyButton.removeClass('progress');
+    
+    setTimeout(function () {
+        applyButton.css('display', 'none');
+    }, 500);
+}
+
 function isApplyVisible() {
     var applyButton = $('#applyButton');
     
@@ -810,7 +830,7 @@ function doApply() {
         return;
     }
     
-    showProgress();
+    beginProgress();
     
     ajax('POST', '/config/0/set/', pushConfigs, function (data) {
         if (data == null || data.error) {
@@ -857,7 +877,7 @@ function doRemCamera() {
     var deviceName = $('#videoDeviceSelect').find('option[value=' + cameraId + ']').text();
     
     runConfirmDialog('Remove camera ' + deviceName + '?', function () {
-        showProgress();
+        beginProgress();
         ajax('POST', '/config/' + cameraId + '/rem/', null, function (data) {
             if (data == null || data.error) {
                 endProgress();
@@ -1057,6 +1077,10 @@ function pushPreview(control) {
     });
 }
 
+function getCameraIdsByInstance() {
+    
+}
+
 
     /* dialogs */
 
@@ -1312,7 +1336,7 @@ function runAddCameraDialog() {
         /* add available devices */
         data.devices.forEach(function (device) {
             if (!device.configured) {
-                deviceSelect.append('<option value="' + device.device + '">' + device.name + '</option>');
+                deviceSelect.append('<option value="' + device.device_uri + '">' + device.name + '</option>');
             }
         });
         
@@ -1341,10 +1365,10 @@ function runAddCameraDialog() {
                 }
                 else {
                     data.proto = 'v4l2';
-                    data.device = deviceSelect.val();
+                    data.device_uri = deviceSelect.val();
                 }
 
-                showProgress();
+                beginProgress();
                 ajax('POST', '/config/add/', data, function (data) {
                     if (data == null || data.error) {
                         endProgress();
@@ -1714,7 +1738,7 @@ function addCameraFrameUi(cameraId, cameraName, framerate) {
     /* error and load handlers */
     cameraImg.error(function () {
         this.error = true;
-        this.loading = false;
+        this.loading = 0;
         
         cameraImg.addClass('error').removeClass('loading');
         cameraImg.height(Math.round(cameraImg.width() * 0.75));
@@ -1727,7 +1751,7 @@ function addCameraFrameUi(cameraId, cameraName, framerate) {
         }
         
         this.error = false;
-        this.loading = false;
+        this.loading = 0;
         
         cameraImg.removeClass('error').removeClass('loading');
         cameraImg.css('height', '');
@@ -1864,7 +1888,14 @@ function refreshCameraFrames() {
     
     function refreshCameraFrame(cameraId, img, fast) {
         if (img.loading) {
-            return; /* still loading the previous image */
+            img.loading++; /* increases each time the camera would refresh but is still loading */
+            
+            if (img.loading > 5) {
+                img.loading = 0;
+            }
+            else {
+                return; /* wait for the previous frame to finish loading */
+            }
         }
         
         var timestamp = new Date().getTime();
@@ -1873,7 +1904,7 @@ function refreshCameraFrames() {
         }
         timestamp = Math.round(timestamp);
         img.src = '/picture/' + cameraId + '/current/?seq=' + timestamp + '&width=' + img.width;
-        img.loading = true;
+        img.loading = 1;
     }
     
     var cameraFrames;
@@ -1951,7 +1982,7 @@ $(document).ready(function () {
     });
     
     initUI();
-    showProgress();
+    beginProgress();
     fetchCurrentConfig(endProgress);
     refreshCameraFrames();
     checkCameraErrors();