# StreamHall
**Self-hosted live stream hall - public list, player, admin panel, analytics & push notifications**
**English** · [简体中文](./README.zh-CN.md)
[![][license-shield]][license-link]
[![][python-shield]][python-link]
[![][docker-shield]][docker-link]
[![][postgres-shield]][postgres-link]
---
- [✨ Features](#-features)
- [🚀 Quick Start](#-quick-start)
- [💻 Local Development](#-local-development)
- [⚙️ Configuration](#️-configuration)
- [🐳 Services](#-services)
- [🔌 Stream Push](#-stream-push)
- [📡 API](#-api)
- [🤝 Contributing](#-contributing)
- [📝 License](#-license)
## ✨ 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** - SRS RTMP publishing helpers, hidden HLS route proxy so real stream keys are never exposed publicly
- **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
[![][back-to-top]](#readme-top)
## 🚀 Quick Start
**1. Download and configure**
```bash
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**
```bash
docker compose up -d
```
**3. Find the initial admin password**
```bash
docker logs streamhall
```
Look for:
```
StreamHall initial admin 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**
```bash
docker compose pull && docker compose up -d
```
[![][back-to-top]](#readme-top)
## 💻 Local Development
**Prerequisites:** Python 3.12+, PostgreSQL 14+
```bash
# 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.
[![][back-to-top]](#readme-top)
## ⚙️ 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 |
> [!WARNING]
> Always change `SECRET_KEY` and `POSTGRES_PASSWORD` before exposing StreamHall to a network. The defaults are intentionally weak placeholders.
[![][back-to-top]](#readme-top)
## 🐳 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/`.
[![][back-to-top]](#readme-top)
## 🔌 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 **Stream Setup** section generates a hidden public HLS URL (`/h//...`) that 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.
[![][back-to-top]](#readme-top)
## 📡 API
### Authentication
- **Browser session** - cookie set by `POST /api?action=login`
- **API key** - send `Authorization: Bearer ` header, or append `?api_key=` 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=` | Player sources and metadata |
| `POST` | `/api?action=verify_password` | Verify a stream password |
### 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` |
### 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=` | Single-stream detail |
| `GET` | `/api?action=stats_sessions_page&id=` | Paginated session list |
| `GET` | `/api?action=stats_export_csv` | Export sessions as CSV |
[![][back-to-top]](#readme-top)
## 💡 Acknowledgements
StreamHall was inspired by [AniLive](https://anilive.nekoss.cn/), 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.
[![][back-to-top]](#readme-top)
## 🤝 Contributing
Issues and pull requests are welcome. Please open an issue first for major changes so the direction can be discussed.
[![][back-to-top]](#readme-top)
## 📝 License
Copyright © 2026 [Stardream](https://git.stdm.moe/Stardream). This project is licensed under the [GNU Affero General Public License v3.0](./LICENSE).
**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.
---
[back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-black?style=flat-square
[license-shield]: https://img.shields.io/badge/license-AGPL--3.0-white?labelColor=black&style=flat-square
[license-link]: ./LICENSE
[python-shield]: https://img.shields.io/badge/python-3.12-blue?labelColor=black&logo=python&logoColor=white&style=flat-square
[python-link]: https://www.python.org/
[docker-shield]: https://img.shields.io/badge/docker-compose-2496ED?labelColor=black&logo=docker&logoColor=white&style=flat-square
[docker-link]: https://docs.docker.com/compose/
[postgres-shield]: https://img.shields.io/badge/postgres-16-336791?labelColor=black&logo=postgresql&logoColor=white&style=flat-square
[postgres-link]: https://www.postgresql.org/