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