fix(search): surface iTunes stubs and resolve feeds for delisted shows
Shows that left Apple Podcasts (e.g. Daily Wire's in 2021) come back from the iTunes Search API as metadata-only stub records with feedUrl null. mapItunesResult dropped them, so The Ben Shapiro Show — the #1 hit for 'ben shapiro' — never appeared in search while sibling shows did. - Keep feedUrl-less results (feedUrl "" + directoryUrl pointing at the Apple page) so delisted shows stay findable. - Resolve the real feed from the Apple page at subscribe time (itunes-feed-resolver: anchor on the collection's adamId, forward-scan for the embedded feedUrl; Apple serves page variants where the showOffer block sits thousands of chars after the adamId). - addFeed refuses feedless stubs whose feed can't be resolved instead of adding a broken feed; SearchPage surfaces the failure via toast. - Tests: stub mapping, extractor variants, and an end-to-end subscribe over a local HTTP server.
This commit is contained in:
@@ -11,6 +11,7 @@ import type { Episode } from "../types/episode";
|
||||
import type { PodcastSource } from "../types/source";
|
||||
import { DEFAULT_SOURCES } from "../types/source";
|
||||
import { parseRSSFeed } from "../api/rss-parser";
|
||||
import { resolveItunesFeedUrl } from "../utils/itunes-feed-resolver";
|
||||
import {
|
||||
loadFeedsFromFile,
|
||||
saveFeedsToFile,
|
||||
@@ -196,6 +197,17 @@ function createFeedStore() {
|
||||
sourceId: string,
|
||||
visibility: FeedVisibility = FeedVisibility.PUBLIC,
|
||||
): Promise<Feed | null> => {
|
||||
// A directory stub (e.g. a show delisted from Apple Podcasts) has no
|
||||
// feed URL; resolve the real feed from its directory page before
|
||||
// subscribing. Refuse when it can't be resolved rather than adding a
|
||||
// broken feed.
|
||||
if (!podcast.feedUrl) {
|
||||
if (!podcast.directoryUrl) return null;
|
||||
const resolved = await resolveItunesFeedUrl(podcast.directoryUrl);
|
||||
if (!resolved) return null;
|
||||
podcast = { ...podcast, feedUrl: resolved, directoryUrl: undefined };
|
||||
}
|
||||
|
||||
// Guard: don't add a feed we already have (matched by feedUrl)
|
||||
if (hasFeedByUrl(podcast.feedUrl)) {
|
||||
return feeds().find((f) => f.podcast.feedUrl === podcast.feedUrl) ?? null;
|
||||
|
||||
Reference in New Issue
Block a user