release: 5.0.2 — VOD hover follow-ups

Fix 1: scaleX und scaleY werden jetzt unabhaengig berechnet. Twitch
Storyboard-Cells haben nicht zwingend 16:9; eine einheitliche scale-Variable
fuehrte zu Subpixel-Leakage am oberen oder unteren Rand mit Inhalt aus der
Nachbarzelle. Mit getrennter Achsen-Skalierung fuellt eine Cell die Overlay-
Box exakt.

Fix 2: Bulk-Select-Checkbox und Downloaded-Badge werden waehrend des Hover-
Previews ausgeblendet (vorher nur die Duration-Badge). Mein vorheriger Move
des Overlays in .vod-thumb-wrap hatte die Z-Order so geaendert, dass diese
Elemente jetzt sichtbar drueber lagen.

219 unit tests + e2e gruen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-05-13 14:40:34 +02:00
parent 44daa65fe6
commit 11e2f957e6
4 changed files with 16 additions and 8 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "5.0.1", "version": "5.0.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "5.0.1", "version": "5.0.2",
"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": "5.0.1", "version": "5.0.2",
"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

@ -136,15 +136,21 @@ async function activateHoverPreview(card: HTMLElement, vodId: string): Promise<v
const width = thumbRect.width; const width = thumbRect.width;
const height = thumbRect.height; const height = thumbRect.height;
const scale = width / storyboard.cellWidth; // Skaliere X und Y unabhaengig, damit eine Cell EXAKT die Overlay-Box
// fuellt — egal ob Twitch-Cell-Aspect (z.B. 320x180) gleich Thumbnail-
// Aspect (CSS 16/9) ist oder leicht abweicht. Ohne separate Y-Skalierung
// gab es bei minimalem Aspect-Diff einen Pixel-Streifen mit Inhalt aus
// row+1 (oder row-1, je nach Vorzeichen) am Rand des Overlays.
const scaleX = width / storyboard.cellWidth;
const scaleY = height / storyboard.cellHeight;
overlay.style.backgroundImage = `url("${storyboard.spriteDataUrl.replace(/"/g, '%22')}")`; overlay.style.backgroundImage = `url("${storyboard.spriteDataUrl.replace(/"/g, '%22')}")`;
overlay.style.backgroundSize = `${storyboard.cols * storyboard.cellWidth * scale}px ${storyboard.rows * storyboard.cellHeight * scale}px`; overlay.style.backgroundSize = `${storyboard.cols * storyboard.cellWidth * scaleX}px ${storyboard.rows * storyboard.cellHeight * scaleY}px`;
overlay.style.backgroundRepeat = 'no-repeat'; overlay.style.backgroundRepeat = 'no-repeat';
overlay.style.width = `${width}px`; overlay.style.width = `${width}px`;
overlay.style.height = `${height}px`; overlay.style.height = `${height}px`;
// Initial position = first chosen cell. // Initial position = first chosen cell.
const first = cellsToShow[0]; const first = cellsToShow[0];
overlay.style.backgroundPosition = `-${first.col * storyboard.cellWidth * scale}px -${first.row * storyboard.cellHeight * scale}px`; overlay.style.backgroundPosition = `-${first.col * storyboard.cellWidth * scaleX}px -${first.row * storyboard.cellHeight * scaleY}px`;
host.appendChild(overlay); host.appendChild(overlay);
// Trigger CSS transition to opacity:1 on the next frame. // Trigger CSS transition to opacity:1 on the next frame.
@ -153,7 +159,7 @@ async function activateHoverPreview(card: HTMLElement, vodId: string): Promise<v
let frameIdx = 1; let frameIdx = 1;
const intervalId = window.setInterval(() => { const intervalId = window.setInterval(() => {
const cell = cellsToShow[frameIdx % cellsToShow.length]; const cell = cellsToShow[frameIdx % cellsToShow.length];
overlay.style.backgroundPosition = `-${cell.col * storyboard.cellWidth * scale}px -${cell.row * storyboard.cellHeight * scale}px`; overlay.style.backgroundPosition = `-${cell.col * storyboard.cellWidth * scaleX}px -${cell.row * storyboard.cellHeight * scaleY}px`;
frameIdx++; frameIdx++;
}, FRAME_INTERVAL_MS); }, FRAME_INTERVAL_MS);

View File

@ -3860,7 +3860,9 @@ input[type="number"]::-webkit-outer-spin-button {
background: rgba(0, 0, 0, 0.88); background: rgba(0, 0, 0, 0.88);
} }
.vod-card.preview-active .vod-duration-badge { .vod-card.preview-active .vod-duration-badge,
.vod-card.preview-active .vod-select-checkbox,
.vod-card.preview-active .vod-downloaded-badge {
opacity: 0; opacity: 0;
transition: opacity 0.2s; transition: opacity 0.2s;
} }