Skip to main content

Overview

The CoverArtManager class provides methods to search for and download album cover art from multiple sources including MusicBrainz Cover Art Archive and iTunes. It includes automatic image processing, resizing, and retry logic.

Constructor

from tagqt.core.art import CoverArtManager

manager = CoverArtManager()
The constructor initializes a requests.Session with automatic retry configuration:
  • Max retries: 3 attempts
  • Backoff factor: 1 second (exponential)
  • Retry on: 500, 502, 503, 504 status codes

Methods

download_and_process_cover()

Downloads cover art from a URL and automatically processes it (resize to 500x500, convert to JPEG).
url
str
required
Direct URL to the cover art image
manager = CoverArtManager()
cover_data = manager.download_and_process_cover(
    "https://coverartarchive.org/release/xxx/front"
)

if cover_data:
    with open('cover.jpg', 'wb') as f:
        f.write(cover_data)
return
bytes | None
Processed JPEG image data (500x500, quality 90), or None on error
Processing steps:
  1. Download image with 15 second timeout
  2. Convert to RGB color mode
  3. Resize to exactly 500x500 using LANCZOS resampling
  4. Save as JPEG with 90% quality
  5. Return raw bytes
Retry behavior:
  • Up to 3 download attempts
  • Exponential backoff (2^attempt seconds)
  • Handles network errors and request exceptions

search_cover()

Searches for cover art using multiple sources. Tries MusicBrainz first, then falls back to iTunes.
artist
str
required
Artist name
album
str
required
Album/release name
manager = CoverArtManager()
cover_url = manager.search_cover(
    artist="Radiohead",
    album="OK Computer"
)

if cover_url:
    print(f"Found cover: {cover_url}")
    cover_data = manager.download_and_process_cover(cover_url)
return
str | None
URL to the cover art image, or None if not found
Search order:
  1. MusicBrainz Cover Art Archive (via search_cover_musicbrainz())
  2. iTunes API (via search_cover_itunes()) if MusicBrainz fails

search_cover_musicbrainz()

Searches MusicBrainz for cover art and returns Cover Art Archive URL.
artist
str
required
Artist name
album
str
required
Album/release name
manager = CoverArtManager()
url = manager.search_cover_musicbrainz(
    artist="Pink Floyd",
    album="The Dark Side of the Moon"
)

if url:
    print(f"MusicBrainz URL: {url}")
return
str | None
Cover Art Archive URL (format: https://coverartarchive.org/release-group/{id}/front), or None if not found
Process:
  1. Searches MusicBrainz for release groups matching artist + album
  2. Extracts release group ID from first result
  3. Constructs Cover Art Archive URL
  4. Returns URL (does not verify image exists)

search_cover_itunes()

Searches iTunes API for cover art. Returns high-resolution URL (1000x1000).
artist
str
required
Artist name
album
str
required
Album name
manager = CoverArtManager()
url = manager.search_cover_itunes(
    artist="Taylor Swift",
    album="1989"
)

if url:
    print(f"iTunes URL: {url}")
return
str | None
iTunes artwork URL (1000x1000 resolution), or None if not found
Process:
  1. Searches iTunes with combined “artist album” query
  2. Filters for music albums
  3. Returns first result’s artwork URL
  4. Automatically upgrades URL from 100x100 to 1000x1000

search_cover_candidates()

Returns multiple cover art candidates from both sources for user selection.
artist
str
required
Artist name
album
str
required
Album name
manager = CoverArtManager()
candidates = manager.search_cover_candidates(
    artist="The Beatles",
    album="Abbey Road"
)

for candidate in candidates:
    print(f"Source: {candidate['source']}")
    print(f"Album: {candidate['album']}")
    print(f"Artist: {candidate['artist']}")
    print(f"Size: {candidate['size']}")
    print(f"URL: {candidate['url']}")
    print()
return
list[dict]
List of cover art candidates from multiple sourcesEach candidate dictionary contains:
  • album (str): Album name from source
  • artist (str): Artist name from source
  • url (str): Direct image URL
  • source (str): Either “iTunes” or “MusicBrainz”
  • size (str): Image dimensions (e.g., “1000x1000” or “Unknown”)
Search behavior:
  • Searches iTunes for up to 5 results
  • Searches MusicBrainz for 1 result
  • Returns combined list (may be empty if no results)
  • Does not download or verify images

Complete Example

from tagqt.core.art import CoverArtManager
from tagqt.core.tags import MetadataHandler

# Load audio file
handler = MetadataHandler("/music/song.mp3")

# Search for cover art
manager = CoverArtManager()
cover_url = manager.search_cover(
    artist=handler.artist or "Radiohead",
    album=handler.album or "OK Computer"
)

if cover_url:
    print(f"Found cover at: {cover_url}")
    
    # Download and process
    cover_data = manager.download_and_process_cover(cover_url)
    
    if cover_data:
        # Embed in audio file (already resized to 500x500)
        handler.set_cover(cover_data, max_size=None)  # Skip resize
        handler.save()
        
        # Also save to file
        handler.save_cover_file(data=cover_data)
        
        print("Cover art downloaded and embedded!")
else:
    print("No cover art found")

Multiple Candidates Example

from tagqt.core.art import CoverArtManager

manager = CoverArtManager()

# Get multiple options for user to choose
candidates = manager.search_cover_candidates(
    artist="The Beatles",
    album="Abbey Road"
)

if not candidates:
    print("No cover art found")
else:
    print(f"Found {len(candidates)} options:\n")
    
    for i, candidate in enumerate(candidates, 1):
        print(f"{i}. {candidate['source']}: {candidate['artist']} - {candidate['album']}")
        print(f"   Size: {candidate['size']}")
        print(f"   URL: {candidate['url']}\n")
    
    # Let user choose (simplified example)
    choice = int(input("Select option: ")) - 1
    selected = candidates[choice]
    
    # Download selected cover
    cover_data = manager.download_and_process_cover(selected['url'])
    
    if cover_data:
        with open('cover.jpg', 'wb') as f:
            f.write(cover_data)
        print("Cover saved!")

Source Comparison

MusicBrainz Cover Art Archive

Advantages:
  • High quality official releases
  • Community-curated
  • Multiple image types (front, back, booklet)
  • Free and open
Disadvantages:
  • May not have covers for all releases
  • Requires exact artist/album match

iTunes API

Advantages:
  • Large catalog
  • High resolution (1000x1000)
  • Fast response
  • Good for popular music
Disadvantages:
  • Limited to iTunes catalog
  • May return remastered/different versions
  • Watermarked in some regions

Error Handling

All methods handle errors gracefully and return None or empty list:
manager = CoverArtManager()

# Search may return None
url = manager.search_cover("Unknown Artist", "Nonexistent Album")
if url is None:
    print("No cover found")

# Download may fail
if url:
    data = manager.download_and_process_cover(url)
    if data is None:
        print("Failed to download/process image")
Common error scenarios:
  • Network timeouts
  • Invalid image data
  • 404 Not Found responses
  • API rate limiting
  • Image processing failures

Best Practices

  1. Try multiple sources: Use search_cover() which tries both sources
  2. Verify downloads: Always check if returned data is not None
  3. Use candidates for UI: Show multiple options to users with search_cover_candidates()
  4. Cache results: Store downloaded covers to avoid repeated API calls
  5. Handle missing metadata: Provide fallback artist/album values if metadata is incomplete

API Configuration

MusicBrainz

iTunes

Dependencies

Requires the following Python packages:
pip install requests pillow urllib3

Build docs developers (and LLMs) love