How to Download and Save Album Covers Alongside Music Files in Spotify-Saver
Spotify-Saver downloads album covers by extracting high-resolution artwork URLs from Spotify metadata and processing them through the ImageDownloader service, either embedding the image bytes directly into audio file metadata or saving separate cover.jpg files alongside track collections.
When using the open-source Spotify-Saver tool to build your local music library, proper album artwork handling ensures your collection displays correctly across media players. This article examines how the gabrielbaute/spotify-saver repository implements cover art retrieval and storage, detailing the two distinct workflows for handling album covers alongside downloaded audio files.
How Album Cover Downloading Works
The application retrieves cover art through a coordinated pipeline involving Spotify's API, a dedicated image download service, and metadata embedding utilities. Two primary flows handle artwork depending on whether you download individual tracks or complete collections.
Extracting Cover Art URLs from Spotify Metadata
The process begins in spotifysaver/services/spotify_api.py, where the SpotifyAPI class constructs data models containing high-resolution cover art URLs. When processing tracks, albums, or playlists, the code extracts the first (highest resolution) image from Spotify's metadata response:
# spotifysaver/services/spotify_api.py
cover_url = raw_data["images"][0]["url"] if raw_data["images"] else None
This cover_url field populates the Track, Album, and Playlist model classes defined in spotifysaver/models/, making the artwork address available throughout the download pipeline.
The ImageDownloader Service
All HTTP image fetching logic resides in spotifysaver/downloader/image_downloader.py. This thin wrapper around the requests library provides two key methods:
download_image(url, output_path): Writes image bytes directly to disk (lines 15-38)get_image_from_url(url): Returns raw bytes for in-memory processing (lines 45-61)
The implementation handles directory creation and timeout configuration:
# spotifysaver/downloader/image_downloader.py
response = requests.get(url, timeout=Config.DOWNLOAD_TIMEOUT)
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_bytes(response.content) # saved to disk
# or return response.content for in-memory use
Embedding Covers into Audio Files
For single track downloads, Spotify-Saver embeds artwork directly into the audio file's metadata tags. In spotifysaver/downloader/youtube_downloader.py, the YouTubeDownloader._download_cover() method (lines 197-208) retrieves image bytes via ImageDownloader.get_image_from_url(), then passes them to MusicFileMetadata:
# youtube_downloader.py
cover_data = self._download_cover(track) # bytes or None
metadata = MusicFileMetadata(file_path=output_path,
track=track,
cover_data=cover_data)
metadata.add_metadata() # embeds image
The MusicFileMetadata class in spotifysaver/metadata/music_file_metadata.py handles writing these bytes into ID3 tags (for MP3) or MP4 metadata (for M4A), ensuring the cover displays in any standard media player.
Saving Separate Cover Image Files
When downloading complete albums or playlists, the application saves a standalone cover.jpg file alongside the audio tracks. The YouTubeDownloader._save_cover_album() method (lines 267-282) orchestrates this process:
# youtube_downloader.py
def _save_cover_album(self, url: str, output_path: Path):
image = self.image_downloader.download_image(url, output_path)
if image:
self.logger.info(f"Cover saved in: {output_path}")
CLI commands in spotifysaver/cli/commands/download/album.py (lines 145-148) and playlist.py (lines 113-116) invoke this helper, passing output_dir / "cover.jpg" as the target path. This creates a folder structure like:
Music/
Artist/
Album (2023)/
01 - Artist - Track.m4a # audio file with embedded art
cover.jpg # separate image for album view
Code Implementation Examples
Downloading a Single Track with Embedded Cover Art
When downloading individual tracks, the cover art is automatically embedded into the audio file metadata:
from spotifysaver.downloader.youtube_downloader import YouTubeDownloader
from spotifysaver.models.track import Track
from spotifysaver.enums.audio_formats_enum import AudioFormat
from spotifysaver.enums.bitrates_enum import Bitrate
from pathlib import Path
# Track instance populated by SpotifyAPI
track = Track(...)
yt = YouTubeDownloader(base_dir=Path("Music"))
audio_path, updated_track = yt.download_track(
track,
output_format=AudioFormat.M4A,
bitrate=Bitrate.B256,
download_lyrics=True,
)
print(f"Saved audio: {audio_path}") # contains embedded cover art
Key call chain: YouTubeDownloader.download_track() → _download_cover() → ImageDownloader.get_image_from_url() → MusicFileMetadata.add_metadata().
Downloading an Album with Separate Cover File
For complete collections, use the cover=True parameter to save artwork as a separate file:
from spotifysaver.downloader.youtube_downloader import YouTubeDownloader
from spotifysaver.models.album import Album
from pathlib import Path
album = Album(...) # populated by SpotifyAPI
yt = YouTubeDownloader(base_dir=Path("Music"))
yt.download_album(album, cover=True) # triggers _save_cover_album
Key call chain: YouTubeDownloader.download_album() → _save_cover_album() → ImageDownloader.download_image().
CLI Usage for Cover Art Preservation
Command-line users can trigger cover saving using the --cover flag:
# Album download with cover.jpg saved alongside tracks
spotifysaver download album "My Favorite Album" --cover
# Playlist download with cover art preservation
spotifysaver download playlist "Chill Vibes" --cover
These commands execute the same underlying methods as the Python API, ensuring consistent artwork handling across interfaces.
Key Components and File Locations
spotifysaver/downloader/image_downloader.py: Core image fetching service withdownload_image()andget_image_from_url()methodsspotifysaver/downloader/youtube_downloader.py: Orchestrates audio downloads and cover handling via_download_cover()and_save_cover_album()spotifysaver/services/spotify_api.py: Retrieves Spotify metadata includingcover_urlfieldsspotifysaver/metadata/music_file_metadata.py: Embeds cover bytes into audio file tagsspotifysaver/cli/commands/download/album.pyandplaylist.py: CLI entry points that invoke cover saving for collections
Summary
- Spotify-Saver extracts high-resolution cover URLs from Spotify's metadata API during the initial track/album lookup phase.
- Two distinct workflows handle artwork: embedding bytes directly into audio file metadata for single tracks, or saving separate
cover.jpgfiles for album/playlist downloads. - The
ImageDownloaderservice inimage_downloader.pyhandles all HTTP image retrieval, supporting both disk writes and in-memory byte returns. YouTubeDownloadercoordinates the process, calling_download_cover()for embedding and_save_cover_album()for standalone files.- CLI commands support the
--coverflag to trigger standalone cover saving for complete collections.
Frequently Asked Questions
Does Spotify-Saver always download album covers automatically?
Individual track downloads automatically embed cover art into the audio file metadata, but saving separate cover.jpg files requires explicitly setting cover=True when downloading albums or playlists via the API, or using the --cover flag in CLI commands.
What image format does Spotify-Saver use for saved covers?
When saving standalone album artwork via ImageDownloader.download_image(), the application preserves the original format provided by Spotify's CDN (typically JPEG) and writes it directly to disk as cover.jpg without transcoding.
Can I disable cover art embedding to save bandwidth?
The current implementation in youtube_downloader.py always attempts to download cover art for single tracks via _download_cover(), but you can skip standalone cover file generation for albums by omitting the cover=True parameter or --cover flag.
Where is the cover art stored when downloading playlists?
According to the source code in spotifysaver/cli/commands/download/playlist.py (lines 113-116), playlist covers are saved as cover.jpg in the root playlist directory, using the same YouTubeDownloader._save_cover_album() method employed for album downloads.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →