18 Commits

Author SHA1 Message Date
debont80 f3e10b100d chore: bump version to 0.7.0 2026-07-08 06:01:17 -04:00
debont80 1be2708d15 chore: bump version to 0.6.1
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 08:20:39 -04:00
debont80 48ce591702 chore: bump version to 0.6.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 05:55:40 -04:00
debont80 8f6b2a761b feat(audit): Batch 24 — one validate-and-coerce schema layer for settings (CC9)
zod field schemas in settingsSchema.ts replace setSettings' bespoke
per-key switch: parse → skip-on-fail → store, side effects (secret
encryption, launch-at-startup sync) kept in settings.ts. sanitizeOptions
extracted to settingsOptions.ts to break the import cycle; backup import
flows through the same schema. Field-by-field parity pinned in
test/settingsSchema.test.ts (15 tests); full suite unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 12:41:00 -04:00
debont80 e6b4f343e0 feat(config+ux): batch #5 — source maps, integration script, copy, redownload options
Clean config/copy items (Phase 7):
- L170: build.sourcemap 'hidden' on main/preload/renderer — emit .map for offline
  crash symbolication (of the CC8 logger's raw stacks) without exposing them.
- L34: add `test:integration` npm script (AEROFETCH_REAL_DOWNLOAD=1) for the opt-in
  real-download suite; stays out of `npm test` (needs network + live yt-dlp).
- L87: HistoryEntry carries the original `options`; redownload replays them so a
  re-download reproduces the same post-processing instead of the current defaults.
- L96: folder "Browse" buttons -> "Browse…" (they open the OS picker).
- L97: PO-token placeholder "(none)" -> "Optional -- paste a token" (consistent).
- Ticked already-resolved: L99 (M28 aria-label), L113 (UX2 tooltip=aria-label),
  L95 (usage follows verb/modifier rule), L172 (skipLibCheck accepted).

typecheck + 268 tests + eslint + prettier green (touched files LF/clean).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 12:06:06 -04:00
debont80 6bd29efd23 build: Phase 2 — stop emitting unused .blockmap + clean dist per build
- L83: nsis.differentialPackage: false — the custom updater does full
  downloads and never consumes the differential blockmap, so don't generate it
  (NsisTarget gates blockmap generation on differentialPackage !== false).
- L84: add clean:dist script (fs.rmSync) run at the front of build:win so dist/
  no longer accumulates old-version installers (~3 GB observed). dist/out were
  already gitignored, so this is local-disk hygiene.

Config only; TS gate unaffected. 137 -> 135 open audit items.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 08:39:38 -04:00
debont80 1376c2dee8 Harden audit findings: correctness, type-safety, Windows conventions & polish
Audit-pass over CODE-AUDIT.md (~48 items closed this pass; all verified —
typecheck + 234 tests + eslint + prettier green).

Correctness / bugs:
- B3: match the release checksum to the asset's filename line (no wrong-hash verify)
- B4: newline-safe metadata probe (one --print with a unit-separator delimiter)
- B5 / L88: guard the meta event against canceled items; progress no longer promotes
  a queued item outside pump()
- B7: cookie-login promise always resolves (handles destroy-without-close)
- L146: trim parser rejects >2 colon-group times; M36: Library selection counts only
  actionable rows
- L11 / L50 / L156 / L57 / L159 / L15 / L3: live queue count, empty-cookie message,
  schedule picker min, dead-code/comment cleanup

Type safety:
- Enable noUncheckedIndexedAccess + noFallthroughCasesInSwitch (15 real edge cases fixed)

Resilience / Windows / metadata:
- R5: settings write failure handled (no unhandled IPC rejection; reconciles to truth)
- W1 / W5 / W6: min window size, seeded folder picker, parented sign-in window;
  L147 dead macOS branches removed
- CL1: shared stdout markers; package/builder metadata (license, homepage, repository,
  copyright, tsbuildinfo glob)

Copy / docs / tests:
- M37 / SR9 dev-jargon cleanup in hints; M8 / M25 / M26 / L66 / L80 / L81 reconciled
- New unit tests for L35 (isValidMediaItem) and L36 (compareVersions)

This commit also checkpoints the previously-uncommitted feat/tray-background-clipboard
work it builds on: background running + auto-download, library clipboard detection,
tray, binary management & library scale, credential encryption at rest, the shared
jsonStore and ui/ primitives, and the eslint/prettier tooling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:02:54 -04:00
debont80 d4fcd19e17 chore: bump version to 0.5.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:38:24 -04:00
debont80 8e161fe9ce feat: Library bulk download + list virtualization for large channels
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>
2026-06-26 07:27:52 -04:00
debont80 fa699a803d chore: bump version to 0.4.1
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:24:15 -04:00
debont80 08b9ed9e7a chore: bump version to 0.4.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 13:01:51 -04:00
wayne 2718624828 Show app version in sidebar, make the sidebar collapsible, and add a Light/Dark/Auto theme switch
- Expose the AeroFetch version over IPC (app:version → app.getVersion); the
  sidebar brand now shows "v<version>" beneath the name.
- Sidebar can collapse to a 60px icon-only rail via a toggle button; nav items
  and the theme control fall back to icon + tooltip when collapsed. The state is
  persisted in localStorage so it survives restarts. Hint gains left/right
  placements for the collapsed-rail tooltips.
- Replace the binary dark-mode Switch with an explicit 3-way Light / Dark / Auto
  segmented control (Auto follows the OS). Collapsed, it becomes a single button
  that cycles the three modes.
- Bump version to 0.3.2.

Verified in the browser UI preview: version label, collapse/expand, dark mode,
and the theme switch all render correctly with no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 06:43:44 -04:00
wayne 37687f9870 Separate per-kind video/audio folders, defaulting to Documents\Video and Documents\Audio
Existing installs had outputDir persisted to the Downloads folder (auto-filled by
earlier versions), so the v0.3.0 per-kind routing never triggered — downloads kept
going to Downloads. Replace the single outputDir setting with independent videoDir
and audioDir settings:

- Settings model: drop Settings.outputDir; add videoDir + audioDir (both blank by
  default). A blank value routes that kind into Documents\Video / Documents\Audio;
  a chosen folder overrides it. The stale outputDir key in old settings files is
  simply ignored, so existing users now get the Documents defaults.
- buildCommand routes by kind: per-download override → per-kind folder → default.
- The renderer no longer sends a global outputDir, so main always routes by kind.
- Settings: the single "Download folder" field becomes separate "Video folder" and
  "Audio folder" pickers, each with a Browse + Reset and a Documents\… placeholder.
  Store gains chooseDir(target) / clearDir(target).
- Onboarding: replace the folder picker with a short note about the two default
  folders (changeable in Settings).
- Bump version to 0.3.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 06:11:15 -04:00
wayne a2763f10b4 Route downloads into Documents\Video / Documents\Audio and simplify the home page
- Create Documents\Video and Documents\Audio on startup (ensureMediaDirs), and
  route each download into them by kind when no explicit output folder is set.
  An empty outputDir now means "sort by type"; a chosen folder still overrides
  for both kinds.
- Settings/Onboarding "Download folder" gains a placeholder + hint describing
  the blank = route-by-type behaviour.
- Trim the home download bar to the essentials: URL box, Search and Paste
  buttons, format/quality, and the Download button. Removed the private-mode
  toggle, per-download Options panel, custom-command panel, command preview, and
  the saving-to-folder line.
- Bump version to 0.3.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 05:17:16 -04:00
debont80 831d0a7dc2 chore: bump version to 0.2.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 21:10:52 -04:00
debont80 26cd7fc7b0 Add a pure, unit-tested buildArgs() module
Extracts yt-dlp argv construction out of download.ts into its own
electron-free module (src/main/buildArgs.ts) so it can be exercised by
vitest without spinning up Electron, plus a real-download integration
test (skipped by default; opt in with AEROFETCH_REAL_DOWNLOAD=1) that
spawns the bundled yt-dlp.exe/ffmpeg.exe against its argv. download.ts
isn't wired up to it yet — that lands with the next commit.

This was done in an earlier local session but never actually committed,
even though download.ts has imported from it since the Phase A commit
(bb5dd6c) — the build had been relying on an uncommitted local file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 20:52:23 -04:00
debont80 bb5dd6c438 Add Seal-parity download options + playlist support (Phase A)
Phase A of the Seal feature-parity roadmap: configurable post-processing via a
shared DownloadOptions model (src/shared/ipc.ts), editable as persisted defaults
in Settings and overridable per-download in the download bar.

- audio formats (mp3/m4a/opus/flac/wav/aac), video container (mp4/mkv/webm),
  preferred-codec sort (-S vcodec)
- subtitles (download/embed/langs/auto), SponsorBlock (remove/mark + categories
  + force-keyframes-at-cuts), embed chapters/metadata/thumbnail, square-crop
  audio artwork
- playlist downloads: probe via `-J --flat-playlist`, inline selection UI
  (checkbox list, select-all/none, live count); each entry enqueued as its own
  single-video download, reusing the existing queue/concurrency/history
- reusable DownloadOptionsForm shared by Settings and the download bar so the
  defaults and per-download override never drift
- ROADMAP.md tracking full Seal parity (phases A-E)

Also includes in-tree security hardening that landed alongside: preload sandbox
(CJS preload output), http(s)-only window-open + blocked renderer navigation,
argv-injection guard for URLs (src/main/url.ts), extension-allowlisted file
open/reveal (src/main/reveal.ts), yt-dlp version-check timeout, and a minimal
window.electron presence marker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 19:37:22 -04:00
debont80 1a2270c95e Initial commit: AeroFetch — yt-dlp/YouTube downloader for Windows
Electron + React (Fluent UI) desktop frontend for yt-dlp:
- Download queue with live progress, concurrency cap, cancel/retry
- Format/quality picker via yt-dlp probe; audio extraction to MP3
- Settings + history persistence (electron-store / JSON)
- Clipboard link auto-detect; persisted light/dark theme
- NSIS + portable packaging (binaries bundled at build time, not in git)

UI: "Studio" sidebar layout with a toffee-brown theme (light + neutral dark).
Dropdowns use a native <select> and tooltips a CSS-only Hint, to avoid a
dev-machine GPU overlay flicker/blank issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:17:41 -04:00