eb53de2ea5
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>
32 lines
1.4 KiB
TypeScript
32 lines
1.4 KiB
TypeScript
import { existsSync } from 'fs'
|
|
import { getFfmpegPath, getFfprobePath } from './binaries'
|
|
import { execFileAsync } from './lib/exec'
|
|
import { VERSION_TIMEOUT_MS } from './constants'
|
|
import type { FfmpegVersionResult } from '@shared/ipc'
|
|
|
|
/**
|
|
* Read the version token from an ffmpeg/ffprobe binary. Both print a first line
|
|
* of the form "<tool> version <VERSION> Copyright ..." (e.g.
|
|
* "ffmpeg version 6.1.1-full_build-www.gyan.dev Copyright ..."), so we return the
|
|
* token after "version". Resolves null if the binary is absent, errors, times
|
|
* out, or the line doesn't parse — Settings then shows "not found" instead of
|
|
* failing. Unlike yt-dlp these are never self-updated, so there's no update path.
|
|
*/
|
|
async function readToolVersion(path: string): Promise<string | null> {
|
|
if (!existsSync(path)) return null
|
|
const r = await execFileAsync(path, ['-version'], { timeout: VERSION_TIMEOUT_MS })
|
|
if (!r.ok) return null
|
|
const firstLine = r.stdout.split('\n', 1)[0] ?? ''
|
|
const m = firstLine.match(/version\s+(\S+)/i)
|
|
return m?.[1] ?? null
|
|
}
|
|
|
|
/** Versions of the managed ffmpeg + ffprobe, read in parallel for the Settings panel. */
|
|
export async function getFfmpegVersions(): Promise<FfmpegVersionResult> {
|
|
const [ffmpeg, ffprobe] = await Promise.all([
|
|
readToolVersion(getFfmpegPath()),
|
|
readToolVersion(getFfprobePath())
|
|
])
|
|
return { ffmpeg, ffprobe }
|
|
}
|