Add project plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
310
plan.md
Normal file
310
plan.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# Restreamer — Project Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Restreamer is a self-hosted, single-container streaming relay that presents a unified web video player to viewers. It supports two ingest sources:
|
||||
|
||||
1. **OBS/RTMP ingest** — streamers push RTMP directly to the server (like Twitch/Owncast)
|
||||
2. **IPTV relay** — an admin selects a channel from an M3U playlist, and the server fetches the upstream HLS stream and rebroadcasts it to all viewers through a single connection to the provider
|
||||
|
||||
All viewers connect to the same output stream regardless of the source. The admin panel controls which source is active and, for IPTV mode, which channel is playing.
|
||||
|
||||
**Deployment target:** VM or LXC container on Proxmox, on rented bare-metal in a datacenter.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Docker Container (entrypoint: Go backend) │
|
||||
│ │
|
||||
│ ┌──────────┐ RTMP ┌───────────┐ │
|
||||
│ │ OBS/RTMP │────────────▶│ MediaMTX │──── HLS/WebRTC ──┐ │
|
||||
│ │ Streamer │ │ (video │ │ │
|
||||
│ └──────────┘ │ engine) │ │ │
|
||||
│ └─────▲─────┘ │ │
|
||||
│ │ RTMP push │ │
|
||||
│ ┌──────────┐ pulls HLS ┌─────┴─────┐ │ │
|
||||
│ │ Upstream │◀────────────│ FFmpeg │ │ │
|
||||
│ │ IPTV │ │ (remux │ │ │
|
||||
│ │ Provider │ │ relay) │ │ │
|
||||
│ └──────────┘ └───────────┘ │ │
|
||||
│ ▲ ▲ │ │
|
||||
│ spawn/kill │ │ spawn/restart │ │
|
||||
│ FFmpeg │ │ MediaMTX │ │
|
||||
│ ┌─┴───────┴──┐ │ │
|
||||
│ │ Go Backend │ │ │
|
||||
│ │ (API + │ │ │
|
||||
│ │ control) │ │ │
|
||||
│ └─────┬──────┘ │ │
|
||||
│ │ serves │ │
|
||||
│ ┌─────▼──────┐ │ │
|
||||
│ │ React/Vite │ │ │
|
||||
│ │ Frontend │◀─────────────────┘ │
|
||||
│ │ (viewer + │ (player fetches │
|
||||
│ │ admin) │ HLS stream) │
|
||||
│ └────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
| Component | Role | Technology |
|
||||
|-----------|------|------------|
|
||||
| **MediaMTX** | Video engine — RTMP ingest, HLS/LL-HLS/WebRTC output | [mediamtx](https://github.com/bluenviron/mediamtx) binary |
|
||||
| **FFmpeg** | Pulls upstream IPTV HLS, remuxes and pushes RTMP into MediaMTX | FFmpeg (no transcoding, copy codecs) |
|
||||
| **Go Backend** | REST API, M3U parsing, process management (MediaMTX + FFmpeg), admin logic, serves frontend | Go (net/http, stdlib) |
|
||||
| **React Frontend** | Video player (hls.js), admin panel, source/channel selector | React + Vite, hls.js |
|
||||
| **Process Manager** | Go backend manages MediaMTX and FFmpeg as child processes | Built into Go backend (os/exec) |
|
||||
|
||||
---
|
||||
|
||||
## Ingest Paths
|
||||
|
||||
### Path 1: OBS / RTMP Direct
|
||||
|
||||
```
|
||||
OBS ──RTMP──▶ MediaMTX (rtmp://server:1935/live/stream)
|
||||
│
|
||||
▼
|
||||
Viewers (HLS/WebRTC via MediaMTX)
|
||||
```
|
||||
|
||||
- OBS pushes to `rtmp://<host>:1935/live/stream`
|
||||
- MediaMTX receives and makes it available as HLS at `http://<host>:8888/live/stream`
|
||||
- The Go backend detects the stream is active (via MediaMTX API or webhook)
|
||||
- Frontend player connects to the HLS/WebRTC endpoint
|
||||
|
||||
### Path 2: IPTV Relay
|
||||
|
||||
```
|
||||
Admin selects channel ──▶ Go Backend parses M3U ──▶ spawns FFmpeg
|
||||
│
|
||||
IPTV Provider ◀──HLS pull──── FFmpeg ──RTMP push──▶ MediaMTX
|
||||
│
|
||||
Viewers (HLS/WebRTC)
|
||||
```
|
||||
|
||||
- Admin uploads or the container mounts an M3U playlist
|
||||
- Admin picks a channel from the parsed playlist in the web UI
|
||||
- Go backend spawns FFmpeg:
|
||||
```
|
||||
ffmpeg -i <upstream_hls_url> -c copy -f flv rtmp://localhost:1935/live/stream
|
||||
```
|
||||
- MediaMTX receives the RTMP push and serves it to all viewers
|
||||
- Only one upstream connection to the IPTV provider regardless of viewer count
|
||||
- When admin switches channels, Go backend kills the FFmpeg process and spawns a new one
|
||||
|
||||
---
|
||||
|
||||
## Feature Scope
|
||||
|
||||
### MVP (Phase 1)
|
||||
|
||||
- [ ] **Docker container** with MediaMTX, FFmpeg, Go backend, React frontend
|
||||
- [ ] **Go backend**
|
||||
- REST API for admin operations
|
||||
- M3U playlist parser (EXTINF, group-title, tvg-logo, etc.)
|
||||
- Process manager for MediaMTX and FFmpeg (spawn, kill, monitor, restart)
|
||||
- Source switcher (OBS vs IPTV, and which IPTV channel)
|
||||
- Serves the built React frontend as static files
|
||||
- Basic health/status endpoint
|
||||
- [ ] **React frontend**
|
||||
- Video player page using hls.js
|
||||
- Admin panel (toggle source, browse/search IPTV channels, select channel)
|
||||
- Stream status indicator (live/offline, current source, viewer count if available)
|
||||
- [ ] **MediaMTX configuration**
|
||||
- RTMP ingest on port 1935
|
||||
- HLS output on port 8888
|
||||
- Preconfigured paths for the `live/stream` path
|
||||
- [ ] **M3U playlist support**
|
||||
- Parse standard M3U/M3U8 IPTV playlists
|
||||
- Extract channel name, group, logo URL, stream URL
|
||||
- Search/filter channels in admin UI
|
||||
- Playlist loaded via bind mount at `/data/playlist.m3u`
|
||||
|
||||
### Phase 2 (Future)
|
||||
|
||||
- [ ] Admin authentication (env var password, then optional user accounts)
|
||||
- [ ] Viewer authentication (optional shared password)
|
||||
- [ ] LL-HLS support via MediaMTX configuration
|
||||
- [ ] WebRTC playback option (MediaMTX supports this natively)
|
||||
- [ ] Playlist upload via admin UI (vs bind mount only)
|
||||
- [ ] Multiple concurrent IPTV channels (viewers choose which to watch)
|
||||
- [ ] EPG/guide data support (XMLTV)
|
||||
- [ ] Stream recording/DVR
|
||||
- [ ] Viewer count tracking
|
||||
- [ ] HTTPS/TLS termination (or document reverse proxy setup)
|
||||
- [ ] OBS stream key authentication
|
||||
|
||||
---
|
||||
|
||||
## API Design (Go Backend)
|
||||
|
||||
### Public Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/` | Serves the React frontend |
|
||||
| `GET` | `/api/status` | Current stream status (source, channel name, live/offline) |
|
||||
|
||||
### Admin Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/api/admin/channels` | List all channels from the M3U playlist |
|
||||
| `GET` | `/api/admin/channels?search=<q>&group=<g>` | Search/filter channels |
|
||||
| `GET` | `/api/admin/groups` | List all channel groups from the playlist |
|
||||
| `POST` | `/api/admin/source` | Set active source `{ "source": "iptv" \| "obs" }` |
|
||||
| `POST` | `/api/admin/channel` | Select IPTV channel `{ "channel_id": "..." }` |
|
||||
| `POST` | `/api/admin/playlist/reload` | Re-parse the M3U playlist from disk |
|
||||
| `GET` | `/api/admin/process/status` | Process status for MediaMTX and FFmpeg (running, pid, uptime, errors) |
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
restreamer/
|
||||
├── plan.md # This file
|
||||
├── Dockerfile # Single all-in-one container
|
||||
├── mediamtx.yml # MediaMTX configuration
|
||||
│
|
||||
├── backend/ # Go backend
|
||||
│ ├── go.mod
|
||||
│ ├── go.sum
|
||||
│ ├── main.go # Entry point, HTTP server
|
||||
│ ├── api/ # HTTP handlers
|
||||
│ │ ├── admin.go # Admin endpoints
|
||||
│ │ ├── status.go # Public status endpoint
|
||||
│ │ └── middleware.go # CORS, logging, (future: auth)
|
||||
│ ├── m3u/ # M3U playlist parser
|
||||
│ │ └── parser.go
|
||||
│ ├── process/ # Child process management (FFmpeg + MediaMTX)
|
||||
│ │ ├── ffmpeg.go # FFmpeg spawn/kill/monitor
|
||||
│ │ └── mediamtx.go # MediaMTX spawn/monitor/restart
|
||||
│ └── models/ # Shared types
|
||||
│ └── types.go
|
||||
│
|
||||
├── frontend/ # React + Vite frontend
|
||||
│ ├── package.json
|
||||
│ ├── vite.config.ts
|
||||
│ ├── index.html
|
||||
│ ├── src/
|
||||
│ │ ├── main.tsx
|
||||
│ │ ├── App.tsx
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── Player.tsx # hls.js video player
|
||||
│ │ │ ├── AdminPanel.tsx # Admin controls
|
||||
│ │ │ ├── ChannelList.tsx # IPTV channel browser
|
||||
│ │ │ └── StatusBar.tsx # Stream status display
|
||||
│ │ ├── api/
|
||||
│ │ │ └── client.ts # API client for Go backend
|
||||
│ │ └── types/
|
||||
│ │ └── index.ts
|
||||
│ └── public/
|
||||
│
|
||||
└── data/ # Runtime data (bind mount target)
|
||||
└── playlist.m3u # IPTV playlist (mounted in)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Setup
|
||||
|
||||
### Single Container Strategy
|
||||
|
||||
- **Base image:** `ubuntu:24.04` or `alpine:3.19`
|
||||
- **Installed:** MediaMTX binary, FFmpeg, Go backend binary, built React static files
|
||||
- **Entrypoint:** The Go backend binary — it spawns MediaMTX as a child process and manages its lifecycle
|
||||
- **The Go backend** serves the React build output as static files (no separate web server needed)
|
||||
|
||||
### Ports
|
||||
|
||||
| Port | Service | Protocol |
|
||||
|------|---------|----------|
|
||||
| `1935` | MediaMTX RTMP ingest | RTMP (TCP) |
|
||||
| `8080` | Go backend (web UI + API) | HTTP |
|
||||
| `8888` | MediaMTX HLS output | HTTP |
|
||||
| `8889` | MediaMTX WebRTC (future) | HTTP |
|
||||
|
||||
> Note: In production, ports 8080 and 8888 could be unified behind a reverse proxy. For MVP, they stay separate.
|
||||
|
||||
### Volumes / Bind Mounts
|
||||
|
||||
| Container Path | Purpose |
|
||||
|----------------|---------|
|
||||
| `/data/playlist.m3u` | IPTV M3U playlist file |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `RESTREAMER_PORT` | `8080` | Go backend listen port |
|
||||
| `MEDIAMTX_RTMP_PORT` | `1935` | RTMP ingest port |
|
||||
| `MEDIAMTX_HLS_PORT` | `8888` | HLS output port |
|
||||
| `PLAYLIST_PATH` | `/data/playlist.m3u` | Path to M3U playlist |
|
||||
|
||||
---
|
||||
|
||||
## Build & Run
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd backend && go run .
|
||||
|
||||
# Frontend
|
||||
cd frontend && npm install && npm run dev
|
||||
|
||||
# MediaMTX (download binary and run locally)
|
||||
./mediamtx mediamtx.yml
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
# Build
|
||||
docker build -t restreamer .
|
||||
|
||||
# Run
|
||||
docker run -d \
|
||||
--name restreamer \
|
||||
-p 1935:1935 \
|
||||
-p 8080:8080 \
|
||||
-p 8888:8888 \
|
||||
-v /path/to/playlist.m3u:/data/playlist.m3u:ro \
|
||||
restreamer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
1. **MediaMTX as the video engine** — supports RTMP, HLS, LL-HLS, WebRTC, and RTSP. Modular enough to experiment with different delivery methods later without changing the rest of the stack.
|
||||
|
||||
2. **FFmpeg for IPTV relay (passthrough)** — `ffmpeg -c copy` remuxes without transcoding. Minimal CPU usage. The Go backend manages the FFmpeg lifecycle.
|
||||
|
||||
3. **Single stream path** — both OBS and IPTV push to the same MediaMTX path (`live/stream`). Viewers always connect to one URL. Switching sources is seamless from the viewer's perspective.
|
||||
|
||||
4. **Go backend as the orchestrator and entrypoint** — lightweight, single binary, manages both MediaMTX and FFmpeg as child processes, parses M3U, serves the API and static frontend. No external database needed (state is in-memory for MVP). No supervisord — the Go binary is the container entrypoint and owns the full process tree.
|
||||
|
||||
5. **React/Vite frontend embedded in Go binary** — built at Docker build time, served as static files by the Go backend. Single port for the entire web experience.
|
||||
|
||||
6. **No transcoding** — passthrough only. Keeps CPU usage low and simplifies the pipeline. Can be revisited in Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. **Project scaffolding** — Go module, React/Vite app, directory structure
|
||||
2. **M3U parser** — parse playlists, extract channels
|
||||
3. **Process manager** — spawn/kill/monitor child processes (MediaMTX + FFmpeg)
|
||||
4. **Go API server** — REST endpoints, serve static files
|
||||
5. **MediaMTX config** — configure for RTMP ingest + HLS output
|
||||
6. **React frontend** — player (hls.js), admin panel, channel list
|
||||
7. **Dockerfile** — multi-stage build, all-in-one container
|
||||
8. **Integration testing** — end-to-end with a test stream
|
||||
Reference in New Issue
Block a user