/
/
/
1"""Tests for Soundcloud artist and track metadata parsing."""
2
3from __future__ import annotations
4
5from typing import Any
6
7import pytest
8from music_assistant_models.errors import InvalidDataError
9
10from music_assistant.providers.soundcloud import SoundcloudMusicProvider
11
12
13def _artist_obj(**extra: Any) -> dict[str, Any]:
14 """Build a Soundcloud API user object."""
15 return {"id": 5, "username": "Some Artist", "permalink": "some-artist", **extra}
16
17
18def _track_obj(**extra: Any) -> dict[str, Any]:
19 """Build a Soundcloud API track object."""
20 return {
21 "id": 1,
22 "title": "Some Track (Radio Edit)",
23 "duration": 235818,
24 "permalink_url": "https://soundcloud.com/artist/1",
25 "user": {"id": 5, "username": "Some Artist", "permalink": "some-artist"},
26 **extra,
27 }
28
29
30async def test_parse_artist_requires_id(provider: SoundcloudMusicProvider) -> None:
31 """A user without an id cannot be turned into an artist."""
32 with pytest.raises(InvalidDataError):
33 await provider._parse_artist(_artist_obj(id=None))
34
35
36async def test_parse_artist_metadata(provider: SoundcloudMusicProvider) -> None:
37 """Description and avatar are carried over, with the artwork upgraded."""
38 artist = await provider._parse_artist(
39 _artist_obj(
40 description="Bio text",
41 avatar_url="https://i1.sndcdn.com/avatars-abc-large.jpg",
42 )
43 )
44
45 assert artist.item_id == "5"
46 assert artist.metadata.description == "Bio text"
47 assert artist.metadata.images is not None
48 assert artist.metadata.images[0].path.endswith("avatars-abc-t500x500.jpg")
49 mapping = next(iter(artist.provider_mappings))
50 assert mapping.url == "https://soundcloud.com/some-artist"
51
52
53async def test_parse_artist_skips_default_avatar(provider: SoundcloudMusicProvider) -> None:
54 """The placeholder avatar is not used, since it has no high resolution variant."""
55 artist = await provider._parse_artist(
56 _artist_obj(avatar_url="https://a1.sndcdn.com/images/default_avatar_large.png")
57 )
58
59 assert not artist.metadata.images
60
61
62async def test_parse_track_metadata(provider: SoundcloudMusicProvider) -> None:
63 """Version, artwork, description, genre and tags end up on the track."""
64 provider._soundcloud.get_user_details.return_value = _artist_obj()
65
66 track = await provider._parse_track(
67 _track_obj(
68 artwork_url="https://i1.sndcdn.com/artworks-abc-large.jpg",
69 description="Track notes",
70 genre="House",
71 tag_list="house dance",
72 )
73 )
74
75 assert track.name == "Some Track"
76 assert track.version == "Radio Edit"
77 assert track.duration == 235
78 assert track.metadata.images is not None
79 assert track.metadata.images[0].path.endswith("artworks-abc-t500x500.jpg")
80 assert track.metadata.description == "Track notes"
81 assert track.metadata.genres == {"House"}
82 assert track.metadata.style == "house dance"
83 assert [artist.item_id for artist in track.artists] == ["5"]
84
85
86async def test_parse_track_position(provider: SoundcloudMusicProvider) -> None:
87 """The playlist position is stored on the track."""
88 provider._soundcloud.get_user_details.return_value = _artist_obj()
89
90 track = await provider._parse_track(_track_obj(), 4)
91
92 assert track.position == 4
93