Feature: Saved Queues#724
Conversation
Clearing player in podcast mode, while user queue is playing, etc. Pretty much any action relating to clearing the queue
|
Hi,
|
|
Hi! Regarding 2. Obviously my above explanation covers why I am not using playqueues specifically, however, I do still account for per Per account binding because I agree with your stance on this. Saved queues have a required toAccount Core Data relationship (SavedQueueMO.toAccount ↔ AccountMO.savedQueues), and every save/fetch/delete in LibraryStorage is filtered by it. getSavedQueues(for:) uses NSPredicate("%K == %@", toAccount, account), and snapshots are always taken against settings.accounts.active. I also made sure to cover this in testing with testDeleteAll_RemovesQueuesForAccountOnly. For 3. I considered using playlists as a data type, it was most first instinct on how to derive the data. However, I saw a few key drawbacks that led me into the flat JSON blob that I settled on, namely: storage and speed. A 500 track blob in the current format is about 10KB of storage and one row. Scale that to the default 20 queues kept and they are not really taking up much space: 20 rows, 200KB. A similar scenario with the playlist implementation would be about 50KB and 501 rows. Scaling that up, is much bigger than the current design. I don't think 4 and 5 need direct addressing because of all the stuff mentioned above. It's a misalignment on the feature, from my perspective. That being said, I do plan to open PRs for this, as I do want cross device sync. I have some code working at the moment, that I am testing, which uses the playQueue endpoint for picking up your current queue on a different device. Then I built in an opt-in (opted out by default) iCloud sync as a backup for Amperfy and offline playback scenarios. This is a completely different feature though. I hope that clears it up a bit. Sorry that it was not clear in the first place! |
|
Thank you for the clarification. I understand the purpose much better now. You're right that the APIs only support a single queue for device switching. I do have a few concerns about the proposed approach. Saved queues are separated by account, but the player itself operates globally. Since users can mix songs from different accounts in the player, wouldn't it be confusing if There are also a couple of implementation details that would need to be adjusted:
|
Address upstream maintainer PR feedback on the saved-queues feature: - SavedQueueMO now owns two system PlaylistMOs (context + user queue), mirroring PlayerMO, instead of storing JSON song-ID blobs. The v50 model drops the Account.savedQueues relationship so queues are global and mixed-account queues restore correctly. - LibraryStorage saved-queue CRUD is account-free. - SavedQueue conforms to PlayableContainable (preview + standard play). - Faithful resume moves behind PlayerFacade.restore(savedQueue:); playCurrentItem is removed from the public PlayerFacade protocol. - saveAsPlaylist filters to the active account and reports skipped songs; logout no longer deletes saved queues. - View controllers, CarPlay, and the full test suite updated for the object-backed, account-agnostic model.
|
Hopefully these changes should address most of your concerns. Definitely my mistake on the account specific part. I am a single account user and didn't actually realise you could mix like that. The changes should fix this to allow for it to be account agnostic. There is a small piece in there which does scrutinise the account though, which is for saving a queue to a playlist, as it it inherently needs to only pull in songs that are available for the playlists destination account. The pieces I didn't implement was the applying a SavedQueue via the generic play() call and playCurrentItem still being in there. My reasoning being that I don't feel like it encompasses enough of what I am trying to achieve here. Restoring a queue needs to persist more state than the current play call can handle, such as shuffle, repeat and the user queue stuff. If I just pass it into play(), these are all stripped. If you want the implementation to strip that data out, that is your call, but I think it is more friendly to faithfully restore the state that the user had at the time of the queue saving. Because of that, restore() sets up a queue manually, instead of going through play(context:), as applying in the order of shuffle and repeat -> context queue -> user queue prevents reshuffling the already filled queue. This is something I ran into while implementing and basically the reasoning behind restore(), as applying directly through clear -> fill -> play of play(context:) does not restore the extra state. The playCurrentItem is just the last step of that process where it tell s the backend to load whatever is now current, after the queue and index are set correctly. It goes through the same insertIntoPlayer call that the play(), play(context) and skip next/prev all use internally, it's just not rebuilding the queue first. So it is less of a separate playback path, more a piece needed to sync the backend after a manual restore |
Add the ability to "Save" queues after they are cleared. This is a feature I used in Symfonium when I was on Android, which I really enjoyed. It basically gives you the ability to get back your previous queues, with position and related information, after you've listened to something else. This would also solve #329, which I commented on.


I added another line to the Library View.
Clicking on the line for it gives you a list of your previous queues. They have a small amount of metadata in the name to help identify. Clicking the queue starts playing, while the i symbol gives you a detailed section on the queue with the song list, ability to reshuffle or resume it, as well as Renaming, deleting or saving the queue to a playlist
I decided that the "tap to play", rather than the typical tap for the list of songs approach seen throughout the rest of the app, was the right choice here due to the nature of how you interact with a saved queue. Typically you just want to resume it. I am happy to change that if necessary, but I tested both and this way felt much more natural.
My dev cert doesn't have carplay rights, so the carplay testing is only as far as the simulator, but it seems to work well in there.
Finally, this should also support other features I am working on handoff and cross device sync. That being said, I am working on those independent of this feature. They just feel nicer when you have your queue saved somewhere, rather than overwriting it.
I hope it is not too bad, this is my first contribution of this size to a project of this size. My apologies in advance! Thank you for the wonderful app though :D