Replaces the FFmpeg -> MediaMTX -> HLS pipeline with a raw MPEG-TS fan-out architecture: - Go stream.Hub holds ONE upstream connection per active channel and broadcasts the raw TS bytes to all connected browsers via /ts. The IPTV provider only ever sees one IP (the server), no matter how many viewers are watching (shared single-channel model). - Frontend uses mpegts.js to play the raw TS in-browser via MSE, fixing HEVC/H.265 4K streams that HLS could not package. - Dropped FFmpeg, MediaMTX, RTMP/RTSP, HLS proxy, playback/ingest modes, the OBS source toggle, and FFmpeg health stats. - UI look preserved (fullscreen video, collapsible sidebar, status bar, upstream-down banner, hourly playlist auto-refresh). Tradeoff: loses iOS Safari (no MSE/mpegts.js); fixes desktop/Android playback of both H.264 and H.265.
46 lines
989 B
Go
46 lines
989 B
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
)
|
|
|
|
// HandleTS streams the shared channel's raw MPEG-TS bytes to a viewer.
|
|
// Every connected browser subscribes to the same upstream via the hub, so the
|
|
// server holds only one connection to the IPTV source regardless of how many
|
|
// clients are watching.
|
|
// GET /ts
|
|
func (a *App) HandleTS(w http.ResponseWriter, r *http.Request) {
|
|
flusher, ok := w.(http.Flusher)
|
|
if !ok {
|
|
http.Error(w, "streaming unsupported", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "video/mp2t")
|
|
w.Header().Set("Cache-Control", "no-cache, no-store")
|
|
w.Header().Set("Connection", "keep-alive")
|
|
w.WriteHeader(http.StatusOK)
|
|
flusher.Flush()
|
|
|
|
sub, unsub := a.Hub.Subscribe()
|
|
defer unsub()
|
|
|
|
ctx := r.Context()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-sub.Done():
|
|
return
|
|
case chunk, ok := <-sub.Chan():
|
|
if !ok {
|
|
return
|
|
}
|
|
if _, err := w.Write(chunk); err != nil {
|
|
return
|
|
}
|
|
flusher.Flush()
|
|
}
|
|
}
|
|
}
|