Files
PodTui/src/config/keybinds.jsonc
Michael Freno 0c3506beb5 feat(search): episode search scope with tab toggle
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
2026-08-11 00:50:13 -04:00

86 lines
4.6 KiB
JSON

{
// ── Yazi-style keybinds for PodTui ──────────────────────────────────────
// Notation:
// "j" single lowercase key
// "G" shift + g (uppercase letter = shift)
// "ctrl-d" ctrl modifier
// "shift-j" shift modifier (equivalent to "J")
// "meta-x" alt/meta modifier (macOS users: map Option to Alt)
// ["g","g"] a two-key sequence (matches only when pressed in order)
// "return" special key (also: escape tab space backspace up down left right)
//
// Yazi heritage: j/k move, h/l swipe between panes, Enter open, Space select,
// v visual mode, gg/G top/bottom, [ ] switch tabs, 1-6 goto tab,
// : / q command palette (q + Enter quits there), Q quick quit, ~ help.
// Audio transport kept on shifted keys / ctrl.
// ── Movement (within a pane) ─────────────────────────────────────────────
"move-down": ["j", "down"],
"move-up": ["k", "up"],
"page-down": ["ctrl-d"],
"page-up": ["ctrl-u"],
"full-down": ["ctrl-f"],
"full-up": ["ctrl-b"],
"jump-down": ["J"], // 5 lines down (shift+j)
"jump-up": ["K"], // 5 lines up (shift+k)
"goto-top": [["g", "g"]],
"goto-bottom": ["G"],
// ── Pane focus / swipe (yazi h/l) ────────────────────────────────────────
"swipe-prev": ["h", "left"], // focus left pane (parent)
"swipe-next": ["l", "right"], // focus right pane (preview)
// ── Open / activate ──────────────────────────────────────────────────────
"open": ["return", "enter"],
"open-interactive": ["shift-return"],
// ── Selection & visual mode ──────────────────────────────────────────────
"toggle-select": ["space"],
"visual-mode": ["v"],
"toggle-all": ["ctrl-a"],
"invert-all": ["ctrl-r"],
"escape": ["escape", "ctrl-["],
// ── Tabs ──────────────────────────────────────────────────────────────────
"tab-prev": ["["],
"tab-next": ["]"],
"tab-goto-1": ["1"],
"tab-goto-2": ["2"],
"tab-goto-3": ["3"],
"tab-goto-4": ["4"],
"tab-goto-5": ["5"],
"tab-goto-6": ["6"],
// ── Command palette & help & quit ────────────────────────────────────────
// q opens the command palette (neovim-style: type q + Enter to quit there).
// Q (shift+q) is the instant quick quit. ctrl-c also quits.
"command": [":", "q"],
"quit": ["Q", "ctrl-c"],
"help": ["~", "f1"],
// ── List operations (yazi: s search, f filter, , sort, . hidden, r refresh)
"search": ["s"],
// tab toggles the Search page between show and episode scope (re-runs the
// current query when viewing results)
"search-scope-toggle": ["tab"],
"filter": ["f"],
"sort": [","],
"toggle-hidden": ["."],
"refresh": ["r"],
"unsubscribe": ["x"], // unsubscribe focused show in My Shows
// ── Downloads & auto-download whitelist ───────────────────────────────────
"download": ["d"], // download the focused episode (detail pane)
"delete-download": ["D"], // delete the focused episode's download (if any)
"whitelist-toggle": ["w"], // add/remove the focused show from the auto-download whitelist (My Shows)
// ── Audio transport (preserved) ──────────────────────────────────────────
// Kept on shifted single keys so they never collide with the yazi core
// (space=select, s=search, f=filter, etc.). Edit freely in this file.
"audio-toggle": ["P"], // play / pause (shift+p)
"audio-next": ["N"], // next episode (shift+n)
"audio-prev": ["B"], // prev episode (shift+b)
"audio-seek-forward": ["shift-."], // seek forward (> = shift+.)
"audio-seek-backward": ["shift-,"] // seek backward (< = shift+,)
}