Commit Graph

14963 Commits

Author SHA1 Message Date
Šarūnas Nejus
2a36fb745f Add documentation 2026-07-13 18:43:23 +01:00
Šarūnas Nejus
8261f72628 Skip tests that fail due to Windows path handling 2026-07-13 18:43:23 +01:00
Šarūnas Nejus
92d90e01d3 Refactor queryparse tests 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
6b568ebd7e Simplify imports in test_queryparse.py 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
471d7f3791 Replace queryparse functions with ModelQuery helpers
- Move query and sort construction into `ModelQuery` classmethods and parse
  tokenized input once.
- Switch call sites to consume `parse_query(...).query` and
  `parse_query(...).sort` instead of tuple unpacking.
- Remove legacy `dbcore` re-exports and obsolete helper functions in
  `queryparse`.
- Update query/sort tests to match the new parsing behavior and simplified
  query object shapes.
2026-07-13 18:43:22 +01:00
Šarūnas Nejus
aa2cd9bf03 Simplify parse_sorted_query 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
5cb0fadbcf Rename query_from_strings -> build_and_query 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
982435e8b8 Do not wrap single query with AndQuery 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
0e774acfae Replace construct_query_term with QueryPart.get_query
- Move per-term query building into QueryTerm.get_query and compose
  field queries with operator-based OR logic.
- Add Query.__or__ plus flattening behavior for AndQuery and OrQuery to
  avoid nested collection queries.
- Update dbcore parsing expectations so single-field terms assert
  SubstringQuery directly.
2026-07-13 18:43:22 +01:00
Šarūnas Nejus
20e6ec222c Centralize field query construction in query classes
- Move field alias handling, shared-table qualification, and path pattern
  normalization into FieldQuery.from_model with a query-specific
  normalize_pattern hook.
- Update query parsing and plugin call sites to construct queries through
  query_cls.from_model and remove redundant model-level field query helpers.
  This keeps model entrypoints focused on orchestration and colocates
  transformation behavior with the query types that own it.
2026-07-13 18:43:22 +01:00
Šarūnas Nejus
c953dbd9b9 Define QueryByField 2026-07-13 18:43:22 +01:00
Šarūnas Nejus
2b7be8175c Replace parse_query_string, parse_query_parts by ModelQuery.parse
- Add ModelQuery in dbcore.queryparse and expose LibModel.parse_query as
  the single parsing entrypoint for string and sequence query inputs.
- Route library fetch, path format matching, and plugin query parsing
  through the model-level API, and deprecate
  beets.library.parse_query_string and parse_query_parts.
- Update tests to cover invalid query parsing via ModelQuery and align
  smartplaylist sort assertions with parsed sort behavior.
2026-07-13 18:43:22 +01:00
Šarūnas Nejus
c13141ebf5 Use model default_sort for library query defaults
- Replace default sort helpers with LibModel.default_sort as a shared,
  config-driven sort helper for Item and Album.
- Route Library._fetch through get_results with parsed query sort, explicit sort,
  or model default_sort fallback.
2026-07-13 18:43:22 +01:00
Šarūnas Nejus
d9ca7ec19b Replace parse_query_part with QueryTerm
- Replace parse_query_part with a QueryTerm parser that captures negate, field,
  prefix, and pattern in one pass.
- Resolve query class selection through QueryTerm so prefix and field-based
  dispatch are handled consistently.
- Move implicit path query normalization into dbcore parsing, simplifying
  library-level query parsing.
- Tighten plugin query typing and update dbcore tests for path behavior and
  related fixture assertions.
2026-07-13 18:43:21 +01:00
Šarūnas Nejus
1c05b7865d Replace construct_sort_term by SortTerm class
- Introduce SortTerm to centralize sort-part validation and direction parsing.
- Move model-specific sort resolution into SortTerm.get_sort, including smart
artist field mapping.
- Simplify sort_from_strings to build sorts from parsed terms.
2026-07-13 18:39:40 +01:00
Šarūnas Nejus
f6621ffa1a Read sort case sensitivity in FieldSort
Move sort case-sensitivity config lookup into `FieldSort` as a cached
class property instead of threading a `case_insensitive` flag through
query parsing helpers.

This centralizes sort behavior at the sort implementation boundary and
simplifies parse/orchestration call paths while preserving configurable
case-sensitive ordering.
2026-07-13 18:39:40 +01:00
Šarūnas Nejus
8e62d66474 dbcore: rename Database._fetch to Database.get_results
This removes ambiguity with Library._fetch
2026-07-13 18:39:40 +01:00
Šarūnas Nejus
0e796d46c1 Move prefixes to where they are used 2026-07-13 18:39:40 +01:00
Šarūnas Nejus
31f46a2bcd Fix beets.plugins.queries type 2026-07-13 18:39:40 +01:00
Šarūnas Nejus
e700135e0a eDit: Enable album-level field editing during interactive import (#6727)
During interactive import, the `edit` plugin only exposed item-level
fields — the `albumfields` configuration was completely ignored in
`importer_edit()`. Users who wanted to modify album-level fields such as
`album` or `year` had to complete the import, then run `beet edit -a
QUERY` as a separate step.

### Solution

Updated `importer_edit()` to support editing album-level fields during
import. Album fields (configured via `albumfields`) are presented as a
YAML header section prepended to the per-track documents. Changes to the
header are applied to all items in the album, making album-level edits
work in both the `eDit` and `edit Candidates` choices.
2026-07-13 17:58:12 +01:00
Alok Saboo
01c2943e76 remove redundant test 2026-07-13 12:37:07 -04:00
Alok Saboo
3ce00617e9 switch the logic ot strip item-only fixed fields 2026-07-13 12:29:55 -04:00
Alok Saboo
77222e7302 Merge branch 'master' into edit 2026-07-13 12:21:19 -04:00
Šarūnas Nejus
9cbbf5be1d Increase test verbosity (#6828)
Change `config["verbose"]` from `1` to `2` so that DEBUG-level logging
from plugin import tasks and event hooks are emitted. (See
`beets.plugins._set_log_level_and_params`.)

`config["verbose"] == 2` does not appear to affect logging anywhere else
in the codebase, while `config["verbose"] == 3` would enable output of
messages logged via `BeetsLogger.extra_debug()`.
2026-07-13 15:16:13 +01:00
Šarūnas Nejus
9cc1c04c6b Merge branch 'master' into overhacked/increase_test_log_level 2026-07-13 13:50:37 +01:00
Alok Saboo
58fb167750 Merge branch 'master' into edit 2026-07-13 08:47:53 -04:00
Šarūnas Nejus
acc1235442 Fix crash when sorting by a nullable field missing on some items (#6832)
Fixes #3461.

Sorting by a field whose declared type is nullable (its null value is
`None`, e.g. `NullInteger`/`NullFloat`) crashed with `TypeError: '<' not
supported between instances of ...` when the field was present on some
objects but missing on others, because `FieldSort.sort` compared `None`
against real values.

The sort key now groups missing values together so `None` is never
compared against a present value: missing values are ordered first when
sorting ascending and last when descending, matching SQLite's default
ordering of NULLs already used by the fast `FixedFieldSort` (SQL) path.
2026-07-13 13:40:57 +01:00
TowyTowy
2293d2f60a Fix crash when sorting by a nullable field missing on some items
Sorting by a field whose declared type is nullable (its null value is
`None`, e.g. `NullInteger`/`NullFloat`) raised `TypeError: '<' not
supported between instances of ...` when the field was present on some
objects but missing on others, because `FieldSort.sort` compared `None`
against real values.

Group missing values together in the sort key so they are never compared
against present ones: they are ordered first when sorting ascending and
last when descending, matching SQLite's default ordering of NULLs used by
the fast `FixedFieldSort` path.

Fixes #3461.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-13 13:36:23 +01:00
Šarūnas Nejus
923675a0e6 test: fix ffprobe tests incorrectly skipped (#6827)
## Description

The `@NEEDS_FFPROBE` decorator was incorrectly skipping tests when
`ffprobe` is available, because it was calling `ffprobe --version`,
while the valid option is `ffprobe -version` (with a single dash).
2026-07-13 13:33:18 +01:00
Šarūnas Nejus
ec25eb203f Merge branch 'master' into overhacked/fix_test_helper_ffprobe 2026-07-13 13:28:34 +01:00
Šarūnas Nejus
1d6354e008 test: fix requests_mock setup in test_art.py (#6826)
## Description

`requests_mock` was configured with a fallback matcher to return an
exception on any request. The intent was to have tests fail if any
requests are attempted in tests without matching mocks. This is the
default behavior of `requests_mock`, so no fallback matcher is
necessary. The side-effect of the fallback matcher, removed by this
commit, was that 1) the `NoMockAddress` exception was raised to the
function under test rather than to the test harness and 2) the
`NoMockAddress` exception was not able to be constructed because the
`exc` parameter to `requests_mock.register_uri` does not support
exceptions that require arguments. This behavior is visible in the
following log snippet, taken from an incorrectly-passing test:

```
DEBUG    beets.fetchart:logging.py:163 downloading image: https://images.amazon.com/images/P/xxxx.01.LZZZZZZZ.jpg
DEBUG    requests_mock.adapter:adapter.py:256 GET https://images.amazon.com/images/P/xxxx.01.LZZZZZZZ.jpg 200
DEBUG    beets.fetchart:logging.py:163 not a supported image: text/html
DEBUG    beets.fetchart:logging.py:163 downloading image: https://images.amazon.com/images/P/xxxx.02.LZZZZZZZ.jpg
DEBUG    beets.fetchart:logging.py:163 error fetching art: NoMockAddress.__init__() missing 1 required positional argument: 'request'
```

The test that emitted these logs passed because the `FetchArt` plugin is
written to handle exceptions raised by art sources, skipping and logging
an error. For the exception to cause a failing test, the default
behavior of `requests_mock` of raising an exception to the test harness
when no matching mock requests can be found must be allowed.
2026-07-13 13:27:05 +01:00
Ross Williams
c2fc7a8a57 test: fix requests_mock setup in test_art.py
`requests_mock` was configured with a fallback matcher to return an
exception on any request. The intent was to have tests fail if any
requests are attempted in tests without matching mocks. This is the
default behavior of `requests_mock`, so no fallback matcher is
necessary. The side-effect of the fallback matcher, removed by this
commit, was that 1) the `NoMockAddress` exception was raised to the
function under test rather than to the test harness and 2) the
`NoMockAddress` exception was not able to be constructed because the
`exc` parameter to `requests_mock.register_uri` does not support
exceptions that require arguments. This behavior is visible in the
following log snippet, taken from an incorrectly-passing test:

```
DEBUG    beets.fetchart:logging.py:163 downloading image: https://images.amazon.com/images/P/xxxx.01.LZZZZZZZ.jpg
DEBUG    requests_mock.adapter:adapter.py:256 GET https://images.amazon.com/images/P/xxxx.01.LZZZZZZZ.jpg 200
DEBUG    beets.fetchart:logging.py:163 not a supported image: text/html
DEBUG    beets.fetchart:logging.py:163 downloading image: https://images.amazon.com/images/P/xxxx.02.LZZZZZZZ.jpg
DEBUG    beets.fetchart:logging.py:163 error fetching art: NoMockAddress.__init__() missing 1 required positional argument: 'request'
```

The test that emitted these logs passed because the `FetchArt` plugin is
written to handle exceptions raised by art sources, skipping and logging
an error. For the exception to cause a failing test, the default
behavior of `requests_mock` of raising an exception to the test harness
when no matching mock requests can be found must be allowed.

Signed-off-by: Ross Williams <ross@ross-williams.net>
2026-07-13 13:21:32 +01:00
Alok Saboo
7f45f51690 Merge branch 'master' into edit 2026-07-12 20:39:16 -04:00
Šarūnas Nejus
1a1d7dc240 lyrics: add --no-keep-synced CLI option (#6769)
- This change adds a small CLI override to `beetsplug/lyrics.py`:
`--no-keep-synced`. It is the inverse of `--keep-synced`, and lets one
manual `lyrics` run ignore the configured `keep_synced: yes`.
2026-07-13 01:24:49 +01:00
Šarūnas Nejus
d9a1bde1c9 Add --no-keep-synced CLI option to lyrics
- Allow manual lyrics fetches to override keep_synced configuration for a single
  run.
2026-07-13 01:14:41 +01:00
Alok Saboo
aeaab7320d Merge branch 'master' into edit 2026-07-12 20:14:33 -04:00
Alok Saboo
210ca09637 ignore item-only fields configured in albumfields 2026-07-12 20:14:11 -04:00
Šarūnas Nejus
ba6610a7b7 lyrics: move intrumental lyrics to a flexible attribute (#6762)
Fixes #6719 

- This change shifts instrumental-track handling in the lyrics flow from
storing the literal `"[Instrumental]"` in `item.lyrics` to storing that
state as structured metadata in `lyrics_instrumental`.

- At the architecture level, the source of truth is now the `Lyrics`
value object in `beets/util/lyrics.py`: it normalizes instrumental
results early, clears the lyrics text, and carries an `instrumental`
flag through the rest of the pipeline.

- The `lyrics` plugin then persists that flag as the flexible field
`lyrics_instrumental`, alongside existing metadata like `lyrics_backend`
and `lyrics_url`. This keeps canonical lyrics text clean while
preserving whether the track was identified as instrumental.

- A new library migration, `InstrumentalLyricsInFlexFieldMigration`,
updates existing databases by moving legacy `"[Instrumental]"` values
out of the main `lyrics` column and into the flexible attribute. This
makes old data match the new model automatically.

- Docs and tests were updated to reflect the new behavior, so reviewers
can think of this as a small data-model cleanup with backward-compatible
migration: cleaner `lyrics` content, explicit instrumental metadata, and
automatic upgrade for existing libraries.
2026-07-13 01:13:12 +01:00
Šarūnas Nejus
95854c7770 Add a migration 2026-07-13 01:07:59 +01:00
Šarūnas Nejus
8020c07acf Track instrumental lyrics metadata
- Leave lyrics text empty when a backend reports an instrumental track and
  persist that state in lyrics_instrumental.
2026-07-13 01:07:59 +01:00
Ross Williams
a64397e025 test: increase test verbosity
Change `config["verbose"]` from `1` to `2` so that DEBUG-level logging
from plugin import tasks and event hooks are emitted.
(See `beets.plugins._set_log_level_and_params`.)

`config["verbose"] == 2` does not appear to affect logging anywhere else
in the codebase, while `config["verbose"] == 3` would enable output of
messages logged via `BeetsLogger.extra_debug()`.

Signed-off-by: Ross Williams <ross@ross-williams.net>
2026-07-12 21:24:34 +01:00
Ross Williams
1e0578b9cb test: fix ffprobe tests incorrectly skipped
The `@NEEDS_FFPROBE` decorator was incorrectly skipping tests when
`ffprobe` is available, because it was calling `ffprobe --version`,
while the valid option is `ffprobe -version` (with a single dash).

Signed-off-by: Ross Williams <ross@ross-williams.net>
2026-07-12 20:06:25 +01:00
Alok Saboo
f91ba3a315 Merge branch 'master' into edit 2026-07-12 09:12:02 -04:00
Serene
4061ea0553 Add fetch_for_asis setting to FetchArt plugin (#6815)
Add `fetch_for_asis` setting to FetchArt plugin

## Description

Enable fetching art for imports even when as-is is selected as the
metadata source. Allows for the case when files with good metadata but
without album art are being imported (e.g. digital download store).

## 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.
- [x] Changelog.
- [x] Tests.
2026-07-12 16:11:14 +10:00
Alok Saboo
55199bf365 harden edit-plugin id matching against duplicate ids and header reordering 2026-07-10 17:52:55 -04:00
Ross Williams
6afc0f282a test: add importer test for fetchart plugin
Test whether fetchart is run during the import phase and, specifically,
whether the `fetch_for_asis` setting is honored. Mock boundary is
between `FetchArtPlugin` and `ArtSource`, an already-existing internal
API boundary.
2026-07-10 22:19:44 +01:00
Ross Williams
77405266eb test: convert test_fetchart to TestHelper
Signed-off-by: Ross Williams <ross@ross-williams.net>
2026-07-10 22:15:39 +01:00
Ross Williams
c3de685484 Add fetch_for_asis setting to FetchArt plugin
Enable fetching art for imports even when as-is is selected as the
metadata source. Allows for the case when files with good metadata
but without album art are being imported (e.g. digital download store).

Signed-off-by: Ross Williams <ross@ross-williams.net>
2026-07-10 22:15:32 +01:00
Alok Saboo
094e38e002 Merge remote-tracking branch 'upstream/master' into edit
# Conflicts:
#	docs/changelog.rst
2026-07-10 16:31:13 -04:00
Šarūnas Nejus
9acb1ecff6 feat(ftintitle): hook metadata events, fixing mbsync (#6726)
Depends on https://github.com/beetbox/beets/pull/6732.

## Summary

This PR integrates `ftintitle` with metadata fetched through beets’
metadata-received events, so commands like `mbsync` apply
already-normalized metadata when `ftintitle` is enabled.

Addresses https://github.com/beetbox/beets/issues/1153.

## Changes

- Register `ftintitle` listeners for `trackinfo_received` and
`albuminfo_received` when `ftintitle.auto` is enabled.
- Rewrite fetched `TrackInfo` metadata before `mbsync` applies it,
avoiding unnecessary re-sync churn.
- Preserve existing manual command and import behavior while sharing the
same rewrite logic.
- Handle `artist_credit`, cached `Info` properties, empty titles, and
no-op configurations consistently.
- Update `ftintitle` docs for the expanded `auto` behavior.
2026-07-10 18:33:30 +01:00