Store higher-quality YouTube thumbnail URLs in recent playlists

Rewrites /vi/ID/{default|mq|hq|sd}default.jpg to maxresdefault.jpg when
saving/updating a recent playlist, so the card shows a sharper image
than the low-res search-result thumbnail.
This commit is contained in:
Arkadiusz Fal
2026-04-17 20:00:38 +02:00
parent 663e96c859
commit c03cd0bd19
2 changed files with 18 additions and 3 deletions

View File

@@ -338,7 +338,7 @@ extension DataManager {
existing.title = playlist.title existing.title = playlist.title
existing.authorName = playlist.authorName existing.authorName = playlist.authorName
existing.videoCount = playlist.videoCount existing.videoCount = playlist.videoCount
existing.thumbnailURLString = playlist.thumbnailURL?.absoluteString existing.thumbnailURLString = RecentPlaylist.upgradedThumbnailURLString(playlist.thumbnailURL)
savedEntry = existing savedEntry = existing
} else { } else {
// Create new entry // Create new entry

View File

@@ -57,10 +57,25 @@ final class RecentPlaylist {
title: playlist.title, title: playlist.title,
authorName: playlist.authorName, authorName: playlist.authorName,
videoCount: playlist.videoCount, videoCount: playlist.videoCount,
thumbnailURLString: playlist.thumbnailURL?.absoluteString thumbnailURLString: upgradedThumbnailURLString(playlist.thumbnailURL)
) )
} }
/// Rewrites YouTube `/vi/ID/{default|mq|hq|sd}default.jpg` thumbnails to `maxresdefault.jpg`
/// so recent playlist cards show a higher-quality image.
static func upgradedThumbnailURLString(_ url: URL?) -> String? {
guard let url else { return nil }
let path = url.path
let upgradable = ["default.jpg", "mqdefault.jpg", "hqdefault.jpg", "sddefault.jpg"]
guard path.range(of: #"/vi/[^/]+/"#, options: .regularExpression) != nil,
let match = upgradable.first(where: { path.hasSuffix($0) }),
var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return url.absoluteString
}
components.path = String(path.dropLast(match.count)) + "maxresdefault.jpg"
return components.url?.absoluteString ?? url.absoluteString
}
private static func extractSourceInfo(from source: ContentSource) -> (String, String?) { private static func extractSourceInfo(from source: ContentSource) -> (String, String?) {
switch source { switch source {
case .global: case .global: