diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index d2e1123..00b4deb 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -111,6 +111,48 @@ func mustLoadTemplates() *template.Template { return t } +type mtxPathGetResp struct { + Item struct { + Name string `json:"name"` + Readers []interface{} `json:"readers"` + } `json:"item"` + // einige Builds liefern die Felder auch „flach“: + Name string `json:"name"` + Readers []interface{} `json:"readers"` +} + +func fetchMTXViewers(ctx context.Context, base, user, pass, name string) (int, error) { + u := strings.TrimRight(base, "/") + "/v3/paths/get/" + url.PathEscape(name) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return 0, err + } + if user != "" || pass != "" { + req.SetBasicAuth(user, pass) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return 0, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return 0, fmt.Errorf("mtx get %s: %s", name, resp.Status) + } + + var out mtxPathGetResp + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + return 0, err + } + + // Priorität: verschachtelt unter item.*, sonst flach + if out.Item.Readers != nil { + return len(out.Item.Readers), nil + } + return len(out.Readers), nil +} + func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) tpls = mustLoadTemplates() @@ -227,7 +269,24 @@ func main() { if len(allowed) > 0 && !allowed[p.Name] { continue } - out.Items = append(out.Items, item{Name: p.Name, Live: p.Live(), Viewers: p.Viewers()}) + viewers := 0 + { + ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second) + v, err := fetchMTXViewers(ctx2, mtxAPI, os.Getenv("MTX_API_USER"), os.Getenv("MTX_API_PASS"), p.Name) + cancel2() + if err == nil { + viewers = v + } else { + // Fallback: falls API kurz zickt, nehme zur Not den alten Wert, + // aber brich das Live-UI nicht: viewers bleibt 0, Live bleibt p.Live() + // log.Printf("warn: mtx viewers %s: %v", p.Name, err) + } + } + out.Items = append(out.Items, item{ + Name: p.Name, + Live: p.Live(), // deine bisherige Live-Logik bleibt erhalten + Viewers: viewers, // echte Leserzahl aus MediaMTX + }) } buf, _ := json.Marshal(out) @@ -337,7 +396,24 @@ func apiStreams(w http.ResponseWriter, r *http.Request) { if len(allowed) > 0 && !allowed[p.Name] { continue } - out.Items = append(out.Items, item{Name: p.Name, Live: p.Live(), Viewers: p.Viewers()}) + viewers := 0 + { + ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second) + v, err := fetchMTXViewers(ctx2, mtxAPI, os.Getenv("MTX_API_USER"), os.Getenv("MTX_API_PASS"), p.Name) + cancel2() + if err == nil { + viewers = v + } else { + // Fallback: falls API kurz zickt, nehme zur Not den alten Wert, + // aber brich das Live-UI nicht: viewers bleibt 0, Live bleibt p.Live() + // log.Printf("warn: mtx viewers %s: %v", p.Name, err) + } + } + out.Items = append(out.Items, item{ + Name: p.Name, + Live: p.Live(), // deine bisherige Live-Logik bleibt erhalten + Viewers: viewers, // echte Leserzahl aus MediaMTX + }) } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(out)