diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd1ba6..3a22882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.16 - 2026-08-13 + +- Preserve completed System Check results when switching between German and English. +- Relocalize successful and failed diagnostics, health badges and running check controls without stale language state. +- Clear obsolete System Check results after download path, imported configuration or managed tool changes. + ## 1.0.15 - 2026-08-13 - Keep update download progress within its popover and make changelog expansion and collapse easier to follow. diff --git a/README.md b/README.md index c87af4c..b39fb17 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ The application works in public mode without a Twitch login. Connecting a Twitch ## Installation 1. Open the [latest GitHub release](https://github.com/Sucukdeluxe/Twitch-VOD-Manager/releases/latest). -2. Download `Twitch-VOD-Manager-Setup-1.0.15.exe`. +2. Download `Twitch-VOD-Manager-Setup-1.0.16.exe`. 3. Run the installer and choose the installation directory. 4. Start Twitch VOD Manager and add a streamer. diff --git a/package-lock.json b/package-lock.json index 727c3ba..186dc51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "1.0.15", + "version": "1.0.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "1.0.15", + "version": "1.0.16", "license": "MIT", "dependencies": { "axios": "^1.16.1", diff --git a/package.json b/package.json index 5583abf..1140d6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "1.0.15", + "version": "1.0.16", "description": "Twitch VOD Manager - Download Twitch VODs easily", "main": "dist/main.js", "author": "Sucukdeluxe", diff --git a/scripts/dev.mjs b/scripts/dev.mjs index 323499f..dd69700 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -93,7 +93,7 @@ if (process.platform === 'win32') { sourcePath: electronSourceExecutable, destinationPath: resolve(rootDirectory, 'node_modules', 'electron', 'dist', 'Twitch VOD Manager.exe'), iconPath: resolve(rootDirectory, 'build', 'icon.ico'), - version: '1.0.15', + version: '1.0.16', }); } diff --git a/scripts/e2e-test-environment.js b/scripts/e2e-test-environment.js index 2405025..0a3bf77 100644 --- a/scripts/e2e-test-environment.js +++ b/scripts/e2e-test-environment.js @@ -208,7 +208,7 @@ async function installOfflineFixtures(app) { ffprobe: true, downloadPathWritable: true }, - messages: ['Offline fixture'], + messages: [], timestamp: '2026-01-01T00:00:00Z' })); replaceHandler('check-update', async () => ({ checking: true, offlineFixture: true })); diff --git a/scripts/smoke-test-public-release-config.js b/scripts/smoke-test-public-release-config.js index 8c06fd7..3a7e61d 100644 --- a/scripts/smoke-test-public-release-config.js +++ b/scripts/smoke-test-public-release-config.js @@ -15,9 +15,9 @@ function check(condition, message) { if (!condition) failures.push(message); } -check(packageJson.version === '1.0.15', `package version is ${packageJson.version}`); -check(packageLock.version === '1.0.15', `lockfile version is ${packageLock.version}`); -check(packageLock.packages?.['']?.version === '1.0.15', `lockfile root package version is ${packageLock.packages?.['']?.version}`); +check(packageJson.version === '1.0.16', `package version is ${packageJson.version}`); +check(packageLock.version === '1.0.16', `lockfile version is ${packageLock.version}`); +check(packageLock.packages?.['']?.version === '1.0.16', `lockfile root package version is ${packageLock.packages?.['']?.version}`); check(packageJson.build?.appId === 'io.github.sucukdeluxe.twitch-vod-manager', `appId is ${packageJson.build?.appId}`); check(packageJson.build?.publish?.provider === 'generic', `publish provider is ${packageJson.build?.publish?.provider}`); check(packageJson.build?.publish?.url === 'https://github.com/Sucukdeluxe/Twitch-VOD-Manager/releases/latest/download/', `publish URL is ${packageJson.build?.publish?.url}`); @@ -65,7 +65,7 @@ check(mainSource.includes('GITHUB_RELEASES_DOWNLOAD_BASE_URL'), 'GitHub releases check(mainSource.includes('https://api.github.com/repos/Sucukdeluxe/Twitch-VOD-Manager/releases/latest'), 'GitHub latest release API URL is missing'); check(mainSource.includes('https://github.com/Sucukdeluxe/Twitch-VOD-Manager/releases/download'), 'GitHub release download URL is missing'); check(!/storyboards\/\d{8,12}(?:-|\/)/.test(mainSource), 'numeric Twitch VOD example remains in the public source'); -check(indexSource.includes('Version: v1.0.15'), 'initial version label is not 1.0.15'); +check(indexSource.includes('Version: v1.0.16'), 'initial version label is not 1.0.16'); check(!indexSource.includes('Version: v4.1.13'), 'legacy version label is still present'); check(fs.existsSync(manifestPath), 'public release manifest is missing'); diff --git a/scripts/smoke-test-workspace-ui.js b/scripts/smoke-test-workspace-ui.js index 7d7f77d..a529019 100644 --- a/scripts/smoke-test-workspace-ui.js +++ b/scripts/smoke-test-workspace-ui.js @@ -96,6 +96,139 @@ async function run() { check(shell.topNavigationItems === 7, `Expected 7 native primary navigation buttons, found ${shell.topNavigationItems}`); check(shell.nonButtonNavigationItems === 0, `Expected only native primary navigation buttons, found ${shell.nonButtonNavigationItems} non-buttons`); + const preflightLocaleRetention = await win.evaluate(async () => { + await window.runPreflight(false); + window.changeLanguage('de'); + const german = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeGood: document.getElementById('healthBadge')?.classList.contains('good') || false + }; + window.changeLanguage('en'); + const english = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeGood: document.getElementById('healthBadge')?.classList.contains('good') || false + }; + return { german, english }; + }); + checks.preflightLocaleRetention = preflightLocaleRetention; + check(preflightLocaleRetention.german.result.includes('OK Download-Pfad') && preflightLocaleRetention.german.result.includes('Alles bereit.'), `German language switch lost the completed system check: ${preflightLocaleRetention.german.result}`); + check(preflightLocaleRetention.english.result.includes('OK Download path') && preflightLocaleRetention.english.result.includes('Everything is ready.'), `English language switch lost the completed system check: ${preflightLocaleRetention.english.result}`); + check(preflightLocaleRetention.german.badgeGood && preflightLocaleRetention.german.badge === 'System: Stabil', `German language switch lost the healthy system badge: ${JSON.stringify(preflightLocaleRetention.german)}`); + check(preflightLocaleRetention.english.badgeGood && preflightLocaleRetention.english.badge === 'System: Stable', `English language switch lost the healthy system badge: ${JSON.stringify(preflightLocaleRetention.english)}`); + + await app.evaluate(({ ipcMain }) => { + ipcMain.removeHandler('run-preflight'); + ipcMain.handle('run-preflight', async () => ({ + ok: false, + autoFixApplied: false, + checks: { + internet: false, + streamlink: true, + ffmpeg: false, + ffprobe: true, + downloadPathWritable: true + }, + messages: [ + 'No internet connection detected.', + 'FFmpeg is missing or not runnable.' + ], + timestamp: '2026-01-01T00:00:00Z' + })); + }); + const failedPreflightLocaleRetention = await win.evaluate(async () => { + window.changeLanguage('en'); + await window.runPreflight(false); + window.changeLanguage('de'); + const german = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeWarn: document.getElementById('healthBadge')?.classList.contains('warn') || false + }; + window.changeLanguage('en'); + const english = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeWarn: document.getElementById('healthBadge')?.classList.contains('warn') || false + }; + return { german, english }; + }); + checks.failedPreflightLocaleRetention = failedPreflightLocaleRetention; + check(failedPreflightLocaleRetention.german.result.includes('Keine Internetverbindung erkannt.') && failedPreflightLocaleRetention.german.result.includes('FFmpeg fehlt oder ist nicht startbar.'), `German language switch did not relocalize failed system checks: ${failedPreflightLocaleRetention.german.result}`); + check(!failedPreflightLocaleRetention.german.result.includes('No internet connection detected.'), `German failed system check kept English diagnostics: ${failedPreflightLocaleRetention.german.result}`); + check(failedPreflightLocaleRetention.english.result.includes('No internet connection detected.') && failedPreflightLocaleRetention.english.result.includes('FFmpeg is missing or not runnable.'), `English language switch did not relocalize failed system checks: ${failedPreflightLocaleRetention.english.result}`); + check(failedPreflightLocaleRetention.german.badgeWarn && failedPreflightLocaleRetention.german.badge === 'System: Warnung', `German failed system badge was not retained: ${JSON.stringify(failedPreflightLocaleRetention.german)}`); + check(failedPreflightLocaleRetention.english.badgeWarn && failedPreflightLocaleRetention.english.badge === 'System: Warning', `English failed system badge was not retained: ${JSON.stringify(failedPreflightLocaleRetention.english)}`); + + await app.evaluate(({ ipcMain }) => { + ipcMain.removeHandler('run-preflight'); + ipcMain.handle('run-preflight', () => new Promise((resolve) => { + globalThis.__workspacePreflightLocaleResolve = () => resolve({ + ok: true, + autoFixApplied: false, + checks: { + internet: true, + streamlink: true, + ffmpeg: true, + ffprobe: true, + downloadPathWritable: true + }, + messages: [], + timestamp: '2026-01-01T00:00:00Z' + }); + })); + }); + await win.evaluate(() => { + window.changeLanguage('en'); + globalThis.__workspacePreflightLocalePending = window.runPreflight(false); + }); + await app.evaluate(async () => { + const deadline = Date.now() + 5000; + while (typeof globalThis.__workspacePreflightLocaleResolve !== 'function') { + if (Date.now() >= deadline) throw new Error('Timed out waiting for the gated system check'); + await new Promise((resolve) => setTimeout(resolve, 1)); + } + }); + const duringPreflightLocale = await win.evaluate(() => { + window.changeLanguage('de'); + return document.getElementById('btnPreflightRun')?.textContent || ''; + }); + const changedDownloadPath = path.join(environment.downloadsDir, 'preflight-path-change'); + fs.mkdirSync(changedDownloadPath, { recursive: true }); + await app.evaluate(({ dialog }, folderPath) => { + dialog.showOpenDialog = async () => ({ canceled: false, filePaths: [folderPath] }); + }, changedDownloadPath); + await win.evaluate(() => window.selectFolder()); + await app.evaluate(() => globalThis.__workspacePreflightLocaleResolve()); + const afterPreflightLocale = await win.evaluate(async () => { + await globalThis.__workspacePreflightLocalePending; + return document.getElementById('btnPreflightRun')?.textContent || ''; + }); + const preflightInFlightLocale = { during: duringPreflightLocale, after: afterPreflightLocale }; + checks.preflightInFlightLocale = preflightInFlightLocale; + check(preflightInFlightLocale.during === 'Prüfe...', `Running system check did not adopt the German language: ${preflightInFlightLocale.during}`); + check(preflightInFlightLocale.after === 'Check ausführen', `Completed system check restored an outdated button label: ${preflightInFlightLocale.after}`); + + const preflightAfterPathChange = await win.evaluate(() => { + window.changeLanguage('en'); + const english = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeUnknown: document.getElementById('healthBadge')?.classList.contains('unknown') || false + }; + window.changeLanguage('de'); + const german = { + result: document.getElementById('preflightResult')?.textContent || '', + badge: document.getElementById('healthBadge')?.textContent || '', + badgeUnknown: document.getElementById('healthBadge')?.classList.contains('unknown') || false + }; + return { english, german }; + }); + checks.preflightAfterPathChange = preflightAfterPathChange; + check(preflightAfterPathChange.english.result === 'No checks run yet.' && preflightAfterPathChange.english.badgeUnknown && preflightAfterPathChange.english.badge === 'System: Unknown', `Download path change kept a stale English system check: ${JSON.stringify(preflightAfterPathChange.english)}`); + check(preflightAfterPathChange.german.result === 'Noch kein Check ausgeführt.' && preflightAfterPathChange.german.badgeUnknown && preflightAfterPathChange.german.badge === 'System: Unbekannt', `Download path change restored a stale German system check: ${JSON.stringify(preflightAfterPathChange.german)}`); + const mergeAddToolbarActions = await win.evaluate(() => { const capture = () => { const button = document.querySelector('[data-toolbar-for="merge"] button[onclick="addMergeFiles()"]'); diff --git a/src/index.html b/src/index.html index 545d1a0..869593a 100644 --- a/src/index.html +++ b/src/index.html @@ -942,7 +942,7 @@
Version: v1.0.15
+Version: v1.0.16
Noch kein Check ausgefuhrt.+
Noch kein Check ausgeführt.