Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load all tracks in "Your Music", "Playlists" and "Top Lists" #279

Merged
merged 1 commit into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions mopidy_spotify/browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import spotify
from mopidy_spotify import countries, playlists, translator
from mopidy_spotify.utils import flatten

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -148,7 +149,16 @@ def _browse_toplist_user(web_client, variant):
return []

if variant in ("tracks", "artists"):
items = web_client.get_one(f"me/top/{variant}").get("items", [])
items = flatten(
[
page.get("items", [])
for page in web_client.get_all(
f"me/top/{variant}",
params={"limit": 50},
)
if page
]
)
if variant == "tracks":
return list(
translator.web_to_track_refs(items, check_playable=False)
Expand Down Expand Up @@ -213,10 +223,16 @@ def _browse_your_music(web_client, variant):
return []

if variant in ("tracks", "albums"):
items = web_client.get_one(
f"me/{variant}",
params={"market": "from_token"},
).get("items", [])
items = flatten(
[
page.get("items", [])
for page in web_client.get_all(
f"me/{variant}",
params={"market": "from_token", "limit": 50},
)
if page
]
)
if variant == "tracks":
return list(translator.web_to_track_refs(items))
else:
Expand All @@ -230,10 +246,15 @@ def _browse_playlists(web_client, variant):
return []

if variant == "featured":
items = (
web_client.get_one("browse/featured-playlists")
.get("playlists", {})
.get("items", [])
items = flatten(
[
page.get("playlists", {}).get("items", [])
for page in web_client.get_all(
"browse/featured-playlists",
params={"limit": 50},
)
if page
]
)
return list(translator.to_playlist_refs(items))
else:
Expand Down
4 changes: 4 additions & 0 deletions mopidy_spotify/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ def time_logger(name, level=TRACE):
yield
end = time.time() - start
logger.log(level, f"{name} took {int(end * 1000)}ms")


def flatten(list_of_lists):
return [item for sublist in list_of_lists for item in sublist]
71 changes: 42 additions & 29 deletions tests/test_browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,25 +229,30 @@ def test_browse_unsupported_top_tracks(web_client_mock, provider):


def test_browse_personal_top_tracks_empty(web_client_mock, provider):
web_client_mock.get_one.return_value = {}
web_client_mock.get_all.return_value = [{}]

results = provider.browse("spotify:top:tracks:user")

web_client_mock.get_one.assert_called_once_with("me/top/tracks")
web_client_mock.get_all.assert_called_once_with(
"me/top/tracks", params={"limit": 50}
)
assert len(results) == 0


def test_browse_personal_top_tracks(web_client_mock, web_track_mock, provider):
# The tracks from this endpoint are erroneously missing some fields:
del web_track_mock["is_playable"]
web_client_mock.get_one.return_value = {
"items": [web_track_mock, web_track_mock],
}
web_client_mock.get_all.return_value = [
{"items": [web_track_mock, web_track_mock]},
{"items": [web_track_mock, web_track_mock]},
]

results = provider.browse("spotify:top:tracks:user")

web_client_mock.get_one.assert_called_once_with("me/top/tracks")
assert len(results) == 2
web_client_mock.get_all.assert_called_once_with(
"me/top/tracks", params={"limit": 50}
)
assert len(results) == 4
assert results[0] == models.Ref.track(
uri="spotify:track:abc", name="ABC 123"
)
Expand Down Expand Up @@ -391,14 +396,17 @@ def test_browse_top_albums_countries_list(
def test_browse_personal_top_artists(
web_client_mock, web_artist_mock, provider
):
web_client_mock.get_one.return_value = {
"items": [web_artist_mock, web_artist_mock],
}
web_client_mock.get_all.return_value = [
{"items": [web_artist_mock, web_artist_mock]},
{"items": [web_artist_mock, web_artist_mock]},
]

results = provider.browse("spotify:top:artists:user")

web_client_mock.get_one.assert_called_once_with("me/top/artists")
assert len(results) == 2
web_client_mock.get_all.assert_called_once_with(
"me/top/artists", params={"limit": 50}
)
assert len(results) == 4
assert results[0] == models.Ref.artist(
uri="spotify:artist:abba", name="ABBA"
)
Expand Down Expand Up @@ -438,33 +446,35 @@ def test_browse_your_music_empty(web_client_mock, provider):

def test_browse_your_music_tracks(web_client_mock, web_track_mock, provider):
web_saved_track_mock = {"track": web_track_mock}
web_client_mock.get_one.return_value = {
"items": [web_saved_track_mock, web_saved_track_mock],
}
web_client_mock.get_all.return_value = [
{"items": [web_saved_track_mock, web_saved_track_mock]},
{"items": [web_saved_track_mock, web_saved_track_mock]},
]

results = provider.browse("spotify:your:tracks")

web_client_mock.get_one.assert_called_once_with(
"me/tracks", params={"market": "from_token"}
web_client_mock.get_all.assert_called_once_with(
"me/tracks", params={"market": "from_token", "limit": 50}
)
assert results == [results[0], results[0]]
assert results == [results[0]] * 4
assert results[0] == models.Ref.track(
uri="spotify:track:abc", name="ABC 123"
)


def test_browse_your_music_albums(web_client_mock, web_album_mock, provider):
web_saved_album_mock = {"album": web_album_mock}
web_client_mock.get_one.return_value = {
"items": [web_saved_album_mock, web_saved_album_mock],
}
web_client_mock.get_all.return_value = [
{"items": [web_saved_album_mock, web_saved_album_mock]},
{"items": [web_saved_album_mock, web_saved_album_mock]},
]

results = provider.browse("spotify:your:albums")

web_client_mock.get_one.assert_called_once_with(
"me/albums", params={"market": "from_token"}
web_client_mock.get_all.assert_called_once_with(
"me/albums", params={"market": "from_token", "limit": 50}
)
assert results == [results[0], results[0]]
assert results == [results[0]] * 4
assert results[0] == models.Ref.album(
uri="spotify:album:def", name="DEF 456"
)
Expand All @@ -473,14 +483,17 @@ def test_browse_your_music_albums(web_client_mock, web_album_mock, provider):
def test_browse_playlists_featured(
web_client_mock, web_playlist_mock, provider
):
web_client_mock.get_one.return_value = {
"playlists": {"items": [web_playlist_mock]}
}
web_client_mock.get_all.return_value = [
{"playlists": {"items": [web_playlist_mock]}},
{"playlists": {"items": [web_playlist_mock]}},
]

results = provider.browse("spotify:playlists:featured")

web_client_mock.get_one.assert_called_once_with("browse/featured-playlists")
web_client_mock.get_all.assert_called_once_with(
"browse/featured-playlists", params={"limit": 50}
)

assert len(results) == 1
assert len(results) == 2
assert results[0].name == "Foo"
assert results[0].uri == "spotify:user:alice:playlist:foo"