strix

A simple web UI for motion
git clone https://www.brianlane.com/git/strix
Log | Files | Refs | LICENSE

api.py (3654B)


      1 # api.py
      2 #
      3 # Copyright (C) 2017 Brian C. Lane
      4 #
      5 # This program is free software; you can redistribute it and/or modify
      6 # it under the terms of the GNU General Public License as published by
      7 # the Free Software Foundation; either version 2 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License
     16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 from gevent import monkey; monkey.patch_all()
     18 from datetime import datetime
     19 from glob import glob
     20 import os
     21 
     22 # Fix mimetypes so that it recognized m4v as video/mp4
     23 import mimetypes
     24 mimetypes.add_type("video/mp4", ".m4v")
     25 
     26 import bottle
     27 from bottle import abort, install, route, run, static_file, request, Response, JSONPlugin
     28 from bottle import template
     29 from json import dumps
     30 from threading import Thread
     31 
     32 from . import logger
     33 from .events import camera_events, EventCache, queue_events
     34 
     35 bottle.TEMPLATE_PATH.insert(0, os.path.dirname(__file__)+"/ui/")
     36 
     37 TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
     38 def timestr_to_dt(rfc_str):
     39     return datetime.strptime(rfc_str, TIME_FORMAT)
     40 
     41 def run_api(logging_queue, base_dir, cameras, host, port, debug, queue_rx):
     42     log = logger.log(logging_queue)
     43     log.info("Starting API", base_dir=base_dir, cameras=cameras, host=host, port=port, debug=debug)
     44     EventCache.logger(log)
     45 
     46     # Listen to queue_rx for new events
     47     th = Thread(target=queue_events, args=(log, queue_rx))
     48     th.start()
     49 
     50     @route('/')
     51     @route('/<filename>')
     52     def serve_root(filename="index.html"):
     53         return static_file(filename, root=os.path.dirname(__file__)+"/ui")
     54 
     55     @route('/motion/<filepath:path>')
     56     def serve_motion(filepath):
     57         if os.path.isfile(base_dir + "/" + filepath):
     58             return static_file(filepath, root=base_dir)
     59 
     60         path = os.path.normpath(base_dir + os.path.normpath("/" + filepath))
     61         if not os.path.isdir(path):
     62             abort(404)
     63 
     64         listing = sorted([os.path.basename(f) for f in glob(path + "/*.jpg")])
     65         return template("dirlist.tmpl", listing=listing)
     66 
     67     @route('/api/cameras/list')
     68     def serve_cameras_list() -> Response:
     69         return {"cameras": cameras}
     70 
     71     @route('/api/events/<cameras>')
     72     def serve_events(cameras):
     73         # request.query is a bottle.MultiDict which pylint doesn't understand
     74         # pylint: disable=no-member
     75         start = timestr_to_dt(request.query.get("start", "1985-10-26 01:22:00"))
     76         end   = timestr_to_dt(request.query.get("end", datetime.now().strftime(TIME_FORMAT)))
     77         offset= int(request.query.get("offset", "0"))
     78         limit = int(request.query.get("limit", "10"))
     79         camera_list = cameras.split(",")
     80 #        log.debug("serve_events", camera_list=camera_list, start=str(start), end=str(end), offset=offset, limit=limit)
     81 
     82         events = {}
     83         for camera in camera_list:
     84             events[camera] = camera_events(log, base_dir, camera, start, end, offset, limit)
     85 
     86 #        log.debug("serve_events", events=events)
     87         return {"start":    str(start),
     88                 "end":      str(end),
     89                 "offset":   offset,
     90                 "limit":    limit,
     91                 "events":   events}
     92 
     93     # Use str as default in json dumps for objects like datetime
     94     install(JSONPlugin(json_dumps=lambda s: dumps(s, default=str)))
     95     run(host=host, port=port, debug=debug, server="gevent")
     96 
     97     th.join(30)