Initial commit — Alta Video Player (WebAVP)
Web-based surveillance video player for Alta/Ava Security camera exports with multi-camera sync, timeline, digital zoom, motion analytics, and cryptographic integrity verification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Alta Video Player — lightweight HTTPS server using only Python stdlib."""
|
||||
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||
from urllib.parse import parse_qs, urlencode, urlparse
|
||||
from urllib.request import urlopen
|
||||
from urllib.error import URLError
|
||||
|
||||
PORT = 5152
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
||||
TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
|
||||
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
parsed = urlparse(self.path)
|
||||
path = parsed.path
|
||||
|
||||
if path == "/":
|
||||
self._serve_file(os.path.join(TEMPLATES_DIR, "index.html"), "text/html")
|
||||
elif path.startswith("/static/"):
|
||||
rel = path[len("/static/"):]
|
||||
file_path = os.path.join(STATIC_DIR, rel)
|
||||
if not os.path.realpath(file_path).startswith(os.path.realpath(STATIC_DIR)):
|
||||
self.send_error(403)
|
||||
return
|
||||
mime = mimetypes.guess_type(file_path)[0] or "application/octet-stream"
|
||||
self._serve_file(file_path, mime)
|
||||
elif path == "/api/verify-cert":
|
||||
self._proxy_verify(parsed.query)
|
||||
else:
|
||||
self.send_error(404)
|
||||
|
||||
def _serve_file(self, file_path, content_type):
|
||||
try:
|
||||
with open(file_path, "rb") as f:
|
||||
data = f.read()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Content-Length", len(data))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
except FileNotFoundError:
|
||||
self.send_error(404)
|
||||
|
||||
def _proxy_verify(self, query_string):
|
||||
params = parse_qs(query_string)
|
||||
serial = params.get("serial", [""])[0]
|
||||
cert_hash = params.get("certificateHash", [""])[0]
|
||||
|
||||
if not serial or not cert_hash:
|
||||
self._json_response(400, {"verified": False, "error": "Missing parameters"})
|
||||
return
|
||||
|
||||
try:
|
||||
qs = urlencode({"serial": serial, "certificateHash": cert_hash})
|
||||
url = f"https://aware.avasecurity.com/api/v1/public/verifyServerCertificate?{qs}"
|
||||
resp = urlopen(url, timeout=10)
|
||||
if 200 <= resp.status < 300:
|
||||
self._json_response(200, {"verified": True})
|
||||
else:
|
||||
self._json_response(200, {"verified": False, "error": f"HTTP {resp.status}"})
|
||||
except URLError as e:
|
||||
self._json_response(200, {"verified": False, "error": str(e)})
|
||||
|
||||
def _json_response(self, status, data):
|
||||
body = json.dumps(data).encode()
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Content-Length", len(body))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
print(f"[AVP] {args[0]}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
server = HTTPServer(("0.0.0.0", PORT), Handler)
|
||||
print(f"Alta Video Player running on http://0.0.0.0:{PORT}")
|
||||
server.serve_forever()
|
||||
Reference in New Issue
Block a user