Artwork Caching
Relevant source files
The following files were used as context for generating this wiki page:
Artwork Caching in Spotty provides a bounded, downsampling mechanism for album and playlist images. Spotify often provides artwork at resolutions significantly higher than the macOS interface requires. To prevent excessive memory consumption, Spotty decodes only the necessary pixels for Retina displays and maintains strict limits on cache size and lifetime.
Sources: Sources/Spotty/Services/ArtworkCache.swift:6-12, README.md:52
Architecture and Components
The system centers on the ArtworkCache singleton, which manages two layers of caching: an in-memory NSCache for decoded NSImage objects and an ephemeral URLCache for raw network responses.
Key Components
- ArtworkCache: A
MainActor-isolated singleton that coordinates image fetching, downsampling, and storage. Sources: Sources/Spotty/Services/ArtworkCache.swift:13-15 - NSCache: Stores downsampled
NSImageobjects with a count limit of 96 and a total cost limit of 24 MiB. Sources: Sources/Spotty/Services/ArtworkCache.swift:17-26 - URLSession (Ephemeral): Uses a 4 MiB memory-only
URLCache. It intentionally avoids disk persistence to prevent storing expired Spotify signed URLs. Sources: Sources/Spotty/Services/ArtworkCache.swift:28-39 - RemoteArtwork: A SwiftUI view that requests images from the cache and releases its strong reference when the view disappears to allow cache eviction. Sources: Sources/Spotty/Views/RemoteArtwork.swift:7-27
Data Structure: SendableCGImage
Because NSImage is not Sendable, the cache uses a private wrapper for CGImage to transfer decoded data across asynchronous boundaries.
private struct SendableCGImage: @unchecked Sendable {
let image: CGImage
}
Sources: Sources/Spotty/Services/ArtworkCache.swift:122-124
Image Processing Flow
When a view requests an image, the cache follows a specific ladder of checks to minimize network and CPU usage.
The system categorizes requested sizes into "buckets" to increase cache hits across different UI components.
Sources: Sources/Spotty/Services/ArtworkCache.swift:42-100
Downsampling Logic
Downsampling occurs on a utility-priority background thread using CGImageSourceCreateThumbnailAtIndex. This process ensures the app only allocates memory for pixels that can actually be displayed on the screen.
Sources: Sources/Spotty/Services/ArtworkCache.swift:108-118, Sources/Spotty/Views/AGENTS.md:20-21
Configuration and Constraints
The cache is strictly bounded to preserve system resources and user privacy.
| Parameter | Value | Description |
|---|---|---|
images.countLimit | 96 | Maximum number of images in the memory cache. |
images.totalCostLimit | 24 MiB | Maximum memory footprint for decoded images. |
URLCache Memory | 4 MiB | Ephemeral storage for raw network data. |
URLCache Disk | 0 | Raw data is never persisted to disk. |
failureRetryInterval | 20s | Time to wait before retrying a failed image URL. |
failureCacheLimit | 256 | Maximum number of failed URLs tracked. |
Sources: Sources/Spotty/Services/ArtworkCache.swift:20-33, PRIVACY.md:20-22
Pixel Bucketing
Requested point sizes are doubled for Retina displays and rounded up to the nearest standard bucket size:
- 64px
- 128px
- 256px
- 384px
- 512px
Sources: Sources/Spotty/Services/ArtworkCache.swift:103-106
Integration with UI
The RemoteArtwork view interacts with the ArtworkCache via a .task modifier. It generates a cache key based on the URL and the target pointSize.
Cleanup and Lifecycle
Artwork is purged under three conditions:
- Cache Limits:
NSCacheautomatically evicts objects when count or cost limits are exceeded. Sources: Sources/Spotty/Services/ArtworkCache.swift:24-26 - Window Closure: The app purges the entire artwork cache when the main window closes. Sources: PRIVACY.md:21-22, Sources/Spotty/Services/ArtworkCache.swift:100-101
- View Disposal: Individual
RemoteArtworkinstances release their image references on disappearance to facilitateNSCacheeviction. Sources: Sources/Spotty/Views/RemoteArtwork.swift:27, Sources/Spotty/Views/AGENTS.md:21-22
Spotty prioritizes memory efficiency by ensuring that stale or off-screen artwork does not persist in memory for the duration of a listening session. Sources: Sources/Spotty/Services/ArtworkCache.swift:28-30