Commit graph

13573 commits

Author SHA1 Message Date
dunkla
c55b6d103c
shorte test description in test/plugins/test_lastgenre.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-23 05:11:37 +00:00
dunkla
1c0ebcf348
remove noisy comment from test/plugins/test_beatport.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-23 05:11:36 +00:00
Johann Fot
70bf57baf6
Add native support for multiple genres per album/track
Simplify multi-genre implementation based on maintainer feedback (PR #6169).

Changes:
- Remove multi_value_genres and genre_separator config options
- Replace complex sync_genre_fields() with ensure_first_value('genre', 'genres')
- Update all plugins (Beatport, MusicBrainz, LastGenre) to always write genres as lists
- Add automatic migration for comma/semicolon/slash-separated genre strings
- Add 'beet migrate genres' command for explicit batch migration with --pretend flag
- Update all tests to reflect simplified approach (44 tests passing)
- Update documentation

Implementation aligns with maintainer vision of always using multi-value genres
internally with automatic backward-compatible sync to the genre field via
ensure_first_value(), eliminating configuration complexity.

Migration strategy avoids problems from #5540:
- Automatic lazy migration on item access (no reimport/mbsync needed)
- Optional batch migration command for user control
- No endless rewrite loops due to proper field synchronization
2026-02-23 05:11:36 +00:00
Šarūnas Nejus
dcef1f4ea4
Create .instructions.md for Copilot
Let's test this
2026-02-23 05:09:03 +00:00
Šarūnas Nejus
fa564a05a1
Add @snejus to docs/team.rst (#6389)
I thought it was time to add an entry for myself to `docs/team.rst`.
2026-02-23 04:01:23 +00:00
Šarūnas Nejus
6fe7a9a7d3
Add @snejus to team 2026-02-23 03:54:20 +00:00
Šarūnas Nejus
2ea7886c0c
Fix handling multi valued fields (#6387)
While working on #6367 I noticed that users are currently required to
use our internal separator `\␀` in order to edit multi-valued fields,
for example `beet modify artists='a\␀b'`.

Similarly, this separator is used in output, for example, reporting of
field changes:

```
$ beet modify path::aaa artists='a\␀b'
Modifying 8 items.
54898 | 2022 / RAVE SLUTZ: Fallen Shrine & dj Christian NXC - DEEEJAAAY
  artists: Fallen Shrine\␀dj Christian NXC -> a\␀b
```

This PR replaces `\␀` separator with `; ` for input and formats changes
in multi-valued fields clearly:

```
$ beet modify path::aaa artists='a; b'
54898 | 2022 / RAVE SLUTZ: Fallen Shrine & dj Christian NXC - DEEEJAAAY
  artists:
    - Fallen Shrine
    - dj Christian NXC
    + a
    + b
```
<img width="539" height="142" alt="image"
src="https://github.com/user-attachments/assets/72299db1-d0f8-4f8f-9f30-65caaac85d9e"
/>


### Architecture-level changes

- `DelimitedString` now separates concerns between:
  - database serialization via `db_delimiter` (`to_sql`)
- user-facing/template formatting via a fixed `'; '` delimiter
(`format`)
  - parsing that accepts both DB and user-facing separators (`parse`)
- Field diff rendering now has a dedicated path for list fields:
  - `_field_diff` detects list values
- `_multi_value_diff` computes set-based added/removed entries and
renders per-item diff lines
- Coloring responsibilities were streamlined:
  - raw ANSI application moved to `_colorize`
  - `colorize` is now only the feature-flag/environment gate
- `colordiff` is reduced to string diff highlighting logic, with
redundant wrapper logic removed

### High-level impact

- Multi-valued fields behave consistently between DB storage and
CLI/template usage (`'; '` for user input/output, DB delimiter
internally).
- Diff output for list fields is much more readable, showing explicit
`+`/`-` item-level changes instead of generic string diffs.
- Docs and tests were updated to reflect the new multi-value behavior,
including `%first` usage and `beet modify` examples.
2026-02-23 01:14:28 +00:00
Šarūnas Nejus
edfe00516f
Handle DelimitedString fields as native lists in edit plugin
Treat DelimitedString as a safe YAML-editable type in the edit plugin,
allowing multi-valued fields to be edited as native lists.
2026-02-23 00:33:24 +00:00
Šarūnas Nejus
4699958f25
Remove redundant coloring logic 2026-02-22 16:13:21 +00:00
Šarūnas Nejus
31f79f14a3
Colorize multi-valued field changes distinctly 2026-02-22 16:13:20 +00:00
Šarūnas Nejus
9d237d10fc
Fix multi-value delimiter handling in templates
- Use '\␀' as the DB delimiter while formatting lists with '; ' for
templates.
- Update DelimitedString parsing to accept both separators:
  * '\␀' for the values from the DB
  * '; ' for the rest of parsed values (for example `beet modify genres="eletronic; jazz"`)
- Refresh %first docs and tests to reflect multi-value field behavior.
2026-02-22 16:12:58 +00:00
snejus
13e978ca0e Increment version to 2.6.2 2026-02-22 16:04:40 +00:00
Šarūnas Nejus
940e94c48c
Fix missing artist-credit field in mbpseudo (#6388)
Fixes #6339

This change moves MusicBrainz lookup defaults into
`beetsplug/_utils/musicbrainz.py` so `MusicBrainzAPI` now owns the
default `includes` for both `get_release` and `get_recording`.

#### Architecture impact

- Added centralized defaults: `RELEASE_INCLUDES` and
`RECORDING_INCLUDES` in `MusicBrainzAPI`.
- Updated `get_release` and `get_recording` to apply these defaults via
`kwargs.setdefault("includes", ...)`.
- Removed duplicated include lists from `beetsplug/musicbrainz.py` and
simplified call sites to `self.mb_api.get_release(...)` /
`self.mb_api.get_recording(...)` without passing includes explicitly.

#### High-level result

- Ensures consistent MusicBrainz payload shape across callers.
- Fixes the `mbpseudo` failure caused by missing `artist_credit` data in
some responses.
- Reduces coupling and duplication by making include policy an API-layer
concern.
2026-02-22 11:55:17 +00:00
Šarūnas Nejus
1930400ab8
Set default release/recording includes in MusicBrainzAPI 2026-02-22 02:09:25 +00:00
Šarūnas Nejus
07d3e05a91
Fix replaygain paths for mp3gain/aacgain on Windows / fix tests (#6373)
## PR Summary

Fixes #2946
Fixes #6335

Replaygain plugin tests used a **fragmented configuration approach**:
each backend mixin set only `backend` as a class variable, while
additional `command` configuration was required for `CmdBackendMixin`.

### Key changes

- **`CmdBackendMixin`** now explicitly sets `"command": "mp3gain"`
alongside the backend name.
- All tests now reference plugin-scoped `self.config` configuration
instead of global one.
- The `GAIN_PROG_AVAILABLE` check now also looks for `mp3rgain` in
addition to `mp3gain` and `aacgain`.
- `mp3gain` is now installed for both `ubuntu` and `windows`-based
runners.
- Tests on Windows caught a legitimate issue #2946 which this PR fixes
also.

This was missed out in #6289 since these tests did not run in CI.
2026-02-21 16:59:41 +00:00
Šarūnas Nejus
c220d1f960
Fix mp3gain/aacgain paths on Windows
Fixes #2946
2026-02-21 16:52:26 +00:00
Šarūnas Nejus
45aa1d5507
Ensure mp3gain is installed in CI 2026-02-21 16:15:46 +00:00
Šarūnas Nejus
743a59be3b
Fix replaygain tests 2026-02-21 16:15:46 +00:00
Šarūnas Nejus
83f16716de
Add beets-fillmissing to the list of plugins (#6371)
Purpose of the plugin is to make manual metadata editing faster.

I wanted to add custom metadata like "language", "mood", and "context"
but existing methods felt too slow, especially when I needed to find and
open the music file to playback separately. So I created this plugin and
I'd like to share it with the community. It helped me to update metadata
for 500 tracks in about 1.5 hours.

See plugin's
[README](https://github.com/amiv1/beets-fillmissing/blob/main/README.md)
file for more details.

## To Do

- [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.)~
2026-02-16 21:51:38 +00:00
Andrey M.
34fe39d066 Add beets-fillmissing to the list of plugins 2026-02-16 20:15:22 +02:00
Šarūnas Nejus
230399fd98
Adjust types for fully typed confuse (#6268)
* Update configuration handling to use fully typed confuse API which
will be released in confuse `v2.2.0`.
* Use `Subview`, `.sequence()`, `MappingTemplate`, and typed `OneOf`.
* Replace 'naked' configuration dictionary access with typed
`.get/.as_*` equivalents.
* Add typing annotations and `cached_property` where appropriate. 
* Fix related issues in `discogs`, `fetchart`, `lyrics`, `playlist`,
`smartplaylist`, and `titlecase` plugins.

> [!IMPORTANT]
> Depends on https://github.com/beetbox/confuse/pull/187 being merged
and released (as `v2.2.0`)
2026-02-16 12:51:14 +00:00
Šarūnas Nejus
15755c1ff9
Update confuse 2026-02-16 12:45:05 +00:00
Šarūnas Nejus
37e18fbb46
Adapt code to fully typed confuse library 2026-02-16 12:45:05 +00:00
Šarūnas Nejus
942638ae28
Clarify Azure Translator resource region requirement (#6363)
Added note about setting the translator resource region to Global to
avoid 401 errors.

## Description

Had a bit of trouble with the lyrics plugin where the translator was not
working. Creating a global resource instead of a regional one fixed the
issue. Added a small note to the documentation so that people won't run
into the same issue in the future.

For a bit more info, you need to specify the region in the request
headers if its a regional resource. This is not required for a global
one.
2026-02-16 12:00:22 +00:00
Šarūnas Nejus
3b670cdf18
In test I/O utility, restore the old stdin/stdout instead of the "true" I/O streams (#5049)
I got a little bit nerdsniped by the problems observed in #5027. In
short, my high-level diagnosis in
https://github.com/beetbox/beets/pull/5027#issuecomment-1857953929 seems
to have been correct: other tests were suppressing the legitimate
failure of a flaky test.

I found the problem by running other tests before the problem test, like
this:

```
$ pytest -k 'test_nonexistant_db or test_delete_removes_item' test/test_ui.py
```

When running `test_nonexistant_db` alone, it fails. When running it like
this with another test that goes first, it passes. That's the problem.

However, `test_delete_removes_item` is just one example that works to
make this problem happen. It appeared that _any_ test in a class that
used our `_common.TestCase` base class had this power. I tracked down
the issue to our `DummyIO` utility, which was having an unintentional
effect even when it was never actually used.

Here's the solution. Instead of restoring `sys.stdin` to
`sys.__stdin__`, we now restore it to whatever it was before we
installed out dummy I/O hooks. This is relevant in pytest, for example,
which installs its *own* `sys.stdin`, which we were then clobbering.
This was leading to the suppression of test failures observed in #5021
and addressed in #5027.

The CI will fail for this PR because it now (correctly) exposes a
failing test. Hopefully by combining this with the fixes in the works in
#5027, we'll be back to a passing test suite. 😃 @Phil305, could
you perhaps help validate that hypothesis?

Edit: @snejus:

I've now consolidated test I/O handling by removing the legacy
`control_stdin`/`capture_stdout` context managers and the custom
`DummyOut` stream, replacing them with a pytest-driven `io` fixture
that:
- provides controllable `stdin` via a lightweight `DummyIn`
- captures `stdout` via `capteesys`
- attaches a `DummyIO` helper to test classes as `self.io`
2026-02-14 18:03:34 +00:00
J0J0 Todos
8eed22c457
fix: wrong count in badfiles log message (#6366)
## Description

Small fix in badfiles: the wrong variable was used for the number of
found errors in badfiles' log messages.
2026-02-13 20:22:45 +01:00
pbnoxious
e4cbbccfdf
append badfiles fix to changelog 2026-02-12 22:58:11 +01:00
pbnoxious
144fd243ec
fix: wrong count in badfiles log message 2026-02-12 22:50:32 +01:00
Meth Munindradasa
e7dfbc96b1
Merge branch 'master' into patch-1 2026-02-13 08:32:39 +11:00
henry
f67c28be0b
Fix #6302: musicbrainz: crash when releases lack the "track" key. (#6364)
## Description

Fixes #6302

Todo: Test. I could not figure out how to add a test for this bug.

<!--
- 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.)
2026-02-11 20:26:07 -08:00
Meth Munindradasa
f41f1839be Format docs to pass lint checker 2026-02-12 07:51:04 +11:00
w4grfw
be8d25ffa4
Update docs/changelog.rst
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-11 21:21:14 +01:00
w4grfw
7f1e7d7bc8 format changelog 2026-02-11 18:28:57 +01:00
w4grfw
63ec1f2f56 changelog entry 2026-02-11 18:25:53 +01:00
w4grfw
fe833d8377 test added 2026-02-11 18:23:55 +01:00
w4grfw
57bd3189df Fix #6302: musicbrainz: crash when releases lack the "track" key. 2026-02-11 16:26:00 +01:00
Meth Munindradasa
b3c1da3c4f
Clarify Azure Translator resource region requirement
Added note about setting the translator resource region to Global to avoid 401 errors.
2026-02-11 21:43:55 +11: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
d613981efe
Replace capture_output with io.getoutput 2026-02-10 00:53:20 +00:00
Šarūnas Nejus
fea789bb59
Replace control_stdin with io.addinput 2026-02-10 00:53:20 +00:00
Šarūnas Nejus
6a65f13776
Replace custom stdio mocks with pytest io fixture
Create a centralised pytest fixture to provide controllable stdin and
captured stdout in all tests. Simplify DummyIO/DummyIn and remove the
custom DummyOut implementation and make use of pytest builtin fixtures.

Create a centralised pytest fixture to provide controllable stdin and
captured stdout that can be applied to any tests, regardless whether
they are based on pytest or unittest.

* `io` fixture can be used as a fixture in pytest-based tests
* `IOMixin` can be used to attach `io` attribute to any test class,
  including `unittest.TestCase`
2026-02-10 00:53:20 +00:00
Šarūnas Nejus
1c87da2c05
Fix test failures 2026-02-10 00:53:20 +00:00
Šarūnas Nejus
a4249af700
Patch sys.stdin and sys.stdout in tests 2026-02-10 00:53:20 +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