feat(setup): fetch ffmpeg on first run instead of bundling it
Ship a smaller installer that no longer carries ffmpeg.exe/ffprobe.exe (the bulk of its size). On first run they are downloaded from a pinned upstream archive (gyan 8.1.2), verified against a pinned SHA-256, and unpacked with the OS tar.exe into the managed userData/bin dir -- the same place as the self-updating yt-dlp, so they survive app updates and portable re-extraction. A hard onboarding gate blocks the app until they are present, with a "locate existing ffmpeg" folder-picker fallback for offline machines and a Repair action in Settings > About. The updater's streaming/checksum/redirect/idle-timeout download loop is extracted to lib/verifiedDownload.streamVerifiedFile and shared by both the app-installer download and the ffmpeg fetch; the updater's public behaviour and error strings are unchanged (its boundary tests still pass). No new npm dependency: extraction uses the System32 bsdtar resolved by absolute path (audit F3). Note: this commit also carries pre-existing, in-progress aria2c/network and updater-token work that was already uncommitted in the working tree and is entangled with the above in shared files (updater.ts, ipc.ts, preload/index.ts, mockApi.ts, shared/ipc.ts, plus the settings/network files and aria2c.exe). It was not cleanly separable by path, so it is included here rather than split out. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+35
-25
@@ -4,33 +4,43 @@
|
||||
* timeouts, caps, tickers) and from user settings (settings.ts). Retarget a
|
||||
* fork's update source by editing these three values.
|
||||
*
|
||||
* The update repo is PRIVATE, so the release API + downloads require a token.
|
||||
* A build-time read-only token (BAKED_UPDATE_TOKEN below) lets a shipped client
|
||||
* reach it without the user configuring anything; a user-set updateToken in
|
||||
* Settings still takes precedence. On a build with no token baked in, the update
|
||||
* check simply reports that it couldn't reach the server.
|
||||
* The update source is a PUBLIC, releases-only repo — it holds no source, just
|
||||
* the published installers — so anonymous reads work and the updater sends no
|
||||
* auth at all. Keeping releases separate from the (private) source repo is what
|
||||
* lets the client stay tokenless: there is no secret in the bundle to leak. A
|
||||
* private fork retargets its updater by editing these constants and rebuilding.
|
||||
*/
|
||||
export const UPDATE_HOST = 'https://gitea.netbird.zimspace.uk:5938'
|
||||
export const UPDATE_OWNER = 'debont80'
|
||||
export const UPDATE_REPO = 'AeroFetch'
|
||||
export const UPDATE_REPO = 'AeroFetch-releases'
|
||||
export const RELEASE_API = `${UPDATE_HOST}/api/v1/repos/${UPDATE_OWNER}/${UPDATE_REPO}/releases/latest`
|
||||
|
||||
/**
|
||||
* Read-only Gitea token baked in at build time so the auto-updater can read the
|
||||
* PRIVATE release repo without each user pasting a token into Settings. Injected
|
||||
* by electron.vite.config's `define` from the AEROFETCH_UPDATE_TOKEN env var (or a
|
||||
* gitignored .update-token file) — so the real value lives only in the built
|
||||
* bundle, never in source or git.
|
||||
*
|
||||
* SECURITY: a shipped client is decompilable, so treat this as PUBLIC. It MUST be
|
||||
* a token from a dedicated service account with read-only access to ONLY this repo
|
||||
* — never a personal/push-capable token. The user's own updateToken overrides it
|
||||
* (see authHeader in updater.ts), so a private fork can point elsewhere.
|
||||
*
|
||||
* `__AEROFETCH_UPDATE_TOKEN__` is a `define`-replaced literal in built code; under
|
||||
* plain vitest (no define) the identifier is undeclared, so the `typeof` guard
|
||||
* keeps this from throwing and falls back to empty (no token).
|
||||
*/
|
||||
declare const __AEROFETCH_UPDATE_TOKEN__: string
|
||||
export const BAKED_UPDATE_TOKEN: string =
|
||||
typeof __AEROFETCH_UPDATE_TOKEN__ === 'string' ? __AEROFETCH_UPDATE_TOKEN__ : ''
|
||||
// --- ffmpeg dependency source ------------------------------------------------
|
||||
// ffmpeg/ffprobe are NOT bundled in the installer (they're the bulk of its size);
|
||||
// they're fetched once on first run into the managed userData/bin dir (ffmpegSetup.ts).
|
||||
//
|
||||
// Unlike the app updater — which pulls from our own host-pinned release server — this
|
||||
// downloads from UPSTREAM (gyan.dev's GitHub releases). Integrity therefore rests on a
|
||||
// PINNED exact-version URL + SHA-256 here, re-verified against the streamed bytes: a
|
||||
// swapped or tampered upstream asset fails the check and nothing is installed. Bumping
|
||||
// ffmpeg is a deliberate edit to these three constants in its own commit (recompute the
|
||||
// hash from the new zip) — the same "pinned decisions" discipline the app version follows.
|
||||
//
|
||||
// Licensing note: gyan's "essentials" is a GPL build. That's fine here because AeroFetch
|
||||
// never redistributes it — it invokes ffmpeg.exe as a separate process (as yt-dlp does)
|
||||
// and the user fetches the binary from upstream themselves. Swapping to an LGPL build
|
||||
// (e.g. a BtbN win64 build) is purely a change to FFMPEG_ARCHIVE_URL/SHA-256 below,
|
||||
// provided the zip still carries ffmpeg.exe + ffprobe.exe under a `*/bin/` path.
|
||||
export const FFMPEG_VERSION = '8.1.2'
|
||||
export const FFMPEG_ARCHIVE_URL = `https://github.com/GyanD/codexffmpeg/releases/download/${FFMPEG_VERSION}/ffmpeg-${FFMPEG_VERSION}-essentials_build.zip`
|
||||
export const FFMPEG_ARCHIVE_SHA256 =
|
||||
'db580001caa24ac104c8cb856cd113a87b0a443f7bdf47d8c12b1d740584a2ec'
|
||||
// The setup UI quotes ~105 MB for this archive; keep that copy in sync when bumping above.
|
||||
// Hosts the archive download may touch, HTTPS-only, re-checked on EVERY redirect hop
|
||||
// (github.com 302s a release asset to release-assets.githubusercontent.com; the older
|
||||
// objects.githubusercontent.com is kept for resilience). Anything off this list fails safe.
|
||||
export const FFMPEG_TRUSTED_HOSTS = [
|
||||
'github.com',
|
||||
'release-assets.githubusercontent.com',
|
||||
'objects.githubusercontent.com'
|
||||
] as const
|
||||
|
||||
Reference in New Issue
Block a user