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.
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`).
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).
mp3rgain is a modern Rust rewrite of mp3gain that provides:
- CLI-compatible drop-in replacement for mp3gain
- Support for both MP3 and AAC/M4A formats (like aacgain)
- Fixes for CVE-2021-34085 (Critical, CVSS 9.8) and CVE-2019-18359 (Medium)
- Memory-safe implementation in Rust
- Works on modern systems (Windows 11, macOS Apple Silicon)
Changes:
- Add mp3rgain to the command search list (prioritized first)
- Update format_supported() with more robust command name detection
using os.path.basename() and startswith() instead of substring matching
- Update documentation with installation instructions
See: https://github.com/M-Igashi/mp3rgain
Looks like our hard-coded API credentials expired. This PR removes
expired credentials and makes it clear to the user that they must
provide their credentials.
Fixes#6270
* master: (37 commits)
importsource: Test skip, Test reimport-skip
Fix initial importsource plugin #4748 changelog
importsource: fix potential prevent_suggest_removal crash
Ensure that inc are joined with a plus
Add retries for connection errors
Add Usage block to RequestHandler
Refactor HTTP request handling with RequestHandler base class
Make musicbrainzngs dependency optional and requests required
musicbrainz: remove error handling
musicbrainz: access the custom server directly, if configured
musicbrainz: browse directly
musicbrainz: search directly
musicbrainz: lookup recordings directly
musicbrainz: lookup release directly
Move pseudo release lookup under the plugin
Add missing blame ignore revs from musicbrainz plugin
Define MusicBrainzAPI class with rate limiting
Move TimeoutSession under beetsplug._utils
expand tests to include check for track artists
remove changes for lastgenre as there was an existing PR for that work
...
- Prioritize explicit featuring tokens (feat, ft, featuring) over generic
separators (&, and) when splitting artist names
- Prevents incorrect splits like 'Alice & Bob feat Charlie' from splitting
on '&' instead of 'feat'
- Add test cases to verify the fix
## Description
Fixes#5625
When `convert.never_convert_lossy_files` is enabled, `beet convert` was
ignoring the explicit `--format` option and just copying the lossy files
without
transcoding them. For example:
- `beet convert format:mp3 --format opus`
would still produce MP3 files instead of OPUS.
Change:
- Allows to override options `never_convert_lossy_files`, `max_bitrate`
or `no_convert` for `beet convert` as well as trying to convert to the
same format as existing already with a new option `--force`. That way,
for example lossy files selected by the query are transcoded to the
requested format anyway.
- Keeps existing behavior for automatic conversion on import (no CLI
override there).
- Adds tests to cover checking whether `--force` correctly overrides
settings or CLI options.
- Documents the behavior in the convert plugin docs
Co-authored-by: J0J0 Todos <jojo@peek-a-boo.at>
Added regex pattern to strip C0/C1 control characters (excluding useful
whitespace) from log messages before terminal output. This prevents
disruptive/malicious control sequences from affecting terminal
rendering.
This plugin aims to address the shortcomings of the %title function, as
brought up in issues #152, #3298 and an initial look to improvement with
#3411. It supplies a new string format command, `%titlecase` which
doesn't interfere with any prior expected behavior of the `%title`
format command.
It also adds the ability to apply titlecase logic to metadata fields
that a user selects, which is useful if you, like me, are looking for
stylistic consistency and the minor stylistic differences between
Musizbrainz, Discogs, Deezer etc, with title case are slightly
infuriating.
This will add an optional dependency of
[titlecase](https://pypi.org/project/titlecase/), which allows the
titlecase core logic to be externally maintained.
If there's not enough draw to have this as a core plugin, I can also
spin this into an independent one, but it seemed like a recurring theme
that the %title string format didn't really behave as expected, and I
wanted my metadata to match too.
- [x] Documentation. (If you've added a new command-line flag, for
example, find the appropriate page under `docs/` to describe it.)
- [x] Changelog. (Add an entry to `docs/changelog.rst` to the bottom of
one of the lists near the top of the document.)
- [x] Tests. - Not 100% coverage, but didn't see a lot of other plugins
with testing for import stages.
pytest.importskip is used to catch the case when beetsplug.bpd cannot be
imported. On macOS, the gi module was able to be imported, but when
trying to specify `gi.require_version`, a ValueError is raised about
Gst being unavailable. pytest does not catch this ValueError during
importskip as it is not an ImportError, and thus the test suite errors
during the test collection phase.
With this change, we catch the ValueError, and re-raise it as an
ImportError and pytest gracefully skips those tests.
Following #4709 and #5447, the web plugin used single-quotes (ie. string
litteral) in the SQL query for table columns. Thus, for instance, the query
`GET /item/values/albumartist` would return the litteral "albumartist"
instead of a list of unique album artists.
Add a dedicated AudioFeaturesUnavailableError and track audio-features
availability with an audio_features_available flag. If the audio-features
endpoint returns HTTP 403, raise the new error, log a warning once, and
disable further audio-features requests for the session. The plugin now
skips attempting audio-features lookups when disabled (avoiding repeated
failed calls and potential rate-limit issues).
Also update changelog to document the behavior.
…file is placed in the command
## Description
see included doc; placing the playlist filename at the end of command
just isn't working for all players
I have this in use with `mpv`
Co-authored-by: cvx35isl <cvx35isl@users.noreply.github.com>
Co-authored-by: J0J0 Todos <2733783+JOJ0@users.noreply.github.com>
Create a custom Sphinx extension to document configuration values with
a simplified syntax. It is based on the `confval` but takes less space
when rendered. The extension provides:
- A `conf` directive for documenting individual configuration values
with optional type and default parameters
- A `conf` role for cross-referencing configuration values
- Automatic formatting of default values in the signature
- A custom domain that handles indexing and cross-references
For example, if we have
.. conf:: search_limit
:default: 5
We refer to this configuration option with :conf:`plugins.discogs:search_limit`.
The extension is loaded by adding the docs/extensions directory to the
Python path and registering it in the Sphinx extensions list.
## Description
For non English tracks (Swedish in my case) feat. words might be
something that ftintitle doesn't pick up.
Eg. for the song `Promoe med Afasi - Inflation`
[https://musicbrainz.org/recording/8e236347-61d6-4e11-9980-52f4cc6b905f](https://musicbrainz.org/recording/8e236347-61d6-4e11-9980-52f4cc6b905f)
the word `med` is `feat.` in Swedish.
With this PR you can add what ever word you wish to match as feat. so it
should cover any kind of language.
The config.yaml could look like this:
ftintitle:
custom_feat_words: ["med"]
## To Do
<!--
- If you believe one of below checkpoints is not required for the change
you
are submitting, cross it out and check the box nonetheless to let us
know.
For example: - [x] ~Changelog~
- Regarding the changelog, often it makes sense to add your entry only
once
reviewing is finished. That way you might prevent conflicts from other
PR's in
that file, as well as keep the chance high your description fits with
the
latest revision of your feature/fix.
- Regarding documentation, bugfixes often don't require additions to the
docs.
- Please remove the descriptive sentences in braces from the enumeration
below,
which helps to unclutter your PR description.
-->
- [x] Documentation. (If you've added a new command-line flag, for
example, find the appropriate page under `docs/` to describe it.)
- [x] Changelog. (Add an entry to `docs/changelog.rst` to the bottom of
one of the lists near the top of the document.)
- [x] Tests. (Very much encouraged but not strictly required.)