Commit graph

12630 commits

Author SHA1 Message Date
Šarūnas Nejus
443ed578dc
Standardize abstract methods for coverage 2025-07-06 16:15:30 +01:00
Šarūnas Nejus
09b22949c0
Refactor test_query
And rewrite test_query.py
2025-07-06 16:15:30 +01:00
Šarūnas Nejus
2c6f314f4f
Replace assertNegationProperties 2025-07-06 16:15:29 +01:00
Šarūnas Nejus
2b306de0fe
Replace assertInResult and assertNotInResult 2025-07-06 16:15:29 +01:00
Šarūnas Nejus
7165b04a22
Move queries and types to respective modules (#5775)
This PR moves query and type definitions away from `library.py` to
`dbcore` to improve modularity and organization.

**Key Changes:**

*   **Query and Type Relocation:**
* `PathQuery` and `SingletonQuery` moved from `beets.library` to
`beets.dbcore.query`.
* `DateType`, `PathType` (and its variants `NullPathType`),
`MusicalKey`, and `DurationType` moved from `beets.library` to
`beets.dbcore.types`.
* The `BLOB_TYPE` definition was moved from `beets.library` to
`beets.dbcore.query` and then referenced in `beets.dbcore.types`.
* The `human_seconds_short` utility function was moved from `beets.ui`
to `beets.util` due to circular dependency.
*   **Test Modernization:**
* The `PathQueryTest` class in `test/test_query.py` has been rewritten
to use `pytest.mark.parametrize` for more concise and readable test
cases.
* **Import Updates:** All internal references to these moved classes and
functions have been updated across the codebase.
2025-07-06 16:14:46 +01:00
Šarūnas Nejus
9d088ab69f
Move human formatting functions under beets.util.units 2025-07-06 16:09:50 +01:00
Šarūnas Nejus
8937978d5f
Refactor PathQuery and add docs 2025-07-06 16:09:50 +01:00
Šarūnas Nejus
45f92ac641
Remove case_sensitive from PathQuery.__init__
The case_sensitive parameter was only used in tests, which now use
monkeypatch to control the behavior of util.case_sensitive() instead.
This simplifies the PathQuery initialization logic while maintaining
test coverage.
2025-07-06 16:09:50 +01:00
Šarūnas Nejus
a38918380d
Rewrite path query tests using pytest.mark.parametrize
And remove `force_implicit_query_detection` attribute from `PathQuery`
class.
2025-07-06 16:09:49 +01:00
Šarūnas Nejus
b40ce836d5
Add NullPathType and types to PathType 2025-07-06 16:09:49 +01:00
Šarūnas Nejus
1a045c9166
Copy paste query, types from library to dbcore 2025-07-06 16:03:46 +01:00
J0J0 Todos
2a896d48b9
Add --remove option to duplicates plugin (#5832)
The duplicates plugin currently only supports deleting files entirely,
sometimes it's desired to only fix the library and keep files in place.
This PR adds this possibility.
2025-07-06 08:56:45 +02:00
J0J0 Todos
7c22cd635c duplicates: Add changelog for --remove option 2025-07-05 07:24:26 +02:00
J0J0 Todos
47eee070ba duplicates: remove or delete options mutually exclusive
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-05 07:22:33 +02:00
J0J0 Todos
549847bfd8 duplicates: Add docs for --remove option 2025-07-05 07:22:28 +02:00
J0J0 Todos
537a71ff82 duplicates: Add --remove option to duplicates plugin
Removes from library but keeps files.
2025-07-05 07:17:59 +02:00
Noor
ac96b9b64e
Preserve line breaks for example cases in substitution plugin docs (#5846)
## Description

Adds line block markup to example substitutions in the plugin
documentation, so that each case is shown on a separate line:

> The replacement can be an expression utilising the matched regex,
allowing us to create more general rules. Say for example, we want to
sort all albums by multiple artists into the directory of the first
artist. We can thus capture everything before the first ,, `` &`` or ``
and``, and use this capture group in the output, discarding the rest of
the string.
> 
> ```yaml
> substitute:
>  ^(.*?)(,| &| and).*: \1
> ```
>
> This would handle all the below cases in a single rule:
>
>> Bob Dylan and The Band -> Bob Dylan
>> Neil Young & Crazy Horse -> Neil Young
>> James Yorkston, Nina Persson & The Second Hand Orchestra -> James
Yorkston
2025-07-02 18:40:37 +00:00
dhruvravii
dd6cb538ac
Fix: Spotify plugin unable to recognize Chinese and Japanese albums. (#5705)
Fixes an issue where each spotify query was converted to ascii before sending. Adds a 
new config option to enable legacy behaviour.

A file called japanese_track_request.json was made to mimic the Spotify
API response since I don't have the credentials. Entries in that will
need to be modified with the actual entries.

Co-authored-by: Sebastian Mohr <sebastian@mohrenclan.de>
Co-authored-by: Sebastian Mohr <39738318+semohr@users.noreply.github.com>
Co-authored-by: J0J0 Todos <2733783+JOJ0@users.noreply.github.com>
2025-07-01 11:08:54 +02:00
Šarūnas Nejus
a005941a56
Fix pipx install action (#5841)
## Fix pipx-install-action Windows compatibility issue

Replace `BrandonLWhite/pipx-install-action@v1.0.3` with
`threeal/pipx-install-action@v1.0.0` in CI workflow due to Windows
compatibility issues.

**Changes:**
- Switch to alternative pipx-install-action that works on Windows
- Add explicit package specification for poethepoet and poetry
- Resolves GitHub issue:
https://github.com/BrandonLWhite/pipx-install-action/issues/62

**Edit**: received a reply from `pipx-install-action` maintainer with a
fix: simply remove the breaking cache from GitHub Actions: this worked
fine.

Thus I reverted the commit which introduced another action on Windows.
The only change that this PR makes is `pipx-install-action` version
upgrade.
2025-06-29 15:06:53 +01:00
Šarūnas Nejus
9926a1ac3c
Revert "Try using threeal/pipx-install-action@v1.0.0 for CI tests"
This reverts commit ab9b2e0b69.
2025-06-29 13:43:48 +01:00
Šarūnas Nejus
ab9b2e0b69
Try using threeal/pipx-install-action@v1.0.0 for CI tests
I have reported the issue with BrandonLWhite/pipx-install-action@v1.0.3
failing on Windows here:
https://github.com/BrandonLWhite/pipx-install-action/issues/62
2025-06-24 12:08:33 +01:00
Šarūnas Nejus
d5bd24bb64
Update pipx-install-action to fix caching errors 2025-06-24 12:08:33 +01:00
Šarūnas Nejus
8fd20b9b67
Fix the MusicBrainz search not taking into account the album/recording aliases (#5821)
When searching on MusicBrainz, beets does not add the `alias` field that
allows for searching on the entity aliases.

As per [the MusicBrainz Indexed Search
Syntax](https://musicbrainz.org/doc/Indexed_Search_Syntax#Search_Fields_9):
> alias | (part of) any alias attached to the release group (diacritics
are ignored)
> [...]
> release | (part of) the title of any of the releases in the release
group

By adding the `alias` field assigned with the entity title, the search
returns better results for titles that can be aliased.

The problem can be reproduced with the following album:
https://musicbrainz.org/release-group/b5b4eed2-e871-4268-80bb-7625ee0c6cd0:
- Currently, beets searches using the following query: [`release:(rude
lose dance \- single) tracks:(1)
artist:(minami)`](https://musicbrainz.org/search?query=release%3A%28rude+lose+dance+%5C-+single%29+tracks%3A%281%29+artist%3A%28minami%29&type=release_group&limit=25&method=advanced)
- We can see that the correct album cannot be found (even after 5
pages!)
- With this PR, beets now searches using the following query:
[`release:(rude lose dance \- single) alias:(rude lose dance \- single)
tracks:(1)
artist:(minami)`](https://musicbrainz.org/search?query=release%3A%28rude+lose+dance+%5C-+single%29+alias%3A%28rude+lose+dance+%5C-+single%29+tracks%3A%281%29+artist%3A%28minami%29&type=release_group&limit=25&method=advanced)
  - We can see that the correct album is now found in 1st position!

Tests had to be updated due to the addition of the `alias` criteria.
2025-06-15 21:54:45 +01:00
Nicolas Mémeint
4893cee5e5 Fix the MusicBrainz search not taking into account the album/recording aliases 2025-06-15 21:33:20 +01:00
Sebastian Mohr
66864fcc27
Minor improvements to spotify plugin typing. (#5815)
## Description

Added some more typehints to the spotify plugin. Also added a method to
get the tokenfile and changed to logic for the handle_response to use
`requests.request`.

This is done mainly to prepare for
https://github.com/beetbox/beets/pull/5787, see also
https://github.com/beetbox/beets/pull/5814
2025-06-11 15:19:46 +02:00
Šarūnas Nejus
0a458966ae
[Inner loop] Require langdetect when running tests (#5801)
Fixes #5797.

Today, local tests (`poe test`) will fail to run if `langdetect` is not
installed. This change makes `langdetect` required for test runs.

Although this is easy to resolve with `poetry install --all-extras`, the
code intends to work without that; it's a worthwhile fix.
2025-06-01 00:12:21 +01:00
Ben Stolovitz
2f98f11d57 fix local langdetect test failures
avoid linter error

avoid other linter error

fix format

changing deps (no lock!)

poetry lock?

lint & format

attempt 2 at poetry lock

crlf -> lf line endings

changelog!
2025-05-31 18:56:21 -04:00
Šarūnas Nejus
87701fd6f0
Move Distance to a dedicated module and refactor related tests (#5800)
This PR:

1. Reorganizes distance-related code by moving it from `hooks.py` and
`match.py` to a new dedicated `distance.py` module:
- The actual implementation logic and algorithms remain unchanged - code
is moved, not rewritten
- Distance class, string distance functions, and track/album distance
calculators are relocated intact
- Only imports and function references are updated to maintain
compatibility
- `current_metadata` function is replaced with equivalent
`get_most_common_tags` function for clarity

2. Refactors the distance testing code from unittest to pytest:
- Tests now use fixtures and parametrization while verifying the same
functionality
- The tested behaviors remain identical, just with improved test
structure
- Actually, `distance.py` coverage slightly increased since I included
an additional test

3. Adds a test for the `sanitize_pairs` function to complete config
utility test coverage

This is primarily a code organization improvement that follows better
separation of concerns, grouping related distance functionality in a
single module without changing how the distance calculations work. No
algorithm changes or behavior modifications were made to the core
distance calculation code - it was simply moved to a more appropriate
location.
2025-05-31 19:49:51 +01:00
Šarūnas Nejus
99f7e94b59
Add Distance and current_metadata to autotag.__init__ for backward compat 2025-05-31 19:17:44 +01:00
Šarūnas Nejus
cb246c28bc
Remove dead chartlyrics
This integration test failed because `chartlyrics.com` website is no
longer available, so I'm removing it.
2025-05-31 19:17:43 +01:00
Šarūnas Nejus
0da6192a4a
Test sanitize_pairs 2025-05-31 19:17:43 +01:00
Šarūnas Nejus
318a840af2
Rewrite distance tests 2025-05-31 19:17:43 +01:00
Šarūnas Nejus
adbd50b237
Move distance to a separate module 2025-05-31 19:17:43 +01:00
Šarūnas Nejus
01b6ea7898
Simplify and speed up plurality/album tags retrieval tests 2025-05-31 19:17:42 +01:00
Šarūnas Nejus
1c9aebd36c
match.current_metadata -> util.get_most_common_tags 2025-05-31 17:58:23 +01:00
Šarūnas Nejus
509cbdcbe4
Move sanitize_pairs/choices from plugins to util module 2025-05-31 17:55:41 +01:00
Ian McCowan
0f76312f31
Fix duplicate database change event send on Library.add (#5561)
## Description

Fixes #5560. Also a couple other incidental changes / improvements:
* Add `EventType` that holds the actual string literals used for event
sending. With type checking, this can prevent subtle bugs resulting from
misspelled event names.
* Fix `HiddenFileTest` by using `bytestring_path()`

## To Do

- [x] ~Documentation.~
- [x] Changelog.
- [x] Tests.

---------

Co-authored-by: J0J0 Todos <jojo@peek-a-boo.at>
Co-authored-by: J0J0 Todos <2733783+JOJ0@users.noreply.github.com>
2025-05-30 13:41:29 +00:00
Uncorrupt3318
dd2f203090
Feat: Add replace plugin (#5644)
Adds replace plugin. The plugin allows the user to replace the audio
file of a song, while keeping the tags and file name.

Some music servers keep track of favourite songs via paths and tags. Now
there won't be a need to 'refavourite'. Plus, this skips the
import/merge steps.
2025-05-27 00:17:52 +02:00
Ben Stolovitz
da5ec00aaf
[Test] Fix path tests on windows (#5803)
## Description

Fixes #5802.

Today, tests fail on most Windows machines because we hard-code `D:` as
the root drive, but most machines use `C:`. This change uses the same
normalization function in the test assertion to ensure the drives match.

## To Do

- [ ] ~~Documentation.~~
- [x] Changelog.
- [x] Tests. (this is a tests change)

## What changed?

* Updated tests to generate the drive name via normalization, instead of
hard-coding `D:`.
* Updated the `Item::destination()` method to document the
`relative_to_libdir` param.

## How tested?

* [x] Tests pass locally.
2025-05-26 19:24:57 +02:00
Šarūnas Nejus
60f24cdc74
Speed up a couple of tests (#5799)
Speed up tests by using `unittest.TestCase` for tests that don't require
directory setup

This PR improves test performance by switching several test classes from
`BeetsTestCase` to standard `unittest.TestCase` when they don't require
the directory setup and teardown overhead. The changes focus on test
classes that:

1. Only test utility functions
2. Don't need temporary directories
3. Don't interact with the filesystem

The PR removes unnecessary imports of `BeetsTestCase` and adds direct
imports of `unittest` where needed. This change reduces the test
execution time by avoiding the expensive setup/teardown steps for tests
that don't require them.
2025-05-26 14:32:36 +01:00
Šarūnas Nejus
5900282093
Use BeetsTestCase for lastgenre tests, re-use the defined config 2025-05-26 13:05:40 +01:00
Šarūnas Nejus
c9f98fca55
Use unittest.TestCase for tests that don't require the dir setup 2025-05-26 12:40:38 +01:00
Šarūnas Nejus
e439c04d89
Make mb_albumartistids available at the album level. (#4909)
As this is a field related to albums, it probably should be accessible
as `album.mb_albumartistids`.
2025-05-22 15:54:05 +01:00
David Logie
43b20f2850 Make mb_albumartistids available at the album level. 2025-05-22 15:49:27 +01:00
Sebastian Mohr
9584216209
Streamlined auto api referencing for documentation (#5795)
## Description

The current developer documentation feels somewhat cluttered due to
inline auto-generated API references for certain classes. To improve
readability and maintainability, this PR introduces a more streamlined
approach that aligns better with best practices observed in other PyData
ecosystem documentation.

Specifically, this PR:
- Adds a dedicated `api/` folder to the documentation structure.
- Moves all auto-generated references (classes, methods, etc.) to this
folder.
- Enables clean, concise linking to API elements from the narrative
documentation—without interrupting human-written content with large
autogenerated blocks.

This separation makes the documentation easier to navigate and maintain,
while still providing full API reference coverage where needed.

- [x] Documentation
- [x] Changelog
2025-05-22 11:35:40 +02:00
Šarūnas Nejus
5356e6e5ea
Replace outdated bitesized label link (#5790)
Meta: I was looking for possible contribution opportunities, so I
noticed this in the docs. I assume that the `bite-size` label is
outdated, as there aren't actually any issues with that label. Looks
like https://github.com/beetbox/beets/labels/good%20first%20issue is
currently used.

Note: Further below there's also mention of a `first timers only` label
– that link also yields no results and even gives a message about the
label being invalid. I wasn't sure if/how that should be replaced, so I
didn't touch it. Maybe the sentence I am changing should actually be
moved down and replace the one mentioning `first timers only`?
2025-05-21 11:19:04 +01:00
Manu
8e84268e06 Replace outdated bitesized label link 2025-05-21 11:13:50 +01:00
Benedikt
79c87e5886
Add fetchart typing v2 (#5716)
Adds typings to fetchart; a revised and modernized version of
https://github.com/beetbox/beets/pull/5213.

The former pull request became stale because I did more refactoring
there, in order to express properties of the `Candidate` (whether or not
it is validated) via the type system (motivated by the type state
pattern which is more common in Rust.
The result was a little contentious, since it became a little unclear
what the purpose of the `Candidate` class should even be at that point.

I think this was a case of combining too many things into a single PR.
Thus, this version does not perform any refactoring of that extent. It
does sprinkle in a few `assert`s to make thinks clear for the type
checker.
2025-05-20 11:07:22 +02:00
wisp3rwind
728076e97d fetchart: assert some invariants to satisfy mypy
Eventually, it would be nice to avoid this by more expressive typings.
For now, avoid such larger refactoring.
2025-05-20 10:06:11 +02:00
wisp3rwind
10d1c51a1d fetchart: consistently use lazy string formatting for debug logging 2025-05-20 09:23:34 +02:00