package notifier import ( "fmt" "sort" "strings" "naviwatcher/internal/scanner" ) // FormatDigest renders newly-found missing releases into a human-readable // Telegram message grouped by artist, with per-artist counts and a link to // the Web UI dashboard. It is deterministic: artists are sorted by name and // releases within an artist are sorted by title. func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string) string { if len(missing) == 0 { return "NaviWatcher: no new missing releases found." } type entry struct { title string } byArtist := make(map[string][]entry) order := make([]string, 0) for _, r := range missing { if _, ok := byArtist[r.ArtistID]; !ok { order = append(order, r.ArtistID) } byArtist[r.ArtistID] = append(byArtist[r.ArtistID], entry{title: r.Title}) } // Stable ordering by ArtistID. sort.Strings(order) var b strings.Builder fmt.Fprintf(&b, "NaviWatcher: %d new missing release(s) found:\n\n", len(missing)) for _, artistID := range order { entries := byArtist[artistID] titles := make([]string, 0, len(entries)) for _, e := range entries { titles = append(titles, e.title) } sort.Strings(titles) fmt.Fprintf(&b, "%s (%d):\n", artistID, len(titles)) for _, t := range titles { fmt.Fprintf(&b, " - %s\n", t) } b.WriteString("\n") } if uiBaseURL != "" { fmt.Fprintf(&b, "View details: %s\n", strings.TrimRight(uiBaseURL, "/")) } return strings.TrimRight(b.String(), "\n") }