Skip to main content

coverart-cli

Fill the missing covers in your music library — embed and sidecar in one pass.

HTML coverage report

CI CodeQL CodeRabbit reviews PyPI PyPI downloads Python License: MIT

What it does

Most cover-art tools only embed or only sidecar. That breaks across players — Subsonic apps (Amperfy, Symfonium) read tags, Plex / Jellyfin prefer cover.jpg, Apple Music wants embedded. coverart-cli does both in one pass and ships an HTML coverage report so you can see what's still missing.

Install

pipx install coverart-cli

Use

# Fetch + embed + sidecar (free providers — no key needed)
coverart ~/Music

# Add Last.fm too (much higher hit rate)
LASTFM_API_KEY=xxx coverart ~/Music

# Just generate the coverage report
coverart ~/Music --report-only --report-html report.html

# See what would happen, change nothing
coverart ~/Music --dry-run -v

Run coverart --help for the full flag list.

Config file

Save your defaults so you don't have to repeat flags:

# ~/.config/coverart-cli/config.toml
lastfm_key      = "your-key"
min_bytes       = 30000
replace_smaller = true
no_musicbrainz  = false

Lookup order (later wins): built-in → ~/.config/coverart-cli/config.toml → ./coverart.toml → --config PATH → CLI flags → environment variables. Run coverart ~/Music afterwards with no flags.

Sources

Tried in order until a cover is found:

  1. Last.fm — album.getinfo (needs a free API key)
  2. iTunes — Apple Music's public search, no key
  3. Deezer — public API, no key
  4. MusicBrainz + Cover Art Archive — fallback for niche releases

Supported formats

MP3 (ID3 APIC), M4A/M4B/MP4 (covr atom), FLAC (Picture block), Ogg Vorbis / Opus (metadata_block_picture).

Programmatic use

from pathlib import Path
from coverart_cli.core import RunOptions, run
from coverart_cli.providers import ITunesProvider, DeezerProvider

stats = run(RunOptions(
    root=Path("~/Music").expanduser(),
    providers=[ITunesProvider(), DeezerProvider()],
))
print(stats.fetched_from, stats.not_found)

Alternatives

Tool When to pick it
sacad Best match rate; Rust binary, more sources
get-cover-art Battle-tested Python API
beets fetchart Already using beets for everything else
coverart-cli (this) You want the HTML report + embed/sidecar dual-output in ~700 LOC

Development

git clone https://github.com/WildDragonKing/coverart-cli && cd coverart-cli
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
ruff check . && pyrefly check && pytest

Releases

Releases are prepared by release-please and published from an immutable Git tag via PyPI Trusted Publishing. Commits to main follow Conventional Commits:

Commit prefix Effect on next release
feat: … minor bump (0.3.0 → 0.4.0)
fix: … patch bump (0.3.0 → 0.3.1)
feat!: … / BREAKING CHANGE: major bump (0.3.0 → 1.0.0)
docs:, refactor:, perf: changelog entry, no bump
chore:, ci:, test: hidden in changelog

The Prepare release workflow uses a short-lived GitHub App token to open and update one rolling Release PR. Merging that PR creates the version tag and publishes the GitHub Release. Its published event triggers the isolated Publish release workflow, which verifies that the tag belongs to main and matches the package metadata and changelog. It builds one wheel and source distribution, attaches those exact files to the GitHub Release, and publishes them to PyPI with OIDC attestations.

Configure a repository-scoped GitHub App with Contents: read and write and Pull requests: read and write, then set its App ID as the repository variable RELEASE_APP_ID and its private key as the repository secret RELEASE_APP_PRIVATE_KEY. The repository-wide setting that lets GITHUB_TOKEN create or approve pull requests can remain disabled.

The PyPI Trusted Publisher must be restricted to this repository, the release-please.yml workflow, and the pypi environment. That filename remains the stable publish identity even though Release Please itself runs in prepare-release.yml. Do not create release tags or upload distributions by hand. A failed publish can be rerun from the same GitHub Actions run without introducing a second release path. Historical releases can be recovered by manually running the same workflow from main; it accepts only an existing published release tag and applies every normal validation and test gate. Pull requests, including Release PRs and dependency updates, require an explicit merge after branch protection passes. GitHub Actions changes are gated by the repository's Zizmor security lint; third-party AI review remains advisory so availability limits cannot block security updates.

License

MIT

Metadata

Release files for coverart-cli 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for coverart-cli 0.4.3
File Size Uploaded
coverart_cli-0.4.3.tar.gz 2.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for coverart-cli 0.4.3
File Interpreter ABI Platform
coverart_cli-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 2.5 MB

Release files / coverart_cli-0.4.3.tar.gz

Download URL coverart_cli-0.4.3.tar.gz
Size 2.5 MB
Tags Source
SHA-256 checksum
How to use checksums
6867a9165bda33cbd74ee048f1824d4734e9d8f30ed49a86b31d6977cdf060a7
BLAKE2b-256 checksum
How to use checksums
8547a8c7158bc5ff197d6055dc0b18c365884a821d9d72702886e6230b4247e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / coverart_cli-0.4.3-py3-none-any.whl

Download URL coverart_cli-0.4.3-py3-none-any.whl
Size 31.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
00162aef9a8517f6c4a8f52ac4b9db71b2f024cf1278590929b99c412b2dc88e
BLAKE2b-256 checksum
How to use checksums
abc2fd812208f5f2b0a53a8c877166d80468dd3b764b9897ad0f122544db87b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.5

2 release files

This release

0.4.3 This release

2 release files

0.4.1

2 release files

0.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page