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
- Keep using the same hyper client instead of building a new one for
each request
- This allows the client to reuse connections and improves the
performance of multiple requests by almost 2x.
- The playlist_tracks example takes 38 secs before and 20 secs after the
change to enumerate a 180 track playlist
- To avoid carrying the hyper Client generics through the whole project,
`ProxyConnector` is always used as the Connector, but disabled when
not using a proxy.
- The client creation is done lazily to keep the `HttpClient::new`
without a `Result` return type
- Fixed resolve function panicking when resolving endpoint type with no
AP in the list
- Fixed fallback APs not being applied when only some of the AP types
were missing
- Switch container type from `Vec` to `VecDeque` for the `AccessPoints`
- Remove the note about fallback AP being used even if the port is not
matching the configured `ap_port`
- Also fix an overflow panic when a token cannot be parsed.
- Getting tokens always requires the keymaster client ID;
passing the actual client ID yields a HashCash challenge.
Some fields were wrongly parsed as `SpotifyId`s, although they do not
always encode exactly 16 bytes in practice. Also, some optional fields
caused `[]` to be parsed as `SpotifyId`, which obviously failed as well.