diff --git a/cspot/include/PlayerContext.h b/cspot/include/PlayerContext.h index 59019c8..1e330db 100644 --- a/cspot/include/PlayerContext.h +++ b/cspot/include/PlayerContext.h @@ -32,12 +32,13 @@ struct PlayerContext { void resolveTracklist( std::vector> metadata_map, - void (*responseFunction)(void*), bool state_changed = false); + void (*responseFunction)(void*), bool state_changed = false, + bool trackIsPartOfContext = false); uint8_t jsonToTracklist( std::vector* tracks, std::vector> metadata_map, nlohmann::json::value_type& json_tracks, const char* provider, - int64_t offset = 0, uint8_t page = 0, bool shuffle = false, + uint32_t offset = 0, uint8_t page = 0, bool shuffle = false, bool preloadedTrack = false); void createIndexBasedOnTracklist(std::vector* tracks, nlohmann::json::value_type& json_tracks, @@ -51,7 +52,7 @@ struct PlayerContext { PlayerState* playerState; std::vector* tracks; uint8_t* index; - std::vector alternative_index; + std::vector alternative_index; char* next_page_url = NULL; std::string context_uri; ~PlayerContext() { diff --git a/cspot/src/DeviceStateHandler.cpp b/cspot/src/DeviceStateHandler.cpp index e6c1cfa..cc344f1 100644 --- a/cspot/src/DeviceStateHandler.cpp +++ b/cspot/src/DeviceStateHandler.cpp @@ -26,6 +26,19 @@ using namespace cspot; static DeviceStateHandler* handler; void DeviceStateHandler::reloadTrackList(void*) { + + if (!handler->offset) { + if (handler->trackQueue->preloadedTracks.size()) + handler->trackQueue->preloadedTracks.clear(); + handler->trackQueue->preloadedTracks.push_back( + std::make_shared( + handler->currentTracks[handler->offset], handler->ctx, + handler->offsetFromStartInMillis)); + handler->device.player_state.track = + handler->currentTracks[handler->offset]; + handler->offsetFromStartInMillis = 0; + handler->offset++; + } if (strcmp(handler->currentTracks[handler->offset - 1].uri, "spotify:delimiter") == 0 && handler->device.player_state.is_playing) { @@ -111,6 +124,8 @@ DeviceStateHandler::DeviceStateHandler(std::shared_ptr ctx) { this->ctx->timeProvider->getSyncedTimestamp(); //putPlayerState(); sendCommand(CommandType::PLAYBACK, trackQueue->preloadedTracks[0]); + if ((uint32_t)currentTracks.size() / 2 == offset) + playerContext->resolveTracklist(metadata_map, reloadTrackList); } else putPlayerState(); }; @@ -714,11 +729,15 @@ void DeviceStateHandler::parseCommand(std::vector& data) { if (options->find("player_options_override") != options->end()) device.player_state.options.shuffling_context = options->at("player_options_override").at("shuffling_context"); + else + device.player_state.options.shuffling_context = false; if (options->find("skip_to") != options->end()) { if (options->at("skip_to").size()) { if (options->at("skip_to").find("track_index") != - options->at("skip_to").end()) + options->at("skip_to").end()) { playlist_offset = options->at("skip_to").at("track_index"); + track.original_index = playlist_offset; + } track.uri = PlayerContext::createStringReferenceIfFound( options->at("skip_to"), "track_uri"); track.uid = PlayerContext::createStringReferenceIfFound( @@ -771,6 +790,24 @@ void DeviceStateHandler::parseCommand(std::vector& data) { } this->device.player_state.context_metadata_count = context_metadata_map.size(); + } else { + if (this->device.player_state.options.context_enhancement_count) { + for (auto& enhamcement : + this->device.player_state.options.context_enhancement) { + this->unreference(enhamcement.key); + this->unreference(enhamcement.value); + } + this->device.player_state.options.context_enhancement_count = 0; + } + context_metadata_map.clear(); + for (int i = this->device.player_state.context_metadata_count - 1; + i >= 0; i--) { + unreference(this->device.player_state.context_metadata[i].key); + unreference(this->device.player_state.context_metadata[i].value); + } + free(this->device.player_state.context_metadata); + this->device.player_state.context_metadata = NULL; + this->device.player_state.context_metadata_count = 0; } unreference(this->device.player_state.context_uri); @@ -825,10 +862,12 @@ void DeviceStateHandler::parseCommand(std::vector& data) { track.full_metadata_count = metadata_offset; track.metadata_count = metadata_offset; track.provider = strdup("context"); - currentTracks.insert(currentTracks.begin(), track); - device.player_state.track = track; + if (track.uri) { + currentTracks.insert(currentTracks.begin(), track); + device.player_state.track = track; + } offset = 1; - playerContext->resolveTracklist(context_metadata_map, reloadTrackList, + playerContext->resolveTracklist(metadata_map, reloadTrackList, true, true); } else if (command->at("endpoint") == "pause") { device.player_state.is_paused = true; diff --git a/cspot/src/MercurySession.cpp b/cspot/src/MercurySession.cpp index f58be03..d04e9db 100644 --- a/cspot/src/MercurySession.cpp +++ b/cspot/src/MercurySession.cpp @@ -216,13 +216,7 @@ void MercurySession::failAllPending() { it.second(response); } - // Fail all subscriptions - for (auto& it : this->subscriptions) { - it.second(response); - } - // Remove references - this->subscriptions = {}; this->callbacks = {}; } diff --git a/cspot/src/PlayerContext.cpp b/cspot/src/PlayerContext.cpp index e8da0b5..328708b 100644 --- a/cspot/src/PlayerContext.cpp +++ b/cspot/src/PlayerContext.cpp @@ -128,7 +128,7 @@ void PlayerContext::createIndexBasedOnTracklist( bool shuffle, uint8_t page) { //create new index alternative_index.clear(); - std::vector shuffle_index; + std::vector shuffle_index; bool smart_shuffle = (json_tracks.at(0).find("metadata") == json_tracks.at(0).end() || json_tracks.at(0).find("metadata")->find("shuffle.distribution") == @@ -148,7 +148,7 @@ void PlayerContext::createIndexBasedOnTracklist( } } if (smart_shuffle) - alternative_index = std::vector(json_tracks.size()); + alternative_index = std::vector(json_tracks.size()); for (int i = 0; i < json_tracks.size(); i++) { if (smart_shuffle) { alternative_index[distributionToIndex(json_tracks.at(i) @@ -186,7 +186,7 @@ uint8_t PlayerContext::jsonToTracklist( std::vector* tracks, std::vector> metadata_map, nlohmann::json::value_type& json_tracks, const char* provider, - int64_t offset, uint8_t page, bool shuffle, bool preloadedTrack) { + uint32_t offset, uint8_t page, bool shuffle, bool preloadedTrack) { if (offset >= json_tracks.size()) return 0; bool radio = (strcmp("autoplay", provider) == 0) ? true : false; @@ -274,15 +274,14 @@ uint8_t PlayerContext::jsonToTracklist( } return copiedTracks; } + void PlayerContext::resolveTracklist( std::vector> metadata_map, - void (*responseFunction)(void*), bool changed_state) { - //if last track was no radio track, resolve tracklist - //CSPOT_LOG() - CSPOT_LOG(debug, "Resolve tracklist"); + void (*responseFunction)(void*), bool changed_state, + bool trackIsPartOfContext) { if (changed_state) { for (int i = 0; i < tracks->size(); i++) { - if (strstr(tracks->at(i).uri, "spotify:delimiter")) { + if (tracks->at(i).uri && strstr(tracks->at(i).uri, "spotify:delimiter")) { uint8_t release_offset = 0; while (i + release_offset < tracks->size()) { cspot::TrackReference::pbReleaseProvidedTrack( @@ -294,16 +293,21 @@ void PlayerContext::resolveTracklist( } } } + + //if last track was no radio track, resolve tracklist if ((playerState->track.provider == NULL || strcmp(playerState->track.provider, "autoplay")) != 0 && playerState->context_uri != NULL) { - std::string requestUrl = string_format( - "hm://context-resolve/v1/%s", - (playerState->options.shuffling_context && playerState->context_url) - ? &playerState->context_url[10] - : playerState->context_uri); - auto responseHandler = [this, metadata_map, responseFunction, - changed_state](MercurySession::Response& res) { + std::string requestUrl = "hm://context-resolve/v1/%s"; + if (playerState->options.shuffling_context && playerState->context_url) + requestUrl = string_format(requestUrl, &playerState->context_url[10]); + else + requestUrl = string_format(requestUrl, playerState->context_uri); + CSPOT_LOG(debug, "Resolve tracklist, url: %s", &requestUrl[0]); + + auto responseHandler = [this, metadata_map, responseFunction, changed_state, + trackIsPartOfContext]( + MercurySession::Response& res) { if (res.fail || !res.parts.size()) return; if (!res.parts[0].size()) @@ -353,12 +357,12 @@ void PlayerContext::resolveTracklist( goto looking_for_playlisttrack; } } + if (trackref == tracks->begin() && strcmp(trackref->uri, "spotify:delimiter") == 0) return; //if track available were all smart_shuffle_tracks, load Tracklist from 0; if (trackref == tracks->begin()) { - for (int i = 0; i < (trackref->full_metadata_count > trackref->metadata_count ? trackref->full_metadata_count @@ -375,7 +379,7 @@ void PlayerContext::resolveTracklist( //look for trackreference for (int i = 0; i < jsonResult["pages"].size(); i++) { - int64_t offset = 0; + uint32_t offset = 0; if (!copy_tracks) { for (auto track : jsonResult["pages"][i]["tracks"]) { if (strcmp(track["uri"].get().c_str(), @@ -473,6 +477,12 @@ void PlayerContext::resolveTracklist( tracks->insert(tracks->begin(), new_track); } + } else if (trackIsPartOfContext) { + jsonToTracklist(tracks, metadata_map, + jsonResult["pages"][0]["tracks"], "context", + tracks->at(0).original_index + 1, 0, + playerState->options.shuffling_context, false); + } else return resolveRadio(metadata_map, responseFunction); } diff --git a/targets/esp32/main/VSPlayer.cpp b/targets/esp32/main/VSPlayer.cpp index 7df9e5b..90db043 100644 --- a/targets/esp32/main/VSPlayer.cpp +++ b/targets/esp32/main/VSPlayer.cpp @@ -75,6 +75,7 @@ VSPlayer::VSPlayer(std::shared_ptr handler, std::get>(event.data); break; case cspot::DeviceStateHandler::CommandType::DEPLETED: + this->track = nullptr; this->futureTrack = nullptr; this->vsSink->stop_feed(); break;