diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json
index b0bc31d..975ddce 100644
--- a/typescript-version/package-lock.json
+++ b/typescript-version/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "twitch-vod-manager",
- "version": "4.1.5",
+ "version": "4.1.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "twitch-vod-manager",
- "version": "4.1.5",
+ "version": "4.1.6",
"license": "MIT",
"dependencies": {
"axios": "^1.6.0",
diff --git a/typescript-version/package.json b/typescript-version/package.json
index 4c6e5e9..24b7f2e 100644
--- a/typescript-version/package.json
+++ b/typescript-version/package.json
@@ -1,6 +1,6 @@
{
"name": "twitch-vod-manager",
- "version": "4.1.5",
+ "version": "4.1.6",
"description": "Twitch VOD Manager - Download Twitch VODs easily",
"main": "dist/main.js",
"author": "xRangerDE",
diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html
index 73f98e6..ee254fd 100644
--- a/typescript-version/src/index.html
+++ b/typescript-version/src/index.html
@@ -457,7 +457,7 @@
Updates
-
Version: v4.1.5
+
Version: v4.1.6
@@ -502,7 +502,7 @@
Nicht verbunden
- v4.1.5
+ v4.1.6
diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts
index fac1038..4765ce8 100644
--- a/typescript-version/src/main.ts
+++ b/typescript-version/src/main.ts
@@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
// ==========================================
// CONFIG & CONSTANTS
// ==========================================
-const APP_VERSION = '4.1.5';
+const APP_VERSION = '4.1.6';
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
// Paths
@@ -30,6 +30,9 @@ const MIN_FREE_DISK_BYTES = 128 * 1024 * 1024;
const TOOL_PATH_REFRESH_TTL_MS = 10 * 1000;
const DEBUG_LOG_FLUSH_INTERVAL_MS = 1000;
const DEBUG_LOG_BUFFER_FLUSH_LINES = 48;
+const AUTO_UPDATE_CHECK_INTERVAL_MS = 10 * 60 * 1000;
+const AUTO_UPDATE_STARTUP_CHECK_DELAY_MS = 5000;
+const AUTO_UPDATE_MIN_CHECK_GAP_MS = 45 * 1000;
const CACHE_CLEANUP_INTERVAL_MS = 60 * 1000;
const MAX_LOGIN_TO_USER_ID_CACHE_ENTRIES = 4096;
const MAX_VOD_LIST_CACHE_ENTRIES = 512;
@@ -43,6 +46,7 @@ const TWITCH_WEB_CLIENT_ID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
type PerformanceMode = 'stability' | 'balanced' | 'speed';
type RetryErrorClass = 'network' | 'rate_limit' | 'auth' | 'tooling' | 'integrity' | 'io' | 'validation' | 'unknown';
+type UpdateCheckSource = 'startup' | 'interval' | 'manual';
// Ensure directories exist
if (!fs.existsSync(APPDATA_DIR)) {
@@ -383,6 +387,12 @@ let bundledToolPathSignature = '';
let bundledToolPathRefreshedAt = 0;
let debugLogFlushTimer: NodeJS.Timeout | null = null;
let pendingDebugLogLines: string[] = [];
+let autoUpdaterInitialized = false;
+let autoUpdateCheckTimer: NodeJS.Timeout | null = null;
+let autoUpdateStartupTimer: NodeJS.Timeout | null = null;
+let autoUpdateCheckInProgress = false;
+let autoUpdateReadyToInstall = false;
+let lastAutoUpdateCheckAt = 0;
// ==========================================
// TOOL PATHS
@@ -2782,7 +2792,75 @@ function createWindow(): void {
// ==========================================
// AUTO-UPDATER (electron-updater)
// ==========================================
+async function requestUpdateCheck(source: UpdateCheckSource, force = false): Promise<{ started: boolean; reason?: string }> {
+ if (autoUpdateReadyToInstall) {
+ return { started: false, reason: 'ready-to-install' };
+ }
+
+ if (autoUpdateCheckInProgress) {
+ return { started: false, reason: 'in-progress' };
+ }
+
+ const now = Date.now();
+ if (!force && lastAutoUpdateCheckAt > 0 && (now - lastAutoUpdateCheckAt) < AUTO_UPDATE_MIN_CHECK_GAP_MS) {
+ return { started: false, reason: 'throttled' };
+ }
+
+ autoUpdateCheckInProgress = true;
+ lastAutoUpdateCheckAt = now;
+ appendDebugLog('update-check-start', { source });
+
+ try {
+ await autoUpdater.checkForUpdates();
+ return { started: true };
+ } catch (err) {
+ appendDebugLog('update-check-failed', { source, error: String(err) });
+ console.error('Update check failed:', err);
+ return { started: false, reason: 'error' };
+ } finally {
+ autoUpdateCheckInProgress = false;
+ }
+}
+
+function stopAutoUpdatePolling(): void {
+ if (autoUpdateCheckTimer) {
+ clearInterval(autoUpdateCheckTimer);
+ autoUpdateCheckTimer = null;
+ }
+
+ if (autoUpdateStartupTimer) {
+ clearTimeout(autoUpdateStartupTimer);
+ autoUpdateStartupTimer = null;
+ }
+}
+
+function startAutoUpdatePolling(): void {
+ if (!autoUpdateCheckTimer) {
+ autoUpdateCheckTimer = setInterval(() => {
+ void requestUpdateCheck('interval');
+ }, AUTO_UPDATE_CHECK_INTERVAL_MS);
+
+ autoUpdateCheckTimer.unref?.();
+ }
+
+ if (autoUpdateStartupTimer) {
+ clearTimeout(autoUpdateStartupTimer);
+ autoUpdateStartupTimer = null;
+ }
+
+ autoUpdateStartupTimer = setTimeout(() => {
+ autoUpdateStartupTimer = null;
+ void requestUpdateCheck('startup', true);
+ }, AUTO_UPDATE_STARTUP_CHECK_DELAY_MS);
+}
+
function setupAutoUpdater() {
+ if (autoUpdaterInitialized) {
+ startAutoUpdatePolling();
+ return;
+ }
+
+ autoUpdaterInitialized = true;
autoUpdater.autoDownload = false;
autoUpdater.autoInstallOnAppQuit = true;
@@ -2792,6 +2870,7 @@ function setupAutoUpdater() {
autoUpdater.on('update-available', (info) => {
console.log('Update available:', info.version);
+ autoUpdateReadyToInstall = false;
if (mainWindow) {
mainWindow.webContents.send('update-available', {
version: info.version,
@@ -2818,6 +2897,7 @@ function setupAutoUpdater() {
autoUpdater.on('update-downloaded', (info) => {
console.log('Update downloaded:', info.version);
+ autoUpdateReadyToInstall = true;
if (mainWindow) {
mainWindow.webContents.send('update-downloaded', {
version: info.version
@@ -2826,13 +2906,11 @@ function setupAutoUpdater() {
});
autoUpdater.on('error', (err) => {
+ autoUpdateCheckInProgress = false;
console.error('Auto-updater error:', err);
});
- // Check for updates
- autoUpdater.checkForUpdates().catch(err => {
- console.error('Update check failed:', err);
- });
+ startAutoUpdatePolling();
}
// ==========================================
@@ -3015,8 +3093,15 @@ ipcMain.handle('get-version', () => APP_VERSION);
ipcMain.handle('check-update', async () => {
try {
- const result = await autoUpdater.checkForUpdates();
- return { checking: true };
+ setupAutoUpdater();
+ const result = await requestUpdateCheck('manual', true);
+ if (result.reason === 'error') {
+ return { error: true };
+ }
+
+ return result.started
+ ? { checking: true }
+ : { checking: true, skipped: result.reason };
} catch (err) {
console.error('Update check failed:', err);
return { error: true };
@@ -3025,6 +3110,7 @@ ipcMain.handle('check-update', async () => {
ipcMain.handle('download-update', async () => {
try {
+ autoUpdateReadyToInstall = false;
await autoUpdater.downloadUpdate();
return { downloading: true };
} catch (err) {
@@ -3198,6 +3284,7 @@ app.on('window-all-closed', () => {
stopMetadataCacheCleanup();
cleanupMetadataCaches('shutdown');
stopDebugLogFlushTimer(true);
+ stopAutoUpdatePolling();
if (currentProcess) {
currentProcess.kill();
@@ -3213,5 +3300,6 @@ app.on('before-quit', () => {
stopMetadataCacheCleanup();
cleanupMetadataCaches('shutdown');
stopDebugLogFlushTimer(true);
+ stopAutoUpdatePolling();
flushQueueSave();
});