mirror of
https://github.com/beetbox/beets.git
synced 2026-09-10 06:38:40 -04:00
189 lines
5.7 KiB
Python
189 lines
5.7 KiB
Python
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from beets.library import Item
|
|
from beetsplug.deezer import DeezerPlugin
|
|
|
|
JSONDict = dict[str, Any]
|
|
|
|
|
|
@pytest.fixture
|
|
def plugin():
|
|
return DeezerPlugin()
|
|
|
|
|
|
class TestSearchQuery:
|
|
def test_track_query_is_free_text(self, plugin):
|
|
query, filters = plugin.get_search_query_with_filters(
|
|
"track", [Item()], "Artist", "Title", False
|
|
)
|
|
|
|
assert query == "Title Artist"
|
|
assert filters == {}
|
|
|
|
def test_track_query_tolerates_missing_artist(self, plugin):
|
|
query, _ = plugin.get_search_query_with_filters(
|
|
"track", [Item()], "", "Title", False
|
|
)
|
|
|
|
assert query == "Title"
|
|
|
|
def test_album_query_filters_on_album_and_artist(self, plugin):
|
|
query, filters = plugin.get_search_query_with_filters(
|
|
"album", [Item()], "Artist", "Album", False
|
|
)
|
|
|
|
assert query == 'album:"Album" artist:"Artist"'
|
|
assert filters == {}
|
|
|
|
def test_album_query_omits_artist_for_various_artists(self, plugin):
|
|
query, _ = plugin.get_search_query_with_filters(
|
|
"album", [Item()], "Various Artists", "Album", True
|
|
)
|
|
|
|
assert query == 'album:"Album"'
|
|
|
|
|
|
def make_track(artist_id: int, position: int) -> JSONDict:
|
|
"""Build a minimal Deezer track payload credited to ``artist_id``."""
|
|
return {
|
|
"title": f"Track {position}",
|
|
"id": 1000 + position,
|
|
"link": f"https://www.deezer.com/track/{1000 + position}",
|
|
"duration": 200,
|
|
"track_position": position,
|
|
"disk_number": 1,
|
|
"artist": {"id": artist_id, "name": f"Artist {artist_id}"},
|
|
}
|
|
|
|
|
|
class TestGetTrack:
|
|
def track_data(self, **fields):
|
|
return {
|
|
"id": 1,
|
|
"title": "Title",
|
|
"duration": 100,
|
|
"link": "https://www.deezer.com/track/1",
|
|
**fields,
|
|
}
|
|
|
|
def test_uses_contributors_when_artist_is_missing(self, plugin):
|
|
track = plugin._get_track(
|
|
self.track_data(contributors=[{"id": 2, "name": "Artist"}])
|
|
)
|
|
|
|
assert track.artist == "Artist"
|
|
assert track.artist_id == "2"
|
|
|
|
def test_falls_back_to_artist_without_contributors(self, plugin):
|
|
track = plugin._get_track(
|
|
self.track_data(artist={"id": 2, "name": "Artist"})
|
|
)
|
|
|
|
assert track.artist == "Artist"
|
|
assert track.artist_id == "2"
|
|
|
|
def test_tolerates_missing_artist_and_contributors(self, plugin):
|
|
track = plugin._get_track(self.track_data())
|
|
|
|
assert track.artist is None
|
|
assert track.artist_id is None
|
|
|
|
|
|
class TestVariousArtistsDetection:
|
|
def make_album(
|
|
self, album_artist_id: int, contributor_ids: list[int]
|
|
) -> JSONDict:
|
|
"""Build a minimal Deezer album payload."""
|
|
return {
|
|
"title": "Some Album",
|
|
"link": "https://www.deezer.com/album/1",
|
|
"record_type": "album",
|
|
"label": "Some Label",
|
|
"release_date": "2017-01-01",
|
|
"artist": {
|
|
"id": album_artist_id,
|
|
"name": f"Artist {album_artist_id}",
|
|
},
|
|
"contributors": [
|
|
{"id": aid, "name": f"Artist {aid}"} for aid in contributor_ids
|
|
],
|
|
"cover_xl": None,
|
|
}
|
|
|
|
def mock_album(
|
|
self,
|
|
requests_mock,
|
|
album_artist_id,
|
|
track_artist_ids,
|
|
contributor_ids=None,
|
|
):
|
|
"""Mock the album and album-tracks endpoints for album id 1.
|
|
|
|
``contributor_ids`` overrides the album-level contributors, which
|
|
otherwise cover every artist involved.
|
|
"""
|
|
if contributor_ids is None:
|
|
contributor_ids = list(
|
|
dict.fromkeys([album_artist_id, *track_artist_ids])
|
|
)
|
|
requests_mock.get(
|
|
f"{DeezerPlugin.album_url}1",
|
|
json=self.make_album(album_artist_id, contributor_ids),
|
|
)
|
|
requests_mock.get(
|
|
f"{DeezerPlugin.album_url}1/tracks",
|
|
json={
|
|
"data": [
|
|
make_track(aid, i)
|
|
for i, aid in enumerate(track_artist_ids, start=1)
|
|
]
|
|
},
|
|
)
|
|
|
|
def test_compilation_with_non_va_album_artist(self, plugin, requests_mock):
|
|
# Album credited to a single "main" artist that performs on only one
|
|
# of many tracks: this is a compilation and should be flagged as VA.
|
|
self.mock_album(
|
|
requests_mock,
|
|
album_artist_id=100,
|
|
track_artist_ids=[100, 200, 300, 400, 500, 600],
|
|
)
|
|
|
|
album_info = plugin.album_for_id("1")
|
|
|
|
assert album_info is not None
|
|
assert album_info.va is True
|
|
assert album_info.artist == "Various Artists"
|
|
|
|
def test_plurality_artist_album_not_va(self, plugin, requests_mock):
|
|
# Album whose main artist performs on 2 of 5 tracks (40%) is above
|
|
# the importer's single-artist threshold and stays single-artist.
|
|
self.mock_album(
|
|
requests_mock,
|
|
album_artist_id=100,
|
|
track_artist_ids=[100, 100, 200, 300, 400],
|
|
contributor_ids=[100],
|
|
)
|
|
|
|
album_info = plugin.album_for_id("1")
|
|
|
|
assert album_info is not None
|
|
assert album_info.va is False
|
|
assert album_info.artist == "Artist 100"
|
|
|
|
def test_single_artist_album_not_va(self, plugin, requests_mock):
|
|
# Album whose main artist performs on every track is not a compilation.
|
|
self.mock_album(
|
|
requests_mock,
|
|
album_artist_id=100,
|
|
track_artist_ids=[100, 100, 100, 100],
|
|
)
|
|
|
|
album_info = plugin.album_for_id("1")
|
|
|
|
assert album_info is not None
|
|
assert album_info.va is False
|
|
assert album_info.artist == "Artist 100"
|