diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c180b..169c2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.0.10 - 2026-08-12 + +- Ignore malformed updater events without a version instead of showing an unusable update prompt. +- Keep the cutter source selection out of the loaded editor layout and render each export profile indicator exactly once. + ## 1.0.9 - 2026-08-12 - Waited for managed-tool checksum streams to close before promoting verified installations, preventing intermittent Windows repair failures caused by open file handles. diff --git a/README.md b/README.md index 961ca87..c5002ee 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.9.exe`. +2. Download `Twitch-VOD-Manager-Setup-1.0.10.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 5f7f2b3..44c7618 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "1.0.9", + "version": "1.0.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "1.0.9", + "version": "1.0.10", "license": "MIT", "dependencies": { "axios": "^1.16.1", diff --git a/package.json b/package.json index 04a16f9..6b59b01 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "1.0.9", + "version": "1.0.10", "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 53327d5..7bc959b 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.9', + version: '1.0.10', }); } diff --git a/scripts/public-release-files.json b/scripts/public-release-files.json index 660e753..78a4ead 100644 --- a/scripts/public-release-files.json +++ b/scripts/public-release-files.json @@ -132,6 +132,7 @@ "src/renderer-command-palette.ts", "src/renderer-cutter.ts", "src/renderer-cutter.production-path.test.ts", + "src/cutter-workspace-styles.production-path.test.ts", "src/renderer-globals.d.ts", "src/renderer-locale-de.ts", "src/renderer-locale-en.ts", @@ -146,6 +147,7 @@ "src/renderer-streamers.ts", "src/renderer-texts.ts", "src/renderer-updates.ts", + "src/renderer-updates.production-path.test.ts", "src/renderer-vod-hover.ts", "src/renderer.ts", "src/styles.css", diff --git a/scripts/smoke-test-cutter.js b/scripts/smoke-test-cutter.js index a8026c6..7432a60 100644 --- a/scripts/smoke-test-cutter.js +++ b/scripts/smoke-test-cutter.js @@ -200,6 +200,34 @@ async function run() { await win.setViewportSize({ width: 1440, height: 900 }); await win.emulateMedia({ reducedMotion: 'reduce' }); await win.evaluate(() => window.showTab('cutter')); + await win.evaluate(() => { + document.getElementById('cutterWorkspace').classList.add('shown'); + document.getElementById('cutterExportProfile').disabled = false; + }); + await win.locator('#cutterExportProfile').waitFor({ state: 'visible' }); + const cutterExportProfileBox = await win.locator('#cutterExportProfile').boundingBox(); + if (!cutterExportProfileBox) throw new Error('Export profile is not visible'); + await win.mouse.move(cutterExportProfileBox.x + cutterExportProfileBox.width / 2, cutterExportProfileBox.y + cutterExportProfileBox.height / 2); + const cutterExportProfilePresentation = await win.evaluate(() => { + const style = getComputedStyle(document.getElementById('cutterExportProfile')); + return { + backgroundImage: style.backgroundImage, + backgroundRepeat: style.backgroundRepeat, + backgroundPosition: style.backgroundPosition, + sourceDisplay: getComputedStyle(document.querySelector('.cutter-source-bar')).display, + }; + }); + check( + cutterExportProfilePresentation.backgroundImage !== 'none' + && cutterExportProfilePresentation.backgroundRepeat === 'no-repeat' + && cutterExportProfilePresentation.backgroundPosition.includes('8px') + && cutterExportProfilePresentation.sourceDisplay === 'none', + `Export profile indicator is tiled or misplaced: ${JSON.stringify(cutterExportProfilePresentation)}` + ); + await win.evaluate(() => { + document.getElementById('cutterWorkspace').classList.remove('shown'); + document.getElementById('cutterExportProfile').disabled = true; + }); const additionalContainerCapabilities = await Promise.all(Object.entries(additionalContainerFiles).map(async ([extension, filePath]) => ({ extension, capability: await createCutterCapability(win, filePath), @@ -316,7 +344,7 @@ async function run() { `Disabled empty-player volume control still expands on hover: ${JSON.stringify({ emptyVolumeBefore, emptyVolumeAfter })}` ); if (process.env.TWITCH_VOD_MANAGER_CUTTER_EMPTY_ONLY === '1') { - console.log(JSON.stringify({ failures, runtimeIssues, emptyLayout, emptyFullscreenLayout, emptyVolumeBefore, emptyVolumeAfter }, null, 2)); + console.log(JSON.stringify({ failures, runtimeIssues, cutterExportProfilePresentation, emptyLayout, emptyFullscreenLayout, emptyVolumeBefore, emptyVolumeAfter }, null, 2)); if (failures.length > 0) process.exitCode = 1; return; } diff --git a/scripts/smoke-test-public-release-config.js b/scripts/smoke-test-public-release-config.js index fe6b6b1..a306a47 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.9', `package version is ${packageJson.version}`); -check(packageLock.version === '1.0.9', `lockfile version is ${packageLock.version}`); -check(packageLock.packages?.['']?.version === '1.0.9', `lockfile root package version is ${packageLock.packages?.['']?.version}`); +check(packageJson.version === '1.0.10', `package version is ${packageJson.version}`); +check(packageLock.version === '1.0.10', `lockfile version is ${packageLock.version}`); +check(packageLock.packages?.['']?.version === '1.0.10', `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}`); @@ -62,7 +62,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.9'), 'initial version label is not 1.0.9'); +check(indexSource.includes('Version: v1.0.10'), 'initial version label is not 1.0.10'); 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/src/cutter-workspace-styles.production-path.test.ts b/src/cutter-workspace-styles.production-path.test.ts new file mode 100644 index 0000000..6621600 --- /dev/null +++ b/src/cutter-workspace-styles.production-path.test.ts @@ -0,0 +1,19 @@ +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { describe, expect, test } from 'vitest'; + +const styles = readFileSync(join(__dirname, 'styles.css'), 'utf8'); +const workspaceStyles = readFileSync(join(__dirname, 'workspace.css'), 'utf8'); + +describe('cutter workspace style production paths', () => { + test('hides the source bar when the non-adjacent workspace is shown', () => { + expect(styles).toContain('.cutter-source-bar:has(~ .cutter-workspace.shown)'); + }); + + test('keeps the export profile indicator from tiling after workspace background styling', () => { + const selector = '#cutterTab .cutter-export-options select {'; + const start = workspaceStyles.indexOf(selector); + const end = workspaceStyles.indexOf('}', start); + expect(workspaceStyles.slice(start, end)).toMatch(/background-repeat:\s*no-repeat/); + }); +}); diff --git a/src/index.html b/src/index.html index 2d99d08..ef445c1 100644 --- a/src/index.html +++ b/src/index.html @@ -940,7 +940,7 @@
Version: v1.0.9
+Version: v1.0.10