Automate background update detection while app is open (v4.1.6)
This commit is contained in:
parent
d04779d0ac
commit
10b80b3f48
4
typescript-version/package-lock.json
generated
4
typescript-version/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.5",
|
"version": "4.1.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.5",
|
"version": "4.1.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.5",
|
"version": "4.1.6",
|
||||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"author": "xRangerDE",
|
"author": "xRangerDE",
|
||||||
|
|||||||
@ -457,7 +457,7 @@
|
|||||||
|
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<h3 id="updateTitle">Updates</h3>
|
<h3 id="updateTitle">Updates</h3>
|
||||||
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.5</p>
|
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.6</p>
|
||||||
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -502,7 +502,7 @@
|
|||||||
<div class="status-dot" id="statusDot"></div>
|
<div class="status-dot" id="statusDot"></div>
|
||||||
<span id="statusText">Nicht verbunden</span>
|
<span id="statusText">Nicht verbunden</span>
|
||||||
</div>
|
</div>
|
||||||
<span id="versionText">v4.1.5</span>
|
<span id="versionText">v4.1.6</span>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// CONFIG & CONSTANTS
|
// CONFIG & CONSTANTS
|
||||||
// ==========================================
|
// ==========================================
|
||||||
const APP_VERSION = '4.1.5';
|
const APP_VERSION = '4.1.6';
|
||||||
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
@ -30,6 +30,9 @@ const MIN_FREE_DISK_BYTES = 128 * 1024 * 1024;
|
|||||||
const TOOL_PATH_REFRESH_TTL_MS = 10 * 1000;
|
const TOOL_PATH_REFRESH_TTL_MS = 10 * 1000;
|
||||||
const DEBUG_LOG_FLUSH_INTERVAL_MS = 1000;
|
const DEBUG_LOG_FLUSH_INTERVAL_MS = 1000;
|
||||||
const DEBUG_LOG_BUFFER_FLUSH_LINES = 48;
|
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 CACHE_CLEANUP_INTERVAL_MS = 60 * 1000;
|
||||||
const MAX_LOGIN_TO_USER_ID_CACHE_ENTRIES = 4096;
|
const MAX_LOGIN_TO_USER_ID_CACHE_ENTRIES = 4096;
|
||||||
const MAX_VOD_LIST_CACHE_ENTRIES = 512;
|
const MAX_VOD_LIST_CACHE_ENTRIES = 512;
|
||||||
@ -43,6 +46,7 @@ const TWITCH_WEB_CLIENT_ID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
|
|||||||
|
|
||||||
type PerformanceMode = 'stability' | 'balanced' | 'speed';
|
type PerformanceMode = 'stability' | 'balanced' | 'speed';
|
||||||
type RetryErrorClass = 'network' | 'rate_limit' | 'auth' | 'tooling' | 'integrity' | 'io' | 'validation' | 'unknown';
|
type RetryErrorClass = 'network' | 'rate_limit' | 'auth' | 'tooling' | 'integrity' | 'io' | 'validation' | 'unknown';
|
||||||
|
type UpdateCheckSource = 'startup' | 'interval' | 'manual';
|
||||||
|
|
||||||
// Ensure directories exist
|
// Ensure directories exist
|
||||||
if (!fs.existsSync(APPDATA_DIR)) {
|
if (!fs.existsSync(APPDATA_DIR)) {
|
||||||
@ -383,6 +387,12 @@ let bundledToolPathSignature = '';
|
|||||||
let bundledToolPathRefreshedAt = 0;
|
let bundledToolPathRefreshedAt = 0;
|
||||||
let debugLogFlushTimer: NodeJS.Timeout | null = null;
|
let debugLogFlushTimer: NodeJS.Timeout | null = null;
|
||||||
let pendingDebugLogLines: string[] = [];
|
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
|
// TOOL PATHS
|
||||||
@ -2782,7 +2792,75 @@ function createWindow(): void {
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// AUTO-UPDATER (electron-updater)
|
// 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() {
|
function setupAutoUpdater() {
|
||||||
|
if (autoUpdaterInitialized) {
|
||||||
|
startAutoUpdatePolling();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
autoUpdaterInitialized = true;
|
||||||
autoUpdater.autoDownload = false;
|
autoUpdater.autoDownload = false;
|
||||||
autoUpdater.autoInstallOnAppQuit = true;
|
autoUpdater.autoInstallOnAppQuit = true;
|
||||||
|
|
||||||
@ -2792,6 +2870,7 @@ function setupAutoUpdater() {
|
|||||||
|
|
||||||
autoUpdater.on('update-available', (info) => {
|
autoUpdater.on('update-available', (info) => {
|
||||||
console.log('Update available:', info.version);
|
console.log('Update available:', info.version);
|
||||||
|
autoUpdateReadyToInstall = false;
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
mainWindow.webContents.send('update-available', {
|
mainWindow.webContents.send('update-available', {
|
||||||
version: info.version,
|
version: info.version,
|
||||||
@ -2818,6 +2897,7 @@ function setupAutoUpdater() {
|
|||||||
|
|
||||||
autoUpdater.on('update-downloaded', (info) => {
|
autoUpdater.on('update-downloaded', (info) => {
|
||||||
console.log('Update downloaded:', info.version);
|
console.log('Update downloaded:', info.version);
|
||||||
|
autoUpdateReadyToInstall = true;
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
mainWindow.webContents.send('update-downloaded', {
|
mainWindow.webContents.send('update-downloaded', {
|
||||||
version: info.version
|
version: info.version
|
||||||
@ -2826,13 +2906,11 @@ function setupAutoUpdater() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
|
autoUpdateCheckInProgress = false;
|
||||||
console.error('Auto-updater error:', err);
|
console.error('Auto-updater error:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for updates
|
startAutoUpdatePolling();
|
||||||
autoUpdater.checkForUpdates().catch(err => {
|
|
||||||
console.error('Update check failed:', err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
@ -3015,8 +3093,15 @@ ipcMain.handle('get-version', () => APP_VERSION);
|
|||||||
|
|
||||||
ipcMain.handle('check-update', async () => {
|
ipcMain.handle('check-update', async () => {
|
||||||
try {
|
try {
|
||||||
const result = await autoUpdater.checkForUpdates();
|
setupAutoUpdater();
|
||||||
return { checking: true };
|
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) {
|
} catch (err) {
|
||||||
console.error('Update check failed:', err);
|
console.error('Update check failed:', err);
|
||||||
return { error: true };
|
return { error: true };
|
||||||
@ -3025,6 +3110,7 @@ ipcMain.handle('check-update', async () => {
|
|||||||
|
|
||||||
ipcMain.handle('download-update', async () => {
|
ipcMain.handle('download-update', async () => {
|
||||||
try {
|
try {
|
||||||
|
autoUpdateReadyToInstall = false;
|
||||||
await autoUpdater.downloadUpdate();
|
await autoUpdater.downloadUpdate();
|
||||||
return { downloading: true };
|
return { downloading: true };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -3198,6 +3284,7 @@ app.on('window-all-closed', () => {
|
|||||||
stopMetadataCacheCleanup();
|
stopMetadataCacheCleanup();
|
||||||
cleanupMetadataCaches('shutdown');
|
cleanupMetadataCaches('shutdown');
|
||||||
stopDebugLogFlushTimer(true);
|
stopDebugLogFlushTimer(true);
|
||||||
|
stopAutoUpdatePolling();
|
||||||
|
|
||||||
if (currentProcess) {
|
if (currentProcess) {
|
||||||
currentProcess.kill();
|
currentProcess.kill();
|
||||||
@ -3213,5 +3300,6 @@ app.on('before-quit', () => {
|
|||||||
stopMetadataCacheCleanup();
|
stopMetadataCacheCleanup();
|
||||||
cleanupMetadataCaches('shutdown');
|
cleanupMetadataCaches('shutdown');
|
||||||
stopDebugLogFlushTimer(true);
|
stopDebugLogFlushTimer(true);
|
||||||
|
stopAutoUpdatePolling();
|
||||||
flushQueueSave();
|
flushQueueSave();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user