feat(podcasts): played/unplayed queue, background generation, share-sheet audio #4

Merged
admin merged 5 commits from feat/podcast-app-experience into master 2026-07-01 18:18:57 +00:00
Owner

Turns the Podcasts tab into a real podcast-app experience. Three features that compose on one shared background-generation service.

#2 — Background generation (keystone)

  • New PodcastGenerationManager runs the generate → poll → download loop off the player, so a new episode is produced without stopping current playback.
  • Headphone taps now never interrupt: player idle → generate-and-play in the foreground (unchanged); already playing → generate in the background, and the finished episode lands in the library.
  • A "Generating…" banner in the bookmarks overlay surfaces active jobs with progress.

#1 — Played/unplayed + queue

  • PodcastEntry gains playedAt (pre-existing index.json decodes as unplayed — automatic migration).
  • Podcasts tab splits into Up Next / Played, with a Play All queue that auto-advances episode to episode.
  • Finishing marks an episode played; swipe to toggle played/unplayed.

#3 — Share-extension audio

  • "Create podcast" toggle on the save card + configurable Auto-Podcast Tags in Settings.
  • The extension enqueues a request into the shared App Group (it's too short-lived to generate); the main app drains it on launch/foreground and runs it through the background manager.

Notes

  • project.yml updated so PodcastRequests.swift is a member of both the Marks and ShareExtension targets; xcodegen generate + simulator build pass clean.

Closes #1
Closes #2
Closes #3
Closes #6
Closes #8

🤖 Generated with Claude Code

Turns the Podcasts tab into a real podcast-app experience. Three features that compose on one shared background-generation service. ## #2 — Background generation (keystone) - New `PodcastGenerationManager` runs the generate → poll → download loop **off** the player, so a new episode is produced without stopping current playback. - Headphone taps now **never interrupt**: player idle → generate-and-play in the foreground (unchanged); already playing → generate in the **background**, and the finished episode lands in the library. - A "Generating…" banner in the bookmarks overlay surfaces active jobs with progress. ## #1 — Played/unplayed + queue - `PodcastEntry` gains `playedAt` (pre-existing `index.json` decodes as unplayed — automatic migration). - Podcasts tab splits into **Up Next** / **Played**, with a **Play All** queue that auto-advances episode to episode. - Finishing marks an episode played; swipe to toggle played/unplayed. ## #3 — Share-extension audio - "Create podcast" toggle on the save card + configurable **Auto-Podcast Tags** in Settings. - The extension enqueues a request into the shared App Group (it's too short-lived to generate); the main app drains it on launch/foreground and runs it through the background manager. ## Notes - `project.yml` updated so `PodcastRequests.swift` is a member of both the Marks and ShareExtension targets; `xcodegen generate` + simulator build pass clean. Closes #1 Closes #2 Closes #3 Closes #6 Closes #8 🤖 Generated with [Claude Code](https://claude.com/claude-code)
admin added 1 commit 2026-07-01 16:38:04 +00:00
feat(podcasts): played/unplayed queue, background generation, share-sheet audio
All checks were successful
CI / build-and-deploy (push) Successful in 24s
CI / build-and-deploy (pull_request) Successful in 15s
af3112530e
Turns the Podcasts tab into a proper podcast-app experience across three
features that compose on a shared background-generation service.

Background generation (#2)
- New PodcastGenerationManager runs generate→poll→download off the player,
  so producing a new episode never stops current playback.
- Headphone taps never interrupt: idle → generate-and-play in the foreground
  (unchanged); already playing → generate in the background, episode lands in
  the library. A "Generating…" banner surfaces active jobs.

Played/unplayed + queue (#1)
- PodcastEntry gains playedAt (old index.json decodes as unplayed).
- Podcasts tab splits into Up Next / Played with a Play All queue that
  auto-advances; finishing marks played; swipe to toggle played state.

Share-extension audio (#3)
- "Create podcast" toggle on the save card, plus configurable Auto-Podcast
  Tags in Settings. The extension enqueues a request into the App Group; the
  main app drains it on launch/foreground and generates in the background.

Closes #1
Closes #2
Closes #3

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-07-01 17:01:59 +00:00
feat(podcasts): surface mark-played in context menu, full player, and row badge
All checks were successful
CI / build-and-deploy (push) Successful in 18s
CI / build-and-deploy (pull_request) Successful in 18s
5e69d99996
- Add a long-press context menu on each library row (Play/Pause,
  Mark as Played/Unplayed, Delete).
- Add a Mark as Played/Unplayed control next to Share Episode in the full
  player, tracking the loaded episode across queue advances.
- Show a green checkmark on played rows, on top of the existing Played
  section + dimmed title, so played state reads at a glance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-07-01 18:07:33 +00:00
feat(podcasts): #6 quick wins — tab badge, remember speed, sleep timer, persist queue
All checks were successful
CI / build-and-deploy (push) Successful in 17s
CI / build-and-deploy (pull_request) Successful in 18s
d2ccbc94b5
- Unread badge on the Podcasts tab via a new observable PodcastLibrary store
  that mirrors PodcastIndex; all played/remove/generation mutations route
  through it so the count stays live.
- Persist playback speed across sessions (UserDefaults), applied on setup.
- Sleep timer (15/30/45 min or end-of-episode) with a moon menu in the full
  player; end-of-episode stops instead of auto-advancing.
- Persist the current episode + Up Next queue and restore a *paused* session on
  launch; save position when backgrounding. Audio session is only claimed on
  actual playback so a restored session never interrupts other audio.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-07-01 18:11:49 +00:00
feat(podcasts): #8 episode detail sheet (source, played state, actions)
All checks were successful
CI / build-and-deploy (push) Successful in 17s
CI / build-and-deploy (pull_request) Successful in 17s
a155c15e17
- New EpisodeDetailView: title, source domain, created date, played badge,
  and per-episode actions — Play/Pause, Mark Played/Unplayed, Open Source,
  Share, Delete — all routed through the PodcastLibrary store so the badge
  stays in sync.
- Reachable by tapping a row (or "Episode Details" in the context menu) in the
  Podcasts tab, and by tapping a row in the episode picker.

Note: AI summary is intentionally omitted for now — it's keyed by bookmark id
(not URL), so surfacing it would recouple the deliberately-decoupled Podcasts
tab to BookmarksViewModel. Open Source uses Safari rather than the in-app
browser to avoid sheet-stacking. Both are noted as follow-ups on issue #8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-07-01 18:16:18 +00:00
feat(podcasts): #8 follow-ups — AI summary + in-app Open Bookmark
All checks were successful
CI / build-and-deploy (push) Successful in 18s
CI / build-and-deploy (pull_request) Successful in 18s
1f49a7dcbe
Resolves the two deviations from the episode detail sheet:

- AI summary now shows in the detail sheet. Added a URL-keyed AISummaryStore
  that BookmarksViewModel populates as it enriches/loads bookmarks, so the
  decoupled Podcasts tab can surface a summary from just the episode URL —
  without recoupling to BookmarksViewModel.
- "Open Bookmark" opens the in-app BrowserView as a nested sheet (generator
  threaded through PodcastLibraryView / EpisodePickerView), alongside the
  existing "Open in Safari" and Share.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
admin merged commit b496e607fc into master 2026-07-01 18:18:57 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/linkding-ios#4