Commit graph

13532 commits

Author SHA1 Message Date
w4grfw
57bd3189df Fix #6302: musicbrainz: crash when releases lack the "track" key. 2026-02-11 16:26:00 +01:00
Šarūnas Nejus
bc52682428
Improve GitHub release rendering (#6356)
This PR hardens the release/changelog generation pipeline so ReST ->
Markdown conversion produces stable, correctly formatted links and
inline code.

- Fix broken rendering of generated references by ensuring RST
`~`-shortened forms like ``` `:class:`~beetsplug._utils...``` are
converted into real Markdown links.
- Updates `extra/release.py` to generate clearer link text for CLI
command refs (e.g., `list-cmd` becomes 'list command') while keeping the
same documentation targets.
- Simplifies the Markdown post-processing step by removing the redundant
`MD_REPLACEMENTS` layer, reducing ad-hoc formatting logic in the release
script.
- Standardizes changelog section header structure in
`docs/changelog.rst` (and the release template) to align with
Sphinx/ReST conventions and avoid ambiguous colon-based headers.
- Strengthens CI by extending `lint-docs` in `pyproject.toml` to fail on
single-backtick inline literals in `.rst`, enforcing double-backtick
literals so `pandoc` does not emit meaningless `<span
class="title-ref">...` output that breaks Markdown rendering.

Net effect: more predictable release notes output, fewer conversion edge
cases, and earlier detection of docs formatting that would render
incorrectly downstream.
2026-02-10 23:59:38 +00:00
Šarūnas Nejus
6dbee2437e
Fix fetching large MusicBrainz releases (#6357)
Fixes #6355 

- Fix `plugins/musicbrainz` handling of very large MusicBrainz releases
by passing the missing `limit` and `includes` kwargs to
`mb_api.browse_recordings`.
2026-02-08 21:18:16 +00:00
Šarūnas Nejus
838681790c
Name these track/recording vars properly 2026-02-08 11:09:59 +00:00
Šarūnas Nejus
9f4c94f512
Provide missing kwargs to musicbrainz browse 2026-02-08 11:09:59 +00:00
Šarūnas Nejus
4fd5c5ef79
Fix single backticks issues 2026-02-08 08:01:31 +00:00
Šarūnas Nejus
e4314b700f
Add rst inline-literal check to lint-docs task
Fail the docs lint task when single-backtick inline literals are used.

This is required because `pandoc` converts:

  `$playlist` -> <span class="title-ref">\$playlist</span>

Where this `span` element has no meaning in markdown context, and
`$playlist` loses its formatting. On the other hand, double backticks
are converted appropriately:

  ``$playlist`` -> `$playlist`
2026-02-08 07:28:09 +00:00
Šarūnas Nejus
1eb74aa740
Improve reference title for command links 2026-02-08 07:28:09 +00:00
Šarūnas Nejus
575f539282
Remove redundant MD_REPLACEMENTS 2026-02-08 07:28:09 +00:00
Šarūnas Nejus
616a674db0
Properly format changelog section headers 2026-02-08 07:28:08 +00:00
Šarūnas Nejus
10d8e5fc04
Sort changelog bullet points case-insensitively
Use a case-insensitive sort key when ordering Markdown changelog bullet
points to produce stable ordering regardless of capitalization.

Diff for the last release:

diff --git a/before b/after
index 51303c65f..d88eda894 100644
--- a/before
+++ b/after
@@ -4,3 +4,2 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee

-- Added support for Python 3.13.
 - [Convert Plugin](https://beets.readthedocs.io/en/stable/plugins/convert.html): `force` can be passed to override checks like no_convert, never_convert_lossy_files, same format, and max_bitrate
@@ -23,2 +22,3 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee
 - [Titlecase Plugin](https://beets.readthedocs.io/en/stable/plugins/titlecase.html): Add the [Titlecase Plugin](https://beets.readthedocs.io/en/stable/plugins/titlecase.html) plugin to allow users to resolve differences in metadata source styles.
+- Added support for Python 3.13.

@@ -26,9 +26,2 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee

-- Errors in metadata plugins during autotage process will now be logged but won't crash beets anymore. If you want to raise exceptions instead, set the new configuration option `raise_on_error` to `yes` 🐛 (#5903), 🐛 (#4789).
-- Fix a bug introduced in release 2.4.0 where import from any valid import-log-file always threw a "none of the paths are importable" error.
-- Handle potential OSError when unlinking temporary files in ArtResizer. 🐛 (#5615)
-- Running <span class="title-ref">beet --config \<mypath\> config -e</span> now edits <span class="title-ref">\<mypath\></span> rather than the default config path. 🐛 (#5652)
-- Sanitize log messages by removing control characters preventing terminal rendering issues.
-- When hardlinking from a symlink (e.g. importing a symlink with hardlinking enabled), dereference the symlink then hardlink, rather than creating a new (potentially broken) symlink 🐛 (#5676)
-- When using [FromFilename Plugin](https://beets.readthedocs.io/en/stable/plugins/fromfilename.html) together with [Edit Plugin](https://beets.readthedocs.io/en/stable/plugins/edit.html), temporary tags extracted from filenames are no longer lost when discarding or cancelling an edit session during import. 🐛 (#6104)
 - [Command-Line Interface](https://beets.readthedocs.io/en/stable/reference/cli.html): Fix 'from_scratch' option for singleton imports: delete all (old) metadata when new metadata is applied. 🐛 (#3706)
@@ -44,4 +37,11 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee
 - [Spotify Plugin](https://beets.readthedocs.io/en/stable/plugins/spotify.html): Updated Spotify API credentials. 🐛 (#6270)
-- [Web Plugin](https://beets.readthedocs.io/en/stable/plugins/web.html): repair broken <span class="title-ref">/item/values/…</span> and <span class="title-ref">/albums/values/…</span> endpoints. Previously, due to single-quotes (ie. string literal) in the SQL query, the query eg. <span class="title-ref">GET /item/values/albumartist</span> would return the literal "albumartist" instead of a list of unique album artists.
 - [update](https://beets.readthedocs.io/en/stable/reference/cli.html#update-cmd) [Edit Plugin](https://beets.readthedocs.io/en/stable/plugins/edit.html) fix display formatting of field changes to clearly show added and removed flexible fields.
+- [Web Plugin](https://beets.readthedocs.io/en/stable/plugins/web.html): repair broken <span class="title-ref">/item/values/…</span> and <span class="title-ref">/albums/values/…</span> endpoints. Previously, due to single-quotes (ie. string literal) in the SQL query, the query eg. <span class="title-ref">GET /item/values/albumartist</span> would return the literal "albumartist" instead of a list of unique album artists.
+- Errors in metadata plugins during autotage process will now be logged but won't crash beets anymore. If you want to raise exceptions instead, set the new configuration option `raise_on_error` to `yes` 🐛 (#5903), 🐛 (#4789).
+- Fix a bug introduced in release 2.4.0 where import from any valid import-log-file always threw a "none of the paths are importable" error.
+- Handle potential OSError when unlinking temporary files in ArtResizer. 🐛 (#5615)
+- Running <span class="title-ref">beet --config \<mypath\> config -e</span> now edits <span class="title-ref">\<mypath\></span> rather than the default config path. 🐛 (#5652)
+- Sanitize log messages by removing control characters preventing terminal rendering issues.
+- When hardlinking from a symlink (e.g. importing a symlink with hardlinking enabled), dereference the symlink then hardlink, rather than creating a new (potentially broken) symlink 🐛 (#5676)
+- When using [FromFilename Plugin](https://beets.readthedocs.io/en/stable/plugins/fromfilename.html) together with [Edit Plugin](https://beets.readthedocs.io/en/stable/plugins/edit.html), temporary tags extracted from filenames are no longer lost when discarding or cancelling an edit session during import. 🐛 (#6104)

@@ -71,2 +71,4 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee

+- [BPD Plugin](https://beets.readthedocs.io/en/stable/plugins/bpd.html): Raise ImportError instead of ValueError when GStreamer is unavailable, enabling `importorskip` usage in pytest setup.
+- dbcore: Allow models to declare SQL indices; add an `items.album_id` index to speed up `album.items()` queries. 🐛 (#5809)
 - Finally removed gmusic plugin and all related code/docs as the Google Play Music service was shut down in 2020.
@@ -76,3 +78 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee
 - Updated color documentation with `bright_*` and `bg_bright_*` entries.
-- [BPD Plugin](https://beets.readthedocs.io/en/stable/plugins/bpd.html): Raise ImportError instead of ValueError when GStreamer is unavailable, enabling `importorskip` usage in pytest setup.
-- dbcore: Allow models to declare SQL indices; add an `items.album_id` index to speed up `album.items()` queries. 🐛 (#5809)
2026-02-08 07:20:44 +00:00
Šarūnas Nejus
50959bb316
Fix rendering generated refs
This specifically fixes v2.6.0 changelog:

diff --git a/before b/after
index dc9a2ecd2..51303c65f 100644
--- a/before
+++ b/after
@@ -51,3 +51,3 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee

-- Added a reusable requests handler which can be used by plugins to make HTTP requests with built-in retry and backoff logic. It uses beets user-agent and configures timeouts. See `~beetsplug._utils.requests.RequestHandler` for documentation.
+- Added a reusable requests handler which can be used by plugins to make HTTP requests with built-in retry and backoff logic. It uses beets user-agent and configures timeouts. See [beetsplug.\_utils.requests.RequestHandler](https://beets.readthedocs.io/en/stable/api/generated/beetsplug._utils.requests.RequestHandler.html#beetsplug._utils.requests.RequestHandler) for documentation.

@@ -62,3 +62,3 @@ Beets now requires Python 3.10 or later since support for EOL Python 3.9 has bee

-  See `~beetsplug._utils.musicbrainz.MusicBrainzAPI` for documentation.
+  See [beetsplug.\_utils.musicbrainz.MusicBrainzAPI](https://beets.readthedocs.io/en/stable/api/generated/beetsplug._utils.musicbrainz.MusicBrainzAPI.html#beetsplug._utils.musicbrainz.MusicBrainzAPI) for documentation.
2026-02-08 07:20:44 +00:00
Šarūnas Nejus
3b89d722ea
Fix mb search term formatting (#6354)
Fixes #6347

- Fixed MusicBrainz Lucene query formatting in
`MusicBrainzAPI.format_search_term()` (lowercase + trim + escape Lucene
special chars).
- Fixed `plugins.musicbrainz:extra_tags` support by mapping `alias` and
`tracks` into MusicBrainz search fields.
- Adjusted logging to make MusicBrainz API logs visible under the shared
`beets` logger (and removed an unused per-module logger in
`beetsplug.bpd`).
2026-02-08 07:20:11 +00:00
Šarūnas Nejus
bf6c0a1bdf
Disable Tekstowo by default as they block requests with the beets UA (#6344) 2026-02-08 01:29:30 +00:00
Šarūnas Nejus
8f81e1d913
Update ownership 2026-02-07 22:41:17 +00:00
Šarūnas Nejus
df1573ce9d
Make MusicBrainzAPI logs visible 2026-02-07 22:36:43 +00:00
Šarūnas Nejus
84b22fddd5
Order mbcollection, mbpseudo, mbsubmit after musicbrainz plugin in docs 2026-02-07 22:28:00 +00:00
Šarūnas Nejus
aeee7b6da4
Musicbrainz: Fix support for alias, tracks extra tags 2026-02-07 22:26:52 +00:00
Šarūnas Nejus
1271b711f7
Format MusicBrainz search terms and escape Lucene special chars
Add a helper to lower/strip and escape Lucene query syntax.
Use it when building search queries and add unit tests.
2026-02-07 22:26:17 +00:00
Kirill A. Korinsky
1d8c378e9f
Disable Tekstowo by default as they block requests with the beets UA 2026-02-03 02:18:59 +01:00
snejus
cdfb813910 Increment version to 2.6.1 2026-02-02 02:29:04 +00:00
Šarūnas Nejus
d65e37cba0
Fix dependencies (#6333)
Fixes #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"
/>
2026-02-02 02:27:06 +00:00
Šarūnas Nejus
9d7d3ae7b0
Update vulnerable dependencies 2026-02-02 02:18:51 +00:00
Šarūnas Nejus
b6230a84fc
Make packaging a required dependency 2026-02-02 02:16:36 +00:00
snejus
680473b9e5 Increment version to 2.6.0 2026-02-01 14:42:50 +00:00
Šarūnas Nejus
b2335b984d
Fix crash in task.imported_items (#6326)
Fixes #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!
2026-01-31 23:54:07 +00:00
J0J0 Todos
d2600c354c Fix crash in task.imported_items 2026-01-31 23:48:43 +00:00
Šarūnas Nejus
f9cf15732c
Safely handle metadata plugin exceptions. (#5965)
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 #5910
2026-01-31 23:47:56 +00:00
Šarūnas Nejus
2196bd89de Simplify tests 2026-01-31 23:42:09 +00:00
Šarūnas Nejus
cb6ad89ce6 Use a decorator-based approach 2026-01-31 23:42:09 +00:00
Sebastian Mohr
8e0b3f1323 Moved config check into find_metadata_source_plugins func. 2026-01-31 23:42:09 +00:00
Sebastian Mohr
5cbdab40d2 Renamed variable to use protected names. 2026-01-31 23:42:09 +00:00
Sebastian Mohr
cfba015998 Fixed cache clear issue. 2026-01-31 23:42:09 +00:00
Sebastian Mohr
4511a37699 Added default config and simplified proxy class. 2026-01-31 23:42:09 +00:00
Sebastian Mohr
3388882c21 Added a proxy to catch and handle exceptions in metadataplugins during
the autotag process.
2026-01-31 23:42:09 +00:00
Šarūnas Nejus
0cde654ffe
musicbrainz: fix release type (#6299)
- 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.
2026-01-31 18:11:21 +00:00
Šarūnas Nejus
8f514eb6ab Replace/fix Release.type with Release.primary-type 2026-01-31 18:05:18 +00:00
Šarūnas Nejus
ea7a0ce370
Extend git blame ignore revs (#6310)
Found a couple of additional historical commits that added noise to git
blame and which should be ignored.
2026-01-31 18:04:52 +00:00
Šarūnas Nejus
5b48701ba1 Add missing commits to git blame ignore revs 2026-01-31 17:59:45 +00:00
J0J0 Todos
a327c28470
fix(lastgenre): Canonicalize keep_existing fallback (#6303) 2026-01-31 13:27:35 +01:00
Arne Beer
4d7b9cb14b fix(lastgenre): Canonicalize keep_existing fallback
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).
2026-01-31 13:22:56 +01:00
Šarūnas Nejus
aaf046e6bd
Add support for creating indices on arbitrary database tables (#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 #5809
2026-01-30 21:42:49 +00:00
Šarūnas Nejus
cde73cc433
Add changelog note 2026-01-30 01:18:11 +00:00
Šarūnas Nejus
a17857213b
Fix lints 2026-01-30 01:06:31 +00:00
Šarūnas Nejus
fc54f809a1
Merge branch 'master' into indices 2026-01-30 01:03:18 +00:00
Šarūnas Nejus
e768f978b6
Simplify creating indices 2026-01-30 00:55:13 +00:00
Šarūnas Nejus
838a94d931
Retries with 1, 2, 4, 8, 16, 32s backoff (#6322)
At least it allows me to more or less use MusicBrainz, and makes issues
from #6312 almost not noticible
2026-01-30 00:50:57 +00:00
Kirill A. Korinsky
48c954edf6 Nuked tests 2026-01-30 00:46:13 +00:00
Kirill A. Korinsky
47b1644110 Attemt to rework tests 2026-01-30 00:46:13 +00:00
Kirill A. Korinsky
78b6d537b6 Retries with 1, 2, 4, 8, 16, 32s backoff
At least it allows me to more or less use MusicBrainz
2026-01-30 00:46:13 +00:00