clone

a desktop tv and program guide for over-the-air broadcasts: what's on air, what your tuner gets, live tv, recordings

Name a show for its channel when its playlist's title names none, and wait for a video's title

FelineStateMachine committed 189823c
"Every Episode" says what a playlist holds, not which show; a premiere
to come is listed without a title until it airs.
commit
189823c3efa08791159c5061d0c08adf0bb595b2
parent
758b5ecc158d5f4e94988fc02b87933acec2e10e
author
FelineStateMachine <226808055+FelineStateMachine@users.noreply.github.com>
kind
fix risk score 1.9 of 3, Jev's estimate
2 files changed, +39 -2
Minternal/podcast/podcast_test.go15+++++++++++++++
Minternal/podcast/update.go26++++++++++++++++++++++++--
M internal/podcast/podcast_test.go +15 -0
M internal/podcast/update.go +24 -2
@@ -1,13 +1,16 @@
11 package podcast22 33 import (4+ "cmp"45 "context"56 "errors"67 "log"78 "math"89 "net/http"10+ "regexp"911 "slices"1012 "strconv"13+ "strings"1114 "time"1215 1316 "airwaves/internal/web"
@@ -163,8 +166,8 @@ func (l *Library) relist(ctx context.Context, s *show) {
163166 // each, plus older ones part watched. Videos too short to be episodes,164167 // and streams to come or under way, are left out.165168 func (s *show) merge(lst youtube.Listing, sr src, now time.Time) {166- if s.Title == "" || lst.Name != "" {167- s.Title = lst.Name169+ if t := showTitle(lst, sr); t != "" {170+ s.Title = t168171 }169172 if lst.Image != "" {170173 s.Thumbnail = lst.Image
@@ -182,6 +185,11 @@ func (s *show) merge(lst youtube.Listing, sr src, now time.Time) {
182185 var out []*episode183186 seen := map[string]bool{}184187 for _, v := range lst.Entries {188+ // A video without a title yet (a premiere to come, say) is189+ // listed once it has one.190+ if v.Title == "" {191+ continue192+ }185193 if seen[v.ID] || !s.fits(v.Seconds, v.LiveStatus, sr) {186194 if v.Seconds > 0 && float64(v.Seconds) < s.MinMinutes*60 {187195 s.skip(v.ID)
@@ -241,6 +249,20 @@ func (s *show) fits(seconds int, live string, sr src) bool {
241249 return seconds <= 0 || float64(seconds) >= s.MinMinutes*60242250 }243251 252+// showTitle is what a listing calls the show: a playlist's title, unless253+// it names no show ("Every Episode", "Full Episodes", "Podcast"), then its254+// channel's name; a channel's name.255+func showTitle(lst youtube.Listing, sr src) string {256+ if sr.playlist && lst.Owner != "" && strings.TrimSpace(generic.ReplaceAllString(lst.Name, "")) == "" {257+ return lst.Owner258+ }259+ return cmp.Or(lst.Name, lst.Owner)260+}261+262+// generic are the words of a playlist's title that say what it holds, not263+// which show.264+var generic = regexp.MustCompile(`(?i)\b(the|every|all|full|latest|new|episodes?|podcasts?|shows?|uploads?|videos?)\b|[^\pL\pN]+`)265+244266 // skip remembers a video that isn't an episode.245267 func (s *show) skip(id string) {246268 if slices.Contains(s.Skipped, id) {