Search now covers individual episodes, not just shows: the iTunes
Search API (entity=podcastEpisode) matches episode titles and show
notes, so a guest or topic finds the episodes they appear in across
shows. Enter on an episode result subscribes to the parent show.
- types: SearchResult becomes a kind-discriminated union
(podcast | episode); EpisodeSearchResult carries the parent show so
existing consumers compile unchanged
- source-searcher: searchEpisodesByType (RSS/CUSTOM return []),
buildItunesEpisodeUrl, cleanDescription (HTML -> text),
mapItunesEpisodeResult (episode id/duration ms->s/audioUrl, reuses
mapItunesResult so delisted shows keep a directoryUrl)
- search: searchEpisodes with an 'episode' cache/dedupe namespace so
shows and episodes for the same query never mix
- stores/search: scope signal (podcast | episode) persisted to
podtui_search_scope; search() branches on scope
- SearchPage: Shows/Episodes pills row with 'tab to toggle', scope-
aware placeholder/empty state/result rows (episode row = title +
Show · date) and preview; toggling re-runs the current query
- keybinds: search-scope-toggle bound to tab (keybinds.jsonc AND the
runtime DEFAULT_KEYBINDS merge so the binding exists for users with
a pre-existing config file); while the input is focused the Shell
router never sees Tab, so the input handles it via onKeyDown +
preventDefault (no double-toggle: the router path only fires when
the input is defocused)
- Shell help overlay documents [tab] shows/episodes