# beets changelog > A command-line music library manager and tagger backed by MusicBrainz. - Vendor: Adrian Sampson - Category: Media - Platforms: Desktop - Official site: https://beets.io - Tracked by: What's New (https://whatsnew.fyi/product/beets) - Harvested from: GitHub (beetbox/beets) - Entries below: 10 (newest first) What's New is an index, not a publisher: every entry below links to the vendor's own release notes, which are the authoritative source. Entries are labelled where they are hand-curated sample data, pre-releases, or drawn from a secondary source such as a developer blog. Reuse: the summaries, labels and curation here are © What's New. Quote freely with attribution and a link back; wholesale republication of the corpus is not permitted — terms: https://whatsnew.fyi/terms. The vendors' own release notes remain their publishers'. ## Releases ### v2.13.1 — Release v2.13.1 - Date: 2026-07-29 - Version: v2.13.1 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.13.1 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.13.1 - Labels: Platforms: Desktop - **fixed** — Source distributions now include the bundled man pages #### Bug fixes - Fixed source distributions not including the bundled man pages. :bug: (#6882) ### v2.13.0 — Release v2.13.0 - Date: 2026-07-27 - Version: v2.13.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.13.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.13.0 - Labels: Platforms: Desktop - **added** — Convert Plugin: Add new configuration option convert.refresh and command-line option --refresh to force operation when original file is newer than existing converted file - **added** — Edit Plugin: Interactive import editor now shows album-level fields as configured by albumfields as a YAML header section when editing an album import - **added** — FetchArt Plugin: Add fetch_for_asis setting that enables fetching album art from online sources even when imported files are not modified by the auto-tagger - **added** — Lyrics Plugin: Add lrcmux backend which aggregates lyrics from various other sources - **added** — Lyrics Plugin: Add --no-keep-synced command option to override keep_synced: yes for a single manual lyrics fetch - **added** — Lyrics Plugin: Add rest_directory configuration option for specifying a reStructuredText output directory - **added** — modify command: Support += and -= operators to add or remove individual values from multi-valued fields without replacing the whole field - **added** — ReplayGain Plugin: Add a metaflac backend that computes ReplayGain for FLAC files using the metaflac command-line tool - **added** — Spotify Plugin: Recognize native Spotify URIs such as spotify:album: and spotify:track: when extracting release and track IDs - **added** — Tidal Plugin: Add cover art support with cover_art_url from Tidal's coverArt relationship - **added** — Automatically create a database backup before running schema migrations, controlled by the create_backup_before_migrations option - **changed** — Edit Plugin: Fields that appear in both itemfields and albumfields are shown only in the header, not per-track - **changed** — Tidal Plugin: Normalize Tidal album types to lowercase - **fixed** — Convert Plugin: convert -a with copy_album_art enabled no longer crashes when the stored album art path points to a missing file - **fixed** — Edit Plugin: Preserve missing album art paths when editing album metadata instead of turning artpath: null into a path ending in None - **fixed** — FtInTitle Plugin: Apply featured-artist rewriting to fetched metadata before commands such as MBSync Plugin use it - **fixed** — ImportFeeds Plugin: import command no longer aborts the whole run when a symlink cannot be created but logs the failure and continues - **fixed** — LastGenre Plugin: Add support for normalizing genre spellings and naming variants with new configuration option aliases, with built-in list of regex patterns and audited whitelist and genre tree - **fixed** — Lyrics Plugin: Leave lyrics empty when a source reports an instrumental track and store that state in lyrics_instrumental flexible attribute - **fixed** — Missing Plugin: Honor the -f/--format option and the format_album configuration when listing missing albums in album mode #### New features - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): Add new configuration option `convert.refresh` and command-line option `--refresh`, allowing to force [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html) operation when original file is newer than existing converted file. - [Edit Plugin](https://beets.readthedocs.io/en/stable/plugins/edit.html): The interactive import editor now shows album-level fields (as configured by `albumfields`) as a YAML header section when editing an album import. Fields that appear in both `itemfields` and `albumfields` are shown only in the header, not per-track. - [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html): Add `fetch_for_asis` setting that enables fetching album art from online sources even when imported files are not modified by the auto-tagger. Default is `no` which means [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html) looks for art only in the local filesystem when the user (or `quiet_fallback`) chooses `asis`. - [FtInTitle Plugin](https://beets.readthedocs.io/en/stable/plugins/ftintitle.html): Apply featured-artist rewriting to fetched metadata before commands such as [MBSync Plugin](https://beets.readthedocs.io/en/stable/plugins/mbsync.html) use it. :bug: (#1153) - [LastGenre Plugin](https://beets.readthedocs.io/en/stable/plugins/lastgenre.html): Add support for normalizing genre spellings and naming variants with a new configuration option `aliases`. The feature is enabled by default and ships with a built-in list of regex patterns. These patterns can be replaced via the user's configuration. The default whitelist and genre tree were audited against the top 1,000 Last.fm tags: canonical names are now consistent across both files, long-standing mismatches between them have been resolved, and entries align with the built-in alias patterns. :bug: (#6466) - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Add `lrcmux` backend, which aggregates lyrics from various other sources. - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Added a `--no-keep-synced` command option to override `keep_synced: yes` for a single manual lyrics fetch. - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Added a `rest_directory` configuration option for specifying a reStructuredText output directory, semantically equivalent to `-r, --write-rest`. :bug: (#2806) - [modify command](https://beets.readthedocs.io/en/stable/reference/cli.html#modify-cmd): Support `+=` and `-=` operators to add or remove individual values from multi-valued fields without replacing the whole field. :bug: (#6587) - [ReplayGain Plugin](https://beets.readthedocs.io/en/stable/plugins/replaygain.html): Add a `metaflac` backend that computes ReplayGain for FLAC files using the `metaflac` command-line tool. :bug: (#1203) - [Spotify Plugin](https://beets.readthedocs.io/en/stable/plugins/spotify.html): Recognize native Spotify URIs (e.g. `spotify:album:` and `spotify:track:`) when extracting release/track IDs, in addition to full `open.spotify.com` URLs and bare IDs - [Tidal Plugin](https://beets.readthedocs.io/en/stable/plugins/tidal.html): Add cover art support. Album metadata now includes `cover_art_url` from Tidal's `coverArt` relationship, which the [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html) plugin can retrieve. - A database backup is now automatically created before running schema migrations. Control with the `create_backup_before_migrations` option (default: yes). #### Bug fixes - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): `convert -a` with `copy_album_art` enabled no longer crashes when the stored album art path points to a missing file (for example a multi-disc album whose cover lives in the album root rather than a per-disc directory); _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.13.0]_ ### v2.12.0 — Release v2.12.0 - Date: 2026-06-22 - Version: v2.12.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.12.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.12.0 - Labels: Platforms: Desktop - **added** — Convert Plugin: The `--force` and `--keep-new` CLI flags are now also available as config options via `force` and `keep_new` - **added** — import command: The `--nomove` / `-M` CLI flag can now be used to override the `move: yes` config option during import - **changed** — Lyrics Plugin: Write synced (LRC) lyrics to the `SYLT` (synchronized lyrics) ID3 frame and plain text to `USLT` for ID3-tagged files, instead of storing raw LRC timestamps in `USLT` - **added** — ListenBrainz Plugin: Add support for importing ListenBrainz listening history from an export file with the `-f` / `--export-file` flag - **added** — MusicBrainz Plugin: Introduce `aliases_as_credits` to make aliases-as-artist-credit optional - **added** — Bad Files Plugin: Add settings for auto error and warning actions - **added** — Tidal Plugin: Populate new flexible attributes during imports including `tidal_track_id`, `tidal_album_id`, `tidal_artist_id`, `tidal_track_popularity`, `tidal_album_popularity`, and `tidal_updated` - **added** — Tidal Plugin: Add new `beet tidalsync` command to refresh popularity data for imported items by default, or albums with `--album`, with `--force` to re-fetch and `--write` to update file tags - **fixed** — Convert Plugin: Tidy the `--playlist` help text so it no longer has awkward indentation in CLI output - **fixed** — Duplicates Plugin: Fix plugin output so information about duplicate items is displayed by default and `--count` option is no longer ignored - **fixed** — FetchArt Plugin: Catch `OSError` in `_set_art` so that permission errors are logged as warnings instead of crashing beets - **fixed** — Fish Plugin: Fix error on plugin initialization - **fixed** — import command: Fix duplicate album merge during import when running in threaded mode to prevent duplicate folders and `could not get filesize` errors - **fixed** — Lyrics Plugin: Add rate limiting and exponential backoff to HTTP requests to prevent `429 Too Many Requests` errors from lyrics sources during bulk imports - **fixed** — Lyrics Plugin: Improve Musica.com lyric scraping so fetched lyrics no longer omit the opening verse or include non-lyric page content - **fixed** — MBSync Plugin / BPSync Plugin: Do not clear items metadata when `import.from_scratch` is enabled - **fixed** — modify command: Fix `beet modify -a` splitting multi-value field strings into individual characters when modifying albums by falling back to corresponding item field type definitions - **fixed** — move command: Skip missing items with a warning and continue execution instead of crashing when an item referenced in the database has been deleted from disk - **fixed** — MPDStats Plugin: Fix crashes and invalid configuration when passing `--host`, `--port`, or `--password` on the command line - **fixed** — MusicBrainz Collection Plugin: Handle MusicBrainz `401 Unauthorized` errors during `mbupdate` without crashing and log a clearer message pointing to `musicbrainz.user` and `musicbrainz.pass` configuration #### New features - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): The `--force` and `--keep-new` CLI flags are now also available as config options via `force` and `keep_new`. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): The `--nomove` / `-M` CLI flag can now be used to override the `move: yes` config option during import. - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Write synced (LRC) lyrics to the `SYLT` (synchronized lyrics) ID3 frame and plain text to `USLT` for ID3-tagged files, instead of storing raw LRC timestamps in `USLT`. Players that only support `USLT` continue to see readable plain lyrics. :bug: (#6541) - [ListenBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/listenbrainz.html): Add support for importing ListenBrainz listening history from an export file. Use the `-f` / `--export-file` flag to specify the path to the ListenBrainz export file. - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Introduce [aliases_as_credits](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html#conf-aliases_as_credits) to make aliases-as-artist-credit optional. - [Bad Files Plugin](https://beets.readthedocs.io/en/stable/plugins/badfiles.html): Added settings for auto error and warning actions. - [Tidal Plugin](https://beets.readthedocs.io/en/stable/plugins/tidal.html): New flexible attributes are now populated during imports, including `tidal_track_id`, `tidal_album_id`, `tidal_artist_id`, `tidal_track_popularity`, `tidal_album_popularity`, and `tidal_updated`. Added a new `beet tidalsync` command to refresh popularity data for imported items by default, or albums with `--album`, with `--force` to re-fetch and `--write` to update file tags. **Migration**: Existing Tidal imports can copy the previously stored IDs into the new flexible attributes with [modify command](https://beets.readthedocs.io/en/stable/reference/cli.html#modify-cmd): run `beet modify data_source:tidal tidal_album_id='$mb_albumid' -a` for albums and `beet modify data_source:tidal tidal_track_id='$mb_trackid'` for items. #### Bug fixes - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): Tidy the `--playlist` help text so it no longer has awkward indentation in CLI output. - [Duplicates Plugin](https://beets.readthedocs.io/en/stable/plugins/duplicates.html): Fix plugin output: information about duplicate items was not displayed by default. --count option was ignored :bug: (#6476) - [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html): Catch `OSError` in `_set_art` so that permission errors (e.g. a file locked by another process) are logged as warnings instead of crashing beets. :bug: (#6193) - [Fish Plugin](https://beets.readthedocs.io/en/stable/plugins/fish.html): Fix error on plugin initialization. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): Fix duplicate album merge during import when running in threaded mode. The merge action no longer creates a duplicate folder or reports `could not get filesize` errors. :bug: (#6601) - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Add rate limiting and exponential backoff to HTTP requests to prevent `429 Too Many Requests` errors from lyrics sources during bulk imports. :bug: (#6728) - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Improve Musica.com lyric scraping so fetched lyrics no longer omit the opening verse or include non-lyric page content. - [MBSync Plugin](https://beets.readthedocs.io/en/stable/plugins/mbsync.html) / [BPSync Plugin](https://beets.readthedocs.io/en/stable/plugins/bpsync.html): Do not clear items metadata when `import.from_scratch` is enabled. :bug: (#6613) - [modify command](https://beets.readthedocs.io/en/stable/reference/cli.html#modify-cmd): Fix `beet modi _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.12.0]_ ### v2.11.0 — Release v2.11.0 - Date: 2026-05-06 - Version: v2.11.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.11.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.11.0 - Labels: Platforms: Desktop - **changed** — Smart Playlist Plugin: restructure splupdate command output to include track count per-playlist summary, show per-track details only with -v flag, make --pretend flag report would be updated count, and add --format option for customizing track line format - **removed** — Smart Playlist Plugin: remove --pretend-paths option - **changed** — import command: remove source archive after successful import when move: yes is set - **added** — FromFilename Plugin: support track prefix when parsing track number from filename - **added** — Tidal plugin: new plugin for fetching metadata from Tidal with support for album and track lookups by ID, batch operations, search by query, and ISRC codes and barcode/EAN support - **added** — Add support for adding or modifying subtitle field (ID3 tag TIT3) - **fixed** — Bad Files Plugin: respect quiet mode during import so corrupt-file prompt is suppressed in non-interactive imports - **fixed** — Discogs Plugin: prevent duplicate featured artists in track artist fields when same artist is credited in both artists and extraartists - **fixed** — import command: fix duplicate album art files being created when re-importing albums with FetchArt Plugin enabled - **fixed** — import command: metadata source plugin ID lookups now correctly call each plugin's own lookup method when running in parallel - **changed** — import command: multi-disc album detection now recognizes cassette, digital media, and vinyl as disc markers in addition to disc, disk, and cd - **fixed** — import command: tags with zero distance penalty are no longer shown as differences in match display - **fixed** — import command: with original_date: yes, album-level year, month, and day now use original release date - **fixed** — Lyrics Plugin: fix apostrophe handling in musixmatch backend slug - **fixed** — MusicBrainz Plugin: correctly handle release dates where leading or intermediate components are missing - **fixed** — Improve DBAccessError messages to mention directory missing and file permissions as potential causes - **fixed** — Library path migration now handles manually edited database rows where item or album-art paths were stored as SQLite TEXT values instead of bytes - **changed** — Spotify Plugin: batch spotifysync track and audio-features API requests and deduplicate repeated Spotify track IDs within a run #### New features - [Smart Playlist Plugin](https://beets.readthedocs.io/en/stable/plugins/smartplaylist.html): The `splupdate` command output is restructured. The per-playlist summary now includes a track count. Per-track details are shown only when `-v` flag is provided (`beet -v splupdate`). The `--pretend` flag produces the same output but reports *"N playlists would be updated"* instead of *"N playlists updated"*. The `--format` option allows customizing the track line format. The `--pretend-paths` option was removed (use `--format='$path'` instead). :bug: (#6183) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): When importing an archive (zip, tar, rar, or 7z) with `move: yes`, the source archive is now removed after a successful import. Archives are preserved if any file in the archive was not imported (e.g. skipped as a duplicate, or the import was aborted), and in non-move import modes. - [FromFilename Plugin](https://beets.readthedocs.io/en/stable/plugins/fromfilename.html): Support `track` prefix when parsing the track number from the filename (e.g., `track01.m4a`). - **Tidal plugin**: Introduces a new plugin for fetching metadata from Tidal. It supports album and track lookups by ID, including batch operations via `albums_for_ids` and `tracks_for_ids`. It also enables search by query as well as identifier-based retrieval, with support for ISRC codes (tracks) and barcode/EANs (albums). This is an initial, relatively minimal implementation, but already fully usable for common metadata workflows. We welcome feedback, improvement ideas, and community contributions to further extend its capabilities. See [Tidal Plugin](https://beets.readthedocs.io/en/stable/plugins/tidal.html) for more information. - Add support for adding or modifying a subtitle (ID3 tag `TIT3`) field #### Bug fixes - [Bad Files Plugin](https://beets.readthedocs.io/en/stable/plugins/badfiles.html): Respect quiet mode (the `--quiet` flag or `import.quiet: yes` config) during import so the corrupt-file prompt is suppressed in non-interactive imports. :bug: (#4736) - [Discogs Plugin](https://beets.readthedocs.io/en/stable/plugins/discogs.html): Prevent duplicate featured artists in track artist fields when the same artist is credited both in `artists` (for example with `Feat.` join text) and `extraartists` as `Featuring`. :bug: (#6166) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): Fix duplicate album art files (e.g. `cover.2.jpg`) being created when re-importing albums with the [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html) plugin enabled. Old album art is now properly removed when replacing duplicate albums during import. :bug: (#1264) :bug: (#6205) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): Metadata source plugin ID lookups now correctly call each plugin's own lookup method when running in parallel. :bug: (#6583) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): Multi-disc album detection now recognizes `cassette`, `digital media`, and `vinyl` as disc markers (e.g. `vinyl 1`, `12 vinyl 2`), in addition to the existing `disc`, `disk`, and `cd` markers. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): Tags with a zero distance penalty are no longer shown as differences in the match display. Previously, custom `distance_weights` could cause fields with no actual mismatch to appear in the `≠` line. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd): With `original_date: yes`, album-level `year`, `month`, and `day` now use the original release date. :bug: (#6577) - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Fix apostrophe handling in the `musixmatch` backend slug. :bug: (#4759) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/st _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.11.0]_ ### v2.10.0 — Release v2.10.0 - Date: 2026-04-19 - Version: v2.10.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.10.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.10.0 - Labels: Platforms: Desktop - **added** — Store item and album-art paths relative to the library root in the database while remaining absolute in the rest of beets, with automatic migration of existing paths on first run - **added** — Access to the album or item object as db_obj in inline plugin fields - **added** — Import Discogs remixer, lyricist, composer, and arranger credits into multi-value remixers, lyricists, composers, and arrangers fields - **added** — Add keep_synced config option and --keep-synced CLI flag to lyrics plugin to skip re-fetching lyrics for tracks that already have synced lyrics - **added** — Use aliases for artist credit in MusicBrainz plugin - **added** — Execute metadata source plugin searches and lookups concurrently to speed up lookups when multiple plugins are enabled - **fixed** — Chromaprint/Acoustid plugin now correctly respects when the MusicBrainz plugin is not enabled and restores compatibility with MusicBrainz Pseudo-Release plugin - **fixed** — Automatically remux WAV files containing MP3 streams to proper MP3 files during import with correct metadata - **fixed** — Remove clutter from imported album folders - **fixed** — Retry ListenBrainz requests for temporary failures - **security** — Fix stored XSS vulnerability in web plugin where unescaped metadata fields could execute arbitrary JavaScript by using escaped template interpolation #### New features - **Beets library is now made portable**: item and album-art paths are now stored relative to the library root in the database while remaining absolute in the rest of beets. Path queries continue matching both library-relative paths and absolute paths under the currently configured music directory under the new storage model. The existing paths in the database are migrated automatically the first time you run any `beet` command after the update. :bug: (#133) > [!WARNING] > make sure you run `beet version` (or any other command) at least once after upgrading to trigger the migration. Only then you can safely move the library to a new location. - [Inline Plugin](https://beets.readthedocs.io/en/stable/plugins/inline.html): Add access to the `album` or `item` object as `db_obj` in inline fields. - [Discogs Plugin](https://beets.readthedocs.io/en/stable/plugins/discogs.html): Import Discogs remixer, lyricist, composer, and arranger credits into the multi-value `remixers`, `lyricists`, `composers`, and `arrangers` fields. :bug: (#6380) - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Add `keep_synced` config option and `--keep-synced` CLI flag to skip re-fetching lyrics for tracks that already have synced lyrics, even when `force` is enabled. :bug: (#5249) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Use aliases for artist credit. - Metadata source plugin searches and lookups are now executed concurrently, speeding up lookups when multiple plugins (e.g. MusicBrainz and Spotify) are enabled. #### Bug fixes - [Chromaprint/Acoustid Plugin](https://beets.readthedocs.io/en/stable/plugins/chroma.html): Do not produce MusicBrainz-sourced autotagger candidates when the [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html) plugin is not enabled. The chroma plugin now looks up the musicbrainz plugin through the metadata-source registry instead of unconditionally instantiating its own private instance, which also restores compatibility with [MusicBrainz Pseudo-Release Plugin](https://beets.readthedocs.io/en/stable/plugins/mbpseudo.html) for chroma-triggered lookups. :bug: (#6212) :bug: (#6441) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Automatically remux WAV files containing MP3 streams (`WAVE_FORMAT_MPEGLAYER3`) to proper MP3 files during import, instead of silently importing them with incorrect metadata. :bug: (#6455) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Remove clutter from imported album folders. :bug: (#5016) - [ListenBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/listenbrainz.html): Retry listenbrainz requests for temporary failures. - [Web Plugin](https://beets.readthedocs.io/en/stable/plugins/web.html): Fix a stored XSS vulnerability where unescaped metadata fields (artist, album, title, comments, lyrics) could execute arbitrary JavaScript in the browser. Template tags now use `<%-` (escaped interpolation) instead of `<%=` (raw interpolation). #### For plugin developers - Consumers of [beetsplug.\_utils.musicbrainz.MusicBrainzAPI](https://beets.readthedocs.io/en/stable/api/generated/beetsplug._utils.musicbrainz.MusicBrainzAPI.html#beetsplug._utils.musicbrainz.MusicBrainzAPI) now receive normalized MusicBrainz payloads with underscore-separated field names (for example `artist_credit` and `release_group`) and grouped relation lists such as `work_relations`, `release_relations`, and `url_relations`. The API responses are also now fully typed with concrete `TypedDict` models for releases, recordings, works, and relations. Update direct access to raw MusicBrainz response keys if needed. ### v2.9.0 — Release v2.9.0 - Date: 2026-04-11 - Version: v2.9.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.9.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.9.0 - Labels: Platforms: Desktop - **added** — Add official support for Python 3.14 - **added** — AutoBPM Plugin: Add force configuration and CLI option - **added** — AutoBPM Plugin: Hide "BPM already exists for item" log message with --quiet flag - **added** — Chromaprint/Acoustid Plugin: Add chromasearch command to search the local library by chromaprint fingerprint - **added** — FetchArt Plugin: Add support for WebP images - **added** — import command: Use ffprobe to recognize format of any import music file that has no extension - **added** — LastGenre Plugin: Add support for a user-configurable ignorelist to exclude unwanted or incorrect Last.fm genres - **added** — MusicBrainz Plugin: Store MBIDs for remixers, lyricists, composers, and arrangers in new multi-valued fields remixers_mbid, lyricists_mbid, composers_mbid, and arrangers_mbid - **added** — ReplayGain Plugin: Remove conflicting replay gain tags on write, removing RG* tags when setting R128* and vice versa - **added** — Smart Playlist Plugin: Sort available playlists alphabetically and print space-delimited and POSIX shell-quoted when required - **added** — Query: Add has_cover_art computed field to query items by embedded cover art presence - **added** — Store track remixers, lyricists, composers, and arrangers in multi-valued fields instead of legacy single-value fields with automatic migration - **deprecated** — AutoBPM Plugin: Deprecate overwrite configuration in favor of force - **fixed** — Deezer Plugin: Fix AttributeError crash when selecting a Deezer match with numeric artist IDs - **fixed** — Deezer Plugin: Fix Various Artists albums being tagged with localized string instead of configured va_name - **fixed** — Discogs Plugin: Store specific Discogs styles in genres field and broader Discogs genres in style field - **fixed** — FetchArt Plugin: Fix error when a configured source does not exist or sources configuration is empty - **fixed** — import command: Fix albumartists_sort incorrectly prepending combined artist credit as first element for multi-artist releases - **fixed** — ListenBrainz Plugin: Fix lbimport crashing when tracks are processed through Last.fm-specific play-count import logic - **fixed** — ListenBrainz Plugin: Paginate through all ListenBrainz listens, aggregate individual listen events into correct play counts, and avoid per-listen MusicBrainz API lookups Beets now officially supports Python 3.14. #### New features - [AutoBPM Plugin](https://beets.readthedocs.io/en/stable/plugins/autobpm.html): Add `force` configuration and CLI option and deprecate `overwrite`. - [AutoBPM Plugin](https://beets.readthedocs.io/en/stable/plugins/autobpm.html): The "BPM already exists for item" log message can now be hidden with the `--quiet` flag. - [Chromaprint/Acoustid Plugin](https://beets.readthedocs.io/en/stable/plugins/chroma.html): Add new command `chromasearch` to search the local library by chromaprint fingerprint. - [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html): Add support for WebP images. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Use ffprobe to recognize format of any import music file that has no extension. If the file cannot be recognized as a music file, leave it alone. :bug: (#4881) - [LastGenre Plugin](https://beets.readthedocs.io/en/stable/plugins/lastgenre.html): Add support for a user-configurable ignorelist to exclude unwanted or incorrect Last.fm (or existing) genres, either per artist or globally :bug: (#6449) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Store MBIDs for remixers, lyricists, composers, and arrangers in the new multi-valued fields `remixers_mbid`, `lyricists_mbid`, `composers_mbid`, and `arrangers_mbid`. :bug: (#5698) - [ReplayGain Plugin](https://beets.readthedocs.io/en/stable/plugins/replaygain.html): Conflicting replay gain tags are now removed on write. [RG]()\* tags are removed when setting [R128]()\* and vice versa. - [Smart Playlist Plugin](https://beets.readthedocs.io/en/stable/plugins/smartplaylist.html): The list of available playlists shown when an unknown playlist name is passed as an argument is now sorted alphabetically and printed space-delimited and POSIX shell-quoted when required. This makes it easier to copy and paste multiple playlists for further use in the shell. - Query: Add `has_cover_art` computed field to query items by embedded cover art presence. Users can now search for tracks with or without embedded artwork using `beet list has_cover_art:true` or `beet list has_cover_art:false`. - Store track remixers, lyricists, composers, and arrangers in the multi-valued `remixers`, `lyricists`, `composers`, and `arrangers` fields instead of the legacy single-value `remixer`, `lyricist`, `composer`, and `arranger` fields. Existing libraries are migrated automatically, and [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html) now preserves each MusicBrainz `remixer`, `lyricist`, `composer`, and `arranger` relation as a separate value. #### Bug fixes - [Deezer Plugin](https://beets.readthedocs.io/en/stable/plugins/deezer.html): Fix a regression in 2.8.0 where selecting a Deezer match during import could crash with `AttributeError: 'AlbumInfo' object has no attribute 'raw_data'` when Deezer returned numeric artist IDs. :bug: (#6503) - [Deezer Plugin](https://beets.readthedocs.io/en/stable/plugins/deezer.html): Fix Various Artists albums being tagged with a localized string instead of the configured `va_name`. Detection now uses Deezer's artist ID rather than the artist name string. :bug: (#4956) - [Discogs Plugin](https://beets.readthedocs.io/en/stable/plugins/discogs.html): Store specific Discogs styles in beets `genres` and broader Discogs genres in the `style` field. When [append_style_genre](https://beets.readthedocs.io/en/stable/plugins/discogs.html#conf-append_style_genre) is enabled, the broader Discogs genres are also appended to the `genres` list. :bug: (#6390) - [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html): Error when a configured source does not exist or sources configuration is empty. :bug: (#6336) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Fix `albumartists_sort` (and related fields) incorrectly _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.9.0]_ ### v2.8.0 — Release v2.8.0 - Date: 2026-03-28 - Version: v2.8.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.8.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.8.0 - Labels: Platforms: Desktop - **added** — Add extra_tags option to Discogs Plugin to use additional tags in search queries - **added** — Add auto_ignore configuration option to Lyrics Plugin to skip fetching lyrics for items matching a beets query during auto import - **added** — Add --release-type flag to Missing Plugin to specify MusicBrainz release types to show in missing album mode - **added** — Add -R/--randomize flag to Play Plugin to shuffle the playlist order before passing it to the player - **added** — Add dest_regen configuration option to Smart Playlist Plugin to regenerate items' path in the generated playlist - **changed** — Missing Plugin default behavior changed to show only releases of type album - **fixed** — Beatport Plugin now uses va_name config for the album artist on VA releases instead of hardcoded "Various Artists" - **fixed** — config command on Windows now uses cmd /c start "" for the default editor fallback so beet config -e works when VISUAL and EDITOR are unset - **fixed** — Fix AttributeError in Fish Plugin - **fixed** — import command autotagging by explicit release or recording IDs now keeps candidates from all enabled metadata sources instead of dropping matches when different providers share the same ID - **fixed** — Simplify import command autotag metadata application for albums and singletons, fixing null-overwrite handling and keeping singular/plural artist metadata fields in sync - **fixed** — LastImport Plugin flexible field renamed from play_count to lastfm_play_count to avoid conflicts with MPDStats Plugin - **fixed** — MBSync Plugin and Missing Plugin now use each item's stored data_source for ID lookups with fallback to MusicBrainz - **fixed** — Missing Plugin --album mode now correctly reports albums using mb_releasegroupid instead of incorrectly reporting albums already in the library as missing - **fixed** — MusicBrainz Plugin now uses va_name config for albumartist_sort, albumartists_sort, albumartist_credit, albumartists_credit, and albumartists on VA releases instead of hardcoded "Various Artists" - **fixed** — Made drive_sep_replace regex logic more precise to prevent edge-case mismatches such as a song titled "1:00 AM" being incorrectly considered a Windows drive path - **changed** — beets.metadata_plugins.album_for_id and beets.metadata_plugins.track_for_id now require a data_source argument and query only that provider - **changed** — Colorisation, diff and layout utility helpers moved from beets.ui to beets.util.color, beets.util.diff, and beets.util.layout - **changed** — lastgenre tunelog helper generalized into beets.logging.BeetsLogger.extra_debug which emits DEBUG messages only at verbosity level 3 or higher #### New features - [Discogs Plugin](https://beets.readthedocs.io/en/stable/plugins/discogs.html): Add [extra_tags](https://beets.readthedocs.io/en/stable/plugins/discogs.html#conf-extra_tags) option to use additional tags (such as `barcode`, `catalognum`, `country`, `label`, `media`, and `year`) in Discogs search queries. - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Add `auto_ignore` configuration option to skip fetching lyrics for items matching a beets query during auto import. - [Missing Plugin](https://beets.readthedocs.io/en/stable/plugins/missing.html): When running in missing album mode, allows users to specify MusicBrainz release types to show using the `--release-type` flag. The default behavior is also changed to just show releases of type `album`. :bug: (#2661) - [Play Plugin](https://beets.readthedocs.io/en/stable/plugins/play.html): Added `-R`/`--randomize` flag to shuffle the playlist order before passing it to the player. - [Smart Playlist Plugin](https://beets.readthedocs.io/en/stable/plugins/smartplaylist.html): Add new configuration option `dest_regen` to regenerate items' path in the generated playlist instead of using those in the library. This is useful when items have been imported in don't copy-move (`-C -M`) mode in the library but are later passed through the [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html) plugin which will regenerate new paths according to the Beets path format. #### Bug fixes - [Beatport Plugin](https://beets.readthedocs.io/en/stable/plugins/beatport.html): Use `va_name` config for the album artist on VA releases instead of hardcoded "Various Artists". :bug: (#6316) - [config command](https://beets.readthedocs.io/en/stable/reference/cli.html#config-cmd) on Windows now uses `cmd /c start ""` for the default editor fallback so `beet config -e` works when `VISUAL` and `EDITOR` are unset. :bug: (#6436) - [Fish Plugin](https://beets.readthedocs.io/en/stable/plugins/fish.html): Fix AttributeError. :bug: (#6340) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Autotagging by explicit release or recording IDs now keeps candidates from all enabled metadata sources instead of dropping matches when different providers share the same ID. :bug: (#6178) :bug: (#6181) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Simplify autotag metadata application for albums and singletons, fixing null-overwrite handling and keeping singular/plural artist metadata fields in sync during tagging. - [LastImport Plugin](https://beets.readthedocs.io/en/stable/plugins/lastimport.html): Rename flexible field `play_count` to `lastfm_play_count` to avoid conflicts with [MPDStats Plugin](https://beets.readthedocs.io/en/stable/plugins/mpdstats.html). **Migration**: This cannot be migrated automatically because of the field clash. If you use [LastImport Plugin](https://beets.readthedocs.io/en/stable/plugins/lastimport.html) without [MPDStats Plugin](https://beets.readthedocs.io/en/stable/plugins/mpdstats.html), migrate manually with `beet modify lastfm_play_count='$play_count'`. - [MBSync Plugin](https://beets.readthedocs.io/en/stable/plugins/mbsync.html) and [Missing Plugin](https://beets.readthedocs.io/en/stable/plugins/missing.html) now use each item's stored `data_source` for ID lookups, with a fallback to `MusicBrainz`. - [Missing Plugin](https://beets.readthedocs.io/en/stable/plugins/missing.html): Fix `--album` mode incorrectly reporting albums already in the library as missing. The comparison now correctly uses `mb_releasegroupid`. - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Use `va_name` config for `albumartist_sort`, `albumartists_sort`, `albumartist_credit`, `albumartists_credit`, and `albumartists` on VA releases instead of hardcoded "Various Artists". :bug: (#6316) - [replace](https://beets.readthedo _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.8.0]_ ### v2.7.1 — Release v2.7.1 - Date: 2026-03-08 - Version: v2.7.1 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.7.1 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.7.1 - Labels: Platforms: Desktop - **fixed** — Tests that depend on the optional langdetect package are now skipped when the package is not installed #### Bug fixes - Tests that depend on the optional `langdetect` package are now skipped when the package is not installed. :bug: (#6421) ### v2.7.0 — Release v2.7.0 - Date: 2026-03-07 - Version: v2.7.0 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.7.0 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.7.0 - Labels: Platforms: Desktop - **added** — Add native support for multiple genres per album/track with the genres field storing genres as a list and written to files as multiple individual genre tags - **added** — LastGenre Plugin: Add cleanup_existing configuration flag to allow whitelist canonicalization of existing genres - **changed** — MusicBrainz Plugin, Beatport Plugin, Discogs Plugin and LastGenre Plugin have been updated to populate the genres field as a list - **changed** — Lyrics Plugin: With synced enabled, existing synced lyrics are no longer replaced by newly fetched plain lyrics even when force is enabled - **changed** — Lyrics Plugin: Remove Source: suffix from lyrics and store the backend name in lyrics_backend, URL in lyrics_url, language in lyrics_language and translation language in lyrics_translation_language flexible attributes - **changed** — Edit Plugin: Editing multi-valued fields now behaves more naturally with list values handled directly - **changed** — LastGenre Plugin: Remove the separator configuration option - **changed** — Lyrics Plugin: Synced lyrics from lrclib source are now checked to ensure the final verse falls within the track's duration - **changed** — modify command: Use semicolon followed by space as the separator to delimit multiple field values instead of \␀ - **fixed** — Convert Plugin: Fix extension substitution inside path of the exported playlist - **fixed** — FetchArt Plugin: Prevent deletion of configured fallback cover art - **fixed** — FtInTitle Plugin: Fix handling of multiple featured artists with ampersand - **fixed** — Fuzzy Search Plugin: Force slow query evaluation whenever the fuzzy prefix is used so fuzzy matching is applied consistently - **fixed** — Fuzzy Search Plugin: Improve fuzzy matching when the query is shorter than the field value so substring-style searches produce more useful results - **fixed** — import command: Duplicate detection now works for as-is imports when autotag is disabled - **fixed** — import command: When autotagging, initialise empty multi-valued fields with None instead of empty list to avoid overwriting existing metadata - **fixed** — Zero Plugin: When the omit_single_disc option is set, disctotal is zeroed alongside disc - **deprecated** — Populating the single genre field in metadata source plugins is deprecated and support will be removed in version 3.0.0; populate the genres list instead #### New features - [LastGenre Plugin](https://beets.readthedocs.io/en/stable/plugins/lastgenre.html): Added `cleanup_existing` configuration flag to allow whitelist canonicalization of existing genres. - Add native support for multiple genres per album/track. The `genres` field now stores genres as a list and is written to files as multiple individual genre tags (e.g., separate GENRE tags for FLAC/MP3). The [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html), [Beatport Plugin](https://beets.readthedocs.io/en/stable/plugins/beatport.html), [Discogs Plugin](https://beets.readthedocs.io/en/stable/plugins/discogs.html) and [LastGenre Plugin](https://beets.readthedocs.io/en/stable/plugins/lastgenre.html) plugins have been updated to populate the `genres` field as a list. **Migration**: Existing libraries with comma-separated, semicolon-separated, or slash-separated genre strings (e.g., `"Rock, Alternative, Indie"`) are automatically migrated to the `genres` list when you first run beets after upgrading. The migration runs once when the database schema is updated, splitting genre strings and writing the changes to the database. The updated `genres` values will be written to media files the next time you run a command that writes tags (such as [write command](https://beets.readthedocs.io/en/stable/reference/cli.html#write-cmd) or during import). No manual action or [MBSync Plugin](https://beets.readthedocs.io/en/stable/plugins/mbsync.html) is required. The `genre` field is split by the first separator found in the string, in the following order of precedence: 1. [LastGenre Plugin](https://beets.readthedocs.io/en/stable/plugins/lastgenre.html) `separator` configuration 2. Semicolon followed by a space 3. Comma followed by a space 4. Slash wrapped by spaces - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): With `synced` enabled, existing synced lyrics are no longer replaced by newly fetched plain lyrics, even when `force` is enabled. - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Remove `Source: ` suffix from lyrics. Store the backend name in `lyrics_backend`, URL in `lyrics_url`, language in `lyrics_language` and translation language (if translations present) in `lyrics_translation_language` flexible attributes. Lyrics are automatically migrated on the first beets run. :bug: (#6370) #### Bug fixes - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): Fix extension substitution inside path of the exported playlist. - [FetchArt Plugin](https://beets.readthedocs.io/en/stable/plugins/fetchart.html): Prevent deletion of configured fallback cover art - [FtInTitle Plugin](https://beets.readthedocs.io/en/stable/plugins/ftintitle.html): Fix handling of multiple featured artists with ampersand. - [Fuzzy Search Plugin](https://beets.readthedocs.io/en/stable/plugins/fuzzy.html): Force slow query evaluation whenever the fuzzy prefix is used (for example `~foo` or `%%foo`), so fuzzy matching is applied consistently. :bug: (#5638) - [Fuzzy Search Plugin](https://beets.readthedocs.io/en/stable/plugins/fuzzy.html): Improve fuzzy matching when the query is shorter than the field value so substring-style searches produce more useful results. :bug: (#2043) - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) Duplicate detection now works for as-is imports (when `autotag` is disabled). Previously, `duplicate_keys` and `duplicate_action` config options were silently ignored for as-is imports. - [import command](https://beets.readthedocs.io/en/stable/reference/cli.html#import-cmd) When autotagging, initialise empty multi-valued fields with `None` instead of empty list, which caused beets to overwrite existing metadata with empty list values instead of leaving them unchanged. :bug: (#6403) - [Zero Plugin](https://beets.readthedocs.io/en/s _[Truncated at 4000 characters — full notes: https://github.com/beetbox/beets/releases/tag/v2.7.0]_ ### v2.6.2 — Release v2.6.2 - Date: 2026-02-22 - Version: v2.6.2 - Original notes: https://github.com/beetbox/beets/releases/tag/v2.6.2 - Permalink: https://whatsnew.fyi/product/beets/releases/v2.6.2 - Labels: Platforms: Desktop - **fixed** — Bad Files Plugin: Fix number of found errors in log message - **fixed** — MusicBrainz Plugin: Fix crash when release mediums lack the tracks key - **fixed** — MusicBrainz Plugin: Fix fetching very large releases that have more than 500 tracks - **fixed** — MusicBrainz Plugin: Fix search terms escaping - **fixed** — MusicBrainz Plugin: Fix support for alias and tracks extra_tags - **fixed** — MusicBrainz Pseudo-Release Plugin: Fix crash due to missing artist_credit field in the MusicBrainz API response - **fixed** — ReplayGain Plugin: Avoid magic Windows prefix in calls to command backends, such as mp3gain - **changed** — Lyrics Plugin: Disable tekstowo by default because it blocks the beets User-Agent #### Bug fixes - [Bad Files Plugin](https://beets.readthedocs.io/en/stable/plugins/badfiles.html): Fix number of found errors in log message - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Fix crash when release mediums lack the `tracks` key. :bug: (#6302) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Fix fetching very large releases that have more than 500 tracks. :bug: (#6355) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Fix search terms escaping. :bug: (#6347) - [MusicBrainz Plugin](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html): Fix support for `alias` and `tracks` [extra_tags](https://beets.readthedocs.io/en/stable/plugins/musicbrainz.html#conf-extra_tags). - [MusicBrainz Pseudo-Release Plugin](https://beets.readthedocs.io/en/stable/plugins/mbpseudo.html): Fix crash due to missing `artist_credit` field in the MusicBrainz API response. :bug: (#6339) - [ReplayGain Plugin](https://beets.readthedocs.io/en/stable/plugins/replaygain.html): Avoid magic Windows prefix in calls to command backends, such as `mp3gain`. :bug: (#2946) #### Other changes - [Lyrics Plugin](https://beets.readthedocs.io/en/stable/plugins/lyrics.html): Disable `tekstowo` by default because it blocks the beets User-Agent.