Commit graph

4103 commits

Author SHA1 Message Date
Šarūnas Nejus
b3f5585849
Add a changelog note 2026-03-06 11:29:05 +00:00
Šarūnas Nejus
192217da5d
Format docs 2026-03-06 11:28:29 +00:00
Šarūnas Nejus
ae3a2e5729
Fix redirect URLs 2026-03-06 11:28:29 +00:00
Šarūnas Nejus
441c838387
Fix broken URLs 2026-03-06 11:28:29 +00:00
Šarūnas Nejus
3d0d032987
Replace http URLs with https 2026-03-06 11:28:29 +00:00
Šarūnas Nejus
e8605747d6
Document migrations 2026-03-06 10:57:08 +00:00
Šarūnas Nejus
7d30efa82c
Migrate lyrics metadata to flex fields on library open
- Add `LyricsMetadataInFlexFieldsMigration` to extract legacy source
  URLs and language metadata from lyrics text into flex attributes
- Add `Lyrics.from_legacy_text` to parse legacy lyrics format
- Move `with_row_factory` context manager up to base `Migration` class
- Rename `migrate_table` to `migrate_model` and pass model class
  instead of table name string. This is so that the migration can access
  both `_table` and `_flex_table` attributes.
- Make `langdetect` import optional in `Lyrics.__post_init__`: users may
  not have have the dependency installed, and we do not want the
  migration to fail because of that.
- Move `BACKEND_BY_NAME` to module level for use outside plugin class
2026-03-06 10:57:08 +00:00
Šarūnas Nejus
38708ae592
Refactor lyrics handling to use structured Lyrics object
* Introduce a `Lyrics` dataclass to carry text, source URL, and language
  metadata through fetch, translation, and storage paths.
* Return `Lyrics` from backends and plugin lookup methods instead of raw
  tuples/strings.
* Store backend name in `lyrics_source` derived from fetched URL root
  domain.
* Simplify translator flow to operate on `Lyrics`, reuse line splitting,
  append translations in-place, and record translation language
  metadata.
2026-03-06 10:57:08 +00:00
Šarūnas Nejus
82bfc03494
Preserve synced lyrics when fetched result is plain text
When lyrics.synced is enabled, avoid replacing existing synced lyrics with
newly fetched unsynced lyrics, even with force enabled.

Allow replacement when the new lyrics are also synced, or when synced mode
is disabled.
2026-03-05 15:36:59 +00:00
Šarūnas Nejus
24ca6abcfe
lyrics: validate synced lyrics duration 2026-03-05 15:34:32 +00:00
Eric Masseran
6abf7c43ae Fix typo 2026-03-04 22:39:33 +01:00
Eric Masseran
1fe5bad4b2 Merge remote-tracking branch 'official/master' into use-aliases-for-track-album
* official/master: (180 commits)
  feat(lastgenre): cleanup_existing
  convert: generate playlist entries from effective output paths
  Fix lint issues
  Move changelog note under Unreleased section
  Enable duplicate detection for as-is imports
  Force slow queries for FuzzyPlugin
  Add tests
  Add changelog note
  Match substrings fuzzily
  Fix lint
  Move test_autotag tests under test/autotag
  Keep missing multi-value fields as None instead of empty list
  Show that album genres are not applied to tracks
  autotag: refactor autotag tests to use single comprehensive test
  fix(lastgenre): Reset plugin config in fixtured tests
  fix(fetchart): prevent deletion of configured fallback cover art
  Move changelog note under unreleased section
  Update changelog note
  fix: ftintitle can handle a list of ampersanded artists
  Fix symlink tests for macOS
  ...
2026-03-04 22:21:03 +01:00
Arne Beer
13fe82f394 feat(lastgenre): cleanup_existing
Introduce a new lastgenre `cleanup_existing` flag.

It handles the case where canonicalization is desired on existing tags.
The new logic triggers if:
- `force`: False
- `cleanup_existing: True

Depending on whether `whitelist: True` or `canonical: True`, the genres
are then canonicalized and/or whitelisting is applied
2026-03-04 21:01:37 +01:00
Šarūnas Nejus
e90bda31d1
Merge branch 'master' into pr-fix-convert-ext 2026-03-04 15:24:54 +00:00
Šarūnas Nejus
c46f99a82b
Merge branch 'master' into pr-fix-convert-ext 2026-03-04 15:22:40 +00:00
Šarūnas Nejus
bf7997d45f
Move changelog note under Unreleased section 2026-03-04 14:32:44 +00:00
Axel Wikström
b5d8ced9d9 Enable duplicate detection for as-is imports
When importing with autotag=no, duplicate detection was skipped entirely
because the import_asis stage called _apply_choice() directly without
first calling _resolve_duplicates(). This meant the duplicate_keys and
duplicate_action config options were ignored for as-is imports.

This was a known limitation documented by a FIXME comment added in
commit 79d1203541 (Sep 2014): "We should also resolve duplicates when
not autotagging." The FIXME was later removed during a comment cleanup
(f145e3b18) but the issue was never addressed.

This commit adds the _resolve_duplicates() call to import_asis, ensuring
duplicate detection works consistently regardless of the autotag setting.
This applies to both album imports and singleton imports.

Test changes:
- Renamed test_no_autotag_keeps_duplicate_album to
  test_no_autotag_removes_duplicate_album to verify the corrected behavior
- Added test_no_autotag_removes_duplicate_singleton to verify singleton
  duplicate detection also works with autotag=no

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-04 14:26:13 +00:00
Šarūnas Nejus
48763eee4f
Force slow queries for FuzzyPlugin 2026-03-03 14:05:35 +00:00
Šarūnas Nejus
56e86a7966
Add changelog note 2026-03-03 13:53:12 +00:00
Šarūnas Nejus
503d5c75ff
Merge branch 'master' into bugfix_editor 2026-03-03 12:03:52 +00:00
Šarūnas Nejus
1838482c7a
Keep missing multi-value fields as None instead of empty list 2026-03-03 07:48:51 +00:00
Danny Trunk
974d917df4 fix(fetchart): prevent deletion of configured fallback cover art
When `import.delete` or `import.move` is enabled, the `assign_art` method calls `task.prune(candidate.path)` unconditionally.
This incorrectly deletes the configured `fetchart.fallback` file.
Add explicit check to skip pruning when the candidate path matches the configured fallback.
2026-03-02 18:10:19 +01:00
Šarūnas Nejus
5c3ba8e006
Move changelog note under unreleased section 2026-03-02 16:38:02 +00:00
Šarūnas Nejus
91fae7c879
Merge branch 'master' into zero-total-discs 2026-03-02 16:37:43 +00:00
Šarūnas Nejus
b17305aa1e
Update changelog note 2026-03-02 14:54:34 +00:00
Fredrik Möllerstrand
bfd95f47d0 fix: ftintitle can handle a list of ampersanded artists
This was inspired by real life events:
https://musicbrainz.org/release/7c4d7a15-6b30-4bef-8b20-af200186fbdb
by the artist Danny L Harle has a a track with a featuring list
that contains "Danny L Harle, Oklou & MNEK".
2026-03-02 14:53:23 +00:00
J0J0 Todos
532b0dabb1 Update my teams page entry 2026-03-02 08:31:44 +01:00
Serene
aa81232336 Use proper syntax highlighting for code block
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-03-01 11:46:44 +00:00
Serene-Arc
dd1bda4bd0 Format docs 2026-03-01 11:46:44 +00:00
edvatar
a40bd7ca3c docs: Document match.distance_weights in autotagger docs
Add documentation for the distance_weights configuration option in
the autotagger matching section. This includes all available fields
with their default values and an example of how to customize them.

Closes #6081

Signed-off-by: edvatar <88481784+toroleapinc@users.noreply.github.com>
2026-03-01 11:46:44 +00:00
Šarūnas Nejus
62e232983a
Document ordering of the genre split separator 2026-02-27 18:36:04 +00:00
Šarūnas Nejus
67cf15b0bd
Remove lastgenre separator config 2026-02-27 18:36:04 +00:00
Šarūnas Nejus
6f886682ea
Update changelog note 2026-02-27 18:36:04 +00:00
Šarūnas Nejus
52375472e8
Replace genre: with genres: in docs 2026-02-27 18:34:26 +00:00
Šarūnas Nejus
a8d53f78de
Fix the rest of the tests 2026-02-27 18:34:26 +00:00
Šarūnas Nejus
cf36ed0754
Only handle multiple genres in discogs 2026-02-27 18:34:26 +00:00
dunkla
36a30b3c65
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-27 18:24:54 +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
6fe7a9a7d3
Add @snejus to team 2026-02-23 03:54:20 +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
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
1930400ab8
Set default release/recording includes in MusicBrainzAPI 2026-02-22 02:09:25 +00:00
Šarūnas Nejus
c220d1f960
Fix mp3gain/aacgain paths on Windows
Fixes #2946
2026-02-21 16:52:26 +00:00
Andrey M.
34fe39d066 Add beets-fillmissing to the list of plugins 2026-02-16 20:15:22 +02: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
Fredrik Möllerstrand
cd9f86ae6d
feat: zero plugin zeroes disctotal if single disc
When omit_single_disc is set, disctotal is now also zeroed alongside disc.
Previously, only the disc tag was zeroed.
2026-02-14 18:32:04 +01:00
pbnoxious
e4cbbccfdf
append badfiles fix to changelog 2026-02-12 22:58:11 +01:00
Meth Munindradasa
e7dfbc96b1
Merge branch 'master' into patch-1 2026-02-13 08:32:39 +11: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
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
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
616a674db0
Properly format changelog section headers 2026-02-08 07:28:08 +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
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
MatMacInf
23653771a9 Added handling FileNotFoundError specifically, changed chanelog 2026-02-03 08:56:16 +01: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
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
Sebastian Mohr
8e0b3f1323 Moved config check into find_metadata_source_plugins func. 2026-01-31 23:42:09 +00: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
cde73cc433
Add changelog note 2026-01-30 01:18:11 +00:00
Sebastian Mohr
ee7dc3c4e7
Enhanced documentation of random plugin. 2026-01-30 00:30:45 +00:00
Sebastian Mohr
34e0de3e1f
Added typehints and some more tests. 2026-01-30 00:30:20 +00:00
Kirill A. Korinsky
5a94209364
Update changelog 2026-01-27 22:56:18 +01:00
Kirill A. Korinsky
1dd2cd019f
Update color docs with bright_* and bg_bright_* entries 2026-01-25 12:05:40 +01:00
MatMacinf
5741be9a11 Fixed error with Errno2 corresponding to set editor in enviroment variables 2026-01-22 16:22:38 +01:00
Rebecca Turner
958b36b298 fish: complete files in more places 2026-01-20 13:07:03 -08:00
Serene
39f65f6b11
Merge branch 'master' into embedart-clear-improvements 2026-01-20 08:43:30 +10:00
Henry
1d6e05709e Fix #6068 - Multivalue fields are now supported & tested. 2026-01-19 12:41:36 -08:00
Henry
9efe87101c Fix #6177, remove derived types, refactor coalesce tracks 2026-01-19 12:40:42 -08:00
Eric Masseran
614f9764ba
Merge branch 'master' into use-aliases-for-track-album 2026-01-18 14:48:15 +01:00
Jesse Pinkman
7002cbdda2
Merge branch 'master' into add-mp3rgain-support 2026-01-18 11:00:38 +01:00
m_igashi
545e7eb0b6 refactor: simplify CommandBackend and improve documentation
- Remove auto-detection of command tools, require explicit command config
- Simplify __init__ method by removing redundant else branch
- Reorganize docs with separate sections for mp3gain, aacgain, mp3rgain
- Fix CVE reference (CVE-2021-34085 is fixed in mp3gain 1.6.2)
- Update command option description per review feedback
2026-01-18 10:52:41 +01:00
Dr.Blank
52284ff7ed
fix: changelog entry 2026-01-17 14:30:22 +05:30
m_igashi
683da049a0 style: format replaygain.rst with docstrfmt 2026-01-16 16:20:45 +01:00
Jesse Pinkman
dc117046a9
Merge branch 'master' into add-mp3rgain-support 2026-01-16 15:55:23 +01:00
Dr.Blank
4ad5871ef0
fix: sort imports 2026-01-16 15:53:34 +05:30
Dr.Blank
b0bce80518
remove changelog not related to pr 2026-01-16 15:50:09 +05:30
Dr.Blank
8482733034
Merge branch 'master' into fix-permission-error 2026-01-16 15:48:19 +05:30
Šarūnas Nejus
bfb24da51c
Add note to the changelog 2026-01-15 15:53:06 +00:00
rdy2go
fdfeb35076 add changelog for and to resolve PR #5828 2026-01-15 16:07:54 +01:00
rdy2go
445ad02399
Merge branch 'beetbox:master' into master 2026-01-15 16:04:46 +01:00
m_igashi
ebd0e70012 Add mp3rgain support to ReplayGain command backend
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
2026-01-14 01:47:45 +01:00
Šarūnas Nejus
1c20e4bd4e
Address RUF012 2026-01-13 20:55:40 +00:00
Šarūnas Nejus
0efce4a86b
Merge branch 'master' into usertag 2026-01-13 13:38:56 +00:00
Šarūnas Nejus
f63585fe31
Remove expired Spotify credentials and log error for missing configuration (#6271)
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
2026-01-11 19:02:37 +00:00
Henry Oberholtzer
f7b05cb7db ftintitle: fix changelog conflict 2026-01-08 12:20:25 -08:00
Šarūnas Nejus
a3c2e383f4
Merge branch 'master' into spotify 2026-01-08 00:23:15 +00:00
Alok Saboo
dd3ecec579 Updated Spotify API credentials 2026-01-07 18:54:39 -05:00
Eric Masseran
fe8dc1e65e Align lint 2026-01-07 20:47:04 +01:00