From 1f57c556a0b005f9a14c352455d1f469c870972a Mon Sep 17 00:00:00 2001 From: Salastil <46979341+Salastil@users.noreply.github.com> Date: Sun, 23 Nov 2025 01:06:12 -0500 Subject: [PATCH] Show popular match viewer counts --- internal/app.go | 38 +++++++++++++++++++++++++++++++++----- internal/client.go | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/internal/app.go b/internal/app.go index dfe00b5..684fb08 100644 --- a/internal/app.go +++ b/internal/app.go @@ -201,7 +201,13 @@ func New(debug bool) Model { if mt.Teams != nil && mt.Teams.Home != nil && mt.Teams.Away != nil { title = fmt.Sprintf("%s vs %s", mt.Teams.Home.Name, mt.Teams.Away.Name) } - return fmt.Sprintf("%s %s (%s)", when, title, mt.Category) + + viewers := "" + if mt.Viewers > 0 { + viewers = fmt.Sprintf(" (%s viewers)", formatViewerCount(mt.Viewers)) + } + + return fmt.Sprintf("%s %s%s (%s)", when, title, viewers, mt.Category) }) m.matches.SetSeparator(func(prev, curr Match) (string, bool) { currDay := time.UnixMilli(curr.Date).Local().Format("Jan 2") @@ -513,9 +519,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case sportsLoadedMsg: - m.sports.SetItems(msg) + sports := prependPopularSport(msg) + m.sports.SetItems(sports) m.lastError = nil - m.status = fmt.Sprintf("Loaded %d sports – pick one with Enter or stay on Popular Matches", len(msg)) + m.status = fmt.Sprintf("Loaded %d sports – pick one with Enter or stay on Popular Matches", len(sports)) return m, nil case matchesLoadedMsg: @@ -571,14 +578,35 @@ func (m Model) fetchPopularMatches() tea.Cmd { func (m Model) fetchMatchesForSport(s Sport) tea.Cmd { return func() tea.Msg { - matches, err := m.apiClient.GetMatchesBySport(context.Background(), s.ID) + get := func() ([]Match, error) { + if strings.EqualFold(s.ID, "popular") { + return m.apiClient.GetPopularMatches(context.Background()) + } + return m.apiClient.GetMatchesBySport(context.Background(), s.ID) + } + + matches, err := get() if err != nil { return errorMsg(err) } - return matchesLoadedMsg{Matches: matches, Title: fmt.Sprintf("Matches (%s)", s.Name)} + title := fmt.Sprintf("Matches (%s)", s.Name) + if strings.EqualFold(s.ID, "popular") { + title = "Popular Matches" + } + return matchesLoadedMsg{Matches: matches, Title: title} } } +func prependPopularSport(sports []Sport) []Sport { + for _, s := range sports { + if strings.EqualFold(s.ID, "popular") || strings.EqualFold(s.Name, "popular") { + return sports + } + } + popular := Sport{ID: "popular", Name: "Popular"} + return append([]Sport{popular}, sports...) +} + func (m Model) fetchStreamsForMatch(mt Match) tea.Cmd { return func() tea.Msg { streams, err := m.apiClient.GetStreamsForMatch(context.Background(), mt) diff --git a/internal/client.go b/internal/client.go index 5459d47..b618fb2 100644 --- a/internal/client.go +++ b/internal/client.go @@ -62,6 +62,8 @@ type Match struct { Source string `json:"source"` ID string `json:"id"` } `json:"sources"` + + Viewers int `json:"viewers"` } type Stream struct { @@ -89,7 +91,23 @@ func (c *Client) GetSports(ctx context.Context) ([]Sport, error) { func (c *Client) GetPopularMatches(ctx context.Context) ([]Match, error) { url := c.base + "/api/matches/all/popular" - return c.getMatches(ctx, url) + matches, err := c.getMatches(ctx, url) + if err != nil { + return nil, err + } + + viewCounts, err := c.GetPopularViewCounts(ctx) + if err != nil { + return nil, err + } + + for i := range matches { + if viewers, ok := viewCounts[matches[i].ID]; ok { + matches[i].Viewers = viewers + } + } + + return matches, nil } func (c *Client) GetMatchesBySport(ctx context.Context, sportID string) ([]Match, error) { @@ -97,6 +115,26 @@ func (c *Client) GetMatchesBySport(ctx context.Context, sportID string) ([]Match return c.getMatches(ctx, url) } +func (c *Client) GetPopularViewCounts(ctx context.Context) (map[string]int, error) { + url := "https://streami.su/api/matches/live/popular-viewcount" + + var payload []struct { + ID string `json:"id"` + Viewers int `json:"viewers"` + } + + if err := c.get(ctx, url, &payload); err != nil { + return nil, err + } + + out := make(map[string]int, len(payload)) + for _, item := range payload { + out[item.ID] = item.Viewers + } + + return out, nil +} + func (c *Client) GetStreamsForMatch(ctx context.Context, mt Match) ([]Stream, error) { var all []Stream for _, src := range mt.Sources {