+-> implement file preserving
+
-> style scroll bars
-> hint text next to section titles
-> clickable hints
-> add a previewer for snapshots
-> add a motioneye.svg icon
--> implement file preserving
-> add other options applicable only to special devices (rpi): wifi settings, notifications
-> group @config rules to top
-> browser compatibility test
-> requirements test
--> add a motion running status indicator (and maybe a start/stop button)
-> other todos
logging.info('motion started')
ioloop = tornado.ioloop.IOLoop.instance()
- ioloop.add_timeout(datetime.timedelta(seconds=10), checker)
+ ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker)
checker()
+def _start_cleanup():
+ import cleanup
+
+ def do_cleanup():
+ cleanup.cleanup_images()
+ cleanup.cleanup_movies()
+
+ ioloop = tornado.ioloop.IOLoop.instance()
+ ioloop.add_timeout(datetime.timedelta(seconds=settings.CLEANUP_INTERVAL), do_cleanup)
+
+ do_cleanup()
+
+
if __name__ == '__main__':
_configure_settings()
_configure_signals()
_configure_logging()
_start_motion()
+ _start_cleanup()
_start_server()
LISTEN = '0.0.0.0'
PORT = 8765
+
+MOTION_CHECK_INTERVAL = 10
+CLEANUP_INTERVAL = 10
--- /dev/null
+
+import datetime
+import logging
+import os
+
+import config
+
+
+def _remove_older_files(dir, moment):
+ for name in os.listdir(dir):
+ full_path = os.path.join(dir, name)
+ if not os.path.isfile(full_path):
+ continue
+
+ file_moment = datetime.datetime.fromtimestamp(os.path.getmtime(file))
+ if file_moment < moment:
+ logging.debug('removing file %(path)s...' % {
+ 'path': full_path})
+
+ #os.remove(full_path)
+
+
+def cleanup_images():
+ logging.debug('cleaning up images...')
+
+ for camera_id in config.get_camera_ids():
+ camera_config = config.get_camera(camera_id)
+ if camera_config.get('@proto') != 'v4l2':
+ continue
+
+ preserve_images = camera_config.get('@preserve_images')
+ if preserve_images == 0:
+ return # preserve forever
+
+ preserve_moment = datetime.datetime.now() - datetime.timedelta(days=preserve_images)
+
+ target_dir = camera_config.get('target_dir')
+ snapshot_filename = camera_config.get('snapshot_filename')
+ jpeg_filename = camera_config.get('snapshot_jpeg')
+
+ if snapshot_filename:
+ snapshot_path = os.path.join(target_dir, snapshot_filename)
+ snapshot_path = os.path.dirname(snapshot_path)
+ _remove_older_files(dir, preserve_moment)
+
+ if jpeg_filename:
+ snapshot_path = os.path.join(target_dir, jpeg_filename)
+ snapshot_path = os.path.dirname(snapshot_path)
+ _remove_older_files(dir, preserve_moment)
+
+
+def cleanup_movies():
+ logging.debug('cleaning up movies...')
+
+ for camera_id in config.get_camera_ids():
+ camera_config = config.get_camera(camera_id)
+ if camera_config.get('@proto') != 'v4l2':
+ continue
+
+ preserve_movies = camera_config.get('@preserve_movies')
+ if preserve_movies == 0:
+ return # preserve forever
+
+ preserve_moment = datetime.datetime.now() - datetime.timedelta(days=preserve_movies)
+
+ target_dir = camera_config.get('target_dir')
+ movie_filename = camera_config.get('movie_filename')
+
+ if movie_filename:
+ snapshot_path = os.path.join(target_dir, movie_filename)
+ snapshot_path = os.path.dirname(snapshot_path)
+ _remove_older_files(dir, preserve_moment)
def get_main(as_lines=False):
global _main_config_cache
- if not as_lines and _main_config_cache:
+ if not as_lines and _main_config_cache is not None:
return _main_config_cache
config_file_path = os.path.join(settings.PROJECT_PATH, _MAIN_CONFIG_FILE_PATH)
def get_camera_ids():
global _camera_ids_cache
- if _camera_ids_cache:
+ if _camera_ids_cache is not None:
return _camera_ids_cache
config_path = settings.CONF_PATH
def get_camera(camera_id, as_lines=False):
global _camera_config_cache
- if not as_lines and _camera_config_cache and camera_id in _camera_config_cache:
+ if not as_lines and _camera_config_cache is not None and camera_id in _camera_config_cache:
return _camera_config_cache[camera_id]
camera_config_path = _CAMERA_CONFIG_FILE_PATH % {'id': camera_id}
class SnapshotHandler(BaseHandler):
- #@asynchronous TODO don't forget about me
+ @asynchronous
def get(self, camera_id, op, filename=None):
if camera_id is not None:
camera_id = int(camera_id)
/* text validators */
makeTextValidator($('#adminUsernameEntry'), true);
- makeTextValidator($('#adminPasswordEntry'), true);
makeTextValidator($('#normalUsernameEntry'), true);
- makeTextValidator($('#normalPasswordEntry'), true);
makeTextValidator($('#deviceNameEntry'), true);
makeTextValidator($('#networkServerEntry'), true);
makeTextValidator($('#networkShareNameEntry'), true);