Fixes#5148.
When importing, the code that matches tracks does not consider the
medium number. This causes problems on Hybrid SACDs (and other releases)
where the artists, track numbers, titles, and lengths are the same on
both layers.
I added a distance penalty for mismatching medium numbers.
Before:
```
$ beet imp .
/Volumes/Music/ti/Red Garland/1958 - All Mornin' Long - 1 (6 items)
Match (95.4%):
The Red Garland Quintet - All Mornin' Long
≠ media, year
MusicBrainz, 2xHybrid SACD (CD layer), 2013, US, Analogue Productions, CPRJ 7130 SA, mono
https://musicbrainz.org/release/6a584522-58ea-470b-81fb-e60e5cd7b21e
* Artist: The Red Garland Quintet
* Album: All Mornin' Long
* Hybrid SACD (CD layer) 1
≠ (#2-1) All Mornin' Long (20:21) -> (#1-1) All Mornin' Long (20:21)
≠ (#2-2) They Can't Take That Away From Me (10:24) -> (#1-2) They Can't Take That Away From Me (10:27)
≠ (#2-3) Our Delight (6:23) -> (#1-3) Our Delight (6:23)
* Hybrid SACD (CD layer) 2
≠ (#1-1) All mornin' long (20:21) -> (#2-1) All Mornin' Long (20:21)
≠ (#1-2) They can't take that away from me (10:27) -> (#2-2) They Can't Take That Away From Me (10:25)
≠ (#1-3) Our delight (6:23) -> (#2-3) Our Delight (6:23)
➜ [A]pply, More candidates, Skip, Use as-is, as Tracks, Group albums,
Enter search, enter Id, aBort, eDit, edit Candidates?
```
Note that all tracks tagged with disc 1 get moved to disc 2 and vice
versa.
After:
```
$ beet-test imp .
/Volumes/Music/ti/Red Garland/1958 - All Mornin' Long - 1 (6 items)
Match (95.4%):
The Red Garland Quintet - All Mornin' Long
≠ media, year
MusicBrainz, 2xMedia, 2013, US, Analogue Productions, CPRJ 7130 SA, mono
https://musicbrainz.org/release/6a584522-58ea-470b-81fb-e60e5cd7b21e
* Artist: The Red Garland Quintet
* Album: All Mornin' Long
* Hybrid SACD (CD layer) 1
≠ (#1-1) All mornin' long (20:21) -> (#1-1) All Mornin' Long (20:21)
≠ (#1-2) They can't take that away from me (10:27) -> (#1-2) They Can't Take That Away From Me (10:27)
≠ (#1-3) Our delight (6:23) -> (#1-3) Our Delight (6:23)
* Hybrid SACD (SACD layer) 2
* (#2-1) All Mornin' Long (20:21)
* (#2-2) They Can't Take That Away From Me (10:24)
* (#2-3) Our Delight (6:23)
➜ [A]pply, More candidates, Skip, Use as-is, as Tracks, Group albums,
Enter search, enter Id, aBort, eDit, edit Candidates?
```
Yay!
Quick fix for #5467.
Checks if the path for python is under the windows store folder then
error and point the user to the beets
[documentation](https://beets.readthedocs.io/en/stable/guides/main.html).
Happy for feedback to improve, but thought it best to exit as early as
possible.
This utilises regex substitution in the substitute plugin. The previous
approach only used regex to match the pattern, then replaced it with a
static string. This change allows more complex substitutions, where the
output depends on the input.
### Example use case
Say we want to keep only the first artist of a multi-artist credit, as
in the following list:
```
Neil Young & Crazy Horse -> Neil Young
Michael Hurley, The Holy Modal Rounders, Jeffrey Frederick & The Clamtones -> Michael Hurley
James Yorkston and the Athletes -> James Yorkston
````
This would previously have required three separate rules, one for each
resulting artist. By using a regex substitution, we can get the desired
behaviour in a single rule:
```yaml
substitute:
^(.*?)(,| &| and).*: \1
```
(Capture the text until the first `,` ` &` or ` and`, then use that
capture group as the output)
### Notes
I've kept the previous behaviour of only applying the first matching
rule, but I'm not 100% sure it's the ideal approach.
I can imagine both cases where you want to apply several rules in
sequence and cases where you want to stop after the first match.
This PR refactors the test codebase by removing redundant functions and
simplifying item and album creation. Key changes include:
- Removed redundant `_item_ident` index tracker from `_common.py`.
- Removed `album` function from `_common.py` replacing it with direct
`library.Album` invocations.
- Removed `generate_album_info` and `generate_track_info` functions,
replacing them directly with `TrackInfo` and `AlbumInfo`.
- Updated `setup.cfg` to exclude test helper files from coverage
reports.
- Adjusted the tests regarding the changes, and simplified
`test_mbsync.py`.
Seems like readthedocs build expects docs dependencies to be available
as an extra, see one of the failing builds:
https://app.readthedocs.org/projects/beets/builds/26079213/.
You can see this has been failing due to missing 'pydata_sphinx_theme'
which is one of our dependencies:
```
raise ThemeError(__('no theme named %r found (missing theme.toml?)') % name)
sphinx.errors.ThemeError: no theme named 'pydata_sphinx_theme' found (missing theme.toml?)
Theme error:
no theme named 'pydata_sphinx_theme' found (missing theme.toml?)
```
This was a very bad idea since this made CI operate within the context
of the *base* branch, which meant that the tests were testing code in
the `master` branch instead of the branch that was to be merged!
Seems like readthedocs build expects docs dependencies to be available
as an extra, see one of the failing builds: https://app.readthedocs.org/projects/beets/builds/26079213/.
You can see this has been failing due to missing 'pydata_sphinx_theme':
raise ThemeError(__('no theme named %r found (missing theme.toml?)') % name)
sphinx.errors.ThemeError: no theme named 'pydata_sphinx_theme' found (missing theme.toml?)
Theme error:
no theme named 'pydata_sphinx_theme' found (missing theme.toml?)
I was running the `convert` plugin with the following config:
```
no_convert: samplerate:..48000 bitdepth:..16
```
but anything that was 24/48 was also not being converted, this was due
to the code returning `False` for `should_transcode` if any part of the
query matches, rather than considering the whole query. This meant that
`bitdepth:...16` was being ignored.
I have changed this so the `no_convert` value is considered as one
query.