From: Calin Crisan Date: Tue, 15 Sep 2015 19:54:45 +0000 (+0300) Subject: major URL refactoring; running behind a reverse-proxy works now X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=8c52d4bf555716f46fe321688f750ae9bbef1349;p=motioneye-debian major URL refactoring; running behind a reverse-proxy works now --- diff --git a/extra/motioneye.conf.sample b/extra/motioneye.conf.sample index aff425b..79503c5 100644 --- a/extra/motioneye.conf.sample +++ b/extra/motioneye.conf.sample @@ -1,8 +1,8 @@ -# static files (.css, .js etc) are served at this root url; +# the base URL path at which motionEye lives # change this if you run motionEye behind a reverse proxy (e.g. nginx), -# and you want static files to be served directly by it -static_url /static/ +# and you want to make motionEye accessible at a specific base path (e.g. /cams) +#base_path /cams # path to the configuration directory (must be writable by motionEye) conf_path /etc/motioneye diff --git a/motioneye/__init__.py b/motioneye/__init__.py index b185f8e..511cacd 100644 --- a/motioneye/__init__.py +++ b/motioneye/__init__.py @@ -1,2 +1,2 @@ -VERSION = "0.27.2" +VERSION = "0.27.2-git" diff --git a/motioneye/config.py b/motioneye/config.py index bc953a3..1160554 100644 --- a/motioneye/config.py +++ b/motioneye/config.py @@ -462,7 +462,7 @@ def add_camera(device_details): else: host = device_details['username'] + '@' + host - device_details['url'] = urlparse.urlunparse((device_details['scheme'], host, device_details['uri'], '', '', '')) + device_details['url'] = urlparse.urlunparse((device_details['scheme'], host, device_details['path'], '', '', '')) # determine the last camera id camera_ids = get_camera_ids() @@ -477,20 +477,20 @@ def add_camera(device_details): camera_config = {'@enabled': True} if proto == 'v4l2': # find a suitable resolution - for (w, h) in v4l2ctl.list_resolutions(device_details['uri']): + for (w, h) in v4l2ctl.list_resolutions(device_details['path']): if w > 300: camera_config['width'] = w camera_config['height'] = h break - camera_config['videodevice'] = device_details['uri'] + camera_config['videodevice'] = device_details['path'] elif proto == 'motioneye': camera_config['@proto'] = 'motioneye' camera_config['@scheme'] = device_details['scheme'] camera_config['@host'] = device_details['host'] camera_config['@port'] = device_details['port'] - camera_config['@uri'] = device_details['uri'] + camera_config['@path'] = device_details['path'] camera_config['@username'] = device_details['username'] camera_config['@password'] = device_details['password'] camera_config['@remote_camera_id'] = device_details['remote_camera_id'] diff --git a/motioneye/handlers.py b/motioneye/handlers.py index 9772f2b..0215b40 100644 --- a/motioneye/handlers.py +++ b/motioneye/handlers.py @@ -226,7 +226,7 @@ class ConfigHandler(BaseHandler): for key, value in local_config.items(): remote_ui_config[key.replace('@', '')] = value - # replace the real device URI with the remote camera URL + # replace the real device url with the remote camera path remote_ui_config['device_url'] = remote.pretty_camera_url(local_config) self.finish_json(remote_ui_config) diff --git a/motioneye/relayevent.py b/motioneye/relayevent.py index 166287b..f22dd93 100644 --- a/motioneye/relayevent.py +++ b/motioneye/relayevent.py @@ -107,14 +107,14 @@ def main(parser, args): admin_username, admin_password = get_admin_credentials() - uri = '/_relay_event/?event=%(event)s&thread_id=%(thread_id)s&_username=%(username)s' % { + path = '/_relay_event/?event=%(event)s&thread_id=%(thread_id)s&_username=%(username)s' % { 'username': admin_username, 'thread_id': options.thread_id, 'event': options.event} - signature = utils.compute_signature('POST', uri, '', admin_password) + signature = utils.compute_signature('POST', path, '', admin_password) - url = 'http://127.0.0.1:%(port)s' + uri + '&_signature=' + signature + url = 'http://127.0.0.1:%(port)s' + path + '&_signature=' + signature url = url % {'port': settings.PORT} try: diff --git a/motioneye/remote.py b/motioneye/remote.py index 374e410..9533cbc 100644 --- a/motioneye/remote.py +++ b/motioneye/remote.py @@ -28,13 +28,13 @@ import utils _DOUBLE_SLASH_REGEX = re.compile('//+') -def _make_request(scheme, host, port, username, password, uri, method='GET', data=None, query=None, timeout=None): - uri = _DOUBLE_SLASH_REGEX.sub('/', uri) - url = '%(scheme)s://%(host)s%(port)s%(uri)s' % { +def _make_request(scheme, host, port, username, password, path, method='GET', data=None, query=None, timeout=None): + path = _DOUBLE_SLASH_REGEX.sub('/', path) + url = '%(scheme)s://%(host)s%(port)s%(path)s' % { 'scheme': scheme, 'host': host, 'port': ':' + str(port) if port else '', - 'uri': uri or ''} + 'path': path or ''} query = dict(query or {}) query['_username'] = username or '' @@ -78,14 +78,14 @@ def pretty_camera_url(local_config, camera=True): scheme = local_config.get('@scheme', local_config.get('scheme')) or 'http' host = local_config.get('@host', local_config.get('host')) port = local_config.get('@port', local_config.get('port')) - uri = local_config.get('@uri', local_config.get('uri')) or '' + path = local_config.get('@path', local_config.get('path')) or '' url = scheme + '://' + host if port and str(port) not in ['80', '443']: url += ':' + str(port) - if uri: - url += uri + if path: + url += path if url.endswith('/'): url = url[:-1] @@ -107,17 +107,17 @@ def _remote_params(local_config): local_config.get('@port', local_config.get('port')), local_config.get('@username', local_config.get('username')), local_config.get('@password', local_config.get('password')), - local_config.get('@uri', local_config.get('uri')) or '', + local_config.get('@path', local_config.get('path')) or '', local_config.get('@remote_camera_id', local_config.get('remote_camera_id'))) def list(local_config, callback): - scheme, host, port, username, password, uri, _ = _remote_params(local_config) + scheme, host, port, username, password, path, _ = _remote_params(local_config) logging.debug('listing remote cameras on %(url)s' % { 'url': pretty_camera_url(local_config, camera=False)}) - request = _make_request(scheme, host, port, username, password, uri + '/config/list/') + request = _make_request(scheme, host, port, username, password, path + '/config/list/') def on_response(response): def make_camera_response(c): @@ -156,13 +156,13 @@ def list(local_config, callback): def get_config(local_config, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('getting config 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, uri + '/config/%(id)s/get/' % {'id': camera_id}) + request = _make_request(scheme, host, port, username, password, path + '/config/%(id)s/get/' % {'id': camera_id}) def on_response(response): if response.error: @@ -198,7 +198,7 @@ def set_config(local_config, ui_config, callback): port = local_config.get('@port', local_config.get('port')) username = local_config.get('@username', local_config.get('username')) password = local_config.get('@password', local_config.get('password')) - uri = local_config.get('@uri', local_config.get('uri')) or '' + path = local_config.get('@path', local_config.get('path')) or '' camera_id = local_config.get('@remote_camera_id', local_config.get('remote_camera_id')) logging.debug('setting config for remote camera %(id)s on %(url)s' % { @@ -207,7 +207,7 @@ def set_config(local_config, ui_config, callback): ui_config = json.dumps(ui_config) - request = _make_request(scheme, host, port, username, password, uri + '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=ui_config) + request = _make_request(scheme, host, port, username, password, path + '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=ui_config) def on_response(response): if response.error: @@ -225,7 +225,7 @@ def set_config(local_config, ui_config, callback): def set_preview(local_config, controls, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('setting preview for remote camera %(id)s on %(url)s' % { 'id': camera_id, @@ -233,7 +233,7 @@ def set_preview(local_config, controls, callback): data = json.dumps(controls) - request = _make_request(scheme, host, port, username, password, uri + '/config/%(id)s/set_preview/' % {'id': camera_id}, method='POST', data=data) + request = _make_request(scheme, host, port, username, password, path + '/config/%(id)s/set_preview/' % {'id': camera_id}, method='POST', data=data) def on_response(response): if response.error: @@ -251,7 +251,7 @@ def set_preview(local_config, controls, callback): def get_current_picture(local_config, width, height, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('getting current picture for remote camera %(id)s on %(url)s' % { 'id': camera_id, @@ -265,7 +265,7 @@ def get_current_picture(local_config, width, height, callback): if height: query['height'] = str(height) - request = _make_request(scheme, host, port, username, password, uri + '/picture/%(id)s/current/' % {'id': camera_id}, query=query) + request = _make_request(scheme, host, port, username, password, path + '/picture/%(id)s/current/' % {'id': camera_id}, query=query) def on_response(response): motion_detected = False @@ -292,7 +292,7 @@ def get_current_picture(local_config, width, height, callback): def list_media(local_config, media_type, prefix, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('getting media list for remote camera %(id)s on %(url)s' % { 'id': camera_id, @@ -303,7 +303,7 @@ 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, uri + '/%(media_type)s/%(id)s/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) def on_response(response): @@ -332,20 +332,20 @@ def list_media(local_config, media_type, prefix, callback): def get_media_content(local_config, filename, media_type, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('downloading file %(filename)s of remote camera %(id)s on %(url)s' % { 'filename': filename, 'id': camera_id, 'url': pretty_camera_url(local_config)}) - uri += '/%(media_type)s/%(id)s/download/%(filename)s' % { + path += '/%(media_type)s/%(id)s/download/%(filename)s' % { 'media_type': media_type, 'id': camera_id, 'filename': filename} # 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, uri, timeout=10 * settings.REMOTE_REQUEST_TIMEOUT) + request = _make_request(scheme, host, port, username, password, path, timeout=10 * settings.REMOTE_REQUEST_TIMEOUT) def on_response(response): if response.error: @@ -364,20 +364,20 @@ def get_media_content(local_config, filename, media_type, callback): def make_zipped_content(local_config, media_type, group, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + 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, 'id': camera_id, 'url': pretty_camera_url(local_config)}) - prepare_uri = uri + '/%(media_type)s/%(id)s/zipped/%(group)s/' % { + prepare_path = path + '/%(media_type)s/%(id)s/zipped/%(group)s/' % { 'media_type': media_type, 'id': camera_id, 'group': group} # timeout here is 100 times larger than usual - we expect a big delay - request = _make_request(scheme, host, port, username, password, prepare_uri, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT) + request = _make_request(scheme, host, port, username, password, prepare_path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT) def on_response(response): if response.error: @@ -406,13 +406,13 @@ def make_zipped_content(local_config, media_type, group, callback): def get_zipped_content(local_config, media_type, key, group, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) 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, uri + '/%(media_type)s/%(id)s/zipped/%(group)s/?key=%(key)s' % { + 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, @@ -439,7 +439,7 @@ 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, uri, camera_id = _remote_params(local_config) + 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, @@ -448,13 +448,13 @@ def make_timelapse_movie(local_config, framerate, interval, group, callback): 'int': interval, 'url': pretty_camera_url(local_config)}) - uri += '/picture/%(id)s/timelapse/%(group)s/?interval=%(int)s&framerate=%(framerate)s' % { + path += '/picture/%(id)s/timelapse/%(group)s/?interval=%(int)s&framerate=%(framerate)s' % { 'id': camera_id, 'int': interval, 'framerate': framerate, 'group': group} - request = _make_request(scheme, host, port, username, password, uri, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT) + request = _make_request(scheme, host, port, username, password, path, timeout=100 * settings.REMOTE_REQUEST_TIMEOUT) def on_response(response): if response.error: @@ -485,13 +485,13 @@ def make_timelapse_movie(local_config, framerate, interval, group, callback): def check_timelapse_movie(local_config, group, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) 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, uri + '/picture/%(id)s/timelapse/%(group)s/?check=true' % { + request = _make_request(scheme, host, port, username, password, path + '/picture/%(id)s/timelapse/%(group)s/?check=true' % { 'id': camera_id, 'group': group}) @@ -521,13 +521,13 @@ def check_timelapse_movie(local_config, group, callback): def get_timelapse_movie(local_config, key, group, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) 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, uri + '/picture/%(id)s/timelapse/%(group)s/?key=%(key)s' % { + 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}, @@ -553,14 +553,14 @@ def get_timelapse_movie(local_config, key, group, callback): def get_media_preview(local_config, filename, media_type, width, height, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('getting file preview for %(filename)s of remote camera %(id)s on %(url)s' % { 'filename': filename, 'id': camera_id, 'url': pretty_camera_url(local_config)}) - uri += '/%(media_type)s/%(id)s/preview/%(filename)s' % { + path += '/%(media_type)s/%(id)s/preview/%(filename)s' % { 'media_type': media_type, 'id': camera_id, 'filename': filename} @@ -573,7 +573,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, uri, query=query) + request = _make_request(scheme, host, port, username, password, path, query=query) def on_response(response): if response.error: @@ -592,19 +592,19 @@ def get_media_preview(local_config, filename, media_type, width, height, callbac def del_media_content(local_config, filename, media_type, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('deleting file %(filename)s of remote camera %(id)s on %(url)s' % { 'filename': filename, 'id': camera_id, 'url': pretty_camera_url(local_config)}) - uri += '/%(media_type)s/%(id)s/delete/%(filename)s' % { + path += '/%(media_type)s/%(id)s/delete/%(filename)s' % { 'media_type': media_type, 'id': camera_id, 'filename': filename} - request = _make_request(scheme, host, port, username, password, uri, method='POST', data='{}', timeout=settings.REMOTE_REQUEST_TIMEOUT) + request = _make_request(scheme, host, port, username, password, path, method='POST', data='{}', timeout=settings.REMOTE_REQUEST_TIMEOUT) def on_response(response): if response.error: @@ -623,19 +623,19 @@ def del_media_content(local_config, filename, media_type, callback): def del_media_group(local_config, group, media_type, callback): - scheme, host, port, username, password, uri, camera_id = _remote_params(local_config) + 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, 'id': camera_id, 'url': pretty_camera_url(local_config)}) - uri += '/%(media_type)s/%(id)s/delete_all/%(group)s/' % { + path += '/%(media_type)s/%(id)s/delete_all/%(group)s/' % { 'media_type': media_type, 'id': camera_id, 'group': group} - request = _make_request(scheme, host, port, username, password, uri, method='POST', data='{}', timeout=settings.REMOTE_REQUEST_TIMEOUT) + request = _make_request(scheme, host, port, username, password, path, method='POST', data='{}', timeout=settings.REMOTE_REQUEST_TIMEOUT) def on_response(response): if response.error: diff --git a/motioneye/server.py b/motioneye/server.py index 3de3ce6..cfa2914 100644 --- a/motioneye/server.py +++ b/motioneye/server.py @@ -158,33 +158,25 @@ def _log_request(handler): log_method("%d %s %.2fms", handler.get_status(), handler._request_summary(), request_time) -application = Application( - [ - (r'^/$', handlers.MainHandler), - (r'^/config/main/(?Pset|get)/?$', handlers.ConfigHandler), - (r'^/config/(?P\d+)/(?Pget|set|rem|set_preview)/?$', handlers.ConfigHandler), - (r'^/config/(?Padd|list|backup|restore)/?$', handlers.ConfigHandler), - (r'^/picture/(?P\d+)/(?Pcurrent|list|frame)/?$', handlers.PictureHandler), - (r'^/picture/(?P\d+)/(?Pdownload|preview|delete)/(?P.+?)/?$', handlers.PictureHandler), - (r'^/picture/(?P\d+)/(?Pzipped|timelapse|delete_all)/(?P.+?)/?$', handlers.PictureHandler), - (r'^/movie/(?P\d+)/(?Plist)/?$', handlers.MovieHandler), - (r'^/movie/(?P\d+)/(?Pdownload|preview|delete)/(?P.+?)/?$', handlers.MovieHandler), - (r'^/movie/(?P\d+)/(?Pdelete_all)/(?P.+?)/?$', handlers.MovieHandler), - (r'^/_relay_event/?$', handlers.RelayEventHandler), - (r'^/log/(?P\w+)/?$', handlers.LogHandler), - (r'^/update/?$', handlers.UpdateHandler), - (r'^/power/(?Pshutdown|reboot)/?$', handlers.PowerHandler), - (r'^/version/?$', handlers.VersionHandler), - (r'^/login/?$', handlers.LoginHandler), - (r'^.*$', handlers.NotFoundHandler), - ], - debug=False, - log_function=_log_request, - static_path=settings.STATIC_PATH, - static_url_prefix=settings.STATIC_URL -) - -template.add_context('STATIC_URL', settings.STATIC_URL) +handler_mapping = [ + (r'^/$', handlers.MainHandler), + (r'^/config/main/(?Pset|get)/?$', handlers.ConfigHandler), + (r'^/config/(?P\d+)/(?Pget|set|rem|set_preview)/?$', handlers.ConfigHandler), + (r'^/config/(?Padd|list|backup|restore)/?$', handlers.ConfigHandler), + (r'^/picture/(?P\d+)/(?Pcurrent|list|frame)/?$', handlers.PictureHandler), + (r'^/picture/(?P\d+)/(?Pdownload|preview|delete)/(?P.+?)/?$', handlers.PictureHandler), + (r'^/picture/(?P\d+)/(?Pzipped|timelapse|delete_all)/(?P.+?)/?$', handlers.PictureHandler), + (r'^/movie/(?P\d+)/(?Plist)/?$', handlers.MovieHandler), + (r'^/movie/(?P\d+)/(?Pdownload|preview|delete)/(?P.+?)/?$', handlers.MovieHandler), + (r'^/movie/(?P\d+)/(?Pdelete_all)/(?P.+?)/?$', handlers.MovieHandler), + (r'^/_relay_event/?$', handlers.RelayEventHandler), + (r'^/log/(?P\w+)/?$', handlers.LogHandler), + (r'^/update/?$', handlers.UpdateHandler), + (r'^/power/(?Pshutdown|reboot)/?$', handlers.PowerHandler), + (r'^/version/?$', handlers.VersionHandler), + (r'^/login/?$', handlers.LoginHandler), + (r'^.*$', handlers.NotFoundHandler), +] def configure_signals(): @@ -376,6 +368,11 @@ def run(): if settings.THUMBNAILER_INTERVAL: start_thumbnailer() + template.add_context('static_path', settings.BASE_PATH + '/static/') + + application = Application(handler_mapping, debug=False, log_function=_log_request, + static_path=settings.STATIC_PATH, static_url_prefix='/static/') + application.listen(settings.PORT, settings.LISTEN) logging.info('server started') diff --git a/motioneye/settings.py b/motioneye/settings.py index 82e059e..64a1911 100644 --- a/motioneye/settings.py +++ b/motioneye/settings.py @@ -17,7 +17,7 @@ STATIC_PATH = os.path.join(PROJECT_PATH, 'static') # static files (.css, .js etc) are served at this root url; # change this if you run motionEye behind a reverse proxy (e.g. nginx), # and you want static files to be served directly by it -STATIC_URL = '/static/' +BASE_PATH = '' # path to the configuration directory (must be writable by motionEye) CONF_PATH = [sys.prefix, ''][sys.prefix == '/usr'] + '/etc/motioneye' diff --git a/motioneye/static/js/frame.js b/motioneye/static/js/frame.js index 276e100..c61475c 100644 --- a/motioneye/static/js/frame.js +++ b/motioneye/static/js/frame.js @@ -18,7 +18,7 @@ function setupCameraFrame() { cameraFrameDiv[0].streamingServerResize = cameraFrameDiv.attr('streaming_server_resize') == 'True'; cameraFrameDiv[0].proto = cameraFrameDiv.attr('proto'); cameraFrameDiv[0].url = cameraFrameDiv.attr('url'); - progressImg.attr('src', staticUrl + 'img/camera-progress.gif'); + progressImg.attr('src', staticPath + 'img/camera-progress.gif'); cameraProgress.addClass('visible'); cameraPlaceholder.css('opacity', '0'); @@ -124,13 +124,13 @@ function refreshCameraFrame() { } var timestamp = new Date().getTime(); - var uri = baseUri + 'picture/' + cameraId + '/current/?_=' + timestamp; + var path = basePath + 'picture/' + cameraId + '/current/?_=' + timestamp; if (cameraFrame.serverSideResize) { - uri += '&width=' + img.width; + path += '&width=' + img.width; } - uri = addAuthParams('GET', uri); - img.src = uri; + path = addAuthParams('GET', path); + img.src = path; img.loading = 1; cameraFrame.refreshDivider = 0; diff --git a/motioneye/static/js/main.js b/motioneye/static/js/main.js index ebaca5b..32ba3b1 100644 --- a/motioneye/static/js/main.js +++ b/motioneye/static/js/main.js @@ -7,7 +7,7 @@ var inProgress = false; var refreshInterval = 50; /* milliseconds */ var username = ''; var password = ''; -var baseUri = null; +var basePath = null; var signatureRegExp = new RegExp('[^a-zA-Z0-9/?_.=&{}\\[\\]":, _-]', 'g'); var initialConfigFetched = false; /* used to workaround browser extensions that trigger stupid change events */ @@ -124,8 +124,8 @@ function qualifyUrl(url) { return a.href; } -function qualifyUri(uri) { - var url = qualifyUrl(uri); +function qualifyPath(path) { + var url = qualifyUrl(path); var pos = url.indexOf('//'); if (pos === -1) { /* not a full url */ return url; @@ -140,24 +140,25 @@ function qualifyUri(uri) { return url.substring(pos); } -function computeSignature(method, uri, body) { - uri = qualifyUri(uri); +function computeSignature(method, path, body) { + path = qualifyPath(path); - var parts = splitUrl(uri); + var parts = splitUrl(path); var query = parts.params; - var baseUrl = parts.baseUrl; + var path = parts.baseUrl; + path = '/' + path.substring(basePath.length); /* sort query arguments alphabetically */ query = Object.keys(query).map(function (key) {return {key: key, value: decodeURIComponent(query[key])};}); query = query.filter(function (q) {return q.key !== '_signature';}); query.sortKey(function (q) {return q.key;}); query = query.map(function (q) {return q.key + '=' + encodeURIComponent(q.value);}).join('&'); - uri = baseUrl + '?' + query; - uri = uri.replace(signatureRegExp, '-'); + path = path + '?' + query; + path = path.replace(signatureRegExp, '-'); body = body && body.replace(signatureRegExp, '-'); var password = window.password.replace(signatureRegExp, '-'); - return sha1(method + ':' + uri + ':' + (body || '') + ':' + password).toLowerCase(); + return sha1(method + ':' + path + ':' + (body || '') + ':' + password).toLowerCase(); } function addAuthParams(method, url, body) { @@ -1459,7 +1460,7 @@ function dict2CameraUi(dict) { $('#videoDeviceSwitch')[0].checked = dict['enabled']; markHideIfNull('enabled', 'videoDeviceSwitch'); $('#deviceNameEntry').val(dict['name']); markHideIfNull('name', 'deviceNameEntry'); - $('#deviceUriEntry').val(dict['device_url']); markHideIfNull('device_url', 'deviceUriEntry'); + $('#deviceUrlEntry').val(dict['device_url']); markHideIfNull('device_url', 'deviceUrlEntry'); $('#deviceTypeEntry').val(prettyType); markHideIfNull(!prettyType, 'deviceTypeEntry'); $('#deviceTypeEntry')[0].proto = dict['proto']; $('#lightSwitchDetectSwitch')[0].checked = dict['light_switch_detect']; markHideIfNull('light_switch_detect', 'lightSwitchDetectSwitch'); @@ -1550,7 +1551,7 @@ function dict2CameraUi(dict) { $('#streamingAuthModeSelect').val(dict['streaming_auth_mode']); markHideIfNull('streaming_auth_mode', 'streamingAuthModeSelect'); $('#streamingMotion')[0].checked = dict['streaming_motion']; markHideIfNull('streaming_motion', 'streamingMotion'); - var cameraUrl = location.protocol + '//' + location.host + '/picture/' + dict.id + '/'; + var cameraUrl = location.protocol + '//' + location.host + basePath + 'picture/' + dict.id + '/'; var snapshotUrl = null; var mjpgUrl = null; @@ -1720,10 +1721,10 @@ function beginProgress(cameraIds) { inProgress = true; /* replace the main page message with a progress indicator */ - $('div.add-camera-message').replaceWith(''); + $('div.add-camera-message').replaceWith(''); /* show the apply button progress indicator */ - $('#applyButton').html(''); + $('#applyButton').html(''); /* show the camera progress indicators */ if (cameraIds) { @@ -1765,12 +1766,12 @@ function endProgress() { }, 500); } -function downloadFile(uri) { - uri = baseUri + uri; +function downloadFile(path) { + path = basePath + path; var url = window.location.href; var parts = url.split('/'); - url = parts.slice(0, 3).join('/') + uri; + url = parts.slice(0, 3).join('/') + path; url = addAuthParams('GET', url); /* download the file by creating a temporary iframe */ @@ -1779,7 +1780,7 @@ function downloadFile(uri) { $('body').append(frame); } -function uploadFile(uri, input, callback) { +function uploadFile(path, input, callback) { if (!window.FormData) { showErrorMessage("Your browser doesn't implement this function!");s callback(); @@ -1789,7 +1790,7 @@ function uploadFile(uri, input, callback) { var files = input[0].files; formData.append('files', files[0], files[0].name); - ajax('POST', uri, formData, callback); + ajax('POST', path, formData, callback); } @@ -1867,7 +1868,7 @@ function doApply() { refreshDisabled[cameraId]++; }); - ajax('POST', baseUri + 'config/0/set/', pushConfigs, function (data) { + ajax('POST', basePath + 'config/0/set/', pushConfigs, function (data) { affectedCameraIds.forEach(function (cameraId) { refreshDisabled[cameraId]--; }); @@ -1881,7 +1882,7 @@ function doApply() { if (data.reboot) { var count = 0; function checkServerReboot() { - ajax('GET', baseUri + 'config/0/get/', null, + ajax('GET', basePath + 'config/0/get/', null, function () { window.location.reload(true); }, @@ -1937,13 +1938,13 @@ function doApply() { function doShutDown() { runConfirmDialog('Really shut down?', function () { - ajax('POST', baseUri + 'power/shutdown/'); + ajax('POST', basePath + 'power/shutdown/'); setTimeout(function () { refreshInterval = 1000000; showModalDialog(''); function checkServer() { - ajax('GET', baseUri, null, + ajax('GET', basePath, null, function () { setTimeout(checkServer, 1000); }, @@ -1964,14 +1965,14 @@ function doShutDown() { function doReboot() { runConfirmDialog('Really reboot?', function () { - ajax('POST', baseUri + 'power/reboot/'); + ajax('POST', basePath + 'power/reboot/'); setTimeout(function () { refreshInterval = 1000000; showModalDialog(''); var shutDown = false; function checkServer() { - ajax('GET', baseUri, null, + ajax('GET', basePath, null, function () { if (!shutDown) { setTimeout(checkServer, 1000); @@ -2016,7 +2017,7 @@ function doRemCamera() { } beginProgress(); - ajax('POST', baseUri + 'config/' + cameraId + '/rem/', null, function (data) { + ajax('POST', basePath + 'config/' + cameraId + '/rem/', null, function (data) { if (data == null || data.error) { endProgress(); showErrorMessage(data && data.error); @@ -2034,7 +2035,7 @@ function doUpdate() { } showModalDialog(''); - ajax('GET', baseUri + 'update/', null, function (data) { + ajax('GET', basePath + 'update/', null, function (data) { if (data.update_version == null) { runAlertDialog('motionEye is up to date (current version: ' + data.current_version + ')'); } @@ -2042,10 +2043,10 @@ function doUpdate() { runConfirmDialog('New version available: ' + data.update_version + '. Update?', function () { refreshInterval = 1000000; showModalDialog('
Updating. This may take a few minutes.
'); - ajax('POST', baseUri + 'update/?version=' + data.update_version, null, function () { + ajax('POST', basePath + 'update/?version=' + data.update_version, null, function () { var count = 0; function checkServer() { - ajax('GET', baseUri + 'config/0/get/', null, + ajax('GET', basePath + 'config/0/get/', null, function () { runAlertDialog('motionEye was successfully updated!', function () { window.location.reload(true); @@ -2131,11 +2132,11 @@ function doRestore() { setTimeout(function () { showModalDialog('
Restoring configuration...
'); - uploadFile(baseUri + 'config/restore/', fileInput, function (data) { + uploadFile(basePath + 'config/restore/', fileInput, function (data) { if (data && data.ok) { var count = 0; function checkServer() { - ajax('GET', baseUri + 'config/0/get/', null, + ajax('GET', basePath + 'config/0/get/', null, function () { runAlertDialog('The configuration has been restored!', function () { window.location.reload(true); @@ -2176,7 +2177,7 @@ function doRestore() { function doDownloadZipped(cameraId, groupKey) { showModalDialog('', null, null, true); - ajax('GET', baseUri + 'picture/' + cameraId + '/zipped/' + groupKey + '/', null, function (data) { + ajax('GET', basePath + 'picture/' + cameraId + '/zipped/' + groupKey + '/', null, function (data) { if (data.error) { hideModalDialog(); /* progress */ showErrorMessage(data.error); @@ -2188,10 +2189,10 @@ function doDownloadZipped(cameraId, groupKey) { }); } -function doDeleteFile(uri, callback) { +function doDeleteFile(path, callback) { var url = window.location.href; var parts = url.split('/'); - url = parts.slice(0, 3).join('/') + uri; + url = parts.slice(0, 3).join('/') + path; runConfirmDialog('Really delete this file?', function () { showModalDialog('', null, null, true); @@ -2216,7 +2217,7 @@ function doDeleteFile(uri, callback) { function doDeleteAllFiles(mediaType, cameraId, groupKey, callback) { runConfirmDialog('Really delete all ' + mediaType + 's in ' + groupKey + '?', function () { showModalDialog('', null, null, true); - ajax('POST', baseUri + mediaType + '/' + cameraId + '/delete_all/' + groupKey + '/', null, function (data) { + ajax('POST', basePath + mediaType + '/' + cameraId + '/delete_all/' + groupKey + '/', null, function (data) { hideModalDialog(); /* progress */ hideModalDialog(); /* confirm */ @@ -2240,7 +2241,7 @@ function doDeleteAllFiles(mediaType, cameraId, groupKey, callback) { function fetchCurrentConfig(onFetch) { function fetchCameraList() { /* fetch the camera list */ - ajax('GET', baseUri + 'config/list/', null, function (data) { + ajax('GET', basePath + 'config/list/', null, function (data) { if (data == null || data.error) { showErrorMessage(data && data.error); data = {cameras: []}; @@ -2306,11 +2307,11 @@ function fetchCurrentConfig(onFetch) { } /* add a progress indicator */ - $('div.page-container').append(''); + $('div.page-container').append(''); if (isAdmin()) { /* fetch the main configuration */ - ajax('GET', baseUri + 'config/main/get/', null, function (data) { + ajax('GET', basePath + 'config/main/get/', null, function (data) { if (data == null || data.error) { showErrorMessage(data && data.error); return; @@ -2328,7 +2329,7 @@ function fetchCurrentConfig(onFetch) { function fetchCurrentCameraConfig(onFetch) { var cameraId = $('#cameraSelect').val(); if (cameraId != null) { - ajax('GET', baseUri + 'config/' + cameraId + '/get/?force=true', null, function (data) { + ajax('GET', basePath + 'config/' + cameraId + '/get/?force=true', null, function (data) { if (data == null || data.error) { showErrorMessage(data && data.error); dict2CameraUi(null); @@ -2421,7 +2422,7 @@ function pushPreview(control) { refreshDisabled[cameraId] |= 0; refreshDisabled[cameraId]++; - ajax('POST', baseUri + 'config/' + cameraId + '/set_preview/', data, function (data) { + ajax('POST', basePath + 'config/' + cameraId + '/set_preview/', data, function (data) { refreshDisabled[cameraId]--; if (data == null || data.error) { @@ -2494,7 +2495,7 @@ function runLoginDialog(retry) { $('body').append(tempFrame); var form = - $('
' + + $('' + '' + '' + '' + @@ -2559,7 +2560,7 @@ function runPictureDialog(entries, pos, mediaType) { var nextArrow = $('
'); content.append(nextArrow); - var progressImg = $(''); + var progressImg = $(''); function updatePicture() { var entry = entries[pos]; @@ -2579,7 +2580,7 @@ function runPictureDialog(entries, pos, mediaType) { progressImg.css('left', (img.parent().width() - progressImg.width()) / 2); progressImg.css('top', (img.parent().height() - progressImg.height()) / 2); - img.attr('src', addAuthParams('GET', baseUri + mediaType + '/' + entry.cameraId + '/preview' + entry.path)); + img.attr('src', addAuthParams('GET', basePath + mediaType + '/' + entry.cameraId + '/preview' + entry.path)); img.load(function () { var aspectRatio = this.naturalWidth / this.naturalHeight; var sizeWidth = width * width / aspectRatio; @@ -2737,8 +2738,8 @@ function runAddCameraDialog() { else if (typeSelect.val() == 'netcam') { usernameEntry.removeAttr('readonly'); - /* make sure there is one trailing slash so that - * an URI can be detected */ + /* make sure there is one trailing slash + * so that a path can be detected */ var url = urlEntry.val().trim(); var m = url.match(new RegExp('/', 'g')); if (m && m.length < 3 && !url.endsWith('/')) { @@ -2753,8 +2754,8 @@ function runAddCameraDialog() { else if (typeSelect.val() == 'mjpeg') { usernameEntry.removeAttr('readonly'); - /* make sure there is one trailing slash so that - * an URI can be detected */ + /* make sure there is one trailing slash + * so that a path can be detected */ var url = urlEntry.val().trim(); var m = url.match(new RegExp('/', 'g')); if (m && m.length < 3 && !url.endsWith('/')) { @@ -2819,10 +2820,10 @@ function runAddCameraDialog() { var scheme = parts[0]; var index = parts[1].indexOf('/'); var host = null; - var uri = ''; + var path = ''; if (index >= 0) { host = parts[1].substring(0, index); - uri = parts[1].substring(index); + path = parts[1].substring(index); } else { host = parts[1]; @@ -2835,20 +2836,20 @@ function runAddCameraDialog() { port = parts[1]; } - if (uri == '') { - uri = '/'; + if (path == '') { + path = '/'; } return { scheme: scheme, host: host, port: port, - uri: uri + path: path }; } function listCameras() { - var progress = $('
'); + var progress = $('
'); addCameraSelect.html(''); addCameraSelect.hide(); @@ -2865,7 +2866,7 @@ function runAddCameraDialog() { cameraMsgLabel.html(''); - ajax('GET', baseUri + 'config/list/', data, function (data) { + ajax('GET', basePath + 'config/list/', data, function (data) { progress.remove(); if (data == null || data.error) { @@ -2945,7 +2946,7 @@ function runAddCameraDialog() { } else { /* assuming v4l2 */ data.proto = 'v4l2'; - data.uri = addCameraSelect.val(); + data.path = addCameraSelect.val(); } /* add all extra attributes */ @@ -2956,7 +2957,7 @@ function runAddCameraDialog() { }); beginProgress(); - ajax('POST', baseUri + 'config/add/', data, function (data) { + ajax('POST', basePath + 'config/add/', data, function (data) { endProgress(); if (data == null || data.error) { @@ -3044,7 +3045,7 @@ function runTimelapseDialog(cameraId, groupKey, group) { noKeys: true }); - var url = baseUri + 'picture/' + cameraId + '/timelapse/' + groupKey + '/'; + var url = basePath + 'picture/' + cameraId + '/timelapse/' + groupKey + '/'; var data = {interval: intervalSelect.val(), framerate: framerateSlider.val()}; var first = true; @@ -3158,9 +3159,9 @@ function runMediaDialog(cameraId, mediaType) { if (!entryDiv) { entryDiv = $('
'); - var previewImg = $(''); + var previewImg = $(''); entryDiv.append(previewImg); - previewImg[0]._src = addAuthParams('GET', baseUri + mediaType + '/' + cameraId + '/preview' + entry.path + '?height=' + height); + previewImg[0]._src = addAuthParams('GET', basePath + mediaType + '/' + cameraId + '/preview' + entry.path + '?height=' + height); var downloadButton = $('
Download
'); entryDiv.append(downloadButton); @@ -3182,7 +3183,7 @@ function runMediaDialog(cameraId, mediaType) { }); deleteButton.click(function () { - doDeleteFile(baseUri + mediaType + '/' + cameraId + '/delete' + entry.path, function () { + doDeleteFile(basePath + mediaType + '/' + cameraId + '/delete' + entry.path, function () { entryDiv.remove(); entries.splice(i, 1); /* remove entry from group */ @@ -3231,10 +3232,10 @@ function runMediaDialog(cameraId, mediaType) { return addEntries(); } - var previewImg = $(''); + var previewImg = $(''); mediaListDiv.append(previewImg); - var url = baseUri + mediaType + '/' + cameraId + '/list/?prefix=' + (key || 'ungrouped'); + var url = basePath + mediaType + '/' + cameraId + '/list/?prefix=' + (key || 'ungrouped'); ajax('GET', url, null, function (data) { previewImg.remove(); @@ -3367,7 +3368,7 @@ function runMediaDialog(cameraId, mediaType) { showModalDialog(''); /* fetch the media list */ - ajax('GET', baseUri + mediaType + '/' + cameraId + '/list/', null, function (data) { + ajax('GET', basePath + mediaType + '/' + cameraId + '/list/', null, function (data) { if (data == null || data.error) { hideModalDialog(); showErrorMessage(data && data.error); @@ -3508,7 +3509,7 @@ function addCameraFrameUi(cameraConfig) { '' + '' + '
' + - '
' + + '
' + '' + '
' + '
' + @@ -3539,7 +3540,7 @@ function addCameraFrameUi(cameraConfig) { cameraFrameDiv[0].refreshDivider = 0; cameraFrameDiv[0].config = cameraConfig; nameSpan.html(cameraConfig.name); - progressImg.attr('src', staticUrl + 'img/camera-progress.gif'); + progressImg.attr('src', staticPath + 'img/camera-progress.gif'); cameraProgress.click(function () { doFullScreenCamera(cameraId); @@ -3589,8 +3590,8 @@ function addCameraFrameUi(cameraConfig) { fullScreenButton.click(function (cameraId) { return function () { - var url = baseUri + 'picture/' + cameraId + '/frame/'; - window.open(url, '_blank'); + var path = basePath + 'picture/' + cameraId + '/frame/'; + window.open(path, '_blank'); }; }(cameraId)); @@ -3677,7 +3678,7 @@ function recreateCameraFrames(cameras) { updateCameras(cameras); } else { - ajax('GET', baseUri + 'config/list/', null, function (data) { + ajax('GET', basePath + 'config/list/', null, function (data) { if (data == null || data.error) { showErrorMessage(data && data.error); return; @@ -3794,14 +3795,14 @@ function refreshCameraFrames() { } var timestamp = new Date().getTime(); - var uri = baseUri + 'picture/' + cameraId + '/current/?_=' + timestamp; + var path = basePath + 'picture/' + cameraId + '/current/?_=' + timestamp; if (serverSideResize) { - uri += '&width=' + img.width; + path += '&width=' + img.width; } - uri = addAuthParams('GET', uri); + path = addAuthParams('GET', path); - img.src = uri; + img.src = path; img.loading = 1; } @@ -3874,13 +3875,13 @@ function checkCameraErrors() { /* startup function */ $(document).ready(function () { - /* detect base uri */ + /* detect base path */ if (frame) { - baseUri = qualifyUri('../../../'); + window.basePath = qualifyPath('../../../'); } else { - baseUri = splitUrl(qualifyUri('')).baseUrl; + window.basePath = splitUrl(qualifyPath('')).baseUrl; /* restore the username from cookie */ window.username = getCookie('username'); @@ -3917,7 +3918,7 @@ $(document).ready(function () { initUI(); beginProgress(); - ajax('GET', baseUri + 'login/', null, function () { + ajax('GET', basePath + 'login/', null, function () { if (!frame) { fetchCurrentConfig(endProgress); } diff --git a/motioneye/templates/base.html b/motioneye/templates/base.html index 6679b8d..5d3d47e 100644 --- a/motioneye/templates/base.html +++ b/motioneye/templates/base.html @@ -10,18 +10,18 @@ {% endblock %} {% block title %}{% endblock %} {% block style %} - + {% endblock %} {% block script %} - - - - - + + + + + {% endblock %} diff --git a/motioneye/templates/main.html b/motioneye/templates/main.html index 393ab51..1349c2d 100644 --- a/motioneye/templates/main.html +++ b/motioneye/templates/main.html @@ -50,24 +50,23 @@ {% block style %} {{super()}} - - + + {% if frame %} - + {% endif %} {% endblock %} {% block script %} {{super()}} - - + + {% if frame %} - + {% endif %} @@ -89,7 +88,7 @@ @@ -207,7 +206,7 @@ - + @@ -805,7 +804,7 @@
- +
diff --git a/motioneye/templates/version.html b/motioneye/templates/version.html index 3c7a8f8..d3a9249 100644 --- a/motioneye/templates/version.html +++ b/motioneye/templates/version.html @@ -6,7 +6,7 @@ var hostname = '{{hostname}}'; var version = '{{version}}'; - + {% endblock %} {% block body %} diff --git a/motioneye/utils.py b/motioneye/utils.py index a3fe0b8..f88d2de 100644 --- a/motioneye/utils.py +++ b/motioneye/utils.py @@ -336,15 +336,15 @@ def test_mjpeg_url(data, auth_modes, allow_jpeg, callback): data.setdefault('scheme', 'http') data.setdefault('host', '127.0.0.1') data.setdefault('port', '80') - data.setdefault('uri', '') + data.setdefault('path', '') data.setdefault('username', None) data.setdefault('password', None) - url = '%(scheme)s://%(host)s%(port)s%(uri)s' % { + url = '%(scheme)s://%(host)s%(port)s%(path)s' % { 'scheme': data['scheme'], 'host': data['host'], 'port': ':' + str(data['port']) if data['port'] else '', - 'uri': data['uri'] or ''} + 'path': data['path'] or ''} called = [False] status_2xx = [False] @@ -414,15 +414,15 @@ def test_rtsp_url(data, callback): data.setdefault('scheme', 'rtsp') data.setdefault('host', '127.0.0.1') data['port'] = data.get('port') or '554' - data.setdefault('uri', '') + data.setdefault('path', '') data.setdefault('username', None) data.setdefault('password', None) - url = '%(scheme)s://%(host)s%(port)s%(uri)s' % { + url = '%(scheme)s://%(host)s%(port)s%(path)s' % { 'scheme': data['scheme'], 'host': data['host'], 'port': ':' + str(data['port']) if data['port'] else '', - 'uri': data['uri'] or ''} + 'path': data['path'] or ''} called = [False] timeout = [None] @@ -563,8 +563,8 @@ def test_rtsp_url(data, callback): stream = connect() -def compute_signature(method, uri, body, key): - parts = list(urlparse.urlsplit(uri)) +def compute_signature(method, path, body, key): + parts = list(urlparse.urlsplit(path)) query = [q for q in urlparse.parse_qsl(parts[3], keep_blank_values=True) if (q[0] != '_signature')] query.sort(key=lambda q: q[0]) # "safe" characters here are set to match the encodeURIComponent JavaScript counterpart @@ -572,8 +572,8 @@ def compute_signature(method, uri, body, key): query = '&'.join([(q[0] + '=' + q[1]) for q in query]) parts[0] = parts[1] = '' parts[3] = query - uri = urlparse.urlunsplit(parts) - uri = _SIGNATURE_REGEX.sub('-', uri) + path = urlparse.urlunsplit(parts) + path = _SIGNATURE_REGEX.sub('-', path) key = _SIGNATURE_REGEX.sub('-', key) if body and body.startswith('---'): @@ -581,7 +581,7 @@ def compute_signature(method, uri, body, key): body = body and _SIGNATURE_REGEX.sub('-', body.decode('utf8')) - return hashlib.sha1('%s:%s:%s:%s' % (method, uri, body or '', key)).hexdigest().lower() + return hashlib.sha1('%s:%s:%s:%s' % (method, path, body or '', key)).hexdigest().lower() def build_basic_header(username, password): @@ -664,7 +664,7 @@ def build_digest_header(method, url, username, password, state): last_nonce = nonce - base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ + base = 'username="%s", realm="%s", nonce="%s", path="%s", ' \ 'response="%s"' % (username, realm, nonce, path, respdig) if opaque: base += ', opaque="%s"' % opaque