Add project plan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 09:23:31 -08:00
parent cfd026dd9d
commit 2e66b8c73d

310
plan.md Normal file
View 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