Simulated live TV for Jellyfin. This repository is ChannelFlow-Server — a .NET 10 app with a red Jellyfin-style Web UI, PostgreSQL, local library playback, WeatherStar, and news.
Home: github.com/binarygeek119/ChannelFlow
ChannelFlow talks to media servers itself (Jellyfin now; Emby and Plex connections are placeholders). Add Live TV in Jellyfin with this server's M3U and XMLTV URLs from the Copy M3U and Copy XMLTV buttons at the top of the web UI.
| ChannelFlow-Server | Jellyfin / other players |
|---|---|
| Channels, lineups, playout, FFmpeg MPEG-TS | Add M3U + XMLTV as a Live TV tuner |
| Library connections (Jellyfin, sidecar .nfo, Emby/Plex later) | Same media files ChannelFlow can read |
| Commercials / CommercialBrainz | |
| EBS, logos, AI lineups | |
| WeatherStar 4000/3000 (native compositor, vendored ws4kp/ws3kp) | |
| News RSS + TTS channel | |
| Web UI (username/password) |
Playback reads local files. On Library → Connections, set path remaps per server (media-server prefix → ChannelFlow mount), for example /data/media → /media.
- .NET 10 SDK to build, or a self-contained publish from
scripts/publish-native.sh - PostgreSQL (your own instance)
- FFmpeg on PATH (or set
FFMPEG_PATH). The Docker image is based on ersatztv-ffmpeg (/usr/local/bin/ffmpeg), same stack as ErsatzTV/legacy. - Jellyfin 10+ (or sidecar folders). Emby and Plex connections can be saved now; catalog sync for those comes later
- The same media paths readable by Jellyfin and ChannelFlow-Server
cp .env.example .env
# optional: set JELLYFIN_URL. PostgreSQL can be configured in the web UI on first launch.
dotnet publish src/ChannelFlow.Server/ChannelFlow.Server.csproj -c Release
# or: bash scripts/publish-native.sh linux-x64Load the .env values into the process environment, then run ChannelFlow.Server (from bin/.../publish or artifacts/native/linux-x64). Listen port is PORT (default 8097). Config, logos, weather, and news files live under CHANNELFLOW_CONFIG (default config next to the app). Postgres connection details are stored in database.json in that folder unless POSTGRES_HOST is set (Docker/Unraid). Channel bugs ship in src/ChannelFlow.Server/wwwroot/images/logos (copied into the config logos folder on startup). EBS graphics and Off Air slates are in wwwroot/images/media, alert/news audio in wwwroot/audio, and bundled bumpers in wwwroot/videos.
Local from source (Fedora/podman): bash scripts/dev.sh starts Postgres on 127.0.0.1:5433 and dotnet run on http://127.0.0.1:8097.
Then:
- Open
http://<host>:8097. On first launch, enter PostgreSQL host/port/database/user/password, then create the admin username and password - Open Library → Connections. Add a Jellyfin server (URL + API key) or a sidecar folder of local files with
.nfometadata. Use Test server, refresh libraries, then Sync catalog - Set path remaps on that server card so ChannelFlow can open the same files
- Copy the M3U and XMLTV URLs from the top of the web UI. In Jellyfin Live TV, add those as a tuner and guide
Items removed from a media server, or whose remapped local file is gone, are marked missing, then deleted by Library → Removed items (or Tasks) after the grace period (default 7 days). Scan local files checks each catalog path after remap.
Set FFMPEG_HWACCEL=vaapi or qsv and pass /dev/dri access for Intel VAAPI / Quick Sync. The container ships ersatztv-ffmpeg 8.1.2 (VAAPI, QSV, NVENC, libva 2.23).
In Jellyfin, add ChannelFlow's M3U and XMLTV URLs from the top of the web UI under Live TV (tuner + guide).
ChannelFlow expects to sit behind Nginx Proxy Manager, SWAG, Caddy, or Traefik on a hostname such as https://channelflow.example.duckdns.org. Forward X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-For. Leave live MPEG-TS unbuffered (proxy_buffering off / Caddy flush_interval -1) and raise the read timeout (an hour is enough).
Optional env vars:
CHANNELFLOW_PUBLIC_URL— public origin used in M3U/XMLTV when Jellyfin fetches them from another host (example:https://channelflow.example.duckdns.org)CHANNELFLOW_PATH_BASE— only if the UI is served under a subpath such as/channelflow
Legacy FINTV_* names for those same variables still work.
You can also set Public base URL on the General tab. Login cookies stay valid across restarts (keys live in the config folder under dataprotection).
Nginx:
location / {
proxy_pass http://127.0.0.1:8097;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}Caddy:
channelflow.example.duckdns.org {
reverse_proxy 127.0.0.1:8097 {
flush_interval -1
}
}WeatherStar graphics are vendored from ws4kp and ws3kp (MIT) and rendered by the native compositor, then encoded to MPEG-TS with optional Jellyfin music as a bed.
News is a 24/7 channel: RSS feeds from the News page, optional TTS, FFmpeg overlay, and bed music.
ChannelFlow-Server code follows this repository's license. WeatherStar vendors keep their upstream MIT licenses.
