From 8c62faa822f045cbde81f53cf32350b38ad03ae1 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Mon, 20 Jul 2026 19:05:44 +0200 Subject: [PATCH] fix: stop the YouTube covers coming out blurry and cropped The ytimg variants are 16:9, so picking one by width handed a square tile far fewer pixels than it needed: a 96px cover got the 120x90 file and kept 90px after the crop. They are chosen by their short side now, the album art is preferred over the video frame when the search returns both, and the display sizes account for the tiles being up to 180px on a 2x screen. --- .../Services/YouTubeMusicService.cs | 7 +++++-- .../Musify.Infrastructure/Services/YouTubeThumbnail.cs | 9 ++++++--- web-player/src/lib/server/thumbnails.ts | 6 +++--- web-player/src/lib/thumbnails.ts | 6 +++--- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/backend/Musify.Infrastructure/Services/YouTubeMusicService.cs b/backend/Musify.Infrastructure/Services/YouTubeMusicService.cs index 3706be7..7ae84c2 100644 --- a/backend/Musify.Infrastructure/Services/YouTubeMusicService.cs +++ b/backend/Musify.Infrastructure/Services/YouTubeMusicService.cs @@ -167,8 +167,11 @@ namespace Musify.Infrastructure.Services { var ordered = thumbnails.OrderBy(thumbnail => thumbnail.Width).ToList(); - var chosen = ordered.FirstOrDefault(thumbnail => thumbnail.Width >= configuration.ThumbnailSize) - ?? ordered.LastOrDefault(); + var square = ordered.Where(thumbnail => YouTubeThumbnail.IsSquare(thumbnail.Url)).ToList(); + var candidates = square.Count > 0 ? square : ordered; + + var chosen = candidates.FirstOrDefault(thumbnail => thumbnail.Width >= configuration.ThumbnailSize) + ?? candidates.LastOrDefault(); return chosen is null ? string.Empty diff --git a/backend/Musify.Infrastructure/Services/YouTubeThumbnail.cs b/backend/Musify.Infrastructure/Services/YouTubeThumbnail.cs index 2eb94f7..1f7ca58 100644 --- a/backend/Musify.Infrastructure/Services/YouTubeThumbnail.cs +++ b/backend/Musify.Infrastructure/Services/YouTubeThumbnail.cs @@ -2,6 +2,9 @@ namespace Musify.Infrastructure.Services { public static class YouTubeThumbnail { + public static bool IsSquare(string url) => + url.Contains("googleusercontent.com", StringComparison.OrdinalIgnoreCase); + public static string WithSize(string url, int size) { if (string.IsNullOrEmpty(url)) @@ -40,9 +43,9 @@ namespace Musify.Infrastructure.Services private static string YtImgFileName(int size) => size switch { - <= 120 => "default.jpg", - <= 320 => "mqdefault.jpg", - <= 480 => "hqdefault.jpg", + <= 90 => "default.jpg", + <= 180 => "mqdefault.jpg", + <= 360 => "hqdefault.jpg", _ => "maxresdefault.jpg" }; diff --git a/web-player/src/lib/server/thumbnails.ts b/web-player/src/lib/server/thumbnails.ts index a840feb..ad64b81 100644 --- a/web-player/src/lib/server/thumbnails.ts +++ b/web-player/src/lib/server/thumbnails.ts @@ -55,9 +55,9 @@ export function resizeThumbnailUrl(url: URL, size: number): string { } function ytImgFileName(size: number): string { - if (size <= 120) return 'default.jpg'; - if (size <= 320) return 'mqdefault.jpg'; - if (size <= 480) return 'hqdefault.jpg'; + if (size <= 90) return 'default.jpg'; + if (size <= 180) return 'mqdefault.jpg'; + if (size <= 360) return 'hqdefault.jpg'; return 'maxresdefault.jpg'; } diff --git a/web-player/src/lib/thumbnails.ts b/web-player/src/lib/thumbnails.ts index ee08d9a..4f1a165 100644 --- a/web-player/src/lib/thumbnails.ts +++ b/web-player/src/lib/thumbnails.ts @@ -1,7 +1,7 @@ export const THUMBNAIL_SIZES = { - small: 96, - medium: 160, - large: 320 + small: 128, + medium: 192, + large: 360 } as const; export type ThumbnailSize = keyof typeof THUMBNAIL_SIZES;