mirror of
https://github.com/sascha-hemi/SpotifyEsp32.git
synced 2026-03-21 04:05:47 +01:00
initial state of Spotify API
This commit is contained in:
842
SpotifyESP32.cpp
Normal file
842
SpotifyESP32.cpp
Normal file
@@ -0,0 +1,842 @@
|
||||
#include "SpotifyESP32.h"
|
||||
|
||||
namespace Spotify_types{
|
||||
bool SHUFFLE_ON = true;
|
||||
bool SHUFFLE_OFF = false;
|
||||
String REPEAT_OFF = "off";
|
||||
String REPEAT_TRACK = "track";
|
||||
String REPEAT_CONTEXT = "context";
|
||||
String TYPE_ALBUM = "album";
|
||||
String TYPE_ARTIST = "artist";
|
||||
String TYPE_TRACK = "track";
|
||||
String TYPE_PLAYLIST = "playlist";
|
||||
}
|
||||
|
||||
Spotify::Spotify(char* refresh_token, char* redirect_uri, char* client_id, char* client_secret,bool debug_on){
|
||||
_retry = 0;
|
||||
_refresh_token = refresh_token;
|
||||
_redirect_uri = redirect_uri;
|
||||
_client_id = client_id;
|
||||
_client_secret = client_secret;
|
||||
_debug_on = debug_on;
|
||||
}
|
||||
response Spotify::currently_playing(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/currently-playing",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
int http_code = http.GET();
|
||||
response_obj.status_code = http_code;
|
||||
if(_debug_on){
|
||||
Serial.print("GET currently_playing status: ");
|
||||
Serial.println(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(http.getString());
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)){
|
||||
String response = http.getString();
|
||||
response_obj.reply = response;
|
||||
}
|
||||
else if(_retry<=3){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = currently_playing();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
|
||||
}
|
||||
response Spotify::current_playback_state(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
int http_code = http.GET();
|
||||
response_obj.status_code = http_code;
|
||||
if(_debug_on){
|
||||
Serial.print("GET current_playback_state status: ");
|
||||
Serial.println(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(http.getString());
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)){
|
||||
String response = http.getString();
|
||||
response_obj.reply = response;
|
||||
}
|
||||
else if(_retry<=3){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = current_playback_state();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
|
||||
}
|
||||
response Spotify::play_uri(String track_uri){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/play",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
String payload;
|
||||
if(track_uri.startsWith("spotify:track:")){
|
||||
payload= "{\"uris\":[\"" + track_uri + "\"]}";
|
||||
}
|
||||
else{
|
||||
payload = "{\"context_uri\":\"" + track_uri + "\",\"offset\":{\"position\":0}}";
|
||||
}
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT play status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = play_uri(track_uri);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::start_playback(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/play",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT start_playback status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = start_playback();
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::pause_playback(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/pause",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT pause status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = pause_playback();
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
|
||||
}
|
||||
response Spotify::skip(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/next";
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.POST(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT skip status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = skip();
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::previous(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/previous";
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.POST(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT previous status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = previous();
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
|
||||
}
|
||||
response Spotify::available_devices(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/devices",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
int http_code = http.GET();
|
||||
response_obj.status_code = http_code;
|
||||
if(_debug_on){
|
||||
Serial.print("GET current_device status: ");
|
||||
Serial.println(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(http.getString());
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)){
|
||||
String response = http.getString();
|
||||
response_obj.reply = response;
|
||||
}
|
||||
else if(_retry<=3){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = available_devices();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::recently_played_tracks(int limit){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
HTTPClient http;
|
||||
String url = "https://api.spotify.com/v1/me/player/recently-played";
|
||||
url += "?limit="+String(limit);
|
||||
http.begin(url,_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
int http_code = http.GET();
|
||||
response_obj.status_code = http_code;
|
||||
String response = http.getString();
|
||||
if(_debug_on){
|
||||
Serial.print("GET recently_played_tracks status: ");
|
||||
Serial.println(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(response);
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)){
|
||||
|
||||
response_obj.reply = response;
|
||||
}
|
||||
else if(_retry<=3){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = recently_played_tracks(limit);
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::get_queue(){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player/queue",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
int http_code = http.GET();
|
||||
response_obj.status_code = http_code;
|
||||
if(_debug_on){
|
||||
Serial.print("GET get_queue status: ");
|
||||
Serial.println(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(http.getString());
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)){
|
||||
String response = http.getString();
|
||||
response_obj.reply = response;
|
||||
}
|
||||
else if(_retry<=3){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = get_queue();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::transfer_playback(String device_id){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin("https://api.spotify.com/v1/me/player",_spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "{\"device_ids\":[\"" + device_id + "\"]}";
|
||||
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT play status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = transfer_playback(device_id);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::seek_to_position(int time_ms){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/seek";
|
||||
url += "?position_ms="+String(time_ms);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT seek_to_position status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = seek_to_position(time_ms);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::repeat_mode(String mode){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/repeat";
|
||||
url += "?state="+mode;
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT repeat status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = repeat_mode(mode);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::set_volume(int value){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/volume";
|
||||
url += "?volume_percent="+String(value);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT set_volume status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = set_volume(value);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::shuffle(bool mode){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String state;
|
||||
if(mode){
|
||||
state = "true";
|
||||
}
|
||||
else{
|
||||
state = "false";
|
||||
}
|
||||
String url = "https://api.spotify.com/v1/me/player/shuffle";
|
||||
url += "?state=" + state;
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
|
||||
int http_code=http.PUT(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT shuffle status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = shuffle(mode);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
response Spotify::add_to_queue(String context_uri){
|
||||
response response_obj;
|
||||
init_response(&response_obj);
|
||||
String url = "https://api.spotify.com/v1/me/player/queue";
|
||||
url += "?uri="+urlEncode(context_uri);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url, _spotify_root_ca);
|
||||
http.addHeader("Accept", "application/json");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
http.addHeader("Authorization","Bearer "+String(_access_token));
|
||||
|
||||
String payload= "";
|
||||
http.addHeader("content-Length", String(payload.length()));
|
||||
int http_code=http.POST(payload);
|
||||
|
||||
response_obj.status_code = http_code;
|
||||
String reply = "";
|
||||
DynamicJsonDocument doc(2000);
|
||||
|
||||
if(http.getSize()>0){
|
||||
reply = http.getString();
|
||||
deserializeJson(doc, reply);
|
||||
}
|
||||
|
||||
if(_debug_on){
|
||||
Serial.print("PUT add_to_queue status: ");
|
||||
Serial.print(http_code);
|
||||
Serial.print(" Reply: ");
|
||||
Serial.println(reply);
|
||||
}
|
||||
if ((http_code >= 200)&&(http_code <= 299)){
|
||||
response_obj.reply = "Success";
|
||||
}
|
||||
else if(_retry<=3){
|
||||
String message = doc["error"]["message"].as<String>();
|
||||
if(message == "Only valid bearer authentication supported"){
|
||||
_retry++;
|
||||
if(get_token()){
|
||||
response_obj = add_to_queue(context_uri);
|
||||
}
|
||||
}
|
||||
else{
|
||||
response_obj.reply = message;
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
_retry = 0;
|
||||
return response_obj;
|
||||
}
|
||||
void Spotify::init_response(response* response_obj){
|
||||
response_obj -> status_code = -1;
|
||||
response_obj -> reply ="If you see this something went wrong";
|
||||
}
|
||||
void print_response(response response_obj){
|
||||
Serial.print("Status: ");
|
||||
Serial.println(response_obj.status_code);
|
||||
Serial.print("Reply: ");
|
||||
Serial.println(response_obj.reply);
|
||||
}
|
||||
bool Spotify::get_token(){
|
||||
bool reply = false;
|
||||
HTTPClient http;
|
||||
String url = "https://accounts.spotify.com/api/token";
|
||||
|
||||
String authorization = String(_client_id) + ":" + String(_client_secret);
|
||||
authorization.trim();
|
||||
authorization = "Basic " + base64::encode(authorization);
|
||||
http.begin(url,_spotify_root_ca);
|
||||
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
http.addHeader("Authorization", authorization);
|
||||
|
||||
String payload = "grant_type=refresh_token&refresh_token="+String(_refresh_token);
|
||||
int http_code = http.POST(payload);
|
||||
if(_debug_on){
|
||||
Serial.print("POST token status: ");
|
||||
Serial.println(http_code);
|
||||
}
|
||||
if ((http_code >=200)&&(http_code<=299)) {
|
||||
String response = http.getString();
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, response);
|
||||
_access_token = doc["access_token"].as<String>();
|
||||
reply = true;
|
||||
}
|
||||
else{
|
||||
reply = false;
|
||||
}
|
||||
http.end();
|
||||
return reply;
|
||||
}
|
||||
String Spotify::current_track_name(){
|
||||
String track_name = "Something went wrong";
|
||||
response data = currently_playing();
|
||||
if((data.status_code>=200)&&(data.status_code<=299)){
|
||||
DynamicJsonDocument doc(10000);
|
||||
deserializeJson(doc,data.reply);
|
||||
track_name = doc["item"]["name"].as<String>();
|
||||
}
|
||||
return track_name;
|
||||
|
||||
}
|
||||
String Spotify::current_track_id(){
|
||||
String track_id = "Something went wrong";
|
||||
response data = currently_playing();
|
||||
if((data.status_code>=200)&&(data.status_code<=299)){
|
||||
DynamicJsonDocument doc(10000);
|
||||
deserializeJson(doc,data.reply);
|
||||
track_id = doc["item"]["id"].as<String>();
|
||||
}
|
||||
return track_id;
|
||||
}
|
||||
String Spotify::current_device_id(){
|
||||
String device_id = "Something went wrong";
|
||||
response data = available_devices();
|
||||
if((data.status_code>=200)&&(data.status_code<=299)){
|
||||
DynamicJsonDocument doc(2000);
|
||||
deserializeJson(doc,data.reply);
|
||||
JsonArray devices = doc["devices"].as<JsonArray>();
|
||||
for (JsonVariant device : devices) {
|
||||
JsonObject deviceObj = device.as<JsonObject>();
|
||||
|
||||
if (deviceObj["is_active"].as<bool>()) {
|
||||
device_id = deviceObj["id"].as<String>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return device_id;
|
||||
}
|
||||
String Spotify::current_artist_names(){
|
||||
String artist_names = "Something went wrong";
|
||||
response data = currently_playing();
|
||||
if((data.status_code>=200)&&(data.status_code<=299)){
|
||||
DynamicJsonDocument doc(10000);
|
||||
deserializeJson(doc,data.reply);
|
||||
JsonArray array = doc["item"]["artists"];
|
||||
int len = array.size();
|
||||
artist_names = "";
|
||||
for (int i = 0; i<len; i++){
|
||||
artist_names += array[i]["name"].as<String>();
|
||||
if (i<len-1){
|
||||
artist_names += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
return artist_names;
|
||||
}
|
||||
String Spotify::convert_id_to_uri(String id, String type){
|
||||
String uri = "spotify:"+type+":"+id;
|
||||
return uri;
|
||||
}
|
||||
88
SpotifyESP32.h
Normal file
88
SpotifyESP32.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef SpotifyESP32
|
||||
#define SpotifyESP32
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <base64.h>
|
||||
#include <UrlEncode.h>
|
||||
namespace Spotify_types{
|
||||
extern bool SHUFFLE_ON;
|
||||
extern bool SHUFFLE_OFF;
|
||||
extern String REPEAT_OFF;
|
||||
extern String REPEAT_TRACK;
|
||||
extern String REPEAT_CONTEXT;
|
||||
extern String TYPE_ALBUM;
|
||||
extern String TYPE_ARTIST;
|
||||
extern String TYPE_TRACK;
|
||||
extern String TYPE_PLAYLIST;
|
||||
};
|
||||
typedef struct{
|
||||
int status_code;
|
||||
String reply;
|
||||
} response;
|
||||
|
||||
void print_response(response response_obj);
|
||||
|
||||
class Spotify {
|
||||
public:
|
||||
Spotify(char* refresh_token, char* redirect_uri, char* client_id, char* client_secret, bool debug_on);
|
||||
response currently_playing();
|
||||
response play_uri(String track_uri);
|
||||
response start_playback();
|
||||
response pause_playback();
|
||||
response skip();
|
||||
response previous();
|
||||
response available_devices();
|
||||
response current_playback_state();
|
||||
response recently_played_tracks(int limit);
|
||||
response seek_to_position(int time_ms);
|
||||
response get_queue();
|
||||
response repeat_mode(String mode);
|
||||
response shuffle(bool mode);
|
||||
response transfer_playback(String device_id);
|
||||
response set_volume(int value);
|
||||
response add_to_queue(String context_uri);
|
||||
//These Are simplified versions of the previous ones
|
||||
String current_track_name();
|
||||
String current_track_id();
|
||||
String current_device_id();
|
||||
String current_artist_names();
|
||||
String convert_id_to_uri(String id, String type);
|
||||
|
||||
private:
|
||||
bool get_token();
|
||||
void init_response(response* response_obj);
|
||||
char* _refresh_token;
|
||||
char* _redirect_uri;
|
||||
char* _client_id;
|
||||
char* _client_secret;
|
||||
int _retry;
|
||||
bool _debug_on;
|
||||
String _access_token;
|
||||
const char* _spotify_root_ca = \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
|
||||
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"\
|
||||
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"\
|
||||
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"\
|
||||
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"\
|
||||
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"\
|
||||
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"\
|
||||
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"\
|
||||
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"\
|
||||
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"\
|
||||
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"\
|
||||
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"\
|
||||
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"\
|
||||
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"\
|
||||
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"\
|
||||
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"\
|
||||
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"\
|
||||
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"\
|
||||
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"\
|
||||
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"\
|
||||
"-----END CERTIFICATE-----\n";
|
||||
};
|
||||
#endif
|
||||
43
Spotify_Esp32_test.ino
Normal file
43
Spotify_Esp32_test.ino
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <base64.h>
|
||||
#include "SpotifyESP32.h"
|
||||
|
||||
const char* ssid = "YOUR SSID";
|
||||
const char* password = "YOUR WIFI PASSWORD";
|
||||
char* client_id = "YOUR CLIENT ID";
|
||||
char* client_secret = "YOUR CLIENT SECRET";
|
||||
char* redirect_uri = "http://localhost:8080";//Set redirect uri on dev dashboard
|
||||
char* refresh_token="YOUR CLIENT SECRET";
|
||||
|
||||
using namespace Spotify_types;
|
||||
|
||||
Spotify sp(refresh_token, redirect_uri, client_id, client_secret, false);//Set last Parameter to true to get more debug information
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
connectToWifi();
|
||||
Serial.print("Current Track: ");
|
||||
Serial.print(sp.current_track_name());
|
||||
Serial.print(" by ");
|
||||
Serial.println(sp.current_artist_names());
|
||||
|
||||
Serial.println(sp.convert_id_to_uri(sp.current_track_id(),TYPE_TRACK));
|
||||
print_response(sp.shuffle(SHUFFLE_ON));
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
}
|
||||
void connectToWifi(){
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.print("Connecting to WiFi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(1000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println("Connected to WiFi");
|
||||
}
|
||||
Reference in New Issue
Block a user