release: 4.2.4 improve updater and queue persistence
This commit is contained in:
parent
b7cd8fbec2
commit
47df9664a4
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.2.3",
|
||||
"version": "4.2.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.2.3",
|
||||
"version": "4.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.2.3",
|
||||
"version": "4.2.4",
|
||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||
"main": "dist/main.js",
|
||||
"author": "xRangerDE",
|
||||
|
||||
@ -450,6 +450,10 @@
|
||||
<input type="checkbox" id="duplicatePreventionToggle" checked>
|
||||
<span id="duplicatePreventionLabel">Duplikate in Queue verhindern</span>
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:8px; margin-top: 8px;">
|
||||
<input type="checkbox" id="persistQueueToggle" checked>
|
||||
<span id="persistQueueLabel">Queue zwischen App-Starts speichern</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="metadataCacheMinutesLabel">Metadata-Cache (Minuten)</label>
|
||||
|
||||
48
src/main.ts
48
src/main.ts
@ -83,6 +83,7 @@ interface Config {
|
||||
smart_queue_scheduler: boolean;
|
||||
performance_mode: PerformanceMode;
|
||||
prevent_duplicate_downloads: boolean;
|
||||
persist_queue_on_restart: boolean;
|
||||
metadata_cache_minutes: number;
|
||||
}
|
||||
|
||||
@ -238,6 +239,7 @@ const defaultConfig: Config = {
|
||||
smart_queue_scheduler: true,
|
||||
performance_mode: DEFAULT_PERFORMANCE_MODE,
|
||||
prevent_duplicate_downloads: true,
|
||||
persist_queue_on_restart: true,
|
||||
metadata_cache_minutes: DEFAULT_METADATA_CACHE_MINUTES
|
||||
};
|
||||
|
||||
@ -272,6 +274,7 @@ function normalizeConfigTemplates(input: Config): Config {
|
||||
smart_queue_scheduler: input.smart_queue_scheduler !== false,
|
||||
performance_mode: normalizePerformanceMode(input.performance_mode),
|
||||
prevent_duplicate_downloads: input.prevent_duplicate_downloads !== false,
|
||||
persist_queue_on_restart: input.persist_queue_on_restart !== false,
|
||||
metadata_cache_minutes: normalizeMetadataCacheMinutes(input.metadata_cache_minutes)
|
||||
};
|
||||
}
|
||||
@ -300,6 +303,10 @@ function saveConfig(config: Config): void {
|
||||
// QUEUE MANAGEMENT
|
||||
// ==========================================
|
||||
function loadQueue(): QueueItem[] {
|
||||
if (config.persist_queue_on_restart === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
if (fs.existsSync(QUEUE_FILE)) {
|
||||
const data = fs.readFileSync(QUEUE_FILE, 'utf-8');
|
||||
@ -314,7 +321,22 @@ function loadQueue(): QueueItem[] {
|
||||
let queueSaveTimer: NodeJS.Timeout | null = null;
|
||||
let pendingQueueSnapshot: QueueItem[] | null = null;
|
||||
|
||||
function clearQueueFileFromDisk(): void {
|
||||
try {
|
||||
if (fs.existsSync(QUEUE_FILE)) {
|
||||
fs.unlinkSync(QUEUE_FILE);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error clearing queue file:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function writeQueueToDisk(queue: QueueItem[]): void {
|
||||
if (config.persist_queue_on_restart === false) {
|
||||
clearQueueFileFromDisk();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fs.writeFileSync(QUEUE_FILE, JSON.stringify(queue, null, 2));
|
||||
} catch (e) {
|
||||
@ -323,6 +345,16 @@ function writeQueueToDisk(queue: QueueItem[]): void {
|
||||
}
|
||||
|
||||
function saveQueue(queue: QueueItem[], force = false): void {
|
||||
if (config.persist_queue_on_restart === false) {
|
||||
pendingQueueSnapshot = null;
|
||||
if (queueSaveTimer) {
|
||||
clearTimeout(queueSaveTimer);
|
||||
queueSaveTimer = null;
|
||||
}
|
||||
clearQueueFileFromDisk();
|
||||
return;
|
||||
}
|
||||
|
||||
pendingQueueSnapshot = queue;
|
||||
|
||||
if (force) {
|
||||
@ -3207,6 +3239,7 @@ function setupAutoUpdater() {
|
||||
autoUpdaterInitialized = true;
|
||||
autoUpdater.autoDownload = false;
|
||||
autoUpdater.autoInstallOnAppQuit = true;
|
||||
autoUpdater.autoRunAppAfterInstall = true;
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
console.log('Checking for updates...');
|
||||
@ -3308,6 +3341,7 @@ ipcMain.handle('save-config', (_, newConfig: Partial<Config>) => {
|
||||
const previousClientId = config.client_id;
|
||||
const previousClientSecret = config.client_secret;
|
||||
const previousCacheMinutes = config.metadata_cache_minutes;
|
||||
const previousPersistQueueOnRestart = config.persist_queue_on_restart;
|
||||
|
||||
config = normalizeConfigTemplates({ ...config, ...newConfig });
|
||||
|
||||
@ -3321,6 +3355,18 @@ ipcMain.handle('save-config', (_, newConfig: Partial<Config>) => {
|
||||
}
|
||||
|
||||
saveConfig(config);
|
||||
|
||||
if (config.persist_queue_on_restart === false) {
|
||||
pendingQueueSnapshot = null;
|
||||
if (queueSaveTimer) {
|
||||
clearTimeout(queueSaveTimer);
|
||||
queueSaveTimer = null;
|
||||
}
|
||||
clearQueueFileFromDisk();
|
||||
} else if (previousPersistQueueOnRestart === false) {
|
||||
saveQueue(downloadQueue, true);
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
@ -3526,7 +3572,7 @@ ipcMain.handle('download-update', async () => {
|
||||
});
|
||||
|
||||
ipcMain.handle('install-update', () => {
|
||||
autoUpdater.quitAndInstall(false, true);
|
||||
autoUpdater.quitAndInstall(true, true);
|
||||
});
|
||||
|
||||
ipcMain.handle('open-external', async (_, url: string) => {
|
||||
|
||||
1
src/renderer-globals.d.ts
vendored
1
src/renderer-globals.d.ts
vendored
@ -13,6 +13,7 @@ interface AppConfig {
|
||||
smart_queue_scheduler?: boolean;
|
||||
performance_mode?: 'stability' | 'balanced' | 'speed';
|
||||
prevent_duplicate_downloads?: boolean;
|
||||
persist_queue_on_restart?: boolean;
|
||||
metadata_cache_minutes?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ const UI_TEXT_DE = {
|
||||
performanceModeSpeed: 'Max Geschwindigkeit',
|
||||
smartSchedulerLabel: 'Smart Queue Scheduler aktivieren',
|
||||
duplicatePreventionLabel: 'Duplikate in Queue verhindern',
|
||||
persistQueueLabel: 'Queue zwischen App-Starts speichern',
|
||||
metadataCacheMinutesLabel: 'Metadata-Cache (Minuten)',
|
||||
filenameTemplatesTitle: 'Dateinamen-Templates',
|
||||
vodTemplateLabel: 'VOD-Template',
|
||||
@ -208,11 +209,11 @@ const UI_TEXT_DE = {
|
||||
downloadNow: 'Jetzt herunterladen',
|
||||
downloadLabel: 'Download',
|
||||
ready: 'bereit zur Installation!',
|
||||
installNow: 'Jetzt installieren',
|
||||
installNow: 'Jetzt installieren & neu starten',
|
||||
modalAvailableTitle: 'Update verfugbar',
|
||||
modalAvailableMessage: 'Version {version} ist verfugbar. Jetzt herunterladen?',
|
||||
modalReadyTitle: 'Update bereit',
|
||||
modalReadyMessage: 'Version {version} wurde heruntergeladen. Jetzt installieren?',
|
||||
modalReadyMessage: 'Version {version} wurde heruntergeladen. Jetzt installieren und neu starten?',
|
||||
modalDismiss: 'Nein',
|
||||
modalDownloadConfirm: 'Ja, herunterladen',
|
||||
modalInstallConfirm: 'Ja, installieren',
|
||||
|
||||
@ -46,6 +46,7 @@ const UI_TEXT_EN = {
|
||||
performanceModeSpeed: 'Max Speed',
|
||||
smartSchedulerLabel: 'Enable smart queue scheduler',
|
||||
duplicatePreventionLabel: 'Prevent duplicate queue entries',
|
||||
persistQueueLabel: 'Keep queue between app restarts',
|
||||
metadataCacheMinutesLabel: 'Metadata Cache (Minutes)',
|
||||
filenameTemplatesTitle: 'Filename Templates',
|
||||
vodTemplateLabel: 'VOD Template',
|
||||
@ -208,11 +209,11 @@ const UI_TEXT_EN = {
|
||||
downloadNow: 'Download now',
|
||||
downloadLabel: 'Download',
|
||||
ready: 'ready to install!',
|
||||
installNow: 'Install now',
|
||||
installNow: 'Install now & restart',
|
||||
modalAvailableTitle: 'Update available',
|
||||
modalAvailableMessage: 'Version {version} is available. Download it now?',
|
||||
modalReadyTitle: 'Update ready',
|
||||
modalReadyMessage: 'Version {version} has been downloaded. Install it now?',
|
||||
modalReadyMessage: 'Version {version} has been downloaded. Install and restart now?',
|
||||
modalDismiss: 'No',
|
||||
modalDownloadConfirm: 'Yes, download',
|
||||
modalInstallConfirm: 'Yes, install',
|
||||
|
||||
@ -318,6 +318,7 @@ function collectDownloadSettingsPayload(): Partial<AppConfig> {
|
||||
performance_mode: byId<HTMLSelectElement>('performanceMode').value as 'stability' | 'balanced' | 'speed',
|
||||
smart_queue_scheduler: byId<HTMLInputElement>('smartSchedulerToggle').checked,
|
||||
prevent_duplicate_downloads: byId<HTMLInputElement>('duplicatePreventionToggle').checked,
|
||||
persist_queue_on_restart: byId<HTMLInputElement>('persistQueueToggle').checked,
|
||||
metadata_cache_minutes: parseInt(byId<HTMLInputElement>('metadataCacheMinutes').value, 10) || 10
|
||||
};
|
||||
}
|
||||
@ -358,6 +359,7 @@ function getSettingsFingerprint(payload: Partial<AppConfig>): string {
|
||||
effective.performance_mode ?? 'balanced',
|
||||
effective.smart_queue_scheduler !== false,
|
||||
effective.prevent_duplicate_downloads !== false,
|
||||
effective.persist_queue_on_restart !== false,
|
||||
effective.metadata_cache_minutes ?? 10,
|
||||
effective.filename_template_vod ?? '{title}.mp4',
|
||||
effective.filename_template_parts ?? '{date}_Part{part_padded}.mp4',
|
||||
@ -373,6 +375,7 @@ function syncSettingsFormFromConfig(): void {
|
||||
byId<HTMLSelectElement>('performanceMode').value = (config.performance_mode as string) || 'balanced';
|
||||
byId<HTMLInputElement>('smartSchedulerToggle').checked = (config.smart_queue_scheduler as boolean) !== false;
|
||||
byId<HTMLInputElement>('duplicatePreventionToggle').checked = (config.prevent_duplicate_downloads as boolean) !== false;
|
||||
byId<HTMLInputElement>('persistQueueToggle').checked = (config.persist_queue_on_restart as boolean) !== false;
|
||||
byId<HTMLInputElement>('metadataCacheMinutes').value = String((config.metadata_cache_minutes as number) || 10);
|
||||
byId<HTMLInputElement>('vodFilenameTemplate').value = (config.filename_template_vod as string) || '{title}.mp4';
|
||||
byId<HTMLInputElement>('partsFilenameTemplate').value = (config.filename_template_parts as string) || '{date}_Part{part_padded}.mp4';
|
||||
@ -481,7 +484,8 @@ function initSettingsAutoSave(): void {
|
||||
'downloadMode',
|
||||
'performanceMode',
|
||||
'smartSchedulerToggle',
|
||||
'duplicatePreventionToggle'
|
||||
'duplicatePreventionToggle',
|
||||
'persistQueueToggle'
|
||||
] as const;
|
||||
|
||||
const debouncedSaveIds = [
|
||||
|
||||
@ -88,6 +88,7 @@ function applyLanguageToStaticUI(): void {
|
||||
setText('performanceModeSpeed', UI_TEXT.static.performanceModeSpeed);
|
||||
setText('smartSchedulerLabel', UI_TEXT.static.smartSchedulerLabel);
|
||||
setText('duplicatePreventionLabel', UI_TEXT.static.duplicatePreventionLabel);
|
||||
setText('persistQueueLabel', UI_TEXT.static.persistQueueLabel);
|
||||
setText('metadataCacheMinutesLabel', UI_TEXT.static.metadataCacheMinutesLabel);
|
||||
setText('filenameTemplatesTitle', UI_TEXT.static.filenameTemplatesTitle);
|
||||
setText('vodTemplateLabel', UI_TEXT.static.vodTemplateLabel);
|
||||
|
||||
@ -366,8 +366,10 @@ function refreshUpdateUiTexts(): void {
|
||||
|
||||
async function checkUpdateSilent(): Promise<void> {
|
||||
try {
|
||||
shouldOpenUpdateModalOnAvailable = true;
|
||||
await window.api.checkUpdate();
|
||||
} catch {
|
||||
shouldOpenUpdateModalOnAvailable = false;
|
||||
// ignore silent updater errors
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user