Player: GET /api/player with Spotify now-playing info
Source, state, artist/title/album, position and duration (from cspot's playback state, so it matches the app), volume and `can`. cspot patch 0004 adds read getters for the playback state and context. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "BellLogger.h"
|
||||
#include "CSpotContext.h"
|
||||
#include "LoginBlob.h"
|
||||
#include "PlaybackState.h"
|
||||
#include "SpircHandler.h"
|
||||
#include "TrackPlayer.h"
|
||||
#include "esp_log.h"
|
||||
@@ -55,6 +56,9 @@ static std::deque<Boundary> s_bounds;
|
||||
static std::string s_last_id; // track of the most recent data callback
|
||||
static std::atomic<bool> s_depleted{false};
|
||||
|
||||
static std::mutex s_track_mutex;
|
||||
static cspot::TrackInfo s_track; // audible track (TRACK_INFO), guarded by s_track_mutex
|
||||
|
||||
static void clear_boundaries(bool new_load)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_bound_mutex);
|
||||
@@ -134,6 +138,30 @@ extern "C" bool spotify_session_active(void)
|
||||
return s_handler != nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool spotify_now_playing(spotify_track_t *t)
|
||||
{
|
||||
auto h = s_handler;
|
||||
if (!h) {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_track_mutex);
|
||||
strlcpy(t->artist, s_track.artist.c_str(), sizeof(t->artist));
|
||||
strlcpy(t->title, s_track.name.c_str(), sizeof(t->title));
|
||||
strlcpy(t->album, s_track.album.c_str(), sizeof(t->album));
|
||||
t->duration_ms = s_track.duration;
|
||||
}
|
||||
// Same position the app shows: last reported position, plus the time since while playing.
|
||||
const auto &st = h->getPlaybackState()->innerFrame.state;
|
||||
t->paused = st.status != PlayStatus_kPlayStatusPlay;
|
||||
uint64_t pos = st.position_ms;
|
||||
if (!t->paused) {
|
||||
pos += h->getContext()->timeProvider->getSyncedTimestamp() - st.position_measured_at;
|
||||
}
|
||||
t->position_ms = t->duration_ms && pos > t->duration_ms ? t->duration_ms : (uint32_t)pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *spotify_state(void)
|
||||
{
|
||||
return s_state.load();
|
||||
@@ -324,6 +352,8 @@ static void session(void)
|
||||
case E::TRACK_INFO: {
|
||||
auto &ti = std::get<cspot::TrackInfo>(ev->data);
|
||||
ESP_LOGI(TAG, "track: %s - %s (%lu ms)", ti.artist.c_str(), ti.name.c_str(), (unsigned long)ti.duration);
|
||||
std::lock_guard<std::mutex> lock(s_track_mutex);
|
||||
s_track = ti;
|
||||
return;
|
||||
}
|
||||
case E::PLAY_PAUSE:
|
||||
@@ -370,6 +400,10 @@ static void session(void)
|
||||
}
|
||||
// Stops the queue and player tasks (waits for them), then closes the connection.
|
||||
s_handler.reset();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_track_mutex);
|
||||
s_track = {};
|
||||
}
|
||||
handler->disconnect();
|
||||
ESP_LOGI(TAG, "session ended");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user