This was a huge effort by photovoltex@gmail.com with help from the community.
Over 140 commits were squashed. Below, their commit messages are kept unchanged.
---
* dealer wrapper for ease of use
* improve sending protobuf requests
* replace connect config with connect_state config
* start integrating dealer into spirc
* payload handling, gzip support
* put connect state consistent
* formatting
* request payload handling, gzip support
* expose dealer::protocol, move request in own file
* integrate handle of connect-state commands
* spirc: remove ident field
* transfer playing state better
* spirc: remove remote_update stream
* spirc: replace command sender with connect state update
* spirc: remove device state and remaining unused methods
* spirc: remove mercury sender
* add repeat track state
* ConnectState: add methods to replace state in spirc
* spirc: move context into connect_state, update load and next
* spirc: remove state, adjust remaining methods
* spirc: handle more dealer request commands
* revert rustfmt.toml
* spirc: impl shuffle
- impl shuffle again
- extracted fill up of next tracks in own method
- moved queue revision update into next track fill up
- removed unused method `set_playing_track_index`
- added option to specify index when resetting the playback context
- reshuffle after repeat context
* spirc: handle device became inactive
* dealer: adjust payload handling
* spirc: better set volume handling
* dealer: box PlayCommand (clippy warning)
* dealer: always respect queued tracks
* spirc: update duration of track
* ConnectState: update more restrictions
* cleanup
* spirc: handle queue requests
* spirc: skip next with track
* proto: exclude spirc.proto
- move "deserialize_with" functions into own file
- replace TrackRef with ProvidedTrack
* spirc: stabilize transfer/context handling
* core: cleanup some remains
* connect: improvements to code structure and performance
- use VecDeque for next and prev tracks
* connect: delayed volume update
* connect: move context resolve into own function
* connect: load context asynchronous
* connect: handle reconnect
- might currently steal the active devices playback
* connect: some fixes and adjustments
- fix wrong offset when transferring playback
- fix missing displayed context in web-player
- remove access_token from log
- send correct state reason when updating volume
- queue track correctly
- fix wrong assumption for skip_to
* connect: replace error case with option
* connect: use own context state
* connect: more stabilising
- handle SkipTo having no Index
- handle no transferred restrictions
- handle no transferred index
- update state before shutdown, for smoother reacquiring
* connect: working autoplay
* connect: handle repeat context/track
* connect: some quick fixes
- found self-named uid in collection after reconnecting
* connect: handle add_to_queue via set_queue
* fix clippy warnings
* fix check errors, fix/update example
* fix 1.75 specific error
* connect: position update improvements
* connect: handle unavailable
* connect: fix incorrect status handling for desktop and mobile
* core: fix dealer reconnect
- actually acquire new token
- use login5 token retrieval
* connect: split state into multiple files
* connect: encapsulate provider logic
* connect: remove public access to next and prev tracks
* connect: remove public access to player
* connect: move state only commands into own file
* connect: improve logging
* connect: handle transferred queue again
* connect: fix all-features specific error
* connect: extract transfer handling into own file
* connect: remove old context model
* connect: handle more transfer cases correctly
* connect: do auth_token pre-acquiring earlier
* connect: handle play with skip_to by uid
* connect: simplified cluster update log
* core/connect: add remaining set value commands
* connect: position update workaround/fix
* connect: some queue cleanups
* connect: add uid to queue
* connect: duration as volume delay const
* connect: some adjustments and todo cleanups
- send volume update before general update
- simplify queue revision to use the track uri
- argument why copying the prev/next tracks is fine
* connect: handle shuffle from set_options
* connect: handle context update
* connect: move other structs into model.rs
* connect: reduce SpircCommand visibility
* connect: fix visibility of model
* connect: fix: shuffle on startup isn't applied
* connect: prevent loading a context with no tracks
* connect: use the first page of a context
* connect: improve context resolving
- support multiple pages
- support page_url of context
- handle single track
* connect: prevent integer underflow
* connect: rename method for better clarity
* connect: handle mutate and update messages
* connect: fix 1.75 problems
* connect: fill, instead of replace next page
* connect: reduce context update to single method
* connect: remove unused SpircError, handle local files
* connect: reduce nesting, adjust initial transfer handling
* connect: don't update volume initially
* core: disable trace logging of handled mercury responses
* core/connect: prevent takeover from other clients, handle session-update
* connect: add queue-uid for set_queue command
* connect: adjust fields for PlayCommand
* connect: preserve context position after update_context
* connect: unify metadata modification
- only handle `is_queued` `true` items for queue
* connect: polish request command handling
- reply to all request endpoints
- adjust some naming
- add some docs
* connect: add uid to tracks without
* connect: simpler update of current index
* core/connect: update log msg, fix wrong behavior
- handle became inactive separately
- remove duplicate stop
- adjust docs for websocket request
* core: add option to request without metrics and salt
* core/context: adjust context requests and update
- search should now return the expected context
- removed workaround for single track playback
- move local playback check into update_context
- check track uri for invalid characters
- early return with `?`
* connect: handle possible search context uri
* connect: remove logout support
- handle logout command
- disable support for logout
- add todos for logout
* connect: adjust detailed tracks/context handling
- always allow next
- handle no prev track available
- separate active and fill up context
* connect: adjust context resolve handling, again
* connect: add autoplay metadata to tracks
- transfer into autoplay again
* core/connect: cleanup session after spirc stops
* update CHANGELOG.md
* playback: fix clippy warnings
* connect: adjust metadata
- unify naming
- move more metadata infos into metadata.rs
* connect: add delimiter between context and autoplay playback
* connect: stop and resume correctly
* connect: adjust context resolving
- improved certain logging parts
- preload autoplay when autoplay attribute mutates
- fix transfer context uri
- fix typo
- handle empty strings for resolve uri
- fix unexpected stop of playback
* connect: ignore failure during stop
* connect: revert resolve_uri changes
* connect: correct context reset
* connect: reduce boiler code
* connect: fix some incorrect states
- uid getting replaced by empty value
- shuffle/repeat clearing autoplay context
- fill_up updating and using incorrect index
* core: adjust incorrect separator
* connect: move `add_to_queue` and `mark_unavailable` into tracks.rs
* connect: refactor - directly modify PutStateRequest
- replace `next_tracks`, `prev_tracks`, `player` and `device` with `request`
- provide helper methods for the removed fields
* connect: adjust handling of context metadata/restrictions
* connect: fix incorrect context states
* connect: become inactive when no cluster is reported
* update CHANGELOG.md
* core/playback: preemptively fix clippy warnings
* connect: minor adjustment to session changed
* connect: change return type changing active context
* connect: handle unavailable contexts
* connect: fix previous restrictions blocking load with shuffle
* connect: update comments and logging
* core/connect: reduce some more duplicate code
* more docs around the dealer
* core: Obtain spclient access token using login5 instead of keymaster (Fixes#1179)
* core: move solving hashcash into util
* login5: add login for mobile
---------
Co-authored-by: Nick Steel <nick@nsteel.co.uk>
Not there yet, as Apollo stations always return autoplay
recommendations even if you set autoplay to false. Along the way
as an effort to bring the protocol up to spec:
- And support for and use different Apollo station scopes depending
on whether we are using autoplay or not. For autoplay, get a
"stations" scope and follow the "tracks" pages from there. Otherwise
use "tracks" immediately for the active scope (playlist, album).
- For the above point we only need the fields from `PageContext`
so use that instead of a `StationContext`.
- Add some documentation from API reverse engineering: things seen
in the wild, some of them to do, others documented for posterity's
sake.
- Update the Spirc device state based on what the latest desktop
client puts out. Unfortunately none of it seems to change the
behavior necessary to support external episodes, shows, but
at least we're doing the right thing.
- Add a salt to HTTPS queries to defeat any caching.
- Add country metrics to HTTPS queries.
- Fix `get_radio_for_track` to use the right Spotify ID format.
- Fix a bug from the previous commit, where the playback position
might not advance when hitting next and the autoplay context
is loaded initially.
- Improve responsiveness by downloading the smallest possible chunk
size when seeking or first loading.
- Improve download time and decrease CPU usage by downloading the
largest possible chunk size as throughput allows, still allowing
for reasonable seek responsiveness (~1 second).
- As a result, take refactoring opportunities: simplify prefetching
logic, download threading, command sending, and some ergonomics.
- Fix disappearing controls in the Spotify mobile UI while loading.
- Fix handling of seek, pause, and play commands while loading.
- Fix download rate calculation (don't use the Mercury rate).
- Fix ping time calculation under lock contention.
Special thanks to @eladyn for all of their help and suggestions.
* Add all player events to `player_event_handler.rs`
* Move event handler code to `player_event_handler.rs`
* Add session events
* Clean up and de-noise events and event firing
* Added metadata support via a TrackChanged event
* Add `event_handler_example.py`
* Handle invalid track start positions by just starting the track from the beginning
* Add repeat support to `spirc.rs`
* Add `disconnect`, `set_position_ms` and `set_volume` to `spirc.rs`
* Set `PlayStatus` to the correct value when Player is loading to avoid blanking out the controls when `self.play_status` is `LoadingPlay` or `LoadingPause` in `spirc.rs`
* Handle attempts to play local files better by basically ignoring attempts to load them in `handle_remote_update` in `spirc.rs`
* Add an event worker thread that runs async to the main thread(s) but sync to itself to prevent potential data races for event consumers.
* Get rid of (probably harmless) `.unwrap()` in `main.rs`
* Ensure that events are emited in a logical order and at logical times
* Handle invalid and disappearing devices better
* Ignore SpircCommands unless we're active with the exception of ShutDown
Better error handling.
Move the checking of the shell command to start so a proper error can be thrown if it's None.
Use write instead of write_all for finer grained error handling and the ability to attempt a restart on write errors.
Use try_wait to skip flushing and killing the process if it's already dead.
Stop the player on shutdown to *mostly* prevent write errors from spamming the logs during shutdown. Previously Ctrl+c always resulted in a write error.
- Switch from `lewton` to `Symphonia`. This is a pure Rust demuxer
and decoder in active development that supports a wide range of
formats, including Ogg Vorbis, MP3, AAC and FLAC for future HiFi
support. At the moment only Ogg Vorbis and MP3 are enabled; all
AAC files are DRM-protected.
- Bump MSRV to 1.51, required for `Symphonia`.
- Filter out all files whose format is not specified.
- Not all episodes seem to be encrypted. If we can't get an audio
key, try and see if we can play the file without decryption.
- After seeking, report the actual position instead of the target.
- Remove the 0xa7 bytes offset from `Subfile`, `Symphonia` does
not balk at Spotify's custom Ogg packet before it. This also
simplifies handling of formats other than Ogg Vorbis.
- When there is no next track to load, signal the UI that the
player has stopped. Before, the player would get stuck in an
infinite reloading loop when there was only one track in the
queue and that track could not be loaded.
- Don't load explicit tracks when the client setting forbids them
- When a client switches explicit filtering on *while* playing
an explicit track, immediately skip to the next track
This should fix remaining cases of a client connecting, and failing
to start playback from *beyond* the beginning when `librespot` is
still loading that track.
This undoes the `suppress_loading_status` workaround from #430,
under the assumption that the race condition reported there has
since been fixed on Spotify's end.
Further changes:
- Improve some debug and trace messages
- Default to streaming download strategy
- Synchronize mixer volume on loading play
- Use default normalisation values when the file position isn't
exactly what we need it to be
- Update track position only when the decoder reports a
successful seek
* Expose all fields of recent protobufs
* Add support for user-scoped playlists, user root playlists and
playlist annotations
* Convert messages with the Rust type system
* Attempt to adhere to embargos (tracks and episodes scheduled for
future release)
* Return `Result`s with meaningful errors instead of panicking on
`unwrap`s
* Add foundation for future playlist editing
* Up version in connection handshake to get all version-gated features
* When autoplay is disabled, then loop back to the first track
instead of 10 tracks back. Continue or stop playing depending
on the state of the repeat button.
* When autoplay is enabled, then extend the playlist *after* the
last track. #844 broke this such that the last track of an album
or playlist was never played.
Fixes: #434