Paginate briefing cards and add video previews

This commit is contained in:
2026-05-25 15:27:34 -04:00
parent e3453de788
commit 3eb74a9083
6 changed files with 277 additions and 41 deletions

View File

@@ -14,7 +14,7 @@ import (
"golang.org/x/net/html"
)
const UserAgent = "box-box/phase-19b-rss-spike"
const UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
// Source describes a feed that can be fetched and normalized.
type Source struct {
@@ -207,6 +207,12 @@ type rssItem struct {
PubDate string `xml:"pubDate"`
Description string `xml:"description"`
Categories []string `xml:"category"`
Thumbnail struct {
URL string `xml:"url,attr"`
} `xml:"http://search.yahoo.com/mrss/ thumbnail"`
Content struct {
URL string `xml:"url,attr"`
} `xml:"http://search.yahoo.com/mrss/ content"`
}
type atomFeed struct {
@@ -225,6 +231,12 @@ type atomEntry struct {
Term string `xml:"term,attr"`
Label string `xml:"label,attr"`
} `xml:"category"`
MediaGroup struct {
Thumbnail struct {
URL string `xml:"url,attr"`
} `xml:"http://search.yahoo.com/mrss/ thumbnail"`
Description string `xml:"http://search.yahoo.com/mrss/ description"`
} `xml:"http://search.yahoo.com/mrss/ group"`
}
type atomLink struct {
@@ -243,6 +255,10 @@ func normalizeRSS(source Source, raw []rssItem, fetchedAt time.Time) []Item {
if !source.SkipSummary {
summary = stripHTML(entry.Description)
}
imgURL := entry.Thumbnail.URL
if imgURL == "" {
imgURL = entry.Content.URL
}
items = append(items, Item{
Source: source.ID,
Title: cleanText(entry.Title),
@@ -251,6 +267,7 @@ func normalizeRSS(source Source, raw []rssItem, fetchedAt time.Time) []Item {
Summary: summary,
Category: firstNonEmpty(entry.Categories, source.Category),
FetchedAt: fetchedAt,
OGImageURL: imgURL,
})
}
return DeduplicateByURL(items)
@@ -265,17 +282,19 @@ func normalizeAtom(source Source, raw []atomEntry, fetchedAt time.Time) []Item {
}
summary := ""
if !source.SkipSummary {
raw := firstNonEmpty([]string{entry.Summary, entry.Content}, "")
raw := firstNonEmpty([]string{entry.Summary, entry.Content, entry.MediaGroup.Description}, "")
summary = stripHTML(raw)
}
items = append(items, Item{
Source: source.ID,
Title: cleanText(entry.Title),
URL: atomEntryURL(entry),
PublishedAt: parseFeedTime(firstNonEmpty([]string{entry.Published, entry.Updated}, "")),
Summary: summary,
Category: category,
FetchedAt: fetchedAt,
Source: source.ID,
Title: cleanText(entry.Title),
URL: atomEntryURL(entry),
PublishedAt: parseFeedTime(firstNonEmpty([]string{entry.Published, entry.Updated}, "")),
Summary: summary,
Category: category,
FetchedAt: fetchedAt,
OGImageURL: entry.MediaGroup.Thumbnail.URL,
OGDescription: stripHTML(entry.MediaGroup.Description),
})
}
return DeduplicateByURL(items)

View File

@@ -166,6 +166,9 @@ func enrichOG(ctx context.Context, client *http.Client, items []Item, parallel i
}
for i := range items {
if items[i].OGImageURL != "" {
continue // Already has preview from feed, skip OG head fetch
}
wg.Add(1)
go func(idx int) {
defer wg.Done()

View File

@@ -7,13 +7,13 @@ import (
func TestCoverageCRUD(t *testing.T) {
s := openTestStore(t)
// Verify schema migration version is 4 (since we added 004_coverage.sql)
// Verify schema migration version is 5 (since we added 005_news_enriched.sql)
version, err := s.SchemaVersion()
if err != nil {
t.Fatalf("SchemaVersion() error = %v", err)
}
if version != 4 {
t.Fatalf("SchemaVersion() = %d, want 4", version)
if version != 5 {
t.Fatalf("SchemaVersion() = %d, want 5", version)
}
// Verify session_coverage table exists

View File

@@ -28,8 +28,8 @@ func TestOpenAppliesMigrations(t *testing.T) {
if err != nil {
t.Fatalf("SchemaVersion() error = %v", err)
}
if version != 4 {
t.Fatalf("SchemaVersion() = %d, want 4", version)
if version != 5 {
t.Fatalf("SchemaVersion() = %d, want 5", version)
}
tables := []string{
@@ -99,6 +99,12 @@ func TestMigrationsAreIdempotent(t *testing.T) {
if count != 1 {
t.Fatalf("schema_migrations v4 count = %d, want 1", count)
}
if err := s.db.QueryRow(`SELECT COUNT(*) FROM schema_migrations WHERE version = 5`).Scan(&count); err != nil {
t.Fatalf("count schema_migrations v5: %v", err)
}
if count != 1 {
t.Fatalf("schema_migrations v5 count = %d, want 1", count)
}
}
func TestRawPayloadInsertAndRead(t *testing.T) {