From f4f80e91ccbf3de2820a1f2839776f01955ecff8 Mon Sep 17 00:00:00 2001 From: primal Date: Wed, 28 Jan 2026 22:36:28 -0500 Subject: [PATCH] Add enclosure support for podcast/media items - Load enclosure fields in GetAllUnpublishedItems query - Only include enclosure URL if it fits within post length limit - Shorter video/audio enclosures will be included when they fit Co-Authored-By: Claude Opus 4.5 --- crawler.go | 19 +++++++++++++++++-- publisher.go | 13 +++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/crawler.go b/crawler.go index 90776f2..a0876f4 100644 --- a/crawler.go +++ b/crawler.go @@ -372,7 +372,8 @@ func (c *Crawler) RefreshAllProfiles(publisher *Publisher, feedPassword string) func (c *Crawler) GetAllUnpublishedItems(limit int) ([]Item, error) { rows, err := c.db.Query(` SELECT i.id, i.feed_url, i.guid, i.title, i.link, i.description, i.content, - i.author, i.pub_date, i.discovered_at, i.image_urls + i.author, i.pub_date, i.discovered_at, i.image_urls, + i.enclosure_url, i.enclosure_type, i.enclosure_length FROM items i JOIN feeds f ON i.feed_url = f.url WHERE f.publish_status = 'pass' @@ -391,9 +392,12 @@ func (c *Crawler) GetAllUnpublishedItems(limit int) ([]Item, error) { var item Item var guid, title, link, description, content, author, imageURLsJSON *string var pubDate, discoveredAt *time.Time + var enclosureURL, enclosureType *string + var enclosureLength *int64 err := rows.Scan(&item.ID, &item.FeedURL, &guid, &title, &link, &description, - &content, &author, &pubDate, &discoveredAt, &imageURLsJSON) + &content, &author, &pubDate, &discoveredAt, &imageURLsJSON, + &enclosureURL, &enclosureType, &enclosureLength) if err != nil { continue } @@ -412,6 +416,17 @@ func (c *Crawler) GetAllUnpublishedItems(limit int) ([]Item, error) { json.Unmarshal([]byte(*imageURLsJSON), &item.ImageURLs) } + // Parse enclosure + if enclosureURL != nil && *enclosureURL != "" { + item.Enclosure = &Enclosure{ + URL: *enclosureURL, + Type: StringValue(enclosureType), + } + if enclosureLength != nil { + item.Enclosure.Length = *enclosureLength + } + } + items = append(items, item) } diff --git a/publisher.go b/publisher.go index 8442318..bb625e1 100644 --- a/publisher.go +++ b/publisher.go @@ -297,12 +297,21 @@ func (p *Publisher) PublishItem(session *PDSSession, item *Item) (string, error) } // Add enclosure URL for podcasts/media (audio/video) if we have room + // Bluesky has 300 char limit, so only add if total URLs + minimal title fits if len(allURLs) < 2 && item.Enclosure != nil && item.Enclosure.URL != "" { encType := strings.ToLower(item.Enclosure.Type) if strings.HasPrefix(encType, "audio/") || strings.HasPrefix(encType, "video/") { if !urlSet[item.Enclosure.URL] { - urlSet[item.Enclosure.URL] = true - allURLs = append(allURLs, item.Enclosure.URL) + // Calculate if enclosure would fit (need ~60 chars for title + separators) + currentURLLen := 0 + for _, u := range allURLs { + currentURLLen += len(u) + 2 // +2 for \n\n + } + enclosureLen := len(item.Enclosure.URL) + 2 + if currentURLLen+enclosureLen < 235 { // Leave 60 chars for title + urlSet[item.Enclosure.URL] = true + allURLs = append(allURLs, item.Enclosure.URL) + } } } }