Feeds from before site icons get one, without waiting for a post (#73)

The icon lookup ran only when a scan got the feed's body, and most feeds
answer 304 to their stored validators, so anildash.com and 68 others
stayed blank until their next post. A feed whose image was never looked
for is now refetched once without validators, as an empty one already
was. A miss is stored as "" (drawn as no art), so neither the refetch nor
the site lookup repeats on every scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 23:27:00 +00:00
parent c6980c355d
commit 2004da3459

View File

@@ -1178,8 +1178,10 @@ async fn scan_one(
// A 304 while nothing is stored means the validator has outlived the data -- a restore
// from backup, a manual edit, a cleanup that removed entries. Believe the database over
// the validator: drop it and ask again, or the feed stays empty until the publisher
// happens to change something.
if matches!(fetched, feed::Fetched::NotModified) && ctx.db.feed_summary(id).await?.entries == 0 {
// happens to change something. The same for artwork never looked for: a feed from before
// site icons (#73) would otherwise wait for its next post to get one.
let stored = ctx.db.feed_summary(id).await?;
if matches!(fetched, feed::Fetched::NotModified) && (stored.entries == 0 || stored.image.is_none()) {
tracing::info!(feed = id, "not modified, but nothing stored; refetching without the validator");
ctx.db.clear_validators(id).await?;
fetched = feed::fetch(&ctx.client, feed_cfg, None, None).await?;
@@ -1206,13 +1208,13 @@ async fn scan_one(
}
let mut parsed = feed::parse(&bytes)?;
// ponytail: a site with no icon at all is asked again on every scan that finds the feed
// changed; remember the miss in the feeds table if that turns out to cost.
if parsed.image.is_none()
&& let Some(site) = &parsed.site
&& ctx.db.feed_summary(id).await?.image.is_none()
{
parsed.image = feed::site_icon(&ctx.client, site).await;
// Looked for once. A miss is stored as "", which the page draws as no art, so a site with
// no icon is not asked again on every scan, nor the feed refetched in full for it above.
if parsed.image.is_none() && stored.image.is_none() {
parsed.image = Some(match &parsed.site {
Some(site) => feed::site_icon(&ctx.client, site).await.unwrap_or_default(),
None => String::new(),
});
}
ctx.db.record_feed(
id,