diff --git a/plugins/feed-discovery/src/feed-discovery.test.ts b/plugins/feed-discovery/src/feed-discovery.test.ts
index f2c4383..1f2fb58 100644
--- a/plugins/feed-discovery/src/feed-discovery.test.ts
+++ b/plugins/feed-discovery/src/feed-discovery.test.ts
@@ -36,6 +36,26 @@ describe("feed parsing", () => {
expect(atom.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",
+ `
+
+
+ Example Podcast
+ Example Host
+ -
+ Episode 1
+
+
+
+ `
+ );
+
+ expect(result.ok).toBe(true);
+ expect(result.kind).toBe("podcast");
+ });
});
describe("site probing helpers", () => {
diff --git a/plugins/feed-discovery/src/feed-parsing.ts b/plugins/feed-discovery/src/feed-parsing.ts
index 92fd4d7..627b382 100644
--- a/plugins/feed-discovery/src/feed-parsing.ts
+++ b/plugins/feed-discovery/src/feed-parsing.ts
@@ -96,7 +96,7 @@ function parseRss(feedUrl: string, rss: Record): ValidationResu
title: title || "Untitled RSS Feed",
description: stringValue(channel.description),
homepageUrl: linkValue(channel.link),
- kind: detectRssKind(channel),
+ kind: detectRssKind(channel, items),
language: stringValue(channel.language),
imageUrl: imageValue(channel.image),
lastPublishedAt: newestDate([stringValue(channel.lastBuildDate), stringValue(channel.pubDate), ...sampleItems.map((item) => item.publishedAt)]),
@@ -132,10 +132,21 @@ function parseAtom(feedUrl: string, feed: Record): ValidationRe
};
}
-function detectRssKind(channel: Record): FeedKind {
+function detectRssKind(channel: Record, items: Record[]): FeedKind {
if (channel.itunes || channel["itunes:author"] || channel.enclosure) {
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";
}