300 lines
9.9 KiB
Markdown
300 lines
9.9 KiB
Markdown
<div align="center"><a name="readme-top"></a>
|
||
|
||
# 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]
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
- [✨ 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
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 🚀 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: <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**
|
||
|
||
```bash
|
||
docker compose pull && docker compose up -d
|
||
```
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 💻 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.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## ⚙️ 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.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 🐳 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/`.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 🔌 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/<slug>/...`) 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.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 📡 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 |
|
||
|
||
### 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=<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 |
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 💡 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.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 🤝 Contributing
|
||
|
||
Issues and pull requests are welcome. Please open an issue first for major changes so the direction can be discussed.
|
||
|
||
<div align="right">
|
||
|
||
[![][back-to-top]](#readme-top)
|
||
|
||
</div>
|
||
|
||
## 📝 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.
|
||
|
||
---
|
||
|
||
<!-- LINK GROUP -->
|
||
[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/
|