strix

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

api.py (3604B)


      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 from bottle import abort, install, route, run, static_file, request, Response, JSONPlugin
     27 from bottle import template
     28 from json import dumps
     29 from threading import Thread
     30 
     31 from . import logger
     32 from .events import camera_events, EventCache, queue_events
     33 
     34 TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
     35 def timestr_to_dt(rfc_str):
     36     return datetime.strptime(rfc_str, TIME_FORMAT)
     37 
     38 def run_api(logging_queue, base_dir, cameras, host, port, debug, queue_rx):
     39     log = logger.log(logging_queue)
     40     log.info("Starting API", base_dir=base_dir, cameras=cameras, host=host, port=port, debug=debug)
     41     EventCache.logger(log)
     42 
     43     # Listen to queue_rx for new events
     44     th = Thread(target=queue_events, args=(log, queue_rx))
     45     th.start()
     46 
     47     @route('/')
     48     @route('/<filename>')
     49     def serve_root(filename="index.html"):
     50         return static_file(filename, root=os.path.dirname(__file__)+"/ui")
     51 
     52     @route('/motion/<filepath:path>')
     53     def serve_motion(filepath):
     54         if os.path.isfile(base_dir + "/" + filepath):
     55             return static_file(filepath, root=base_dir)
     56 
     57         path = os.path.normpath(base_dir + os.path.normpath("/" + filepath))
     58         if not os.path.isdir(path):
     59             abort(404)
     60 
     61         listing = sorted([os.path.basename(f) for f in glob(path + "/*.jpg")])
     62         return template(os.path.dirname(__file__)+"/ui/dirlist.tmpl", listing=listing)
     63 
     64     @route('/api/cameras/list')
     65     def serve_cameras_list() -> Response:
     66         return {"cameras": cameras}
     67 
     68     @route('/api/events/<cameras>')
     69     def serve_events(cameras):
     70         # request.query is a bottle.MultiDict which pylint doesn't understand
     71         # pylint: disable=no-member
     72         start = timestr_to_dt(request.query.get("start", "1985-10-26 01:22:00"))
     73         end   = timestr_to_dt(request.query.get("end", datetime.now().strftime(TIME_FORMAT)))
     74         offset= int(request.query.get("offset", "0"))
     75         limit = int(request.query.get("limit", "10"))
     76         camera_list = cameras.split(",")
     77 #        log.debug("serve_events", camera_list=camera_list, start=str(start), end=str(end), offset=offset, limit=limit)
     78 
     79         events = {}
     80         for camera in camera_list:
     81             events[camera] = camera_events(log, base_dir, camera, start, end, offset, limit)
     82 
     83 #        log.debug("serve_events", events=events)
     84         return {"start":    str(start),
     85                 "end":      str(end),
     86                 "offset":   offset,
     87                 "limit":    limit,
     88                 "events":   events}
     89 
     90     # Use str as default in json dumps for objects like datetime
     91     install(JSONPlugin(json_dumps=lambda s: dumps(s, default=str)))
     92     run(host=host, port=port, debug=debug, server="gevent")
     93 
     94     th.join(30)