a822a2bb52
Phase C had been implemented in the working tree but never committed: named custom-command templates (CRUD + per-download override), command preview, and the in-app yt-dlp self-updater. Phase D adds: history search/kind-filter/multi-select/bulk-delete/ re-download; native OS notifications on completion/failure; a private/ incognito download mode that skips history; settings+template backup/ restore via JSON; and a persistent error log surfaced as a Diagnostics report in Settings. See ROADMAP.md for the full per-item breakdown. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
173 lines
11 KiB
Markdown
173 lines
11 KiB
Markdown
# AeroFetch Roadmap — feature parity with Seal
|
|
|
|
AeroFetch is the Windows/Electron counterpart to [Seal](https://github.com/JunkFood02/Seal),
|
|
the Android Material-You frontend for [yt-dlp](https://github.com/yt-dlp/yt-dlp). The core
|
|
loop (probe → format pick → queue → download → history) is already in place. This document
|
|
tracks the remaining **gap**: everything Seal does that AeroFetch doesn't yet.
|
|
|
|
Sources: [Seal GitHub](https://github.com/JunkFood02/Seal) ·
|
|
[Seal on F-Droid](https://f-droid.org/packages/com.junkfood.seal/) ·
|
|
[It's FOSS overview](https://itsfoss.com/news/seal/).
|
|
|
|
---
|
|
|
|
## Already at parity ✅
|
|
|
|
Video + audio download · audio → mp3 with embedded thumbnail/metadata · interactive format
|
|
picker (probe) · quality presets · queue + concurrency cap + cancel · download history
|
|
(open / show-in-folder) · clipboard auto-detect · light/dark theme · output folder +
|
|
filename template · yt-dlp version check · NSIS installer + portable build.
|
|
|
|
---
|
|
|
|
## Phase A — Core download power ✅ COMPLETE
|
|
|
|
A shared `DownloadOptions` model (`src/shared/ipc.ts`) carries the post-processing
|
|
choices end-to-end. Persisted defaults are editable in **Settings → Format &
|
|
post-processing** via a reusable `DownloadOptionsForm` component, which the download
|
|
bar also hosts in a collapsible per-download **Options** panel. The main process emits
|
|
the flags in `buildArgs` (`src/main/download.ts`). All items verified in the UI preview
|
|
(typecheck clean). *Caveat: the option flags themselves were validated by reasoning +
|
|
typecheck, not yet by live yt-dlp downloads — worth a real-download smoke test pass.*
|
|
|
|
- [x] **Playlist downloads.** Probe now uses `yt-dlp -J --flat-playlist` and returns either
|
|
a single video (with formats) or a flat playlist. The download bar shows a selection
|
|
panel (scrollable checkbox list, select-all/none, live count) and enqueues each chosen
|
|
entry as its own single-video download — reusing the existing queue/concurrency/history.
|
|
- [x] **Subtitles.** Download + embed (`--write-subs`, `--write-auto-subs`, `--sub-langs`,
|
|
`--embed-subs`, `--convert-subs srt`); language field + auto-caption toggle.
|
|
- [x] **SponsorBlock.** `--sponsorblock-mark` / `--sponsorblock-remove` with a category
|
|
multi-select (sponsor, intro, outro, selfpromo, music_offtopic…) + `--force-keyframes-at-cuts`.
|
|
- [x] **More audio formats.** Was mp3-only. Now best / mp3 / m4a / opus / flac / wav / aac
|
|
via `--audio-format`.
|
|
- [x] **Video container + codec preference.** Container choice (mp4/mkv/webm) +
|
|
preferred codec (`-S res,fps,vcodec:…`) to nudge toward av1 / vp9 / h264 without
|
|
overriding the requested resolution.
|
|
- [x] **Embed chapters.** `--embed-chapters` toggle. (`--split-chapters` still TODO.)
|
|
- [x] **Embed thumbnail crop-to-square** for audio (Seal's "crop artwork") via thumbnail
|
|
post-processor args. *Implemented; needs a real-download smoke test of the ffmpeg crop recipe.*
|
|
- [x] **Per-download overrides.** Collapsible Options panel in the download bar (shared
|
|
`DownloadOptionsForm`) so one download — or one playlist batch — can deviate from the
|
|
persisted defaults; "Reset to defaults" clears it. Threads `options` through
|
|
`addFromUrl → DownloadItem → startDownload` and is carried on retry.
|
|
|
|
## Phase B — Access & networking ✅ COMPLETE
|
|
|
|
`buildArgs`'s former `NetworkOptions` param is now `AccessOptions` (still in
|
|
`src/main/buildArgs.ts`) — it grew past pure networking once cookies and
|
|
filename/archive flags joined proxy/rate-limit/aria2c. *Caveat: the sign-in
|
|
window's cookie export is implemented per the Electron session-cookie and
|
|
Netscape cookie-jar formats and verified by reasoning + typecheck, not yet by
|
|
an actual live login → yt-dlp download against a gated video — worth a real
|
|
smoke test.*
|
|
|
|
- [x] **Cookies.** Settings → Cookies has a source picker:
|
|
- *From a browser's cookie store* → `--cookies-from-browser <name>` (chrome/edge/
|
|
firefox/brave/opera/vivaldi — `COOKIE_BROWSERS` in `src/shared/ipc.ts`).
|
|
- *Sign-in window (built into AeroFetch)* → opens an Electron `BrowserWindow` on a
|
|
persisted session partition (`persist:aerofetch-login`, see `src/main/cookies.ts`);
|
|
OAuth/SSO popups are allowed through onto the same partition. Closing the window
|
|
exports its cookies to a Netscape-format file (`userData/cookies.txt`) which
|
|
`buildArgs` passes via `--cookies`. Settings → Cookies shows last-saved time + a
|
|
"Clear saved cookies" button (also clears the partition's storage).
|
|
- [x] **aria2c external downloader.** Settings → Network has a "Use aria2c downloader"
|
|
toggle; when on and `resources/bin/aria2c.exe` exists, `buildArgs` emits
|
|
`--downloader <path> --downloader-args` (`ARIA2C_ARGS` in `src/main/buildArgs.ts`:
|
|
`-x 16 -s 16 -k 1M`). Missing binary falls back silently to yt-dlp's own downloader
|
|
(checked in `src/main/download.ts`). Binary is optional and not committed — see
|
|
`resources/bin/README.md`.
|
|
- [x] **Proxy** (`--proxy`) and **rate limit** (`--limit-rate`). Settings → Network fields
|
|
(`Settings.proxy` / `Settings.rateLimit`), threaded through `buildArgs`'s
|
|
`AccessOptions` param.
|
|
- [x] **Restrict filenames** toggle (`--restrict-filenames`) + **download archive**
|
|
(`--download-archive`, skip already-downloaded) — both in Settings → Filenames.
|
|
The archive file lives at a fixed `userData/download-archive.txt`
|
|
(`getDownloadArchivePath()` in `src/main/settings.ts`), not user-configurable.
|
|
|
|
## Phase C — Custom commands & yt-dlp management ✅ COMPLETE
|
|
|
|
Named `CommandTemplate`s (`src/shared/ipc.ts`) persist to `templates.json`
|
|
(`src/main/templates.ts`, mirrors `history.ts`'s plain-JSON pattern) and are managed
|
|
inline in **Settings → Custom commands** via `TemplateManager.tsx` — no modal, matching
|
|
the rest of the app's no-portal-overlay convention (see the Hint/Select comments re:
|
|
this dev machine's GPU/driver). A template's extra yt-dlp flags are shell-split
|
|
(`parseExtraArgs`, `src/main/buildArgs.ts`) and appended to the generated argv
|
|
immediately before the `--` URL terminator, so a template flag can override anything
|
|
chosen earlier. `Settings.customCommandEnabled` + `defaultTemplateId` apply a template
|
|
to every new download; the download bar's own **Custom command** panel lets a single
|
|
download override that default or opt out entirely (`extraArgs` on
|
|
`StartDownloadOptions`, mirroring the existing per-download `options` override).
|
|
`buildCommand()` (`src/main/download.ts`) now centralises settings/access/
|
|
options/extraArgs resolution, shared by both the real `startDownload` spawn and the new
|
|
preview path. All items verified in the UI preview + `npm run typecheck` +
|
|
`npm run test` (11 new unit tests covering `parseExtraArgs`, `formatCommandLine`, and
|
|
extraArgs ordering). *Caveat: the extra-args splitting and command construction were
|
|
validated by reasoning + tests, not yet by a real yt-dlp run with actual custom flags —
|
|
worth a real-download smoke test pass, same as Phase A/B.*
|
|
|
|
- [x] **Custom command templates.** Named, editable templates of extra yt-dlp args
|
|
(`CommandTemplate`), CRUD'd inline via `TemplateManager.tsx`; persisted to
|
|
`templates.json`. **Pick a default** via `Settings.defaultTemplateId` (a Select in
|
|
the Custom commands card). The **"run custom command" mode** is
|
|
`Settings.customCommandEnabled`, applied to every new download unless overridden
|
|
per-download in the download bar's Custom command panel.
|
|
- [x] **Command preview.** `IpcChannels.commandPreview` → `previewCommand()`
|
|
(`src/main/download.ts`) builds the exact argv via the same `buildCommand()` path
|
|
a real download would take, then renders it with `formatCommandLine`. Surfaced as
|
|
a **Preview command** button in the download bar, with a Copy button.
|
|
- [x] **In-app yt-dlp updater.** `updateYtdlp(channel)` (`src/main/ytdlp.ts`) runs
|
|
yt-dlp's own `--update-to stable|nightly`. Surfaced in **Settings → About**, right
|
|
next to the existing version check, with a channel picker + result output.
|
|
|
|
## Phase D — Library, UX & notifications ✅ COMPLETE
|
|
|
|
History stays plain JSON (`history.json`, 500-entry cap) — search/filter/select are done
|
|
client-side over the already-small array, so the planned better-sqlite3 migration wasn't
|
|
needed for this phase and was deliberately skipped to avoid a native-module build step for
|
|
no functional gain at this scale. Failed downloads (pre-spawn rejections and in-flight
|
|
yt-dlp failures alike) now persist to a new `errorlog.json` (`src/main/errorlog.ts`,
|
|
200-entry cap) independent of the queue, so a report survives `Clear finished`. Native
|
|
notifications and the backup file both reuse existing settings/templates plumbing
|
|
(`getSettings`/`setSettings`, `listTemplates`/the new `replaceTemplates`) rather than adding
|
|
parallel storage. All items verified in the UI preview (typecheck + `npm run test` clean).
|
|
|
|
- [x] **History search + multi-select + filter** (video/audio) + bulk delete + **re-download**.
|
|
`HistoryView.tsx` gained a search box, an All/Video/Audio filter, a "Select" mode with
|
|
per-row checkboxes + select-all + **Delete selected** (new `historyRemoveMany` IPC,
|
|
`src/main/history.ts`), and a per-row re-download button that re-queues the entry's
|
|
URL/kind/quality via the existing `addFromUrl`.
|
|
- [x] **Native OS notifications** on completion / failure (Electron `Notification`,
|
|
`src/main/download.ts`). Gated by a new **Notify when downloads finish** switch
|
|
(`Settings.notifyOnComplete`, default on); clicking a notification refocuses the window.
|
|
- [x] **Private / incognito mode** — a download bar toggle (`DownloadBar.tsx`, sticky like an
|
|
incognito tab) sets `DownloadItem.incognito`, which `store/downloads.ts` checks before
|
|
ever calling `useHistory().add(...)`. Queue items show an eye-off badge when private.
|
|
- [x] **Backup / restore** settings + templates (export / import JSON). New
|
|
`src/main/backup.ts` writes/reads `{ settings, templates }` via a save/open dialog;
|
|
`replaceTemplates()` (`src/main/templates.ts`) does a full restore rather than a
|
|
merge-by-id. Surfaced as **Settings → Backup & restore**.
|
|
- [x] **Error log / copy error report** view (Seal's debug report). New
|
|
`src/main/errorlog.ts` persists every failure (pre-spawn rejection, spawn error, or
|
|
non-zero yt-dlp exit); **Settings → Diagnostics** lists recent entries with
|
|
**Copy full report** and **Clear log**.
|
|
|
|
## Phase E — Theming & platform polish
|
|
|
|
Some items are Android-specific in Seal and adapted to Windows here.
|
|
|
|
- [ ] **Theme presets + "follow system"** and high-contrast (toffee light/dark already exists;
|
|
add system-follow + a few accent presets). *Material-You dynamic color is Android-only;
|
|
closest Windows analog is accent presets / system accent.*
|
|
- [ ] **i18n / language setting** (Seal ships ~40 languages). Large but optional.
|
|
- [ ] **Windows "open with" / share integration** — register a URL-protocol handler or Explorer
|
|
"Send to" entry (analog of Android's share sheet). *Lower priority, platform-specific.*
|
|
- [ ] **Onboarding / welcome screen** on first run.
|
|
|
|
---
|
|
|
|
## Not portable from Seal (noted for completeness)
|
|
|
|
- SAF directory picker (Android storage) → already covered by the native folder dialog.
|
|
- Android share-sheet / quick-download-on-share → partially mapped to Phase E.
|
|
- F-Droid distribution → N/A (AeroFetch ships NSIS + portable).
|