Commit Graph
3832 Commits
Author SHA1 Message Date
Šarūnas Nejus bca1ba3209 ui: use readline for a more appropriate prompt 2026-08-27 03:02:14 +01:00
Šarūnas Nejus ebf638dce1 match: Improve Proposal and add AlbumImportTask 2026-08-27 03:00:57 +01:00
Šarūnas Nejus 89341e14b6 move cmd: simplify operation paramater 2026-08-27 03:00:56 +01:00
Šarūnas Nejus 99a0c677a1 distance: Add missing fields
Add new keys to distance calculation:
  - missing_fields
  - missing_label
  - missing_month
  - missing_catalognum
2026-08-27 02:58:40 +01:00
Šarūnas Nejus bba642108d logging: use RichHandler for logging 2026-08-27 02:58:39 +01:00
Šarūnas Nejus 28d9dec9fd display: use rich layout 2026-08-27 02:58:09 +01:00
Šarūnas Nejus e20c322dc6 Enable querying related flexible attributes
Unify query creation logic from
- queryparse.py:construct_query_part,
- Model.field_query,
- DefaultTemplateFunctions._tmpl_unique

to a single implementation under `LibModel.field_query` class method.
This method should be used for query resolution for model (flex)fields.

Allow filtering item attributes in album queries and vice versa by
merging `flex_attrs` from Album and Item together as `all_flex_attrs`.
This field is only used for filtering and is discarded after.
2026-08-27 02:56:48 +01:00
Šarūnas Nejus 98051a234d Add ability to filter flexible attributes through the Query
For a flexible attribute query, replace the `col_name` property with
a function call that extracts that attribute from the `field_attrs`
field introduced in the earlier commit.

Additionally, for boolean, numeric and date queries CAST the value to
NUMERIC SQLite affinity to ensure that our queries like 'flex:1..5' and
'flex:true' continue working fine.

This removes the concept of 'slow query', since every query for any
field now has an SQL clause.
2026-08-27 02:56:48 +01:00
Šarūnas Nejus 01375c7392 typing: fix core annotations 2026-08-22 17:49:49 +01:00
Šarūnas Nejus d9e2b65758 Merge branch 'master' into fix/lrclib-null-lyrics 2026-08-22 17:41:55 +01:00
Šarūnas Nejus 467cf7a8b7 Fix lyrics integration tests 2026-08-21 20:56:39 +01:00
Šarūnas Nejus 914441da16 typing: fix command handlers types 2026-08-21 20:56:38 +01:00
Šarūnas Nejus a3bb963ea0 ipfs: fix play command 2026-08-20 00:51:44 +01:00
Šarūnas Nejus 27900f58fb Prefer imports from modules that provide import aliases 2026-08-18 23:20:39 +01:00
Šarūnas Nejus 4aa5aa62ac typing: fix types in beetsplug._utils.art 2026-08-18 23:20:38 +01:00
Šarūnas Nejus 9adcb601f8 typing: make dbcore.db.Results a Sequence
Now we are able to type Results simply as a Sequence. This way, we can
also now use a more generic representation `Sequence[LibModel]` to refer
to *any* of the two models.
2026-08-18 23:20:38 +01:00
Šarūnas Nejus 1969622874 typing: fix types in event handlers 2026-08-18 10:46:33 +01:00
J0J0 Todos 5b0e9e94cd lastgenre: Test new fetch_va_genres helper 2026-08-18 07:01:09 +02:00
Šarūnas Nejus cf385e7614 Merge branch 'master' into fix/skip-empty-metadata-search 2026-08-17 09:35:05 +01:00
Šarūnas Nejus d53af83386 Serialize BPD notifications per connection
- Track active notification tasks by connection so repeated dispatches do not
  send duplicate idle responses while a previous send is still draining.
- Add regression coverage for serialized notification delivery and idle command
  disconnect handling.
2026-08-17 05:05:21 +01:00
Šarūnas Nejus 9b16f67af1 Remove bluelet in favor of using asyncio in bpd plugin 2026-08-17 05:05:21 +01:00
Šarūnas Nejus b19f0c0967 Fix lrclib integration test 2026-08-15 17:53:34 -07:00
David HowardandClaude Opus 5 f68aefa058 lyrics: address review feedback
Return an empty string rather than INSTRUMENTAL_LYRICS from the final
fallback in LRCLyrics.get_text. That branch is not about an instrumental
track, so the marker was misleading.

Strip the LRC timestamps when synced lyrics stand in for a null
plainLyrics. The value is being used as plain text there, so the
timestamps do not belong in it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 17:52:56 -07:00
David Howard cd50a42c04 lyrics: don't match LRCLib entries that have no lyrics
LRCLib stores track metadata independently of the lyrics themselves, so an
entry can come back with both `plainLyrics` and `syncedLyrics` null while
`instrumental` is False. `LRCLyrics.is_valid` accepted such an entry as a
match on duration alone, and `get_text` then returned `self.plain`, i.e.
None, despite being annotated `-> str`.

The None propagated into `Lyrics`, and the first access of its text raised

    AttributeError: 'NoneType' object has no attribute 'splitlines'

`beet lyrics` surfaced this per track, but during an import the exception
escaped the pipeline stage and aborted the entire run: one such track
stranded every file queued behind it.

Treat an entry with no lyrics text as not a match, so the search moves on to
other candidates and backends and ultimately reports that no lyrics were
found. That is deliberately distinct from an instrumental track, where "no
lyrics" is itself the answer and the existing `instrumental` handling still
applies. Marking these as instrumental would assert something the API
response does not tell us.

Also fall back to synced lyrics when only `plainLyrics` is null, rather than
discarding lyrics we do have, and correct the annotations: `plainLyrics` and
`LRCLyrics.plain` are both nullable.
2026-08-15 17:49:54 -07:00
Henry b7993d19ac fix(discogs): retry malformed search responses #6912 2026-08-15 09:53:26 -07:00
Cohen Karnell d97d78f830 Fix KeyError in Deezer track conversion when artist is missing
_get_track resolved the artist with track_data.get('contributors', [track_data['artist']]),
whose default is evaluated eagerly, so track_data['artist'] raises KeyError whenever the
artist key is absent, even when contributors is present. Guard the fallback the same way
album_for_id already does. Fixes #4339.
2026-08-14 12:02:07 -04:00
Sebastian Mohr 54b5d41acd Merge branch 'master' into fix/skip-empty-metadata-search 2026-08-12 12:28:20 +02:00
Trey Turner afd07ce5d3 fix(discogs): retry malformed search responses 2026-08-11 16:04:08 -05:00
Alok Saboo abacc3aad0 Merge branch 'master' into upgrade2 2026-08-11 08:19:15 -04:00
NoDancing f6b7e1f761 tidal: Normalize copyright text into a concise label name
_parse_label() used to store Tidal's raw copyright info as the label
name. Add _normalize_label(), a helper that strips leading markers,
years, legal entities, and boilerplate clauses.

Fixes #6796
2026-08-11 00:39:31 +01:00
Sanjay Santhanam 58bd7ede4c fix: skip metadata source search when query and filters are empty
Items with no artist or title tags produce a search with an empty query
and no filters. The request was still sent to the metadata source API,
and MusicBrainz answers it with a 400 Bad Request, which was logged with
a traceback once per affected file during an import.

Return no candidates instead of issuing a request that cannot match
anything.
2026-08-06 10:04:57 -07:00
Alok Saboo e9d6c996ba remove dead code 2026-08-05 14:46:04 -04:00
Alok Saboo 1ddc95f7a6 address copilot comments 2026-08-05 09:05:51 -04:00
Alok Saboo cbe300f7ef Merge branch 'master' into upgrade2 2026-08-05 08:57:42 -04:00
Alok Saboo c19b6b42d8 add interactive upgrade option 2026-08-05 08:47:26 -04:00
Šarūnas Nejus 97904e7e16 Refactor autotag to use Source abstraction
Introduce Source class to encapsulate metadata extraction logic,
replacing scattered `get_most_common_tags` calls throughout codebase.

- Add Source class in importer.tasks with artist, name, and metadata
- Simplify `distance()` to accept Source.data instead of items list
- Update display functions to use Source objects
- Cache Source creation with @cached_property on ImportTask

This centralizes metadata handling and reduces coupling between
autotag and library modules.
2026-08-05 02:06:48 +01:00
Šarūnas Nejus ea334bd977 Move AttrDict under beets.util 2026-08-05 02:04:12 +01:00
Šarūnas Nejus 5933fcad85 Refactor template evaluation to handle format strings ONLY
- Handle formats as strings ONLY and evaluate them through a shared
  cached template helper.
- This removes the need for conditional logic that acts on Template
  objects or strings.
2026-08-05 01:56:59 +01:00
Šarūnas Nejus 03045b80e9 Merge branch 'master' into master 2026-08-04 16:45:30 +01:00
Vincent Gao 2fe5dc7a0e Fix storing flex media fields during update 2026-08-04 08:29:44 +02:00
Sebastian Cao c7a842941d Fix queries for flexible attributes with uppercase names 2026-08-03 20:31:12 +08:00
Mohsin Hirani 8e6be08849 style: apply ruff formatting to test_util.py 2026-08-02 13:50:06 -04:00
Mohsin Hirani 46498a8967 docs: fix RST markup and improve test coverage per review 2026-08-02 13:39:12 -04:00
Mohsin Hirani 4cf62d5360 test: add tests for editor_command() config option 2026-08-02 13:38:36 -04:00
Piotr Szpetkowski 681f27feb6 fix(deezer): use free text for singleton searches
Singleton searches built the query as `<title> artist:"<artist>"`. Deezer
discards unquoted free text as soon as a query contains any field:"value"
filter, so that was evaluated as `artist:"<artist>"` alone - every track by
the artist, in Deezer's own relevance order, truncated to `search_limit`
(default 5). Substituting nonsense for the title returns a byte-identical
result set. For any artist with more releases than that window, the track
being imported was simply never among the candidates offered.

Filtering on the title as well (`track:"<title>" artist:"<artist>"`) is not
a fix: `artist:` matches loosely enough to return unrelated artists, so the
two filters can intersect to nothing even for a correctly tagged file.
`track:"Get Lucky" artist:"Daft Punk"` returns zero results, while the plain
free text `Get Lucky Daft Punk` returns the right track first.

Measured over 12 tracks at the default `search_limit`, counting the wanted
track appearing anywhere in the results:

  `<title> artist:"..."`              6/12, mean rank 1.50
  `track:"..." artist:"..."`          7/12, mean rank 1.00
  free text                          10/12, mean rank 1.00

Album searches are unchanged; `album:"<name>"` has no equivalent problem.

Adds test/plugins/test_deezer.py, which did not exist.
2026-07-30 21:18:59 +02:00
Alok Saboo 7a49cc4882 Merge branch 'master' into upgrade 2026-07-30 09:11:46 -04:00
Šarūnas Nejus bb66b0c378 Return Path from TestHelper.create_mediafile_fixture 2026-07-30 12:18:49 +01:00
Šarūnas Nejus b2f52ac124 Remove syspath 2026-07-30 12:18:49 +01:00
Šarūnas Nejus 951e32a852 Use pathlib.Path wherever possible in tests 2026-07-30 12:18:49 +01:00
Šarūnas Nejus 04c2304879 Replace item.path with item.filepath in tests 2026-07-30 12:18:49 +01:00