Config flags, synced lyrics, ListenBrainz import, Tidal attrs
Beets
Developer ProductivityA media library management system for organizing and enhancing music collections
Features
- Automatically improves metadata using MusicBrainz, Discogs, Beatport or acoustic fingerprinting
- Fetches or calculates album art, lyrics, genres, tempos, ReplayGain levels and more via plugins
- Transcodes audio to any desired format
- Detects duplicate tracks/albums and identifies missing tracks in collections
Recent releases
View all 10 releases →- `--pretend-paths` flag removed from Smart Playlist Plugin; use `--format='$path'` instead.
- Library path migration now handles manually edited database rows with SQLite TEXT paths for seamless upgrade to portable-path storage format (fix #6561).
- [Smart Playlist Plugin] Restructured `splupdate` output with track count, per-track details on `-v`, `--pretend` reports "would be updated", added `--format` for custom line format.
- [import command] Automatically removes source archives after successful move imports; preserves archives when any file is skipped or import aborts.
- [FromFilename Plugin] Added support for parsing track numbers prefixed with `track` (e.g., `track01.m4a`).
Full changelog
New features
-
Smart Playlist Plugin: The
splupdatecommand output is restructured. The per-playlist summary now includes a track count. Per-track details are shown only when-vflag is provided (beet -v splupdate). The--pretendflag produces the same output but reports "N playlists would be updated" instead of "N playlists updated". The--formatoption allows customizing the track line format. The--pretend-pathsoption was removed (use--format='$path'instead). :bug: (#6183) -
import command: 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: Support
trackprefix 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_idsandtracks_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 for more information.
-
Add support for adding or modifying a subtitle (ID3 tag
TIT3) field
Bug fixes
- Bad Files Plugin: Respect quiet mode (the
--quietflag orimport.quiet: yesconfig) during import so the corrupt-file prompt is suppressed in non-interactive imports. :bug: (#4736) - Discogs Plugin: Prevent duplicate featured artists in track artist fields when the same artist is credited both in
artists(for example withFeat.join text) andextraartistsasFeaturing. :bug: (#6166) - import command: Fix duplicate album art files (e.g.
cover.2.jpg) being created when re-importing albums with the FetchArt Plugin plugin enabled. Old album art is now properly removed when replacing duplicate albums during import. :bug: (#1264) :bug: (#6205) - import command: Metadata source plugin ID lookups now correctly call each plugin's own lookup method when running in parallel. :bug: (#6583)
- import command: Multi-disc album detection now recognizes
cassette,digital media, andvinylas disc markers (e.g.vinyl 1,12 vinyl 2), in addition to the existingdisc,disk, andcdmarkers. - import command: Tags with a zero distance penalty are no longer shown as differences in the match display. Previously, custom
distance_weightscould cause fields with no actual mismatch to appear in the≠line. - import command: With
original_date: yes, album-levelyear,month, anddaynow use the original release date. :bug: (#6577) - Lyrics Plugin: Fix apostrophe handling in the
musixmatchbackend slug. :bug: (#4759) - MusicBrainz Plugin: Correctly handle release dates where leading or intermediate components are missing, e.g. 2008-??-02
- Improve
DBAccessErrormessages to help users diagnose database permission issues more easily. The error message now mentions directory missing and file permissions as potential causes. :bug: (#1676) - Library path migration now also handles manually edited database rows where item or album-art paths were stored as SQLite
TEXTvalues instead of bytes, so upgrading to the portable-path storage format no longer fails for those libraries. :bug: (#6561)
Other changes
- Spotify Plugin: Batch
spotifysynctrack and audio-features API requests and deduplicate repeated Spotify track IDs within a run.
- Run `beet version` (or any other command) at least once after upgrading to trigger the library‑path migration before relocating the library.
- Library item and album‑art paths stored relative to the library root; run any `beet` command after upgrade to trigger migration before moving the library.
- Web plugin: fixed stored XSS by using escaped interpolation (`<%-`) for metadata fields (artist, album, title, comments, lyrics).
- Inline Plugin now exposes `db_obj` (album or item) in inline fields.
- Discogs Plugin imports remixer, lyricist, composer, and arranger credits into multi‑value fields.
- Lyrics Plugin adds `keep_synced` option/CLI flag to skip re‑fetching synced lyrics.
Full changelog
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
beetcommand after the update. :bug: (#133)
[!WARNING]
make sure you runbeet 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: Add access to the
albumoritemobject asdb_objin inline fields. - Discogs Plugin: Import Discogs remixer, lyricist, composer, and arranger credits into the multi-value
remixers,lyricists,composers, andarrangersfields. :bug: (#6380) - Lyrics Plugin: Add
keep_syncedconfig option and--keep-syncedCLI flag to skip re-fetching lyrics for tracks that already have synced lyrics, even whenforceis enabled. :bug: (#5249) - MusicBrainz Plugin: 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: Do not produce MusicBrainz-sourced autotagger candidates when the MusicBrainz Plugin 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 for chroma-triggered lookups. :bug: (#6212) :bug: (#6441)
- import command 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 Remove clutter from imported album folders. :bug: (#5016)
- ListenBrainz Plugin: Retry listenbrainz requests for temporary failures.
- Web Plugin: 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 now receive normalized MusicBrainz payloads with underscore-separated field names (for example
artist_creditandrelease_group) and grouped relation lists such aswork_relations,release_relations, andurl_relations. The API responses are also now fully typed with concreteTypedDictmodels for releases, recordings, works, and relations. Update direct access to raw MusicBrainz response keys if needed.
- [AutoBPM Plugin] Add `force` config/CLI option and deprecate `overwrite`
- [AutoBPM Plugin] Hide "BPM already exists" log with `--quiet` flag
- [Chromaprint/Acoustid Plugin] New `chromasearch` command to search library by fingerprint
Full changelog
Beets now officially supports Python 3.14.
New features
- AutoBPM Plugin: Add
forceconfiguration and CLI option and deprecateoverwrite. - AutoBPM Plugin: The "BPM already exists for item" log message can now be hidden with the
--quietflag. - Chromaprint/Acoustid Plugin: Add new command
chromasearchto search the local library by chromaprint fingerprint. - FetchArt Plugin: Add support for WebP images.
- import command 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: 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: Store MBIDs for remixers, lyricists, composers, and arrangers in the new multi-valued fields
remixers_mbid,lyricists_mbid,composers_mbid, andarrangers_mbid. :bug: (#5698) - ReplayGain Plugin: Conflicting replay gain tags are now removed on write. RG* tags are removed when setting R128* and vice versa.
- Smart Playlist Plugin: 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_artcomputed field to query items by embedded cover art presence. Users can now search for tracks with or without embedded artwork usingbeet list has_cover_art:trueorbeet list has_cover_art:false. - Store track remixers, lyricists, composers, and arrangers in the multi-valued
remixers,lyricists,composers, andarrangersfields instead of the legacy single-valueremixer,lyricist,composer, andarrangerfields. Existing libraries are migrated automatically, and MusicBrainz Plugin now preserves each MusicBrainzremixer,lyricist,composer, andarrangerrelation as a separate value.
Bug fixes
- Deezer Plugin: 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: 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: Store specific Discogs styles in beets
genresand broader Discogs genres in thestylefield. When append_style_genre is enabled, the broader Discogs genres are also appended to thegenreslist. :bug: (#6390) - FetchArt Plugin: Error when a configured source does not exist or sources configuration is empty. :bug: (#6336)
- import command Fix
albumartists_sort(and related fields) incorrectly prepending the full combined artist credit as the first element for multi-artist releases. :bug: (#6470) - ListenBrainz Plugin: Fix
lbimportcrashing when ListenBrainz tracks are processed through Last.fm-specific play-count import logic. Play-count imports now use source-specific fields so ListenBrainz Plugin, LastImport Plugin, and MPDStats Plugin do not clash. :bug: (#6469) - ListenBrainz Plugin: Paginate through all ListenBrainz listens instead of fetching only 25, aggregate individual listen events into correct play counts, use
recording_mbidfrom the ListenBrainz mapping when available, and avoid per-listen MusicBrainz API lookups that caused imports to hang on large listen histories. :bug: (#6469) - modify command accepts legacy singular field names such as
genre,composer,lyricist,remixer, andarrangerin assignments, rewrites them to the corresponding multi-valued fields, and warns users to switch to the plural field names. list command, and query expressions, accept the same legacy singular field names and warn users to switch to the plural field names. :bug: (#6483) - Rewrite Plugin Advanced Rewrite Plugin: Fix rewriting multi-valued fields such as
genresby applying rules to each matching list entry. Additionally, apply rewrite rules in config order, so that multiple rules can be applied to the same field. :bug: (#6515) - Correctly handle semicolon-delimited genre values from externally-tagged files. :bug: (#6450)
For plugin developers
- If you maintain a metadata source plugin that populates any of
arranger,composer,lyricist,remixerfields, update it to populate the respective multi-valued fields instead (arrangers,composers,lyricists,remixers).
- Deprecation warning: Beatport and BPSync plugins are deprecated due to retired API.
- [Missing Plugin] Now uses stored `data_source` for ID lookups with fallback to MusicBrainz.
- [MBSync Plugin] Same behavior change as Missing plugin regarding data source usage.
- LastImport plugin: `play_count` flexible field renamed to `lastfm_play_count`; manual migration required because automatic migration is impossible due to name clash with MPDStats plugin.
- [Discogs Plugin] Added `extra_tags` option for barcode, catalognum, country, label, media, and year in Discogs search queries.
- [Lyrics Plugin] Introduced `auto_ignore` config to skip lyric fetching for items matching a beets query during auto import.
- [Missing Plugin] Added `--release-type` flag to filter missing album mode by MusicBrainz release types; default changed to show only type `album`.
Full changelog
New features
- Discogs Plugin: Add extra_tags option to use additional tags (such as
barcode,catalognum,country,label,media, andyear) in Discogs search queries. - Lyrics Plugin: Add
auto_ignoreconfiguration option to skip fetching lyrics for items matching a beets query during auto import. - Missing Plugin: When running in missing album mode, allows users to specify MusicBrainz release types to show using the
--release-typeflag. The default behavior is also changed to just show releases of typealbum. :bug: (#2661) - Play Plugin: Added
-R/--randomizeflag to shuffle the playlist order before passing it to the player. - Smart Playlist Plugin: Add new configuration option
dest_regento 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 plugin which will regenerate new paths according to the Beets path format.
Bug fixes
- Beatport Plugin: Use
va_nameconfig for the album artist on VA releases instead of hardcoded "Various Artists". :bug: (#6316) - config command on Windows now uses
cmd /c start ""for the default editor fallback sobeet config -eworks whenVISUALandEDITORare unset. :bug: (#6436) - Fish Plugin: Fix AttributeError. :bug: (#6340)
- 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. :bug: (#6178) :bug: (#6181)
- import command 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: Rename flexible field
play_counttolastfm_play_countto avoid conflicts with MPDStats Plugin. Migration: This cannot be migrated automatically because of the field clash. If you use LastImport Plugin without MPDStats Plugin, migrate manually withbeet modify lastfm_play_count='$play_count'. - MBSync Plugin and Missing Plugin now use each item's stored
data_sourcefor ID lookups, with a fallback toMusicBrainz. - Missing Plugin: Fix
--albummode incorrectly reporting albums already in the library as missing. The comparison now correctly usesmb_releasegroupid. - MusicBrainz Plugin: Use
va_nameconfig foralbumartist_sort,albumartists_sort,albumartist_credit,albumartists_credit, andalbumartistson VA releases instead of hardcoded "Various Artists". :bug: (#6316) - replace: Made
drive_sep_replaceregex logic more precise to prevent edge-case mismatches (e.g., a song titled "1:00 AM" would incorrectly be considered a Windows drive path).
For plugin developers
beets.metadata_plugins.album_for_idandbeets.metadata_plugins.track_for_idnow require adata_sourceargument and query only that provider.- Colorisation, diff and layout utility helpers previously imported from
beets.uinow live inbeets.util.color,beets.util.diff, andbeets.util.layout. Update external imports accordingly. - The lastgenre
tuneloghelper was generalized intobeets.logging.BeetsLogger.extra_debug, which emitsDEBUGmessages only at verbosity level 3 or higher (for example-vvv). Plugin authors can use it viaself._log.extra_debug(...).
Other changes
- Contributing: Update pipx installation guide link
- Getting Started: Update quick installation section to reflect current installation guide structure.
- Installation: Remove redundant macOS section from the installation guide. :bug: (#5993)
- Installation: Update installation guide to document plugin management with pipx and move package manager instructions to the FAQ.
- Installation: Update pipx installation guide link
- API-backed metadata source plugins can now use SearchApiMetadataSourcePlugin for shared search orchestration. Implement provider behavior in
~beets.metadata_plugins.SearchApiMetadataSourcePlugin.get_search_query_with_filtersand~beets.metadata_plugins.SearchApiMetadataSourcePlugin.get_search_response. - Deprecate the Beatport Plugin and BPSync Plugin plugins. Beatport has retired the API these plugins rely on, making them non-functional. :bug: (#3862)
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.