From daa852c7d09e13b2ca1137a7d33d1aaa0032dcfb Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Sat, 9 Nov 2013 20:12:10 +0200 Subject: [PATCH] media files are now made of *pictures* and *movies* --- doc/todo.txt | 1 + motioneye.py | 6 ++--- settings_default.py | 2 +- src/config.py | 6 ++--- src/handlers.py | 41 +++++++++++++++++++++++++---- src/{cleanup.py => mediafiles.py} | 14 ++++++---- src/remote.py | 43 ++++++++++++++++++++++++++++--- src/server.py | 4 +-- static/js/main.js | 6 ++--- templates/main.html | 4 +-- 10 files changed, 99 insertions(+), 28 deletions(-) rename src/{cleanup.py => mediafiles.py} (91%) diff --git a/doc/todo.txt b/doc/todo.txt index dc1a2ac..e7968cd 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -6,6 +6,7 @@ -> style scroll bars -> hint text next to section titles -> clickable hints +-> update mechanism should not say "ok" until the server reloads -> implement working schedule (add another combo deciding what to do during working schedule) -> implement notifications diff --git a/motioneye.py b/motioneye.py index 911b488..f677f24 100755 --- a/motioneye.py +++ b/motioneye.py @@ -178,7 +178,7 @@ def _start_motion(): def _start_cleanup(): - import cleanup + import mediafiles def do_cleanup(): ioloop = tornado.ioloop.IOLoop.instance() @@ -186,8 +186,8 @@ def _start_cleanup(): return try: - cleanup.cleanup_images() - cleanup.cleanup_movies() + mediafiles.cleanup_pictures() + mediafiles.cleanup_movies() except Exception as e: logging.error('failed to cleanup media files: %(msg)s' % { diff --git a/settings_default.py b/settings_default.py index cce949a..46898be 100644 --- a/settings_default.py +++ b/settings_default.py @@ -32,7 +32,7 @@ PORT = 8765 # interval in seconds at which motionEye checks if motion is running MOTION_CHECK_INTERVAL = 10 -# interval in seconds at which the janitor is called to remove old images and movies +# interval in seconds at which the janitor is called to remove old pictures and movies CLEANUP_INTERVAL = 43200 # timeout in seconds to wait for responses when contacting a remote server diff --git a/src/config.py b/src/config.py index 851e64a..657ba3a 100644 --- a/src/config.py +++ b/src/config.py @@ -442,7 +442,7 @@ def camera_ui_to_dict(ui): 'snapshot_interval': 0, 'jpeg_filename': '', 'snapshot_filename': '', - '@preserve_images': int(ui.get('preserve_images', 0)), + '@preserve_pictures': int(ui.get('preserve_pictures', 0)), # movies 'ffmpeg_cap_new': ui.get('motion_movies', False), @@ -616,7 +616,7 @@ def camera_dict_to_ui(data): 'image_file_name': '%Y-%m-%d-%H-%M-%S', 'image_quality': 85, 'snapshot_interval': 0, - 'preserve_images': data['@preserve_images'], + 'preserve_pictures': data['@preserve_pictures'], # motion movies 'motion_movies': data.get('ffmpeg_cap_new'), @@ -983,7 +983,7 @@ def _set_default_motion_camera(data): data.setdefault('snapshot_interval', 0) data.setdefault('snapshot_filename', '') data.setdefault('quality', 85) - data.setdefault('@preserve_images', 0) + data.setdefault('@preserve_pictures', 0) data.setdefault('ffmpeg_variable_bitrate', 0) data.setdefault('ffmpeg_bps', 400000) diff --git a/src/handlers.py b/src/handlers.py index 309ceae..cb9d5fa 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -513,7 +513,7 @@ class ConfigHandler(BaseHandler): self.finish_json() -class SnapshotHandler(BaseHandler): +class PictureHandler(BaseHandler): @asynchronous def get(self, camera_id, op, filename=None): if camera_id is not None: @@ -553,7 +553,7 @@ class SnapshotHandler(BaseHandler): else: self.finish(jpg) - remote.current_snapshot( + remote.current_picture( camera_config['@host'], camera_config['@port'], camera_config['@username'], @@ -562,15 +562,46 @@ class SnapshotHandler(BaseHandler): @BaseHandler.auth() def list(self, camera_id): - logging.debug('listing snapshots for camera %(id)s' % {'id': camera_id}) + logging.debug('listing pictures for camera %(id)s' % {'id': camera_id}) - # TODO implement me + if camera_id not in config.get_camera_ids(): + raise HTTPError(404, 'no such camera') + + camera_config = config.get_camera(camera_id) + if camera_config['@proto'] != 'v4l2': + def on_response(remote_list): + camera_url = remote.make_remote_camera_url( + camera_config.get('@host'), + camera_config.get('@port'), + camera_config.get('@remote_camera_id')) + + camera_full_url = camera_config['@proto'] + '://' + camera_url + + if remote_list is None: + return self.finish_json({'error': 'Failed to get picture list for %(url)s.' % { + 'url': camera_full_url}}) + + self.finish_json(remote_list) + + remote.list_pictures( + camera_config.get('@host'), + camera_config.get('@port'), + camera_config.get('@username'), + camera_config.get('@password'), + camera_config.get('@remote_camera_id'), on_response) + + else: + pictures = [] + + #for + + self.finish_json({'pictures': pictures}) self.finish_json() @BaseHandler.auth() def download(self, camera_id, filename): - logging.debug('downloading snapshot %(filename)s of camera %(id)s' % { + logging.debug('downloading picture %(filename)s of camera %(id)s' % { 'filename': filename, 'id': camera_id}) # TODO implement me diff --git a/src/cleanup.py b/src/mediafiles.py similarity index 91% rename from src/cleanup.py rename to src/mediafiles.py index e63dad1..e423698 100644 --- a/src/cleanup.py +++ b/src/mediafiles.py @@ -41,19 +41,19 @@ def _remove_older_files(dir, moment, exts): os.remove(full_path) -def cleanup_images(): - logging.debug('cleaning up images...') +def cleanup_pictures(): + logging.debug('cleaning up pictures...') 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: + preserve_pictures = camera_config.get('@preserve_pictures') + if preserve_pictures == 0: return # preserve forever - preserve_moment = datetime.datetime.now() - datetime.timedelta(days=preserve_images) + preserve_moment = datetime.datetime.now() - datetime.timedelta(days=preserve_pictures) target_dir = camera_config.get('target_dir') _remove_older_files(target_dir, preserve_moment, exts=['.jpg', '.png']) @@ -75,3 +75,7 @@ def cleanup_movies(): target_dir = camera_config.get('target_dir') _remove_older_files(target_dir, preserve_moment, exts=['.avi']) + + +def list_pictures(config): + pass \ No newline at end of file diff --git a/src/remote.py b/src/remote.py index 216b4e8..d4afebf 100644 --- a/src/remote.py +++ b/src/remote.py @@ -173,15 +173,15 @@ def set_preview(host, port, username, password, camera_id, controls, callback): http_client.fetch(request, on_response) -def current_snapshot(host, port, username, password, camera_id, callback): +def current_picture(host, port, username, password, camera_id, callback): global _snapshot_cache - logging.debug('getting current snapshot for remote camera %(id)s on %(host)s:%(port)s' % { + logging.debug('getting current picture for remote camera %(id)s on %(host)s:%(port)s' % { 'id': camera_id, 'host': host, 'port': port}) - request = _make_request(host, port, username, password, '/snapshot/%(id)s/current/' % {'id': camera_id}) + request = _make_request(host, port, username, password, '/picture/%(id)s/current/' % {'id': camera_id}) cached = _snapshot_cache.setdefault(request.url, {'pending': 0, 'jpg': None}) if cached['pending'] > 0: # a pending request for this snapshot exists @@ -192,7 +192,7 @@ def current_snapshot(host, port, username, password, camera_id, callback): cached['jpg'] = response.body if response.error: - logging.error('failed to get current snapshot for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % { + logging.error('failed to get current picture for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % { 'id': camera_id, 'host': host, 'port': port, @@ -206,3 +206,38 @@ def current_snapshot(host, port, username, password, camera_id, callback): http_client = AsyncHTTPClient() http_client.fetch(request, on_response) + + +def list_pictures(host, port, username, password, camera_id, callback): + logging.debug('getting picture list for remote camera %(id)s on %(host)s:%(port)s' % { + 'id': camera_id, + 'host': host, + 'port': port}) + + request = _make_request(host, port, username, password, '/picture/%(id)s/list/' % {'id': camera_id}) + + def on_response(response): + if response.error: + logging.error('failed to get picture list for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % { + 'id': camera_id, + 'host': host, + 'port': port, + 'msg': unicode(response.error)}) + + return callback(None) + + try: + response = json.loads(response.body) + + except Exception as e: + logging.error('failed to decode json answer from %(host)s:%(port)s: %(msg)s' % { + 'host': host, + 'port': port, + 'msg': unicode(e)}) + + return callback(None) + + return callback(response['pictures']) + + http_client = AsyncHTTPClient() + http_client.fetch(request, on_response) diff --git a/src/server.py b/src/server.py index d35429c..fcac5fa 100644 --- a/src/server.py +++ b/src/server.py @@ -44,8 +44,8 @@ application = Application( (r'^/config/main/(?Pset|get)/?$', handlers.ConfigHandler), (r'^/config/(?P\d+)/(?Pget|set|rem|set_preview)/?$', handlers.ConfigHandler), (r'^/config/(?Padd|list|list_devices)/?$', handlers.ConfigHandler), - (r'^/snapshot/(?P\d+)/(?Pcurrent|list)/?$', handlers.SnapshotHandler), - (r'^/snapshot/(?P\d+)/(?Pdownload)/(?P.+)/?$', handlers.SnapshotHandler), + (r'^/picture/(?P\d+)/(?Pcurrent|list)/?$', handlers.PictureHandler), + (r'^/picture/(?P\d+)/(?Pdownload)/(?P.+)/?$', handlers.PictureHandler), (r'^/movie/(?P\d+)/(?Plist)/?$', handlers.MovieHandler), (r'^/movie/(?P\d+)/(?Pdownload)/(?P.+)/?$', handlers.MovieHandler), (r'^/update/?$', handlers.UpdateHandler), diff --git a/static/js/main.js b/static/js/main.js index e98b903..234fc96 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -505,7 +505,7 @@ function cameraUi2Dict() { 'image_quality': $('#imageQualitySlider').val(), 'capture_mode': $('#captureModeSelect').val(), 'snapshot_interval': $('#snapshotIntervalEntry').val(), - 'preserve_images': $('#preserveImagesSelect').val(), + 'preserve_pictures': $('#preservePicturesSelect').val(), /* motion movies */ 'motion_movies': $('#motionMoviesSwitch')[0].checked, @@ -629,7 +629,7 @@ function dict2CameraUi(dict) { $('#imageQualitySlider').val(dict['image_quality']); $('#captureModeSelect').val(dict['capture_mode']); $('#snapshotIntervalEntry').val(dict['snapshot_interval']); - $('#preserveImagesSelect').val(dict['preserve_images']); + $('#preservePicturesSelect').val(dict['preserve_pictures']); /* motion movies */ $('#motionMoviesSwitch')[0].checked = dict['motion_movies']; @@ -1466,7 +1466,7 @@ function refreshCameraFrames() { timestamp /= 500; } timestamp = Math.round(timestamp); - img.src = '/snapshot/' + cameraId + '/current/?_=' + timestamp; + img.src = '/picture/' + cameraId + '/current/?_=' + timestamp; } var cameraFrames; diff --git a/templates/main.html b/templates/main.html index 25a05a7..13dad74 100644 --- a/templates/main.html +++ b/templates/main.html @@ -291,9 +291,9 @@ ? - Preserve Images + Preserve Pictures - -- 2.39.5