Optimize debug log I/O and settings auto-refresh polling (v4.1.11)

This commit is contained in:
xRangerDE 2026-02-21 00:47:20 +01:00
parent 9392398db7
commit 8d656772fc
5 changed files with 105 additions and 10 deletions

View File

@ -1,12 +1,12 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.1.10", "version": "4.1.11",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.1.10", "version": "4.1.11",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"axios": "^1.6.0", "axios": "^1.6.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.1.10", "version": "4.1.11",
"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",

View File

@ -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.10</p> <p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.11</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.10</span> <span id="versionText">v4.1.11</span>
</div> </div>
</main> </main>
</div> </div>

View File

@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
// ========================================== // ==========================================
// CONFIG & CONSTANTS // CONFIG & CONSTANTS
// ========================================== // ==========================================
const APP_VERSION = '4.1.10'; const APP_VERSION = '4.1.11';
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 DEBUG_LOG_READ_TAIL_BYTES = 512 * 1024;
const DEBUG_LOG_MAX_BYTES = 8 * 1024 * 1024;
const DEBUG_LOG_TRIM_TO_BYTES = 4 * 1024 * 1024;
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;
@ -533,11 +536,78 @@ function flushPendingDebugLogLines(): void {
const payload = pendingDebugLogLines.join(''); const payload = pendingDebugLogLines.join('');
pendingDebugLogLines = []; pendingDebugLogLines = [];
fs.appendFileSync(DEBUG_LOG_FILE, payload); fs.appendFileSync(DEBUG_LOG_FILE, payload);
trimDebugLogFileIfNeeded();
} catch { } catch {
// ignore debug log errors // ignore debug log errors
} }
} }
function trimDebugLogFileIfNeeded(): void {
try {
if (!fs.existsSync(DEBUG_LOG_FILE)) {
return;
}
const stats = fs.statSync(DEBUG_LOG_FILE);
if (stats.size <= DEBUG_LOG_MAX_BYTES) {
return;
}
const bytesToKeep = Math.min(DEBUG_LOG_TRIM_TO_BYTES, stats.size);
const startOffset = Math.max(0, stats.size - bytesToKeep);
const buffer = Buffer.allocUnsafe(bytesToKeep);
let fileHandle: number | null = null;
try {
fileHandle = fs.openSync(DEBUG_LOG_FILE, 'r');
fs.readSync(fileHandle, buffer, 0, bytesToKeep, startOffset);
} finally {
if (fileHandle !== null) {
fs.closeSync(fileHandle);
}
}
const firstLineBreak = buffer.indexOf(0x0a);
const trimmed = firstLineBreak >= 0 && firstLineBreak + 1 < buffer.length
? buffer.subarray(firstLineBreak + 1)
: buffer;
fs.writeFileSync(DEBUG_LOG_FILE, trimmed);
} catch {
// ignore debug log errors
}
}
function readDebugLogTailFromDisk(): string {
const stats = fs.statSync(DEBUG_LOG_FILE);
if (stats.size <= 0) {
return '';
}
const bytesToRead = Math.min(stats.size, DEBUG_LOG_READ_TAIL_BYTES);
if (bytesToRead === stats.size) {
return fs.readFileSync(DEBUG_LOG_FILE, 'utf-8');
}
const buffer = Buffer.allocUnsafe(bytesToRead);
let fileHandle: number | null = null;
try {
fileHandle = fs.openSync(DEBUG_LOG_FILE, 'r');
fs.readSync(fileHandle, buffer, 0, bytesToRead, stats.size - bytesToRead);
} finally {
if (fileHandle !== null) {
fs.closeSync(fileHandle);
}
}
const firstLineBreak = buffer.indexOf(0x0a);
const slice = firstLineBreak >= 0 && firstLineBreak + 1 < buffer.length
? buffer.subarray(firstLineBreak + 1)
: buffer;
return slice.toString('utf-8');
}
function startDebugLogFlushTimer(): void { function startDebugLogFlushTimer(): void {
if (debugLogFlushTimer) { if (debugLogFlushTimer) {
return; return;
@ -569,7 +639,7 @@ function readDebugLog(lines = 200): string {
return 'Debug-Log ist leer.'; return 'Debug-Log ist leer.';
} }
const text = fs.readFileSync(DEBUG_LOG_FILE, 'utf-8'); const text = readDebugLogTailFromDisk();
const rows = text.split(/\r?\n/).filter(Boolean); const rows = text.split(/\r?\n/).filter(Boolean);
return rows.slice(-lines).join('\n') || 'Debug-Log ist leer.'; return rows.slice(-lines).join('\n') || 'Debug-Log ist leer.';
} catch (e) { } catch (e) {

View File

@ -1,4 +1,13 @@
let lastRuntimeMetricsOutput = ''; let lastRuntimeMetricsOutput = '';
let lastDebugLogOutput = '';
function canRunSettingsAutoRefresh(): boolean {
if (document.hidden) {
return false;
}
return document.querySelector('.tab-content.active')?.id === 'settingsTab';
}
async function connect(): Promise<void> { async function connect(): Promise<void> {
const hasCredentials = Boolean((config.client_id ?? '').toString().trim() && (config.client_secret ?? '').toString().trim()); const hasCredentials = Boolean((config.client_id ?? '').toString().trim() && (config.client_secret ?? '').toString().trim());
@ -142,6 +151,10 @@ function toggleRuntimeMetricsAutoRefresh(enabled: boolean): void {
if (enabled) { if (enabled) {
runtimeMetricsAutoRefreshTimer = window.setInterval(() => { runtimeMetricsAutoRefreshTimer = window.setInterval(() => {
if (!canRunSettingsAutoRefresh()) {
return;
}
void refreshRuntimeMetrics(false); void refreshRuntimeMetrics(false);
}, 2000); }, 2000);
} }
@ -245,9 +258,17 @@ async function runPreflight(autoFix = false): Promise<void> {
async function refreshDebugLog(): Promise<void> { async function refreshDebugLog(): Promise<void> {
const text = await window.api.getDebugLog(250); const text = await window.api.getDebugLog(250);
const panel = byId('debugLogOutput'); const panel = byId('debugLogOutput');
const keepAtBottom = (panel.scrollHeight - panel.scrollTop - panel.clientHeight) < 20;
if (text !== lastDebugLogOutput) {
panel.textContent = text; panel.textContent = text;
lastDebugLogOutput = text;
}
if (keepAtBottom) {
panel.scrollTop = panel.scrollHeight; panel.scrollTop = panel.scrollHeight;
} }
}
function toggleDebugAutoRefresh(enabled: boolean): void { function toggleDebugAutoRefresh(enabled: boolean): void {
if (debugLogAutoRefreshTimer) { if (debugLogAutoRefreshTimer) {
@ -257,8 +278,12 @@ function toggleDebugAutoRefresh(enabled: boolean): void {
if (enabled) { if (enabled) {
debugLogAutoRefreshTimer = window.setInterval(() => { debugLogAutoRefreshTimer = window.setInterval(() => {
if (!canRunSettingsAutoRefresh()) {
return;
}
void refreshDebugLog(); void refreshDebugLog();
}, 1500); }, 2000);
} }
} }