from flask import Blueprint, current_app, jsonify, render_template, request bp = Blueprint("main", __name__) def _check_hook_auth(): """MediaMTX hooks authenticate with a simple shared-secret token so random requests to /hooks/* can't spoof stream start/stop events. Not meant to be a strong secret — just keeps it out of casual reach.""" token = current_app.hook_token if not token: return True provided = request.args.get("token") or request.headers.get("X-Hook-Token") return provided == token @bp.route("/") def index(): return render_template( "index.html", domain=current_app.domain, rtmp_port=current_app.rtmp_port, ) @bp.route("/api/active") def api_active(): return jsonify(current_app.state.active()) @bp.route("/api/history") def api_history(): return jsonify(current_app.state.history()) @bp.route("/health") def health(): return jsonify({"status": "ok"}) def _check_creds_auth(): """Separate token from the hook auth so the IRC-bot-facing credential endpoint can be rotated independently of the MediaMTX hook token.""" token = current_app.creds_token if not token: return True provided = request.args.get("token") or request.headers.get("X-Creds-Token") return provided == token @bp.route("/api/creds") def api_creds(): """Returns the current publish URL for the IRC bot to hand out. Not meant to be a strong secret — the IRC channel is a high-trust environment; this just keeps it off the public landing page.""" if not _check_creds_auth(): return jsonify({"error": "unauthorized"}), 401 url = ( f"rtmp://{current_app.domain}:{current_app.rtmp_port}/live" f"?user={current_app.publish_user}&pass={current_app.publish_password}" ) return jsonify({ "url": url, "user": current_app.publish_user, "password": current_app.publish_password, }) @bp.route("/hooks/ready", methods=["POST"]) def hook_ready(): if not _check_hook_auth(): return jsonify({"error": "unauthorized"}), 401 path = request.form.get("path") or request.args.get("path") source_type = request.form.get("source_type") or request.args.get("source_type") if not path: return jsonify({"error": "missing path"}), 400 current_app.state.on_ready(path, source_type) return jsonify({"ok": True}) @bp.route("/hooks/not-ready", methods=["POST"]) def hook_not_ready(): if not _check_hook_auth(): return jsonify({"error": "unauthorized"}), 401 path = request.form.get("path") or request.args.get("path") if not path: return jsonify({"error": "missing path"}), 400 current_app.state.on_not_ready(path) return jsonify({"ok": True})