Parent
#123
What this delivers
Offline downloads on the new iOS app: background video and audio downloads, a managed queue, offline playback, and server-synced watch positions. Existing downloads in the current app are not migrated.
Ownership
This feature owns its simultaneous-download limit, queue persistence, storage accounting, and local completion-notification permission. Settings #138 assembles links to those controls but does not reimplement them.
Scope
- Download HLS assets through AVAssetDownloadURLSession with background-session restoration after relaunch or reboot, alongside audio-file downloads.
- Manage a persisted queue with the configurable concurrency limit, numeric per-item progress, pause, cancel, multi-select delete, retry, and partial-failure reporting.
- Request local completion-notification permission within the download flow and surface storage accounting in the downloads screen.
- From one explicit action, hand a single unsupported file through conversion completion into download without losing its queue identity, while showing conversion and download as distinct stages.
- Inventory available audio languages before download and let the user select one or more tracks within a disclosed, bounded storage budget.
- Preserve every selected audio track in downloaded media, select the preferred language when present with a predictable fallback, and allow switching among all downloaded tracks offline.
- Disclose the stored audio and subtitle tracks in download details, while keeping existing single-audio downloads working.
- Play through the shared player slices while offline, record positions locally, and sync them when connectivity returns.
- Choose the queue/state persistence mechanism in this slice and record it as a repository pattern; the current app's Realm choice is not a constraint.
Acceptance criteria
Verification
Unit tests cover queue persistence, limits, conversion handoff, pre-download track inventory, bounded multi-audio selection, preferred-language fallback, stored-track disclosure, single-audio regression, relaunch, offline track switching, accounting, and sync. Physical-device proof covers background completion and airplane-mode playback; simulator proof alone is insufficient.
Blocked by
Boundaries
No migration of existing downloads. Batch and folder offline UX beyond current-app parity remains post-v1 #92.
Verified checkpoint — 2026-09-10
#219 merged as 9276e88. A Downloads tab backed by a JSON-persisted queue and AVAssetDownloadURLSession: multi-audio inventory and bounded selection with a storage estimate, conversion-then-download under one identity, configurable concurrency, pause/resume/retry/multi-select remove, details disclosing stored tracks, offline playback with preferred-language selection, local position recording with sync on foreground and across relaunch, storage accounting, completion notifications, per-account queues, and account-keyed background tasks with a relay journal so a finished download survives a background relaunch. The queue document under Application Support is the recorded persistence pattern.
Simulator proof: the downloads preflight in the files-browser journey covers inventory, bounded selection, completion, details, offline playback selecting Turkish, pending position across relaunch, sync, and removal.
Remaining on a physical device: background completion after the device relocks, and airplane-mode playback.
Verified checkpoint — 2026-09-13
#229 (0e07df3), #230 (cf602a0), and #234 (d8111fd) closed #106: removing a download can also ask put.io for the original through a separately worded destructive choice. The local copy goes first; remote failures report per file with a retry; owed originals persist across relaunch, sign-out, and purge; the Trash setting is confirmed from the server before each request and a changed setting refuses instead of deleting permanently; loaded folders reconcile. #223 (070b0f9) purges packages a quarantined queue no longer lists.
Real-account proof on the devs-auto profile: download from the live harness folder, remove with move-to-Trash, folder reconciled, original confirmed in Trash through the CLI.
Follow-ups: #232 (completed row reads Zero kB), #233 (store swallows write failures), #235 (refresh loaded folders after a lost-response failure).
Parent
#123
What this delivers
Offline downloads on the new iOS app: background video and audio downloads, a managed queue, offline playback, and server-synced watch positions. Existing downloads in the current app are not migrated.
Ownership
This feature owns its simultaneous-download limit, queue persistence, storage accounting, and local completion-notification permission. Settings #138 assembles links to those controls but does not reimplement them.
Scope
Acceptance criteria
Verification
Unit tests cover queue persistence, limits, conversion handoff, pre-download track inventory, bounded multi-audio selection, preferred-language fallback, stored-track disclosure, single-audio regression, relaunch, offline track switching, accounting, and sync. Physical-device proof covers background completion and airplane-mode playback; simulator proof alone is insufficient.
Blocked by
Boundaries
No migration of existing downloads. Batch and folder offline UX beyond current-app parity remains post-v1 #92.
Verified checkpoint — 2026-09-10
#219 merged as 9276e88. A Downloads tab backed by a JSON-persisted queue and AVAssetDownloadURLSession: multi-audio inventory and bounded selection with a storage estimate, conversion-then-download under one identity, configurable concurrency, pause/resume/retry/multi-select remove, details disclosing stored tracks, offline playback with preferred-language selection, local position recording with sync on foreground and across relaunch, storage accounting, completion notifications, per-account queues, and account-keyed background tasks with a relay journal so a finished download survives a background relaunch. The queue document under Application Support is the recorded persistence pattern.
Simulator proof: the downloads preflight in the files-browser journey covers inventory, bounded selection, completion, details, offline playback selecting Turkish, pending position across relaunch, sync, and removal.
Remaining on a physical device: background completion after the device relocks, and airplane-mode playback.
Verified checkpoint — 2026-09-13
#229 (0e07df3), #230 (cf602a0), and #234 (d8111fd) closed #106: removing a download can also ask put.io for the original through a separately worded destructive choice. The local copy goes first; remote failures report per file with a retry; owed originals persist across relaunch, sign-out, and purge; the Trash setting is confirmed from the server before each request and a changed setting refuses instead of deleting permanently; loaded folders reconcile. #223 (070b0f9) purges packages a quarantined queue no longer lists.
Real-account proof on the
devs-autoprofile: download from the live harness folder, remove with move-to-Trash, folder reconciled, original confirmed in Trash through the CLI.Follow-ups: #232 (completed row reads Zero kB), #233 (store swallows write failures), #235 (refresh loaded folders after a lost-response failure).