A feed's own artwork has to be there before it is used (#89)

A feed's itunes:image or <image><url> was stored without being asked
for, so a dead one stood in the way of the site's icon. Ken and Robin
Talk About Stuff names http://kenandrobin.wpengine.com/.../kartas_podcast.png,
a 404, while its site's apple-touch-icon works. The feed's artwork now has
to answer as an image, as the site icon already did, when the feed is
read in full; otherwise the site's icon is looked for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 14:11:16 +00:00
parent 66e40e3c71
commit d4e00be085
3 changed files with 13 additions and 4 deletions

View File

@@ -385,19 +385,19 @@ pub async fn site_icon(client: &reqwest::Client, site: &str) -> Option<String> {
&& let Ok(page) = resp.bytes().await
&& let Some(href) = page_icon(&page)
&& let Ok(url) = base.join(&href)
&& is_image(client, &url).await
&& is_image(client, url.as_str()).await
{
return Some(url.into());
}
let ico = base.join("/favicon.ico").ok()?;
is_image(client, &ico).await.then(|| ico.into())
is_image(client, ico.as_str()).await.then(|| ico.into())
}
/// Whether `url` answers with an image. A site with no favicon often answers 200 with its home
/// page, which is not an icon.
async fn is_image(client: &reqwest::Client, url: &reqwest::Url) -> bool {
pub async fn is_image(client: &reqwest::Client, url: &str) -> bool {
let timeout = std::time::Duration::from_secs(20);
let Ok(resp) = client.get(url.clone()).timeout(timeout).send().await else { return false };
let Ok(resp) = client.get(url).timeout(timeout).send().await else { return false };
resp.status().is_success()
&& resp
.headers()

View File

@@ -1258,6 +1258,14 @@ async fn scan_one(
// is stored as "", which the page draws as no art, and which stops the refetch above.
// ponytail: a feed without validators is read in full every scan and asks its site each
// time too; keep a checked-at time per feed if that shows up in anyone's logs.
// A feed's own artwork has to be there too: Ken and Robin's names a 404, and stored unasked
// it stood in the way of the site's icon, which works (#89).
if let Some(art) = &parsed.image
&& !feed::is_image(&ctx.client, art).await
{
tracing::info!(feed = id, art = %art, "the feed's artwork is not an image; trying its site's icon");
parsed.image = None;
}
if parsed.image.is_none() {
parsed.image = Some(match &parsed.site {
Some(site) => feed::site_icon(&ctx.client, site).await.unwrap_or_default(),