Skip to content

Commit e81856e

Browse files
committed
Moved construct search into SearchApiMetadataSource to dedupe some
deezer and spotify functionalities.
1 parent bde5de4 commit e81856e

File tree

5 files changed

+53
-49
lines changed

5 files changed

+53
-49
lines changed

beets/metadata_plugins.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import warnings
1515
from typing import TYPE_CHECKING, Generic, Literal, Sequence, TypedDict, TypeVar
1616

17+
import unidecode
18+
1719
from beets.util import cached_classproperty
1820
from beets.util.id_extractors import extract_release_id
1921

@@ -338,6 +340,14 @@ class SearchApiMetadataSourcePlugin(
338340
of identifiers for the requested type (album or track).
339341
"""
340342

343+
def __init__(self, *args, **kwargs) -> None:
344+
super().__init__(*args, **kwargs)
345+
self.config.add(
346+
{
347+
"search_query_ascii": False,
348+
}
349+
)
350+
341351
@abc.abstractmethod
342352
def _search_api(
343353
self,
@@ -386,6 +396,34 @@ def item_candidates(
386396
self.tracks_for_ids([result["id"] for result in results if result]),
387397
)
388398

399+
def _construct_search_query(
400+
self, filters: SearchFilter, keywords: str = ""
401+
) -> str:
402+
"""Construct a query string with the specified filters and keywords to
403+
be provided to the Spotify (or similar) Search API.
404+
405+
At the moment, this is used to construct a query string for:
406+
- Spotify (https://developer.spotify.com/documentation/web-api/reference/search).
407+
- Deezer (https://developers.deezer.com/api/search).
408+
409+
:param filters: Field filters to apply.
410+
:param keywords: Query keywords to use.
411+
:return: Query string to be provided to the Search API.
412+
"""
413+
414+
query_components = [
415+
keywords,
416+
" ".join(f'{k}:"{v}"' for k, v in filters.items()),
417+
]
418+
query = " ".join([q for q in query_components if q])
419+
if not isinstance(query, str):
420+
query = query.decode("utf8")
421+
422+
if self.config["search_query_ascii"].get():
423+
query = unidecode.unidecode(query)
424+
425+
return query
426+
389427

390428
# Dynamically copy methods to BeetsPlugin for legacy support
391429
# TODO: Remove this in the future major release, v3.0.0

beetsplug/deezer.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from typing import TYPE_CHECKING, Literal, Sequence
2222

2323
import requests
24-
import unidecode
2524

2625
from beets import ui
2726
from beets.autotag import AlbumInfo, TrackInfo
@@ -216,27 +215,6 @@ def _get_track(self, track_data: JSONDict) -> TrackInfo:
216215
deezer_updated=time.time(),
217216
)
218217

219-
@staticmethod
220-
def _construct_search_query(
221-
filters: SearchFilter, keywords: str = ""
222-
) -> str:
223-
"""Construct a query string with the specified filters and keywords to
224-
be provided to the Deezer Search API
225-
(https://developers.deezer.com/api/search).
226-
227-
:param filters: Field filters to apply.
228-
:param keywords: (Optional) Query keywords to use.
229-
:return: Query string to be provided to the Search API.
230-
"""
231-
query_components = [
232-
keywords,
233-
" ".join(f'{k}:"{v}"' for k, v in filters.items()),
234-
]
235-
query = " ".join([q for q in query_components if q])
236-
if not isinstance(query, str):
237-
query = query.decode("utf8")
238-
return unidecode.unidecode(query)
239-
240218
def _search_api(
241219
self,
242220
query_type: Literal[

beetsplug/spotify.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import confuse
3131
import requests
32-
import unidecode
3332

3433
from beets import ui
3534
from beets.autotag.hooks import AlbumInfo, TrackInfo
@@ -139,7 +138,6 @@ def __init__(self):
139138
"client_id": "4e414367a1d14c75a5c5129a627fcab8",
140139
"client_secret": "f82bdc09b2254f1a8286815d02fd46dc",
141140
"tokenfile": "spotify_token.json",
142-
"search_query_ascii": False,
143141
}
144142
)
145143
self.config["client_id"].redact = True
@@ -422,31 +420,6 @@ def track_for_id(self, track_id: str) -> None | TrackInfo:
422420
track.medium_total = medium_total
423421
return track
424422

425-
def _construct_search_query(
426-
self, filters: SearchFilter, keywords: str = ""
427-
) -> str:
428-
"""Construct a query string with the specified filters and keywords to
429-
be provided to the Spotify Search API
430-
(https://developer.spotify.com/documentation/web-api/reference/search).
431-
432-
:param filters: (Optional) Field filters to apply.
433-
:param keywords: (Optional) Query keywords to use.
434-
:return: Query string to be provided to the Search API.
435-
"""
436-
437-
query_components = [
438-
keywords,
439-
" ".join(f"{k}:{v}" for k, v in filters.items()),
440-
]
441-
query = " ".join([q for q in query_components if q])
442-
if not isinstance(query, str):
443-
query = query.decode("utf8")
444-
445-
if self.config["search_query_ascii"].get():
446-
query = unidecode.unidecode(query)
447-
448-
return query
449-
450423
def _search_api(
451424
self,
452425
query_type: Literal["album", "track"],

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ Bug fixes:
5454
e.g. non latin characters as 盗作. If you want to keep the legacy behavior
5555
set the config option ``spotify.search_query_ascii: yes``.
5656
:bug:`5699`
57+
* :doc:`/plugins/deezer`: Fix the issue with that every query to deezer was
58+
ascii encoded. This resulted in bad matches for queries that contained special
59+
e.g. non latin characters as 盗作. If you want to keep the legacy behavior
60+
set the config option ``deezer.search_query_ascii: yes``.
61+
:bug:`5860`
5762

5863
For packagers:
5964

docs/plugins/deezer.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,14 @@ Configuration
2424

2525
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
2626

27+
The default options should work as-is, but there are some options you can put
28+
in config.yaml under the ``deezer:`` section:
29+
30+
- **search_query_ascii**: If set to ``yes``, the search query will be converted to
31+
ASCII before being sent to Deezer. Converting searches to ASCII can
32+
enhance search results in some cases, but in general, it is not recommended.
33+
For instance `artist:deadmau5 album:4×4` will be converted to
34+
`artist:deadmau5 album:4x4` (notice `×!=x`).
35+
Default: ``no``.
36+
2737
The ``deezer`` plugin provides an additional command ``deezerupdate`` to update the ``rank`` information from Deezer. The ``rank`` (ranges from 0 to 1M) is a global indicator of a song's popularity on Deezer that is updated daily based on streams. The higher the ``rank``, the more popular the track is.

0 commit comments

Comments
 (0)