mirror of
https://github.com/librespot-org/librespot.git
synced 2026-04-27 08:15:50 +03:00
[GH-ISSUE #264] Implement 'unshuffle' functionality #176
Labels
No labels
A-Alsa
SpotifyAPI
Tokio 1.0
audio
bug
can't reproduce
compilation
dependencies
duplicate
enhancement
good first issue
help wanted
high priority
imported
imported
invalid
new api
pull-request
question
reverse engineering
wiki
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/librespot#176
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @sashahilton00 on GitHub (Nov 12, 2018).
Original GitHub issue: https://github.com/librespot-org/librespot/issues/264
Currently when one shuffles the songs, the local queue in librespot is shuffled. when shuffle is disabled, the queue is not unshuffled. We should retrieve the original playlist on unshuffle, and then replace queue will all tracks after the index of the one currently playing.
@kingosticks commented on GitHub (Nov 12, 2018):
Indeed. We need to look up the context for this. In cases where this is no context, I'm not sure what you do.
@sashahilton00 commented on GitHub (Nov 12, 2018):
The other solution might be to take a random index for selecting the song, i.e. don't shuffle the list of tracks, but rather create a
shuffle_arrayof sequential integers the length of the track array from0 => len(track_array), shuffle the array, and move the current playing track's index to position 0, then map that across to the ordered track array when choosing the next song for playback.So for a
track_array['a', 'b', 'c', 'd', 'e']with currently playing songc(index 2), create an integershuffle_array([0, 1, 2, 3, 4]), shuffle to[3, 1, 0, 2, 4], move currently playing track to position 0 ([2, 3, 1, 0, 4]), then when the next song is requested, map theshuffle_arraytotrack_array, to give a play queue of['c', 'd', 'b', 'a', 'e']. Then to revert to ordered play, just stop mapping theshuffle_array, and instead use the currenttrack_arrayindex + 1for the next song.A bit more complicated, but means that one doesn't need to work out how to retrieve ordered lists when no context is provided.
@ashthespy commented on GitHub (Nov 12, 2018):
If we can keep track of the seed, the Fisher–Yates algorithm (that you describe here?) might be a way to shuffle - unshuffle lists with small overheads?
@sashahilton00 commented on GitHub (Nov 12, 2018):
Not sure it's an official algorithm, just made it up to be what I thought a sensible way to do things. How you shuffle the integer array initially is up to you
@kingosticks commented on GitHub (Nov 13, 2018):
I think when I was experimenting the official app just didn't let you unshuffle. However, most of the time you do have a context so you just don't notice. That to me seems fine, the less complicated the better. But maybe its changed, someone should investigate.
@sashahilton00 commented on GitHub (Nov 13, 2018):
What is
thatin this sentence?@sashahilton00 commented on GitHub (Nov 13, 2018):
Also, Spotify uses Fisher-Yates, so for the sake of consistency, we should probably aim for that.
@sashahilton00 commented on GitHub (Nov 13, 2018):
Now this is interesting, Spotify filed a patent for a weighted playlist shuffling algorithm: https://patentimages.storage.googleapis.com/d2/65/e2/8d6d3df46e77da/US20170244770A1.pdf and the weights are included with the tracks in a playlist, when retrieved via a uri such as
hm://playlist/user/spotify/playlist/37i9dQZF1DWWjGdmeTyeJ6?revision=1542071134%2C0000008f00000166ef91c8b900000166eb2e5322&handlesContent=More food for thought, I don't think we need to implement the same level of complexity, something like fisher yates or a random shuffle and context retrieval should be plenty.
@sashahilton00 commented on GitHub (Nov 13, 2018):
Agreed, we can just seed with a hash of the start time of librespot or something and Store that in memory. Shouldn't be too hard.
@kingosticks commented on GitHub (Nov 13, 2018):
The problem with the non-context case is when some other client shuffles the tracks and sends them in an update, all you have is those tracks. You have no way to know how to unshuffle them. The other client may have shuffled a hundred time before librespot joined the connect session so it really has no idea of the shuffle history and the seed doesn't help.
Not letting you unshuffle tracks without a context. Or, rather, making it a no-op.
@sashahilton00 commented on GitHub (Nov 13, 2018):
Have just experimented, Spotify is syncing shuffle state across clients. If you shuffle on one client, skip a song, connect from another client and take over listening, you can go back to the previous song. However, if you shuffle a playlist on
client 1, switch playback toclient 2as in the previous scenario, then killclient 1and try to go back to the previous shuffled song onclient 2, you can't. So it looks like there's some sort of shuffle state passed fromclient 1toclient 2that is lost when one closesclient 1. Additionally shuffle and repeat features are not available on dailymixes, which makes me think that there is some sort of additional protocol for communicating shuffle state that hasn't been upgraded to support dailymixes yet.@kingosticks commented on GitHub (Nov 13, 2018):
I'm not sure I follow what you are saying here. The (shuffled) track list and current track index give you all the state you need to skip backwards. This is all already implemented in librespot, yes?
@sashahilton00 commented on GitHub (Nov 13, 2018):
As in the shuffled track list is kept in sync between clients, and not just on the client locally
@devgianlu commented on GitHub (Nov 13, 2018):
@sashahilton00 In fact, you have to communicate it for Spotify to display the queue.
@kingosticks commented on GitHub (Nov 13, 2018):
Yes, exactly. That's how it all works already and that's what we support in the original shuffle/repeat/queue work.
@sashahilton00 commented on GitHub (Nov 13, 2018):
sure, but that doesn't explain why you can skip back/forwards when the client that originally shuffled it is open, but when you move clients and close the previous, you lose the ability to skip back
@sashahilton00 commented on GitHub (Nov 13, 2018):
it's a minor issue, i'm not bothered if we can't skip back after switching clients on a shuffled playlist, but just thought i'd note it.
@kingosticks commented on GitHub (Nov 13, 2018):
I found the behaviour was inconsistent between phone and desktop clients. It might just be their buggy software.
@devgianlu commented on GitHub (Nov 21, 2018):
I've looked at some captured packets and it looks like Spotify doesn't do much when you toggle shuffle, probably because he has already stored in memory a copy of the playlist. Anyway it does something:
hm://playlist/v2/playlist-v1-uriswhich gives400(why does it even do that?)hm://event-service/v1/eventsjust for analytics purposeshm://remote/3/user/{userId}/and gets200in responseSome of the metadata includes:
UIInteraction 5 zlink player click enable-shuffleorUIInteraction 5 zlink player click disable-shuffleInteraction 1 interactionID player/shuffle-button click shuffle nowplaying/queue spotify:app:queue268 1 desktop-stranger-things Enabled