Files
StreamHall/README.md
T
Stardream 2b0aaf3a5d
Build and Push Docker Image / build (push) Successful in 12s
fix: security hardening and code review improvements
- hls proxy now signs full URL instead of hostname only (SSRF)
- viewer token required to start session (prevents stats forgery and password bypass)
- weak SECRET_KEY placeholder replaced with REPLACE_ME, startup warning added
- api key auth drops query-string fallback, Bearer header only
- hls variant playlist DRM detection fetches first variant
- dash manifest DRM detection added
- android webview detection restricted to Telegram only
- privacy comment removed from ip hash (ip is stored in plaintext)
- csv export adds range filter (today/7d/30d/all), defaults to 30d
- analytics export button integrated as dropdown with range selection
- docker-compose placeholder defaults updated
- readme and readme.zh-cn updated for v1.2.0 changes
2026-05-24 01:40:03 +10:00

12 KiB

StreamHall

Self-hosted live stream hall - public list, player, admin panel, analytics & push notifications

English · 简体中文


Features

  • Public stream list - Live and archive tabs, password-protected streams, custom site branding, bilingual UI (Chinese / English) with per-language site description
  • Player - HLS, FLV, MPEG-DASH playback via ArtPlayer; AES-128 key override and DASH ClearKey support; Widevine and FairPlay DRM playback via Shaka Player (multi-DRM configs per source, Android Telegram WebView detection)
  • Admin panel - Add, edit, reorder, enable/disable streams; manage sources; drag-and-drop ordering
  • Viewer analytics - Session tracking, unique visitors, peak concurrent viewers, average watch duration, device / browser / OS / geography breakdown, real-time dashboard, CSV export
  • Telegram notifications - Per-stream push messages on stream start and stop
  • Stream push - Local file browser with per-file and per-folder RTMP push management; multi-file folder push with independent stream keys; inline push status and detail modal; remote RTMP push config for external encoders; hidden HLS route proxy (/h/<slug>) so real stream keys are never exposed publicly
  • VOD / file serving - Signed /video/ URLs with HTTP Range support (seek-capable); publish any local video file or folder as an archive stream directly from the file browser
  • HLS proxy - Signed /proxy/hls/ routes for cross-origin HLS playback
  • API key auth - Generate per-key tokens in the admin panel for programmatic access to all admin and analytics endpoints
  • Mobile responsive - Admin panel sidebar, file browser rows, and push directory sidebar all collapse gracefully on narrow screens

🚀 Quick Start

1. Download and configure

curl -LO https://git.stdm.moe/Stardream/StreamHall/raw/branch/main/docker-compose.yml
curl -LO https://git.stdm.moe/Stardream/StreamHall/raw/branch/main/nginx-hls.conf

Important

Open docker-compose.yml and change SECRET_KEY and POSTGRES_PASSWORD to strong random values before starting.

2. Start

docker compose up -d

3. Find the initial admin password

docker logs streamhall

Look for:

StreamHall initial admin password: <random-password>

4. Access

URL Description
http://HOST:8085/ Public stream list
http://HOST:8085/admin Admin panel
http://HOST:18088/ SRS HTTP playback
http://HOST:8889/ Nginx HLS proxy

Tip

After first login, change your password under Site Settings → Security. The initial password is printed once and not stored in plaintext.

Updating to a newer version

docker compose pull && docker compose up -d

Resetting a forgotten admin password

docker exec streamhall-postgres psql -U streamhall -d streamhall \
  -c "DELETE FROM site_settings WHERE key='admin_password_hash';"
docker restart streamhall
docker logs streamhall

Deleting the hash causes StreamHall to generate a new random password on the next startup and print it to the log.

💻 Local Development

Prerequisites: Python 3.12+, PostgreSQL 14+

# 1. Clone the repo
git clone https://git.stdm.moe/Stardream/StreamHall.git
cd StreamHall

# 2. Install the single runtime dependency
pip install -r requirements.txt

# 3. Export required environment variables
export SECRET_KEY=dev-secret
export DATABASE_URL=postgresql://user:pass@localhost:5432/streamhall

# 4. Start the server
python server.py

The app listens on http://localhost:8080 by default. On first startup it creates the database schema and prints a one-time admin password to stdout.

⚙️ Configuration

Set these environment variables in docker-compose.yml:

Variable Default Required Description
SECRET_KEY REPLACE_ME Yes HMAC signing key for sessions and stream routes. Generate with openssl rand -hex 32
DATABASE_URL see compose file Yes PostgreSQL connection string
POSTGRES_PASSWORD see compose file Yes PostgreSQL password
TZ UTC No Container timezone, e.g. Asia/Shanghai
SRS_HTTP_ORIGIN http://srs:8080 No SRS HTTP playback base URL
STREAM_PROBE_TIMEOUT 4 No Seconds before aborting a stream URL probe
STREAM_MONITOR_INTERVAL 10 No Seconds between stream liveness checks
TELEGRAM_TIMEOUT 6 No Seconds before aborting a Telegram API call
RTMP_HOST srs No Hostname of the SRS container used for local push jobs
VIDEOS_DIRS (unset) No Comma-separated list of directories exposed in the file browser. Optionally prefix each path with a label: label:/app/path. Multiple entries: movies:/app/movies,shows:/app/shows

Warning

Always change SECRET_KEY and POSTGRES_PASSWORD before exposing StreamHall to a network. The defaults are intentionally weak placeholders.

Mounting video directories for Local Push

Method 1 — single base directory, multiple sources as subdirectories:

Mount multiple host paths under one container base path. The file browser shows them as subdirectories.

environment:
  VIDEOS_DIRS: "/app/videos"
volumes:
  - ./videos:/app/videos/local
  - /your/media/path:/app/videos/external

Method 2 — multiple labeled top-level directories:

Each path is listed as a separate labeled root entry in the file browser.

environment:
  VIDEOS_DIRS: "/app/videos,external:/app/media/external"
volumes:
  - ./videos:/app/videos
  - /your/media/path:/app/media/external

🐳 Services

The default compose stack starts four containers:

Container Image Port(s) Purpose
streamhall local build 8085→8080 Python app + static frontend
streamhall-postgres postgres:16-alpine - PostgreSQL persistent database
streamhall-srs ossrs/srs:6 1935, 18088→8080 RTMP publishing + HTTP playback
streamhall-nginx-hls nginx:alpine 8889→80 Clean public HLS route proxy

Persistent data is stored in ./postgres-data/.

🔌 Stream Push

SRS handles RTMP publishing on port 1935. Configure your encoder as follows:

RTMP server:  rtmp://HOST:1935/live
Stream key:   your-stream-key

The admin panel's Local Push section provides a file browser for your media directory. Select any video file to push it via RTMP with a custom stream key, or select a folder to push all contained videos simultaneously with independent stream keys. Push status is shown inline per file; a detail modal gives real-time duration, copy addresses, and stop controls.

The hidden public HLS URL (/h/<slug>/...) routes through nginx on port 8889, keeping the real stream key out of the public URL.

Note

The RTMP host field accepts an optional port, e.g. live.example.com:1935. Do not hard-code :1935 if you use a non-standard port.

📡 API

Authentication

  • Browser session - cookie set by POST /api?action=login
  • API key - send Authorization: Bearer <token> header. Keys are managed in the admin panel under Site Settings → API Keys.

Public Endpoints

Method Endpoint Description
GET /api?action=public_list Stream list for the public homepage
GET /api?action=site_settings Site title, description, branding
GET /api?action=get_player_data&id=<public_id> Player sources and metadata
POST /api?action=verify_password Verify a stream password
GET /video/<token>/<payload> Signed VOD endpoint with HTTP Range support

Admin Endpoints

Method Endpoint Description
POST /api?action=login Authenticate and start a session
GET /api?action=logout End the current session
GET /api?action=list_admin Full stream list
POST /api?action=add Add a stream
POST /api?action=update Update a stream
POST /api?action=delete Delete a stream
POST /api?action=set_stream_enabled Toggle stream visibility
POST /api?action=reorder_streams Reorder within a label group
POST /api?action=update_site_settings Save site settings
GET /api?action=telegram_settings Read Telegram bot config
POST /api?action=update_telegram_settings Save Telegram bot config
POST /api?action=update_admin_password Change admin password
GET /api?action=list_api_keys List API keys (tokens not returned)
POST /api?action=create_api_key Create a key - token returned once
POST /api?action=delete_api_key Revoke a key by id
GET /api?action=list_pushes List active push jobs
POST /api?action=start_push Start an RTMP push job for a file
POST /api?action=stop_push Stop a push job by stream key
GET /api?action=list_folder_videos List playable files in a directory (with signed URLs)

Analytics Endpoints

Method Endpoint Description
GET /api?action=stats_overview Aggregated totals
GET /api?action=stats_streams Per-stream stats table
GET /api?action=stats_timeseries Bucketed view counts
GET /api?action=stats_geo Country-level visitor counts
GET /api?action=stats_stream_detail&id=<id> Single-stream detail
GET /api?action=stats_sessions_page&id=<id> Paginated session list
GET /api?action=stats_export_csv&range=<range> Export sessions as CSV (range: today, 7d, 30d (default), all)

💡 Acknowledgements

StreamHall was inspired by AniLive, a live stream listing site that is not open-source. This project is an independent reimplementation built from scratch, sharing no code with the original site.

🤝 Contributing

Issues and pull requests are welcome. Please open an issue first for major changes so the direction can be discussed.

📝 License

Copyright © 2026 Stardream. This project is licensed under the GNU Affero General Public License v3.0.

Permissions

Commercial use
Modification
Distribution
Private use

Conditions

⚠️ Disclose source - modified versions must also be open-source
⚠️ Same license - derivative works must use AGPL-3.0
⚠️ Network use = distribution - if you run a modified version as a network service, you must make the source available to users
⚠️ State changes - modifications must be documented

In short: you are free to use, modify, and self-host StreamHall. If you distribute or offer a modified version as a hosted service, you must publish the full source under AGPL-3.0.