Files
StreamHall/README.md
T
Stardream dc949bdeab
Build and Push Docker Image / build (push) Failing after 1m5s
feat: local push file browser, VOD serving, and admin UX overhaul
Local push & file browser
- File browser with breadcrumb nav, search, directory memory, .. row,
  and hidden/system folder filtering (./@/#)
- Color-coded file extension tags; file sizes shown inline
- Per-file push modal with random stream key generator and responsive width
- Folder multi-file push modal: independent stream keys per file,
  batch start/stop, inline live-dot status with real-time duration
- Push status inline in file rows replacing top push-jobs area;
  job detail modal with copy/stop/add-stream actions
- /h/<slug> HLS proxy route registered automatically on push start
- Folder push and publish-archive recurse subfolders via os.walk
- "Add to existing stream" dropdown at file, folder, and job modal entries
- Stream editor supports prefilling multiple source links via links array
- list_folder_videos API returns playable files with signed URLs

VOD / video serving
- /video/<token>/<payload> endpoint with HMAC-signed URLs and
  HTTP Range support (206 Partial Content, seek-capable)
- Publish-archive button on file rows and folder rows

Admin UX
- Replace all 18 native alert() with themed Toast notifications
  (success/error/info/warn, 3.5s auto-dismiss, dark mode aware)
- Replace all 3 native confirm() with custom modal (showConfirm)
- Custom overlay scrollbar for admin.html and index.html: no layout
  shift, theme-colored, auto-hides after 1.5s, drag-supported
- background-attachment: fixed on admin and index body backgrounds
- Drag handle for viewport config rows in stream editor
- Pagination and real-time search for hidden push address mapping table
- Pagination for stream analytics detail table with SSE-safe page state
- Stream picker search placeholder i18n
- Lang toggle button title/aria-label i18n
- View URL hash renamed: push -> local, obs -> remote

Index (public) page
- Load more: viewport-aware initial batch calculated from .stream-switch
  bottom position; ghost-style button; card entrance animation with
  50ms per-card stagger on load-more click only

Infrastructure
- Dockerfile: install ffmpeg; separate requirements COPY for layer cache
- docker-compose.yml: add RTMP_HOST, VIDEOS_DIRS env vars, videos volume
- README: document VIDEOS_DIRS mount methods, password reset procedure

Fixes
- action=add 500 error: psycopg3 dict_row does not support int subscript
- Lang toggle button title/aria-label missing i18n keys
- API Keys list not re-rendering on language switch
- Admin stream count per tab showing combined LIVE+ARCHIVE total
- Em dash in api.new_token_hint replaced with hyphen
2026-05-22 21:10:33 +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
  • 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

🚀 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 change-this-secret Yes HMAC signing key for sessions and stream routes
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, or append ?api_key=<token> to any admin endpoint. 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 Export sessions as CSV

💡 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.