Closed kimfucious closed 2 years ago
print("Error Saving Tracks to Playlist", error)
The above code is not saving any tracks to a playlist.
If the above returns the items, I'd like update "state" by appending currentSpotifyUsersPlaylists with said items
The playlist that you create using SpotifyAPI.createPlaylist(for:_:) will not contain any items (tracks/episodes). The documentation mentions this. Why would you expect a just-created playlist to contain items?
The return type of the aforementioned method is AnyPublisher<Playlist<PlaylistItems>, Error>
, meaning that the type of playlistToReturn
is Playlist<PlaylistItems>
. But the type of currentUsersSpotifyPlaylists
is [Playlist<PlaylistItemsReference>]
. You can only append values of type Playlist<PlaylistItemsReference>
—not Playlist<PlaylistItems>
— to this array. Swift is a statically typed language.
After you create a new playlist and, optionally, add items to it (which the posted code doesn't do yet), you should make another call to getSpotifyUsersPlaylists
, which will then update currentUsersSpotifyPlaylists
with the newly-created playlist. Spotify's database may not update immediately after you create the playlist, so you can call this function repeatedly —with an exponentially increasing delay—until currentUsersSpotifyPlaylists
contains a playlist with the URI of the newly-created playlist.
let playlistsPage = try await spotify.api.currentUserPlaylists(limit: 50) .extendPages(spotify.api) .awaitSingleValue()
This doesn't do what you think it does. Publisher.extendPages(_:maxExtraPages:) returns a publisher that publishes multiple values: one for each page of results. Publisher.awaitSingleValue
only waits for a single value from the publisher. Therefore, you're only retrieving a single page of playlists.
What you need is a way of asynchronously collecting all values produced by the publisher into an array:
let playlists: [Playlist<PlaylistItemsReference>] = try await spotify.api
.currentUserPlaylists(limit: 50)
.extendPages(spotify.api)
.values
.reduce(into: [], { result, page in
result.append(contentsOf: page.items)
})
networkManager.currentUsersSpotifyPlaylists = playlists
Publisher.values has the same behavior as Publisher.awaitValues
in #28, but I trust Apple's implementation more than my own. The reduce
method collects the items
array from each PagingObject
into a single array.
if result != nil { // ... playlistToReturn = result! }
Stop using this pattern. Don't use a boolean test for whether an optional is
nil
and then force-unwrap it and assign it to a non-optional variable. Instead use the if-let pattern:if let result = result { // ... playlistToReturn = result }
Hi @Peter-Schorn, thanks for your insightful feedback.
First, you're spot on that I was misunderstanding the return of the createSpotifyPlaylist
function. I was thinking that items
would be multiple playlists (actually one playlist in an array), not a single playlist, and not tracks, which, as you said, wouldn't be there anyhow. So, thanks for setting me straight there.
So my original question was how to append [SpotifyWebAPI.Playlist
And thus, your solution to re-fetch the user's playlists after the creation of a new one, is ironically what I put in as a work-around while waiting for your reply. I was hoping to avoid that extra call, but it seems the path of least resistance for now.
The new playlist seems to be there pretty quick. I've not seen it not be there, even after an immediate get of the playlists after a new one is created. In my use case, the new playlist is not immediately needed until another view appears later on, at which point another call to get the playlists is done, so I believe it's kinda safe.
Refetching also obviates the need to return the playlist after creation, as well, which simplifies the create function.
Regarding awaitSingleValue()
, I've implemented that heavily, so I guess, I'll begin replacing that with values/reduce(into...
pattern where it makes sense to do so, though awaitSingleValue()
has been working as expected thus far.
Lastly, I realize that I'm bothering and that my code is mostly Scheiße. I've only really been working with Swift for a couple/few months now, so my apologies for any anguish that I cause.
I do appreciate your taking the time to respond to my queries and the valueable feedback you provide.
Regarding
awaitSingleValue()
, I've implemented that heavily, so I guess, I'll begin replacing that withvalues
/reduce
pattern where it makes sense to do so, thoughawaitSingleValue()
has been working as expected thus far.
If only one page of results exists, then the behavior will be the same. But you should never assume only one page of results exists.
HI @Peter-Schorn,
I've been putting your wonderful library to great use, thanks for making this!
Question:
I'm fetching a user's playlists and successfully storing them in "state" as a published variable:
I can populate this initially with:
In some cases the user will create a playlist using this:
If the above returns the items, I'd like update "state" by appending
currentSpotifyUsersPlaylists
with said items; however, after quite a while of futzing around, I cannot figure out how to do that, as.append()
and+ operator
are obviously the wrong tools for the job here when dealing with the type at hand.Any tips?
Thanks!