Application for managing album cover art in music libraries, with CLI + GUI interfaces.
Note: This application works best with properly tagged files. You can use tools like MusicBrainz Picard, MP3Tag, etc. to prepare your files.
- Library scanning: Recursive analysis of all album folders
- Multi-format detection: MP3, FLAC, OGG, OGA, M4A, MP4, Opus, WAV, AIFF, WMA
- Dual verification: Embedded covers (tags) AND image files (cover.jpg, folder.png, etc.)
- Custom patterns: Folder exclusion via glob patterns (Podcasts, Audiobooks, etc.)
- Detailed reports: JSON or CSV export for review before modification
- Multi-providers: MusicBrainz/Cover Art Archive (default), Discogs, Last.fm
- Multi-level identification: Hierarchical system to find the best match
- Level 1: MusicBrainz ID (MBID) from tags
- Level 2: Discogs ID from tags
- Level 3: UPC/EAN barcode
- Level 4: ISRC (International Standard Recording Code)
- Level 5: Text search by artist/album
- Level 6: AcoustID audio fingerprinting (optional)
- Source selector: Enable/disable providers in preferences
- Tag embedding: Integration into audio files (ID3, FLAC, MP4, OGG)
- External file: Save cover.jpg/folder.jpg in the folder
- Timestamp preservation: Option to keep original file modification date
- Configurable strategy: Customizable filename and compression settings
- Python 3.12 or higher
- Linux, macOS, or Windows
This project uses uv as package manager (recommended):
# Install uv curl -LsSf https://astral.sh/uv/install.sh | sh # Create environment and install uv venv source .venv/bin/activate uv pip install -e .
Or with pip:
pip install -e . # or pip install -r requirements.txt
| Package | Usage |
|---|---|
PySide6 |
Qt6 graphical interface |
mutagen |
Audio tag reading/writing (embedded covers) |
requests |
MusicBrainz and Cover Art Archive API calls |
Pillow |
Image manipulation (optional, improves OGG/Opus support) |
pyacoustid |
AcoustID audio fingerprinting (optional) |
To enable AcoustID identification, install chromaprint:
# Linux (Debian/Ubuntu) sudo apt install libchromaprint-tools && pip install pyacoustid # macOS brew install chromaprint && pip install pyacoustid # Windows: Download fpcalc.exe from https://acoustid.org/chromaprint pip install pyacoustid
A free AcoustID API key is required: https://acoustid.org/new-application
python -m src.main
# or
python -m src.main gui- Drag & Drop: Drop folders or audio files directly into the library
- Import/Export: Save and load album lists as JSON (Ctrl+E / Ctrl+I)
- Group as album: Combine individual files into a single album entry
- Ungroup: Split a grouped album back into individual files
- Grid/List views: Switch between visual grid and compact list
Filter albums by cover status:
- No cover / Embedded only / External only / Both covers
- Covers that differ (embedded β external)
- Identical covers (find duplicates by image hash)
- Small covers / Covers to improve
- Without AcoustID / Single tracks
Sort by: Artist, Album, Year, Cover size, Path
When an album has both embedded and external covers:
- Sync to file: Copy embedded cover to folder
- Sync to tags: Copy folder cover to audio tags
- Keep largest: Automatically use the higher resolution version
- Compare: Side-by-side comparison dialog with zoom
- Batch download: Fetch covers for multiple albums with progress tracking
- Batch AcoustID: Identify albums via audio fingerprinting
- Minimum score: Configurable threshold for automatic matching (default: 95%)
- Skip/Cancel: Granular control during batch processing
View library statistics including:
- Cover status distribution
- Average dimensions (embedded vs external)
- Format distribution (JPEG, PNG, etc.)
- File size statistics
The CLI workflow has two steps to ensure no modifications without approval.
python -m src.main scan /path/to/music [options]
| Option | Description |
|---|---|
-o, --output FILE |
Output file (default: terminal only) |
-f, --format {json,csv} |
Report format (default: json) |
-q, --quiet |
No progress bar |
-e, --exclude PATTERNS |
Folders to exclude |
# Examples python -m src.main scan ~/Music python -m src.main scan ~/Music -o report.json python -m src.main scan ~/Music --exclude Podcasts Audiobooks
python -m src.main fetch report.json [options]
| Option | Description |
|---|---|
--auto |
Automatic mode (perfect matches only) |
--min-score N |
Minimum score in auto mode (default: 95) |
--embed |
Embed cover in audio files |
--dry-run |
Simulation without modifications |
--start-from N |
Resume from index N |
# Interactive (default) python -m src.main fetch report.json # Automatic python -m src.main fetch report.json --auto --min-score 90 # Dry run python -m src.main fetch report.json --dry-run
| Extension | Tag reading | Cover embedding |
|---|---|---|
.mp3 |
Yes | Yes (ID3 APIC) |
.flac |
Yes | Yes (FLAC Picture) |
.ogg / .oga |
Yes | Yes (metadata_block_picture) |
.opus |
Yes | Yes (metadata_block_picture) |
.m4a / .mp4 |
Yes | Yes (covr atom) |
.wav |
Yes | No |
.aiff |
Yes | No |
.wma |
Yes | No |
Names: cover, folder, front, album, albumart, artwork, art, thumb, disc, scan, jacket
Extensions: .jpg, .jpeg, .png, .gif, .bmp, .webp
Configuration is stored in:
- Linux:
~/.config/tunecover/config.json - macOS:
~/Library/Application Support/tunecover/config.json - Windows:
%APPDATA%\tunecover\config.json
To improve MusicBrainz rate limit (1 β 50 req/s), configure a contact email in Edit > Preferences > General.
For Discogs and Last.fm, configure API keys in Edit > Preferences > API Keys:
- Discogs: https://www.discogs.com/settings/developers
- Last.fm: https://www.last.fm/api/account/create
Configurable via Edit > Preferences > Cache:
| Option | Default |
|---|---|
| Disk cache size | 500 MB |
| Cache expiration | 24h |
| Embedded cover memory | 150 MB |
| Thumbnail count | 1500 |
# Clone and install git clone https://github.com/comxd/tune-cover.git cd tune-cover uv venv && source .venv/bin/activate uv pip install -e ".[dev]" pre-commit install # Commands make test # Run tests make test-cov # Tests with coverage make lint # Check code (ruff) make format # Format code (ruff) make run # Run the application
Application metadata is centralized using a single source of truth:
pyproject.toml ββΊ version, name (canonical source)
β
βΌ (importlib.metadata)
src/utils/constants.py ββΊ VERSION, APP_NAME_SLUG, APP_NAME, etc.
β
βΌ (uv run python -c "...")
Makefile ββΊ VERSION, PROJECT variables
β
βΌ (pybabel --project --version)
messages.pot ββΊ Project-Id-Version header (template only)
To update the version:
- Edit
versioninpyproject.toml - Run
uv pip install -e .to update package metadata - Run
make i18n-extractto update the.pottemplate
Note: .po files keep their own Project-Id-Version to track when translations were made.
Key files:
pyproject.toml: Canonical version (version = "X.Y.Z")src/utils/constants.py: All app name variants and dynamic versionMakefile: Reads constants for i18n commands
Download ready-to-use packages from GitHub Releases:
| Platform | Format | Notes |
|---|---|---|
| Linux | .flatpak |
Universal package, includes all dependencies |
| Windows | .zip |
Portable, extract and run TuneCover.exe |
| macOS | .dmg |
Universal Binary (Intel + Apple Silicon) |
# Install prerequisites sudo apt install flatpak flatpak-builder flatpak install flathub org.kde.Platform//6.8 org.kde.Sdk//6.8 # Build cd flatpak flatpak-builder --force-clean --user --repo=repo build-dir io.github.comxd.TuneCover.yml # Test without installing flatpak-builder --run build-dir io.github.comxd.TuneCover.yml tunecover # Create installable bundle flatpak build-bundle repo TuneCover-linux-x86_64.flatpak io.github.comxd.TuneCover
# Install dependencies uv sync --frozen --all-extras # Compile translations uv run pybabel compile -d src/i18n/locales # Build executable cd packaging uv run pyinstaller tunecover.spec # Result: dist/TuneCover/TuneCover.exe
# Install dependencies uv sync --frozen --all-extras brew install chromaprint # Compile translations uv run pybabel compile -d src/i18n/locales # Generate icon and build ./packaging/generate-macos-icons.sh cd packaging uv run pyinstaller tunecover-macos.spec # Result: dist/TuneCover.app
The project uses GitHub Actions to build for all platforms automatically. You can trigger builds without creating a release:
- Go to Actions β Build Release
- Click Run workflow
- Select branch and click Run workflow
- Download artifacts from the completed workflow
# Trigger the workflow gh workflow run build-release.yml # Watch progress gh run watch # List artifacts when complete gh run view --log
git tag v1.0.0-test
git push origin v1.0.0-test
# A draft release with all platform builds will be createdPython dependencies are managed with req2flatpak for reproducibility:
# Update versions in requirements file # Edit flatpak/requirements-flatpak.txt # Regenerate manifest sources (uvx installs and runs the tool) uvx req2flatpak \ --requirements-file flatpak/requirements-flatpak.txt \ --target-platforms 312-x86_64 \ --yaml # Copy output to io.github.comxd.TuneCover.yml (python3-dependencies section)
| Issue | Solution |
|---|---|
| No MusicBrainz results | Check artist/album tags are correct. Use Picard to fix metadata. |
| No cover available | Album exists but has no cover on Cover Art Archive. You can add it manually. |
| Covers not detected | Check filename matches recognized patterns. Hidden files are ignored. |
| PySide6/Qt error | Install: sudo apt install libxcb-xinerama0 libxkbcommon-x11-0 |
| Fingerprinting unavailable | Install chromaprint and verify fpcalc --version works. |
GPL-3.0-or-later - See LICENSE for details.