]> www.vanbest.org Git - motioneye-debian/commitdiff
a few PEP8 code cleanups
authorCalin Crisan <ccrisan@gmail.com>
Sat, 5 Aug 2017 09:55:52 +0000 (12:55 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Sat, 5 Aug 2017 09:55:52 +0000 (12:55 +0300)
27 files changed:
.gitignore
motioneye/cleanup.py
motioneye/config.py
motioneye/diskctl.py
motioneye/handlers.py
motioneye/mediafiles.py
motioneye/meyectl.py
motioneye/mjpgclient.py
motioneye/monitor.py
motioneye/motionctl.py
motioneye/ordereddict.py [deleted file]
motioneye/powerctl.py
motioneye/prefs.py
motioneye/remote.py
motioneye/sendmail.py
motioneye/server.py
motioneye/settings.py
motioneye/smbctl.py
motioneye/tasks.py
motioneye/tzctl.py
motioneye/update.py
motioneye/uploadservices.py
motioneye/utils.py
motioneye/v4l2ctl.py
motioneye/webhook.py
motioneye/wifictl.py
motioneye/wsswitch.py

index a41af758b5b1d3c9de3feb1af22d0d867c0b89be..ebdc131ab6dc27aaca9ade808ebf51af0e7001cb 100644 (file)
@@ -6,6 +6,7 @@
 .pydevproject
 *.conf
 .settings
+.idea
 run
 dist
 motioneye.egg-info
index 6f122d3550e77b048f731132845b6a56a2674f2e..9e4aa46768350ad50f42ec42abe8b0f3ed313c9c 100644 (file)
@@ -68,7 +68,7 @@ def _run_process():
     # schedule the next call
     io_loop.add_timeout(datetime.timedelta(seconds=settings.CLEANUP_INTERVAL), _run_process)
 
-    if not running(): # check that the previous process has finished
+    if not running():  # check that the previous process has finished
         logging.debug('running cleanup process...')
 
         _process = multiprocessing.Process(target=_do_cleanup)
index 48e8cf53ea0aa2e96a1ec4b82ed8beb49f422d4b..07a84322f130967b1ff382832d2f85a50cdcbfa0 100644 (file)
@@ -41,8 +41,9 @@ import v4l2ctl
 
 _CAMERA_CONFIG_FILE_NAME = 'thread-%(id)s.conf'
 _MAIN_CONFIG_FILE_NAME = 'motion.conf'
-_ACTIONS = ['lock', 'unlock', 'light_on', 'light_off', 'alarm_on', 'alarm_off', 'up', 'right', 'down', 'left', 'zoom_in', 'zoom_out',
-        'preset1', 'preset2', 'preset3', 'preset4', 'preset5', 'preset6', 'preset7', 'preset8', 'preset9']
+_ACTIONS = ['lock', 'unlock', 'light_on', 'light_off', 'alarm_on', 'alarm_off', 'up',
+            'right', 'down', 'left', 'zoom_in', 'zoom_out',
+            'preset1', 'preset2', 'preset3', 'preset4', 'preset5', 'preset6', 'preset7', 'preset8', 'preset9']
 
 _main_config_cache = None
 _camera_config_cache = {}
@@ -54,11 +55,11 @@ _monitor_command_cache = {}
 
 # when using the following video codecs, the ffmpeg_variable_bitrate parameter appears to have an exponential effect
 _EXPONENTIAL_QUALITY_CODECS = ['mpeg4', 'msmpeg4', 'swf', 'flv', 'mov', 'mkv']
-_EXPONENTIAL_QUALITY_FACTOR = 100000 # voodoo
-_EXPONENTIAL_DEF_QUALITY = 511 # about 75%
+_EXPONENTIAL_QUALITY_FACTOR = 100000  # voodoo
+_EXPONENTIAL_DEF_QUALITY = 511  # about 75%
 _MAX_FFMPEG_VARIABLE_BITRATE = 32767
 
-_KNOWN_MOTION_OPTIONS = set([
+_KNOWN_MOTION_OPTIONS = {
     'auto_brightness',
     'brightness',
     'contrast',
@@ -117,8 +118,8 @@ _KNOWN_MOTION_OPTIONS = set([
     'text_right',
     'threshold',
     'videodevice',
-    'width',
-])
+    'width'
+}
 
 
 def additional_section(func):
@@ -145,13 +146,14 @@ def get_main(as_lines=False):
     
     lines = None
     try:
-        file = open(config_file_path, 'r')
+        f = open(config_file_path, 'r')
     
     except IOError as e:
         if e.errno == errno.ENOENT:  # file does not exist
             logging.info('main config file %(path)s does not exist, using default values' % {'path': config_file_path})
             
             lines = []
+            f = None
         
         else:
             logging.error('could not open main config file %(path)s: %(msg)s' % {
@@ -159,9 +161,9 @@ def get_main(as_lines=False):
             
             raise
     
-    if lines is None:
+    if lines is None and f:
         try:
-            lines = [l[:-1] for l in file.readlines()]
+            lines = [l[:-1] for l in f.readlines()]
         
         except Exception as e:
             logging.error('could not read main config file %(path)s: %(msg)s' % {
@@ -170,7 +172,7 @@ def get_main(as_lines=False):
             raise
         
         finally:
-            file.close()
+            f.close()
     
     if as_lines:
         return lines
@@ -207,7 +209,7 @@ def set_main(main_config):
     logging.debug('writing main config to %(path)s...' % {'path': config_file_path})
     
     try:
-        file = open(config_file_path, 'w')
+        f = open(config_file_path, 'w')
     
     except Exception as e:
         logging.error('could not open main config file %(path)s for writing: %(msg)s' % {
@@ -218,7 +220,7 @@ def set_main(main_config):
     lines = _dict_to_conf(lines, main_config, list_names=['thread'])
     
     try:
-        file.writelines([utils.make_str(l) + '\n' for l in lines])
+        f.writelines([utils.make_str(l) + '\n' for l in lines])
     
     except Exception as e:
         logging.error('could not write main config file %(path)s: %(msg)s' % {
@@ -227,7 +229,7 @@ def set_main(main_config):
         raise
     
     finally:
-        file.close()
+        f.close()
 
 
 def get_camera_ids(filter_valid=True):
@@ -316,7 +318,7 @@ def get_camera(camera_id, as_lines=False):
     logging.debug('reading camera config from %(path)s...' % {'path': camera_config_path})
     
     try:
-        file = open(camera_config_path, 'r')
+        f = open(camera_config_path, 'r')
     
     except Exception as e:
         logging.error('could not open camera config file: %(msg)s' % {'msg': unicode(e)})
@@ -324,7 +326,7 @@ def get_camera(camera_id, as_lines=False):
         raise
     
     try:
-        lines = [l.strip() for l in file.readlines()]
+        lines = [l.strip() for l in f.readlines()]
     
     except Exception as e:
         logging.error('could not read camera config file %(path)s: %(msg)s' % {
@@ -333,7 +335,7 @@ def get_camera(camera_id, as_lines=False):
         raise
     
     finally:
-        file.close()
+        f.close()
     
     if as_lines:
         return lines
@@ -399,7 +401,7 @@ def get_camera(camera_id, as_lines=False):
         
         _set_default_simple_mjpeg_camera(camera_id, camera_config)
     
-    else: # incomplete configuration
+    else:  # incomplete configuration
         logging.warn('camera config file at %s is incomplete, ignoring' % camera_config_path)
         
         return None
@@ -491,7 +493,7 @@ def set_camera(camera_id, camera_config):
     logging.debug('writing camera config to %(path)s...' % {'path': camera_config_path})
     
     try:
-        file = open(camera_config_path, 'w')
+        f = open(camera_config_path, 'w')
     
     except Exception as e:
         logging.error('could not open camera config file %(path)s for writing: %(msg)s' % {
@@ -502,7 +504,7 @@ def set_camera(camera_id, camera_config):
     lines = _dict_to_conf(lines, camera_config)
     
     try:
-        file.writelines([utils.make_str(l) + '\n' for l in lines])
+        f.writelines([utils.make_str(l) + '\n' for l in lines])
     
     except Exception as e:
         logging.error('could not write camera config file %(path)s: %(msg)s' % {
@@ -511,7 +513,7 @@ def set_camera(camera_id, camera_config):
         raise
     
     finally:
-        file.close()
+        f.close()
         
 
 def add_camera(device_details):
@@ -530,7 +532,8 @@ def add_camera(device_details):
             else:
                 host = device_details['username'] + '@' + host
 
-        device_details['url'] = urlparse.urlunparse((device_details['scheme'], host, device_details['path'], '', '', ''))
+        device_details['url'] = urlparse.urlunparse(
+                (device_details['scheme'], host, device_details['path'], '', '', ''))
 
     # determine the last camera id
     camera_ids = get_camera_ids()
@@ -580,7 +583,7 @@ def add_camera(device_details):
             camera_config['width'] = 640
             camera_config['height'] = 480
 
-    else: # assuming mjpeg
+    else:  # assuming mjpeg
         camera_config['@proto'] = 'mjpeg'
         camera_config['@url'] = device_details['url']
     
@@ -680,7 +683,7 @@ def motion_camera_ui_to_dict(ui, old_config=None):
     import smbctl
     
     old_config = dict(old_config or {})
-    main_config = get_main() # needed for surveillance password
+    main_config = get_main()  # needed for surveillance password
 
     data = {
         # device
@@ -813,7 +816,7 @@ def motion_camera_ui_to_dict(ui, old_config=None):
             else:
                 data['hue'] = max(1, int(round(int(ui['hue']) * 2.55)))
     
-    else: # assuming netcam
+    else:  # assuming netcam
         if data.get('netcam_url', old_config.get('netcam_url', '')).startswith('rtsp'):
             # motion uses the configured width and height for RTSP cameras
             width = int(ui['resolution'].split('x')[0])
@@ -823,7 +826,7 @@ def motion_camera_ui_to_dict(ui, old_config=None):
             
             threshold = int(float(ui['frame_change_threshold']) * width * height / 100)
         
-        else: # width & height are not available for other netcams
+        else:  # width & height are not available for other netcams
             threshold = int(float(ui['frame_change_threshold']) * 640 * 480 / 100)
 
     data['threshold'] = threshold
@@ -852,9 +855,9 @@ def motion_camera_ui_to_dict(ui, old_config=None):
         os.makedirs(data['target_dir'])
         logging.debug('created root directory %s for camera %s' % (data['target_dir'], data['@name']))
     
-    except Exception as e:
+    except OSError as e:
         if isinstance(e, OSError) and e.errno == errno.EEXIST:
-            pass # already exists, things should be just fine
+            pass  # already exists, things should be just fine
         
         else:
             logging.error('failed to create root directory "%s": %s' % (data['target_dir'], e), exc_info=True)
@@ -923,7 +926,8 @@ def motion_camera_ui_to_dict(ui, old_config=None):
     q = int(ui['movie_quality'])
     if motionctl.needs_ffvb_quirks():
         if data['ffmpeg_video_codec'] in _EXPONENTIAL_QUALITY_CODECS:
-            vbr = max(1, _MAX_FFMPEG_VARIABLE_BITRATE * (1 - math.log(max(1, q * _EXPONENTIAL_QUALITY_FACTOR), _EXPONENTIAL_QUALITY_FACTOR * 100)))
+            vbr = max(1, _MAX_FFMPEG_VARIABLE_BITRATE * (1 - math.log(max(1, q * _EXPONENTIAL_QUALITY_FACTOR),
+                                                                      _EXPONENTIAL_QUALITY_FACTOR * 100)))
             
         else:
             vbr = 1 + (_MAX_FFMPEG_VARIABLE_BITRATE - 1) / 100.0 * (100 - q)
@@ -950,7 +954,8 @@ def motion_camera_ui_to_dict(ui, old_config=None):
             if data.get('rotate') in [90, 270]:
                 capture_width, capture_height = capture_height, capture_width
 
-            data['mask_file'] = utils.build_editable_mask_file(old_config['@id'], ui['mask_lines'], capture_width, capture_height)
+            data['mask_file'] = utils.build_editable_mask_file(old_config['@id'], ui['mask_lines'],
+                                                               capture_width, capture_height)
 
     # working schedule
     if ui['working_schedule']:
@@ -970,7 +975,8 @@ def motion_camera_ui_to_dict(ui, old_config=None):
     if ui['email_notifications_enabled']:
         emails = re.sub('\\s', '', ui['email_notifications_addresses'])
         
-        on_event_start.append("%(script)s '%(server)s' '%(port)s' '%(account)s' '%(password)s' '%(tls)s' '%(from)s' '%(to)s' 'motion_start' '%%t' '%%Y-%%m-%%dT%%H:%%M:%%S' '%(timespan)s'" % {
+        line = "%(script)s '%(server)s' '%(port)s' '%(account)s' '%(password)s' '%(tls)s' '%(from)s' '%(to)s' " \
+               "'motion_start' '%%t' '%%Y-%%m-%%dT%%H:%%M:%%S' '%(timespan)s'" % {
                 'script': meyectl.find_command('sendmail'),
                 'server': ui['email_notifications_smtp_server'],
                 'port': ui['email_notifications_smtp_port'],
@@ -979,7 +985,9 @@ def motion_camera_ui_to_dict(ui, old_config=None):
                 'tls': ui['email_notifications_smtp_tls'],
                 'from': ui['email_notifications_from'],
                 'to': emails,
-                'timespan': ui['email_notifications_picture_time_span']})
+                'timespan': ui['email_notifications_picture_time_span']}
+
+        on_event_start.append(line)
 
     if ui['web_hook_notifications_enabled']:
         url = re.sub('\\s', '+', ui['web_hook_notifications_url'])
@@ -1085,7 +1093,7 @@ def motion_camera_dict_to_ui(data):
         'upload_subfolders': data['@upload_subfolders'],
         'upload_username': data['@upload_username'],
         'upload_password': data['@upload_password'],
-        'upload_authorization_key': '', # needed, otherwise the field is hidden
+        'upload_authorization_key': '',  # needed, otherwise the field is hidden
         'web_hook_storage_enabled': False,
         'command_storage_enabled': False,
 
@@ -1169,11 +1177,11 @@ def motion_camera_dict_to_ui(data):
 
             threshold = data['threshold'] * 100.0 / (data['width'] * data['height'])
 
-        else: # width & height are not available for other netcams
+        else:  # width & height are not available for other netcams
             # we have no other choice but use something like 640x480 as reference
             threshold = data['threshold'] * 100.0 / (640 * 480)
 
-    else: # assuming v4l2
+    else:  # assuming v4l2
         ui['device_url'] = data['videodevice']
         ui['proto'] = 'v4l2'
 
@@ -1186,7 +1194,7 @@ def motion_camera_dict_to_ui(data):
         # indicate the presence of these controls
         # we must call v4l2ctl functions to determine the available controls    
         brightness = v4l2ctl.get_brightness(data['videodevice'])
-        if brightness is not None: # has brightness control
+        if brightness is not None:  # has brightness control
             if data.get('brightness', 0) != 0:
                 ui['brightness'] = brightness
                     
@@ -1194,7 +1202,7 @@ def motion_camera_dict_to_ui(data):
                 ui['brightness'] = 50
 
         contrast = v4l2ctl.get_contrast(data['videodevice'])
-        if contrast is not None: # has contrast control
+        if contrast is not None:  # has contrast control
             if data.get('contrast', 0) != 0:
                 ui['contrast'] = contrast
             
@@ -1202,7 +1210,7 @@ def motion_camera_dict_to_ui(data):
                 ui['contrast'] = 50
             
         saturation = v4l2ctl.get_saturation(data['videodevice'])
-        if saturation is not None: # has saturation control
+        if saturation is not None:  # has saturation control
             if data.get('saturation', 0) != 0:
                 ui['saturation'] = saturation
             
@@ -1210,7 +1218,7 @@ def motion_camera_dict_to_ui(data):
                 ui['saturation'] = 50
             
         hue = v4l2ctl.get_hue(data['videodevice'])
-        if hue is not None: # has hue control
+        if hue is not None:  # has hue control
             if data.get('hue', 0) != 0:
                 ui['hue'] = hue
             
@@ -1222,7 +1230,10 @@ def motion_camera_dict_to_ui(data):
     ui['frame_change_threshold'] = threshold
     
     if (data['@storage_device'] == 'network-share') and settings.SMB_SHARES:
-        mount_point = smbctl.make_mount_point(data['@network_server'], data['@network_share_name'], data['@network_username'])
+        mount_point = smbctl.make_mount_point(data['@network_server'],
+                                              data['@network_share_name'],
+                                              data['@network_username'])
+
         ui['root_directory'] = data['target_dir'][len(mount_point):] or '/'
     
     elif data['@storage_device'].startswith('local-disk'):
@@ -1233,8 +1244,10 @@ def motion_camera_dict_to_ui(data):
                 ui['root_directory'] = data['target_dir'][len(partition['mount_point']):] or '/'
                 break
 
-        else: # not found for some reason
-            logging.error('could not find mounted partition for device "%s" and target dir "%s"' % (target_dev, data['target_dir']))
+        else:  # not found for some reason
+            logging.error('could not find mounted partition for device "%s" and target dir "%s"' %
+                          (target_dev, data['target_dir']))
+
             ui['root_directory'] = data['target_dir']
 
     else:
@@ -1317,7 +1330,8 @@ def motion_camera_dict_to_ui(data):
     bitrate = data['ffmpeg_variable_bitrate']
     if motionctl.needs_ffvb_quirks():
         if data['ffmpeg_video_codec'] in _EXPONENTIAL_QUALITY_CODECS:
-            q = (100 * _EXPONENTIAL_QUALITY_FACTOR) ** ((1 - float(bitrate) / _MAX_FFMPEG_VARIABLE_BITRATE)) / _EXPONENTIAL_QUALITY_FACTOR
+            q = (100 * _EXPONENTIAL_QUALITY_FACTOR) ** \
+                    (1 - float(bitrate) / _MAX_FFMPEG_VARIABLE_BITRATE) / _EXPONENTIAL_QUALITY_FACTOR
     
         else:
             q = 100 - (bitrate - 1) * 100.0 / (_MAX_FFMPEG_VARIABLE_BITRATE - 1)
@@ -1400,9 +1414,9 @@ def motion_camera_dict_to_ui(data):
             ui['web_hook_notifications_url'] = e[-1]
         
         elif e.count('relayevent'):
-            continue # ignore internal relay script
+            continue  # ignore internal relay script
 
-        else: # custom command
+        else:  # custom command
             command_notifications.append(e)
     
     if command_notifications: 
@@ -1427,9 +1441,9 @@ def motion_camera_dict_to_ui(data):
             ui['web_hook_storage_url'] = e[-1]
 
         elif e.count('relayevent'):
-            continue # ignore internal relay script
+            continue  # ignore internal relay script
 
-        else: # custom command
+        else:  # custom command
             command_storage.append(e)
     
     if command_storage: 
@@ -1448,7 +1462,7 @@ def motion_camera_dict_to_ui(data):
     for name, value in data.iteritems():
         if name not in _KNOWN_MOTION_OPTIONS and not name.startswith('@'):
             if isinstance(value, bool):
-                value = ['off', 'on'][value] # boolean values should be transferred as on/off
+                value = ['off', 'on'][value]  # boolean values should be transferred as on/off
 
             extra_options.append((name, value))
 
@@ -1535,7 +1549,9 @@ def backup():
     logging.debug('generating config backup file')
 
     if len(os.listdir(settings.CONF_PATH)) > 100:
-        logging.debug('config path "%s" appears to be a system-wide config directory, performing a selective backup' % settings.CONF_PATH)
+        logging.debug('config path "%s" appears to be a system-wide config directory, performing a selective backup' %
+                      settings.CONF_PATH)
+
         cmd = ['tar', 'zc', 'motion.conf']
         cmd += map(os.path.basename, glob.glob(os.path.join(settings.CONF_PATH, 'thread-*.conf')))
         try:
@@ -1550,7 +1566,8 @@ def backup():
             return None
 
     else:
-        logging.debug('config path "%s" appears to be a motion-specific config directory, performing a full backup' % settings.CONF_PATH)
+        logging.debug('config path "%s" appears to be a motion-specific config directory, performing a full backup' %
+                      settings.CONF_PATH)
 
         try:
             content = subprocess.check_output(['tar', 'zc', '.'], cwd=settings.CONF_PATH)
@@ -1647,24 +1664,30 @@ def _python_to_value(value):
         return value
 
 
-def _conf_to_dict(lines, list_names=[], no_convert=[]):
-    data = utils.OrderedDict()
+def _conf_to_dict(lines, list_names=None, no_convert=None):
+    if list_names is None:
+        list_names = []
+
+    if no_convert is None:
+        no_convert = []
+
+    data = collections.OrderedDict()
     
     for line in lines:
         line = line.strip()
         if len(line) == 0:  # empty line
             continue
         
-        match = re.match('^\#\s*(\@\w+)\s*(.*)', line)
+        match = re.match('^#\s*(@\w+)\s*(.*)', line)
         if match:
             name, value = match.groups()[:2]
         
-        elif line.startswith('#') or line.startswith(';'): # comment line
+        elif line.startswith('#') or line.startswith(';'):  # comment line
             continue
 
         else:
             parts = line.split(None, 1)
-            if len(parts) == 1: # empty value
+            if len(parts) == 1:  # empty value
                 parts.append('')
 
             (name, value) = parts
@@ -1683,9 +1706,12 @@ def _conf_to_dict(lines, list_names=[], no_convert=[]):
     return data
 
 
-def _dict_to_conf(lines, data, list_names=[]):
+def _dict_to_conf(lines, data, list_names=None):
+    if list_names is None:
+        list_names = []
+
     conf_lines = []
-    remaining = utils.OrderedDict(data)
+    remaining = collections.OrderedDict(data)
     processed = set()
     
     # parse existing lines and replace the values
@@ -1696,8 +1722,8 @@ def _dict_to_conf(lines, data, list_names=[]):
             conf_lines.append(line)
             continue
 
-        match = re.match('^\#\s*(\@\w+)\s*(.*)', line)
-        if match: # @line
+        match = re.match('^#\s*(@\w+)\s*(.*)', line)
+        if match:  # @line
             (name, value) = match.groups()[:2]
         
         elif line.startswith('#') or line.startswith(';'):  # simple comment line
@@ -1713,7 +1739,7 @@ def _dict_to_conf(lines, data, list_names=[]):
                 (name, value) = parts[0], ''
             
         if name in processed:
-            continue # name already processed
+            continue  # name already processed
         
         processed.add(name)
         
@@ -1743,11 +1769,11 @@ def _dict_to_conf(lines, data, list_names=[]):
     # add the remaining config values not covered by existing lines
     
     if len(remaining) and len(lines):
-        conf_lines.append('') # add a blank line
+        conf_lines.append('')  # add a blank line
     
     for (name, value) in remaining.iteritems():
         if name.startswith('@_'):
-            continue # ignore additional configs
+            continue  # ignore additional configs
         
         if name in list_names:
             for v in value:
@@ -1774,7 +1800,7 @@ def _dict_to_conf(lines, data, list_names=[]):
             line = '# ' + line
         
         elif i > 0 and conf_lines[i - 1].startswith('@'):
-            lines.append('') # add a blank line between @lines and the rest
+            lines.append('')  # add a blank line between @lines and the rest
         
         lines.append(line)
         
@@ -1885,12 +1911,12 @@ def _set_default_motion_camera(camera_id, data):
     data.setdefault('max_movie_time', 0)
     data.setdefault('ffmpeg_output_movies', False)
     if motionctl.has_new_movie_format_support():
-        data.setdefault('ffmpeg_video_codec', 'mp4') # will use h264 codec
+        data.setdefault('ffmpeg_video_codec', 'mp4')  # will use h264 codec
         if motionctl.needs_ffvb_quirks():
-            data.setdefault('ffmpeg_variable_bitrate', _MAX_FFMPEG_VARIABLE_BITRATE / 4) # 75%
+            data.setdefault('ffmpeg_variable_bitrate', _MAX_FFMPEG_VARIABLE_BITRATE / 4)  # 75%
             
         else:
-            data.setdefault('ffmpeg_variable_bitrate', 75) # 75%
+            data.setdefault('ffmpeg_variable_bitrate', 75)  # 75%
         
     else:
         data.setdefault('ffmpeg_video_codec', 'msmpeg4')
@@ -1919,7 +1945,7 @@ def get_additional_structure(camera, separators=False):
                 'with' if separators else 'without'))
 
         # gather sections
-        sections = utils.OrderedDict()
+        sections = collections.OrderedDict()
         for func in _additional_section_funcs:
             result = func()
             if not result:
@@ -1936,7 +1962,7 @@ def get_additional_structure(camera, separators=False):
             
             logging.debug('additional config section: %s' % result['name'])
     
-        configs = utils.OrderedDict()
+        configs = collections.OrderedDict()
         for func in _additional_config_funcs:
             result = func()
             if not result:
index 8691474fa840a043bbbf28f1bcc8ae815b9f7432..8d7a4b18216ebd8a797a44d2d87866898e18572e 100644 (file)
@@ -46,12 +46,12 @@ def _list_mounts():
                 continue
             
             if target in seen_targets:
-                continue # probably a bind mount
+                continue  # probably a bind mount
             
             seen_targets.add(target)
 
             if fstype == 'fuseblk':
-                fstype = 'ntfs' # most likely
+                fstype = 'ntfs'  # most likely
             
             logging.debug('found mount "%s" at "%s"' % (target, mount_point))
             
@@ -161,15 +161,15 @@ def _list_disks_fdisk():
     disks = []
     disk = None
     
-    def add_disk(disk):
+    def add_disk(d):
         logging.debug('found disk at "%s" on bus "%s": "%s %s"' %
-                (disk['target'], disk['bus'], disk['vendor'], disk['model']))
+                (d['target'], d['bus'], d['vendor'], d['model']))
 
-        for part in disk['partitions']:
+        for part in d['partitions']:
             logging.debug('found partition "%s" at "%s" on bus "%s": "%s %s"' %
                     (part['part_no'], part['target'], part['bus'], part['vendor'], part['model']))
 
-        disks.append(disk)
+        disks.append(d)
 
     for line in output.split('\n'):
         line = line.replace('*', '')
index 051621c10c0a1ad78ecab05649456db11b63aa3e..587372a7c1271564aeb027df9cf6b021f6a5c59e 100644 (file)
@@ -76,16 +76,16 @@ class BaseHandler(RequestHandler):
 
         return self._json
     
-    def get_argument(self, name, default=None):
-        DEF = {}
-        argument = RequestHandler.get_argument(self, name, default=DEF)
-        if argument is DEF:
+    def get_argument(self, name, default=None, strip=True):
+        def_ = {}
+        argument = RequestHandler.get_argument(self, name, default=def_)
+        if argument is def_:
             # try to find it in json body
             data = self.get_json()
             if data:
-                argument = data.get(name, DEF)
+                argument = data.get(name, def_)
         
-            if argument is DEF:
+            if argument is def_:
                 argument = default
         
         return argument
@@ -101,8 +101,11 @@ class BaseHandler(RequestHandler):
         
         content = template.render(template_name, **context)
         self.finish(content)
-    
-    def finish_json(self, data={}):
+
+    def finish_json(self, data=None):
+        if data is None:
+            data = {}
+
         self.set_header('Content-Type', 'application/json')
         self.finish(json.dumps(data))
 
@@ -113,7 +116,7 @@ class BaseHandler(RequestHandler):
         signature = self.get_argument('_signature', None)
         login = self.get_argument('_login', None) == 'true'
         if (username == main_config.get('@admin_username') and
-            (signature == utils.compute_signature(self.request.method, self.request.uri, # backwards compatibility
+            (signature == utils.compute_signature(self.request.method, self.request.uri,  # backwards compatibility
                                                   self.request.body, main_config['@admin_password']) or
              signature == utils.compute_signature(self.request.method, self.request.uri,
                                                   self.request.body,
@@ -121,11 +124,11 @@ class BaseHandler(RequestHandler):
 
             return 'admin'
         
-        elif not username and not main_config.get('@normal_password'): # no authentication required for normal user
+        elif not username and not main_config.get('@normal_password'):  # no authentication required for normal user
             return 'normal'
         
         elif (username == main_config.get('@normal_username') and
-            (signature == utils.compute_signature(self.request.method, self.request.uri, # backwards compatibility
+            (signature == utils.compute_signature(self.request.method, self.request.uri,  # backwards compatibility
                                                   self.request.body, main_config.get('@normal_password')) or
              signature == utils.compute_signature(self.request.method, self.request.uri,
                                                   self.request.body,
@@ -149,7 +152,8 @@ class BaseHandler(RequestHandler):
             if isinstance(exception, HTTPError):
                 logging.error(str(exception))
                 self.set_status(exception.status_code)
-                self.finish_json({'error': exception.log_message or getattr(exception, 'reason', None) or str(exception)})
+                self.finish_json({'error': exception.log_message or
+                                           getattr(exception, 'reason', None) or str(exception)})
             
             else:
                 logging.error(str(exception), exc_info=True)
@@ -157,7 +161,7 @@ class BaseHandler(RequestHandler):
                 self.finish_json({'error':  'internal server error'})
                 
         except RuntimeError:
-            pass # nevermind
+            pass  # nevermind
         
     @staticmethod
     def auth(admin=False, prompt=True):
@@ -230,7 +234,7 @@ class ManifestHandler(BaseHandler):
         import motioneye
         
         self.set_header('Content-Type', 'application/manifest+json')
-        self.set_header('Cache-Control', 'max-age=2592000') # 30 days
+        self.set_header('Cache-Control', 'max-age=2592000')  # 30 days
         self.render('manifest.json', version=motioneye.VERSION)
 
 
@@ -300,8 +304,10 @@ class ConfigHandler(BaseHandler):
             elif utils.is_remote_camera(local_config):
                 def on_response(remote_ui_config=None, error=None):
                     if error:
-                        return self.finish_json({'error': 'Failed to get remote camera configuration for %(url)s: %(msg)s.' % {
-                                'url': remote.pretty_camera_url(local_config), 'msg': error}})
+                        msg = 'Failed to get remote camera configuration for %(url)s: %(msg)s.' % {
+                                'url': remote.pretty_camera_url(local_config), 'msg': error}
+
+                        return self.finish_json({'error': msg})
                     
                     for key, value in local_config.items():
                         remote_ui_config[key.replace('@', '')] = value
@@ -312,7 +318,7 @@ class ConfigHandler(BaseHandler):
                 
                 remote.get_config(local_config, on_response)
                 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 ui_config = config.simple_mjpeg_camera_dict_to_ui(local_config)
                     
                 self.finish_json(ui_config)
@@ -347,18 +353,18 @@ class ConfigHandler(BaseHandler):
 
                 config.set_camera(camera_id, local_config)
             
-                on_finish(None, True) # (no error, motion needs restart)
+                on_finish(None, True)  # (no error, motion needs restart)
 
             elif utils.is_remote_camera(local_config):
                 # update the camera locally
                 local_config['@enabled'] = ui_config['enabled']
                 config.set_camera(camera_id, local_config)
                 
-                if ui_config.has_key('name'):
-                    def on_finish_wrapper(error=None):
-                        return on_finish(error, False)
+                if 'name' in ui_config:
+                    def on_finish_wrapper(e=None):
+                        return on_finish(e, False)
                     
-                    ui_config['enabled'] = True # never disable the camera remotely 
+                    ui_config['enabled'] = True  # never disable the camera remotely
                     remote.set_config(local_config, ui_config, on_finish_wrapper)
                 
                 else:
@@ -367,24 +373,28 @@ class ConfigHandler(BaseHandler):
                     # the camera was probably disabled due to errors
                     on_finish(None, False)
                     
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 local_config = config.simple_mjpeg_camera_ui_to_dict(ui_config, local_config)
 
                 config.set_camera(camera_id, local_config)
             
-                on_finish(None, False) # (no error, motion doesn't need restart)
+                on_finish(None, False)  # (no error, motion doesn't need restart)
 
         def set_main_config(ui_config):
             logging.debug('setting main config...')
             
             old_main_config = config.get_main()
-            old_admin_credentials = '%s:%s' % (old_main_config.get('@admin_username', ''), old_main_config.get('@admin_password', ''))
-            old_normal_credentials = '%s:%s' % (old_main_config.get('@normal_username', ''), old_main_config.get('@normal_password', ''))
+            old_admin_credentials = '%s:%s' % (old_main_config.get('@admin_username', ''),
+                                               old_main_config.get('@admin_password', ''))
+            old_normal_credentials = '%s:%s' % (old_main_config.get('@normal_username', ''),
+                                                old_main_config.get('@normal_password', ''))
 
             main_config = config.main_ui_to_dict(ui_config)
             main_config.setdefault('thread', old_main_config.get('thread', [])) 
-            admin_credentials = '%s:%s' % (main_config.get('@admin_username', ''), main_config.get('@admin_password', ''))
-            normal_credentials = '%s:%s' % (main_config.get('@normal_username', ''), main_config.get('@normal_password', ''))
+            admin_credentials = '%s:%s' % (main_config.get('@admin_username', ''),
+                                           main_config.get('@admin_password', ''))
+            normal_credentials = '%s:%s' % (main_config.get('@normal_username', ''),
+                                            main_config.get('@normal_password', ''))
 
             additional_configs = config.get_additional_structure(camera=False)[1]           
             reboot_config_names = [('@_' + c['name']) for c in additional_configs.values() if c.get('reboot')]
@@ -425,8 +435,8 @@ class ConfigHandler(BaseHandler):
 
             return {'reload': reload, 'reboot': reboot, 'restart': restart}
         
-        reload = False # indicates that browser should reload the page
-        reboot = [False] # indicates that the server will reboot immediately
+        reload = False  # indicates that browser should reload the page
+        reboot = [False]  # indicates that the server will reboot immediately
         restart = [False]  # indicates that the local motion instance was modified and needs to be restarted
         error = [None]
         
@@ -461,7 +471,7 @@ class ConfigHandler(BaseHandler):
             self.finish({'reload': reload, 'reboot': reboot[0], 'error': error[0]})
         
         if camera_id is not None:
-            if camera_id == 0: # multiple camera configs
+            if camera_id == 0:  # multiple camera configs
                 if len(ui_config) > 1:
                     logging.debug('setting multiple configs')
                 
@@ -471,12 +481,13 @@ class ConfigHandler(BaseHandler):
                     self.finish()
                 
                 so_far = [0]
+
                 def check_finished(e, r):
                     restart[0] = restart[0] or r
                     error[0] = error[0] or e
                     so_far[0] += 1
                     
-                    if so_far[0] >= len(ui_config): # finished
+                    if so_far[0] >= len(ui_config):  # finished
                         finish()
 
                 # make sure main config is handled first
@@ -494,7 +505,7 @@ class ConfigHandler(BaseHandler):
                     else:
                         set_camera_config(int(key), cfg, check_finished)
             
-            else: # single camera config
+            else:  # single camera config
                 def on_finish(e, r):
                     error[0] = e
                     restart[0] = r
@@ -502,7 +513,7 @@ class ConfigHandler(BaseHandler):
 
                 set_camera_config(camera_id, ui_config, on_finish)
 
-        else: # main config
+        else:  # main config
             result = set_main_config(ui_config)
             reload = result['reload']
             reboot[0] = result['reboot']
@@ -558,7 +569,7 @@ class ConfigHandler(BaseHandler):
             
             remote.set_preview(camera_config, controls, on_response)
         
-        else: # not supported
+        else:  # not supported
             self.finish_json({'error': True})
 
     @BaseHandler.auth()
@@ -587,7 +598,8 @@ class ConfigHandler(BaseHandler):
                     self.finish_json({'cameras': cameras})
             
             if scheme in ['http', 'https']:
-                utils.test_mjpeg_url(self.get_all_arguments(), auth_modes=['basic'], allow_jpeg=True, callback=on_response)
+                utils.test_mjpeg_url(self.get_all_arguments(), auth_modes=['basic'], allow_jpeg=True,
+                                     callback=on_response)
                 
             elif motionctl.get_rtsp_support() and scheme == 'rtsp':
                 utils.test_rtsp_url(self.get_all_arguments(), callback=on_response)
@@ -603,7 +615,8 @@ class ConfigHandler(BaseHandler):
                 else:
                     self.finish_json({'cameras': cameras})
             
-            utils.test_mjpeg_url(self.get_all_arguments(), auth_modes=['basic', 'digest'], allow_jpeg=False, callback=on_response)
+            utils.test_mjpeg_url(self.get_all_arguments(), auth_modes=['basic', 'digest'], allow_jpeg=False,
+                                 callback=on_response)
         
         elif proto == 'v4l2':
             configured_devices = set()
@@ -624,6 +637,7 @@ class ConfigHandler(BaseHandler):
                 camera_ids = []
                 
             length = [len(camera_ids)]
+
             def check_finished():
                 if len(cameras) == length[0]:
                     cameras.sort(key=lambda c: c['id'])
@@ -675,10 +689,10 @@ class ConfigHandler(BaseHandler):
                     if local_config.get('@enabled') or self.get_argument('force', None) == 'true':
                         remote.get_config(local_config, on_response_builder(camera_id, local_config))
                     
-                    else: # don't try to reach the remote of the camera is disabled
+                    else:  # don't try to reach the remote of the camera is disabled
                         on_response_builder(camera_id, local_config)(error=True)
                         
-                else: # assuming simple mjpeg camera
+                else:  # assuming simple mjpeg camera
                     ui_config = config.simple_mjpeg_camera_dict_to_ui(local_config)
                     cameras.append(ui_config)
                     check_finished()
@@ -728,7 +742,7 @@ class ConfigHandler(BaseHandler):
                 
             remote.get_config(camera_config, on_response)
         
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             ui_config = config.simple_mjpeg_camera_dict_to_ui(camera_config)
             
             self.finish_json(ui_config)
@@ -792,7 +806,6 @@ class ConfigHandler(BaseHandler):
             logging.warn('accessing %s failed: %s' % (service_name, result))
             request_handler.finish_json({'error': result})
         
-
     @BaseHandler.auth(admin=True)
     def test(self, camera_id):
         what = self.get_argument('what')
@@ -804,7 +817,7 @@ class ConfigHandler(BaseHandler):
                 service_name = data['service']
                 ConfigHandler._upload_service_test_info = (self, service_name)
 
-                tasks.add(0, uploadservices.test_access, tag='uploadservices.test(%s)'% service_name,
+                tasks.add(0, uploadservices.test_access, tag='uploadservices.test(%s)' % service_name,
                         camera_id=camera_id, service_name=service_name, data=data, callback=self._on_test_result)
 
             elif what == 'email':
@@ -833,8 +846,10 @@ class ConfigHandler(BaseHandler):
     
                     old_timeout = settings.SMTP_TIMEOUT
                     settings.SMTP_TIMEOUT = 10
-                    sendmail.send_mail(data['smtp_server'], int(data['smtp_port']), data['smtp_account'], data['smtp_password'], data['smtp_tls'],
-                            data['from'], [data['addresses']], subject=subject, message=message, files=[])
+                    sendmail.send_mail(data['smtp_server'], int(data['smtp_port']), data['smtp_account'],
+                                       data['smtp_password'], data['smtp_tls'], data['from'], [data['addresses']],
+                                       subject=subject, message=message, files=[])
+
                     settings.SMTP_TIMEOUT = old_timeout
 
                     self.finish_json()
@@ -868,7 +883,9 @@ class ConfigHandler(BaseHandler):
                 logging.debug('testing access to network share //%s/%s' % (data['server'], data['share']))
 
                 try:
-                    smbctl.test_share(data['server'], data['share'], data['username'], data['password'], data['root_directory'])
+                    smbctl.test_share(data['server'], data['share'], data['username'],
+                                      data['password'], data['root_directory'])
+
                     logging.debug('access to network share //%s/%s succeeded' % (data['server'], data['share']))
                     self.finish_json()
 
@@ -941,7 +958,7 @@ class PictureHandler(BaseHandler):
     
     @asynchronous
     def post(self, camera_id, op, filename=None, group=None):
-        if group == '/': # ungrouped
+        if group == '/':  # ungrouped
             group = ''
         
         if camera_id is not None:
@@ -1000,10 +1017,9 @@ class PictureHandler(BaseHandler):
             
             remote.get_current_picture(camera_config, width=width, height=height, callback=on_response)
             
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
             
-
     @BaseHandler.auth()
     def list(self, camera_id):
         logging.debug('listing pictures for camera %(id)s' % {'id': camera_id})
@@ -1030,15 +1046,19 @@ class PictureHandler(BaseHandler):
 
                 self.finish_json(remote_list)
             
-            remote.list_media(camera_config, media_type='picture', prefix=self.get_argument('prefix', None), callback=on_response)
+            remote.list_media(camera_config, media_type='picture', prefix=self.get_argument('prefix', None),
+                              callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     def frame(self, camera_id):
         camera_config = config.get_camera(camera_id)
         
-        if utils.is_local_motion_camera(camera_config) or utils.is_simple_mjpeg_camera(camera_config) or self.get_argument('title', None) is not None:
+        if (utils.is_local_motion_camera(camera_config) or
+            utils.is_simple_mjpeg_camera(camera_config) or
+            self.get_argument('title', None) is not None):
+
             self.render('main.html',
                     frame=True,
                     camera_id=camera_id,
@@ -1090,7 +1110,7 @@ class PictureHandler(BaseHandler):
                     return self.finish_json({'error': 'Failed to download picture from %(url)s: %(msg)s.' % {
                             'url': remote.pretty_camera_url(camera_config), 'msg': error}})
 
-                pretty_filename = os.path.basename(filename) # no camera name available w/o additional request
+                pretty_filename = os.path.basename(filename)  # no camera name available w/o additional request
                 self.set_header('Content-Type', 'image/jpeg')
                 self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';')
                 
@@ -1098,7 +1118,7 @@ class PictureHandler(BaseHandler):
 
             remote.get_media_content(camera_config, filename=filename, media_type='picture', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth()
@@ -1137,7 +1157,7 @@ class PictureHandler(BaseHandler):
                     height=self.get_argument('height', None),
                     callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
     
     @BaseHandler.auth(admin=True)
@@ -1164,7 +1184,7 @@ class PictureHandler(BaseHandler):
 
             remote.del_media_content(camera_config, filename=filename, media_type='picture', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth()
@@ -1200,12 +1220,13 @@ class PictureHandler(BaseHandler):
                     self.set_header('Content-Disposition', response['content_disposition'])
                     self.finish(response['data'])
 
-                remote.get_zipped_content(camera_config, media_type='picture', key=key, group=group, callback=on_response)
+                remote.get_zipped_content(camera_config, media_type='picture', key=key, group=group,
+                                          callback=on_response)
 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 raise HTTPError(400, 'unknown operation')
 
-        else: # prepare
+        else:  # prepare
             logging.debug('preparing zip file for group "%(group)s" of camera %(id)s' % {
                     'group': group or 'ungrouped', 'id': camera_id})
 
@@ -1231,7 +1252,7 @@ class PictureHandler(BaseHandler):
 
                 remote.make_zipped_content(camera_config, media_type='picture', group=group, callback=on_response)
 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth()
@@ -1240,7 +1261,7 @@ class PictureHandler(BaseHandler):
         check = self.get_argument('check', False)
         camera_config = config.get_camera(camera_id)
 
-        if key: # download
+        if key:  # download
             logging.debug('serving timelapse movie for group "%(group)s" of camera %(id)s with key %(key)s' % {
                     'group': group or 'ungrouped', 'id': camera_id, 'key': key})
             
@@ -1262,8 +1283,10 @@ class PictureHandler(BaseHandler):
             elif utils.is_remote_camera(camera_config):
                 def on_response(response=None, error=None):
                     if error:
-                        return self.finish_json({'error': 'Failed to download timelapse movie from %(url)s: %(msg)s.' % {
-                                'url': remote.pretty_camera_url(camera_config), 'msg': error}})
+                        msg = 'Failed to download timelapse movie from %(url)s: %(msg)s.' % {
+                                'url': remote.pretty_camera_url(camera_config), 'msg': error}
+
+                        return self.finish_json({'error': msg})
 
                     self.set_header('Content-Type', response['content_type'])
                     self.set_header('Content-Disposition', response['content_disposition'])
@@ -1271,7 +1294,7 @@ class PictureHandler(BaseHandler):
 
                 remote.get_timelapse_movie(camera_config, key, group=group, callback=on_response)
 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 raise HTTPError(400, 'unknown operation')
 
         elif check:
@@ -1292,8 +1315,10 @@ class PictureHandler(BaseHandler):
             elif utils.is_remote_camera(camera_config):
                 def on_response(response=None, error=None):
                     if error:
-                        return self.finish_json({'error': 'Failed to check timelapse movie progress at %(url)s: %(msg)s.' % {
-                                'url': remote.pretty_camera_url(camera_config), 'msg': error}})
+                        msg = 'Failed to check timelapse movie progress at %(url)s: %(msg)s.' % {
+                                'url': remote.pretty_camera_url(camera_config), 'msg': error}
+
+                        return self.finish_json({'error': msg})
 
                     if response['progress'] == -1 and response.get('key'):
                         self.finish_json({'key': response['key'], 'progress': -1})
@@ -1303,20 +1328,21 @@ class PictureHandler(BaseHandler):
 
                 remote.check_timelapse_movie(camera_config, group=group, callback=on_response)
 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 raise HTTPError(400, 'unknown operation')
 
-        else: # start timelapse
+        else:  # start timelapse
             interval = int(self.get_argument('interval'))
             framerate = int(self.get_argument('framerate'))
 
-            logging.debug('preparing timelapse movie for group "%(group)s" of camera %(id)s with rate %(framerate)s/%(int)s' % {
-                    'group': group or 'ungrouped', 'id': camera_id, 'framerate': framerate, 'int': interval})
+            msg = 'preparing timelapse movie for group "%(group)s" of camera %(id)s with rate %(framerate)s/%(int)s' % {
+                    'group': group or 'ungrouped', 'id': camera_id, 'framerate': framerate, 'int': interval}
+            logging.debug(msg)
 
             if utils.is_local_motion_camera(camera_config):
                 status = mediafiles.check_timelapse_movie()
                 if status['progress'] != -1:
-                    self.finish_json({'progress': status['progress']}) # timelapse already active
+                    self.finish_json({'progress': status['progress']})  # timelapse already active
 
                 else:
                     mediafiles.make_timelapse_movie(camera_config, framerate, interval, group=group)
@@ -1329,7 +1355,7 @@ class PictureHandler(BaseHandler):
                                 'url': remote.pretty_camera_url(camera_config), 'msg': error}})
                     
                     if response['progress'] != -1:
-                        return self.finish_json({'progress': response['progress']}) # timelapse already active
+                        return self.finish_json({'progress': response['progress']})  # timelapse already active
     
                     def on_make(response=None, error=None):
                         if error:
@@ -1342,7 +1368,7 @@ class PictureHandler(BaseHandler):
 
                 remote.check_timelapse_movie(camera_config, group=group, callback=on_status)
 
-            else: # assuming simple mjpeg camera
+            else:  # assuming simple mjpeg camera
                 raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth(admin=True)
@@ -1369,7 +1395,7 @@ class PictureHandler(BaseHandler):
 
             remote.del_media_group(camera_config, group=group, media_type='picture', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     def try_finish(self, content):
@@ -1402,7 +1428,7 @@ class MovieHandler(BaseHandler):
     
     @asynchronous
     def post(self, camera_id, op, filename=None, group=None):
-        if group == '/': # ungrouped
+        if group == '/':  # ungrouped
             group = ''
 
         if camera_id is not None:
@@ -1445,9 +1471,10 @@ class MovieHandler(BaseHandler):
 
                 self.finish_json(remote_list)
             
-            remote.list_media(camera_config, media_type='movie', prefix=self.get_argument('prefix', None), callback=on_response)
+            remote.list_media(camera_config, media_type='movie', prefix=self.get_argument('prefix', None),
+                              callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth()
@@ -1471,7 +1498,7 @@ class MovieHandler(BaseHandler):
                     return self.finish_json({'error': 'Failed to download movie from %(url)s: %(msg)s.' % {
                             'url': remote.pretty_camera_url(camera_config), 'msg': error}})
 
-                pretty_filename = os.path.basename(filename) # no camera name available w/o additional request
+                pretty_filename = os.path.basename(filename)  # no camera name available w/o additional request
                 self.set_header('Content-Type', 'video/mpeg')
                 self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';')
                 
@@ -1479,7 +1506,7 @@ class MovieHandler(BaseHandler):
 
             remote.get_media_content(camera_config, filename=filename, media_type='movie', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth()
@@ -1518,7 +1545,7 @@ class MovieHandler(BaseHandler):
                     height=self.get_argument('height', None),
                     callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth(admin=True)
@@ -1545,7 +1572,7 @@ class MovieHandler(BaseHandler):
 
             remote.del_media_content(camera_config, filename=filename, media_type='movie', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
     @BaseHandler.auth(admin=True)
@@ -1572,7 +1599,7 @@ class MovieHandler(BaseHandler):
 
             remote.del_media_group(camera_config, group=group, media_type='movie', callback=on_response)
 
-        else: # assuming simple mjpeg camera
+        else:  # assuming simple mjpeg camera
             raise HTTPError(400, 'unknown operation')
 
 
@@ -1587,8 +1614,10 @@ class ActionHandler(BaseHandler):
         if utils.is_remote_camera(local_config):
             def on_response(error=None):
                 if error:
-                    return self.finish_json({'error': 'Failed to execute action on remote camera at %(url)s: %(msg)s.' % {
-                            'url': remote.pretty_camera_url(local_config), 'msg': error}})
+                    msg = 'Failed to execute action on remote camera at %(url)s: %(msg)s.' % {
+                            'url': remote.pretty_camera_url(local_config), 'msg': error}
+
+                    return self.finish_json({'error': msg})
 
                 self.finish_json()
 
@@ -1682,7 +1711,7 @@ class RelayEventHandler(BaseHandler):
             return self.finish_json()
 
         else:
-            logging.debug('recevied relayed event %(event)s for thread id %(id)s (camera id %(cid)s)' % {
+            logging.debug('received relayed event %(event)s for thread id %(id)s (camera id %(cid)s)' % {
                     'event': event, 'id': thread_id, 'cid': camera_id})
         
         camera_config = config.get_camera(camera_id)
@@ -1748,13 +1777,13 @@ class LogHandler(BaseHandler):
         self.set_header('Content-Type', 'text/plain')
         self.set_header('Content-Disposition', 'attachment; filename=' + filename + ';')
 
-        if path.startswith('/'): # an actual path        
+        if path.startswith('/'):  # an actual path
             logging.debug('serving log file "%s" from "%s"' % (filename, path))
 
             with open(path) as f:
                 self.finish(f.read())
                 
-        else: # a command to execute 
+        else:  # a command to execute
             logging.debug('serving log file "%s" from command "%s"' % (filename, path))
 
             try:
index 680cdd9fa5592a8881046782fd3f293927a95e53..fc7afb62291327abf2ec7539794036b366b2083a 100644 (file)
@@ -101,14 +101,14 @@ def findfiles(path):
     return files
 
 
-def _list_media_files(dir, exts, prefix=None):
+def _list_media_files(directory, exts, prefix=None):
     media_files = []
     
     if prefix is not None:
         if prefix == 'ungrouped':
             prefix = ''
         
-        root = os.path.join(dir, prefix)
+        root = os.path.join(directory, prefix)
         for name in os.listdir(root):
             # ignore hidden files/dirs and other unwanted files
             if name.startswith('.') or name == 'lastsnap.jpg':
@@ -122,7 +122,7 @@ def _list_media_files(dir, exts, prefix=None):
                 logging.error('stat failed: ' + unicode(e))
                 continue
                 
-            if not stat.S_ISREG(st.st_mode): # not a regular file
+            if not stat.S_ISREG(st.st_mode):  # not a regular file
                 continue
 
             full_path_lower = full_path.lower()
@@ -132,7 +132,7 @@ def _list_media_files(dir, exts, prefix=None):
             media_files.append((full_path, st))
 
     else:
-        for full_path, name, st in findfiles(dir):
+        for full_path, name, st in findfiles(directory):
             full_path_lower = full_path.lower()
             if not [e for e in exts if full_path_lower.endswith(e)]:
                 continue
@@ -142,8 +142,8 @@ def _list_media_files(dir, exts, prefix=None):
     return media_files
 
 
-def _remove_older_files(dir, moment, exts):
-    for (full_path, st) in _list_media_files(dir, exts):
+def _remove_older_files(directory, moment, exts):
+    for (full_path, st) in _list_media_files(directory, exts):
         file_moment = datetime.datetime.fromtimestamp(st.st_mtime)
         if file_moment < moment:
             logging.debug('removing file %(path)s...' % {'path': full_path})
@@ -154,7 +154,7 @@ def _remove_older_files(dir, moment, exts):
             
             except OSError as e:
                 if e.errno == errno.ENOENT:
-                    pass # the file might have been removed in the meantime
+                    pass  # the file might have been removed in the meantime
                 
                 else:
                     logging.error('failed to remove %s: %s' % (full_path, e))
@@ -167,7 +167,7 @@ def _remove_older_files(dir, moment, exts):
             listing = os.listdir(dir_path)
             thumbs = [l for l in listing if l.endswith('.thumb')]
             
-            if len(listing) == len(thumbs): # only thumbs
+            if len(listing) == len(thumbs):  # only thumbs
                 for p in thumbs:
                     try:
                         os.remove(os.path.join(dir_path, p))
@@ -190,7 +190,7 @@ def find_ffmpeg():
     try:
         return subprocess.check_output(['which', 'ffmpeg'], stderr=utils.DEV_NULL).strip()
     
-    except subprocess.CalledProcessError: # not found
+    except subprocess.CalledProcessError:  # not found
         return None
 
 
@@ -200,9 +200,9 @@ def cleanup_media(media_type):
     if media_type == 'picture':
         exts = _PICTURE_EXTS
         
-    elif media_type == 'movie':
+    else:  # media_type == 'movie'
         exts = _MOVIE_EXTS + ['.thumb']
-        
+
     for camera_id in config.get_camera_ids():
         camera_config = config.get_camera(camera_id)
         if not utils.is_local_motion_camera(camera_config):
@@ -210,7 +210,7 @@ def cleanup_media(media_type):
         
         preserve_media = camera_config.get('@preserve_%(media_type)ss' % {'media_type': media_type}, 0)
         if preserve_media == 0:
-            continue # preserve forever
+            continue  # preserve forever
         
         still_images_enabled = bool(
                 ((camera_config['emulate_motion'] or camera_config['output_pictures']) and camera_config['picture_filename']) or
@@ -219,10 +219,10 @@ def cleanup_media(media_type):
         movies_enabled = camera_config['ffmpeg_output_movies']
 
         if media_type == 'picture' and not still_images_enabled:
-            continue # only cleanup pictures for cameras with still images enabled
+            continue  # only cleanup pictures for cameras with still images enabled
         
         elif media_type == 'movie' and not movies_enabled:
-            continue # only cleanup movies for cameras with movies enabled
+            continue  # only cleanup movies for cameras with movies enabled
 
         preserve_moment = datetime.datetime.now() - datetime.timedelta(days=preserve_media)
 
@@ -348,24 +348,24 @@ def list_media(camera_config, media_type, callback, prefix=None):
     
     def poll_process():
         io_loop = IOLoop.instance()
-        if process.is_alive(): # not finished yet
+        if process.is_alive():  # not finished yet
             now = datetime.datetime.now()
             delta = now - started
             if delta.seconds < settings.LIST_MEDIA_TIMEOUT:
                 io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)
                 read_media_list()
             
-            else: # process did not finish in time
+            else:  # process did not finish in time
                 logging.error('timeout waiting for the media listing process to finish')
                 try:
                     os.kill(process.pid, signal.SIGTERM)
                 
                 except:
-                    pass # nevermind
+                    pass  # nevermind
                     
                 callback(None)
 
-        else: # finished
+        else:  # finished
             read_media_list()
             logging.debug('media listing process has returned %(count)s files' % {'count': len(media_list)})
             callback(media_list)
@@ -463,17 +463,17 @@ def get_zipped_content(camera_config, media_type, group, callback):
             if delta.seconds < settings.ZIP_TIMEOUT:
                 io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)
 
-            else: # process did not finish in time
+            else:  # process did not finish in time
                 logging.error('timeout waiting for the zip process to finish')
                 try:
                     os.kill(process.pid, signal.SIGTERM)
                 
                 except:
-                    pass # nevermind
+                    pass  # nevermind
 
                 callback(None)
 
-        else: # finished
+        else:  # finished
             try:
                 data = parent_pipe.recv()
                 logging.debug('zip process has returned %d bytes' % len(data))
@@ -494,7 +494,7 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
     codec = camera_config.get('ffmpeg_video_codec')
     
     codec = FFMPEG_CODEC_MAPPING.get(codec, codec)
-    format = FFMPEG_FORMAT_MAPPING.get(codec, codec)
+    fmt = FFMPEG_FORMAT_MAPPING.get(codec, codec)
 
     # create a subprocess to retrieve media files
     def do_list_media(pipe):
@@ -528,24 +528,24 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
         
     def poll_media_list_process():
         io_loop = IOLoop.instance()
-        if _timelapse_process.is_alive(): # not finished yet
+        if _timelapse_process.is_alive():  # not finished yet
             now = datetime.datetime.now()
             delta = now - started[0]
-            if delta.seconds < settings.TIMELAPSE_TIMEOUT: # the subprocess has limited time to complete its job
+            if delta.seconds < settings.TIMELAPSE_TIMEOUT:  # the subprocess has limited time to complete its job
                 io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_media_list_process)
                 read_media_list()
 
-            else: # process did not finish in time
+            else:  # process did not finish in time
                 logging.error('timeout waiting for the media listing process to finish')
                 try:
                     os.kill(_timelapse_process.pid, signal.SIGTERM)
                 
                 except:
-                    pass # nevermind
+                    pass  # nevermind
 
                 _timelapse_process.progress = -1
 
-        else: # finished
+        else:  # finished
             read_media_list()
             logging.debug('media listing process has returned %(count)s files' % {'count': len(media_list)})
             
@@ -572,11 +572,11 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
 
         selected = []
         for i in xrange(max_idx + 1):
-            slice = slices.get(i)
-            if not slice:
+            s = slices.get(i)
+            if not s:
                 continue
 
-            selected.append(min(slice, key=lambda m: m['delta']))
+            selected.append(min(s, key=lambda m: m['delta']))
 
         logging.debug('selected %d/%d media files' % (len(selected), len(media_list)))
         
@@ -585,8 +585,9 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
     def make_movie(pictures):
         global _timelapse_process
 
-        cmd =  'rm -f %(tmp_filename)s;'
-        cmd += 'cat %(jpegs)s | ffmpeg -framerate %(framerate)s -f image2pipe -vcodec mjpeg -i - -vcodec %(codec)s -format %(format)s -b:v %(bitrate)s -qscale:v 0.1 -f avi %(tmp_filename)s'
+        cmd = 'rm -f %(tmp_filename)s;'
+        cmd += 'cat %(jpegs)s | ffmpeg -framerate %(framerate)s -f image2pipe -vcodec mjpeg -i - -vcodec %(codec)s ' \
+               '-format %(format)s -b:v %(bitrate)s -qscale:v 0.1 -f avi %(tmp_filename)s'
 
         bitrate = 9999999
 
@@ -595,14 +596,14 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
             'jpegs': ' '.join((('"' + p['path'] + '"') for p in pictures)),
             'framerate': framerate,
             'codec': codec,
-            'format': format,
+            'format': fmt,
             'bitrate': bitrate
         }
         
         logging.debug('executing "%s"' % cmd)
 
         _timelapse_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
-        _timelapse_process.progress = 0.01 # 1%
+        _timelapse_process.progress = 0.01  # 1%
         
         # make subprocess stdout pipe non-blocking
         fd = _timelapse_process.stdout.fileno()
@@ -616,7 +617,7 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
         global _timelapse_data
         
         io_loop = IOLoop.instance()
-        if _timelapse_process.poll() is None: # not finished yet
+        if _timelapse_process.poll() is None:  # not finished yet
             io_loop.add_timeout(datetime.timedelta(seconds=0.5), functools.partial(poll_movie_process, pictures))
 
             try:
@@ -640,7 +641,7 @@ def make_timelapse_movie(camera_config, framerate, interval, group):
             
             logging.debug('timelapse progress: %s' % int(100 * _timelapse_process.progress))
 
-        else: # finished
+        else:  # finished
             exit_code = _timelapse_process.poll()
             _timelapse_process = None
             
@@ -761,7 +762,7 @@ def del_media_content(camera_config, path, media_type):
         listing = os.listdir(dir_path)
         thumbs = [l for l in listing if l.endswith('.thumb')]
         
-        if len(listing) == len(thumbs): # only thumbs
+        if len(listing) == len(thumbs):  # only thumbs
             for p in thumbs:
                 os.remove(os.path.join(dir_path, p))
 
@@ -780,7 +781,7 @@ def del_media_group(camera_config, group, media_type):
     if media_type == 'picture':
         exts = _PICTURE_EXTS
         
-    elif media_type == 'movie':
+    else:  # media_type == 'movie'
         exts = _MOVIE_EXTS
         
     target_dir = camera_config.get('target_dir')
@@ -804,7 +805,7 @@ def del_media_group(camera_config, group, media_type):
     listing = os.listdir(full_path)
     thumbs = [l for l in listing if l.endswith('.thumb')]
 
-    if len(listing) == len(thumbs): # only thumbs
+    if len(listing) == len(thumbs):  # only thumbs
         for p in thumbs:
             os.remove(os.path.join(full_path, p))
 
@@ -822,14 +823,14 @@ def get_current_picture(camera_config, width, height):
         return None
     
     if width is height is None:
-        return jpg # no server-side resize needed
+        return jpg  # no server-side resize needed
 
     sio = StringIO.StringIO(jpg)
     image = Image.open(sio)
     
-    if width and width < 1: # given as percent
+    if width and width < 1:  # given as percent
         width = int(width * image.size[0])
-    if height and height < 1: # given as percent
+    if height and height < 1:  # given as percent
         height = int(height * image.size[1])
 
     width = width and int(width) or image.size[0]
@@ -843,7 +844,7 @@ def get_current_picture(camera_config, width, height):
     height = min(max_height, height)
     
     if width >= image.size[0] and height >= image.size[1]:
-        return jpg # no enlarging of the picture on the server side
+        return jpg  # no enlarging of the picture on the server side
     
     image.thumbnail((width, height), Image.CUBIC)
 
@@ -869,7 +870,7 @@ def set_prepared_cache(data):
         if _prepared_files.pop(key, None) is not None:
             logging.warn('key "%s" was still present in the prepared cache, removed' % key)
 
-    timeout = 3600 # the user has 1 hour to download the file after creation
+    timeout = 3600  # the user has 1 hour to download the file after creation
     
     io_loop = IOLoop.instance()
     io_loop.add_timeout(datetime.timedelta(seconds=timeout), clear)
index 22838b59f70c3736deb9560a9be1a6ca20c7fd8d..64a445a1fa9cc850eef7b71774e5f13d75bd34bf 100755 (executable)
@@ -35,12 +35,12 @@ def find_command(command):
     if command == 'relayevent':
         relayevent_sh = os.path.join(os.path.dirname(__file__), 'scripts/relayevent.sh')
         
-        cmd = relayevent_sh + ' "%s"' % (settings._config_file or '')
+        cmd = relayevent_sh + ' "%s"' % (settings.config_file or '')
 
     else:
         cmd = __file__
         cmd = sys.executable + ' ' + cmd
-        cmd = cmd.replace('-b', '') # remove server-specific options
+        cmd = cmd.replace('-b', '')  # remove server-specific options
         cmd += ' %s ' % command
         cmd += ' '.join([pipes.quote(arg) for arg in sys.argv[2:]
                 if arg not in ['-b']])
@@ -134,7 +134,7 @@ def load_settings():
         # use the config file directory as base dir
         # if not specified otherwise in the config file
         base_dir = os.path.dirname(config_file)
-        settings._config_file = config_file
+        settings.config_file = config_file
 
         if not conf_path_given[0]:
             settings.CONF_PATH = base_dir
@@ -157,10 +157,10 @@ def load_settings():
 
 def configure_logging(cmd, log_to_file=False):
     if log_to_file or cmd != 'motioneye':
-        format = '%(asctime)s: [{cmd}] %(levelname)8s: %(message)s'.format(cmd=cmd)
+        fmt = '%(asctime)s: [{cmd}] %(levelname)8s: %(message)s'.format(cmd=cmd)
         
     else:
-        format = '%(levelname)8s: %(message)s'.format(cmd=cmd)
+        fmt = '%(levelname)8s: %(message)s'.format(cmd=cmd)
 
     for h in logging.getLogger().handlers:
         logging.getLogger().removeHandler(h)
@@ -173,7 +173,7 @@ def configure_logging(cmd, log_to_file=False):
             log_file = None
 
         logging.basicConfig(filename=log_file, level=settings.LOG_LEVEL,
-                format=format, datefmt='%Y-%m-%d %H:%M:%S')
+                format=fmt, datefmt='%Y-%m-%d %H:%M:%S')
     
     except Exception as e:
         sys.stderr.write('failed to configure logging: %s\n' % e)
index dc9c65602ee841271d62daa2e34b54bb950320ba..f3fc8b0b42dc0bcce34242b5658dd3646d3a7b06 100644 (file)
@@ -34,8 +34,8 @@ import utils
 class MjpgClient(IOStream):
     _FPS_LEN = 4
     
-    clients = {} # dictionary of clients indexed by camera id
-    _last_erroneous_close_time = 0 # helps detecting erroneous connections and restart motion
+    clients = {}  # dictionary of clients indexed by camera id
+    _last_erroneous_close_time = 0  # helps detecting erroneous connections and restart motion
 
     def __init__(self, camera_id, port, username, password, auth_mode):
         self._camera_id = camera_id
@@ -45,7 +45,7 @@ class MjpgClient(IOStream):
         self._auth_mode = auth_mode
         self._auth_digest_state = {}
         
-        self._last_access = None
+        self._last_access = 0
         self._last_jpg = None
         self._last_jpg_times = []
         
@@ -54,8 +54,11 @@ class MjpgClient(IOStream):
         
         self.set_close_callback(self.on_close)
         
-    def connect(self):
+    def do_connect(self):
         IOStream.connect(self, ('localhost', self._port), self._on_connect)
+
+    def get_port(self):
+        return self._port
     
     def on_close(self):
         logging.debug('connection closed for mjpg client for camera %(camera_id)s on port %(port)s' % {
@@ -68,11 +71,13 @@ class MjpgClient(IOStream):
         if getattr(self, 'error', None) and self.error.errno != errno.ECONNREFUSED:
             now = time.time()
             if now - MjpgClient._last_erroneous_close_time < settings.MJPG_CLIENT_TIMEOUT:
-                logging.error('connection problem detected for mjpg client for camera %(camera_id)s on port %(port)s' % {
-                        'port': self._port, 'camera_id': self._camera_id})
+                msg = 'connection problem detected for mjpg client for camera %(camera_id)s on port %(port)s' % {
+                        'port': self._port, 'camera_id': self._camera_id}
+
+                logging.error(msg)
                 
                 if settings.MOTION_RESTART_ON_ERRORS:
-                    motionctl.stop(invalidate=True) # this will close all the mjpg clients
+                    motionctl.stop(invalidate=True)  # this will close all the mjpg clients
                     motionctl.start(deferred=True)
 
             MjpgClient._last_erroneous_close_time = now
@@ -80,7 +85,16 @@ class MjpgClient(IOStream):
     def get_last_jpg(self):
         self._last_access = time.time()
         return self._last_jpg
-    
+
+    def get_last_access(self):
+        return self._last_access
+
+    def get_last_jpg_time(self):
+        if not self._last_jpg_times:
+            self._last_jpg_times.append(time.time())
+
+        return self._last_jpg_times[-1]
+
     def get_fps(self):
         if len(self._last_jpg_times) < self._FPS_LEN:
             return 0  # not enough "samples"
@@ -100,7 +114,7 @@ class MjpgClient(IOStream):
             return True
             
         error = getattr(self, 'error', None)
-        if (error is None) or (getattr(error, 'errno', None) == 0): # error could also be ESUCCESS for some reason
+        if (error is None) or (getattr(error, 'errno', None) == 0):  # error could also be ESUCCESS for some reason
             return False
         
         self._error(error)
@@ -127,7 +141,7 @@ class MjpgClient(IOStream):
             auth_header = utils.build_basic_header(self._username, self._password)
             self.write('GET / HTTP/1.0\r\n\r\nAuthorization: %s\r\n\r\n' % auth_header)
             
-        else: # in digest auth mode, the header is built upon receiving 401
+        else:  # in digest auth mode, the header is built upon receiving 401
             self.write('GET / HTTP/1.0\r\n\r\n')
 
         self._seek_http()
@@ -142,7 +156,7 @@ class MjpgClient(IOStream):
         if data.endswith('401 '):
             self._seek_www_authenticate()
 
-        else: # no authorization required, skip to content length
+        else:  # no authorization required, skip to content length
             self._seek_content_length()
 
     def _seek_www_authenticate(self):
@@ -252,7 +266,7 @@ def get_jpg(camera_id):
             auth_mode = 'digest' if camera_config.get('stream_auth_method') > 1 else 'basic'
 
         client = MjpgClient(camera_id, port, username, password, auth_mode)
-        client.connect()
+        client.do_connect()
         
         MjpgClient.clients[camera_id] = client
 
@@ -284,37 +298,33 @@ def _garbage_collector():
 
     now = time.time()
     for camera_id, client in MjpgClient.clients.items():
-        port = client._port
-        
-        # check for jpeg frame timeout
-        if not client._last_jpg_times:
-            client._last_jpg_times.append(now)
-        
-        last_jpg_time = client._last_jpg_times[-1]
+        port = client.get_port()
 
         if client.closed():
             continue
 
+        # check for jpeg frame timeout
+        last_jpg_time = client.get_last_jpg_time()
         delta = now - last_jpg_time
         if delta > settings.MJPG_CLIENT_TIMEOUT:
             logging.error('mjpg client timed out receiving data for camera %(camera_id)s on port %(port)s' % {
                     'camera_id': camera_id, 'port': port})
             
             if settings.MOTION_RESTART_ON_ERRORS:
-                motionctl.stop(invalidate=True) # this will close all the mjpg clients
+                motionctl.stop(invalidate=True)  # this will close all the mjpg clients
                 motionctl.start(deferred=True)
             
             break
 
         # check for last access timeout
-        if client._last_access is None:
-            continue
-
-        delta = now - client._last_access
+        delta = now - client.get_last_access()
         if settings.MJPG_CLIENT_IDLE_TIMEOUT and delta > settings.MJPG_CLIENT_IDLE_TIMEOUT:
-            logging.debug('mjpg client for camera %(camera_id)s on port %(port)s has been idle for %(timeout)s seconds, removing it' % {
+            msg = ('mjpg client for camera %(camera_id)s on port %(port)s has been idle '
+                   'for %(timeout)s seconds, removing it' % {
                     'camera_id': camera_id, 'port': port, 'timeout': settings.MJPG_CLIENT_IDLE_TIMEOUT})
 
+            logging.debug(msg)
+
             client.close()
 
             continue
index a3da581ad46456292ae0fbc35486ddc9b7fd43a3..6cb873886611f3631dca5fdc40ed9b862106de46 100644 (file)
@@ -23,29 +23,27 @@ import urllib
 import config
 
 
-DEFAULT_INTERVAL = 1 # seconds
+DEFAULT_INTERVAL = 1  # seconds
 
-_monior_info_cache_by_camera_id = {}
+_monitor_info_cache_by_camera_id = {}
 _last_call_time_by_camera_id = {}
 _interval_by_camera_id = {}
 
 
 def get_monitor_info(camera_id):
-    global _command_cache_time
-
     now = time.time()
     command = config.get_monitor_command(camera_id)
     if command is None:
         return ''
 
-    monitor_info = _monior_info_cache_by_camera_id.get(camera_id)
+    monitor_info = _monitor_info_cache_by_camera_id.get(camera_id)
     last_call_time = _last_call_time_by_camera_id.get(camera_id, 0)
     interval = _interval_by_camera_id.get(camera_id, DEFAULT_INTERVAL)
     if monitor_info is None or now - last_call_time > interval:
         monitor_info, interval = _exec_monitor_command(command)
         monitor_info = urllib.quote(monitor_info, safe='')
         _interval_by_camera_id[camera_id] = interval
-        _monior_info_cache_by_camera_id[camera_id] = monitor_info
+        _monitor_info_cache_by_camera_id[camera_id] = monitor_info
         _last_call_time_by_camera_id[camera_id] = now
 
     return monitor_info 
index 832ed38bb19eda55924e7fa8b6745c3ae799be1e..cc4611bbb1fcb81a6abca678d10d8e02aab4d17f 100644 (file)
@@ -52,17 +52,17 @@ def find_motion():
         else:
             return None, None
 
-    else: # autodetect motion binary path
+    else:  # autodetect motion binary path
         try:
             binary = subprocess.check_output(['which', 'motion'], stderr=utils.DEV_NULL).strip()
         
-        except subprocess.CalledProcessError: # not found
+        except subprocess.CalledProcessError:  # not found
             return None, None
 
     try:
         help = subprocess.check_output(binary + ' -h || true', shell=True)
     
-    except subprocess.CalledProcessError: # not found
+    except subprocess.CalledProcessError:  # not found
         return None, None
     
     result = re.findall('motion Version ([^,]+)', help, re.IGNORECASE)
@@ -105,11 +105,8 @@ def start(deferred=False):
     motion_log_path = os.path.join(settings.LOG_PATH, 'motion.log')
     motion_pid_path = os.path.join(settings.RUN_PATH, 'motion.pid')
     
-    args = [program,
-            '-n',
-            '-c', motion_config_path]
-    
-    args.append('-d')
+    args = [program, '-n', '-c', motion_config_path, '-d']
+
     if settings.LOG_LEVEL <= logging.DEBUG:
         args.append('9')
     
@@ -119,7 +116,7 @@ def start(deferred=False):
     elif settings.LOG_LEVEL <= logging.ERROR:
         args.append('4')
     
-    else: # fatat, quiet
+    else:  # fatal, quiet
         args.append('1')
 
     log_file = open(motion_log_path, 'w')
@@ -331,14 +328,14 @@ def has_old_config_format():
     if not binary:
         return False
 
-    if version.startswith('trunkREV'): # e.g. "trunkREV599"
+    if version.startswith('trunkREV'):  # e.g. "trunkREV599"
         version = int(version[8:])
         return version <= _LAST_OLD_CONFIG_VERSIONS[0]
 
-    elif version.lower().count('git'): # e.g. "Unofficial-Git-a5b5f13" or "3.2.12+git20150927mrdave"
-        return False # all git versions are assumed to be new
+    elif version.lower().count('git'):  # e.g. "Unofficial-Git-a5b5f13" or "3.2.12+git20150927mrdave"
+        return False  # all git versions are assumed to be new
 
-    else: # stable release, should have the format "x.y.z"
+    else:  # stable release, should have the format "x.y.z"
         return update.compare_versions(version, _LAST_OLD_CONFIG_VERSIONS[1]) <= 0
 
 
@@ -359,15 +356,15 @@ def get_rtsp_support():
     if not binary:
         return []
 
-    if version.startswith('trunkREV'): # e.g. trunkREV599
+    if version.startswith('trunkREV'):  # e.g. trunkREV599
         version = int(version[8:])
         if version > _LAST_OLD_CONFIG_VERSIONS[0]:
             return ['tcp']
 
     elif version.lower().count('git') or update.compare_versions(version, '3.4') >= 0:
-        return ['tcp', 'udp'] # all git versions are assumed to support both transport protocols
+        return ['tcp', 'udp']  # all git versions are assumed to support both transport protocols
     
-    else: # stable release, should be in the format x.y.z
+    else:  # stable release, should be in the format x.y.z
         return []
 
 
diff --git a/motioneye/ordereddict.py b/motioneye/ordereddict.py
deleted file mode 100644 (file)
index 0874135..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
-# Passes Python2.7's test suite and incorporates all the latest updates.
-
-try:
-    from thread import get_ident as _get_ident
-except ImportError:
-    from dummy_thread import get_ident as _get_ident
-
-try:
-    from _abcoll import KeysView, ValuesView, ItemsView
-except ImportError:
-    pass
-
-
-class OrderedDict(dict):
-    'Dictionary that remembers insertion order'
-    # An inherited dict maps keys to values.
-    # The inherited dict provides __getitem__, __len__, __contains__, and get.
-    # The remaining methods are order-aware.
-    # Big-O running times for all methods are the same as for regular dictionaries.
-
-    # The internal self.__map dictionary maps keys to links in a doubly linked list.
-    # The circular doubly linked list starts and ends with a sentinel element.
-    # The sentinel element never gets deleted (this simplifies the algorithm).
-    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
-
-    def __init__(self, *args, **kwds):
-        '''Initialize an ordered dictionary.  Signature is the same as for
-        regular dictionaries, but keyword arguments are not recommended
-        because their insertion order is arbitrary.
-
-        '''
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__root
-        except AttributeError:
-            self.__root = root = []                     # sentinel node
-            root[:] = [root, root, None]
-            self.__map = {}
-        self.__update(*args, **kwds)
-
-    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
-        'od.__setitem__(i, y) <==> od[i]=y'
-        # Setting a new item creates a new link which goes at the end of the linked
-        # list, and the inherited dictionary is updated with the new key/value pair.
-        if key not in self:
-            root = self.__root
-            last = root[0]
-            last[1] = root[0] = self.__map[key] = [last, root, key]
-        dict_setitem(self, key, value)
-
-    def __delitem__(self, key, dict_delitem=dict.__delitem__):
-        'od.__delitem__(y) <==> del od[y]'
-        # Deleting an existing item uses self.__map to find the link which is
-        # then removed by updating the links in the predecessor and successor nodes.
-        dict_delitem(self, key)
-        link_prev, link_next, key = self.__map.pop(key)
-        link_prev[1] = link_next
-        link_next[0] = link_prev
-
-    def __iter__(self):
-        'od.__iter__() <==> iter(od)'
-        root = self.__root
-        curr = root[1]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[1]
-
-    def __reversed__(self):
-        'od.__reversed__() <==> reversed(od)'
-        root = self.__root
-        curr = root[0]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[0]
-
-    def clear(self):
-        'od.clear() -> None.  Remove all items from od.'
-        try:
-            for node in self.__map.itervalues():
-                del node[:]
-            root = self.__root
-            root[:] = [root, root, None]
-            self.__map.clear()
-        except AttributeError:
-            pass
-        dict.clear(self)
-
-    def popitem(self, last=True):
-        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
-        Pairs are returned in LIFO order if last is true or FIFO order if false.
-
-        '''
-        if not self:
-            raise KeyError('dictionary is empty')
-        root = self.__root
-        if last:
-            link = root[0]
-            link_prev = link[0]
-            link_prev[1] = root
-            root[0] = link_prev
-        else:
-            link = root[1]
-            link_next = link[1]
-            root[1] = link_next
-            link_next[0] = root
-        key = link[2]
-        del self.__map[key]
-        value = dict.pop(self, key)
-        return key, value
-
-    # -- the following methods do not depend on the internal structure --
-
-    def keys(self):
-        'od.keys() -> list of keys in od'
-        return list(self)
-
-    def values(self):
-        'od.values() -> list of values in od'
-        return [self[key] for key in self]
-
-    def items(self):
-        'od.items() -> list of (key, value) pairs in od'
-        return [(key, self[key]) for key in self]
-
-    def iterkeys(self):
-        'od.iterkeys() -> an iterator over the keys in od'
-        return iter(self)
-
-    def itervalues(self):
-        'od.itervalues -> an iterator over the values in od'
-        for k in self:
-            yield self[k]
-
-    def iteritems(self):
-        'od.iteritems -> an iterator over the (key, value) items in od'
-        for k in self:
-            yield (k, self[k])
-
-    def update(*args, **kwds): #@NoSelf
-        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
-
-        If E is a dict instance, does:           for k in E: od[k] = E[k]
-        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
-        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
-        In either case, this is followed by:     for k, v in F.items(): od[k] = v
-
-        '''
-        if len(args) > 2:
-            raise TypeError('update() takes at most 2 positional '
-                            'arguments (%d given)' % (len(args),))
-        elif not args:
-            raise TypeError('update() takes at least 1 argument (0 given)')
-        self = args[0]
-        # Make progressively weaker assumptions about "other"
-        other = ()
-        if len(args) == 2:
-            other = args[1]
-        if isinstance(other, dict):
-            for key in other:
-                self[key] = other[key]
-        elif hasattr(other, 'keys'):
-            for key in other.keys():
-                self[key] = other[key]
-        else:
-            for key, value in other:
-                self[key] = value
-        for key, value in kwds.items():
-            self[key] = value
-
-    __update = update  # let subclasses override update without breaking __init__
-
-    __marker = object()
-
-    def pop(self, key, default=__marker):
-        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-        If key is not found, d is returned if given, otherwise KeyError is raised.
-
-        '''
-        if key in self:
-            result = self[key]
-            del self[key]
-            return result
-        if default is self.__marker:
-            raise KeyError(key)
-        return default
-
-    def setdefault(self, key, default=None):
-        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
-        if key in self:
-            return self[key]
-        self[key] = default
-        return default
-
-    def __repr__(self, _repr_running={}):
-        'od.__repr__() <==> repr(od)'
-        call_key = id(self), _get_ident()
-        if call_key in _repr_running:
-            return '...'
-        _repr_running[call_key] = 1
-        try:
-            if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
-        finally:
-            del _repr_running[call_key]
-
-    def __reduce__(self):
-        'Return state information for pickling'
-        items = [[k, self[k]] for k in self]
-        inst_dict = vars(self).copy()
-        for k in vars(OrderedDict()):
-            inst_dict.pop(k, None)
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def copy(self):
-        'od.copy() -> a shallow copy of od'
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
-        and values equal to v (which defaults to None).
-
-        '''
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
-        while comparison to a regular mapping is order-insensitive.
-
-        '''
-        if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
-
-    # -- the following methods are only used in Python 2.7 --
-
-    def viewkeys(self):
-        "od.viewkeys() -> a set-like object providing a view on od's keys"
-        return KeysView(self)
-
-    def viewvalues(self):
-        "od.viewvalues() -> an object providing a view on od's values"
-        return ValuesView(self)
-
-    def viewitems(self):
-        "od.viewitems() -> a set-like object providing a view on od's items"
-        return ItemsView(self)
index 4171fbd8ce2f0e035d600cb4960fc85ce6356a7c..2c9149e06df896a48ab7062d71b8c6c67c7e5154 100644 (file)
@@ -25,7 +25,7 @@ def _find_prog(prog):
     try:
         return subprocess.check_output(['which', prog], stderr=utils.DEV_NULL).strip()
     
-    except subprocess.CalledProcessError: # not found
+    except subprocess.CalledProcessError:  # not found
         return None
 
 
index 0b3a8c1090ef6cae58ddb5be2e30a395da21ee98..386dc6621a39dd3efbcdf28f508d8571a43766ad 100644 (file)
@@ -45,7 +45,7 @@ def _load():
         logging.debug('loading preferences from "%s"...' % file_path)
     
         try:
-            file = open(file_path, 'r')
+            f = open(file_path, 'r')
         
         except Exception as e:
             logging.error('could not open preferences file "%s": %s' % (file_path, e))
@@ -53,13 +53,13 @@ def _load():
             return
         
         try:
-            _prefs = json.load(file)
+            _prefs = json.load(f)
 
         except Exception as e:
-            logging.error('could not read preferences from file "%s": %s'(file_path, e))
+            logging.error('could not read preferences from file "%s": %s' % (file_path, e))
 
         finally:
-            file.close()
+            f.close()
             
     else:
         logging.debug('preferences file "%s" does not exist, using default preferences' % file_path)
@@ -71,7 +71,7 @@ def _save():
     logging.debug('saving preferences to "%s"...' % file_path)
 
     try:
-        file = open(file_path, 'w')
+        f = open(file_path, 'w')
 
     except Exception as e:
         logging.error('could not open preferences file "%s": %s' % (file_path, e))
@@ -79,13 +79,13 @@ def _save():
         return
 
     try:
-        json.dump(_prefs, file, sort_keys=True, indent=4)
+        json.dump(_prefs, f, sort_keys=True, indent=4)
 
     except Exception as e:
-        logging.error('could not save preferences to file "%s": %s'(file_path, e))
+        logging.error('could not save preferences to file "%s": %s' % (file_path, e))
 
     finally:
-        file.close()
+        f.close()
 
 
 def get(username, key=None):
index 8e6e45589949c22cace87e3a000ac881072b92ee..b5cb9970ff4809c89757c0dd5e7aa23b5e624b28 100644 (file)
@@ -28,7 +28,9 @@ import utils
 _DOUBLE_SLASH_REGEX = re.compile('//+')
 
 
-def _make_request(scheme, host, port, username, password, path, method='GET', data=None, query=None, timeout=None, content_type=None):
+def _make_request(scheme, host, port, username, password, path, method='GET', data=None, query=None,
+                  timeout=None, content_type=None):
+
     path = _DOUBLE_SLASH_REGEX.sub('/', path)
     url = '%(scheme)s://%(host)s%(port)s%(path)s' % {
             'scheme': scheme,
@@ -38,7 +40,7 @@ def _make_request(scheme, host, port, username, password, path, method='GET', da
     
     query = dict(query or {})
     query['_username'] = username or ''
-    query['_admin'] = 'true' # always use the admin account
+    query['_admin'] = 'true'  # always use the admin account
     
     if url.count('?'):
         url += '&'
@@ -57,7 +59,7 @@ def _make_request(scheme, host, port, username, password, path, method='GET', da
         headers['Content-Type'] = content_type
 
     return HTTPRequest(url, method, body=data, connect_timeout=timeout, request_timeout=timeout, headers=headers,
-            validate_cert=settings.VALIDATE_CERTS)
+                       validate_cert=settings.VALIDATE_CERTS)
 
 
 def _callback_wrapper(callback):
@@ -131,7 +133,7 @@ def list(local_config, callback):
             'url': pretty_camera_url(local_config, camera=False)})
     
     request = _make_request(scheme, host, port, username, password,
-            path + '/config/list/')
+                            path + '/config/list/')
     
     def on_response(response):
         def make_camera_response(c):
@@ -160,8 +162,7 @@ def list(local_config, callback):
         cameras = response['cameras']
         
         # filter out simple mjpeg cameras
-        cameras = [make_camera_response(c) for c in cameras
-                if c['proto'] != 'mjpeg' and c.get('enabled')]
+        cameras = [make_camera_response(c) for c in cameras if c['proto'] != 'mjpeg' and c.get('enabled')]
         
         callback(cameras)
     
@@ -177,7 +178,7 @@ def get_config(local_config, callback):
             'url': pretty_camera_url(local_config)})
     
     request = _make_request(scheme, host, port, username, password,
-            path + '/config/%(id)s/get/' % {'id': camera_id})
+                            path + '/config/%(id)s/get/' % {'id': camera_id})
     
     def on_response(response):
         if response.error:
@@ -221,10 +222,10 @@ def set_config(local_config, ui_config, callback):
             'url': pretty_camera_url(local_config)})
     
     ui_config = json.dumps(ui_config)
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/config/%(id)s/set/' % {'id': camera_id},
-            method='POST', data=ui_config, content_type='application/json')
+
+    p = path + '/config/%(id)s/set/' % {'id': camera_id}
+    request = _make_request(scheme, host, port, username, password, p,
+                            method='POST', data=ui_config, content_type='application/json')
     
     def on_response(response):
         if response.error:
@@ -249,10 +250,10 @@ def set_preview(local_config, controls, callback):
             'url': pretty_camera_url(local_config)})
     
     data = json.dumps(controls)
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/config/%(id)s/set_preview/' % {'id': camera_id},
-            method='POST', data=data, content_type='application/json')
+
+    p = path + '/config/%(id)s/set_preview/' % {'id': camera_id}
+    request = _make_request(scheme, host, port, username, password, p,
+                            method='POST', data=data, content_type='application/json')
 
     def on_response(response):
         if response.error:
@@ -279,9 +280,9 @@ def test(local_config, data, callback):
 
     data = json.dumps(data)
 
-    request = _make_request(scheme, host, port, username, password,
-            path + '/config/%(id)s/test/' % {'id': camera_id},
-            method='POST', data=data, content_type='application/json')
+    p = path + '/config/%(id)s/test/' % {'id': camera_id}
+    request = _make_request(scheme, host, port, username, password, p,
+                            method='POST', data=data, content_type='application/json')
 
     def on_response(response):
         if response.error:
@@ -313,10 +314,9 @@ def get_current_picture(local_config, width, height, callback):
         
     if height:
         query['height'] = str(height)
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/picture/%(id)s/current/' % {'id': camera_id},
-            query=query)
+
+    p = path + '/picture/%(id)s/current/' % {'id': camera_id}
+    request = _make_request(scheme, host, port, username, password, p, query=query)
     
     def on_response(response):
         cookies = utils.parse_cookies(response.headers.get_list('Set-Cookie'))
@@ -351,10 +351,9 @@ def list_media(local_config, media_type, prefix, callback):
         query['prefix'] = prefix
     
     # timeout here is 10 times larger than usual - we expect a big delay when fetching the media list
-    request = _make_request(scheme, host, port, username, password,
-            path + '/%(media_type)s/%(id)s/list/' % {
-            'id': camera_id, 'media_type': media_type}, query=query,
-            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
+    p = path + '/%(media_type)s/%(id)s/list/' % {'id': camera_id, 'media_type': media_type}
+    request = _make_request(scheme, host, port, username, password, p, query=query,
+                            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
     
     def on_response(response):
         if response.error:
@@ -396,7 +395,7 @@ def get_media_content(local_config, filename, media_type, callback):
     
     # timeout here is 10 times larger than usual - we expect a big delay when fetching the media list
     request = _make_request(scheme, host, port, username, password,
-            path, timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
+                            path, timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
     
     def on_response(response):
         if response.error:
@@ -429,15 +428,18 @@ def make_zipped_content(local_config, media_type, group, callback):
  
     # timeout here is 100 times larger than usual - we expect a big delay
     request = _make_request(scheme, host, port, username, password,
-            prepare_path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT)
+                            prepare_path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT)
 
     def on_response(response):
         if response.error:
-            logging.error('failed to prepare zip file for group "%(group)s" of remote camera %(id)s on %(url)s: %(msg)s' % {
+            msg = 'failed to prepare zip file for group "%(group)s" ' \
+                  'of remote camera %(id)s on %(url)s: %(msg)s' % {
                     'group': group or 'ungrouped',
                     'id': camera_id,
                     'url': pretty_camera_url(local_config),
-                    'msg': utils.pretty_http_error(response)})
+                    'msg': utils.pretty_http_error(response)}
+
+            logging.error(msg)
 
             return callback(error=utils.pretty_http_error(response))
         
@@ -463,14 +465,15 @@ def get_zipped_content(local_config, media_type, key, group, callback):
     logging.debug('downloading zip file for remote camera %(id)s on %(url)s' % {
             'id': camera_id,
             'url': pretty_camera_url(local_config)})
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/%(media_type)s/%(id)s/zipped/%(group)s/?key=%(key)s' % {
-                    'media_type': media_type,
-                    'group': group,
-                    'id': camera_id,
-                    'key': key},
-            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
+
+    p = path + '/%(media_type)s/%(id)s/zipped/%(group)s/?key=%(key)s' % {
+            'media_type': media_type,
+            'group': group,
+            'id': camera_id,
+            'key': key}
+
+    request = _make_request(scheme, host, port, username, password, p,
+                            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
 
     def on_response(response):
         if response.error:
@@ -494,12 +497,15 @@ def get_zipped_content(local_config, media_type, key, group, callback):
 def make_timelapse_movie(local_config, framerate, interval, group, callback):
     scheme, host, port, username, password, path, camera_id = _remote_params(local_config)
 
-    logging.debug('making timelapse movie for group "%(group)s" of remote camera %(id)s with rate %(framerate)s/%(int)s on %(url)s' % {
+    msg = 'making timelapse movie for group "%(group)s" of remote camera %(id)s ' \
+          'with rate %(framerate)s/%(int)s on %(url)s' % {
             'group': group or 'ungrouped',
             'id': camera_id,
             'framerate': framerate,
             'int': interval,
-            'url': pretty_camera_url(local_config)})
+            'url': pretty_camera_url(local_config)}
+
+    logging.debug(msg)
 
     path += '/picture/%(id)s/timelapse/%(group)s/?interval=%(int)s&framerate=%(framerate)s' % {
             'id': camera_id,
@@ -508,17 +514,20 @@ def make_timelapse_movie(local_config, framerate, interval, group, callback):
             'group': group}
     
     request = _make_request(scheme, host, port, username, password,
-            path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT)
+                            path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT)
 
     def on_response(response):
         if response.error:
-            logging.error('failed to make timelapse movie for group "%(group)s" of remote camera %(id)s with rate %(framerate)s/%(int)s on %(url)s: %(msg)s' % {
+            msg = 'failed to make timelapse movie for group "%(group)s" of remote camera %(id)s ' \
+                  'with rate %(framerate)s/%(int)s on %(url)s: %(msg)s' % {
                     'group': group or 'ungrouped',
                     'id': camera_id,
                     'url': pretty_camera_url(local_config),
                     'int': interval,
                     'framerate': framerate,
-                    'msg': utils.pretty_http_error(response)})
+                    'msg': utils.pretty_http_error(response)}
+
+            logging.error(msg)
 
             return callback(error=utils.pretty_http_error(response))
         
@@ -544,11 +553,11 @@ def check_timelapse_movie(local_config, group, callback):
     logging.debug('checking timelapse movie status for remote camera %(id)s on %(url)s' % {
             'id': camera_id,
             'url': pretty_camera_url(local_config)})
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/picture/%(id)s/timelapse/%(group)s/?check=true' % {
-                    'id': camera_id,
-                    'group': group})
+
+    p = path + '/picture/%(id)s/timelapse/%(group)s/?check=true' % {
+            'id': camera_id,
+            'group': group}
+    request = _make_request(scheme, host, port, username, password, p)
     
     def on_response(response):
         if response.error:
@@ -581,13 +590,14 @@ def get_timelapse_movie(local_config, key, group, callback):
     logging.debug('downloading timelapse movie for remote camera %(id)s on %(url)s' % {
             'id': camera_id,
             'url': pretty_camera_url(local_config)})
-    
-    request = _make_request(scheme, host, port, username, password,
-            path + '/picture/%(id)s/timelapse/%(group)s/?key=%(key)s' % {
-                'id': camera_id,
-                'group': group,
-                'key': key},
-            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
+
+    p = path + '/picture/%(id)s/timelapse/%(group)s/?key=%(key)s' % {
+            'id': camera_id,
+            'group': group,
+            'key': key}
+
+    request = _make_request(scheme, host, port, username, password, p,
+                            timeout=10 * settings.REMOTE_REQUEST_TIMEOUT)
 
     def on_response(response):
         if response.error:
@@ -629,8 +639,7 @@ def get_media_preview(local_config, filename, media_type, width, height, callbac
     if height:
         query['height'] = str(height)
     
-    request = _make_request(scheme, host, port, username, password,
-            path, query=query)
+    request = _make_request(scheme, host, port, username, password, path, query=query)
     
     def on_response(response):
         if response.error:
@@ -661,9 +670,8 @@ def del_media_content(local_config, filename, media_type, callback):
             'id': camera_id,
             'filename': filename}
 
-    request = _make_request(scheme, host, port, username, password,
-            path, method='POST', data='{}',
-            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
+    request = _make_request(scheme, host, port, username, password, path, method='POST', data='{}',
+                            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
 
     def on_response(response):
         if response.error:
@@ -694,9 +702,8 @@ def del_media_group(local_config, group, media_type, callback):
             'id': camera_id,
             'group': group}
 
-    request = _make_request(scheme, host, port, username, password, path,
-            method='POST', data='{}',
-            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
+    request = _make_request(scheme, host, port, username, password, path, method='POST', data='{}',
+                            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
 
     def on_response(response):
         if response.error:
@@ -726,9 +733,8 @@ def exec_action(local_config, action, callback):
             'action': action,
             'id': camera_id}
 
-    request = _make_request(scheme, host, port, username, password, path,
-            method='POST', data='{}',
-            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
+    request = _make_request(scheme, host, port, username, password, path, method='POST', data='{}',
+                            timeout=settings.REMOTE_REQUEST_TIMEOUT, content_type='application/json')
 
     def on_response(response):
         if response.error:
index 130ef94d9b18e086920db904b3d61c5066fd4815..664e5471cbb23d0a993699a54a858eb808433857 100644 (file)
@@ -64,13 +64,13 @@ def send_mail(server, port, account, password, tls, _from, to, subject, message,
     email['Date'] = formatdate(localtime=True)
     email.attach(MIMEText(message))
     
-    for file in reversed(files):
+    for f in reversed(files):
         part = MIMEBase('image', 'jpeg')
-        with open(file, 'rb') as f:
+        with open(f, 'rb') as f:
             part.set_payload(f.read())
         
         Encoders.encode_base64(part)
-        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
+        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
         email.attach(part)
     
     if files:
@@ -94,7 +94,7 @@ def make_message(subject, message, camera_id, moment, timespan, callback):
 
         if media_files:
             logging.debug('got media files')
-            media_files = [m for m in media_files if abs(m['timestamp'] - timestamp) < timespan] # filter out non-recent media files
+            media_files = [m for m in media_files if abs(m['timestamp'] - timestamp) < timespan]  # filter out non-recent media files
             media_files.sort(key=lambda m: m['timestamp'], reverse=True)
             media_files = [os.path.join(camera_config['target_dir'], re.sub('^/', '', m['path'])) for m in media_files]
         
@@ -125,7 +125,7 @@ def make_message(subject, message, camera_id, moment, timespan, callback):
         return on_media_files([])
     
     logging.debug('waiting for pictures to be taken')
-    time.sleep(timespan) # give motion some time to create motion pictures
+    time.sleep(timespan)  # give motion some time to create motion pictures
     
     logging.debug('creating email message')
     mediafiles.list_media(camera_config, media_type='picture', callback=on_media_files)
@@ -155,7 +155,7 @@ def main(parser, args):
     # the motion daemon overrides SIGCHLD,
     # so we must restore it here,
     # or otherwise media listing won't work
-    signal.signal(signal.SIGCHLD,signal.SIG_DFL)
+    signal.signal(signal.SIGCHLD, signal.SIG_DFL)
 
     if len(args) == 12:
         # backwards compatibility with older configs lacking "from" field
@@ -177,7 +177,7 @@ def main(parser, args):
     message = messages.get(options.msg_id)
     subject = subjects.get(options.msg_id)
     options.moment = datetime.datetime.strptime(options.moment, '%Y-%m-%dT%H:%M:%S')
-    options.password = options.password.replace('\\;', ';') # unescape password
+    options.password = options.password.replace('\\;', ';')  # unescape password
     
     # do not wait too long for media list,
     # email notifications are critical
@@ -207,7 +207,7 @@ def main(parser, args):
     def on_message(subject, message, files):
         try:
             send_mail(options.server, options.port, options.account, options.password,
-                    options.tls, _from, to, subject, message, files or [])
+                      options.tls, _from, to, subject, message, files or [])
             logging.info('email sent')
 
         except Exception as e:
index 12ea1bea0c62bea45328015bf448739aaba6daba..7ff1313bd121d12dec0028ba9648d0150d7a1aca 100644 (file)
@@ -45,7 +45,7 @@ class Daemon(object):
     def daemonize(self):
         # first fork
         try: 
-            if os.fork() > 0: # parent
+            if os.fork() > 0:  # parent
                 sys.exit(0)
 
         except OSError, e: 
@@ -58,7 +58,7 @@ class Daemon(object):
 
         # second fork
         try: 
-            if os.fork() > 0: # parent 
+            if os.fork() > 0:  # parent
                 sys.exit(0) 
         
         except OSError, e: 
@@ -291,7 +291,7 @@ def test_requirements():
 def make_media_folders():
     import config
     
-    config.get_main() # just to have main config already loaded
+    config.get_main()  # just to have main config already loaded
     
     camera_ids = config.get_camera_ids()
     for camera_id in camera_ids:
@@ -339,7 +339,7 @@ def start_motion():
 
 def parse_options(parser, args):
     parser.add_argument('-b', help='start the server in background (daemonize)',
-            action='store_true', dest='background', default=False)
+                        action='store_true', dest='background', default=False)
 
     return parser.parse_args(args)
 
@@ -388,7 +388,7 @@ def run():
     template.add_context('static_path', 'static/')
     
     application = Application(handler_mapping, debug=False, log_function=_log_request,
-            static_path=settings.STATIC_PATH, static_url_prefix='/static/')
+                              static_path=settings.STATIC_PATH, static_url_prefix='/static/')
     
     application.listen(settings.PORT, settings.LISTEN)
     logging.info('server started')
index cfd8488d4b49f5106feb06eb20a3012903443a27..44786611dded48bae54eb46d8f8a9418db9df024 100644 (file)
@@ -5,7 +5,7 @@ import sys
 
 import motioneye
 
-_config_file = None
+config_file = None
 
 # the root directory of the project
 PROJECT_PATH = os.path.dirname(motioneye.__file__)
@@ -17,7 +17,7 @@ TEMPLATE_PATH = os.path.join(PROJECT_PATH, 'templates')
 STATIC_PATH = os.path.join(PROJECT_PATH, 'static')
 
 # path to the configuration directory (must be writable by motionEye)
-CONF_PATH = [sys.prefix, ''][sys.prefix == '/usr']  + '/etc/motioneye'
+CONF_PATH = [sys.prefix, ''][sys.prefix == '/usr'] + '/etc/motioneye'
 
 # path to the directory where pid files go (must be writable by motionEye)
 for d in ['/run', '/var/run', '/tmp', '/var/tmp']:
index 894fbe5bc22a61106ffd8a49a701f925dc452329..4a7d48ba5e1aba0d026a4c5a7cf7016082d4c8d8 100644 (file)
@@ -42,7 +42,7 @@ def find_mount_cifs():
     try:
         return subprocess.check_output(['which', 'mount.cifs'], stderr=utils.DEV_NULL).strip()
     
-    except subprocess.CalledProcessError: # not found
+    except subprocess.CalledProcessError:  # not found
         return None
 
 
@@ -92,7 +92,7 @@ def list_mounts():
                 continue
             
             server, share = match.groups()
-            share = share.replace('\\040', ' ') # spaces are reported oddly by /proc/mounts
+            share = share.replace('\\040', ' ')  # spaces are reported oddly by /proc/mounts
             
             match = re.search('username=([a-z][-\w]*)', opts)
             if match:
@@ -119,16 +119,18 @@ def update_mounts():
     mounts = list_mounts()
     mounts = dict(((m['server'], m['share'], m['username'] or ''), False) for m in mounts)
     
-    should_stop = False # indicates that motion should be stopped immediately
-    should_start = True # indicates that motion can be started afterwards
+    should_stop = False  # indicates that motion should be stopped immediately
+    should_start = True  # indicates that motion can be started afterwards
     for network_share in network_shares:
         key = (network_share['server'], network_share['share'], network_share['username'] or '')
-        if key in mounts: # found
+        if key in mounts:  # found
             mounts[key] = True
         
-        else: # needs to be mounted
+        else:  # needs to be mounted
             should_stop = True
-            if not _mount(network_share['server'], network_share['share'], network_share['username'], network_share['password']):
+            if not _mount(network_share['server'], network_share['share'],
+                          network_share['username'], network_share['password']):
+
                 should_start = False
     
     # unmount the no longer necessary mounts
@@ -137,7 +139,7 @@ def update_mounts():
             _umount(server, share, username)
             should_stop = True
     
-    return (should_stop, should_start)
+    return should_stop, should_start
 
 
 def test_share(server, share, username, password, root_directory):
index d6c412be484a72c829387000d9650898eeb8fb4a..996b9584d9c264a93ae9216c6f6eac5352369a53 100644 (file)
@@ -59,7 +59,6 @@ def start():
 def stop():
     global _pool
     
-    #_pool.terminate()
     _pool = None
 
 
@@ -69,7 +68,7 @@ def add(when, func, tag=None, callback=None, **params):
     
     now = time.time()
     
-    if isinstance(when, int): # delay, in seconds
+    if isinstance(when, int):  # delay, in seconds
         when += now
         
     elif isinstance(when, datetime.timedelta):
@@ -117,7 +116,7 @@ def _load():
         logging.debug('loading tasks from "%s"...' % file_path)
     
         try:
-            file = open(file_path, 'r')
+            f = open(file_path, 'r')
         
         except Exception as e:
             logging.error('could not open tasks file "%s": %s' % (file_path, e))
@@ -125,13 +124,13 @@ def _load():
             return
         
         try:
-            _tasks = cPickle.load(file)
+            _tasks = cPickle.load(f)
 
         except Exception as e:
             logging.error('could not read tasks from file "%s": %s' % (file_path, e))
 
         finally:
-            file.close()
+            f.close()
             
 
 def _save():
@@ -140,7 +139,7 @@ def _save():
     logging.debug('saving tasks to "%s"...' % file_path)
 
     try:
-        file = open(file_path, 'w')
+        f = open(file_path, 'w')
 
     except Exception as e:
         logging.error('could not open tasks file "%s": %s' % (file_path, e))
@@ -150,10 +149,10 @@ def _save():
     try:
         # don't save tasks that have a callback
         tasks = [t for t in _tasks if not t[3]]
-        cPickle.dump(tasks, file)
+        cPickle.dump(tasks, f)
 
     except Exception as e:
-        logging.error('could not save tasks to file "%s": %s'% (file_path, e))
+        logging.error('could not save tasks to file "%s": %s' % (file_path, e))
 
     finally:
-        file.close()
+        f.close()
index a7572733844c16de0134390abfaea89bf8877882..e85710ff7ecf16db65e2eca21338407a218078e4 100644 (file)
@@ -32,24 +32,24 @@ def get_time_zone():
 
 
 def _get_time_zone_symlink():
-    file = settings.LOCAL_TIME_FILE
-    if not file:
+    f = settings.LOCAL_TIME_FILE
+    if not f:
         return None
     
-    for i in xrange(8): # recursively follow the symlinks @UnusedVariable
+    for i in xrange(8):  # recursively follow the symlinks @UnusedVariable
         try:
-            file = os.readlink(file)
+            f = os.readlink(f)
 
         except OSError:
             break
     
-    if file and file.startswith('/usr/share/zoneinfo/'):
-        file = file[20:]
+    if f and f.startswith('/usr/share/zoneinfo/'):
+        f = f[20:]
     
     else:
-        file = None
+        f = None
 
-    time_zone = file or None
+    time_zone = f or None
     if time_zone:
         logging.debug('found time zone by symlink method: %s' % time_zone)
     
@@ -105,7 +105,7 @@ def _set_time_zone(time_zone):
         os.remove(settings.LOCAL_TIME_FILE)
     
     except:
-        pass # nevermind
+        pass  # nevermind
     
     try:
         os.symlink(zoneinfo_file, settings.LOCAL_TIME_FILE)
index a3ceacdfcf9db3493333e1c306aebfbee0b9bf74..ff8e68838a82d312241abe4c56956946ea4ded1c 100644 (file)
@@ -56,7 +56,7 @@ def _get_os_version_uname():
         return name, version
 
     except:
-        return ('Linux', '')  # most likely :)
+        return 'Linux', ''  # most likely :)
 
 
 def compare_versions(version1, version2):
index b76abc9a64ecdff9601c62b6c26b339c2fa450dc..fd93d1423a4f00fa2807ac40770d9f39fcae61f6 100644 (file)
@@ -75,7 +75,9 @@ class UploadService(object):
             raise Exception(msg)
 
         if st.st_size > self.MAX_FILE_SIZE:
-            msg = 'file "%s" is too large (%sMB/%sMB)' % (filename, st.st_size / 1024 / 1024, self.MAX_FILE_SIZE / 1024 / 1024)
+            msg = 'file "%s" is too large (%sMB/%sMB)' % \
+                    (filename, st.st_size / 1024 / 1024, self.MAX_FILE_SIZE / 1024 / 1024)
+
             self.error(msg)
             raise Exception(msg)
 
@@ -348,7 +350,7 @@ class GoogleDrive(UploadService):
                     # retry the request with refreshed credentials
                     return self._request(url, body, headers, retry_auth=False)
 
-                except Exception as e:
+                except Exception:
                     self.error('refreshing credentials failed')
                     raise
 
@@ -555,9 +557,9 @@ class Dropbox(UploadService):
                     self.save()
 
                     # retry the request with refreshed credentials
-                    self._request(url, body, headers, retry_auth=False)
+                    return self._request(url, body, headers, retry_auth=False)
 
-                except Exception as e:
+                except Exception:
                     self.error('refreshing credentials failed')
                     raise
 
@@ -885,7 +887,7 @@ def _load():
         logging.debug('loading upload services state from "%s"...' % file_path)
 
         try:
-            file = open(file_path, 'r')
+            f = open(file_path, 'r')
 
         except Exception as e:
             logging.error('could not open upload services state file "%s": %s' % (file_path, e))
@@ -893,7 +895,7 @@ def _load():
             return services
 
         try:
-            data = json.load(file)
+            data = json.load(f)
 
         except Exception as e:
             logging.error('could not read upload services state from file "%s": %s' % (file_path, e))
@@ -901,7 +903,7 @@ def _load():
             return services
 
         finally:
-            file.close()
+            f.close()
 
         for camera_id, d in data.iteritems():
             for name, state in d.iteritems():
@@ -929,7 +931,7 @@ def _save(services):
             data.setdefault(str(camera_id), {})[name] = service.dump()
 
     try:
-        file = open(file_path, 'w')
+        f = open(file_path, 'w')
 
     except Exception as e:
         logging.error('could not open upload services state file "%s": %s' % (file_path, e))
@@ -937,10 +939,10 @@ def _save(services):
         return
 
     try:
-        json.dump(data, file, sort_keys=True, indent=4)
+        json.dump(data, f, sort_keys=True, indent=4)
 
     except Exception as e:
-        logging.error('could not save upload services state to file "%s": %s'(file_path, e))
+        logging.error('could not save upload services state to file "%s": %s' % (file_path, e))
 
     finally:
-        file.close()
+        f.close()
index 95cea8aa40b656d7e4125d2fe2ed85ef29838eda..d8456e2d07064cae317902be1c3892fafcd87663 100644 (file)
@@ -37,14 +37,8 @@ from tornado.ioloop import IOLoop
 
 import settings
 
-try:
-    from collections import OrderedDict  # @UnusedImport
 
-except:
-    from ordereddict import OrderedDict  # @UnusedImport @Reimport
-
-
-_SIGNATURE_REGEX = re.compile('[^a-zA-Z0-9/?_.=&{}\[\]":, _-]')
+_SIGNATURE_REGEX = re.compile('[^a-zA-Z0-9/?_.=&{}\[\]":, -]')
 _SPECIAL_COOKIE_NAMES = {'expires', 'domain', 'path', 'secure', 'httponly'}
 
 MASK_WIDTH = 32
@@ -74,9 +68,13 @@ COMMON_RESOLUTIONS = [
 ]
 
 
+def _(x):
+    return x  # this could later be replaced by a proper translate function
+
+
 def pretty_date_time(date_time, tzinfo=None, short=False):
     if date_time is None:
-        return '(' _('never') + ')'
+        return '(' + _('never') + ')'
 
     if isinstance(date_time, int):
         return pretty_date_time(datetime.datetime.fromtimestamp(date_time))
@@ -115,7 +113,7 @@ def pretty_date_time(date_time, tzinfo=None, short=False):
 
 def pretty_date(date):
     if date is None:
-        return '(' _('never') + ')'
+        return '(' + _('never') + ')'
 
     if isinstance(date, int):
         return pretty_date(datetime.datetime.fromtimestamp(date))
@@ -212,36 +210,36 @@ def pretty_duration(duration):
         return special_result
 
     if days:
-        format = "{d}d{h}h{m}m"
+        fmt = "{d}d{h}h{m}m"
 
     elif hours:
-        format = "{h}h{m}m"
+        fmt = "{h}h{m}m"
 
     elif minutes:
-        format = "{m}m"
+        fmt = "{m}m"
         if seconds:
-            format += "{s}s"
+            fmt += "{s}s"
 
     else:
-        format = "{s}s"
+        fmt = "{s}s"
 
     if negative:
-        format = '-' + format
+        fmt = '-' + fmt
 
-    return format.format(d=days, h=hours, m=minutes, s=seconds)
+    return fmt.format(d=days, h=hours, m=minutes, s=seconds)
 
 
 def pretty_size(size):
-    if size < 1024: # less than 1kB
+    if size < 1024:  # less than 1kB
         size, unit = size, 'B'
     
-    elif size < 1024 * 1024: # less than 1MB
+    elif size < 1024 * 1024:  # less than 1MB
         size, unit = size / 1024.0, 'kB'
         
-    elif size < 1024 * 1024 * 1024: # less than 1GB
+    elif size < 1024 * 1024 * 1024:  # less than 1GB
         size, unit = size / 1024.0 / 1024, 'MB'
     
-    else: # greater than or equal to 1GB
+    else:  # greater than or equal to 1GB
         size, unit = size / 1024.0 / 1024 / 1024, 'GB'
     
     return '%.1f %s' % (size, unit)
@@ -333,31 +331,31 @@ def get_disk_usage(path):
     total_size = total_blocks * block_size
     used_size = total_size - free_size
     
-    return (used_size, total_size)
+    return used_size, total_size
 
 
 def is_local_motion_camera(config):
-    '''Tells if a camera is managed by the local motion instance.'''
+    """Tells if a camera is managed by the local motion instance."""
     return bool(config.get('videodevice') or config.get('netcam_url'))
 
 
 def is_remote_camera(config):
-    '''Tells if a camera is managed by a remote motionEye server.'''
+    """Tells if a camera is managed by a remote motionEye server."""
     return config.get('@proto') == 'motioneye'
 
 
 def is_v4l2_camera(config):
-    '''Tells if a camera is a v4l2 device managed by the local motion instance.'''
+    """Tells if a camera is a v4l2 device managed by the local motion instance."""
     return bool(config.get('videodevice'))
 
 
 def is_net_camera(config):
-    '''Tells if a camera is a network camera managed by the local motion instance.'''
+    """Tells if a camera is a network camera managed by the local motion instance."""
     return bool(config.get('netcam_url'))
 
 
 def is_simple_mjpeg_camera(config):
-    '''Tells if a camera is a simple MJPEG camera not managed by any motion instance.'''
+    """Tells if a camera is a simple MJPEG camera not managed by any motion instance."""
     return bool(config.get('@proto') == 'mjpeg')
 
 
@@ -390,8 +388,9 @@ def test_mjpeg_url(data, auth_modes, allow_jpeg, callback):
         logging.debug('testing (m)jpg netcam at %s using %s authentication' % (url, auth))
 
         request = HTTPRequest(url, auth_username=username, auth_password=password, auth_mode=auth_modes.pop(0),
-                connect_timeout=settings.REMOTE_REQUEST_TIMEOUT, request_timeout=settings.REMOTE_REQUEST_TIMEOUT,
-                header_callback=on_header, validate_cert=settings.VALIDATE_CERTS)
+                              connect_timeout=settings.REMOTE_REQUEST_TIMEOUT,
+                              request_timeout=settings.REMOTE_REQUEST_TIMEOUT,
+                              header_callback=on_header, validate_cert=settings.VALIDATE_CERTS)
 
         http_client = AsyncHTTPClient(force_instance=True)
         http_client.fetch(request, on_response)
@@ -474,7 +473,7 @@ def test_rtsp_url(data, callback):
         stream.connect((host, int(port)), on_connect)
 
         timeout[0] = io_loop.add_timeout(datetime.timedelta(seconds=settings.MJPG_CLIENT_TIMEOUT),
-                functools.partial(on_connect, _timeout=True))
+                                         functools.partial(on_connect, _timeout=True))
         
         return stream
     
@@ -655,7 +654,7 @@ def compute_signature(method, path, body, key):
     key = _SIGNATURE_REGEX.sub('-', key)
 
     if body and body.startswith('---'):
-        body = None # file attachment
+        body = None  # file attachment
 
     body = body and _SIGNATURE_REGEX.sub('-', body.decode('utf8'))
 
@@ -679,6 +678,7 @@ def parse_cookies(cookies_headers):
 
     return parsed
 
+
 def build_basic_header(username, password):
     return 'Basic ' + base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
 
@@ -705,7 +705,7 @@ def build_digest_header(method, url, username, password, state):
             return hashlib.md5(x).hexdigest()
         hash_utf8 = md5_utf8
 
-    elif _algorithm == 'SHA':
+    else:  # _algorithm == 'SHA'
         def sha_utf8(x):
             if isinstance(x, str):
                 x = x.encode('utf-8')
@@ -773,7 +773,7 @@ def build_digest_header(method, url, username, password, state):
     state['last_nonce'] = last_nonce
     state['nonce_count'] = nonce_count
 
-    return 'Digest %s' % (base)
+    return 'Digest %s' % base
 
 
 def urlopen(*args, **kwargs):
@@ -801,24 +801,24 @@ def build_editable_mask_file(camera_id, mask_lines, capture_width=None, capture_
     mask_lines = mask_lines[2:]
     
     logging.debug('building editable mask for camera with id %s (%sx%s)' %
-            (camera_id, width, height))
+                  (camera_id, width, height))
 
     # horizontal rectangles
-    nx = MASK_WIDTH # number of rectangles
+    nx = MASK_WIDTH  # number of rectangles
     if width % nx:
         nx -= 1
-        rx = width % nx # remainder
+        rx = width % nx  # remainder
 
     else:
         rx = 0
     
-    rw = width / nx # rectangle width
+    rw = width / nx  # rectangle width
 
     # vertical rectangles
-    ny = mask_height = height * MASK_WIDTH / width # number of rectangles
+    ny = mask_height = height * MASK_WIDTH / width  # number of rectangles
     if height % ny:
         ny -= 1
-        ry = height % ny # remainder
+        ry = height % ny  # remainder
     
     else:
         ry = 0
@@ -835,10 +835,10 @@ def build_editable_mask_file(camera_id, mask_lines, capture_width=None, capture_
     else:
         line_index_func = lambda y: (len(mask_lines) - 1) * y / ny
 
-    rh = height / ny # rectangle height
+    rh = height / ny  # rectangle height
 
     # draw the actual mask image content
-    im = Image.new('L', (width, height), 255) # all white
+    im = Image.new('L', (width, height), 255)  # all white
     dr = ImageDraw.Draw(im)
     
     for y in xrange(ny):
@@ -864,7 +864,7 @@ def build_editable_mask_file(camera_id, mask_lines, capture_width=None, capture_
     # resize the image if necessary
     if capture_width and capture_height and im.size != (capture_width, capture_height):
         logging.debug('editable mask needs resizing from %sx%s to %sx%s' %
-                (im.size[0], im.size[1], capture_width, capture_height))
+                      (im.size[0], im.size[1], capture_width, capture_height))
 
         im = im.resize((capture_width, capture_height))
 
@@ -896,7 +896,7 @@ def parse_editable_mask_file(camera_id, capture_width=None, capture_height=None)
         # resize the image if necessary
         if im.size != (capture_width, capture_height):
             logging.debug('editable mask needs resizing from %sx%s to %sx%s' %
-                    (im.size[0], im.size[1], capture_width, capture_height))
+                          (im.size[0], im.size[1], capture_width, capture_height))
 
             im = im.resize((capture_width, capture_height))
             
@@ -910,26 +910,26 @@ def parse_editable_mask_file(camera_id, capture_width=None, capture_height=None)
     pixels = list(im.getdata())
 
     # horizontal rectangles
-    nx = MASK_WIDTH # number of rectangles
+    nx = MASK_WIDTH  # number of rectangles
     if width % nx:
         nx -= 1
-        rx = width % nx # remainder
+        rx = width % nx  # remainder
 
     else:
         rx = 0
     
-    rw = width / nx # rectangle width
+    rw = width / nx  # rectangle width
 
     # vertical rectangles
-    ny = height * MASK_WIDTH / width # number of rectangles
+    ny = height * MASK_WIDTH / width  # number of rectangles
     if height % ny:
         ny -= 1
-        ry = height % ny # remainder
+        ry = height % ny  # remainder
     
     else:
         ry = 0
 
-    rh = height / ny # rectangle height
+    rh = height / ny  # rectangle height
 
     # parse the image contents and build the mask lines
     mask_lines = [width, height]
index c8d84acd2089a31c587ef2dbe787bdffd1572cd8..cd8c2a35a5e0379e68fd9742cf5dbef4b57bf262 100644 (file)
@@ -38,7 +38,7 @@ def find_v4l2_ctl():
     try:
         return subprocess.check_output(['which', 'v4l2-ctl'], stderr=utils.DEV_NULL).strip()
     
-    except subprocess.CalledProcessError: # not found
+    except subprocess.CalledProcessError:  # not found
         return None
 
 
@@ -85,7 +85,7 @@ def list_devices():
         p.kill()
 
     except:
-        pass # nevermind
+        pass  # nevermind
 
     name = None
     devices = []
@@ -124,8 +124,10 @@ def list_resolutions(device):
     resolutions = set()
     output = ''
     started = time.time()
-    p = subprocess.Popen('v4l2-ctl -d %(device)s --list-formats-ext | grep -vi stepwise | grep -oE "[0-9]+x[0-9]+" || true' % {
-            'device': pipes.quote(device)}, shell=True, stdout=subprocess.PIPE, bufsize=1)
+    cmd = 'v4l2-ctl -d %(device)s --list-formats-ext | grep -vi stepwise | grep -oE "[0-9]+x[0-9]+" || true' % {
+            'device': pipes.quote(device)}
+
+    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, bufsize=1)
 
     fd = p.stdout.fileno()
     fl = fcntl.fcntl(fd, fcntl.F_GETFL)
@@ -156,7 +158,7 @@ def list_resolutions(device):
         p.kill()
     
     except:
-        pass # nevermind
+        pass  # nevermind
 
     for pair in output.split('\n'):
         pair = pair.strip()
@@ -168,9 +170,9 @@ def list_resolutions(device):
         height = int(height)
 
         if (width, height) in resolutions:
-            continue # duplicate resolution
+            continue  # duplicate resolution
 
-        if width < 96 or height < 96: # some reasonable minimal values
+        if width < 96 or height < 96:  # some reasonable minimal values
             continue
         
         if not motionctl.resolution_is_valid(width, height):
@@ -326,8 +328,9 @@ def _set_ctrl(device, control, value):
 
     output = ''
     started = time.time()
-    p = subprocess.Popen('v4l2-ctl -d %(device)s --set-ctrl %(control)s=%(value)s' % {
-            'device': pipes.quote(device), 'control': pipes.quote(control), 'value': pipes.quote(str(value))}, shell=True, stdout=subprocess.PIPE, bufsize=1)
+    cmd = 'v4l2-ctl -d %(device)s --set-ctrl %(control)s=%(value)s' % {
+            'device': pipes.quote(device), 'control': pipes.quote(control), 'value': pipes.quote(str(value))}
+    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, bufsize=1)
 
     fd = p.stdout.fileno()
     fl = fcntl.fcntl(fd, fcntl.F_GETFL)
@@ -358,7 +361,7 @@ def _set_ctrl(device, control, value):
         p.kill()
 
     except:
-        pass # nevermind
+        pass  # nevermind
 
 
 def _list_ctrls(device):
@@ -403,14 +406,14 @@ def _list_ctrls(device):
         p.kill()
 
     except:
-        pass # nevermind
+        pass  # nevermind
 
     controls = {}
     for line in output.split('\n'):
         if not line:
             continue
         
-        match = re.match('^\s*(\w+)\s+\(\w+\)\s*\:\s*(.+)\s*', line)
+        match = re.match('^\s*(\w+)\s+\(\w+\)\s*:\s*(.+)\s*', line)
         if not match:
             continue
         
index bf90ba32aaf2a9c21fee8fe23f25653b3da630b7..22ed7995b1f774889b7df48f0bdcee67daabd0c8 100644 (file)
@@ -52,19 +52,19 @@ def main(parser, args):
         headers['Content-Type'] = 'text/plain'
         data = ''
 
-    elif options.method == 'POSTf': # form url-encoded
+    elif options.method == 'POSTf':  # form url-encoded
         headers['Content-Type'] = 'application/x-www-form-urlencoded'
         data = parts.query
         url = options.url.split('?')[0]
 
-    elif options.method == 'POSTj': # json
+    elif options.method == 'POSTj':  # json
         headers['Content-Type'] = 'application/json'
         data = urlparse.parse_qs(parts.query)
         data = {k: v[0] for (k, v) in data.iteritems()}
         data = json.dumps(data)
         url = options.url.split('?')[0]
 
-    else: # GET
+    else:  # GET
         pass
 
     request = urllib2.Request(url, data, headers=headers)
index 3066ece645e67f1a4dd7ff879a9ab1ef4b2429ef..7f93ed8ec19feb608c4578167fe6456a0eb3f5f2 100644 (file)
@@ -160,7 +160,7 @@ def _set_wifi_settings(s):
                     lines[i] = '    key_mgmt=' + key_mgmt + '\n'
                     found_key_mgmt = True
         
-            else: # wifi disabled
+            else:  # wifi disabled
                 if re.match('ssid\s*=\s*".*?"', line) or re.match('psk\s*=\s*".*?"', line):
                     lines.pop(i)
                     i -= 1
index 3c34afb22d23105b841a8570003b2ef69a76f1c4..2842fa21896258c2505b75eaad738015609c56a6 100644 (file)
@@ -34,21 +34,21 @@ def start():
 def _during_working_schedule(now, working_schedule):
     parts = working_schedule.split('|')
     if len(parts) < 7:
-        return False # invalid ws
+        return False  # invalid ws
 
     ws_day = parts[now.weekday()]
     parts = ws_day.split('-')
     if len(parts) != 2:
-        return False # invalid ws
+        return False  # invalid ws
     
     _from, to = parts
     if not _from or not to:
-        return False # ws disabled for this day
+        return False  # ws disabled for this day
     
     _from = _from.split(':')
     to = to.split(':')
     if len(_from) != 2 or len(to) != 2:
-        return False # invalid ws
+        return False  # invalid ws
     
     try:
         from_h = int(_from[0])
@@ -57,7 +57,7 @@ def _during_working_schedule(now, working_schedule):
         to_m = int(to[1])
     
     except ValueError:
-        return False # invalid ws
+        return False  # invalid ws
     
     if now.hour < from_h or now.hour > to_h:
         return False
@@ -80,7 +80,7 @@ def _check_ws():
         return
     
     def on_motion_detection_status(camera_id, must_be_enabled, working_schedule_type, enabled=None, error=None):
-        if error: # could not detect current status
+        if error:  # could not detect current status
             return logging.warn('skipping motion detection status update for camera with id %(id)s: %(error)s' % {
                     'id': camera_id, 'error': error})
             
@@ -108,14 +108,15 @@ def _check_ws():
         motion_detection = camera_config.get('@motion_detection')
         working_schedule_type = camera_config.get('@working_schedule_type') or 'outside'
         
-        if not working_schedule: # working schedule disabled, motion detection left untouched
+        if not working_schedule:  # working schedule disabled, motion detection left untouched
             continue
         
-        if not motion_detection: # motion detection explicitly disabled
+        if not motion_detection:  # motion detection explicitly disabled
             continue
         
         now_during = _during_working_schedule(now, working_schedule)
-        must_be_enabled = (now_during and working_schedule_type == 'during') or (not now_during and working_schedule_type == 'outside')
+        must_be_enabled = ((now_during and working_schedule_type == 'during') or
+                           (not now_during and working_schedule_type == 'outside'))
         
         motionctl.get_motion_detection(camera_id, functools.partial(
                 on_motion_detection_status, camera_id, must_be_enabled, working_schedule_type))