released v1.3.5

This commit is contained in:
Pari Malam
2026-06-27 10:35:05 +08:00
parent 5a859323a5
commit af0ba287c3
2 changed files with 281 additions and 341 deletions
+148 -86
View File
@@ -1,104 +1,166 @@
#!/usr/bin/env bash
# setup.sh Fully automatic environment setup + launcher
#
# Fixed for src/ layout: binary, configs, and RunMe.sh live under src/
# This script creates the venv at the project root and delegates to src/RunMe.sh
# Creates venv, installs dependencies, verifies structure, then launches.
# All arguments are forwarded to src/RunMe.sh.
#
# Usage:
# ./setup.sh # o11pro + hls_proxy (default)
# MONITOR=true ./setup.sh # o11pro + hls_proxy + security monitor
# HLS_PROXY=false ./setup.sh # o11pro only
# MONITOR=true HLS_PROXY=false ./setup.sh # o11pro + security monitor only
# ./setup.sh # default port 1337
# ./setup.sh 8080 # custom port
# ./setup.sh 8080 4 # custom port + verbose=4
#
# Environment variables (pass before or alongside):
# MONITOR=true Enable security monitoring proxy (port 19998)
# MONITOR_PORT=19998 Monitor proxy port
# HLS_PROXY=true Enable HLS rewrite proxy (port 9999)
# HLS_PROXY_PORT=9999 HLS proxy port
# GOMEMLIMIT=4G Override Go memory limit
# MONITOR=true Enable security monitoring proxy (port 1339)
# HLS_PROXY=false Disable HLS rewrite proxy (default: true)
# GOMEMLIMIT=4G Override Go memory limit (default: 2GiB)
# MAX_STREAMS=8 Limit concurrent streams
# ADMIN_USER=admin Static admin username
# ADMIN_PASS=secret Static admin password
# ADMIN_USER=admin Static admin username (default: admin)
# ADMIN_PASS=secret Static admin password (default: admin1337)
set -euo pipefail
SETUP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SRC_DIR="$SETUP_DIR/src"
echo "=========================================="
echo " Automatic setup and launch"
echo " Project root: $SETUP_DIR"
echo " Source dir: $SRC_DIR"
echo "=========================================="
if ! command -v python3 &> /dev/null; then
echo "Python 3 not found. Installing..."
if command -v apt-get &> /dev/null; then
sudo apt-get update
sudo apt-get install -y python3 python3-venv python3-pip
elif command -v yum &> /dev/null; then
sudo yum install -y python3 python3-pip
else
echo "ERROR: No supported package manager. Please install Python 3 manually."
exit 1
fi
else
echo "Python 3 is installed: $(python3 --version)"
fi
VENV_DIR="$SETUP_DIR/venv"
if [ ! -d "$VENV_DIR" ]; then
echo "Creating virtual environment in $VENV_DIR ..."
python3 -m venv "$VENV_DIR"
echo "Virtual environment created."
else
echo "Virtual environment already exists."
fi
echo "Installing / updating requirements from requirements.txt ..."
"$VENV_DIR/bin/pip" install --upgrade pip -q 2>&1 | tail -1
if [ -f "$SETUP_DIR/requirements.txt" ]; then
"$VENV_DIR/bin/pip" install -r "$SETUP_DIR/requirements.txt" -q 2>&1 | tail -3
echo "Dependencies installed."
else
echo "Warning: requirements.txt not found skipping package installation."
fi
RUNME="$SRC_DIR/RunMe.sh"
if [ -f "$RUNME" ]; then
# Make it executable
chmod +x "$RUNME"
echo "RunMe.sh PATH is configured dynamically."
else
echo "ERROR: RunMe.sh not found at $RUNME"
exit 1
fi
echo "Checking required files in $SRC_DIR ..."
if [ ! -f "$SRC_DIR/o11pro" ]; then
echo "ERROR: Required file 'src/o11pro' not found."
echo "Please place o11pro binary under src/."
exit 1
fi
echo "All required files present."
echo ""
MODE_PARTS=("o11pro :${1:-19999}") # FIX: was $1 (unbound when no args)
if [ "${HLS_PROXY:-true}" = "true" ]; then
MODE_PARTS+=("hls_proxy :${HLS_PROXY_PORT:-9999}")
fi
if [ "${MONITOR:-false}" = "true" ]; then
MODE_PARTS+=("monitoring :${MONITOR_PORT:-19998}")
fi
echo "Launch mode: ${MODE_PARTS[*]}"
echo ""
echo "=========================================="
echo " Launching RunMe.sh with venv Python"
echo "=========================================="
# cd into src/ so RunMe.sh finds its binary and configs
# Switch to src/ early — venv, scripts, and binary all live here
cd "$SRC_DIR"
# ─── Colors ────────────────────────────────────────────────────────────
BLD='\033[1m'
DIM='\033[2m'
RED='\033[0;31m'
GRN='\033[0;32m'
YLW='\033[0;33m'
BLU='\033[0;34m'
MAG='\033[0;35m'
CYN='\033[0;36m'
RST='\033[0m'
CHECK="${GRN}\xE2\x9C\x94${RST}"
CROSS="${RED}\xE2\x9C\x98${RST}"
ARROW="${CYN}\xE2\x96\xB6${RST}"
# ─── Helpers ───────────────────────────────────────────────────────────
ok() { echo -e " ${CHECK} ${BLD}$1${RST} $2"; }
info() { echo -e " ${ARROW} ${DIM}$1${RST}"; }
warn() { echo -e " ${YLW}\xE2\x9A\xA0${RST} ${BLD}$1${RST} $2"; }
fail() { echo -e " ${CROSS} ${RED}$1${RST}"; }
sep() { echo -e " ${DIM}──────────────────────────────────────────────${RST}"; }
box() {
local s="$1" w=56
echo -e " ${DIM}\xE2\x95\x94$(printf '\xE2\x95\x90%.0s' $(seq 1 $w))\xE2\x95\x97${RST}"
echo -e " ${DIM}\xE2\x95\x91${RST} ${BLD}$s${RST}"
echo -e " ${DIM}\xE2\x95\x9A$(printf '\xE2\x95\x90%.0s' $(seq 1 $w))\xE2\x95\x9D${RST}"
}
# ─── Header ────────────────────────────────────────────────────────────
clear 2>/dev/null || true
echo
box "o11pro Setup & Launch"
echo
# ─── Phase 1: Python 3 ─────────────────────────────────────────────────
echo -e " ${BLU}\xE2\x96\xBC${RST} ${BLD}Phase 1${RST} \xE2\x80\x94 Python 3"
echo
if ! command -v python3 &>/dev/null; then
warn "Python 3 not found" "attempting install..."
if command -v apt-get &>/dev/null; then
sudo apt-get update && sudo apt-get install -y python3 python3-venv python3-pip
elif command -v yum &>/dev/null; then
sudo yum install -y python3 python3-pip
else
fail "No supported package manager. Install Python 3 manually."; exit 1
fi
fi
ok "Python" "$(python3 --version)"
echo
# ─── Phase 2: Virtual Environment ──────────────────────────────────────
echo -e " ${BLU}\xE2\x96\xBC${RST} ${BLD}Phase 2${RST} \xE2\x80\x94 Virtual Environment"
echo
VENV_DIR="$SRC_DIR/venv"
if [ ! -d "$VENV_DIR" ]; then
info "Creating venv at ${DIM}$VENV_DIR${RST}..."
python3 -m venv "$VENV_DIR"
ok "venv" "created"
else
ok "venv" "exists at ${DIM}$VENV_DIR${RST}"
fi
echo
# ─── Phase 3: Dependencies ─────────────────────────────────────────────
echo -e " ${BLU}\xE2\x96\xBC${RST} ${BLD}Phase 3${RST} \xE2\x80\x94 Python Dependencies"
echo
"$VENV_DIR/bin/pip" install --upgrade pip -q 2>/dev/null
if [ -f "$SETUP_DIR/requirements.txt" ]; then
REQ_COUNT=$(grep -cEv '^\s*(#|$)' "$SETUP_DIR/requirements.txt" || echo 0)
info "Installing ${REQ_COUNT} packages from ${DIM}requirements.txt${RST}..."
"$VENV_DIR/bin/pip" install -r "$SETUP_DIR/requirements.txt" -q 2>&1 | tail -1
ok "dependencies" "ready"
else
warn "requirements.txt not found" "\xE2\x80\x94 skipping packages"
fi
echo
# ─── Phase 4: Project Structure ────────────────────────────────────────
echo -e " ${BLU}\xE2\x96\xBC${RST} ${BLD}Phase 4${RST} \xE2\x80\x94 Project Structure"
echo
ok "root" "${DIM}$SETUP_DIR${RST}"
# Launcher scripts
LAUNCHER_COUNT=$(ls -1 *.sh 2>/dev/null | wc -l)
ok "src/" "${LAUNCHER_COUNT} launcher(s)"
# Binary
BINARY=""
for b in o11pro o11; do
[ -f "$b" ] && BINARY="$b" && break
done
if [ -n "$BINARY" ]; then
BIN_SIZE=$(stat -c%s "$BINARY" 2>/dev/null | numfmt --to=iec 2>/dev/null || echo "?")
ok "binary" "${DIM}$BINARY${RST} (${BIN_SIZE})"
[ -x "$BINARY" ] || chmod +x "$BINARY" && ok "binary" "made executable"
else
fail "No o11pro binary found in ${DIM}$SRC_DIR${RST}"; exit 1
fi
# RunMe.sh
if [ -f "RunMe.sh" ]; then
chmod +x "RunMe.sh"
ok "launcher" "${DIM}RunMe.sh${RST}"
else
fail "RunMe.sh not found in ${DIM}$SRC_DIR${RST}"; exit 1
fi
# Provider configs
PROV_DIR="$SETUP_DIR/providers"
PROV_COUNT=0
if [ -d "$PROV_DIR" ]; then
PROV_COUNT=$(find "$PROV_DIR" -maxdepth 1 -name '*.cfg' 2>/dev/null | wc -l)
fi
if [ "$PROV_COUNT" -gt 0 ]; then
ok "providers/" "${PROV_COUNT} config(s)"
else
info "No provider configs yet — place .cfg files in ${DIM}providers/${RST}"
fi
# HLS proxy maps
CACHE_DIR="$SETUP_DIR/cache"
ORIG_MAP="$CACHE_DIR/orig_urls.json"
if [ -f "$ORIG_MAP" ]; then
MAP_COUNT=$(python3 -c "import json; print(len(json.load(open('$ORIG_MAP'))))" 2>/dev/null || echo "?")
ok "HLS map" "${MAP_COUNT} channel(s) in ${DIM}cache/orig_urls.json${RST}"
else
info "HLS map will be auto-generated on launch"
fi
echo
# ─── Phase 5: Launch ───────────────────────────────────────────────────
echo -e " ${GRN}\xE2\x96\xB6${RST} ${BLD}Starting o11pro${RST} — delegating to src/RunMe.sh"
echo
export PATH="$VENV_DIR/bin:$PATH"
exec ./RunMe.sh "$@"
+133 -255
View File
@@ -1,56 +1,32 @@
#!/bin/bash
#!/usr/bin/env bash
# RunMe.sh o11pro launcher
#
# RunMe.sh Launcher for o11pro
#
# Incorporates all fixes from the analysis:
# - KID format patch (DRM key lookup)
# - Banner string patches (nulled!! -> Ap0dexMe0)
# - Provider config fixes (StreamsCount, PipeOutputCmdFormated)
# - Memory mitigation (-keep=false, GOMEMLIMIT)
# - Correct PATH for python3.13 dependencies
# Starts the Go binary, HLS proxy, and security monitor.
# Run from inside src/ (setup.sh handles this automatically).
#
# Usage:
# ./RunMe.sh # Run with defaults (port 1337, verbose=2)
# ./RunMe.sh 8080 # Run on custom port
# ./RunMe.sh 8080 4 # Run on port 8080 with verbose=4 (trace)
# GOMEMLIMIT=4G ./RunMe.sh # Override memory limit
# MAX_STREAMS=8 ./RunMe.sh # Override max concurrent streams
# MONITOR=true ./RunMe.sh # Enable security monitoring proxy
# HLS_PROXY=false ./RunMe.sh # Disable HLS proxy
#
# Files required (in same directory as this script):
# o11pro Patched binary
# keys.txt DRM KID:key pairs (optional)
# ./RunMe.sh # default port 1337
# ./RunMe.sh 8080 # custom port
# ./RunMe.sh 8080 4 # custom port + verbose=4
# GOMEMLIMIT=4G ./RunMe.sh # override memory limit
# MAX_STREAMS=8 ./RunMe.sh # limit concurrent streams
# MONITOR=false ./RunMe.sh # disable security monitor
# HLS_PROXY=false ./RunMe.sh # disable HLS proxy
set -euo pipefail
# Configuration
# Security monitor: set to true to run through the HTTP proxy/monitor
# Architecture: Client -> :1339 (proxy/monitor) -> :1337 (real o11 API)
# ─── Config Defaults ───────────────────────────────────────────────────
MONITOR="${MONITOR:-true}"
# Monitor proxy listen port (only used when MONITOR=true)
MONITOR_PORT="${MONITOR_PORT:-1339}"
# FIX: HLS Proxy config was missing entirely
# Architecture: Player -> :1338 (hls_proxy) -> upstream CDN
HLS_PROXY="${HLS_PROXY:-true}"
HLS_PROXY_PORT="${HLS_PROXY_PORT:-1338}"
HLS_PROXY_BIND="${HLS_PROXY_BIND:-127.0.0.1}"
# Path setup: need /usr/bin first so binary spawns python3.13 (has deps)
# instead of venv python3.12 (lacks deps like curl_cffi, cloudscraper)
# VENV_PATCHED
KID_PATCH_OFFSET="${KID_PATCH_OFFSET:-0x15625cd}"
# Port for HTTP API and streaming (default 1337, override with $1)
PORT="${1:-1337}"
# FIX: was VERBOSE="${2:-2}" (always defaulted to 2 even when $2 was set)
VERBOSE="${2:-2}"
# Bind address: 127.0.0.1 = all interfaces (use 127.0.0.1 for localhost-only)
BIND="${BIND:-127.0.0.1}"
GOMEMLIMIT="${GOMEMLIMIT:-2GiB}"
@@ -60,279 +36,181 @@ HTTPS="${HTTPS:-false}"
ADMIN_USER="${ADMIN_USER:-admin}"
ADMIN_PASS="${ADMIN_PASS:-admin1337}"
# Working directory (where binary and configs live)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
export PATH="$PROJECT_ROOT/venv/bin:/usr/bin:/bin:/usr/local/bin:${PATH:-}"
VENV_DIR="$SCRIPT_DIR/venv"
HLS_PROXY_CONFIG="${HLS_PROXY_CONFIG:-$PROJECT_ROOT/cache/orig_urls.json}"
export PATH="$VENV_DIR/bin:/usr/bin:/bin:/usr/local/bin:${PATH:-}"
cd "$SCRIPT_DIR"
# Pre-flight checks
# ─── Colors ────────────────────────────────────────────────────────────
BLD='\033[1m'; DIM='\033[2m'
RED='\033[0;31m'; GRN='\033[0;32m'; YLW='\033[0;33m'; CYN='\033[0;36m'
RST='\033[0m'
CHECK="${GRN}\xE2\x9C\x94${RST}"; CROSS="${RED}\xE2\x9C\x98${RST}"
ARROW="${CYN}\xE2\x96\xB6${RST}"
echo "=========================================="
echo " o11pro launcher"
echo "=========================================="
echo ""
ok() { echo -e " ${CHECK} ${BLD}$1${RST} $2"; }
info() { echo -e " ${ARROW} ${DIM}$1${RST}"; }
warn() { echo -e " ${YLW}\xE2\x9A\xA0${RST} ${BLD}$1${RST} $2"; }
fail() { echo -e " ${CROSS} ${RED}$1${RST}"; exit 1; }
# ─── Pre-flight ────────────────────────────────────────────────────────
BINARY="o11pro"
if [ ! -f "$BINARY" ]; then
echo "ERROR: Binary '$BINARY' not found in $SCRIPT_DIR"
exit 1
fi
# Verify the binary has the KID patch (not the original REDA bug)
KID_PATCH=$(python3 -c "
with open('$BINARY','rb') as f:
f.seek($KID_PATCH_OFFSET)
b = f.read(4)
print('OK' if b == b'%02x' else 'MISSING')
" 2>/dev/null || echo "CHECK_FAILED")
if [ "$KID_PATCH" != "OK" ]; then
echo "WARNING: KID format patch not detected in binary!"
echo ""
fi
chmod +x "$BINARY"
[ "$KID_PATCH" = "OK" ] || warn "KID patch" "NOT detected"
if [ ! -f "keys.txt" ]; then
echo "WARNING: keys.txt not found encrypted streams will fail"
echo ""
else
KEY_COUNT=$(grep -c ':' keys.txt 2>/dev/null || echo 0)
echo "Found keys.txt with $KEY_COUNT KID:key pairs"
touch keys.txt
fi
cp keys.txt keys/ 2>/dev/null || true
PYTHON_DEPS_OK=$(python3 -c "
try:
import curl_cffi, cloudscraper, dns, requests, requests_toolbelt, socks
print('OK')
except ImportError as e:
print('MISSING: ' + str(e))
" 2>/dev/null || echo "CHECK_FAILED")
if [ "$PYTHON_DEPS_OK" != "OK" ]; then
echo "WARNING: Python dependencies missing: $PYTHON_DEPS_OK"
echo ""
fi
# Prepare directories
echo "Preparing directories..."
mkdir -p hls/live keys epg dl manifests offair overlay logos fonts rec scripts logs providers cache
if [ -f "keys.txt" ] && [ ! -f "keys/keys.txt" ]; then
cp keys.txt keys/ 2>/dev/null || true
fi
# Build command line
mkdir -p hls/live keys epg dl manifests offair overlay logos fonts \
rec scripts logs providers cache
# ─── Build Args ────────────────────────────────────────────────────────
ARGS="-c o11.cfg -p $PORT -b $BIND -stdout -v $VERBOSE"
if [ "$KEEP_FALSE" = "true" ]; then
ARGS="$ARGS -keep=false"
ARGS="$ARGS -keep=false"
fi
if [ "$HTTPS" = "true" ]; then
ARGS="$ARGS -https"
if [ ! -f "server.crt" ] || [ ! -f "server.key" ]; then
echo "WARNING: -https requested but server.crt/server.key not found"
fi
ARGS="$ARGS -https"
[ -f "server.crt" ] && [ -f "server.key" ] || warn "HTTPS" "missing certs"
fi
if [ -n "$ADMIN_USER" ] && [ -n "$ADMIN_PASS" ]; then
ARGS="$ARGS -user $ADMIN_USER -password $ADMIN_PASS"
ARGS="$ARGS -user $ADMIN_USER -password $ADMIN_PASS"
fi
# Set Go runtime environment
GOMEMLIMIT_BYTES=0
if [ -n "$GOMEMLIMIT" ] && [ "$GOMEMLIMIT" != "0" ]; then
GOMEMLIMIT_BYTES=$(python3 -c "
GOMEMLIMIT_BYTES=$(python3 -c "
import re
s = '$GOMEMLIMIT'.strip()
m = re.match(r'^(\d+(?:\.\d+)?)\s*([KMGT]i?B?|B)?$', s, re.I)
if not m:
print(0)
else:
n = float(m.group(1))
unit = (m.group(2) or 'B').upper()
mult = {'B':1, 'KB':1000, 'KIB':1024, 'MB':1000000, 'MIB':1048576,
'GB':1000000000, 'GIB':1073741824, 'TB':1000000000000, 'TIB':1099511627776}
print(int(n * mult.get(unit, 1)))
m = re.match(r'^(\d+(?:\.\d+)?)\s*([KMGT]i?B?|B)?\$', s, re.I)
if not m: print(0); exit()
n = float(m.group(1))
unit = (m.group(2) or 'B').upper()
mult = {'B':1, 'KB':1000, 'KIB':1024, 'MB':1000000, 'MIB':1048576,
'GB':1000000000, 'GIB':1073741824, 'TB':1000000000000, 'TIB':1099511627776}
print(int(n * mult.get(unit, 1)))
" 2>/dev/null || echo "0")
if [ "$GOMEMLIMIT_BYTES" -gt 0 ]; then
export GOMEMLIMIT="$GOMEMLIMIT_BYTES"
echo "Go memory limit: $GOMEMLIMIT bytes ($GOMEMLIMIT_BYTES bytes)"
fi
fi
[ "$GOMEMLIMIT_BYTES" -gt 0 ] && export GOMEMLIMIT="$GOMEMLIMIT_BYTES"
export GOTRACEBACK="${GOTRACEBACK:-0}"
# Kill any existing instance
# ─── Launch ────────────────────────────────────────────────────────────
# Kill existing instance on our port
EXISTING_PID=$(pgrep -f "o11pro.*-p $PORT" 2>/dev/null || true)
if [ -n "$EXISTING_PID" ]; then
echo "Killing existing instance on port $PORT (PID $EXISTING_PID)..."
kill "$EXISTING_PID" 2>/dev/null || true
sleep 2
if kill -0 "$EXISTING_PID" 2>/dev/null; then
kill -9 "$EXISTING_PID" 2>/dev/null || true
sleep 1
fi
info "Killing existing o11pro on :${PORT} (PID ${EXISTING_PID})..."
kill "$EXISTING_PID" 2>/dev/null || true
sleep 2
if kill -0 "$EXISTING_PID" 2>/dev/null; then
kill -9 "$EXISTING_PID" 2>/dev/null || true
sleep 1
fi
fi
# Launch
if [ "$MONITOR" != "true" ] && [ "$HLS_PROXY" != "true" ]; then
echo -e " ${GRN}\xE2\x96\xB6${RST} ${BLD}o11pro${RST} on :${PORT}"
exec "./$BINARY" $ARGS
fi
echo ""
echo "=========================================="
echo " Launching o11pro"
echo "=========================================="
echo " Port: $PORT"
echo " Bind: $BIND"
echo " Verbose: $VERBOSE"
echo " Keep files: false (memory-safe mode)"
echo " Memory cap: ${GOMEMLIMIT:-none}"
echo " Max streams: ${MAX_STREAMS:-unlimited}"
echo " HTTPS: $HTTPS"
echo " HLS Proxy: $HLS_PROXY${HLS_PROXY:+ (port $HLS_PROXY_PORT)}"
echo " Security mon: $MONITOR${MONITOR:+ (port $MONITOR_PORT)}"
echo "=========================================="
echo ""
echo "Service endpoints:"
if [ "$MONITOR" = "true" ]; then
echo " Web UI (monitored): http://$BIND:$MONITOR_PORT (-> o11 :$PORT)"
else
echo " Web UI (direct): http://$BIND:$PORT"
fi
if [ "$HLS_PROXY" = "true" ]; then
echo " HLS Proxy: http://$HLS_PROXY_BIND:$HLS_PROXY_PORT"
echo " Channel manifest: http://$HLS_PROXY_BIND:$HLS_PROXY_PORT/channel/{name}/master.m3u8"
fi
if [ "$MONITOR" = "true" ]; then
echo " Audit log: logs/audit.log"
echo " Alert log: logs/audit_alerts.log"
fi
echo ".++===========================================================================================++."
echo ""
# FIX: Unified background PID tracking + cleanup (replaces separate handlers)
# ── Background mode ─────────────────────────────────────────────────
_BG_PIDS=""
cleanup_all() {
echo ""
echo "Shutting down..."
for pid in $_BG_PIDS; do
kill "$pid" 2>/dev/null || true
done
for pid in $_BG_PIDS; do
wait "$pid" 2>/dev/null || true
done
echo "All processes stopped"
echo
echo -e " ${YLW}\xE2\x96\xA0${RST} ${BLD}Shutting down${RST}..."
for pid in $_BG_PIDS; do kill "$pid" 2>/dev/null || true; done
for pid in $_BG_PIDS; do wait "$pid" 2>/dev/null || true; done
ok "done" ""
}
trap cleanup_all EXIT INT TERM
if [ "$MONITOR" = "true" ] || [ "$HLS_PROXY" = "true" ]; then
# FIX: Background mode for both HLS_PROXY and MONITOR (were separate)
trap cleanup_all EXIT INT TERM
echo -e " ${GRN}\xE2\x96\xB6${RST} ${BLD}Starting o11pro${RST} on :${PORT}..."
"./$BINARY" $ARGS &
O11_PID=$!
_BG_PIDS="$O11_PID"
# Start o11pro in background
echo "Starting o11pro in background..."
"./$BINARY" $ARGS & # FIX: was "$BINARY" (not in PATH)
O11_PID=$!
_BG_PIDS="$O11_PID"
echo "o11pro started (PID $O11_PID)"
info "Waiting for port ${PORT}..."
_O11_TRIES=0
while [ $_O11_TRIES -lt 30 ]; do
_O11_TRIES=$((_O11_TRIES + 1))
if python3 -c "import socket; s=socket.socket(); s.settimeout(1); s.connect(('127.0.0.1',$PORT)); s.close()" 2>/dev/null; then
ok "ready" ":${PORT}"
break
fi
[ $_O11_TRIES -eq 30 ] && fail "o11pro did not start within 30s"
sleep 1
done
# Wait for o11pro to be ready
echo "Waiting for o11pro to be ready on port $PORT..."
_O11_TRIES=0
while [ $_O11_TRIES -lt 30 ]; do
_O11_TRIES=$((_O11_TRIES + 1))
if python3 -c "import socket; s=socket.socket(); s.settimeout(1); s.connect(('127.0.0.1',$PORT)); s.close()" 2>/dev/null; then
echo ".++===========================================================================================++."
break
fi
if [ $_O11_TRIES -eq 30 ]; then
echo "ERROR: o11pro did not start in time"
kill "$O11_PID" 2>/dev/null || true
exit 1
fi
sleep 1
done
# Start HLS Proxy if enabled
if [ "$HLS_PROXY" = "true" ]; then
if [ ! -f "modules/hls_proxy.py" ]; then
echo "WARNING: modules/hls_proxy.py not found skipping HLS proxy"
else
# Auto-generate orig_urls.json from provider .cfg files
if [ -f "modules/generate_orig_urls.py" ]; then
echo "Generating HLS proxy config from providers..."
python3 modules/generate_orig_urls.py \
--dir "$PROJECT_ROOT/providers" \
--output "$HLS_PROXY_CONFIG" || true
fi
if [ ! -f "$HLS_PROXY_CONFIG" ]; then
echo "WARNING: HLS proxy config not found at $HLS_PROXY_CONFIG skipping HLS proxy"
else
echo "Starting HLS Proxy on port $HLS_PROXY_PORT..."
python3 modules/hls_proxy.py \
--config "$HLS_PROXY_CONFIG" \
--port "$HLS_PROXY_PORT" \
--bind "$HLS_PROXY_BIND" &
HLS_PID=$!
_BG_PIDS="$_BG_PIDS $HLS_PID"
echo "HLS Proxy started (PID $HLS_PID)"
fi
fi
# HLS Proxy
if [ "$HLS_PROXY" = "true" ]; then
if [ ! -f "modules/hls_proxy.py" ]; then
warn "HLS proxy" "not found — skipping"
else
if [ -f "modules/generate_orig_urls.py" ]; then
python3 modules/generate_orig_urls.py \
--dir "$PROJECT_ROOT/providers" \
--output "$HLS_PROXY_CONFIG" 2>/dev/null || true
fi
# Start security monitor if enabled
if [ "$MONITOR" = "true" ]; then
if [ ! -f "modules/monitoring.py" ]; then
echo "ERROR: modules/monitoring.py not found cannot start monitor"
exit 1
fi
# FIX: Build monitor command array with explicit --pid (avoids flaky auto-detection)
# FIX: Log to persistent logs/ directory instead of /tmp
MONITOR_CMD=(
python3 modules/monitoring.py
--proxy-mode
--proxy-port "$MONITOR_PORT"
--target-port "$PORT"
--log "logs/audit.log"
--alerts "logs/audit_alerts.log"
)
if [ -n "$O11_PID" ] && kill -0 "$O11_PID" 2>/dev/null; then
MONITOR_CMD+=(--pid "$O11_PID")
fi
if [ -n "${MONITOR_ARGS:-}" ]; then
MONITOR_CMD+=($MONITOR_ARGS)
fi
echo "Security monitor enabled"
echo " Proxy port: $MONITOR_PORT (-> o11 API :$PORT)"
echo " Process scan: PID $O11_PID"
echo " File watch: keys.txt, providers/, logs/, hls/"
echo " Audit log: logs/audit.log"
echo " Alert log: logs/audit_alerts.log"
echo ""
echo "Starting security monitor on port $MONITOR_PORT..."
echo "Press Ctrl+C to stop"
echo ""
exec "${MONITOR_CMD[@]}"
if [ ! -f "$HLS_PROXY_CONFIG" ]; then
warn "HLS proxy" "config missing — skipping"
else
# No foreground monitor keep the script alive
echo ""
echo "All services running. Press Ctrl+C to stop."
echo ""
wait -n 2>/dev/null || wait
echo -e " ${GRN}\xE2\x96\xB6${RST} ${BLD}HLS proxy${RST} on :${HLS_PROXY_PORT}..."
python3 modules/hls_proxy.py \
--config "$HLS_PROXY_CONFIG" \
--port "$HLS_PROXY_PORT" \
--bind "$HLS_PROXY_BIND" &
_BG_PIDS="$_BG_PIDS $!"
ok "HLS proxy" "PID $!"
fi
fi
fi
else
# Direct mode: run o11pro directly (no proxies)
echo "Press Ctrl+C to stop"
echo ""
exec "./$BINARY" $ARGS # FIX: was "$BINARY" (not in PATH)
fi
# Security monitor
if [ "$MONITOR" = "true" ]; then
[ -f "modules/monitoring.py" ] || fail "monitoring.py not found"
MONITOR_CMD=(
python3 modules/monitoring.py
--proxy-mode
--proxy-port "$MONITOR_PORT"
--target-port "$PORT"
--log "logs/audit.log"
--alerts "logs/audit_alerts.log"
)
if [ -n "$O11_PID" ] && kill -0 "$O11_PID" 2>/dev/null; then
MONITOR_CMD+=(--pid "$O11_PID")
fi
[ -n "${MONITOR_ARGS:-}" ] && MONITOR_CMD+=($MONITOR_ARGS)
echo
echo -e " ${GRN}\xE2\x96\xB6${RST} ${BLD}Security monitor${RST} on :${MONITOR_PORT}"
echo -e " ${DIM} Web UI http://${BIND}:${MONITOR_PORT}${RST}"
echo -e " ${DIM} Audit log logs/audit.log${RST}"
echo
echo -e " ${DIM}Press Ctrl+C to stop all services${RST}"
echo
exec "${MONITOR_CMD[@]}"
fi
echo
echo -e " ${DIM}All services running. Press Ctrl+C to stop.${RST}"
echo
wait -n 2>/dev/null || wait