@asynchronous
def post(self, camera_id, op, filename=None, group=None):
+ if group == '/': # ungrouped
+ group = ''
+
if camera_id is not None:
camera_id = int(camera_id)
if camera_id not in config.get_camera_ids():
camera_config = config.get_camera(camera_id)
if key:
- logging.debug('serving zip file for group %(group)s of camera %(id)s with key %(key)s' % {
- 'group': group, 'id': camera_id, 'key': key})
+ logging.debug('serving zip file for group "%(group)s" of camera %(id)s with key %(key)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id, 'key': key})
if utils.local_motion_camera(camera_config):
data = mediafiles.get_prepared_cache(key)
raise HTTPError(400, 'unknown operation')
else: # prepare
- logging.debug('preparing zip file for group %(group)s of camera %(id)s' % {
- 'group': group, 'id': camera_id})
+ logging.debug('preparing zip file for group "%(group)s" of camera %(id)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id})
if utils.local_motion_camera(camera_config):
def on_zip(data):
return self.finish_json({'error': 'Failed to create zip file.'})
key = mediafiles.set_prepared_cache(data)
- logging.debug('prepared zip file for group %(group)s of camera %(id)s with key %(key)s' % {
- 'group': group, 'id': camera_id, 'key': key})
+ logging.debug('prepared zip file for group "%(group)s" of camera %(id)s with key %(key)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id, 'key': key})
self.finish_json({'key': key})
mediafiles.get_zipped_content(camera_config, media_type='picture', group=group, callback=on_zip)
camera_config = config.get_camera(camera_id)
if key: # download
- logging.debug('serving timelapse movie for group %(group)s of camera %(id)s with key %(key)s' % {
- 'group': group, 'id': camera_id, 'key': key})
+ 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})
if utils.local_motion_camera(camera_config):
data = mediafiles.get_prepared_cache(key)
raise HTTPError(400, 'unknown operation')
elif check:
- logging.debug('checking timelapse movie status for group %(group)s of camera %(id)s' % {
- 'group': group, 'id': camera_id})
+ logging.debug('checking timelapse movie status for group "%(group)s" of camera %(id)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id})
if utils.local_motion_camera(camera_config):
status = mediafiles.check_timelapse_movie()
if status['progress'] == -1 and status['data']:
key = mediafiles.set_prepared_cache(status['data'])
- logging.debug('prepared timelapse movie for group %(group)s of camera %(id)s with key %(key)s' % {
- 'group': group, 'id': camera_id, 'key': key})
+ logging.debug('prepared timelapse movie for group "%(group)s" of camera %(id)s with key %(key)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id, 'key': key})
self.finish_json({'key': key, 'progress': -1})
else:
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, 'id': camera_id, 'framerate': framerate, 'int': interval})
+ 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})
if utils.local_motion_camera(camera_config):
status = mediafiles.check_timelapse_movie()
@BaseHandler.auth(admin=True)
def delete_all(self, camera_id, group):
- logging.debug('deleting picture group %(group)s of camera %(id)s' % {
- 'group': group, 'id': camera_id})
+ logging.debug('deleting picture group "%(group)s" of camera %(id)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id})
camera_config = config.get_camera(camera_id)
if utils.local_motion_camera(camera_config):
elif utils.remote_camera(camera_config):
def on_response(response=None, error=None):
if error:
- return self.finish_json({'error': 'Failed to delete picture group from %(url)s: %(msg)s.' % {
+ return self.finish_json({'error': 'Failed to delete picture group at %(url)s: %(msg)s.' % {
'url': remote.pretty_camera_url(camera_config), 'msg': error}})
self.finish_json()
@asynchronous
def post(self, camera_id, op, filename=None, group=None):
+ if group == '/': # ungrouped
+ group = ''
+
if camera_id is not None:
camera_id = int(camera_id)
if camera_id not in config.get_camera_ids():
@BaseHandler.auth(admin=True)
def delete_all(self, camera_id, group):
- logging.debug('deleting movie group %(group)s of camera %(id)s' % {
- 'group': group, 'id': camera_id})
+ logging.debug('deleting movie group "%(group)s" of camera %(id)s' % {
+ 'group': group or 'ungrouped', 'id': camera_id})
camera_config = config.get_camera(camera_id)
if utils.local_motion_camera(camera_config):
elif utils.remote_camera(camera_config):
def on_response(response=None, error=None):
if error:
- return self.finish_json({'error': 'Failed to delete movie group from %(url)s: %(msg)s.' % {
+ return self.finish_json({'error': 'Failed to delete movie group at %(url)s: %(msg)s.' % {
'url': remote.pretty_camera_url(camera_config), 'msg': error}})
self.finish_json()
def make_zipped_content(local_config, media_type, group, callback):
scheme, host, port, username, password, path, camera_id = _remote_params(local_config)
- logging.debug('preparing zip file for group %(group)s of remote camera %(id)s on %(url)s' % {
- 'group': group,
+ logging.debug('preparing zip file for group "%(group)s" of remote camera %(id)s on %(url)s' % {
+ 'group': group or 'ungrouped',
'id': camera_id,
'url': pretty_camera_url(local_config)})
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' % {
- 'group': group,
+ logging.error('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)})
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' % {
- 'group': group,
+ logging.debug('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,
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' % {
- 'group': group,
+ 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' % {
+ 'group': group or 'ungrouped',
'id': camera_id,
'url': pretty_camera_url(local_config),
'int': interval,
def del_media_group(local_config, group, media_type, callback):
scheme, host, port, username, password, path, camera_id = _remote_params(local_config)
- logging.debug('deleting group %(group)s of remote camera %(id)s on %(url)s' % {
- 'group': group,
+ logging.debug('deleting group "%(group)s" of remote camera %(id)s on %(url)s' % {
+ 'group': group or 'ungrouped',
'id': camera_id,
'url': pretty_camera_url(local_config)})
def on_response(response):
if response.error:
- logging.error('failed to delete group %(group)s of remote camera %(id)s on %(url)s: %(msg)s' % {
- 'group': group,
+ logging.error('failed to delete 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)})
(r'^/config/(?P<op>add|list|backup|restore)/?$', handlers.ConfigHandler),
(r'^/picture/(?P<camera_id>\d+)/(?P<op>current|list|frame)/?$', handlers.PictureHandler),
(r'^/picture/(?P<camera_id>\d+)/(?P<op>download|preview|delete)/(?P<filename>.+?)/?$', handlers.PictureHandler),
- (r'^/picture/(?P<camera_id>\d+)/(?P<op>zipped|timelapse|delete_all)/(?P<group>.+?)/?$', handlers.PictureHandler),
+ (r'^/picture/(?P<camera_id>\d+)/(?P<op>zipped|timelapse|delete_all)/(?P<group>.*?)/?$', handlers.PictureHandler),
(r'^/movie/(?P<camera_id>\d+)/(?P<op>list)/?$', handlers.MovieHandler),
(r'^/movie/(?P<camera_id>\d+)/(?P<op>download|preview|delete)/(?P<filename>.+?)/?$', handlers.MovieHandler),
- (r'^/movie/(?P<camera_id>\d+)/(?P<op>delete_all)/(?P<group>.+?)/?$', handlers.MovieHandler),
+ (r'^/movie/(?P<camera_id>\d+)/(?P<op>delete_all)/(?P<group>.*?)/?$', handlers.MovieHandler),
(r'^/_relay_event/?$', handlers.RelayEventHandler),
(r'^/log/(?P<name>\w+)/?$', handlers.LogHandler),
(r'^/update/?$', handlers.UpdateHandler),
$.ajax(options);
}
+function getCookie(name) {
+ if (document.cookie.length <= 0) {
+ return null;
+ }
+
+ var start = document.cookie.indexOf(name + '=');
+ if (start == -1) {
+ return null;
+ }
+
+ var start = start + name.length + 1;
+ var end = document.cookie.indexOf(';', start);
+ if (end == -1) {
+ end = document.cookie.length;
+ }
+
+ return unescape(document.cookie.substring(start, end));
+}
+
+function setCookie(name, value, days) {
+ var date, expires;
+ if (days) {
+ date = new Date();
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
+ expires = 'expires=' + date.toGMTString();
+ }
+ else {
+ expires = '';
+ }
+
+ document.cookie = name + '=' + value + '; ' + expires + '; path=/';
+}
+
+function remCookie(name) {
+ document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
+}
+
+function showErrorMessage(message) {
+ if (message == null || message == true) {
+ message = 'An error occurred. Refreshing is recommended.';
+ }
+
+ showPopupMessage(message, 'error');
+}
+
+function doLogout() {
+ setCookie('username', '_');
+ window.location.reload(true);
+}
+
+
+ /* Object utilities */
+
Object.keys = Object.keys || (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty;
var hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString');
}
};
+
+ /* Array utilities */
+
Array.prototype.indexOf = Array.prototype.indexOf || function (obj) {
for (var i = 0; i < this.length; i++) {
if (this[i] === obj) {
});
};
+
+ /* String utilities */
+
String.prototype.startsWith = String.prototype.startsWith || function (str) {
return (this.substr(0, str.length) === str);
};
return s.toString();
};
-function getCookie(name) {
- if (document.cookie.length <= 0) {
- return null;
- }
-
- var start = document.cookie.indexOf(name + '=');
- if (start == -1) {
- return null;
- }
-
- var start = start + name.length + 1;
- var end = document.cookie.indexOf(';', start);
- if (end == -1) {
- end = document.cookie.length;
- }
+String.prototype.format = function () {
+ var text = this;
- return unescape(document.cookie.substring(start, end));
-}
-
-function setCookie(name, value, days) {
- var date, expires;
- if (days) {
- date = new Date();
- date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
- expires = 'expires=' + date.toGMTString();
+ var rex = new RegExp('%[sdf]');
+ var match, i = 0;
+ while (match = text.match(rex)) {
+ text = text.substring(0, match.index) + arguments[i] + text.substring(match.index + 2);
+ i++;
}
- else {
- expires = '';
+
+ if (i) { /* %s format used */
+ return text;
}
-
- document.cookie = name + '=' + value + '; ' + expires + '; path=/';
-}
-
-function remCookie(name) {
- document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
-}
-
-function showErrorMessage(message) {
- if (message == null || message == true) {
- message = 'An error occurred. Refreshing is recommended.';
+
+ var keywords = arguments[0];
+
+ for (var key in keywords) {
+ text = text.replace('%(' + key + ')s', "" + keywords[key]);
+ text = text.replace('%(' + key + ')d', "" + keywords[key]);
+ text = text.replace('%(' + key + ')f', "" + keywords[key]);
}
- showPopupMessage(message, 'error');
-}
-
-function doLogout() {
- setCookie('username', '_');
- window.location.reload(true);
-}
-
+ return text;
+};
-/* UI initialization */
+
+ /* UI initialization */
function initUI() {
/* checkboxes */
}
function doDeleteAllFiles(mediaType, cameraId, groupKey, callback) {
- runConfirmDialog('Really delete all ' + mediaType + 's in ' + groupKey + '?', function () {
+ var msg;
+ if (groupKey) {
+ if (mediaType == 'picture') {
+ msg = 'Really delete all pictures from "%(group)s"?'.format({group: groupKey});
+ }
+ else {
+ msg = 'Really delete all movies from "%(group)s"?'.format({group: groupKey});
+ }
+ }
+ else {
+ if (mediaType == 'picture') {
+ msg = 'Really delete all ungrouped pictures?';
+ }
+ else {
+ msg = 'Really delete all ungrouped movies?';
+ }
+ }
+
+ runConfirmDialog(msg, function () {
showModalDialog('<div class="modal-progress"></div>', null, null, true);
- ajax('POST', basePath + mediaType + '/' + cameraId + '/delete_all/' + groupKey + '/', null, function (data) {
+ if (groupKey) {
+ groupKey += '/';
+ }
+ ajax('POST', basePath + mediaType + '/' + cameraId + '/delete_all/' + groupKey, null, function (data) {
hideModalDialog(); /* progress */
hideModalDialog(); /* confirm */