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.
44 lines
1.1 KiB
Go
44 lines
1.1 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
const upstreamDownAfter = 10 * time.Second
|
|
|
|
// HandleStatus returns the current stream status as JSON.
|
|
// GET /api/status
|
|
func (a *App) HandleStatus(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
a.mu.RLock()
|
|
status := a.Status
|
|
a.mu.RUnlock()
|
|
|
|
// Detect upstream health from the hub. Once the hub receives data, the
|
|
// channel is considered live; if no data arrives within the threshold
|
|
// after a switch, flag upstream_down so all watchers see the warning.
|
|
gotData, since := a.Hub.GotData()
|
|
if status.Transitioning && gotData {
|
|
a.mu.Lock()
|
|
a.Status.Transitioning = false
|
|
a.Status.UpstreamDown = false
|
|
a.mu.Unlock()
|
|
status.Transitioning = false
|
|
status.UpstreamDown = false
|
|
} else if status.Transitioning && !gotData && since >= upstreamDownAfter {
|
|
a.mu.Lock()
|
|
a.Status.UpstreamDown = true
|
|
a.mu.Unlock()
|
|
status.UpstreamDown = true
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(status)
|
|
}
|