Commit graph

13711 commits

Author SHA1 Message Date
Will Burden
8a97fba2ab Fix ReplacePlugin CLI command 2026-03-08 17:27:07 +00:00
Šarūnas Nejus
80d08ed11b
beatport: Deprecate beatport and bpsync plugins (#6426)
As agreed in the comments:
https://github.com/beetbox/beets/pull/4477#issuecomment-3990774420

Deprecation notices reference those for additional context:
- https://github.com/beetbox/beets/issues/3862
- https://github.com/beetbox/beets/pull/4477

Beatport retired the API (v3) that the built-in `beatport` plugin relies
on, making it non-functional. This PR soft-deprecates both the
`beatport` and `bpsync` plugins following the same pattern used for
`acousticbrainz` — adding deprecation warnings in `__init__()` while
keeping all existing code intact.

The `bpsync` plugin is deprecated alongside `beatport` since it imports
and depends on `BeatportPlugin` directly.

### Changes

- **`beetsplug/beatport.py`**: Add deprecation warning in
`BeatportPlugin.__init__()`
- **`beetsplug/bpsync.py`**: Add deprecation warning in
`BPSyncPlugin.__init__()`
- **`docs/plugins/beatport.rst`**: Add `.. deprecated::` directive
- **`docs/plugins/bpsync.rst`**: Add `.. deprecated::` directive
- **`docs/changelog.rst`**: Add changelog entry under Unreleased → Other
changes

### What's NOT changed (and why)

- **`pyproject.toml`** (beatport extra): Kept so the plugin loads and
shows the deprecation warning instead of crashing with an `ImportError`
- **`test/plugins/test_beatport.py`**: Tests cover data models which
still exist — all 15 tests pass
- **`docs/plugins/index.rst`**: `beatport` stays in the toctree since
the page still exists
- **`beets/util/id_extractors.py`**: Core utility, not plugin-specific
2026-03-08 17:17:45 +00:00
Szymon Tarasiński
b008488b84 refactor: Use deprecate_for_user for beatport/bpsync deprecation warnings 2026-03-08 17:10:29 +00:00
Szymon Tarasiński
bdb039c760 Fix docs: use single-line deprecated directive compatible with docstrfmt 2026-03-08 17:10:29 +00:00
Szymon Tarasiński
740db4d500 Fix docs formatting for beatport and bpsync rst files 2026-03-08 17:10:29 +00:00
Szymon Tarasiński
efa1f370b7 Deprecate beatport and bpsync plugins
Beatport has retired the API these plugins rely on, making them
non-functional. Add deprecation warnings and update documentation
to reflect the current state.

Fixes #3862
2026-03-08 17:10:29 +00:00
Šarūnas Nejus
f1509a40f9
Fix fish plugin (#6428)
Fixes #6340
2026-03-08 13:24:01 +00:00
Konstantin
d2705fef4e Update changelog.rst 2026-03-08 14:16:49 +01:00
Konstantin
b64bda86ff try to fix fish plugin 2026-03-08 13:57:42 +01:00
Šarūnas Nejus
3c48b0c6e6
Centralise common autotagger search functionality (#5982)
Add a unified search abstraction across metadata source plugins.

Summary:
- Introduces `SearchApiMetadataSourcePlugin` with `SearchParams`,
`get_search_query_with_filters`, and `get_search_response` hooks to
standardize album/track searches.
- Replaces ad-hoc `_search_api` and query construction logic in Deezer,
Spotify, MusicBrainz, and Discogs plugins with the new shared
implementation.
- Refactors Discogs and MusicBrainz plugins to use the new abstraction
and move provider-specific criteria/query construction into hook
methods.
- Centralizes error handling and logging in the shared search flow;
Spotify now retries authentication once on `401`, and failures cleanly
fall back to empty results at the shared layer.
2026-03-08 09:17:48 +00:00
Šarūnas Nejus
46aa0a4ba5
Make get_search_query_with_filters abstract 2026-03-08 09:06:00 +00:00
Šarūnas Nejus
0670611d7a
Document new methods 2026-03-08 09:00:14 +00:00
Šarūnas Nejus
4cccb70921
Document shared metadata search plugin workflow
Add developer guidance for SearchApiMetadataSourcePlugin and its hooks.

Clarify migration advice for API-backed metadata source plugins.
2026-03-08 09:00:14 +00:00
Šarūnas Nejus
9855d46901
Bound Spotify auth retry during search
Replace recursive 401 handling with a single retry loop.

This prevents unbounded recursion when authentication keeps failing.
2026-03-08 09:00:14 +00:00
Šarūnas Nejus
9b63985989
Migrate MusicBrainz to shared search hooks
Move MusicBrainzPlugin to SearchApiMetadataSourcePlugin hooks.

Keep entity mapping and criteria in provider-specific hooks.

Update typing and tests for the candidate search path.
2026-03-08 09:00:14 +00:00
Šarūnas Nejus
27bb34411c
Refactor shared search API flow
Move search orchestration into SearchApiMetadataSourcePlugin.

Migrate Deezer, Spotify, and Discogs to provider hooks.

Keep query handling, logging, and limits centralized.
2026-03-08 09:00:14 +00:00
Šarūnas Nejus
9f6a4b4147
Clarify %if template behavior (#6399)
Fixes #4991.

I don't know if there's a single, good workaround for this, so I opted
to not add an example solution.
2026-03-08 08:57:55 +00:00
Emil Hammarberg
1f2beb6d02 Format 2026-03-08 08:51:42 +00:00
Emil Hammarberg
763dc7ccb1 Fix empty literal error 2026-03-08 08:51:42 +00:00
Emil Hammarberg
8a57472224 Reword 2026-03-08 08:51:42 +00:00
Emil Hammarberg
654b76190c Clarify %if template behavior
Closes #4991
2026-03-08 08:51:42 +00:00
Šarūnas Nejus
6ef2a8cb0d
docs(CONTRIBUTING): Fix typo (#6423) 2026-03-08 08:50:12 +00:00
Pierre Ayoub
af42992cd9 docs(CONTRIBUTING): Fix typo 2026-03-08 08:45:09 +00:00
snejus
13665a5a55 Increment version to 2.7.1 2026-03-08 08:30:00 +00:00
Šarūnas Nejus
1acbdbd67c
Skip langdetect-dependent tests when package is not installed (#6422)
## Skip `langdetect`-dependent tests when package is unavailable

Fixes #6421.

### What changed

- Adds a `requires_import(module)` pytest marker to `conftest.py` that
skips tests when an optional dependency is not installed
- Adds an `is_importable` fixture for conditional assertions within a
test body
- Marks `TestTranslation` and other `langdetect`-dependent
tests/assertions with the new marker or fixture
- Extends `requires_import` with a `force_ci=True` kwarg — tests marked
this way are **never** skipped in `beetbox/beets` CI, ensuring coverage
where all deps are installed
- Moves marker declarations from `setup.cfg` into `pytest_configure` in
`conftest.py`
2026-03-08 08:26:58 +00:00
Šarūnas Nejus
bd2a448ca6
Document custom marks in CONTRIBUTING.rst 2026-03-08 08:19:55 +00:00
Šarūnas Nejus
a8b34d2976
Pin docstrfmt>=2.0.2 and add --preserve-adornments flag 2026-03-08 08:19:55 +00:00
Šarūnas Nejus
b683cb6540
Extend requires_import marker with force_ci option
Add force_ci kwarg to requires_import pytest marker to allow tests
to run unconditionally in CI (GitHub Actions), even if the module
is not detected locally. Refactor autobpm test to use this instead
of manual env-checking at module level.
2026-03-08 08:19:55 +00:00
Šarūnas Nejus
13ad15b83e
Move pytest marker definitions to conftest.py
Replace static marker declarations in setup.cfg with dynamic
registration via pytest_configure hook in conftest.py.
2026-03-08 08:19:55 +00:00
Šarūnas Nejus
a7325e7483
Skip langdetect-dependent tests when package is not installed
Add a `requires_import` pytest marker and `is_importable` fixture to
conditionally skip or adjust assertions based on whether optional
dependencies are available. Apply this to `langdetect`-dependent
language detection tests in lyrics and migration test suites.
2026-03-08 08:19:55 +00:00
Šarūnas Nejus
2678124b88
Upgrade all dependencies (#6420)
See

<img width="1029" height="1235" alt="image"
src="https://github.com/user-attachments/assets/979fbc1b-385c-4ba5-b48a-d7658d6e7a0d"
/>
2026-03-07 21:56:43 +00:00
Šarūnas Nejus
02145a3ac0
Upgrade all dependencies 2026-03-07 21:33:24 +00:00
snejus
156870419e Increment version to 2.7.0 2026-03-07 21:16:10 +00:00
Šarūnas Nejus
c996a42f6d
Add docs fixes to git blame ignore revs 2026-03-07 19:43:52 +00:00
Šarūnas Nejus
cff5434cf7
Fix docs links (#6418)
## Documentation Link Maintenance

This PR audits and fixes all hyperlinks across the beets documentation.
No functional code changes — purely doc hygiene.

### What changed

- **HTTP → HTTPS**: Upgrades all `http://` links to `https://` where
supported.
- **Broken/outdated URLs**: Replaces dead or redirected links with their
current canonical targets. Key examples:
  - `codecov.io` → `app.codecov.io`
- Python docs from `docs.python.org/library/` →
`docs.python.org/3/library/`
  - PEP links from `python.org/dev/peps/` → `peps.python.org/`
  - SourceForge project links updated to current project page URLs
- Spotify, Plex, Sonos, Discogs, IPFS, and other service URLs updated to
their current domains/paths
- Archived URLs wrapped in `web.archive.org` where the original is gone
(e.g. `echonest`, `albumart.org`, `phash`)
- **`docs/conf.py`**: Adds link-check exclusions for domains known to
block automated requests (SourceForge, fanart.tv, Imgur, Discogs
settings).

### Impact

No user-facing behaviour changes. Fixes broken links that would
frustrate contributors and users reading the docs, and unblocks the
Sphinx `linkcheck` builder from false positives.
2026-03-07 19:40:59 +00:00
Š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
a6ac5eff5b
Add lyrics_url, lyrics_backend flex attrs, improve lrclib reliability (#6393)
Fixes: #6370

This PR completes the lyrics pipeline refactor around a structured
`Lyrics` value object and aligns storage, migration, and docs with that
model.

At a high level, lyrics handling is now end-to-end structured instead of
ad-hoc string/tuple flows: fetchers return `Lyrics`, translation
operates on `Lyrics`, and persistence writes both canonical text and
structured metadata.

High-level impact:

- Backends now return `Lyrics` instead of `(text, url)` tuples.
- Lyrics source metadata is no longer embedded in `item.lyrics` as a
`Source: ...` suffix.
- Lyrics metadata is stored in flexible fields:
`lyrics_backend`, `lyrics_url`, `lyrics_language`,
`lyrics_translation_language`.
- Existing libraries are automatically migrated on first run by a
one-time data migration that:
normalizes legacy mixed-content lyrics text and moves auxiliary metadata
into flex fields.
- Sync safety is improved:
with `synced` enabled, existing synced lyrics are not replaced by newly
fetched plain lyrics, even with `force`.
- LRCLib synced lyrics validation is stricter:
synced results are accepted only when the final synced timestamp is
consistent with track duration.

Docs and tests:

- Lyrics plugin docs now describe the new flexible metadata fields and
synced replacement behavior.
- Developer docs now document migration lifecycle, class-name-based
migration identity, and migration use cases.
- Changelog updated for all user-visible behavior changes.
- Tests were expanded/updated for migration behavior, backend return
types, translation behavior, synced-lyrics safety, and LRCLib duration
validation.
2026-03-06 11:27:53 +00:00
Šarūnas Nejus
ace6a99d07
Document methods changed/introduced 2026-03-06 10:57:08 +00:00
Šarūnas Nejus
e8605747d6
Document migrations 2026-03-06 10:57:08 +00:00
Šarūnas Nejus
05a822dd5c
Move Lyrics class under beets.util as it is used by migrations 2026-03-06 10:57:08 +00:00
Šarūnas Nejus
50a564e66d
Set constant langdetection seed for stable results 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
7df14e1877
Fix timestamp format in translation/synced lyrics test 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
835115a6f7
Fix genius end to end lyrics test 2026-03-06 10:57:08 +00:00
Šarūnas Nejus
c239275193
Do not split orig/trans if they are not different 2026-03-05 15:36:59 +00:00