Smooth auto-updater flow with background downloads and status events (v4.1.9)
This commit is contained in:
parent
4ade0a46ac
commit
3695c096ba
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.8",
|
"version": "4.1.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.8",
|
"version": "4.1.9",
|
||||||
"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.8",
|
"version": "4.1.9",
|
||||||
"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.8</p>
|
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.9</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.8</span>
|
<span id="versionText">v4.1.9</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.8';
|
const APP_VERSION = '4.1.9';
|
||||||
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
@ -33,6 +33,7 @@ const DEBUG_LOG_BUFFER_FLUSH_LINES = 48;
|
|||||||
const AUTO_UPDATE_CHECK_INTERVAL_MS = 10 * 60 * 1000;
|
const AUTO_UPDATE_CHECK_INTERVAL_MS = 10 * 60 * 1000;
|
||||||
const AUTO_UPDATE_STARTUP_CHECK_DELAY_MS = 5000;
|
const AUTO_UPDATE_STARTUP_CHECK_DELAY_MS = 5000;
|
||||||
const AUTO_UPDATE_MIN_CHECK_GAP_MS = 45 * 1000;
|
const AUTO_UPDATE_MIN_CHECK_GAP_MS = 45 * 1000;
|
||||||
|
const AUTO_UPDATE_AUTO_DOWNLOAD = true;
|
||||||
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;
|
||||||
@ -47,6 +48,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';
|
type UpdateCheckSource = 'startup' | 'interval' | 'manual';
|
||||||
|
type UpdateDownloadSource = 'auto' | 'manual';
|
||||||
|
|
||||||
// Ensure directories exist
|
// Ensure directories exist
|
||||||
if (!fs.existsSync(APPDATA_DIR)) {
|
if (!fs.existsSync(APPDATA_DIR)) {
|
||||||
@ -395,6 +397,7 @@ let autoUpdateCheckTimer: NodeJS.Timeout | null = null;
|
|||||||
let autoUpdateStartupTimer: NodeJS.Timeout | null = null;
|
let autoUpdateStartupTimer: NodeJS.Timeout | null = null;
|
||||||
let autoUpdateCheckInProgress = false;
|
let autoUpdateCheckInProgress = false;
|
||||||
let autoUpdateReadyToInstall = false;
|
let autoUpdateReadyToInstall = false;
|
||||||
|
let autoUpdateDownloadInProgress = false;
|
||||||
let lastAutoUpdateCheckAt = 0;
|
let lastAutoUpdateCheckAt = 0;
|
||||||
let twitchLoginInFlight: Promise<boolean> | null = null;
|
let twitchLoginInFlight: Promise<boolean> | null = null;
|
||||||
|
|
||||||
@ -2892,6 +2895,30 @@ async function requestUpdateCheck(source: UpdateCheckSource, force = false): Pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function requestUpdateDownload(source: UpdateDownloadSource): Promise<{ started: boolean; reason?: string }> {
|
||||||
|
if (autoUpdateReadyToInstall) {
|
||||||
|
return { started: false, reason: 'ready-to-install' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoUpdateDownloadInProgress) {
|
||||||
|
return { started: false, reason: 'in-progress' };
|
||||||
|
}
|
||||||
|
|
||||||
|
autoUpdateDownloadInProgress = true;
|
||||||
|
appendDebugLog('update-download-start', { source });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await autoUpdater.downloadUpdate();
|
||||||
|
return { started: true };
|
||||||
|
} catch (err) {
|
||||||
|
appendDebugLog('update-download-failed', { source, error: String(err) });
|
||||||
|
console.error('Download failed:', err);
|
||||||
|
return { started: false, reason: 'error' };
|
||||||
|
} finally {
|
||||||
|
autoUpdateDownloadInProgress = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function stopAutoUpdatePolling(): void {
|
function stopAutoUpdatePolling(): void {
|
||||||
if (autoUpdateCheckTimer) {
|
if (autoUpdateCheckTimer) {
|
||||||
clearInterval(autoUpdateCheckTimer);
|
clearInterval(autoUpdateCheckTimer);
|
||||||
@ -2936,21 +2963,28 @@ function setupAutoUpdater() {
|
|||||||
|
|
||||||
autoUpdater.on('checking-for-update', () => {
|
autoUpdater.on('checking-for-update', () => {
|
||||||
console.log('Checking for updates...');
|
console.log('Checking for updates...');
|
||||||
|
mainWindow?.webContents.send('update-checking');
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-available', (info) => {
|
autoUpdater.on('update-available', (info) => {
|
||||||
console.log('Update available:', info.version);
|
console.log('Update available:', info.version);
|
||||||
autoUpdateReadyToInstall = false;
|
autoUpdateReadyToInstall = false;
|
||||||
|
autoUpdateDownloadInProgress = false;
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
mainWindow.webContents.send('update-available', {
|
mainWindow.webContents.send('update-available', {
|
||||||
version: info.version,
|
version: info.version,
|
||||||
releaseDate: info.releaseDate
|
releaseDate: info.releaseDate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AUTO_UPDATE_AUTO_DOWNLOAD) {
|
||||||
|
void requestUpdateDownload('auto');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-not-available', () => {
|
autoUpdater.on('update-not-available', () => {
|
||||||
console.log('No updates available');
|
console.log('No updates available');
|
||||||
|
mainWindow?.webContents.send('update-not-available');
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('download-progress', (progress) => {
|
autoUpdater.on('download-progress', (progress) => {
|
||||||
@ -2968,6 +3002,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;
|
autoUpdateReadyToInstall = true;
|
||||||
|
autoUpdateDownloadInProgress = false;
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
mainWindow.webContents.send('update-downloaded', {
|
mainWindow.webContents.send('update-downloaded', {
|
||||||
version: info.version
|
version: info.version
|
||||||
@ -2977,6 +3012,10 @@ function setupAutoUpdater() {
|
|||||||
|
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
autoUpdateCheckInProgress = false;
|
autoUpdateCheckInProgress = false;
|
||||||
|
autoUpdateDownloadInProgress = false;
|
||||||
|
const message = String(err);
|
||||||
|
appendDebugLog('auto-updater-error', message);
|
||||||
|
mainWindow?.webContents.send('update-error', { message });
|
||||||
console.error('Auto-updater error:', err);
|
console.error('Auto-updater error:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3194,9 +3233,15 @@ ipcMain.handle('check-update', async () => {
|
|||||||
|
|
||||||
ipcMain.handle('download-update', async () => {
|
ipcMain.handle('download-update', async () => {
|
||||||
try {
|
try {
|
||||||
autoUpdateReadyToInstall = false;
|
setupAutoUpdater();
|
||||||
await autoUpdater.downloadUpdate();
|
const result = await requestUpdateDownload('manual');
|
||||||
return { downloading: true };
|
if (result.reason === 'error') {
|
||||||
|
return { error: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.started
|
||||||
|
? { downloading: true }
|
||||||
|
: { downloading: true, skipped: result.reason };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed:', err);
|
console.error('Download failed:', err);
|
||||||
return { error: true };
|
return { error: true };
|
||||||
|
|||||||
@ -165,13 +165,22 @@ contextBridge.exposeInMainWorld('api', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Auto-Update Events
|
// Auto-Update Events
|
||||||
|
onUpdateChecking: (callback: () => void) => {
|
||||||
|
ipcRenderer.on('update-checking', () => callback());
|
||||||
|
},
|
||||||
onUpdateAvailable: (callback: (info: { version: string; releaseDate?: string }) => void) => {
|
onUpdateAvailable: (callback: (info: { version: string; releaseDate?: string }) => void) => {
|
||||||
ipcRenderer.on('update-available', (_, info) => callback(info));
|
ipcRenderer.on('update-available', (_, info) => callback(info));
|
||||||
},
|
},
|
||||||
|
onUpdateNotAvailable: (callback: () => void) => {
|
||||||
|
ipcRenderer.on('update-not-available', () => callback());
|
||||||
|
},
|
||||||
onUpdateDownloadProgress: (callback: (progress: { percent: number; bytesPerSecond: number; transferred: number; total: number }) => void) => {
|
onUpdateDownloadProgress: (callback: (progress: { percent: number; bytesPerSecond: number; transferred: number; total: number }) => void) => {
|
||||||
ipcRenderer.on('update-download-progress', (_, progress) => callback(progress));
|
ipcRenderer.on('update-download-progress', (_, progress) => callback(progress));
|
||||||
},
|
},
|
||||||
onUpdateDownloaded: (callback: (info: { version: string }) => void) => {
|
onUpdateDownloaded: (callback: (info: { version: string }) => void) => {
|
||||||
ipcRenderer.on('update-downloaded', (_, info) => callback(info));
|
ipcRenderer.on('update-downloaded', (_, info) => callback(info));
|
||||||
|
},
|
||||||
|
onUpdateError: (callback: (payload: { message: string }) => void) => {
|
||||||
|
ipcRenderer.on('update-error', (_, payload) => callback(payload));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
5
typescript-version/src/renderer-globals.d.ts
vendored
5
typescript-version/src/renderer-globals.d.ts
vendored
@ -179,7 +179,7 @@ interface ApiBridge {
|
|||||||
mergeVideos(inputFiles: string[], outputFile: string): Promise<{ success: boolean; outputFile: string | null }>;
|
mergeVideos(inputFiles: string[], outputFile: string): Promise<{ success: boolean; outputFile: string | null }>;
|
||||||
getVersion(): Promise<string>;
|
getVersion(): Promise<string>;
|
||||||
checkUpdate(): Promise<{ checking?: boolean; error?: boolean; skipped?: 'ready-to-install' | 'in-progress' | 'throttled' | 'error' | string }>;
|
checkUpdate(): Promise<{ checking?: boolean; error?: boolean; skipped?: 'ready-to-install' | 'in-progress' | 'throttled' | 'error' | string }>;
|
||||||
downloadUpdate(): Promise<{ downloading?: boolean; error?: boolean }>;
|
downloadUpdate(): Promise<{ downloading?: boolean; error?: boolean; skipped?: 'ready-to-install' | 'in-progress' | 'error' | string }>;
|
||||||
installUpdate(): Promise<void>;
|
installUpdate(): Promise<void>;
|
||||||
openExternal(url: string): Promise<void>;
|
openExternal(url: string): Promise<void>;
|
||||||
runPreflight(autoFix: boolean): Promise<PreflightResult>;
|
runPreflight(autoFix: boolean): Promise<PreflightResult>;
|
||||||
@ -193,9 +193,12 @@ interface ApiBridge {
|
|||||||
onDownloadFinished(callback: () => void): void;
|
onDownloadFinished(callback: () => void): void;
|
||||||
onCutProgress(callback: (percent: number) => void): void;
|
onCutProgress(callback: (percent: number) => void): void;
|
||||||
onMergeProgress(callback: (percent: number) => void): void;
|
onMergeProgress(callback: (percent: number) => void): void;
|
||||||
|
onUpdateChecking(callback: () => void): void;
|
||||||
onUpdateAvailable(callback: (info: UpdateInfo) => void): void;
|
onUpdateAvailable(callback: (info: UpdateInfo) => void): void;
|
||||||
|
onUpdateNotAvailable(callback: () => void): void;
|
||||||
onUpdateDownloadProgress(callback: (progress: UpdateDownloadProgress) => void): void;
|
onUpdateDownloadProgress(callback: (progress: UpdateDownloadProgress) => void): void;
|
||||||
onUpdateDownloaded(callback: (info: UpdateInfo) => void): void;
|
onUpdateDownloaded(callback: (info: UpdateInfo) => void): void;
|
||||||
|
onUpdateError(callback: (payload: { message: string }) => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|||||||
@ -197,7 +197,13 @@ const UI_TEXT_DE = {
|
|||||||
updates: {
|
updates: {
|
||||||
bannerDefault: 'Neue Version verfugbar!',
|
bannerDefault: 'Neue Version verfugbar!',
|
||||||
latest: 'Du hast die neueste Version!',
|
latest: 'Du hast die neueste Version!',
|
||||||
|
checking: 'Suche nach Updates...',
|
||||||
|
checkInProgress: 'Update-Prufung lauft bereits.',
|
||||||
|
readyToInstall: 'Update ist bereit zur Installation.',
|
||||||
|
checkFailed: 'Update-Prufung fehlgeschlagen.',
|
||||||
downloading: 'Wird heruntergeladen...',
|
downloading: 'Wird heruntergeladen...',
|
||||||
|
downloadInProgress: 'Update-Download lauft bereits.',
|
||||||
|
downloadFailed: 'Update-Download fehlgeschlagen.',
|
||||||
available: 'verfugbar!',
|
available: 'verfugbar!',
|
||||||
downloadNow: 'Jetzt herunterladen',
|
downloadNow: 'Jetzt herunterladen',
|
||||||
downloadLabel: 'Download',
|
downloadLabel: 'Download',
|
||||||
|
|||||||
@ -197,7 +197,13 @@ const UI_TEXT_EN = {
|
|||||||
updates: {
|
updates: {
|
||||||
bannerDefault: 'New version available!',
|
bannerDefault: 'New version available!',
|
||||||
latest: 'You are on the latest version!',
|
latest: 'You are on the latest version!',
|
||||||
|
checking: 'Checking for updates...',
|
||||||
|
checkInProgress: 'Update check is already running.',
|
||||||
|
readyToInstall: 'Update is ready to install.',
|
||||||
|
checkFailed: 'Update check failed.',
|
||||||
downloading: 'Downloading...',
|
downloading: 'Downloading...',
|
||||||
|
downloadInProgress: 'Update download is already running.',
|
||||||
|
downloadFailed: 'Update download failed.',
|
||||||
available: 'available!',
|
available: 'available!',
|
||||||
downloadNow: 'Download now',
|
downloadNow: 'Download now',
|
||||||
downloadLabel: 'Download',
|
downloadLabel: 'Download',
|
||||||
|
|||||||
@ -1,24 +1,99 @@
|
|||||||
|
let updateCheckInProgress = false;
|
||||||
|
let updateDownloadInProgress = false;
|
||||||
|
let manualUpdateCheckPending = false;
|
||||||
|
let latestUpdateVersion = '';
|
||||||
|
|
||||||
|
function notifyUpdate(message: string, type: 'info' | 'warn' = 'info'): void {
|
||||||
|
const toastFn = (window as unknown as { showAppToast?: (msg: string, kind?: 'info' | 'warn') => void }).showAppToast;
|
||||||
|
if (typeof toastFn === 'function') {
|
||||||
|
toastFn(message, type);
|
||||||
|
} else if (type === 'warn') {
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCheckButtonCheckingState(enabled: boolean): void {
|
||||||
|
const btn = byId<HTMLButtonElement>('checkUpdateBtn');
|
||||||
|
btn.disabled = enabled;
|
||||||
|
btn.textContent = enabled ? UI_TEXT.updates.checking : UI_TEXT.static.checkUpdates;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUpdateBanner(): void {
|
||||||
|
byId('updateBanner').style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDownloadPendingUi(): void {
|
||||||
|
showUpdateBanner();
|
||||||
|
const button = byId<HTMLButtonElement>('updateButton');
|
||||||
|
button.textContent = UI_TEXT.updates.downloading;
|
||||||
|
button.disabled = true;
|
||||||
|
byId('updateProgress').style.display = 'block';
|
||||||
|
const bar = byId('updateProgressBar');
|
||||||
|
bar.classList.add('downloading');
|
||||||
|
bar.style.width = '30%';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDownloadReadyUi(version: string): void {
|
||||||
|
showUpdateBanner();
|
||||||
|
updateReady = true;
|
||||||
|
updateDownloadInProgress = false;
|
||||||
|
latestUpdateVersion = version || latestUpdateVersion;
|
||||||
|
|
||||||
|
const bar = byId('updateProgressBar');
|
||||||
|
bar.classList.remove('downloading');
|
||||||
|
bar.style.width = '100%';
|
||||||
|
|
||||||
|
byId('updateText').textContent = `Version ${latestUpdateVersion || '?'} ${UI_TEXT.updates.ready}`;
|
||||||
|
const button = byId<HTMLButtonElement>('updateButton');
|
||||||
|
button.textContent = UI_TEXT.updates.installNow;
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
async function checkUpdateSilent(): Promise<void> {
|
async function checkUpdateSilent(): Promise<void> {
|
||||||
|
try {
|
||||||
await window.api.checkUpdate();
|
await window.api.checkUpdate();
|
||||||
|
} catch {
|
||||||
|
// ignore silent updater errors
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkUpdate(): Promise<void> {
|
async function checkUpdate(): Promise<void> {
|
||||||
|
manualUpdateCheckPending = true;
|
||||||
|
setCheckButtonCheckingState(true);
|
||||||
|
|
||||||
|
try {
|
||||||
const result = await window.api.checkUpdate();
|
const result = await window.api.checkUpdate();
|
||||||
|
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
|
manualUpdateCheckPending = false;
|
||||||
|
updateCheckInProgress = false;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
notifyUpdate(UI_TEXT.updates.checkFailed, 'warn');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const skippedReason = result?.skipped;
|
const skippedReason = result?.skipped;
|
||||||
if (skippedReason === 'in-progress' || skippedReason === 'ready-to-install' || skippedReason === 'throttled') {
|
if (skippedReason === 'ready-to-install') {
|
||||||
|
manualUpdateCheckPending = false;
|
||||||
|
updateCheckInProgress = false;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
notifyUpdate(UI_TEXT.updates.readyToInstall, 'info');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
if (skippedReason === 'in-progress' || skippedReason === 'throttled') {
|
||||||
if (byId('updateBanner').style.display !== 'flex') {
|
manualUpdateCheckPending = false;
|
||||||
alert(UI_TEXT.updates.latest);
|
updateCheckInProgress = false;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
notifyUpdate(UI_TEXT.updates.checkInProgress, 'info');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
manualUpdateCheckPending = false;
|
||||||
|
updateCheckInProgress = false;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
notifyUpdate(UI_TEXT.updates.checkFailed, 'warn');
|
||||||
}
|
}
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadUpdate(): void {
|
function downloadUpdate(): void {
|
||||||
@ -27,20 +102,77 @@ function downloadUpdate(): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byId('updateButton').textContent = UI_TEXT.updates.downloading;
|
if (updateDownloadInProgress) {
|
||||||
byId('updateButton').disabled = true;
|
notifyUpdate(UI_TEXT.updates.downloadInProgress, 'info');
|
||||||
byId('updateProgress').style.display = 'block';
|
return;
|
||||||
byId('updateProgressBar').classList.add('downloading');
|
|
||||||
void window.api.downloadUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateDownloadInProgress = true;
|
||||||
|
setDownloadPendingUi();
|
||||||
|
|
||||||
|
void window.api.downloadUpdate().then((result) => {
|
||||||
|
if (result?.error) {
|
||||||
|
updateDownloadInProgress = false;
|
||||||
|
const button = byId<HTMLButtonElement>('updateButton');
|
||||||
|
button.textContent = UI_TEXT.updates.downloadNow;
|
||||||
|
button.disabled = false;
|
||||||
|
byId('updateProgressBar').classList.remove('downloading');
|
||||||
|
notifyUpdate(UI_TEXT.updates.downloadFailed, 'warn');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.skipped === 'ready-to-install') {
|
||||||
|
setDownloadReadyUi(latestUpdateVersion);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.skipped === 'in-progress') {
|
||||||
|
notifyUpdate(UI_TEXT.updates.downloadInProgress, 'info');
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
updateDownloadInProgress = false;
|
||||||
|
const button = byId<HTMLButtonElement>('updateButton');
|
||||||
|
button.textContent = UI_TEXT.updates.downloadNow;
|
||||||
|
button.disabled = false;
|
||||||
|
byId('updateProgressBar').classList.remove('downloading');
|
||||||
|
notifyUpdate(UI_TEXT.updates.downloadFailed, 'warn');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.api.onUpdateChecking(() => {
|
||||||
|
updateCheckInProgress = true;
|
||||||
|
setCheckButtonCheckingState(true);
|
||||||
|
});
|
||||||
|
|
||||||
window.api.onUpdateAvailable((info: UpdateInfo) => {
|
window.api.onUpdateAvailable((info: UpdateInfo) => {
|
||||||
byId('updateBanner').style.display = 'flex';
|
updateCheckInProgress = false;
|
||||||
|
updateReady = false;
|
||||||
|
updateDownloadInProgress = true;
|
||||||
|
manualUpdateCheckPending = false;
|
||||||
|
latestUpdateVersion = info.version;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
|
||||||
|
showUpdateBanner();
|
||||||
byId('updateText').textContent = `Version ${info.version} ${UI_TEXT.updates.available}`;
|
byId('updateText').textContent = `Version ${info.version} ${UI_TEXT.updates.available}`;
|
||||||
byId('updateButton').textContent = UI_TEXT.updates.downloadNow;
|
byId('updateButton').textContent = UI_TEXT.updates.downloading;
|
||||||
|
byId<HTMLButtonElement>('updateButton').disabled = true;
|
||||||
|
byId('updateProgress').style.display = 'block';
|
||||||
|
byId('updateProgressBar').classList.add('downloading');
|
||||||
|
});
|
||||||
|
|
||||||
|
window.api.onUpdateNotAvailable(() => {
|
||||||
|
updateCheckInProgress = false;
|
||||||
|
setCheckButtonCheckingState(false);
|
||||||
|
|
||||||
|
if (manualUpdateCheckPending) {
|
||||||
|
notifyUpdate(UI_TEXT.updates.latest, 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
manualUpdateCheckPending = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
window.api.onUpdateDownloadProgress((progress: UpdateDownloadProgress) => {
|
window.api.onUpdateDownloadProgress((progress: UpdateDownloadProgress) => {
|
||||||
|
updateDownloadInProgress = true;
|
||||||
const bar = byId('updateProgressBar');
|
const bar = byId('updateProgressBar');
|
||||||
bar.classList.remove('downloading');
|
bar.classList.remove('downloading');
|
||||||
bar.style.width = progress.percent + '%';
|
bar.style.width = progress.percent + '%';
|
||||||
@ -51,13 +183,22 @@ window.api.onUpdateDownloadProgress((progress: UpdateDownloadProgress) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.api.onUpdateDownloaded((info: UpdateInfo) => {
|
window.api.onUpdateDownloaded((info: UpdateInfo) => {
|
||||||
updateReady = true;
|
setDownloadReadyUi(info.version);
|
||||||
|
});
|
||||||
const bar = byId('updateProgressBar');
|
|
||||||
bar.classList.remove('downloading');
|
window.api.onUpdateError(() => {
|
||||||
bar.style.width = '100%';
|
updateCheckInProgress = false;
|
||||||
|
const wasDownloading = updateDownloadInProgress;
|
||||||
byId('updateText').textContent = `Version ${info.version} ${UI_TEXT.updates.ready}`;
|
updateDownloadInProgress = false;
|
||||||
byId('updateButton').textContent = UI_TEXT.updates.installNow;
|
manualUpdateCheckPending = false;
|
||||||
byId('updateButton').disabled = false;
|
setCheckButtonCheckingState(false);
|
||||||
|
|
||||||
|
const button = byId<HTMLButtonElement>('updateButton');
|
||||||
|
if (!updateReady) {
|
||||||
|
button.textContent = UI_TEXT.updates.downloadNow;
|
||||||
|
button.disabled = false;
|
||||||
|
byId('updateProgressBar').classList.remove('downloading');
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyUpdate(wasDownloading ? UI_TEXT.updates.downloadFailed : UI_TEXT.updates.checkFailed, 'warn');
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user