Commit graph

13855 commits

Author SHA1 Message Date
Šarūnas Nejus
79787cfd97
tagging: fix list albumartists field 2026-03-22 19:23:52 +00:00
Šarūnas Nejus
f3f132942a
autotag: fix list fields 2026-03-22 19:23:52 +00:00
Šarūnas Nejus
b4ab2d8aa4
tagging: allow nulling singleton fields 2026-03-22 19:23:52 +00:00
Šarūnas Nejus
819b35f6aa
autotag: add a test for overwrite_null configuration 2026-03-22 19:23:52 +00:00
Šarūnas Nejus
da7714aea6
Add feature to exclude albums/songs during auto import (#6452)
Fixes #3523.
2026-03-22 01:54:27 +00:00
kelamg
47148d5100 Fix formatting 2026-03-22 01:46:50 +00:00
kelamg
7556beb33a Revert docstring 2026-03-22 01:46:50 +00:00
kelamg
131930144b Update beetsplug/lyrics.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-03-22 01:46:50 +00:00
kelamg
97a89e919c Update docs/plugins/lyrics.rst
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2026-03-22 01:46:50 +00:00
kelamg
989fc665c9 Improve test 2026-03-22 01:46:50 +00:00
kelamg
2e70472748 Remove + chars 2026-03-22 01:46:50 +00:00
kelamg
2f83c0869e Fix integration test 2026-03-22 01:46:50 +00:00
kelamg
b3bcb78349 Fix indentation 2026-03-22 01:46:50 +00:00
jochem
55b6fbe77d copied more generic implementation from snejus, and updated the tests and docs accordingly 2026-03-22 01:46:50 +00:00
kelamg
d4dc46591d Update beetsplug/lyrics.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-22 01:46:50 +00:00
kelamg
eacaa09a07 Fix docs formatting 2026-03-22 01:46:50 +00:00
kelamg
9a735df125 Fix formatting 2026-03-22 01:46:50 +00:00
kelamg
ec4def9e91 Refactor exclusion tests to pytest 2026-03-22 01:46:50 +00:00
jochem
2f9ee89b2a Added feature to exclude albums/songs during importing when auto is enabled, as requested in issue #3523. Also added corresponding tests and documentation. 2026-03-22 01:46:50 +00:00
Šarūnas Nejus
b09801b24e
docs: Update links to pipx installation guide (#6454)
The [old link](https://pipx.pypa.io/stable/installation/) now responds
with 404.
2026-03-21 18:09:20 +00:00
Andrey Mivrenik
fb46314027 docs: Update links to pipx installation guide 2026-03-21 20:01:46 +02:00
Šarūnas Nejus
03b1ab012c
Refactor dist display (#6444)
## Refactor: Move display logic into `Distance` and `Match` as
properties

Display-related logic previously scattered across `display.py` and
`session.py` is consolidated into the data classes themselves.

### What changed

**`Distance` gains three properties:**

- `penalties` — list of cleaned-up penalty key strings
- `color` — threshold-based `ColorName` derived from the distance value
- `string` — colorized similarity percentage

**`Match` gains two properties:**

- `disambig_string` — formatted comma-separated disambiguation string
- `base_disambig_data` — override point for subclass-specific field
pre-processing (e.g. `media` for `AlbumMatch`,
`index`/`track_alt`/`album` for `TrackMatch`)

**`display.py` / `session.py`:** Standalone functions `dist_string`,
`dist_colorize`, `penalty_string`, `disambig_string`,
`get_album_disambig_fields`, `get_singleton_disambig_fields` are
removed. Call sites now use the properties directly.

A minor fix in `show_match_header` collects output into a list and uses
`textwrap.indent` for a single `ui.print_` call, replacing the previous
per-line prints.

### Impact

- Display logic lives next to the data it describes — easier to find,
easier to test
- `display.py` and `session.py` become thinner; no shared utility
functions to keep in sync
2026-03-20 19:23:54 +00:00
Šarūnas Nejus
2d1461f1d0
Refactor distance and match display into properties
Move disambig string and penalty formatting logic from display.py
into Distance and Match classes as properties.

Add Distance.color, Distance.string, Distance.penalties,
Match.disambig_string, and Match.base_disambig_data to consolidate
display logic closer to the data.

Remove now-redundant standalone functions from display.py and
session.py.
2026-03-17 20:45:32 +00:00
Šarūnas Nejus
1943b14565
Refactor of layout utils (#6442)
This PR refactors import-match layout rendering by centralizing layout
selection and line generation in `beets.util.layout`, simplifying the
`ShowChange` display path, and tightening the layout
data model.

## What Changed
- Added `get_layout_lines()` and `get_layout_method()` in
`beets.util.layout` so layout selection (`column` vs `newline`) is
handled in one place.
- Replaced `Side` from a mutable `TypedDict` with an immutable
`NamedTuple` that exposes derived helpers (`rendered`, prefix/suffix
widths, and rendered width).
- Simplified `split_into_lines()` from a 3-width tuple API to
`(first_width, width)` and removed legacy last-line empty-string
handling.
- Refactored `beets.ui.commands.import_/display.py` `ShowChange` to call
`get_layout_lines()` directly and removed duplicate per-class
layout-selection logic.
- Updated tracklist width calculation to use `Side` helpers and explicit
width assignment via `_replace(width=...)`.
- Reworked `ShowChange` tests into snapshot-style assertions for both
`newline` and `column` layouts, and updated util layout tests to the new
`split_into_lines()` signature.

## Why
- Reduces duplicated wrapping/layout logic across UI code paths.
- Makes layout behavior easier to reason about and test at the utility
boundary.
- Narrows the display layer to orchestration while keeping
transformation/rendering logic in reusable utilities.
- Improves maintainability by moving from loosely typed dict mutation to
a typed, self-describing data structure.
2026-03-17 18:07:34 +00:00
Šarūnas Nejus
a3e94ecac3
Document Side 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
2a003ac709
Refactor ShowChangeTest to use snapshot-style assertions
Replace multiple small tests with two comprehensive snapshot tests
covering the same edge cases and newline and column layouts.

Use BeetsTestCase to ensure that the local dev config is ignored.
2026-03-17 17:59:51 +00:00
Šarūnas Nejus
89784c6e3b
Middle and last line widths are always the same for split_into_lines 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
d10abe426c
Rename width_tuple to widths 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
0d465231c2
Create attributes for widths 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
c19c7dec2f
Dedupe common logic from both layout methods 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
3395968988
Use NamedTuple instead of dict for Side 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
df60e38f5c
Remove redundant term_width and separator args 2026-03-17 17:59:51 +00:00
Šarūnas Nejus
983d41efe0
docs(installation): Update installation guide (#6447)
Update installation guide to document plugin management with pipx and
move package manager instructions to the FAQ.

Related to https://github.com/beetbox/beets/discussions/6429
2026-03-17 17:55:27 +00:00
Andrey Mivrenik
f6813c0909 docs(main): Update to reflect current installation guide 2026-03-17 18:24:09 +02:00
Andrey Mivrenik
3ff93c2eeb docs(installation): Update installation guide 2026-03-17 18:00:53 +02:00
Šarūnas Nejus
9a7a0b93c0
Rename play_count -> lastfm_play_count in lastimport due to clash with mpdstats (#6443)
## `lastimport`: Rename `play_count` field to `lastfm_play_count`

Renames the flexible field written by the `lastimport` plugin from
`play_count` to `lastfm_play_count` to avoid a silent collision with the
same-named field written by the `mpdstats` plugin.

### Impact

- **Breaking change**: existing databases with `play_count` populated by
`lastimport` must be migrated manually — automatic migration is not
possible due to the field name clash. Users are instructed to run `beet
modify lastfm_play_count='$play_count'`.
2026-03-17 08:35:13 +00:00
Šarūnas Nejus
6eff971257
lastimport: rename flexible field because of the clash with mpdstats 2026-03-17 08:20:47 +00:00
Šarūnas Nejus
05f0ec3102
Lastgenre: Separate last.fm client; Centralize extra_debug logging; Group related methods (#6368)
- Separation of concerns
  - API client
  - Rest of plugin logic
- Make `tunelog`helper available as `extra_debug` in `logger.py` - now
usable everywhere in beets.
- Named types for parsed whitelist and canonicalization tree
- Group all canonicalization tree processing tools together at the top
of the file as plain functions.

### New modules

- `client.py` - Last.fm API client (`LastFmClient`) extracted from main
plugin

**No functional changes** - pure refactoring to improve structure.
2026-03-17 08:18:52 +00:00
J0J0 Todos
4431aebd40 Make extra_debug a BeetsLogger method 2026-03-17 07:49:05 +01:00
J0J0 Todos
747f9ed4b3 lastgenre: Ignore client.py move commit 2026-03-17 07:07:58 +01:00
J0J0 Todos
b3e77d50d5 Changelog for extra_debug tool 2026-03-17 07:02:05 +01:00
J0J0 Todos
870845d9c7 lastgenre: Polish method grouping comments wording 2026-03-17 06:52:30 +01:00
J0J0 Todos
af8cbc179c lastgenre: Adapt test to canon helpers move 2026-03-17 06:52:30 +01:00
J0J0 Todos
9747d91557 lastgenre: Group all tree processing helpers together 2026-03-17 06:52:30 +01:00
J0J0 Todos
71a104bbdc lastgenre: Named types Whitelist and CanonTree 2026-03-17 06:52:30 +01:00
J0J0 Todos
ffc6f23407 lastgenre: Adapt test to last.fm client separation 2026-03-17 06:52:30 +01:00
J0J0 Todos
c928c04ac2 lastgenre: Move fetching to client module 2026-03-17 06:52:30 +01:00
J0J0 Todos
84111aa8ee Add extra_debug utility to beets.logging 2026-03-17 06:52:30 +01:00
Šarūnas Nejus
4b93413851
Fix Windows fallback for beet config -e when no editor is set (#6445)
Fixes #6436.

On Windows, `beet config -e` falls back to `open_anything()` when
`VISUAL`/`EDITOR` are unset. That fallback returned `start`, but `start`
is a `cmd.exe` builtin (not an executable), so `os.execlp()` raised
`FileNotFoundError`.

This changes the Windows fallback command to `cmd /c start ""` so the
builtin is invoked via the shell and file opening works as intended.

## Changes

- Update `open_anything()` Windows fallback to `cmd /c start ""`.
- Add regression test for `interactive_open()` with the Windows fallback
command.
- Add regression test for `beet config -e` on simulated Windows with no
editor env vars.
- Add changelog entry under Unreleased bug fixes.
2026-03-16 21:25:04 +00:00
Aditya Inamdar
886bb8626d Remove implementation-focused tests per review 2026-03-16 21:19:12 +00:00