Harden queue lifecycle and auth/update check concurrency (v4.1.8)
This commit is contained in:
parent
8b508177b5
commit
4ade0a46ac
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.7",
|
"version": "4.1.8",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.7",
|
"version": "4.1.8",
|
||||||
"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.7",
|
"version": "4.1.8",
|
||||||
"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.7</p>
|
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.8</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.7</span>
|
<span id="versionText">v4.1.8</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.7';
|
const APP_VERSION = '4.1.8';
|
||||||
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
@ -396,6 +396,7 @@ let autoUpdateStartupTimer: NodeJS.Timeout | null = null;
|
|||||||
let autoUpdateCheckInProgress = false;
|
let autoUpdateCheckInProgress = false;
|
||||||
let autoUpdateReadyToInstall = false;
|
let autoUpdateReadyToInstall = false;
|
||||||
let lastAutoUpdateCheckAt = 0;
|
let lastAutoUpdateCheckAt = 0;
|
||||||
|
let twitchLoginInFlight: Promise<boolean> | null = null;
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// TOOL PATHS
|
// TOOL PATHS
|
||||||
@ -1447,6 +1448,10 @@ function emitQueueUpdated(force = false): void {
|
|||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasQueueItemId(id: string): boolean {
|
||||||
|
return downloadQueue.some((item) => item.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
function getRuntimeMetricsSnapshot(): RuntimeMetricsSnapshot {
|
function getRuntimeMetricsSnapshot(): RuntimeMetricsSnapshot {
|
||||||
return {
|
return {
|
||||||
...runtimeMetrics,
|
...runtimeMetrics,
|
||||||
@ -1644,6 +1649,22 @@ async function twitchLogin(): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestTwitchLogin(): Promise<boolean> {
|
||||||
|
if (twitchLoginInFlight) {
|
||||||
|
return twitchLoginInFlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let loginPromise: Promise<boolean>;
|
||||||
|
loginPromise = twitchLogin().finally(() => {
|
||||||
|
if (twitchLoginInFlight === loginPromise) {
|
||||||
|
twitchLoginInFlight = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
twitchLoginInFlight = loginPromise;
|
||||||
|
return loginPromise;
|
||||||
|
}
|
||||||
|
|
||||||
async function ensureTwitchAuth(forceRefresh = false): Promise<boolean> {
|
async function ensureTwitchAuth(forceRefresh = false): Promise<boolean> {
|
||||||
if (!config.client_id || !config.client_secret) {
|
if (!config.client_id || !config.client_secret) {
|
||||||
accessToken = null;
|
accessToken = null;
|
||||||
@ -1654,7 +1675,7 @@ async function ensureTwitchAuth(forceRefresh = false): Promise<boolean> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await twitchLogin();
|
return await requestTwitchLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeLogin(input: string): string {
|
function normalizeLogin(input: string): string {
|
||||||
@ -2749,6 +2770,14 @@ async function processQueue(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasQueueItemId(item.id)) {
|
||||||
|
appendDebugLog('queue-item-finished-removed', { itemId: item.id });
|
||||||
|
runtimeMetrics.activeItemId = null;
|
||||||
|
runtimeMetrics.activeItemTitle = null;
|
||||||
|
activeQueueItemId = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const wasPaused = pauseRequested || (finalResult.error || '').includes('pausiert');
|
const wasPaused = pauseRequested || (finalResult.error || '').includes('pausiert');
|
||||||
item.status = finalResult.success ? 'completed' : (wasPaused ? 'paused' : 'error');
|
item.status = finalResult.success ? 'completed' : (wasPaused ? 'paused' : 'error');
|
||||||
item.progress = finalResult.success ? 100 : item.progress;
|
item.progress = finalResult.success ? 100 : item.progress;
|
||||||
@ -2813,6 +2842,13 @@ function createWindow(): void {
|
|||||||
|
|
||||||
mainWindow.loadFile(path.join(__dirname, '../src/index.html'));
|
mainWindow.loadFile(path.join(__dirname, '../src/index.html'));
|
||||||
|
|
||||||
|
mainWindow.webContents.on('did-finish-load', () => {
|
||||||
|
emitQueueUpdated(true);
|
||||||
|
if (isDownloading) {
|
||||||
|
mainWindow?.webContents.send('download-started');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mainWindow.on('closed', () => {
|
mainWindow.on('closed', () => {
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
@ -2961,6 +2997,7 @@ ipcMain.handle('save-config', (_, newConfig: Partial<Config>) => {
|
|||||||
|
|
||||||
if (config.client_id !== previousClientId || config.client_secret !== previousClientSecret) {
|
if (config.client_id !== previousClientId || config.client_secret !== previousClientSecret) {
|
||||||
accessToken = null;
|
accessToken = null;
|
||||||
|
twitchLoginInFlight = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.metadata_cache_minutes !== previousCacheMinutes) {
|
if (config.metadata_cache_minutes !== previousCacheMinutes) {
|
||||||
@ -3021,6 +3058,9 @@ ipcMain.handle('remove-from-queue', (_, id: string) => {
|
|||||||
if (currentProcess) {
|
if (currentProcess) {
|
||||||
currentProcess.kill();
|
currentProcess.kill();
|
||||||
}
|
}
|
||||||
|
activeQueueItemId = null;
|
||||||
|
runtimeMetrics.activeItemId = null;
|
||||||
|
runtimeMetrics.activeItemTitle = null;
|
||||||
appendDebugLog('queue-item-removed-active-cancelled', { id });
|
appendDebugLog('queue-item-removed-active-cancelled', { id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
typescript-version/src/renderer-globals.d.ts
vendored
2
typescript-version/src/renderer-globals.d.ts
vendored
@ -178,7 +178,7 @@ interface ApiBridge {
|
|||||||
cutVideo(inputFile: string, startTime: number, endTime: number): Promise<{ success: boolean; outputFile: string | null }>;
|
cutVideo(inputFile: string, startTime: number, endTime: number): Promise<{ success: boolean; outputFile: string | null }>;
|
||||||
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 }>;
|
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 }>;
|
||||||
installUpdate(): Promise<void>;
|
installUpdate(): Promise<void>;
|
||||||
openExternal(url: string): Promise<void>;
|
openExternal(url: string): Promise<void>;
|
||||||
|
|||||||
@ -3,7 +3,16 @@ async function checkUpdateSilent(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function checkUpdate(): Promise<void> {
|
async function checkUpdate(): Promise<void> {
|
||||||
await window.api.checkUpdate();
|
const result = await window.api.checkUpdate();
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const skippedReason = result?.skipped;
|
||||||
|
if (skippedReason === 'in-progress' || skippedReason === 'ready-to-install' || skippedReason === 'throttled') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (byId('updateBanner').style.display !== 'flex') {
|
if (byId('updateBanner').style.display !== 'flex') {
|
||||||
|
|||||||
@ -10,6 +10,8 @@ async function init(): Promise<void> {
|
|||||||
config.language = language;
|
config.language = language;
|
||||||
const initialQueue = await window.api.getQueue();
|
const initialQueue = await window.api.getQueue();
|
||||||
queue = Array.isArray(initialQueue) ? initialQueue : [];
|
queue = Array.isArray(initialQueue) ? initialQueue : [];
|
||||||
|
downloading = await window.api.isDownloading();
|
||||||
|
markQueueActivity();
|
||||||
const version = await window.api.getVersion();
|
const version = await window.api.getVersion();
|
||||||
|
|
||||||
byId('versionText').textContent = `v${version}`;
|
byId('versionText').textContent = `v${version}`;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user