feat: self-managing yt-dlp + ffmpeg version display
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>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { shouldAutoCheckYtdlp, AUTO_UPDATE_INTERVAL_MS } from '../src/main/ytdlpPolicy'
|
||||
|
||||
const NOW = 1_782_435_469_486 // arbitrary fixed "now"
|
||||
|
||||
describe('shouldAutoCheckYtdlp', () => {
|
||||
it('never checks when auto-update is disabled', () => {
|
||||
expect(shouldAutoCheckYtdlp(false, 0, NOW)).toBe(false)
|
||||
// …even if a full interval has elapsed.
|
||||
expect(shouldAutoCheckYtdlp(false, NOW - AUTO_UPDATE_INTERVAL_MS * 2, NOW)).toBe(false)
|
||||
})
|
||||
|
||||
it('checks on first run (lastCheck is 0 / never)', () => {
|
||||
expect(shouldAutoCheckYtdlp(true, 0, NOW)).toBe(true)
|
||||
})
|
||||
|
||||
it('skips while inside the throttle window', () => {
|
||||
// Checked one minute ago → far inside the 24h window.
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - 60_000, NOW)).toBe(false)
|
||||
// Exactly one ms short of the interval still skips.
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - (AUTO_UPDATE_INTERVAL_MS - 1), NOW)).toBe(false)
|
||||
})
|
||||
|
||||
it('checks once the interval has elapsed (boundary inclusive)', () => {
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - AUTO_UPDATE_INTERVAL_MS, NOW)).toBe(true)
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - AUTO_UPDATE_INTERVAL_MS * 3, NOW)).toBe(true)
|
||||
})
|
||||
|
||||
it('honours a custom interval', () => {
|
||||
const hour = 60 * 60 * 1000
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - 30 * 60_000, NOW, hour)).toBe(false)
|
||||
expect(shouldAutoCheckYtdlp(true, NOW - hour, NOW, hour)).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user