fetchart: handle sources config given as plain string#6437
Open
wavebyrd wants to merge 9033 commits intobeetbox:masterfrom
Open
fetchart: handle sources config given as plain string#6437wavebyrd wants to merge 9033 commits intobeetbox:masterfrom
wavebyrd wants to merge 9033 commits intobeetbox:masterfrom
Conversation
…x#5926) Creating indexes turned out to be relatively straightforward! While we can’t remove them yet, that doesn’t seem necessary for now. Interestingly, much of the infrastructure for database additions was already in place. - This PR introduces a new type, `Index`, which can be used to create an index on any defined table. 🎉 - The `items` table now automatically registers an index on `album_id` Closes beetbox#5809
Fixes a bug where existing tags were set to None, if they weren't whitelisted, but an whitelisted canonicalized parent existed up the tree. In all other cases, the original genres are canonicalized and considered for the final genre, except in the keep_existing logic branch. This PR fixes the issue and results in the expected behavior for this combination of options. For the bug to trigger several conditions had to be met: - Canonicalization is enabled and a whitelist is specified. - `force` and `keep_existing` are set. Meaning, that Lastfm is queried for a genre, but the existing genres are still left around when none are found online. - A release with a non-whitelisted genre exists, but that genre has a whitelisted genre parent up the tree. - That very release has no genre on lastfm. This is rather convoluted, but stay with me :D What would happen is the following: - `keep_genres` is set to the existing genres, as `force` and `keep_existing` is set. - Genres for `track`/`album`/`artist` aren't found for this release, as they don't exist in lastfm. - Then the `keep_existing` logic is entered. - The old logic only checks if the existing genres have an **exact** match for the whitelist. In contrast to all other code branches, we don't do the `_try_resolve_stage` in case there's no direct match, resulting in no match. - We continue to the fallback logic, which returns the fallback (`None` in my case) This patch results in one last try to resolve the existing genres when `keep_existing` is set, which includes canonicalization (if enabled).
Found a couple of additional historical commits that added noise to git blame and which should be ignored.
- Update the MusicBrainz integration to read the release group's canonical `'primary-type'` field instead of the legacy `'type'` field when deriving `info.albumtype`. Noticed that `albumtype` was missing from the metadata when I did some imports in my library.
the autotag process.
When a metadata plugin raises an exception during the auto-tagger process, the entire operation crashes. This behavior is not desirable, since metadata lookups can legitimately fail for various reasons (e.g., temporary API downtime, network issues, or offline usage). This PR introduces a safeguard by adding general exception handling around metadata plugin calls. Instead of causing the whole process to fail, exceptions from individual plugins are now caught and logged. This ensures that the auto-tagger continues to function with the remaining available metadata sources. I used a proxy pattern here as this seems like an elegant solution to me. This replaces the efforts from beetbox#5910
Fixes beetbox#6291 I think it does not hurt if the imported_items() method returned an empty list instead of an throwing an exception if there is nothing in it!
Fixes beetbox#6332 - Promotes `packaging` from a release-only dependency to a required runtime dependency by moving it into `pyproject.toml`'s main dependencies. - Updates `poetry.lock` to pick up patched versions of vulnerable libraries, notably `brotli` (`1.1.0` → `1.2.0`), `urllib3` (`2.5.0` → `2.6.3`), `werkzeug` (`3.1.3` → `3.1.5`), and `filelock` (`3.20.2` → `3.20.3`). <img width="442" height="169" alt="image" src="https://github.com/user-attachments/assets/fe70475e-0163-4d45-b1e4-362008669c00" />
Add a helper to lower/strip and escape Lucene query syntax. Use it when building search queries and add unit tests.
These functions now accept both an ID and data_source parameter, enabling plugins like mbsync and missing to retrieve metadata from the correct source. Update mbsync and missing plugins to use the restored functions with explicit data_source parameters. Add data_source validation to prevent lookups when the source is not specified. Add get_metadata_source helper function to retrieve plugins by their data_source name, cached for performance.
Closes beetbox#6178 (multiple metadata source results per ID) and beetbox#6181 (duplicate/overwrite of candidates). - (beetbox#6178) Replace `album_for_id` / `track_for_id` with `albums_for_ids` / `tracks_for_ids` in `metadata_plugins` that yield candidates from all metadata sources - (beetbox#6181) Use `Info.identifier` (`(data_source, id)`) as candidate keys to avoid cross-source ID collisions. - Add tests (`test/autotag/test_match.py`) for assignment logic and multi-source ID matching - Simplify `match_by_id` - Dedupe `album_matched` event emission by moving it to `AlbumMatch.__post_init__` (and convert `AlbumMatch` / `TrackMatch` to dataclasses)
…rack-album * official/master: (54 commits) Require data_source in album_for_id and track_for_id functions Invoke album_matched hook from AlbumMatch.__post_init__ Refactor match_by_id Take data source into account when deciding duplicate candidates Return album candidates from multiple sources when matching by IDs Add a test to reproduce the issue Move assignment tests to test/autotag/test_match.py Pulled latest changelog and added my entry to 'Unreleased > Bug fixes' section. Moved changelog note to top, under Unreleased. This PR improves the regex detection used for the drive_sep_replace default. This PR improves the regex detection used for the drive_sep_replace default. refactor: Use deprecate_for_user for beatport/bpsync deprecation warnings Fix docs: use single-line deprecated directive compatible with docstrfmt Fix docs formatting for beatport and bpsync rst files Deprecate beatport and bpsync plugins Update changelog.rst try to fix fish plugin Make get_search_query_with_filters abstract Document new methods Document shared metadata search plugin workflow ...
> This PR add support for aliases to releases, release-groups and recordings. > This PR is a must have (IMO at least) for people that listen to Japanese, Chinese and other songs that has other symbols for letters. With this, not only the artist name will use the alias if available, but now the album and track name will also use aliases. Follow up from beetbox#5277 based on the recent new mechanism to query musicbrainz (beetbox#6052). ## API examples - Aliases for releases, recordings and release groups: http://musicbrainz.org/ws/2/release/59211ea4-ffd2-4ad9-9a4e-941d3148024a?inc=recordings+aliases+release-groups&fmt=json - Aliases for recordings: https://musicbrainz.org/ws/2/recording/b9ad642e-b012-41c7-b72a-42cf4911f9ff?inc=aliases&fmt=json
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
…tbox#6427) Fixes beetbox#5993 The section is outdated. MacOS (or HomeBrew's python package?) by default disallows using `pip3 install` even with `--user` option. I'd actually propose to add more information around how to use `pipx` in this installation guide to install beets and its plugins (both provided as extras and third-party), maybe even make it the main focus of this page as a recommended way regardless of which OS and Linux distro is used. I can create a separate issue/discussion to discuss and align on this if it's fine by you.
## Enforce Changelog Entries Under 'Unreleased' Section
I've had enough checking this manually 😆. Adds a CI lint step
that prevents contributors from accidentally adding changelog entries
under an already-released version header in `docs/changelog.rst`.
### How it works
The check runs `git diff --word-diff=plain -U1000` against the base
branch, then pipes through `awk` to scan the diff for new list entries
(`{+- ...`) that appear after any versioned release header (e.g. `1.2.3
(`). If such an entry is found, the step fails with a human-readable
error pointing to the offending line which GitHub should show in the
diff view.
* `--word-diff=plain` is required to match _truly new_ changelog entries
instead of some formatting adjustments in the middle of the line.
* `-U1000` should ensure that we grab the first 1000 lines in the
changelog to reliably match the headers.
…, reset config in test
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
Formatting fix
Fixes beetbox#6412. This is my first time submitting a PR for an open source project so please point out any mistakes! ## Summary - Add `discogs.extra_tags` configuration option to narrow Discogs search queries using existing tag values. - Map supported tags (`barcode`, `catalognum`, `country`, `label`, `media`, `year`) to corresponding Discogs search parameters. - Update Discogs plugin documentation and tests to cover the new behavior. ## Details The Discogs plugin now mirrors `musicbrainz.extra_tags` by allowing users to specify additional tags that should be used when building Discogs search filters. - New config option: `discogs.extra_tags` (default: `[]`). - Supported tags and their Discogs search parameters: - `barcode` → `barcode` - `catalognum` → `catno` (whitespace removed) - `country` → `country` - `label` → `label` - `media` → `format` - `year` → `year` - Tags `alias` and `tracks` are recognized but intentionally ignored for Discogs, since the Discogs API does not provide direct equivalents for these MusicBrainz-specific fields. When `extra_tags` are configured, the plugin uses `beets.util.plurality` over the items in the import session to select the most common value for each configured tag and adds the corresponding Discogs filter. ## Testing - Added unit tests in `test/plugins/test_discogs.py` to verify: - Default search filters remain unchanged when `extra_tags` is not set. - `discogs.extra_tags: [label, catalognum]` results in `label` and `catno` filters populated from library items (with catalog number whitespace stripped). - Ran: - `pytest test/plugins/test_discogs.py` - `pytest test/plugins/test_musicbrainz.py`
When the 'sources' config is a plain string (e.g. "sources: filesystem" rather than "sources: [filesystem]"), confuse 2.2.0's Pairs template iterates over individual characters instead of treating it as a single source name. This is because Pairs no longer inherits StrSeq's string-to-list normalization. Normalize the config value to a list before calling as_pairs() so both forms work correctly. Fixes beetbox#6336
snejus
reviewed
Mar 13, 2026
| if isinstance(raw_sources, str): | ||
| self.config["sources"].set(raw_sources.split()) | ||
| sources = sanitize_pairs( | ||
| self.config["sources"].as_pairs(default_value="*"), |
Member
There was a problem hiding this comment.
Is it not possible to simply
Suggested change
| self.config["sources"].as_pairs(default_value="*"), | |
| self.config["sources"].as_str_seq(), |
?
af6def0 to
3763b9b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fetchartfailing with "no art found" whensourcesis configured as a plain string (e.g.sources: filesystem) instead of a list (sources: [filesystem]).Pairstemplate no longer inheritsStrSeq's string-to-list normalization, so a bare string gets iterated character by character. This normalizes the value to a list before passing it toas_pairs().sourcesconfig.Fixes #6336
Related: #5962
Test plan
sources: filesystem(string),sources: [filesystem](list), andsources: filesystem coverart(space-separated string) all produce the correct source objects