1a2270c95e
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>
35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import { app } from 'electron'
|
|
import { join } from 'path'
|
|
import { accessSync, mkdirSync, constants } from 'fs'
|
|
|
|
/**
|
|
* When running as the portable build, keep all per-user data (settings, history,
|
|
* caches — everything under `userData`) in an `AeroFetch-data` folder right next to
|
|
* the portable .exe. That makes the app fully self-contained on a USB stick and
|
|
* leaves nothing behind on a shared/library PC.
|
|
*
|
|
* Detection: electron-builder's `portable` target sets PORTABLE_EXECUTABLE_DIR at
|
|
* runtime to the folder the user launched the exe from. The installed (NSIS) build
|
|
* and dev don't set it, so they correctly use the default %APPDATA%\AeroFetch —
|
|
* which is per-user and never requires admin either.
|
|
*
|
|
* If the portable folder is read-only (locked-down machine, read-only media), we
|
|
* silently fall back to %APPDATA%. Either way the app needs no admin privileges.
|
|
*
|
|
* Must be called at startup, before the app is ready and before anything reads a
|
|
* user path (electron-store, history DB, etc.).
|
|
*/
|
|
export function setupPortableData(): void {
|
|
const portableExeDir = process.env.PORTABLE_EXECUTABLE_DIR
|
|
if (!portableExeDir) return
|
|
|
|
const portableDataDir = join(portableExeDir, 'AeroFetch-data')
|
|
try {
|
|
mkdirSync(portableDataDir, { recursive: true })
|
|
accessSync(portableDataDir, constants.W_OK)
|
|
app.setPath('userData', portableDataDir)
|
|
} catch {
|
|
// Read-only media — keep the default %APPDATA% userData (per-user, no admin).
|
|
}
|
|
}
|