Skip to content

Commit

Permalink
tracklist will always be filled with enough tracks, fix for play command
Browse files Browse the repository at this point in the history
  • Loading branch information
tobiasguyer committed Oct 4, 2024
1 parent 88c96c4 commit ea556ec
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 30 deletions.
7 changes: 4 additions & 3 deletions cspot/include/PlayerContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ struct PlayerContext {

void resolveTracklist(
std::vector<std::pair<std::string, std::string>> metadata_map,
void (*responseFunction)(void*), bool state_changed = false);
void (*responseFunction)(void*), bool state_changed = false,
bool trackIsPartOfContext = false);
uint8_t jsonToTracklist(
std::vector<ProvidedTrack>* tracks,
std::vector<std::pair<std::string, std::string>> 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<ProvidedTrack>* tracks,
nlohmann::json::value_type& json_tracks,
Expand All @@ -51,7 +52,7 @@ struct PlayerContext {
PlayerState* playerState;
std::vector<ProvidedTrack>* tracks;
uint8_t* index;
std::vector<int64_t> alternative_index;
std::vector<uint32_t> alternative_index;
char* next_page_url = NULL;
std::string context_uri;
~PlayerContext() {
Expand Down
47 changes: 43 additions & 4 deletions cspot/src/DeviceStateHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<cspot::QueuedTrack>(
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) {
Expand Down Expand Up @@ -111,6 +124,8 @@ DeviceStateHandler::DeviceStateHandler(std::shared_ptr<cspot::Context> 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();
};
Expand Down Expand Up @@ -714,11 +729,15 @@ void DeviceStateHandler::parseCommand(std::vector<uint8_t>& 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(
Expand Down Expand Up @@ -771,6 +790,24 @@ void DeviceStateHandler::parseCommand(std::vector<uint8_t>& 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);
Expand Down Expand Up @@ -825,10 +862,12 @@ void DeviceStateHandler::parseCommand(std::vector<uint8_t>& 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;
Expand Down
6 changes: 0 additions & 6 deletions cspot/src/MercurySession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
}

Expand Down
44 changes: 27 additions & 17 deletions cspot/src/PlayerContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void PlayerContext::createIndexBasedOnTracklist(
bool shuffle, uint8_t page) {
//create new index
alternative_index.clear();
std::vector<int64_t> shuffle_index;
std::vector<uint32_t> 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") ==
Expand All @@ -148,7 +148,7 @@ void PlayerContext::createIndexBasedOnTracklist(
}
}
if (smart_shuffle)
alternative_index = std::vector<int64_t>(json_tracks.size());
alternative_index = std::vector<uint32_t>(json_tracks.size());
for (int i = 0; i < json_tracks.size(); i++) {
if (smart_shuffle) {
alternative_index[distributionToIndex(json_tracks.at(i)
Expand Down Expand Up @@ -186,7 +186,7 @@ uint8_t PlayerContext::jsonToTracklist(
std::vector<ProvidedTrack>* tracks,
std::vector<std::pair<std::string, std::string>> 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;
Expand Down Expand Up @@ -274,15 +274,14 @@ uint8_t PlayerContext::jsonToTracklist(
}
return copiedTracks;
}

void PlayerContext::resolveTracklist(
std::vector<std::pair<std::string, std::string>> 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(
Expand All @@ -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())
Expand Down Expand Up @@ -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
Expand All @@ -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<std::string>().c_str(),
Expand Down Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions targets/esp32/main/VSPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ VSPlayer::VSPlayer(std::shared_ptr<cspot::DeviceStateHandler> handler,
std::get<std::shared_ptr<cspot::QueuedTrack>>(event.data);
break;
case cspot::DeviceStateHandler::CommandType::DEPLETED:
this->track = nullptr;
this->futureTrack = nullptr;
this->vsSink->stop_feed();
break;
Expand Down

0 comments on commit ea556ec

Please sign in to comment.