6 Commits

Author SHA1 Message Date
debont80 94ef814fa7 chore: bump version to 0.7.2 2026-07-10 10:43:14 -04:00
debont80 78a168ca5c Merge pull request 'chore(config): point the updater at the now-public AeroFetch repo' (#13) from chore/consolidate-update-source into main
Reviewed-on: #13
2026-07-10 10:41:28 -04:00
debont80 3b9dd6788d chore(config): point the updater at the now-public AeroFetch repo
The source repo is public now, so the separate releases-only repo
(AeroFetch-releases) is no longer needed to keep the updater tokenless.
Retarget UPDATE_REPO from AeroFetch-releases back to AeroFetch and refresh the
config doc comment. The dedicated read-only baked-token service account
(aerofetch-updater) has been deleted and its token revoked, so nothing reads a
token any more; the .gitignore comment for the retired .update-token file is
updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:39:12 -04:00
debont80 ccee9b7d3b chore: bump version to 0.7.1 2026-07-09 15:50:14 -04:00
debont80 af9c285864 Merge pull request 'fix(sync): run watched sync when a scheduled --sync hits the running instance' (#12) from fix/scheduled-sync-running-instance into main
Reviewed-on: #12
2026-07-09 15:48:31 -04:00
debont80 87e16ca28e fix(sync): run watched sync when a scheduled --sync hits the running instance
The Windows daily-sync task launches `AeroFetch.exe --sync`, but the single-
instance lock routes that relaunch to the `second-instance` handler whenever
AeroFetch is already open. The handler only focused the window and looked for a
link -- it never checked `isSyncLaunch(argv)` -- so the sync never ran. The daily
auto-download of new watched-source uploads therefore did nothing for minimize-
to-tray / always-on users (and the relaunch stole window focus each day).

Add a `runWatchedSync` main->renderer push: on a `--sync` relaunch the handler
now nudges the renderer to run syncWatched() instead of focusing, so the daily
sync fires whether AeroFetch was closed or already running.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:45:35 -04:00
9 changed files with 38 additions and 13 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ dist
# Secrets — never commit # Secrets — never commit
.gitea-token .gitea-token
# Retired: no longer read by the build (baked update token removed), but the # Retired: the baked update token was removed from the build and its service
# local file still holds a live token until it's revoked — keep it ignored. # account revoked; kept ignored so a stray local .update-token can never be committed.
.update-token .update-token
# VS Code user settings (workspace settings/.vscode/launch.json are committed) # VS Code user settings (workspace settings/.vscode/launch.json are committed)
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "aerofetch", "name": "aerofetch",
"version": "0.7.0", "version": "0.7.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "aerofetch", "name": "aerofetch",
"version": "0.7.0", "version": "0.7.2",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "aerofetch", "name": "aerofetch",
"version": "0.7.0", "version": "0.7.2",
"description": "A yt-dlp frontend for Windows", "description": "A yt-dlp frontend for Windows",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "AeroFetch", "author": "AeroFetch",
+7 -6
View File
@@ -4,15 +4,16 @@
* timeouts, caps, tickers) and from user settings (settings.ts). Retarget a * timeouts, caps, tickers) and from user settings (settings.ts). Retarget a
* fork's update source by editing these three values. * fork's update source by editing these three values.
* *
* The update source is a PUBLIC, releases-only repo — it holds no source, just * The update source is the main AeroFetch repo itself, made PUBLIC — so anonymous
* the published installers — so anonymous reads work and the updater sends no * reads work and the updater sends no auth at all; there is no secret in the bundle
* auth at all. Keeping releases separate from the (private) source repo is what * to leak. (A prior design split releases into a separate releases-only repo so the
* lets the client stay tokenless: there is no secret in the bundle to leak. A * source could stay private; that's retired now that the source repo is public
* private fork retargets its updater by editing these constants and rebuilding. * itself — one fewer moving part.) 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_HOST = 'https://gitea.netbird.zimspace.uk:5938'
export const UPDATE_OWNER = 'debont80' export const UPDATE_OWNER = 'debont80'
export const UPDATE_REPO = 'AeroFetch-releases' export const UPDATE_REPO = 'AeroFetch'
export const RELEASE_API = `${UPDATE_HOST}/api/v1/repos/${UPDATE_OWNER}/${UPDATE_REPO}/releases/latest` export const RELEASE_API = `${UPDATE_HOST}/api/v1/repos/${UPDATE_OWNER}/${UPDATE_REPO}/releases/latest`
// --- ffmpeg dependency source ------------------------------------------------ // --- ffmpeg dependency source ------------------------------------------------
+9
View File
@@ -260,6 +260,15 @@ if (isPrimaryInstance) {
// link it carried and hand it to the window we already have. // link it carried and hand it to the window we already have.
app.on('second-instance', (_e, argv) => { app.on('second-instance', (_e, argv) => {
if (!mainWindow) return if (!mainWindow) return
// A scheduled `--sync` relaunch (Task Scheduler) hit the already-running instance:
// run the watched-source sync in this window instead of no-opping. Without this the
// daily auto-download never fires while AeroFetch is open — e.g. minimize-to-tray
// users. Deliberately does NOT focus the window, so the daily sync stays unobtrusive
// (mirrors the fresh-launch `--sync` showInactive path in createWindow).
if (isSyncLaunch(argv)) {
mainWindow.webContents.send(IpcChannels.runWatchedSync)
return
}
focusWindow(mainWindow) focusWindow(mainWindow)
const incomingUrl = extractIncomingUrl(argv) const incomingUrl = extractIncomingUrl(argv)
if (incomingUrl) mainWindow.webContents.send(IpcChannels.externalUrl, incomingUrl) if (incomingUrl) mainWindow.webContents.send(IpcChannels.externalUrl, incomingUrl)
+8
View File
@@ -279,6 +279,14 @@ const api = {
return () => ipcRenderer.removeListener(IpcChannels.indexProgress, listener) return () => ipcRenderer.removeListener(IpcChannels.indexProgress, listener)
}, },
/** Subscribe to the "run watched-source sync now" nudge a scheduled `--sync` relaunch
* sends when it hits the already-running instance. Returns an unsubscribe function. */
onRunWatchedSync: (cb: () => void): (() => void) => {
const listener = (): void => cb()
ipcRenderer.on(IpcChannels.runWatchedSync, listener)
return () => ipcRenderer.removeListener(IpcChannels.runWatchedSync, listener)
},
// --- Built-in yt-dlp terminal (Phase N) --- // --- Built-in yt-dlp terminal (Phase N) ---
/** Run the bundled yt-dlp with raw args; output streams via onTerminalOutput. */ /** Run the bundled yt-dlp with raw args; output streams via onTerminalOutput. */
+1
View File
@@ -271,6 +271,7 @@ export const mockApi: Api = {
onSystemThemeUpdate: () => () => {}, onSystemThemeUpdate: () => () => {},
openHighContrastSettings: async () => {}, openHighContrastSettings: async () => {},
onExternalUrl: () => () => {}, onExternalUrl: () => () => {},
onRunWatchedSync: () => () => {},
// Media-manager sources — a seeded channel so the (Phase H) Library view has // Media-manager sources — a seeded channel so the (Phase H) Library view has
// demo data in this browser-only preview. // demo data in this browser-only preview.
listSources: async () => [ listSources: async () => [
+5 -2
View File
@@ -485,13 +485,16 @@ if (!PREVIEW) {
.listSources() .listSources()
.then((sources) => { .then((sources) => {
useSources.setState({ sources }) useSources.setState({ sources })
// If any source is watched, kick off a sync shortly after launch (covers the // If any source is watched, kick off a sync shortly after launch (covers a fresh
// scheduled `--sync` launch and a normal launch alike). // `--sync` launch and a normal launch alike).
if (sources.some((s) => s.watched)) { if (sources.some((s) => s.watched)) {
setTimeout(() => useSources.getState().syncWatched(), 1500) setTimeout(() => useSources.getState().syncWatched(), 1500)
} }
}) })
.catch(logError('startup listSources')) .catch(logError('startup listSources'))
// A scheduled `--sync` relaunch that hit the already-running instance nudges us here,
// so the daily sync fires even when AeroFetch was already open (e.g. tray mode).
window.api.onRunWatchedSync?.(() => useSources.getState().syncWatched())
window.api.onIndexProgress((p: IndexProgress) => { window.api.onIndexProgress((p: IndexProgress) => {
useSources.setState({ useSources.setState({
indexing: { indexing: {
+3
View File
@@ -105,6 +105,9 @@ export const IpcChannels = {
scheduledSyncSet: 'sources:scheduled-sync-set', scheduledSyncSet: 'sources:scheduled-sync-set',
/** main → renderer push channel for live indexing progress */ /** main → renderer push channel for live indexing progress */
indexProgress: 'sources:index-progress', indexProgress: 'sources:index-progress',
/** main → renderer: a scheduled `--sync` relaunch hit the running instance — run the
* watched-source sync here instead of no-opping (Phase J) */
runWatchedSync: 'sources:run-sync',
// --- Built-in yt-dlp terminal (Phase N) --- // --- Built-in yt-dlp terminal (Phase N) ---
terminalRun: 'terminal:run', terminalRun: 'terminal:run',
terminalCancel: 'terminal:cancel', terminalCancel: 'terminal:cancel',