From ba9bae63e4ffb2138fb770cb9d26a8d5aabdcd52 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sun, 22 Mar 2026 20:28:45 -0700 Subject: [PATCH] test: address latest review feedback --- .../immersion-tracker-service.test.ts | 10 +++++-- stats/src/lib/media-library-grouping.test.tsx | 28 +++++++++++++++++++ stats/src/lib/media-library-grouping.ts | 11 +++++--- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/core/services/immersion-tracker-service.test.ts b/src/core/services/immersion-tracker-service.test.ts index c4fe2de..d336f4e 100644 --- a/src/core/services/immersion-tracker-service.test.ts +++ b/src/core/services/immersion-tracker-service.test.ts @@ -2317,15 +2317,18 @@ test('handleMediaChange stores youtube metadata for new youtube sessions', async let tracker: ImmersionTrackerService | null = null; const originalFetch = globalThis.fetch; const originalPath = process.env.PATH; + let fakeBinDir: string | null = null; try { - const fakeBinDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-yt-dlp-bin-')); + fakeBinDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-yt-dlp-bin-')); const ytDlpOutput = '{"id":"abc123","title":"Video Name","webpage_url":"https://www.youtube.com/watch?v=abc123","thumbnail":"https://i.ytimg.com/vi/abc123/hqdefault.jpg","channel_id":"UCcreator123","channel":"Creator Name","channel_url":"https://www.youtube.com/channel/UCcreator123","uploader_id":"@creator","uploader_url":"https://www.youtube.com/@creator","description":"Video description","channel_follower_count":12345,"thumbnails":[{"url":"https://i.ytimg.com/vi/abc123/hqdefault.jpg"},{"url":"https://yt3.googleusercontent.com/channel-avatar=s88"}]}'; if (process.platform === 'win32') { + const outputPath = path.join(fakeBinDir, 'output.json'); + fs.writeFileSync(outputPath, ytDlpOutput, 'utf8'); fs.writeFileSync( path.join(fakeBinDir, 'yt-dlp.cmd'), - `@echo off\r\necho ${ytDlpOutput.replace(/"/g, '\\"')}\r\n`, + '@echo off\r\ntype "%~dp0output.json"\r\n', 'utf8', ); } else { @@ -2429,6 +2432,9 @@ printf '%s\n' '${ytDlpOutput}' globalThis.fetch = originalFetch; tracker?.destroy(); cleanupDbPath(dbPath); + if (fakeBinDir) { + fs.rmSync(fakeBinDir, { recursive: true, force: true }); + } } }); diff --git a/stats/src/lib/media-library-grouping.test.tsx b/stats/src/lib/media-library-grouping.test.tsx index 0071971..ff8ed33 100644 --- a/stats/src/lib/media-library-grouping.test.tsx +++ b/stats/src/lib/media-library-grouping.test.tsx @@ -90,6 +90,16 @@ test('resolveMediaArtworkUrl prefers youtube thumbnails for video and channel im assert.equal(resolveMediaArtworkUrl(localVideo, 'channel'), null); }); +test('resolveMediaArtworkUrl normalizes blank thumbnail urls to null', () => { + const item = { + videoThumbnailUrl: ' ', + channelThumbnailUrl: '', + }; + + assert.equal(resolveMediaArtworkUrl(item, 'video'), null); + assert.equal(resolveMediaArtworkUrl(item, 'channel'), null); +}); + test('summarizeMediaLibraryGroups stays aligned with rendered group buckets', () => { const groups = groupMediaLibraryItems([youtubeEpisodeA, localVideo, youtubeEpisodeB]); const summary = summarizeMediaLibraryGroups(groups); @@ -100,6 +110,24 @@ test('summarizeMediaLibraryGroups stays aligned with rendered group buckets', () }); }); +test('groupMediaLibraryItems backfills missing group artwork from later items', () => { + const first = { + ...youtubeEpisodeA, + videoId: 10, + videoThumbnailUrl: null, + channelThumbnailUrl: null, + }; + const second = { + ...youtubeEpisodeB, + videoId: 11, + channelThumbnailUrl: null, + }; + + const groups = groupMediaLibraryItems([first, second]); + + assert.equal(groups[0]?.imageUrl, second.videoThumbnailUrl); +}); + test('CoverImage renders explicit remote artwork when src is provided', () => { const markup = renderToStaticMarkup( , kind: 'video' | 'channel', ): string | null { - if (kind === 'channel') { - return item.channelThumbnailUrl ?? null; - } - return item.videoThumbnailUrl ?? null; + const raw = kind === 'channel' ? item.channelThumbnailUrl : item.videoThumbnailUrl; + const normalized = raw?.trim() ?? ''; + return normalized.length > 0 ? normalized : null; } export function resolveMediaCoverApiUrl(videoId: number): string { @@ -61,6 +60,10 @@ export function groupMediaLibraryItems(items: MediaLibraryItem[]): MediaLibraryG existing.totalActiveMs += item.totalActiveMs; existing.totalCards += item.totalCards; existing.lastWatchedMs = Math.max(existing.lastWatchedMs, item.lastWatchedMs); + if (!existing.imageUrl) { + existing.imageUrl = + resolveMediaArtworkUrl(item, 'channel') ?? resolveMediaArtworkUrl(item, 'video'); + } continue; }