fix: address code review findings

- notifier: show artist display names (not internal IDs) in digest; resolve
  names from artist_settings and fall back to ID when unavailable
- notifier: skip sending an empty digest to avoid daily spam
- config: require telegram token/chat_id when enabled
- web: warn loudly when auth is disabled on a non-loopback bind; add HTTP
  server timeouts
- web: treat SetReleaseIgnored "release not found" as benign redirect (0 rows)
- musicbrainz: reject low-score/name-mismatched MBID resolutions instead of
  silently caching the wrong artist
- database: remove dead duplicate err check; harden DSN param appending
- musicbrainz: check rows.Err() after iterating existing releases
This commit is contained in:
2026-07-19 23:46:05 +03:00
parent 389d177d85
commit 7cdb473d9c
12 changed files with 189 additions and 22 deletions

View File

@@ -10,9 +10,13 @@ import (
// 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
// the Web UI dashboard. It is deterministic: artists are sorted by label and
// releases within an artist are sorted by title.
func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string) string {
//
// artistNames maps an ArtistID to its human-readable display name. Names are
// optional: if an ID is absent from the map (or the map itself is nil), the
// raw ArtistID is used as the label so the digest remains informative.
func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string, artistNames map[string]string) string {
if len(missing) == 0 {
return "NaviWatcher: no new missing releases found."
}
@@ -28,8 +32,10 @@ func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string) string {
}
byArtist[r.ArtistID] = append(byArtist[r.ArtistID], entry{title: r.Title})
}
// Stable ordering by ArtistID.
sort.Strings(order)
// Stable ordering by display label (name if known, else ID).
sort.Slice(order, func(i, j int) bool {
return artistLabel(order[i], artistNames) < artistLabel(order[j], artistNames)
})
var b strings.Builder
fmt.Fprintf(&b, "NaviWatcher: %d new missing release(s) found:\n\n", len(missing))
@@ -40,7 +46,7 @@ func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string) string {
titles = append(titles, e.title)
}
sort.Strings(titles)
fmt.Fprintf(&b, "%s (%d):\n", artistID, len(titles))
fmt.Fprintf(&b, "%s (%d):\n", artistLabel(artistID, artistNames), len(titles))
for _, t := range titles {
fmt.Fprintf(&b, " - %s\n", t)
}
@@ -51,3 +57,15 @@ func FormatDigest(missing []scanner.MissingRelease, uiBaseURL string) string {
}
return strings.TrimRight(b.String(), "\n")
}
// artistLabel returns the human-readable display name for an artist ID when
// available, otherwise the raw ID. A non-empty name takes precedence so
// operators see recognizable artist names rather than opaque internal IDs.
func artistLabel(artistID string, names map[string]string) string {
if names != nil {
if name, ok := names[artistID]; ok && name != "" {
return name
}
}
return artistID
}