Detect RSS podcast media enclosures

This commit is contained in:
lazyGPT07 2026-06-12 20:12:55 -06:00
parent 8f4691584c
commit bad2ed508b
2 changed files with 33 additions and 2 deletions

View file

@ -36,6 +36,26 @@ describe("feed parsing", () => {
expect(atom.ok).toBe(true); expect(atom.ok).toBe(true);
expect(json.ok).toBe(true); expect(json.ok).toBe(true);
}); });
it("classifies RSS feeds with audio enclosures as podcasts", () => {
const result = parseFeedDocument(
"https://example.com/podcast.xml",
`<?xml version="1.0"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
<channel>
<title>Example Podcast</title>
<itunes:author>Example Host</itunes:author>
<item>
<title>Episode 1</title>
<enclosure url="https://example.com/episode-1.mp3" type="audio/mpeg" />
</item>
</channel>
</rss>`
);
expect(result.ok).toBe(true);
expect(result.kind).toBe("podcast");
});
}); });
describe("site probing helpers", () => { describe("site probing helpers", () => {

View file

@ -96,7 +96,7 @@ function parseRss(feedUrl: string, rss: Record<string, unknown>): ValidationResu
title: title || "Untitled RSS Feed", title: title || "Untitled RSS Feed",
description: stringValue(channel.description), description: stringValue(channel.description),
homepageUrl: linkValue(channel.link), homepageUrl: linkValue(channel.link),
kind: detectRssKind(channel), kind: detectRssKind(channel, items),
language: stringValue(channel.language), language: stringValue(channel.language),
imageUrl: imageValue(channel.image), imageUrl: imageValue(channel.image),
lastPublishedAt: newestDate([stringValue(channel.lastBuildDate), stringValue(channel.pubDate), ...sampleItems.map((item) => item.publishedAt)]), lastPublishedAt: newestDate([stringValue(channel.lastBuildDate), stringValue(channel.pubDate), ...sampleItems.map((item) => item.publishedAt)]),
@ -132,10 +132,21 @@ function parseAtom(feedUrl: string, feed: Record<string, unknown>): ValidationRe
}; };
} }
function detectRssKind(channel: Record<string, unknown>): FeedKind { function detectRssKind(channel: Record<string, unknown>, items: Record<string, unknown>[]): FeedKind {
if (channel.itunes || channel["itunes:author"] || channel.enclosure) { if (channel.itunes || channel["itunes:author"] || channel.enclosure) {
return "podcast"; return "podcast";
} }
const hasMediaEnclosure = items.some((item) =>
asArray(item.enclosure)
.filter(isRecord)
.some((enclosure) => {
const type = stringValue(enclosure.type)?.toLowerCase();
return type?.startsWith("audio/") || type?.startsWith("video/");
})
);
if (hasMediaEnclosure) {
return "podcast";
}
return "blog"; return "blog";
} }