feat(podcasts): API endpoints — add/list/detail, subscriptions, downloads, sequence, search (task 1.7)
The §8 surface, wired through main.go → router.Config → /api/podcasts (JWT). Scoping is the engine's (D20): lookups outside the caller's scope simply return no rows → 404; the only Go-level checks are explicit-argument authorization (AddFeed's library + allow_member_feeds gate) and the admin role on feed deletion. Endpoints: POST/GET /feeds (add: fetch+parse+upsert+subscribe, optional download_all; list: subscriptions + episode counts + facet values computed in Go — feed counts are tens), GET /feeds/:id (detail with download states + gap count), PUT/DELETE /subscription (the ONLY user-writable podcast state, D9; unsubscribe retains files per D6), POST /refresh, POST /episodes/:eid/download (+ episode_ids[] bulk and eid='all' = Download All, exactly the non-downloaded set), PUT /order (D5 per-user override in the reader_settings KV — podcast_order:<feed_id>; 'native' deletes the row so default and explicit choice are indistinguishable), GET /sequence (effective order — override applied, native fallback — DOWNLOADED-only with the gap list; this payload powers web chain mode and, per §15, the future media3 queue), GET /search (subscription-scoped feed + episode search covering un-downloaded and historical rows, D14), DELETE /feeds/:id (admin; best-effort file removal, cascade deletes rows). Gap definition (countGaps): an un-downloaded episode with a downloaded episode AFTER it in list order — the D8 'middle episodes missing' banner condition.
This commit is contained in:
1 parent
a6723e6ac8
commit
45b1152a15
5 files changed
+772
No files matched your search
@@ -177,6 +177,12 @@ func main() {
|
||||
matchingHandler := handlers.NewMatchingHandler(queries, connManager)
|
||||
jobsHandler := handlers.NewJobsHandler(queries, worker)
|
||||
|
||||
// Podcast subsystem: fetcher service + sequential download worker +
|
||||
// poller. One instance trio per server (per-feed locks dedupe).
|
||||
podcastService := services.NewPodcastService(queries)
|
||||
podcastWorker := services.NewPodcastDownloadWorker(queries, podcastService)
|
||||
podcastHandler := handlers.NewPodcastHandler(queries, podcastService, podcastWorker)
|
||||
|
||||
e := echo.New()
|
||||
|
||||
// Set up validator
|
||||
@@ -237,6 +243,9 @@ func main() {
|
||||
CollectionHandler: collectionHandler,
|
||||
FiltersHandler: filtersHandler,
|
||||
DashboardHandler: dashboardHandler,
|
||||
PodcastHandler: podcastHandler,
|
||||
PodcastService: podcastService,
|
||||
PodcastWorker: podcastWorker,
|
||||
DashboardService: dashboardService,
|
||||
SeriesHandler: seriesHandler,
|
||||
OPDSHandler: opdsHandler,
|
||||
|
||||
Reference in new issue
Block a user