A unified streaming control panel that centralizes Twitch management, OBS scene automation, bitrate failover, raid auto-stop, admin chat commands, BELABOX + restream endpoints settings, alert sounds, chat viewing, and remote stream PC control—built to keep a flaky connection stable and reactive from one dashboard.
- Overview
- Features
- Architecture
- Quick Start
- Prerequisites
- Installation
- Configuration
- Running the Services
- Using the Web UI
- Restream Management
- Chat Commands
- Bitrate & Raid Automation
- Twitch Integration & Tokens
- Alert Sound
- Logs Viewer
- Health Indicators
- Security Recommendations
- Ip Banning
- Troubleshooting
- Extending
- Contributing
Stream-Control consists of:
- A Flask-based control panel (web dashboard).
- A companion background process (Stream Guard) that:
- Monitors bitrate via a stats endpoint (e.g. SRS / SLS / nginx module JSON)
- Switches scenes automatically (LIVE <-> lowbitrate)
- Listens for Twitch outgoing raids (EventSub WebSocket) and can stop the stream
- Exposes a local health JSON polled by the panel
- An overlay alert channel (WebSocket) for visual/audio notifications (e.g. low bitrate).
No database—simple JSON + environment variables.
- OBS start/stop + scene switching.
- Twitch title & category update with live search.
- Outgoing raid trigger.
- Automatic bitrate-based fallback & recovery scene logic.
- Automatic Twitch user token maintenance (refresh & persistence).
- EventSub (channel.raid) with reconnect + revocation recovery + resubscribe.
- Restream editor (writes JSON, regenerates nginx push config, auto reload).
- Wake-on-LAN / restart / shutdown for remote Mini-PC.
- Optional systemd chatbot control.
- Overlay alert push (low / restored).
- Health/status indicators (OBS, raid WS, subscription, token, etc.).
- Chat commands (!start, !live, !brb, !fix, !stop) via EventSub chat messages (admins only, case sensitive).
Component | Role |
---|---|
app.py |
UI endpoints, token refresh, restream config generation, alerts broadcast |
stream_guard.py |
Bitrate/scene logic, raid EventSub, health server |
static/main.js |
UI interactions, polling, modals, toasts |
templates/ |
HTML + nginx Jinja2 template |
twitch_tokens.json |
Access + refresh token store (rotated automatically) |
Processes are decoupled for resilience.
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env
python app.py
python stream_guard.py
Open http://localhost:5000 (login with LOGIN_PASSWORD).
- Python 3.10+
- OBS with obs-websocket v5
- nginx with RTMP module (if restreaming)
- Stats endpoint (for bitrate switching)
- Twitch API credentials (Client ID + Secret + user tokens)
- Optional: stunnel (RTMPS), systemd
git clone https://github.com/Kimsec/Stream-Control.git
cd Stream-Control
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
Key groups in .env
:
Group | Examples |
---|---|
Flask/Auth | FLASK_SECRET_KEY, LOGIN_PASSWORD |
OBS | OBS_HOST, OBS_PORT, OBS_PASSWORD |
Bitrate | STATS_URL, BITRATE_LOW_KBPS, BITRATE_HIGH_KBPS, POLL_INTERVAL_SEC, LOW_CONSEC_SAMPLES |
Scenes | LIVE_SCENE_NAME, LOW_SCENE_NAME |
Restream | CONFIG_PATH, NGINX_CONF_OUT |
Mini-PC | MINI_PC_USER, MINI_PC_IP, MAC_ADDRESS |
Twitch | TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET, TWITCH_BROADCASTER_ID, TWITCH_OAUTH_TOKEN, TWITCH_REFRESH_TOKEN, TWITCH_TOKENS_PATH |
Raid | RAID_AUTO_STOP_ENABLED, RAID_AUTO_STOP_DELAY |
Chat Commands | TWITCH_ADMINS, STARTING_SCENE_NAME, BRB_SCENE_NAME |
Behavior | WAIT_FOR_STREAM_START, EXIT_WHEN_STREAM_ENDS, IDLE_WHEN_STREAM_ENDS |
Overlay | ALERTS_BASE_URL |
Tokens are auto-refreshed and persisted.
Development:
python app.py
python stream_guard.py
Production:
gunicorn
for app.py- systemd units for both processes
- Auto-restart on failure
Section | Purpose |
---|---|
Status | OBS state, scene, health dots |
Twitch | Title/category edit, raid |
Restream | Manage push endpoints / Restream endpoints |
Stream-PC | Wake / reboot / shutdown |
Bot | Control a systemd service (optional) |
Chat | Embedded Twitch chat |
Alerts | Sounds when visiting Website |
Toasts provide immediate feedback.
If the backend feels stuck (e.g., nginx not serving correctly or StreamGuard appears unresponsive), the Mini-PC tab includes a "Repair Backend" button. This triggers a controlled restart of critical services to recover quickly.
What it does (by default):
- Restarts nginx
- Restarts StreamGuard (the guard process handling bitrate and EventSub)
- Restarts Stunnel (RTMPS)
Notes:
- The operation is idempotent and safe to run when services are already healthy.
- Use this when health indicators show red for nginx/StreamGuard/Stunnel or the UI becomes unresponsive due to those services.
Workflow:
- Open Restream panel.
- Edit/add endpoints (checkbox = enabled).
- Save → JSON updated → nginx config rendered → nginx reloaded automatically.
- Only enabled endpoints produce
push
lines.
Chat commands are processed via the Twitch EventSub channel.chat.message
subscription.
A valid user access token (loaded from twitch_tokens.json
) is required and must include the chat scopes: user:read:chat and user:write:chat
.
Only admins listed in TWITCH_ADMINS
(comma separated, lowercase) are authorized.
Commands are CASE SENSITIVE and must match exactly:
Command | Action |
---|---|
!start |
Start the stream (ignored if already live) then switch to STARTING_SCENE_NAME (if set) or stay on current |
!live |
Switch to LIVE_SCENE_NAME |
!brb |
Switch to BRB_SCENE_NAME |
!fix |
Switch to BRB then back to LIVE after ~1 second |
!stop |
Stop the current stream |
Environment variables affecting commands:
TWITCH_ADMINS=admin1,admin2
STARTING_SCENE_NAME=Starting soon
(optional)BRB_SCENE_NAME=BRB
(optional; defaults handled in code)
If scenes are missing in OBS, commands log errors but do not crash the guard.
Feature | Behavior |
---|---|
Low fallback | Switch after N consecutive low samples |
Recovery | Switch back once high threshold met |
Raid auto-stop | Optional post-raid stream stop |
Idle handling | Idle, continue, or exit when stream ends (configurable) |
Scene transitions also dispatch overlay alerts.
- Automatic refresh when invalid or near expiry.
- Shared file
twitch_tokens.json
used by Stream Guard. - Health shows validity + remaining lifetime.
- Revoked tokens trigger subscription re-attempt after refresh.
Both app.py
and stream_guard.py
use the same token file (twitch_tokens.json
, path set by TWITCH_TOKENS_PATH
).
-
app.py is the ONLY process that refreshes / rotates the access + refresh tokens (writes the file).
-
stream_guard.py is read‑only: it loads the current access token to:
- Subscribe to EventSub topics (raids, chat messages)
- Send chat messages (Helix Chat API) for feedback / raid completion Required scopes for full functionality (recommend granting when generating initial tokens):
-
user:read:chat
-
user:write:chat
-
channel:manage:broadcast (title/category updates)
-
channel:read:subscriptions (optional future use) If a token is revoked or expires, app.py refresh logic updates the file; guard detects validity returning to healthy automatically.
- Alerts when low bitrate / Connection restored (TTS on website)
- Send:
POST /api/alert
{ "type": "low"|"restored", "message": "..." }
- Transport: WebSocket (stateless; waits for next event)
A built-in, mobile-friendly log viewer is available from the Mini-PC tab via the "Logs" button. It helps you inspect systemd service logs without SSH.
Features:
- Service dropdown: switch between multiple services without mixing lines. Current services:
- stream-guard.service (StreamGuard)
- chatbot.service (optional)
- nginx.service
- stunnel-kick.service
- stream-control.service (the web app itself)
- Line count selector: load last 25 (default), 50, or 100 lines.
- Follow toggle: continue streaming new lines in real time via WebSocket.
- Timestamp format: rendered in journalctl short style, e.g. "Sep 08 04:56:38:" for readability.
- Color cues: basic highlighting for ERROR/WARN/INFO/DEBUG.
- Auto-scroll, large buffer trimming, and service-isolated sessions avoid stale entries when switching.
API (optional):
- HTTP: GET
/api/logs?service=<key>&lines=<n>
returns the initial batch of lines. - WS: connect to
/ws/logs?service=<key>
to follow (-n 0
on the backend prevents duplicate backlog). - Accepted service keys match the UI dropdown (e.g.
streamguard
,chatbot
,nginx
,stunnel
,streamcontrol
).
Notes:
- Changing the selected service closes the previous follow stream and ignores stale messages by session.
- The default 25 lines load immediately on open; follow can be toggled on/off without reloading the history.
The dashboard polls a lightweight health endpoint and renders compact status dots (ok/offline/error) with labels.
Data source: GET /api/sg_status
Provided states (UI shows a dot + concise label):
- Chatbot:
chatbot_state
(systemd unit state) - Nginx:
nginx_state
(systemd unit state) - Stunnel:
stunnel_state
(systemd unit state) - StreamGuard:
streamguard_state
(systemd unit state) - ChatGuard: derived from
chat_ws
andchat_subscribed
(ok when both are true; showsws
when WS is up but not yet subscribed) - SLS:
sls_state
(stats endpoint availability) - OBS:
obs_connected
(ok when true) - Twitch Events WS:
raid_ws
(EventSub WebSocket alive) - Raid AutoStop:
raid_subscribed
(EventSubchannel.raid
subscription active) - Twitch Token:
token_valid
plustoken_expires_in
(minutes shown in the label when valid)
Color coding in UI:
- ok: green dot
- offline: gray dot
- error: red dot (e.g., explicit error conditions)
Operational notes:
- StreamGuard’s EventSub client auto-retries subscription with backoff after network/token changes.
- When a token transitions from invalid to valid, a forced re-subscribe attempt is scheduled promptly.
- Reverse proxy + HTTPS
- Limit network exposure (VPN / LAN)
- Least-privilege sudo (only what’s required)
- Strong secrets (FLASK_SECRET_KEY, LOGIN_PASSWORD)
- Restrict token file permissions (600)
- Never commit
.env
or live stream keys
Stream-Control now includes support for IP banning to protect against unwanted connections or abuse. When an IP is banned:
- Connections from the banned IP address are immediately blocked.
- A log entry is created to indicate that a blocked IP attempted to connect.
- Banned IPs can be managed via the
bans.json
file or directly through the admin control panel at/bans
.
- IP banning is enabled by default.
- Ensure the
bans.json
file is protected against unauthorized access. - Use this feature cautiously to avoid accidentally blocking legitimate users.
- Unbanning IPs can be done easily via the admin control panel at
/bans
.
Issue | Hint |
---|---|
OBS “Error” | Check port/password & plugin |
Token stays invalid | Refresh token expired → reissue |
No raid stop | Verify raid_ws & raid_subscribed |
Bitrate static | STATS_URL response format |
nginx reload fails | Endpoint syntax / template values |
Chat missing | Ensure broadcaster_name + correct parent domain |
Check logs for both processes first.
Ideas:
- HTTP Security headers (CSP, HSTS, Referrer-Policy)
- “Grace window” by the start (ignore first X sec because of unstable output).
- UI Timeline for logs (behind a button)
- Watchdog thread: if main loop stalls > timeout → process exit (systemd restarter)
- Async HTTP
- More metrics
- Role-based access
- Fork
- Branch
feat/<name>
- Commit with clear messages
- Open PR (Problem / Solution / Test)
Provided “as is.” Review before exposing publicly.
Happy streaming.