- Taskbar progress bar: renderer pushes summarizeQueue aggregate over a new
taskbar:progress channel (App store subscription); setProgressBar normal/error
- System tray (src/main/tray.ts) + minimize-to-tray (Settings.minimizeToTray);
close hides to tray, isQuitting guards real exits; icon via getAppIconPath()
(build/icon.ico added to extraResources)
- Jump list: app.setUserTasks "Open AeroFetch" (thumbnail toolbar deferred)
- Settings search: filters the ~11 SettingsView cards live by text match
Overlay badge deferred (needs a drawn NativeImage). typecheck + test (192) +
build all clean. Roadmap: Phase O COMPLETE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold Phases L-P into ROADMAP.md: media editing (trim/cut, split-chapters,
metadata editing), queue/daily-use UX, power-user surface, Windows-native
integration, and reliability/trust. Cross-link from ROADMAP-PINCHFLAT.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Library channel cards now collapse their playlist groups by default
(single-group sources auto-expand), and each group header has a
Download button that queues just that playlist's pending videos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a source-wide "Select all" across all playlist groups, and make one
click queue every indexed video (the previous 100-per-click cap is gone).
Bulk download skips items that are already downloaded or in flight, so it
can't enqueue duplicates, and it includes failed/canceled ones so it also
retries them.
Make the UI hold up at channel scale (1000s of videos): virtualize both
the Downloads queue and the Library item list with @tanstack/react-virtual
so only on-screen rows hit the DOM, memoize the queue row so they don't all
reconcile on every progress tick, and batch the enqueue so queuing a whole
channel stays O(n) instead of O(n^2).
- VirtualList: reusable windowed list that owns its own scroll container
- DownloadsView: virtualized, flex-filled queue
- LibraryView: groups flattened to rows; virtualized panel above 100 rows,
inline below so small sources are unchanged
- QueueItem: React.memo
- downloads store: addMany (one state update + one pump); sources:
enqueue the whole selection via addMany, no cap
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
yt-dlp is now a managed, auto-updating binary rather than a static bundled
one. On launch AeroFetch seeds a writable copy under userData from the
bundled seed, self-heals it if it goes missing, and — throttled to once a
day — self-updates it to the configured channel (default: nightly). This
keeps the binary current so YouTube changes don't silently cause 403s, and
an app reinstall (or portable re-extraction) can no longer roll it back.
Settings shows an auto-update toggle, the live version, last-checked time,
and the channel selector.
Also surface the bundled ffmpeg/ffprobe versions in Settings (display only:
they have no self-update path and, unlike yt-dlp, don't break as sites
change, so there is no auto-update for them).
- binaries: split the read-only bundled seed from the managed userData copy
- ytdlp: ensureManagedYtdlp (seed + self-heal), startup auto-update runner
- ytdlpPolicy: pure once-a-day throttle decision (unit-tested)
- ffmpeg: parse ffmpeg/ffprobe -version for the Settings panel
- settings/ipc/preload/renderer: new settings, IPC channels, types, and UI
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>