Commit graph

3847 commits

Author SHA1 Message Date
J0J0 Todos
462a7a524a _combine_and_label return None not empty str 2025-01-21 17:04:02 +01:00
J0J0 Todos
6866fce364 Fix default for _dedup_genre whitelist arg
when not stated otherwise whitelist_only must be disabled, we assume it
that way in _get_genre calls.
2025-01-21 17:04:02 +01:00
J0J0 Todos
cbc33e78fc lastgenre: Add comments over groups of methods
trying to get a little order in the chaos. Maybe reordering and/or
moving out of the main plugin logic would be a better idea for some
methods but don't put much more refactoring into this PR to keep it
readable.
2025-01-21 17:04:02 +01:00
J0J0 Todos
11f7a98917 Refactor keep/new genres combination
- Handle genre combination logic in a well documented helper function
  that also include type hints.
- Throughout the _get_genre function rename the result variable to
  new_genres to make it clearly descriptive.
- Rewrite thze _get_genre function's docstring.
2025-01-21 17:04:02 +01:00
J0J0 Todos
d935ec869c Implement --force and --keep-allowed behaviours
- Retrieving, filtering and deduplicating present genres of Items/Albums
  via separate methods.
- Implement all four cases of behaviour as described in PR#4982
- Issues:
  - There is quite some unnecessary spliting of genres from strings into
    lists and the other way round happening throughout the plugin.
  - In the case where existing genres get "augmented" with last.fm
    genres, we might end up with _more_ genres than the configured
    limit.
2025-01-21 17:04:02 +01:00
J0J0 Todos
318c02099a Add lastgenre keep_allowed options (-k/-K)
- Default to False.
- During PR#4982 discussions we came to the conclusion that the
  following behaviour would be a good new default choice:
  - Keep whitelisted existing genres
  - Only Fetch last.fm genres for empty tags.
  - To get this we also have to change the default of the force
    option!!!
  - Resulting in "force: no" and "keep_allowed: yes"; see Case 4 in
    PR#4982 description
- Options are not put to use yet, just defined and defaults set!
2025-01-21 17:04:02 +01:00
J0J0 Todos
4ea8650799 Use provided deduplicate function for keep_allowed
generation, instead of a simple set(). This way we keep the original
order of genres.
2025-01-21 17:04:02 +01:00
J0J0 Todos
fe466f4bb3 Use separator as configured instead of hardcoding
in lastgenre plugin.
2025-01-21 17:04:02 +01:00
J0J0 Todos
517c037c25 Refactor lastgenre keep_allowed to list comprehension 2025-01-21 17:04:02 +01:00
J0J0 Todos
7d6a4046ce Handle dups of existing genres in lastgenre plugin
When handling existing comma-separated genres in the _get_genre method
of the plugin, make sure duplicate genres are removed.
2025-01-21 17:04:02 +01:00
J0J0 Todos
6ab6ae2051 Fix track-level genre handling in lastgenre plugin
When `lastgenre.source: track` is configured,

- `lastgenre -a` _should not_ fall back to the album level genre (by
  making use of the with_album=False kwarg of the Libary's get method).
- `lastgenre -a`, when finally storing the genres of _an album_, should
  _not_ also write the tracks genres (by making use of the inherit=False
  kwarg of the Album's store method.
2025-01-21 17:04:02 +01:00
J0J0 Todos
4ff8c34ed1 Quickfix lastgenre always overwriting multi-genre 2025-01-21 17:04:02 +01:00
Šarūnas Nejus
bb5f3e0593
lyrics: sort lrclib lyrics by synced field and query search first
I found that the `/get` endpoint often returns incorrect or unsynced
lyrics, while results returned by the `/search` more accurate options.

Thus I reversed the change in the previous commit to prioritize
searching first.
2025-01-20 13:14:37 +00:00
Šarūnas Nejus
33aafdd50b
Remove trailing spaces in synced lyrics lines without text 2025-01-19 18:39:56 +00:00
Šarūnas Nejus
618c3a21a6
Try to GET LRCLib lyrics before searching 2025-01-19 18:39:54 +00:00
Šarūnas Nejus
2fb72c65a5
lyrics/LRCLib: handle instrumental lyrics 2025-01-19 15:19:44 +00:00
Šarūnas Nejus
30379bca38
Update lyrics.sources configuration to prioritize lrclib 2025-01-19 15:19:44 +00:00
Šarūnas Nejus
a398fbe62d
LRCLib: Improve exception handling 2025-01-19 15:19:44 +00:00
Šarūnas Nejus
8d4a569291
Fix fetching lyrics from lrclib
Adjust the base URL to perform a '/search' instead of attempting to
'/get' specific lyrics where we're unlikely to find lyrics for the
specific combination of album, artist, track names and the duration (see
https://lrclib.net/docs).

Since we receive an array of matching lyrics candidates, rank them by
their duration similarity to the item's duration, and whether they
contain synced lyrics.
2025-01-19 15:19:41 +00:00
Šarūnas Nejus
c250bfa724
Google: test the entire fetch method 2025-01-19 01:48:04 +00:00
Šarūnas Nejus
334bbde826
Make album, duration required for LyricsPlugin.fetch
Since at least one Backend requires album` and `duration` arguments
(`LRCLib`), the caller (`LyricsPlugin.fetch_item_lyrics`) must always
provide them.

Since they need to provided, we need to enforce this by defining them as
positional arguments.

Why is this important? I found that integrated `LRCLib` tests have been
passing, but they called `LRCLib.fetch` with values for `artist` and
`title` fields only, while the actual functionality *always* provides
values for `album` and `duration` fields too.

When I adjusted the test to provide values for the missing fields,
I found that it failed. This makes sense: Lib `album` and `duration`
filters are strict on LRCLib, so I was not surprised the lyrics could
not be found.

Thus I adjusted `LRCLib` backend implementation to only filter by each
of these fields when their values are truthy.
2025-01-19 01:48:04 +00:00
Šarūnas Nejus
0a12d07a94
Do not attempt to fetch lyrics with empty data
Modified `search_pairs` function in `lyrics.py` to:

* Firstly strip each of `artist`, `artist_sort` and `title` fields
* Only generate alternatives if both `artist` and `title` are not empty
* Ensure that `artist_sort` is not empty and not equal to artist (ignoring
  case) before appending it to the artists

Extended tests to cover the changes.
2025-01-19 01:48:04 +00:00
Šarūnas Nejus
3b73a26002
Address failing google sources tests
Two google sources failed to return the expected output. I looked into
each case why parsing failed:

- lyrics on musica.com contain <aside> Google Ads
- each lyrics line on lacoccinelle.net is wrapped within alternating
  <em> and <strong> tags

Thus remove these tags as part of the HTML cleanup logic.
2025-01-19 01:32:17 +00:00
Šarūnas Nejus
a8ad7df064
Use Item.field_query for queries that receive user input 2025-01-19 01:09:11 +00:00
Šarūnas Nejus
4650f6513b
Add Item.any_writable_media_field_query method for BPD search 2025-01-19 01:09:11 +00:00
J0J0 Todos
0c10635ff7 Another round of lastgenre logging nitpicks
- Printing out album/item in default format could lead to unreadable
  clutter depending on the user's configured formats.
- The album's name and the individual tracks' title should be just
  sufficient to provide context as well readability.
- Log like this while importing as well as in standalone runs.
2025-01-07 01:54:17 +01:00
J0J0 Todos
9d09d6f317 Fix lastgenre source:track handling during imports 2025-01-07 01:54:17 +01:00
J0J0 Todos
18e76f08c7 Prevent album genre inherit only when source:track
is configured.
2025-01-07 01:54:17 +01:00
J0J0 Todos
9ec2a8146f Streamline lastgenre singleton log with album log
It was rather confusing that the lastgenre plugin, when handling
singletons, sometimes showed that it applied genres from last.fm and
sometimes didn't (it did only in debug log). This streamlines the
behaviour:

- Change debug to info log.
- Streamline wording.
- Display details about the track.
2025-01-07 01:54:17 +01:00
J0J0 Todos
d4ada3ce43 Fix track-level genre handling in lastgenre plugin
When `lastgenre.source: track` is configured,

- `lastgenre -a` _should not_ fall back to the album level genre (by
  making use of the with_album=False kwarg of the Libary's get method).
- `lastgenre -a`, when finally storing the genres of _an album_, should
  _not_ also write the tracks genres (by making use of the inherit=False
  kwarg of the Album's store method.
2025-01-07 01:53:58 +01:00
Šarūnas Nejus
5c81f94cf7
Move imports required for typing under the TYPE_CHECKING block 2024-12-10 06:10:04 +00:00
Šarūnas Nejus
161b0522bb
Update deprecated imports 2024-12-10 06:10:04 +00:00
Šarūnas Nejus
7ef1b61070
Replace Union types by PEP604 pipe character 2024-12-10 06:10:04 +00:00
Šarūnas Nejus
51f9dd229e
Use PEP585 lowercase collections typing annotations 2024-12-10 06:10:03 +00:00
Edgars Supe
09360259cc lyrics: Fallback to plain lyrics if synced not available 2024-12-07 19:08:37 +02:00
Šarūnas Nejus
65e935bee5
Perform a regex substitution in the substitute plugin (#5357)
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.
2024-11-22 05:02:50 +00:00
Alok Saboo
b9c6ee208e lint error 2024-11-10 20:27:41 -05:00
Alok Saboo
35c6e13255 Update line length 2024-11-10 20:25:28 -05:00
Alok Saboo
3586669dd5 Merge branch 'lb_error' of https://github.com/arsaboo/beets into lb_error 2024-11-10 20:24:36 -05:00
Alok Saboo
24115167d3 Merge remote-tracking branch 'upstream/master' into lb_error 2024-11-10 20:23:34 -05:00
Alok Saboo
c1b4b58e65
Update beetsplug/listenbrainz.py
Co-authored-by: Šarūnas Nejus <snejus@protonmail.com>
2024-11-10 20:23:11 -05:00
Šarūnas Nejus
69dbfd9868
Fix lints
These seem to have managed to escape the CI checks since the previously
merged PR was based on master commit which did not include the checks.
2024-10-30 12:13:30 +00:00
Joseph Bushell
4b78abd939 create seperate in_no_convert function, update tests 2024-10-26 19:09:56 +01:00
Joseph Bushell
d1c88bbd25 consider value of no_convert as one query rather than splitting 2024-10-26 18:17:00 +01:00
Alok Saboo
93aa569e3f Improve ListenBrainz error handling and simplify playlist handling 2024-10-25 10:06:54 -04:00
Nicholas Boyd Isacsson
8e0558b804 Apply substitute rules in sequence 2024-10-16 16:36:36 +02:00
Nicholas Boyd Isacsson
ffdc3f73ab Revert configuration format changes 2024-10-14 22:54:38 +02:00
Nicholas Boyd Isacsson
195644fc46 Refactor according to review comments 2024-10-12 15:34:05 +02:00
Šarūnas Nejus
d3955bac65
Update Tekstowo backend to fetch lyrics directly
- Refactored Tekstowo backend to fetch lyrics directly from song pages.
- Added `encode` method to convert artist and title to their URL format,
  where non-alphanumeric characters are replaced with underscores.
- Removed the now redundant search functionality and associated tests.
- Simplified `extract_lyrics` method to directly parse lyrics without
  any checks.
2024-10-12 02:14:18 +01:00
Šarūnas Nejus
9d2b34d457
Create DirectBackend interface for MusiXmatch and Tekstowo
And replace some of the encoding logic by unidecode.
2024-10-12 01:29:55 +01:00