From cd268e4099bb4c21fe207eda5a9ac91eb5516da4 Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Wed, 19 Aug 2015 17:52:43 +0300 Subject: [PATCH] initial work on migrating to setuptools --- .gitignore | 3 +- MANIFEST.in | 2 + README.md | 12 +- motioneye.py | 419 ------------------ motioneye/__init__.py | 2 + {src => motioneye}/cleanup.py | 0 {src => motioneye}/config.py | 0 {src => motioneye}/diskctl.py | 0 eventrelay.py => motioneye/eventrelay.py | 0 {src => motioneye}/handlers.py | 0 {src => motioneye}/mediafiles.py | 0 {src => motioneye}/mjpgclient.py | 0 {src => motioneye}/motionctl.py | 0 {src => motioneye}/ordereddict.py | 0 {src => motioneye}/powerctl.py | 0 {src => motioneye}/remote.py | 0 sendmail.py => motioneye/sendmail.py | 0 motioneye/server.py | 351 +++++++++++++++ settings_default.py => motioneye/settings.py | 36 +- {src => motioneye}/smbctl.py | 0 {static => motioneye/static}/css/frame.css | 0 .../static}/css/jquery.timepicker.css | 0 {static => motioneye/static}/css/main.css | 0 {static => motioneye/static}/css/ui.css | 0 {static => motioneye/static}/favicon.ico | Bin .../static}/fnt/mavenpro-black-webfont.eot | Bin .../static}/fnt/mavenpro-black-webfont.svg | 0 .../static}/fnt/mavenpro-black-webfont.ttf | Bin .../static}/fnt/mavenpro-black-webfont.woff | Bin .../static}/fnt/mavenpro-bold-webfont.eot | Bin .../static}/fnt/mavenpro-bold-webfont.svg | 0 .../static}/fnt/mavenpro-bold-webfont.ttf | Bin .../static}/fnt/mavenpro-bold-webfont.woff | Bin .../static}/fnt/mavenpro-medium-webfont.eot | Bin .../static}/fnt/mavenpro-medium-webfont.svg | 0 .../static}/fnt/mavenpro-medium-webfont.ttf | Bin .../static}/fnt/mavenpro-medium-webfont.woff | Bin .../static}/fnt/mavenpro-regular-webfont.eot | Bin .../static}/fnt/mavenpro-regular-webfont.svg | 0 .../static}/fnt/mavenpro-regular-webfont.ttf | Bin .../static}/fnt/mavenpro-regular-webfont.woff | Bin .../static}/img/apply-progress.gif | Bin {static => motioneye/static}/img/arrows.svg | 0 .../static}/img/camera-progress.gif | Bin .../static}/img/combo-box-arrow.svg | 0 {static => motioneye/static}/img/logout.svg | 0 .../static}/img/main-loading-progress.gif | Bin .../static}/img/modal-progress.gif | Bin .../static}/img/motioneye-icon.svg | 0 .../static}/img/motioneye-logo.svg | 0 .../static}/img/no-camera.svg | 0 .../static}/img/no-preview.svg | 0 {static => motioneye/static}/img/settings.svg | 0 .../static}/img/slider-arrow.svg | 0 .../static}/img/small-progress.gif | Bin .../static}/img/top-bar-buttons.svg | 0 .../static}/img/validation-error.svg | 0 .../static}/js/css-browser-selector.js | 0 {static => motioneye/static}/js/frame.js | 0 {static => motioneye/static}/js/jquery.min.js | 0 .../static}/js/jquery.mousewheel.js | 0 .../static}/js/jquery.timepicker.min.js | 0 {static => motioneye/static}/js/main.js | 15 +- {static => motioneye/static}/js/ui.js | 0 {static => motioneye/static}/js/version.js | 0 {src => motioneye}/template.py | 0 {templates => motioneye/templates}/base.html | 0 {templates => motioneye/templates}/main.html | 0 .../templates}/version.html | 0 {src => motioneye}/thumbnailer.py | 0 {src => motioneye}/tzctl.py | 0 {src => motioneye}/update.py | 0 {src => motioneye}/utils.py | 0 {src => motioneye}/v4l2ctl.py | 0 webhook.py => motioneye/webhook.py | 0 {src => motioneye}/wifictl.py | 0 {src => motioneye}/wsswitch.py | 0 setup.py | 64 +++ src/server.py | 67 --- 79 files changed, 461 insertions(+), 510 deletions(-) create mode 100644 MANIFEST.in delete mode 100755 motioneye.py create mode 100644 motioneye/__init__.py rename {src => motioneye}/cleanup.py (100%) rename {src => motioneye}/config.py (100%) rename {src => motioneye}/diskctl.py (100%) rename eventrelay.py => motioneye/eventrelay.py (100%) rename {src => motioneye}/handlers.py (100%) rename {src => motioneye}/mediafiles.py (100%) rename {src => motioneye}/mjpgclient.py (100%) rename {src => motioneye}/motionctl.py (100%) rename {src => motioneye}/ordereddict.py (100%) rename {src => motioneye}/powerctl.py (100%) rename {src => motioneye}/remote.py (100%) rename sendmail.py => motioneye/sendmail.py (100%) create mode 100644 motioneye/server.py rename settings_default.py => motioneye/settings.py (75%) rename {src => motioneye}/smbctl.py (100%) rename {static => motioneye/static}/css/frame.css (100%) rename {static => motioneye/static}/css/jquery.timepicker.css (100%) rename {static => motioneye/static}/css/main.css (100%) rename {static => motioneye/static}/css/ui.css (100%) rename {static => motioneye/static}/favicon.ico (100%) rename {static => motioneye/static}/fnt/mavenpro-black-webfont.eot (100%) rename {static => motioneye/static}/fnt/mavenpro-black-webfont.svg (100%) rename {static => motioneye/static}/fnt/mavenpro-black-webfont.ttf (100%) rename {static => motioneye/static}/fnt/mavenpro-black-webfont.woff (100%) rename {static => motioneye/static}/fnt/mavenpro-bold-webfont.eot (100%) rename {static => motioneye/static}/fnt/mavenpro-bold-webfont.svg (100%) rename {static => motioneye/static}/fnt/mavenpro-bold-webfont.ttf (100%) rename {static => motioneye/static}/fnt/mavenpro-bold-webfont.woff (100%) rename {static => motioneye/static}/fnt/mavenpro-medium-webfont.eot (100%) rename {static => motioneye/static}/fnt/mavenpro-medium-webfont.svg (100%) rename {static => motioneye/static}/fnt/mavenpro-medium-webfont.ttf (100%) rename {static => motioneye/static}/fnt/mavenpro-medium-webfont.woff (100%) rename {static => motioneye/static}/fnt/mavenpro-regular-webfont.eot (100%) rename {static => motioneye/static}/fnt/mavenpro-regular-webfont.svg (100%) rename {static => motioneye/static}/fnt/mavenpro-regular-webfont.ttf (100%) rename {static => motioneye/static}/fnt/mavenpro-regular-webfont.woff (100%) rename {static => motioneye/static}/img/apply-progress.gif (100%) rename {static => motioneye/static}/img/arrows.svg (100%) rename {static => motioneye/static}/img/camera-progress.gif (100%) rename {static => motioneye/static}/img/combo-box-arrow.svg (100%) rename {static => motioneye/static}/img/logout.svg (100%) rename {static => motioneye/static}/img/main-loading-progress.gif (100%) rename {static => motioneye/static}/img/modal-progress.gif (100%) rename {static => motioneye/static}/img/motioneye-icon.svg (100%) rename {static => motioneye/static}/img/motioneye-logo.svg (100%) rename {static => motioneye/static}/img/no-camera.svg (100%) rename {static => motioneye/static}/img/no-preview.svg (100%) rename {static => motioneye/static}/img/settings.svg (100%) rename {static => motioneye/static}/img/slider-arrow.svg (100%) rename {static => motioneye/static}/img/small-progress.gif (100%) rename {static => motioneye/static}/img/top-bar-buttons.svg (100%) rename {static => motioneye/static}/img/validation-error.svg (100%) rename {static => motioneye/static}/js/css-browser-selector.js (100%) rename {static => motioneye/static}/js/frame.js (100%) rename {static => motioneye/static}/js/jquery.min.js (100%) rename {static => motioneye/static}/js/jquery.mousewheel.js (100%) rename {static => motioneye/static}/js/jquery.timepicker.min.js (100%) rename {static => motioneye/static}/js/main.js (99%) rename {static => motioneye/static}/js/ui.js (100%) rename {static => motioneye/static}/js/version.js (100%) rename {src => motioneye}/template.py (100%) rename {templates => motioneye/templates}/base.html (100%) rename {templates => motioneye/templates}/main.html (100%) rename {templates => motioneye/templates}/version.html (100%) rename {src => motioneye}/thumbnailer.py (100%) rename {src => motioneye}/tzctl.py (100%) rename {src => motioneye}/update.py (100%) rename {src => motioneye}/utils.py (100%) rename {src => motioneye}/v4l2ctl.py (100%) rename webhook.py => motioneye/webhook.py (100%) rename {src => motioneye}/wifictl.py (100%) rename {src => motioneye}/wsswitch.py (100%) create mode 100644 setup.py delete mode 100644 src/server.py diff --git a/.gitignore b/.gitignore index 3be82e4..806f37a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,7 @@ *.conf *.json .settings -settings.py conf run media -log \ No newline at end of file +log diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..1c2510d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README.md + diff --git a/README.md b/README.md index dd5865d..de116c1 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,6 @@ * ffmpeg * v4l-utils -On a debian-based system you could run (as root): - - apt-get install motion ffmpeg v4l-utils python-pip - pip install python-imaging jinja2 pycurl tornado - -## Browser Compatibility ## - -motionEye works fine with most modern browsers, including IE9+. -Being designed with responsiveness in mind, it will also work nicely on mobile devices and tablets. - ## Installation ## 1. download the latest version from [bitbucket](https://bitbucket.org/ccrisan/motioneye/downloads) (use the *Tags* tab). @@ -42,4 +32,4 @@ Being designed with responsiveness in mind, it will also work nicely on mobile d ./motioneye.py - 5. point your favourite browser to \ No newline at end of file + 5. point your favourite browser to diff --git a/motioneye.py b/motioneye.py deleted file mode 100755 index 5f54e4b..0000000 --- a/motioneye.py +++ /dev/null @@ -1,419 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2013 Calin Crisan -# This file is part of motionEye. -# -# motionEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import datetime -import imp -import inspect -import logging -import multiprocessing -import os.path -import re -import signal -import sys - -from tornado.httpclient import AsyncHTTPClient - -# test if a --settings directive has been supplied -for i in xrange(1, len(sys.argv) - 1): - if sys.argv[i] == '--settings': - settings_module = sys.argv[i + 1] - imp.load_source('settings', settings_module) - -sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'src')) - -import settings -import update - -VERSION = '0.25.2' - - -def _configure_settings(): - def set_default_setting(name, value): - if not hasattr(settings, name): - setattr(settings, name, value) - - set_default_setting('PROJECT_PATH', os.path.dirname(sys.argv[0])) - set_default_setting('TEMPLATE_PATH', os.path.join(settings.PROJECT_PATH, 'templates')) - set_default_setting('STATIC_PATH', os.path.join(settings.PROJECT_PATH, 'static')) - set_default_setting('STATIC_URL', '/static/') - set_default_setting('CONF_PATH', os.path.join(settings.PROJECT_PATH, 'conf')) - set_default_setting('RUN_PATH', os.path.join(settings.PROJECT_PATH, 'run')) - set_default_setting('LOG_PATH', os.path.join(settings.PROJECT_PATH, 'log')) - set_default_setting('MEDIA_PATH', os.path.join(settings.PROJECT_PATH, 'media')) - set_default_setting('MOTION_BINARY', None) - set_default_setting('LOG_LEVEL', logging.INFO) - set_default_setting('LISTEN', '0.0.0.0') - set_default_setting('PORT', 8765) - set_default_setting('MOUNT_CHECK_INTERVAL', 300) - set_default_setting('MOTION_CHECK_INTERVAL', 10) - set_default_setting('CLEANUP_INTERVAL', 43200) - set_default_setting('THUMBNAILER_INTERVAL', 60) - set_default_setting('REMOTE_REQUEST_TIMEOUT', 10) - set_default_setting('MJPG_CLIENT_TIMEOUT', 10) - set_default_setting('MJPG_CLIENT_IDLE_TIMEOUT', 10) - set_default_setting('SMB_SHARES', False) - set_default_setting('SMB_MOUNT_ROOT', '/media') - set_default_setting('WPA_SUPPLICANT_CONF', None) - set_default_setting('LOCAL_TIME_FILE', None) - set_default_setting('ENABLE_REBOOT', False) - set_default_setting('SMTP_TIMEOUT', 60) - set_default_setting('ZIP_TIMEOUT', 500) - set_default_setting('ADD_REMOVE_CAMERAS', True) - - length = len(sys.argv) - 1 - for i in xrange(length): - arg = sys.argv[i + 1] - - if not arg.startswith('--'): - continue - - next_arg = None - if i < length - 1: - next_arg = sys.argv[i + 2] - - name = arg[2:].upper().replace('-', '_') - - if name == 'HELP': - _print_help() - sys.exit(0) - - if hasattr(settings, name): - curr_value = getattr(settings, name) - - if next_arg.lower() == 'debug': - next_arg = logging.DEBUG - - elif next_arg.lower() == 'info': - next_arg = logging.INFO - - elif next_arg.lower() == 'warn': - next_arg = logging.WARN - - elif next_arg.lower() == 'error': - next_arg = logging.ERROR - - elif next_arg.lower() == 'fatal': - next_arg = logging.FATAL - - elif next_arg.lower() == 'true': - next_arg = True - - elif next_arg.lower() == 'false': - next_arg = False - - elif isinstance(curr_value, int): - next_arg = int(next_arg) - - elif isinstance(curr_value, float): - next_arg = float(next_arg) - - setattr(settings, name, next_arg) - - else: - return arg[2:] - - try: - os.makedirs(settings.CONF_PATH) - - except: - pass - - try: - os.makedirs(settings.RUN_PATH) - - except: - pass - - try: - os.makedirs(settings.LOG_PATH) - - except: - pass - - try: - os.makedirs(settings.MEDIA_PATH) - - except: - pass - - -def _test_requirements(): - if os.geteuid() != 0: - if settings.SMB_SHARES: - print('SMB_SHARES require root privileges') - return False - - if settings.ENABLE_REBOOT: - print('reboot requires root privileges') - return False - - try: - import tornado # @UnusedImport - has_tornado = True - - except ImportError: - has_tornado = False - - if update.compare_versions(tornado.version, '3.1') < 0: - has_tornado = False - - try: - import jinja2 # @UnusedImport - has_jinja2 = True - - except ImportError: - has_jinja2 = False - - try: - import PIL.Image # @UnusedImport - has_pil = True - - except ImportError: - has_pil = False - - try: - import pycurl # @UnusedImport - has_pycurl = True - - except ImportError: - has_pycurl = False - - import mediafiles - has_ffmpeg = mediafiles.find_ffmpeg() is not None - - import motionctl - has_motion = motionctl.find_motion() is not None - - import v4l2ctl - has_v4lutils = v4l2ctl.find_v4l2_ctl() is not None - - import smbctl - has_mount_cifs = smbctl.find_mount_cifs() is not None - - ok = True - if not has_tornado: - print('please install tornado (python-tornado), version 3.1 or greater') - ok = False - - if not has_jinja2: - print('please install jinja2 (python-jinja2)') - ok = False - - if not has_pil: - print('please install PIL (python-imaging)') - ok = False - - if not has_pycurl: - print('please install pycurl (python-pycurl)') - ok = False - - if not has_ffmpeg: - print('please install ffmpeg') - ok = False - - if not has_motion: - print('please install motion') - ok = False - - if not has_v4lutils: - print('please install v4l-utils') - ok = False - - if settings.SMB_SHARES and not has_mount_cifs: - print('please install cifs-utils') - ok = False - - return ok - - -def _configure_signals(): - def bye_handler(signal, frame): - import tornado.ioloop - - logging.info('interrupt signal received, shutting down...') - - # shut down the IO loop if it has been started - ioloop = tornado.ioloop.IOLoop.instance() - ioloop.stop() - - def child_handler(signal, frame): - # this is required for the multiprocessing mechanism to work - multiprocessing.active_children() - - signal.signal(signal.SIGINT, bye_handler) - signal.signal(signal.SIGTERM, bye_handler) - signal.signal(signal.SIGCHLD, child_handler) - - -def _configure_logging(module=None): - if module: - format = '%(asctime)s: [{module}] %(levelname)s: %(message)s'.format(module=module) - - else: - format = '%(asctime)s: %(levelname)s: %(message)s' - - logging.basicConfig(filename=None, level=settings.LOG_LEVEL, - format=format, datefmt='%Y-%m-%d %H:%M:%S') - - logging.getLogger('tornado').setLevel(logging.WARN) - - -def _configure_tornado(): - AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient', max_clients=16) - - -def _print_help(): - print('Usage: ' + sys.argv[0] + ' [option1 value1] ...') - print('available options: ') - - options = list(inspect.getmembers(settings)) - - print(' --settings ') - - for (name, value) in sorted(options): - if name.upper() != name: - continue - - if not re.match('^[A-Z0-9_]+$', name): - continue - - name = '--' + name.lower().replace('_', '-') - if value is not None: - value = type(value).__name__ - - line = ' ' + name - if value: - line += ' <' + value + '>' - print(line) - - print('') - - -def _run_server(): - import cleanup - import motionctl - import thumbnailer - import tornado.ioloop - import server - import smbctl - - server.application.listen(settings.PORT, settings.LISTEN) - logging.info('server started') - - tornado.ioloop.IOLoop.instance().start() - - logging.info('server stopped') - - if thumbnailer.running(): - thumbnailer.stop() - logging.info('thumbnailer stopped') - - if cleanup.running(): - cleanup.stop() - logging.info('cleanup stopped') - - if motionctl.running(): - motionctl.stop() - logging.info('motion stopped') - - if settings.SMB_SHARES: - smbctl.umount_all() - logging.info('SMB shares unmounted') - - -def _start_motion(): - import tornado.ioloop - import config - import motionctl - - ioloop = tornado.ioloop.IOLoop.instance() - - # add a motion running checker - def checker(): - if ioloop._stopped: - return - - if not motionctl.running() and motionctl.started() and config.get_enabled_local_motion_cameras(): - try: - logging.error('motion not running, starting it') - motionctl.start() - - except Exception as e: - logging.error('failed to start motion: %(msg)s' % { - 'msg': unicode(e)}, exc_info=True) - - ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) - - motionctl.start() - - ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) - - -def _start_cleanup(): - import cleanup - - cleanup.start() - logging.info('cleanup started') - - -def _start_wsswitch(): - import wsswitch - - wsswitch.start() - logging.info('wsswitch started') - - -def _start_thumbnailer(): - import thumbnailer - - thumbnailer.start() - logging.info('thumbnailer started') - - -if __name__ == '__main__': - cmd = _configure_settings() - - _configure_signals() - _configure_logging() - - if not _test_requirements(): - sys.exit(-1) - - _configure_tornado() - - logging.info('hello! this is motionEye %s' % VERSION) - - if settings.SMB_SHARES: - import smbctl - - stop, start = smbctl.update_mounts() - if start: - _start_motion() - - else: - _start_motion() - - _start_cleanup() - _start_wsswitch() - - if settings.THUMBNAILER_INTERVAL: - _start_thumbnailer() - - _run_server() - - logging.info('bye!') \ No newline at end of file diff --git a/motioneye/__init__.py b/motioneye/__init__.py new file mode 100644 index 0000000..ad23e4c --- /dev/null +++ b/motioneye/__init__.py @@ -0,0 +1,2 @@ + +VERSION = '0.26' diff --git a/src/cleanup.py b/motioneye/cleanup.py similarity index 100% rename from src/cleanup.py rename to motioneye/cleanup.py diff --git a/src/config.py b/motioneye/config.py similarity index 100% rename from src/config.py rename to motioneye/config.py diff --git a/src/diskctl.py b/motioneye/diskctl.py similarity index 100% rename from src/diskctl.py rename to motioneye/diskctl.py diff --git a/eventrelay.py b/motioneye/eventrelay.py similarity index 100% rename from eventrelay.py rename to motioneye/eventrelay.py diff --git a/src/handlers.py b/motioneye/handlers.py similarity index 100% rename from src/handlers.py rename to motioneye/handlers.py diff --git a/src/mediafiles.py b/motioneye/mediafiles.py similarity index 100% rename from src/mediafiles.py rename to motioneye/mediafiles.py diff --git a/src/mjpgclient.py b/motioneye/mjpgclient.py similarity index 100% rename from src/mjpgclient.py rename to motioneye/mjpgclient.py diff --git a/src/motionctl.py b/motioneye/motionctl.py similarity index 100% rename from src/motionctl.py rename to motioneye/motionctl.py diff --git a/src/ordereddict.py b/motioneye/ordereddict.py similarity index 100% rename from src/ordereddict.py rename to motioneye/ordereddict.py diff --git a/src/powerctl.py b/motioneye/powerctl.py similarity index 100% rename from src/powerctl.py rename to motioneye/powerctl.py diff --git a/src/remote.py b/motioneye/remote.py similarity index 100% rename from src/remote.py rename to motioneye/remote.py diff --git a/sendmail.py b/motioneye/sendmail.py similarity index 100% rename from sendmail.py rename to motioneye/sendmail.py diff --git a/motioneye/server.py b/motioneye/server.py new file mode 100644 index 0000000..76b385b --- /dev/null +++ b/motioneye/server.py @@ -0,0 +1,351 @@ + +# Copyright (c) 2013 Calin Crisan +# This file is part of motionEye. +# +# motionEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import datetime +import multiprocessing +import os.path +import signal +import sys + +from tornado.httpclient import AsyncHTTPClient +from tornado.web import Application + +import handlers +import logging +import settings +import template + + +def load_settings(): + # TODO use optparse +# length = len(sys.argv) - 1 +# for i in xrange(length): +# arg = sys.argv[i + 1] +# +# if not arg.startswith('--'): +# continue +# +# next_arg = None +# if i < length - 1: +# next_arg = sys.argv[i + 2] +# +# name = arg[2:].upper().replace('-', '_') +# +# if hasattr(settings, name): +# curr_value = getattr(settings, name) +# +# if next_arg.lower() == 'debug': +# next_arg = logging.DEBUG +# +# elif next_arg.lower() == 'info': +# next_arg = logging.INFO +# +# elif next_arg.lower() == 'warn': +# next_arg = logging.WARN +# +# elif next_arg.lower() == 'error': +# next_arg = logging.ERROR +# +# elif next_arg.lower() == 'fatal': +# next_arg = logging.FATAL +# +# elif next_arg.lower() == 'true': +# next_arg = True +# +# elif next_arg.lower() == 'false': +# next_arg = False +# +# elif isinstance(curr_value, int): +# next_arg = int(next_arg) +# +# elif isinstance(curr_value, float): +# next_arg = float(next_arg) +# +# setattr(settings, name, next_arg) +# +# else: +# return arg[2:] + + if not os.path.exists(settings.CONF_PATH): + logging.fatal('config directory "%s" does not exist' % settings.CONF_PATH) + sys.exit(-1) + + if not os.path.exists(settings.RUN_PATH): + logging.fatal('pid directory "%s" does not exist' % settings.RUN_PATH) + sys.exit(-1) + + if not os.path.exists(settings.LOG_PATH): + logging.fatal('log directory "%s" does not exist' % settings.LOG_PATH) + sys.exit(-1) + + if not os.path.exists(settings.MEDIA_PATH): + logging.fatal('media directory "%s" does not exist' % settings.MEDIA_PATH) + sys.exit(-1) + + +def configure_signals(): + def bye_handler(signal, frame): + import tornado.ioloop + + logging.info('interrupt signal received, shutting down...') + + # shut down the IO loop if it has been started + ioloop = tornado.ioloop.IOLoop.instance() + ioloop.stop() + + def child_handler(signal, frame): + # this is required for the multiprocessing mechanism to work + multiprocessing.active_children() + + signal.signal(signal.SIGINT, bye_handler) + signal.signal(signal.SIGTERM, bye_handler) + signal.signal(signal.SIGCHLD, child_handler) + + +def configure_logging(module=None): + if module: + format = '%(asctime)s: [{module}] %(levelname)s: %(message)s'.format(module=module) + + else: + format = '%(asctime)s: %(levelname)s: %(message)s' + + logging.basicConfig(filename=None, level=settings.LOG_LEVEL, + format=format, datefmt='%Y-%m-%d %H:%M:%S') + + logging.getLogger('tornado').setLevel(logging.WARN) + + +def configure_tornado(): + AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient', max_clients=16) + + +def test_requirements(): + if os.geteuid() != 0: + if settings.SMB_SHARES: + print('SMB_SHARES require root privileges') + return False + + if settings.ENABLE_REBOOT: + print('reboot requires root privileges') + return False + + try: + import tornado # @UnusedImport + + except ImportError: + logging.fatal('please install tornado version 3.1 or greater') + sys.exit(-1) + + try: + import jinja2 # @UnusedImport + + except ImportError: + logging.fatal('please install jinja2') + sys.exit(-1) + + try: + import PIL.Image # @UnusedImport + + except ImportError: + logging.fatal('please install pillow or PIL') + sys.exit(-1) + + try: + import pycurl # @UnusedImport + + except ImportError: + logging.fatal('please install pycurl') + sys.exit(-1) + + import mediafiles + has_ffmpeg = mediafiles.find_ffmpeg() is not None + + import motionctl + has_motion = motionctl.find_motion() is not None + + import v4l2ctl + has_v4lutils = v4l2ctl.find_v4l2_ctl() is not None + + import smbctl + if settings.SMB_SHARES and smbctl.find_mount_cifs() is None: + logging.fatal('please install cifs-utils') + sys.exit(-1) + + if not has_ffmpeg: + logging.info('ffmpeg not installed') + + if not has_motion: + logging.info('motion not installed') + + if not has_v4lutils: + logging.info('v4l-utils not installed') + + +def start_motion(): + import tornado.ioloop + import config + import motionctl + + ioloop = tornado.ioloop.IOLoop.instance() + + # add a motion running checker + def checker(): + if ioloop._stopped: + return + + if not motionctl.running() and motionctl.started() and config.get_enabled_local_motion_cameras(): + try: + logging.error('motion not running, starting it') + motionctl.start() + + except Exception as e: + logging.error('failed to start motion: %(msg)s' % { + 'msg': unicode(e)}, exc_info=True) + + ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) + + motionctl.start() + + ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) + + +def start_cleanup(): + import cleanup + + cleanup.start() + logging.info('cleanup started') + + +def start_wsswitch(): + import wsswitch + + wsswitch.start() + logging.info('wsswitch started') + + +def start_thumbnailer(): + import thumbnailer + + thumbnailer.start() + logging.info('thumbnailer started') + + +def run_server(): + import cleanup + import motionctl + import thumbnailer + import tornado.ioloop + import smbctl + + application.listen(settings.PORT, settings.LISTEN) + logging.info('server started') + + tornado.ioloop.IOLoop.instance().start() + + logging.info('server stopped') + + if thumbnailer.running(): + thumbnailer.stop() + logging.info('thumbnailer stopped') + + if cleanup.running(): + cleanup.stop() + logging.info('cleanup stopped') + + if motionctl.running(): + motionctl.stop() + logging.info('motion stopped') + + if settings.SMB_SHARES: + smbctl.umount_all() + logging.info('SMB shares unmounted') + + +def log_request(handler): + if handler.get_status() < 400: + log_method = logging.debug + + elif handler.get_status() < 500: + log_method = logging.warning + + else: + log_method = logging.error + + request_time = 1000.0 * handler.request.request_time() + 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) + + +def main(): + import motioneye + + load_settings() + configure_signals() + configure_logging() + test_requirements() + configure_tornado() + + logging.info('hello! this is motionEye %s' % motioneye.VERSION) + + if settings.SMB_SHARES: + import smbctl + + stop, start = smbctl.update_mounts() # @UnusedVariable + if start: + start_motion() + + else: + start_motion() + + start_cleanup() + start_wsswitch() + + if settings.THUMBNAILER_INTERVAL: + start_thumbnailer() + + run_server() + + logging.info('bye!') diff --git a/settings_default.py b/motioneye/settings.py similarity index 75% rename from settings_default.py rename to motioneye/settings.py index d200cc3..9e7f68b 100644 --- a/settings_default.py +++ b/motioneye/settings.py @@ -3,36 +3,54 @@ import logging import os.path import sys -# you normally don't have to change these -PROJECT_PATH = os.path.dirname(sys.argv[0]) +import motioneye + +# the root directory of the project +PROJECT_PATH = os.path.dirname(motioneye.__file__) + +# the templates directory TEMPLATE_PATH = os.path.join(PROJECT_PATH, 'templates') + +# the static files directory STATIC_PATH = os.path.join(PROJECT_PATH, 'static') # static files (.css, .js etc) are served at this root url STATIC_URL = '/static/' # path to the config directory; must be writable -CONF_PATH = os.path.abspath(os.path.join(PROJECT_PATH, 'conf')) +CONF_PATH = [sys.prefix, ''][sys.prefix == '/usr'] + '/etc/motioneye' # pid files go here -RUN_PATH = os.path.abspath(os.path.join(PROJECT_PATH, 'run')) +for d in ['/run', '/var/run', '/tmp', '/var/tmp']: + if os.path.exists(d): + RUN_PATH = d + break + +else: + RUN_PATH = PROJECT_PATH # log files go here -LOG_PATH = os.path.abspath(os.path.join(PROJECT_PATH, 'log')) +for d in ['/log', '/var/log', '/tmp', '/var/tmp']: + if os.path.exists(d): + LOG_PATH = d + break + +else: + LOG_PATH = RUN_PATH # default output path for media files -MEDIA_PATH = os.path.abspath(os.path.join(PROJECT_PATH, 'media')) +MEDIA_PATH = RUN_PATH # path to motion binary (automatically detected if not set) MOTION_BINARY = None -# set to logging.DEBUG for verbose output +# the log level LOG_LEVEL = logging.INFO -# set to 127.0.0.1 to restrict access to localhost +# IP addresses to listen on LISTEN = '0.0.0.0' -# change the port according to your requirements/restrictions +# the TCP port to listen on PORT = 8765 # interval in seconds at which motionEye checks the SMB mounts diff --git a/src/smbctl.py b/motioneye/smbctl.py similarity index 100% rename from src/smbctl.py rename to motioneye/smbctl.py diff --git a/static/css/frame.css b/motioneye/static/css/frame.css similarity index 100% rename from static/css/frame.css rename to motioneye/static/css/frame.css diff --git a/static/css/jquery.timepicker.css b/motioneye/static/css/jquery.timepicker.css similarity index 100% rename from static/css/jquery.timepicker.css rename to motioneye/static/css/jquery.timepicker.css diff --git a/static/css/main.css b/motioneye/static/css/main.css similarity index 100% rename from static/css/main.css rename to motioneye/static/css/main.css diff --git a/static/css/ui.css b/motioneye/static/css/ui.css similarity index 100% rename from static/css/ui.css rename to motioneye/static/css/ui.css diff --git a/static/favicon.ico b/motioneye/static/favicon.ico similarity index 100% rename from static/favicon.ico rename to motioneye/static/favicon.ico diff --git a/static/fnt/mavenpro-black-webfont.eot b/motioneye/static/fnt/mavenpro-black-webfont.eot similarity index 100% rename from static/fnt/mavenpro-black-webfont.eot rename to motioneye/static/fnt/mavenpro-black-webfont.eot diff --git a/static/fnt/mavenpro-black-webfont.svg b/motioneye/static/fnt/mavenpro-black-webfont.svg similarity index 100% rename from static/fnt/mavenpro-black-webfont.svg rename to motioneye/static/fnt/mavenpro-black-webfont.svg diff --git a/static/fnt/mavenpro-black-webfont.ttf b/motioneye/static/fnt/mavenpro-black-webfont.ttf similarity index 100% rename from static/fnt/mavenpro-black-webfont.ttf rename to motioneye/static/fnt/mavenpro-black-webfont.ttf diff --git a/static/fnt/mavenpro-black-webfont.woff b/motioneye/static/fnt/mavenpro-black-webfont.woff similarity index 100% rename from static/fnt/mavenpro-black-webfont.woff rename to motioneye/static/fnt/mavenpro-black-webfont.woff diff --git a/static/fnt/mavenpro-bold-webfont.eot b/motioneye/static/fnt/mavenpro-bold-webfont.eot similarity index 100% rename from static/fnt/mavenpro-bold-webfont.eot rename to motioneye/static/fnt/mavenpro-bold-webfont.eot diff --git a/static/fnt/mavenpro-bold-webfont.svg b/motioneye/static/fnt/mavenpro-bold-webfont.svg similarity index 100% rename from static/fnt/mavenpro-bold-webfont.svg rename to motioneye/static/fnt/mavenpro-bold-webfont.svg diff --git a/static/fnt/mavenpro-bold-webfont.ttf b/motioneye/static/fnt/mavenpro-bold-webfont.ttf similarity index 100% rename from static/fnt/mavenpro-bold-webfont.ttf rename to motioneye/static/fnt/mavenpro-bold-webfont.ttf diff --git a/static/fnt/mavenpro-bold-webfont.woff b/motioneye/static/fnt/mavenpro-bold-webfont.woff similarity index 100% rename from static/fnt/mavenpro-bold-webfont.woff rename to motioneye/static/fnt/mavenpro-bold-webfont.woff diff --git a/static/fnt/mavenpro-medium-webfont.eot b/motioneye/static/fnt/mavenpro-medium-webfont.eot similarity index 100% rename from static/fnt/mavenpro-medium-webfont.eot rename to motioneye/static/fnt/mavenpro-medium-webfont.eot diff --git a/static/fnt/mavenpro-medium-webfont.svg b/motioneye/static/fnt/mavenpro-medium-webfont.svg similarity index 100% rename from static/fnt/mavenpro-medium-webfont.svg rename to motioneye/static/fnt/mavenpro-medium-webfont.svg diff --git a/static/fnt/mavenpro-medium-webfont.ttf b/motioneye/static/fnt/mavenpro-medium-webfont.ttf similarity index 100% rename from static/fnt/mavenpro-medium-webfont.ttf rename to motioneye/static/fnt/mavenpro-medium-webfont.ttf diff --git a/static/fnt/mavenpro-medium-webfont.woff b/motioneye/static/fnt/mavenpro-medium-webfont.woff similarity index 100% rename from static/fnt/mavenpro-medium-webfont.woff rename to motioneye/static/fnt/mavenpro-medium-webfont.woff diff --git a/static/fnt/mavenpro-regular-webfont.eot b/motioneye/static/fnt/mavenpro-regular-webfont.eot similarity index 100% rename from static/fnt/mavenpro-regular-webfont.eot rename to motioneye/static/fnt/mavenpro-regular-webfont.eot diff --git a/static/fnt/mavenpro-regular-webfont.svg b/motioneye/static/fnt/mavenpro-regular-webfont.svg similarity index 100% rename from static/fnt/mavenpro-regular-webfont.svg rename to motioneye/static/fnt/mavenpro-regular-webfont.svg diff --git a/static/fnt/mavenpro-regular-webfont.ttf b/motioneye/static/fnt/mavenpro-regular-webfont.ttf similarity index 100% rename from static/fnt/mavenpro-regular-webfont.ttf rename to motioneye/static/fnt/mavenpro-regular-webfont.ttf diff --git a/static/fnt/mavenpro-regular-webfont.woff b/motioneye/static/fnt/mavenpro-regular-webfont.woff similarity index 100% rename from static/fnt/mavenpro-regular-webfont.woff rename to motioneye/static/fnt/mavenpro-regular-webfont.woff diff --git a/static/img/apply-progress.gif b/motioneye/static/img/apply-progress.gif similarity index 100% rename from static/img/apply-progress.gif rename to motioneye/static/img/apply-progress.gif diff --git a/static/img/arrows.svg b/motioneye/static/img/arrows.svg similarity index 100% rename from static/img/arrows.svg rename to motioneye/static/img/arrows.svg diff --git a/static/img/camera-progress.gif b/motioneye/static/img/camera-progress.gif similarity index 100% rename from static/img/camera-progress.gif rename to motioneye/static/img/camera-progress.gif diff --git a/static/img/combo-box-arrow.svg b/motioneye/static/img/combo-box-arrow.svg similarity index 100% rename from static/img/combo-box-arrow.svg rename to motioneye/static/img/combo-box-arrow.svg diff --git a/static/img/logout.svg b/motioneye/static/img/logout.svg similarity index 100% rename from static/img/logout.svg rename to motioneye/static/img/logout.svg diff --git a/static/img/main-loading-progress.gif b/motioneye/static/img/main-loading-progress.gif similarity index 100% rename from static/img/main-loading-progress.gif rename to motioneye/static/img/main-loading-progress.gif diff --git a/static/img/modal-progress.gif b/motioneye/static/img/modal-progress.gif similarity index 100% rename from static/img/modal-progress.gif rename to motioneye/static/img/modal-progress.gif diff --git a/static/img/motioneye-icon.svg b/motioneye/static/img/motioneye-icon.svg similarity index 100% rename from static/img/motioneye-icon.svg rename to motioneye/static/img/motioneye-icon.svg diff --git a/static/img/motioneye-logo.svg b/motioneye/static/img/motioneye-logo.svg similarity index 100% rename from static/img/motioneye-logo.svg rename to motioneye/static/img/motioneye-logo.svg diff --git a/static/img/no-camera.svg b/motioneye/static/img/no-camera.svg similarity index 100% rename from static/img/no-camera.svg rename to motioneye/static/img/no-camera.svg diff --git a/static/img/no-preview.svg b/motioneye/static/img/no-preview.svg similarity index 100% rename from static/img/no-preview.svg rename to motioneye/static/img/no-preview.svg diff --git a/static/img/settings.svg b/motioneye/static/img/settings.svg similarity index 100% rename from static/img/settings.svg rename to motioneye/static/img/settings.svg diff --git a/static/img/slider-arrow.svg b/motioneye/static/img/slider-arrow.svg similarity index 100% rename from static/img/slider-arrow.svg rename to motioneye/static/img/slider-arrow.svg diff --git a/static/img/small-progress.gif b/motioneye/static/img/small-progress.gif similarity index 100% rename from static/img/small-progress.gif rename to motioneye/static/img/small-progress.gif diff --git a/static/img/top-bar-buttons.svg b/motioneye/static/img/top-bar-buttons.svg similarity index 100% rename from static/img/top-bar-buttons.svg rename to motioneye/static/img/top-bar-buttons.svg diff --git a/static/img/validation-error.svg b/motioneye/static/img/validation-error.svg similarity index 100% rename from static/img/validation-error.svg rename to motioneye/static/img/validation-error.svg diff --git a/static/js/css-browser-selector.js b/motioneye/static/js/css-browser-selector.js similarity index 100% rename from static/js/css-browser-selector.js rename to motioneye/static/js/css-browser-selector.js diff --git a/static/js/frame.js b/motioneye/static/js/frame.js similarity index 100% rename from static/js/frame.js rename to motioneye/static/js/frame.js diff --git a/static/js/jquery.min.js b/motioneye/static/js/jquery.min.js similarity index 100% rename from static/js/jquery.min.js rename to motioneye/static/js/jquery.min.js diff --git a/static/js/jquery.mousewheel.js b/motioneye/static/js/jquery.mousewheel.js similarity index 100% rename from static/js/jquery.mousewheel.js rename to motioneye/static/js/jquery.mousewheel.js diff --git a/static/js/jquery.timepicker.min.js b/motioneye/static/js/jquery.timepicker.min.js similarity index 100% rename from static/js/jquery.timepicker.min.js rename to motioneye/static/js/jquery.timepicker.min.js diff --git a/static/js/main.js b/motioneye/static/js/main.js similarity index 99% rename from static/js/main.js rename to motioneye/static/js/main.js index ecdf58f..1048701 100644 --- a/static/js/main.js +++ b/motioneye/static/js/main.js @@ -9,6 +9,7 @@ var username = ''; var password = ''; var baseUri = null; var signatureRegExp = new RegExp('[^a-zA-Z0-9/?_.=&{}\\[\\]":, _-]', 'g'); +var initialConfigFetched = false; /* used to workaround browser extensions that trigger stupid change events */ /* utils */ @@ -2248,6 +2249,8 @@ function fetchCurrentConfig(onFetch) { } } + initialConfigFetched = true; + var i, cameras = data.cameras; if (isAdmin()) { @@ -2351,6 +2354,10 @@ function fetchCurrentCameraConfig(onFetch) { } function pushMainConfig(reboot) { + if (!initialConfigFetched) { + return; + } + var mainConfig = mainUi2Dict(); pushConfigReboot = pushConfigReboot || reboot; @@ -2361,13 +2368,17 @@ function pushMainConfig(reboot) { } function pushCameraConfig(reboot) { - var cameraConfig = cameraUi2Dict(); - var cameraId = $('#cameraSelect').val(); + if (!initialConfigFetched) { + return; + } + var cameraId = $('#cameraSelect').val(); if (!cameraId) { return; /* event triggered without a selected camera */ } + var cameraConfig = cameraUi2Dict(); + pushConfigReboot = pushConfigReboot || reboot; pushConfigs[cameraId] = cameraConfig; if (!isApplyVisible()) { diff --git a/static/js/ui.js b/motioneye/static/js/ui.js similarity index 100% rename from static/js/ui.js rename to motioneye/static/js/ui.js diff --git a/static/js/version.js b/motioneye/static/js/version.js similarity index 100% rename from static/js/version.js rename to motioneye/static/js/version.js diff --git a/src/template.py b/motioneye/template.py similarity index 100% rename from src/template.py rename to motioneye/template.py diff --git a/templates/base.html b/motioneye/templates/base.html similarity index 100% rename from templates/base.html rename to motioneye/templates/base.html diff --git a/templates/main.html b/motioneye/templates/main.html similarity index 100% rename from templates/main.html rename to motioneye/templates/main.html diff --git a/templates/version.html b/motioneye/templates/version.html similarity index 100% rename from templates/version.html rename to motioneye/templates/version.html diff --git a/src/thumbnailer.py b/motioneye/thumbnailer.py similarity index 100% rename from src/thumbnailer.py rename to motioneye/thumbnailer.py diff --git a/src/tzctl.py b/motioneye/tzctl.py similarity index 100% rename from src/tzctl.py rename to motioneye/tzctl.py diff --git a/src/update.py b/motioneye/update.py similarity index 100% rename from src/update.py rename to motioneye/update.py diff --git a/src/utils.py b/motioneye/utils.py similarity index 100% rename from src/utils.py rename to motioneye/utils.py diff --git a/src/v4l2ctl.py b/motioneye/v4l2ctl.py similarity index 100% rename from src/v4l2ctl.py rename to motioneye/v4l2ctl.py diff --git a/webhook.py b/motioneye/webhook.py similarity index 100% rename from webhook.py rename to motioneye/webhook.py diff --git a/src/wifictl.py b/motioneye/wifictl.py similarity index 100% rename from src/wifictl.py rename to motioneye/wifictl.py diff --git a/src/wsswitch.py b/motioneye/wsswitch.py similarity index 100% rename from src/wsswitch.py rename to motioneye/wsswitch.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b963858 --- /dev/null +++ b/setup.py @@ -0,0 +1,64 @@ + +# Always prefer setuptools over distutils +from setuptools import setup +# To use a consistent encoding +from codecs import open +from os import path + +here = path.abspath(path.dirname(__file__)) + +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='motioneye', + + version='0.25.2', + + description='motionEye server', + long_description=long_description, + + url='https://bitbucket.org/ccrisan/motioneye/', + + author='Calin Crisan', + author_email='ccrisan@gmail.com', + + license='GPLv3', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + 'Development Status :: 3 - Beta', + + 'Intended Audience :: End Users/Desktop', + 'Topic :: Multimedia :: Video', + + 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', + + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7' + ], + + keywords='motion video surveillance frontend', + + packages=['motioneye'], + + install_requires=['tornado>=3.1', 'jinja2', 'pillow', 'pycurl'], + + package_data={ + 'motioneye': [ + 'static/*', + 'static/*/*', + 'templates/*' + ] + }, + + data_files=[], + + entry_points={ + 'console_scripts': [ + 'motioneye=motioneye.motioneye:main', + ], + }, +) + diff --git a/src/server.py b/src/server.py deleted file mode 100644 index 623b9a4..0000000 --- a/src/server.py +++ /dev/null @@ -1,67 +0,0 @@ - -# Copyright (c) 2013 Calin Crisan -# This file is part of motionEye. -# -# motionEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from tornado.web import Application - -import handlers -import logging -import settings -import template - - -def log_request(handler): - if handler.get_status() < 400: - log_method = logging.debug - - elif handler.get_status() < 500: - log_method = logging.warning - - else: - log_method = logging.error - - request_time = 1000.0 * handler.request.request_time() - 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) -- 2.39.5