Commit graph

13589 commits

Author SHA1 Message Date
Šarūnas Nejus
151468ee37
Document ordering of the genre split separator 2026-02-22 14:21:00 +00:00
Šarūnas Nejus
1b326ea5dc
Remove lastgenre separator config 2026-02-22 14:21:00 +00:00
Šarūnas Nejus
76ca663138
Update changelog note 2026-02-22 14:21:00 +00:00
Šarūnas Nejus
f9c84937ed
Replace genre: with genres: in docs 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
0c67fda1ca
Fix the rest of the tests 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
4ab2e483fa
Remove genre field 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
76e3755671
Stop overwriting this test file name 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
7a53eb0d5c
Only handle multiple genres in discogs 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
2c61176592
Fix deprecation warning 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
6778e58198
Add migration for multi-value genres field
* Move genre-to-genres migration into a dedicated Migration class and
  wire it into Library._migrations for items and albums.
* Add batched SQL updates via mutate_many and share the multi-value
  delimiter as a constant.
* Cover migration behavior with new tests.

I initially attempted to migrate using our model infrastructure
/ Model.store(), see the comparison below:

Durations migrating my library of ~9000 items and ~2300 albums:
1. Using our Python logic: 11 minutes
2. Using SQL directly: 4 seconds

That's why I've gone ahead with option 2.
2026-02-22 14:20:59 +00:00
Šarūnas Nejus
aaffafaa93
Add generic Migration implementation 2026-02-22 14:20:59 +00:00
Šarūnas Nejus
93f30f9c3f
Add support for migrations 2026-02-22 14:20:59 +00:00
dunkla
0c2af3215c
Fix mypy incompatible return type in lastgenre 2026-02-22 14:19:17 +00:00
dunkla
d25c6204eb
Update lastgenre docstring and remove misleading comment (ref https://github.com/beetbox/beets/pull/6169#issuecomment-3716893013) 2026-02-22 14:19:17 +00:00
dunkla
1a648a4223
Remove noisy comments from beatport tests (ref https://github.com/beetbox/beets/pull/6169#issuecomment-3716893013) 2026-02-22 14:19:17 +00:00
dunkla
4ec68390a5
Remove conditional logic from lastgenre tests (ref https://github.com/beetbox/beets/pull/6169#issuecomment-3716893013) 2026-02-22 14:19:17 +00:00
dunkla
d49f35a4d4
Use compact generator expression in Beatport (ref https://github.com/beetbox/beets/pull/6169#issuecomment-3716893013) 2026-02-22 14:19:17 +00:00
dunkla
df46d4291e
Fix lastgenre migration separator logic (ref https://github.com/beetbox/beets/pull/6169#issuecomment-3716893013) 2026-02-22 14:19:17 +00:00
dunkla
938f458eef
Remove manual migrate command
Migration now happens automatically when the database schema is
updated (in Library._make_table()), so the manual 'beet migrate'
command is no longer needed.

Addresses PR review comment.
2026-02-22 14:19:17 +00:00
dunkla
9597075751
Simplify MusicBrainz genres assignment
Remove intermediate variable and assign directly to info.genres.
Addresses PR review comment.
2026-02-22 14:19:17 +00:00
dunkla
85903804ef
Implement automatic database-level genre migration
- Add Library._make_table() override to automatically migrate genres when database schema is updated
- Migration splits comma/semicolon/slash-separated genre strings into genres list
- Writes changes to both database and media files with progress reporting
- Remove lazy migration from correct_list_fields() - now handled at database level
- Remove migration-specific tests (migration is now automatic, not lazy)
- Update changelog to reflect automatic migration behavior

Related PR review comment changes:
- Replace _is_valid with _filter_valid method in lastgenre plugin
- Use unique_list and remove genre field from Beatport plugin
- Simplify LastGenre tests - remove separator logic
- Document separator deprecation in lastgenre plugin
- Add deprecation warning for genre parameter in Info.__init__()
2026-02-22 14:19:17 +00:00
dunkla
f2af5f8778
simplify check for fallback in beetsplug/lastgenre/__init__.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
dunkla
fe562f4009
simplify genre unpacking in beetsplug/lastgenre/__init__.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
dunkla
ee5dffaab5
simplify return logic in beetsplug/lastgenre/__init__.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
dunkla
8c28a962d3
better function description in beetsplug/lastgenre/__init__.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
dunkla
0d75777516
shorte test description in test/plugins/test_lastgenre.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
dunkla
99749cfc9b
remove noisy comment from test/plugins/test_beatport.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-02-22 14:19:17 +00:00
Johann Fot
ee5f96be78
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-22 14:19:17 +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