Fully Documented

This commit is contained in:
Finian Landes
2024-01-07 18:18:13 +01:00
parent 044042d436
commit ccf65e38ba
4 changed files with 1015 additions and 140 deletions

View File

@@ -1,9 +1,62 @@
# Spotify_Esp32
TODO:<br />
Optional:<br />
-Self diagnosis<br />
All Player Functions Working
# Spotify Library for ESP32
This library is a wrapper for the [Spotify Web API](https://developer.spotify.com/documentation/web-api/) and is designed to work with the [ESP32](https://www.espressif.com/en/products/socs/esp32/overview) microcontroller.
## Dependencies
- [ArduinoJson](https://arduinojson.org/) </br>
- [HTTPClient](https://github.com/amcewen/HttpClient) </br>
- [WiFi](https://www.arduino.cc/en/Reference/WiFi) </br>
- [UrlEncode](https://github.com/plageoj/urlencode) </br>
## Setup
1. Create a new application on the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/applications) and copy the Client ID and Client Secret. </br>
2. Get a refresh token with the needed scopes. (You can do that with this [tool](https://spotify-refresh-token-generator.netlify.app/#welcome)) </br>
3. Save refresh token, client id, client secret and redirect uri in your main.cpp or project_name.ino file. </br>
4. Create an instance of the Spotify class: </br>
```c++
Spotify sp("refresh_token", "client_id", "client_secret", "redirect_uri", "bool debug", "int number of retries");
```
Debug and number of retries are optional. Debug is false as default and retries is set to 3. </br>
5. Connect to Wifi: </br>
```c++
void connectToWifi(){
WiFi.begin("your_ssid", "your_password");§
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("Connected to WiFi");
}
```
This is a simple example using the WiFi library. </br>
6. Now you can call your needed functions on the Spotify instance. The functions have doxygen comments, so you can read them in your IDE. The functions are also corresponding to the [Spotify Web API](https://developer.spotify.com/documentation/web-api/). </br>
7. The normal functions return an response object. You can get the http code of type int with ```response_obj.status_code``` and the response message of type String with ```response_obj.reply```. </br>
To print the response you can use the ```print_response(response_obj)``` function. </br>
8. There are also some helper and some simplified functions. </br>
```c++
// Get the current track name and return it as String
String current_track_name();
// Get the current track id and return it as String
String current_track_id();
// Get the current device id and return it as String
String current_device_id();
// Get the current artist names and return it as String
String current_artist_names();
// Get the current device id and return a pointer to the char, can be used as parameter for other functions
char* current_device_id(char* device_id);
// Get the current track id and return a pointer to the char, can be used as parameter for other functions
char* current_track_id(char* track_id);
// Get the current track name and return a pointer to the char, can be used as parameter for other functions
char* current_track_name(char* track_name);
// Get the current artist names and return a pointer to the char, can be used as parameter for other functions
char* current_artist_names(char* artist_names);
//Check if the device is playing and return true or false
bool is_playing();
//Check if volume of the current device is modifyable and return true or false
bool volume_modifyable();
//Convert a context id to a uri and return it as a char
char convert_id_to_uri(char* id, char* type);
//Convert a context id to a uri and return it as a pointer to the char
char* convert_id_to_uri(char* id, char* type, char* uri);
```
9. You can also include the namespace: ```using namespace Spotify_types;```. These are some types used in the library eg. TYPES, SIZES of uris/ids </br>

View File

@@ -1,6 +1,5 @@
#include "SpotifyESP32.h"
namespace Spotify_types{
namespace Spotify_types {
bool SHUFFLE_ON = true;
bool SHUFFLE_OFF = false;
char* REPEAT_OFF = "off";
@@ -23,7 +22,6 @@ namespace Spotify_types{
int SIZE_OF_URI = 50;
}
Spotify::Spotify(const char* refresh_token, const char* redirect_uri, const char* client_id,const char* client_secret, bool debug_on, int max_num_retry){
_retry = 0;
_refresh_token = refresh_token;
@@ -38,6 +36,7 @@ Spotify::Spotify(const char* refresh_token, const char* redirect_uri, const char
_max_num_retry = 1;
}
}
//Basic functions
response Spotify::RestApiPut(char* rest_url,int payload_size, char* payload){
response response_obj;
@@ -47,7 +46,7 @@ response Spotify::RestApiPut(char* rest_url,int payload_size, char* payload){
http.begin(rest_url,_spotify_root_ca);
http.addHeader("Accept", "application/json");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization","Bearer "+String(_access_token));
http.addHeader("Authorization","Bearer "+_access_token);
http.addHeader("content-Length", String(payload_size));
int http_code=http.PUT(payload);
@@ -97,7 +96,7 @@ response Spotify::RestApiGet(char* rest_url){
http.begin(rest_url,_spotify_root_ca);
http.addHeader("Accept", "application/json");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization","Bearer "+String(_access_token));
http.addHeader("Authorization","Bearer "+_access_token);
int http_code = http.GET();
response_obj.status_code = http_code;
@@ -132,7 +131,7 @@ response Spotify::RestApiPost(char* rest_url,int payload_size, char* payload){
http.begin(rest_url,_spotify_root_ca);
http.addHeader("Accept", "application/json");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization","Bearer "+String(_access_token));
http.addHeader("Authorization","Bearer "+_access_token);
http.addHeader("content-Length", String(payload_size));
@@ -182,7 +181,7 @@ response Spotify::RestApiDelete(char* rest_url, char* payload){
http.begin(rest_url, _spotify_root_ca);
http.addHeader("Accept", "application/json");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", "Bearer " + String(_access_token));
http.addHeader("Authorization", "Bearer " + _access_token);
int http_code = http.sendRequest("DELETE", payload);
@@ -235,9 +234,9 @@ bool Spotify::get_token(){
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
http.addHeader("Authorization", authorization);
String payload = "grant_type=refresh_token&refresh_token="+String(_refresh_token);
String payload = "grant_type=refresh_token&refresh_token=" + String(_refresh_token);
int http_code = http.POST(payload);
if(_debug_on){
if (_debug_on) {
Serial.print("POST \"token\" status: ");
Serial.println(http_code);
}
@@ -493,13 +492,15 @@ response Spotify::get_artist(char* artist_id){
}
response Spotify::get_several_artists(int size, char ** artist_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/artists?ids=%s", array_to_char(size, artist_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/artists?ids=%s", array_to_char(size, artist_ids, arr));
return RestApiGet(url);
}
response Spotify::get_artist_albums(char* artist_id,int size_groups, char** include_groups, int limit, int offset){
char url[200];
sprintf(url, "https://api.spotify.com/v1/artists/%s/albums?include_groups=%s&limit=%d&offset=%d", artist_id, array_to_char(size_groups,include_groups), limit, offset);
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/artists/%s/albums?include_groups=%s&limit=%d&offset=%d", artist_id, array_to_char(size_groups,include_groups, arr), limit, offset);
return RestApiGet(url);
}
@@ -531,7 +532,8 @@ response Spotify::get_audiobook(char* audiobook_id){
}
response Spotify::get_several_audiobooks(int size, char** audiobook_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/audiobooks?ids=%s", array_to_char(size, audiobook_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/audiobooks?ids=%s", array_to_char(size, audiobook_ids,arr));
return RestApiGet(url);
}
@@ -549,34 +551,59 @@ response Spotify::get_users_audiobooks(int limit, int offset){
}
response Spotify::save_audiobooks_for_current_user(int size, char** audiobook_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks?ids=%s", array_to_char(size, audiobook_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks?ids=%s", array_to_char(size, audiobook_ids, arr));
return RestApiPut(url);
}
response Spotify::remove_audiobooks_for_current_user(int size, char** audiobook_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks?ids=%s", array_to_char(size, audiobook_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks?ids=%s", array_to_char(size, audiobook_ids, arr));
return RestApiDelete(url);
}
response Spotify::check_users_saved_audiobooks(int size, char** audiobook_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks/contains?ids=%s", array_to_char(size, audiobook_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/audiobooks/contains?ids=%s", array_to_char(size, audiobook_ids,arr));
return RestApiGet(url);
}
#endif
#ifdef ENABLE_CATEGORIES
//Categories
response Spotify::get_several_browse_categories(char* country, char* locale, int limit, int offset){
response Spotify::get_several_browse_categories(int limit, int offset, char* country, char* locale){
char url[200];
sprintf(url, "https://api.spotify.com/v1/browse/categories?country=%s&locale=%s&limit=%d&offset=%d", country, locale, limit, offset);
if((country == nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories?limit=%d&offset=%d", limit, offset);
}
else if((country == nullptr)&&(locale != nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories?locale=%s&limit=%d&offset=%d", locale, limit, offset);
}
else if((country != nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories?country=%s&limit=%d&offset=%d", country, limit, offset);
}
else{
sprintf(url, "https://api.spotify.com/v1/browse/categories?country=%s&locale=%s&limit=%d&offset=%d", country, locale, limit, offset);
}
return RestApiGet(url);
}
response Spotify::get_single_browse_category(char* category_id, char* country, char* locale){
char url[150];
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s?country=%s&locale=%s", category_id, country, locale);
if((country == nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s", category_id);
}
else if((country == nullptr)&&(locale != nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s?locale=%s", category_id, locale);
}
else if((country != nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s?country=%s", category_id, country);
}
else{
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s?country=%s&locale=%s", category_id, country, locale);
}
return RestApiGet(url);
}
@@ -591,7 +618,8 @@ response Spotify::get_chapter(char* chapter_id){
}
response Spotify::get_several_chapters(int size, char** chapter_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/chapters?ids=%s", array_to_char(size, chapter_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/chapters?ids=%s", array_to_char(size, chapter_ids, arr));
return RestApiGet(url);
}
@@ -606,7 +634,8 @@ response Spotify::get_episode(char* episode_id){
}
response Spotify::get_several_episodes(int size,char** episode_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/episodes?ids=%s", array_to_char(size, episode_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/episodes?ids=%s", array_to_char(size, episode_ids, arr));
return RestApiGet(url);
}
@@ -634,7 +663,8 @@ response Spotify::remove_episodes_for_current_user(int size,char** episode_ids){
}
response Spotify::check_users_saved_episodes(int size,char** episode_ids){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/episodes/contains?ids=%s", array_to_char(size, episode_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/episodes/contains?ids=%s", array_to_char(size, episode_ids, arr));
return RestApiGet(url);
}
@@ -657,9 +687,28 @@ response Spotify::get_available_markets(){
#endif
#ifdef ENABLE_PLAYLISTS
//Playlist
response Spotify::get_playlist(char* playlist_id, char* fields) {
response Spotify::get_playlist(char* playlist_id,int size, char** fields,int size_of_additional_types, char** additional_types) {
char url[200];
sprintf(url, "https://api.spotify.com/v1/playlists/%s?fields=%s", playlist_id, fields);
if(size == 0){
if(size_of_additional_types == 0){
sprintf(url, "https://api.spotify.com/v1/playlists/%s", playlist_id);
}
else{
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/playlists/%s?additional_types=%s", playlist_id, array_to_char(size_of_additional_types, additional_types, arr));
}
}
else{
if(size_of_additional_types == 0){
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/playlists/%s?fields=%s", playlist_id, array_to_char(size, fields, arr));
}
else{
char arr[_max_char_size];
char arr2[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/playlists/%s?fields=%s&additional_types=%s", playlist_id, array_to_char(size, fields, arr), array_to_char(size_of_additional_types, additional_types, arr2));
}
}
return RestApiGet(url);
}
@@ -728,8 +777,8 @@ response Spotify::add_items_to_playlist(char* playlist_id, int size, char ** uri
response Spotify::remove_playlist_items(char* playlist_id,int size, char** uris) {
char url[100];
sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks", playlist_id);
char* payload = array_to_char(size, uris);
char arr[_max_char_size];
char* payload = array_to_char(size, uris, arr);
return RestApiDelete(url, payload);
@@ -766,15 +815,45 @@ response Spotify::create_playlist(char* user_id, char* name, bool is_public, boo
return RestApiPost(url, payload_size, payload);
}
response Spotify::get_featured_playlists(char* country, char* locale, char* timestamp, int limit, int offset) {
response Spotify::get_featured_playlists( int limit, int offset,char* timestamp,char* country, char* locale) {
char url[200];
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&locale=%s&timestamp=%s&limit=%d&offset=%d", country, locale, timestamp, limit, offset);
if(timestamp != nullptr){
if((country == nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?timestamp=%s&limit=%d&offset=%d", timestamp, limit, offset);
}
else if((country == nullptr)&&(locale != nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?locale=%s&timestamp=%s&limit=%d&offset=%d", locale, timestamp, limit, offset);
}
else if((country != nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&timestamp=%s&limit=%d&offset=%d", country, timestamp, limit, offset);
}
else{
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&locale=%s&timestamp=%s&limit=%d&offset=%d", country, locale, timestamp, limit, offset);
}
}else{
if((country == nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?limit=%d&offset=%d", limit, offset);
}
else if((country == nullptr)&&(locale != nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?locale=%s&limit=%d&offset=%d", locale, limit, offset);
}
else if((country != nullptr)&&(locale == nullptr)){
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&limit=%d&offset=%d", country, limit, offset);
}
else{
sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&locale=%s&limit=%d&offset=%d", country, locale, limit, offset);
}
}
return RestApiGet(url);
}
response Spotify::get_category_playlists(char* category_id, char* country, int limit, int offset) {
response Spotify::get_category_playlists(char* category_id, int limit, int offset, char* country) {
char url[200];
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s/playlists?country=%s&limit=%d&offset=%d", category_id, country, limit, offset);
if(country == nullptr){
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s/playlists?limit=%d&offset=%d", category_id, limit, offset);
}
else{
sprintf(url, "https://api.spotify.com/v1/browse/categories/%s/playlists?country=%s&limit=%d&offset=%d", category_id, country, limit, offset);
}
return RestApiGet(url);
}
@@ -794,9 +873,26 @@ response Spotify::add_custom_playlist_cover_image(char* playlist_id, char* data)
#endif
#ifdef ENABLE_SEARCH
//Search
response Spotify::search(char* q, char* type, int limit, int offset){
response Spotify::search(char* q, int type_size, char** type, int limit, int offset, char* market){
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/search?q=%s&type=%s&limit=%d&offset=%d", q, type, limit, offset);
char arr[_max_char_size];
if(market != nullptr){
if(type_size == 0){
sprintf(url, "https://api.spotify.com/v1/search?q=%s&limit=%d&offset=%d&market=%s", q, limit, offset, market);
}
else{
sprintf(url, "https://api.spotify.com/v1/search?q=%s&type=%s&limit=%d&offset=%d&market=%s", q, array_to_char(type_size, type, arr), limit, offset, market);
}
}
else{
if(type_size == 0){
sprintf(url, "https://api.spotify.com/v1/search?q=%s&limit=%d&offset=%d&market=%s", q, limit, offset, market);
}
else{
sprintf(url, "https://api.spotify.com/v1/search?q=%s&type=%s&limit=%d&offset=%d&market=%s", q, array_to_char(type_size, type, arr), limit, offset, market);
}
}
return RestApiGet(url);
}
@@ -811,7 +907,8 @@ response Spotify::get_show(char* show_id) {
}
response Spotify::get_several_shows(int size,char ** show_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/shows?ids=%s", array_to_char(size, show_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/shows?ids=%s", array_to_char(size, show_ids, arr));
return RestApiGet(url);
}
@@ -829,19 +926,22 @@ response Spotify::get_users_saved_shows(int limit, int offset) {
}
response Spotify::save_shows_for_current_user(int size,char ** show_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows?ids=%s", array_to_char(size, show_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows?ids=%s", array_to_char(size, show_ids, arr));
return RestApiPut(url);
}
response Spotify::remove_shows_for_current_user(int size,char ** show_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows?ids=%s", array_to_char(size, show_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows?ids=%s", array_to_char(size, show_ids, arr));
return RestApiDelete(url);
}
response Spotify::check_users_saved_shows(int size,char ** show_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows/contains?ids=%s", array_to_char(size, show_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/shows/contains?ids=%s", array_to_char(size, show_ids, arr));
return RestApiGet(url);
}
@@ -856,7 +956,8 @@ response Spotify::get_track(char* track_id) {
}
response Spotify::get_several_tracks(int size,char ** track_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/tracks?ids=%s", array_to_char(size, track_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/tracks?ids=%s", array_to_char(size, track_ids, arr));
return RestApiGet(url);
}
@@ -1151,13 +1252,15 @@ response Spotify::unfollow_artists_or_users(char* type,int size, char** artist_u
}
response Spotify::check_if_user_follows_artists_or_users(char* type,int size, char** artist_user_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/following/contains?type=%s&ids=%s", type, array_to_char(size, artist_user_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/me/following/contains?type=%s&ids=%s", type, array_to_char(size, artist_user_ids, arr));
return RestApiGet(url);
}
response Spotify::check_if_users_follow_playlist(char* playlist_id,int size, char** user_ids) {
char url[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/playlists/%s/followers/contains?ids=%s", playlist_id, array_to_char(size, user_ids));
char arr[_max_char_size];
sprintf(url, "https://api.spotify.com/v1/playlists/%s/followers/contains?ids=%s", playlist_id, array_to_char(size, user_ids, arr));
return RestApiGet(url);
}
@@ -1284,6 +1387,16 @@ bool Spotify::is_playing(){
}
return is_playing;
}
bool Spotify::volume_modifyable(){
bool volume_modifyable = false;
response data = current_playback_state();
if((data.status_code>=200)&&(data.status_code<=299)){
DynamicJsonDocument doc(10000);
deserializeJson(doc,data.reply);
volume_modifyable = doc["device"]["supports_volume"];
}
return volume_modifyable;
}
#endif
char Spotify::convert_id_to_uri(char* id, char* type){
char uri[45];
@@ -1297,6 +1410,6 @@ char* Spotify::convert_id_to_uri(char* id, char* type,char * uri){
void print_response(response response_obj){
Serial.print("Status: ");
Serial.println(response_obj.status_code);
/*Serial.print("Reply: ");
Serial.println(response_obj.reply);*/
Serial.print("Reply: ");
Serial.println(response_obj.reply);
}

View File

@@ -1,21 +1,21 @@
#ifndef SpotifyESP32
#define SpotifyESP32
//#define ENABLE_PLAYER
#define ENABLE_ALBUM
//#define ENABLE_ARTIST
//#define ENABLE_AUDIOBOOKS
//#define ENABLE_CATEGORIES
//#define ENABLE_CHAPTERS
//#define ENABLE_EPISODES
//#define ENABLE_GENRES
//#define ENABLE_MARKETS
//#define ENABLE_PLAYLISTS
//#define ENABLE_SEARCH
//#define ENABLE_SHOWS
//define ENABLE_TRACKS
//#define ENABLE_USERS
//#define ENABLE_SIMPIFIED //Player needs to be enabled for this to work
#define ENABLE_PLAYER
#define ENABLE_ALBUM
#define ENABLE_ARTIST
#define ENABLE_AUDIOBOOKS
#define ENABLE_CATEGORIES
#define ENABLE_CHAPTERS
#define ENABLE_EPISODES
#define ENABLE_GENRES
#define ENABLE_MARKETS
#define ENABLE_PLAYLISTS
#define ENABLE_SEARCH
#define ENABLE_SHOWS
#define ENABLE_TRACKS
#define ENABLE_USER
#define ENABLE_SIMPIFIED
#include <Arduino.h>
#include <WiFi.h>
@@ -30,35 +30,37 @@
namespace Spotify_types{
extern const bool SHUFFLE_ON;//Shuffle on
extern const bool SHUFFLE_OFF;//Shuffle off
extern const char* REPEAT_OFF;//Repeat off
extern const char* REPEAT_TRACK;//Repeat track
extern const char* REPEAT_CONTEXT;//Repeat context
extern const char* TYPE_ALBUM;//URI type album
extern const char* TYPE_ARTIST;//URI type artist
extern const char* TYPE_TRACK;//URI type track
extern const char* TYPE_PLAYLIST;//URI type playlist
extern const char* GROUP_ALBUM;//Get artist's albums include groups album
extern const char* GROUP_SINGLE;//Get artist's albums include groups single
extern const char* GROUP_APPEARS_ON;//Get artist's albums include groups appears on
extern const char* GROUP_COMPILATION;//Get artist's albums include groups compilation
extern const char* TIME_RANGE_SHORT;//4 weeks
extern const char* TIME_RANGE_MEDIUM;//6 months
extern const char* TIME_RANGE_LONG;//Several years
extern const char* TOP_TYPE_ARTIST;//Users top artist's
extern const char* TOP_TYPE_TRACKS;//Users top tracks
extern const int SIZE_OF_URI;//Size to allocate for uri
extern const int SIZE_OF_ID;//Size to allocate for id
};
namespace Spotify_types {
extern bool SHUFFLE_ON;
extern bool SHUFFLE_OFF;
extern char* REPEAT_OFF;
extern char* REPEAT_TRACK;
extern char* REPEAT_CONTEXT;
extern char* TYPE_ALBUM;
extern char* TYPE_ARTIST;
extern char* TYPE_TRACK;
extern char* TYPE_PLAYLIST;
extern char* TOP_TYPE_ARTIST;
extern char* TOP_TYPE_TRACKS;
extern char* GROUP_ALBUM;
extern char* GROUP_SINGLE;
extern char* GROUP_APPEARS_ON;
extern char* GROUP_COMPILATION;
extern char* TIME_RANGE_SHORT;
extern char* TIME_RANGE_MEDIUM;
extern char* TIME_RANGE_LONG;
extern int SIZE_OF_ID;
extern int SIZE_OF_URI;
}
/// @brief Response object containing http status code and reply
typedef struct{
int status_code;
String reply;
} response;//Response object containing http status code and reply
} response;
/// @brief Recommendation object, used to create recommendations
struct recommendations {
char** seed_artists;
int seed_artists_size = 0;
@@ -108,11 +110,11 @@ struct recommendations {
float min_valence = -1.0;
float max_valence = -1.0;
float target_valence = -1.0;
};//Fill in the values you want to use for recommendations, at least one seed is required
void print_response(response response_obj);//Print response object
};
/// @brief Print response object
/// @param response_obj Response object to print
void print_response(response response_obj);
class Spotify {
public:
///@brief Constructor for Spotify object
@@ -123,7 +125,6 @@ class Spotify {
///@param debug_on Debug mode on or off(default off)
///@param max_num_retry Max number of retries for a request(default 3)
Spotify(const char* refresh_token, const char* redirect_uri,const char* client_id,const char* client_secret, bool debug_on = false, int max_num_retry =3);
//Player
#ifdef ENABLE_PLAYER
///@brief Get information about the user's current playback state, including track, track progress, and active device.
///@return response object containing http status code and reply
@@ -191,7 +192,6 @@ class Spotify {
response add_to_queue(char* context_uri);
#endif
#ifdef ENABLE_ALBUM
//Albums
///@brief Get Spotify information for a single album.
///@param album_id Spotify ID of the album
///@return response object containing http status code and reply
@@ -232,10 +232,9 @@ class Spotify {
///@param offset The index of the first item to return. Default: 0 (the first object). Use with limit to get the next set of items.
///@param country A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country.
///@return response object containing http status code and reply
response get_new_releases(int limit = 10, int offset = 0, char* country ="");
response get_new_releases(int limit = 10, int offset = 0, char* country = nullptr);
#endif
#ifdef ENABLE_ARTIST
//Artists
///@brief Get Spotify information for a single artist
///@param artist_id Spotify ID of the artist
///@return response object containing http status code and reply
@@ -264,174 +263,488 @@ class Spotify {
response get_artist_related_artist(char* artist_id);
#endif
#ifdef ENABLE_AUDIOBOOKS
//Audiobooks (Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
///@brief Get Spotify information for a single audiobook
///@brief Get Spotify information for a single audiobook(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
///@param audiobook_id Spotify ID of the audiobook
///@return response object containing http status code and reply
response get_audiobook(char* audiobook_id);
///@brief Get Spotify information for multiple audiobooks
///@brief Get Spotify information for multiple audiobooks(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
///@param size Number of audiobook ids in audiobook_ids array
///@param audiobook_ids Array of Spotify IDs of the audiobooks
///@return response object containing http status code and reply
response get_several_audiobooks(int size, char** audiobook_ids);
///@brief Get Spotify information about an audiobook's chapters
///@brief Get Spotify information about an audiobook's chapters(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
///@param audiobook_id Spotify ID of the audiobook
///@param limit The maximum number of items to return. Default: 10. Minimum: 1. Maximum: 50
///@param offset The index of the first chapter to return. Default: 0 (the first object). Use with limit to get the next set of chapters.
///@return response object containing http status code and reply
response get_audiobook_chapters(char* audiobook_id, int limit = 10, int offset = 0);
/// @brief
/// @param limit
/// @param offset
/// @return
/// @brief Get users saved audiobooks(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_users_audiobooks(int limit = 10, int offset = 0);
/// @brief Save one or more audiobooks to the current user's music library
/// @brief Save one or more audiobooks to the current user's music library(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
/// @param size Number of audiobook ids in audiobook_ids array
/// @param audiobook_ids Array of Spotify IDs of the audiobooks
/// @return response object containing http status code and reply
response save_audiobooks_for_current_user(int size, char** audiobook_ids);
/// @brief Remove one or more audiobooks from the current user's music library
/// @brief Remove one or more audiobooks from the current user's music library(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
/// @param size Number of audiobook ids in audiobook_ids array
/// @param audiobook_ids Array of Spotify IDs of the audiobooks
/// @return response object containing http status code and reply
response remove_audiobooks_for_current_user(int size, char** audiobook_ids);
/// @brief Check if one or more audiobooks is already saved in the current Spotify user's music library
/// @brief Check if one or more audiobooks is already saved in the current Spotify user's music library(Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
/// @param size Number of audiobook ids in audiobook_ids array
/// @param audiobook_ids Array of Spotify IDs of the audiobooks
/// @return response object containing http status code and reply
response check_users_saved_audiobooks(int size, char** audiobook_ids);
#endif
#ifdef ENABLE_CATEGORIES
//Categories
response get_several_browse_categories(char* country, char* locale, int limit = 10, int offset = 0);
response get_single_browse_category(char* category_id, char* country, char* locale);
///@brief Get a list of categories used to tag items in Spotify
///@param limit The maximum number of items to return
///@param offset The index of the first item to return
///@param country An ISO 3166-1 alpha-2 country code, if ommited the returned items will not be country-specific
///@param locale The desired language, consisting of an ISO 639-1 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore, if ommited the response defaults to American English
///@return response object containing http status code and reply
response get_several_browse_categories(int limit = 10, int offset = 0, char* country = nullptr, char* locale = nullptr);
///@brief Get a single category used to tag items in Spotify
///@param category_id Spotify category ID of the category
///@param country An ISO 3166-1 alpha-2 country code, if ommited the returned items will not be country-specific
///@param locale The desired language, consisting of an ISO 639-1 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore, if ommited the response defaults to American English
///@return response object containing http status code and reply
response get_single_browse_category(char* category_id, char* country = nullptr, char* locale = nullptr);
#endif
#ifdef ENABLE_CHAPTERS
//Chapters (Only Available in US, UK, Canada, Ireland, New Zealand and Australia)
///@brief Get Spotify information for a single chapter, Only Available in US, UK, Canada, Ireland, New Zealand and Australia
///@param chapter_id Spotify ID of the chapter
///@return response object containing http status code and reply
response get_chapter(char* chapter_id);
///@brief Get Spotify information for multiple chapters, Only Available in US, UK, Canada, Ireland, New Zealand and Australia
///@param size Number of chapter ids in chapter_ids array
///@param chapter_ids Array of Spotify IDs of the chapters
///@return response object containing http status code and reply
response get_several_chapters(int size, char** chapter_ids);
#endif
#ifdef ENABLE_EPISODES
//Episodes
///@brief Get Spotify information for a single episode
///@param episode_id Spotify ID of the episode
///@return response object containing http status code and reply
response get_episode(char* episode_id);
///@brief Get Spotify information for multiple episodes
///@param size Number of episode ids in episode_ids array
///@param episode_ids Array of Spotify IDs of the episodes
///@return response object containing http status code and reply
response get_several_episodes(int size, char** episode_ids);
///@brief Get users saved episodes
///@param limit The maximum number of items to return,
///@param offset The index of the first item to return
///@return response object containing http status code and reply
response get_users_saved_episodes(int limit = 10, int offset = 0);
///@brief Save one or more episodes to the current user's music library
///@param size Number of episode ids in episode_ids array
///@param episode_ids Array of Spotify IDs of the episodes
///@return response object containing http status code and reply
response save_episodes_for_current_user(int size, char** episode_ids);
///@brief Remove one or more episodes from the current user's music library
///@param size Number of episode ids in episode_ids array
///@param episode_ids Array of Spotify IDs of the episodes
///@return response object containing http status code and reply
response remove_episodes_for_current_user(int size, char** episode_ids);
///@brief Check if one or more episodes is already saved in the current Spotify user's music library
///@param size Number of episode ids in episode_ids array
///@param episode_ids Array of Spotify IDs of the episodes
///@return response object containing http status code and reply
response check_users_saved_episodes(int size, char** episode_ids);
#endif
#ifdef ENABLE_GENRES
//Genres
///@brief Get a list of available genre seeds for recommendations
///@return response object containing http status code and reply
response get_available_genre_seeds();
#endif
#ifdef ENABLE_MARKETS
//Markets
///@brief Get a list of available markets for recommendations
///@return response object containing http status code and reply
response get_available_markets();
#endif
#ifdef ENABLE_PLAYLISTS
//Playlists
response get_playlist(char* playlist_id, char* fields);
///@brief Get Spotify information for a single playlist
///@param playlist_id Spotify ID of the playlist
///@param size Number of fields in fields array
///@param fields Array of fields to return, leave empty to return all fields
///@param additional_types A comma-separated list of item types that your client supports besides the default track type. Valid types are: track and episode.
///@return response object containing http status code and reply
response get_playlist(char* playlist_id,int size = 0, char** fields = nullptr,int size_of_additional_types = 0, char ** additional_types = nullptr);
/// @brief Change details of a playlist
/// @param playlist_id ID of the playlist
/// @param name Set the name of the playlist
/// @param is_public Set the playlist to public or not
/// @param is_collaborative Set the playlist to collaborative or not
/// @param description Set the description of the playlist
/// @return response object containing http status code and reply
response change_playlist_details(char* playlist_id, char* name, bool is_public, bool is_collaborative, char* description);
/// @brief Get Items of a playlist
/// @param playlist_id Id of the playlist
/// @param fields Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are returned. For example, to get just the total number of items and the request limit:
/// @param limit Number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_playlist_items(char* playlist_id, char* fields, int limit = 10, int offset = 0);
/// @brief Either reorder or replace items in a playlist depending on the request's parameters
/// @param playlist_id Id of the playlist
/// @param size Size of uris array
/// @param uris Array of Spotify URIs this will overwrite all existing items in the playlist, If items should only be reordered pass nullptr
/// @param range_length The position of the first item to be reordered.
/// @param range_start The position where the items should be inserted.
/// @param insert_before The amount of items to be reordered.
/// @return response object containing http status code and reply
response update_playlist_items(char* playlist_id, int size, char** uris = nullptr, int range_length = 1, int range_start = 0, int insert_before = 1 );
/// @brief Add items to a playlist
/// @param playlist_id Id of the playlist
/// @param size Size of uris array
/// @param uris Array of Spotify URIs of the items to add
/// @param position The position to insert the items, a zero-based index
/// @return response object containing http status code and reply
response add_items_to_playlist(char* playlist_id, int size, char** uris, int position = 0);
/// @brief Remove items from a playlist
/// @param playlist_id Id of the playlist
/// @param size Size of uris array
/// @param uris Array of Spotify URIs of the items to remove
/// @return response object containing http status code and reply
response remove_playlist_items(char* playlist_id, int size, char** uris);
/// @brief Get a list of users playlists
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_current_users_playlists(int limit = 10, int offset = 0);
/// @brief get a users playlist
/// @param user_id Id of the user
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_user_playlists(char* user_id,int limit = 10, int offset = 0);
/// @brief Create a playlist
/// @param user_id Id of the user
/// @param name Name of the playlist
/// @param is_public Set the playlist to public or not
/// @param is_collaborative Set the playlist to collaborative or not
/// @param description Description of the playlist
/// @return response object containing http status code and reply
response create_playlist(char* user_id, char* name, bool is_public, bool is_collaborative, char* description);
response get_featured_playlists(char* country, char* locale, char* timestamp,int limit = 10, int offset = 0);
response get_category_playlists(char* category_id, char* country, int limit = 10, int offset = 0);
/// @brief Get a list of Spotify featured playlists
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @param timestamp A timestamp in ISO 8601 format: yyyy-MM-ddTHH:mm:ss if ommited current utc time is used
/// @param country An ISO 3166-1 alpha-2 country code, Provide this to ensure that the category exists for a particular country.
/// @param locale The desired language, consisting of an ISO 639-1 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore, if ommited the response defaults to American English
/// @return response object containing http status code and reply
response get_featured_playlists( int limit = 10, int offset = 0, char* timestamp = nullptr, char* country = nullptr, char* locale = nullptr);
/// @brief Get a list of Spotify playlists tagged with a particular category.
/// @param category_id Category ID can be got from get_several_browse_categories
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @param country The country: an ISO 3166-1 alpha-2 country code, Provide this to ensure that the category exists for a particular country.
/// @return response object containing http status code and reply
response get_category_playlists(char* category_id, int limit = 10, int offset = 0, char* country = nullptr);
/// @brief Get a cover image of a playlist
/// @param playlist_id Id of the playlist
/// @return response object containing http status code and reply
response get_playlist_cover_image(char* playlist_id);
/// @brief Upload a custom cover image of a playlist
/// @param playlist_id Id of the playlist
/// @param data Image data
/// @param market An ISO 3166-1 alpha-2 country code, Provide this parameter if you want to apply Track Relinking
/// @return response object containing http status code and reply
response add_custom_playlist_cover_image(char* playlist_id, char* data);
#endif
#ifdef ENABLE_SEARCH
//Search
response search(char* q, char* type, int limit = 10, int offset = 0);
/// @brief Search for an item
/// @param q Search query keywords and optional field filters and operators
/// @param type_size Number of item types in type array,needs to e set to 0 if limit, offset or market is used and type is not used
/// @param type A comma-separated list of item types to search across, needs to be set to nullptr if limit, offset or market is used and type is not used
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @param market An ISO 3166-1 alpha-2 country code or the string from_token, Provide this parameter if you want to apply Track Relinking
/// @return response object containing http status code and reply
response search(char* q,int type_size = 0, char** type = nullptr, int limit = 10, int offset = 0, char* market = nullptr);
#endif
#ifdef ENABLE_SHOWS
//Shows
/// @brief Get Spotify information for a single show
/// @param show_id Spotify ID of the show
/// @return response object containing http status code and reply
response get_show(char* show_id);
/// @brief Get Spotify information for multiple shows
/// @param size Number of show ids in show_ids array
/// @param show_ids Array of Spotify IDs of the shows
/// @return response object containing http status code and reply
response get_several_shows(int size, char** show_ids);
/// @brief Get Spotify information about a show's episodes
/// @param show_id Spotify ID of the show
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_show_episodes(char* show_id, int limit = 10, int offset = 0);
/// @brief Get users saved shows
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_users_saved_shows(int limit = 10, int offset = 0);
/// @brief Save one or more shows to the current user's music library
/// @param size Number of show ids in show_ids array
/// @param show_ids Array of Spotify IDs of the shows
/// @return response object containing http status code and reply
response save_shows_for_current_user(int size, char** show_ids);
/// @brief Remove one or more shows from the current user's music library
/// @param size Number of show ids in show_ids array
/// @param show_ids Array of Spotify IDs of the shows
/// @return response object containing http status code and reply
response remove_shows_for_current_user(int size, char** show_ids);
/// @brief Check if one or more shows is already saved in the current Spotify user's music library
/// @param size Number of show ids in show_ids array
/// @param show_ids Array of Spotify IDs of the shows
/// @return response object containing http status code and reply
response check_users_saved_shows(int size, char** show_ids);
#endif
#ifdef ENABLE_TRACKS
//Tracks
/// @brief Get Spotify information for a single track
/// @param track_id Spotify ID of the track
/// @return response object containing http status code and reply
response get_track(char* track_id);
/// @brief Get Spotify information for multiple tracks
/// @param size Number of track ids in track_ids array
/// @param track_ids Array of Spotify IDs of the tracks
/// @return response object containing http status code and reply
response get_several_tracks(int size, char** track_ids);
/// @brief Get users saved tracks
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_user_saved_tracks(int limit = 10, int offset = 0);
/// @brief Save one or more tracks to the current user's music library
/// @param size Number of track ids in track_ids array
/// @param track_ids Array of Spotify IDs of the tracks
/// @return response object containing http status code and reply
response save_tracks_for_current_user(int size, char** track_ids);
/// @brief Remove one or more tracks from the current user's music library
/// @param size Number of track ids in track_ids array
/// @param track_ids Array of Spotify IDs of the tracks
/// @return response object containing http status code and reply
response remove_user_saved_tracks(int size, char** track_ids);
/// @brief Check if one or more tracks is already saved in the current Spotify user's music library
/// @param size Number of track ids in track_ids array
/// @param track_ids Array of Spotify IDs of the tracks
/// @return response object containing http status code and reply
response check_user_saved_tracks(int size, char** track_ids);
/// @brief Get audio features for multiple tracks
/// @param size Number of track ids in track_ids array
/// @param track_ids Array of Spotify IDs of the tracks
/// @return response object containing http status code and reply
response get_tracks_audio_features(int size, char** track_ids);
/// @brief Get audio features for a single track
/// @param track_id Spotify ID of the track
/// @return response object containing http status code and reply
response get_track_audio_features(char* track_id);
/// @brief Get audio analysis for a single track
/// @param track_id Spotify ID of the track
/// @return response object containing http status code and reply
response get_track_audio_analysis(char* track_id);
/// @brief Get a list of new album releases featured in Spotify
/// @param recom Recommendation object containing atleast one seed
/// @param limit The maximum number of items to return
/// @return response object containing http status code and reply
response get_recommendations(recommendations& recom, int limit = 10);
#endif
#ifdef ENABLE_USERS
//Users
#ifdef ENABLE_USER
/// @brief Get detailed profile information about the current user (including the current user's username)
/// @return response object containing http status code and reply
response get_current_user_profile();
/// @brief Get users top items
/// @param type The type of item to get, Valid values are: artists or tracks
/// @param time_range Over what time frame the affinities are computed, Valid values are: long_term, medium_term, short_term
/// @param limit The maximum number of items to return
/// @param offset The index of the first item to return
/// @return response object containing http status code and reply
response get_user_top_items(char* type, char* time_range = "medium_term", int limit = 10, int offset = 0);
/// @brief Get a users profile
/// @param user_id Id of the user
/// @return response object containing http status code and reply
response get_user_profile(char* user_id);
/// @brief Follow a playlist
/// @param playlist_id The Id of the playlist
/// @param is_public If true the playlist will be included in user's public playlists, if false it will remain private.
/// @return response object containing http status code and reply
response follow_playlist(char* playlist_id, bool is_public);
/// @brief Unfollow a playlist
/// @param playlist_id The Id of the playlist
/// @return response object containing http status code and reply
response unfollow_playlist(char* playlist_id);
/// @brief get users followed artists
/// @param after The last artist ID retrieved from the previous request
/// @param type The ID type, currently only artist is supported
/// @param limit The maximum number of items to return
/// @return response object containing http status code and reply
response get_followed_artists(char* after, char* type = "artist", int limit = 10);
/// @brief Follow artists or users
/// @param type The ID type, artist or user
/// @param size Number of artist or user ids in artist_user_ids array
/// @param artist_user_ids Array of Spotify IDs of the artists or users
/// @return response object containing http status code and reply
response follow_artists_or_users(char* type, int size, char** artist_user_ids);
/// @brief Unfollow artists or users
/// @param type The ID type, artist or user
/// @param size Number of artist or user ids in artist_user_ids array
/// @param artist_user_ids Array of Spotify IDs of the artists or users
/// @return response object containing http status code and reply
response unfollow_artists_or_users(char* type, int size, char** artist_user_ids);
/// @brief Check if users follow artists or users
/// @param type The ID type, artist or user
/// @param size Number of artist or user ids in artist_user_ids array
/// @param artist_user_ids Array of Spotify IDs of the artists or users
/// @return response object containing http status code and reply
response check_if_user_follows_artists_or_users(char* type, int size, char** artist_user_ids);
/// @brief Check if users follow a playlist
/// @param playlist_id The ID of the playlist
/// @param size Number of user ids in user_ids array
/// @param user_ids Array of Spotify IDs of the users
/// @return response object containing http status code and reply
response check_if_users_follow_playlist(char* playlist_id, int size, char** user_ids);
#endif
#ifdef ENABLE_SIMPIFIED
//Simplified versions of the above
/// @brief Get Current track name
/// @return Current track name as String
String current_track_name();
/// @brief Get Current track id
/// @return Current track id as String
String current_track_id();
/// @brief Get Current device id
/// @return Current device id as String
String current_device_id();
/// @brief Get Current artist names
/// @return Current artist names as String
String current_artist_names();
/// @brief Get Current device id
/// @param char array to store device id
/// @return Current device id as pointer to char array
char* current_device_id(char* device_id);
/// @brief Get Current track id
/// @param char array to store track id
/// @return Current track id as pointer to char array
char* current_track_id(char* track_id);
/// @brief Get Current track name
/// @param char array to store track name
/// @return Current track name as pointer to char array
char* current_track_name(char* track_name);
/// @brief Get Current artist names
/// @param char array to store artist names
/// @return Current artist names as pointer to char array
char* current_artist_names(char* artist_names);
/// @brief Get if device is playing
/// @return true if device is playing
bool is_playing();
/// @brief Get if it is possible to modify volume on current device
/// @return true if it is possible to modify volume on current device
bool volume_modifyable();
#endif
//String convert_id_to_uri(String id, String type);
/// @brief Convert ID to URI
/// @param id ID to convert
/// @param type Type of ID
/// @return URI as char
char convert_id_to_uri(char* id, char* type);
/// @brief Convert ID to URI
/// @param id ID to convert
/// @param type Type of ID
/// @param uri char array to store URI
/// @return URI as pointer to char array
char* convert_id_to_uri(char* id, char* type, char* uri);
private:
static const int _max_num_items = 20;//Number of items to be sent in one request
static const int _max_char_size = 35*_max_num_items + 150;// 35 beeing the size of a uri + comma + 150 as buffer for url etc.
/// @brief Maximum number of items in one request
static const int _max_num_items = 20;
/// @brief Maximum size of char array(35 been the size of a uri + comma + 150 as buffer for url etc.)
static const int _max_char_size = 35*_max_num_items + 150;
/// @brief Size of a uri
static const int _size_of_uri = 45;
/// @brief Size of an id
static const int _size_of_id = 25;
int _max_num_retry = 3;//Max number of retries for a request
/// @brief Maximum number of items in one request
int _max_num_retry = 3;
/// @brief Users refresh token
const char* _refresh_token;
/// @brief Users set redirect uri
const char* _redirect_uri;
/// @brief Users set client id
const char* _client_id;
/// @brief Users set client secret
const char* _client_secret;
/// @brief Current number of retries
int _retry;
/// @brief Debug mode
bool _debug_on;
String _access_token;
bool get_token();//Get access token
void init_response(response* response_obj);//Initialize response object
/// @brief Access token
String _access_token;
/// @brief Get Access Token with refresh token
/// @return Bool if token was successfully retrieved
bool get_token();
/// @brief Initialize response object
/// @param response_obj Response object to initialize
void init_response(response* response_obj);
/// @brief Make PUT request to Spotify API
/// @param rest_url URL to make request to
/// @param payload_size Size of payload
/// @param payload Payload to send
/// @return Response object containing http status code and reply
response RestApiPut(char* rest_url, int payload_size = 0, char* payload = nullptr);
/// @brief Make POST request to Spotify API
/// @param rest_url URL to make request to
/// @param payload_size Size of payload
/// @param payload Payload to send
/// @return Response object containing http status code and reply
response RestApiPost(char* rest_url, int payload_size = 0, char* payload = nullptr);
/// @brief Make DELETE request to Spotify API
/// @param rest_url URL to make request to
/// @param payload Payload to send
/// @return Response object containing http status code and reply
response RestApiDelete(char* rest_url, char* payload = nullptr);
/// @brief Make GET request to Spotify API
/// @param rest_url URL to make request to
/// @return Response object containing http status code and reply
response RestApiGet(char* rest_url);
char* array_to_char(int size, char** array, char* result);//Convert array of chars to one comma separated char
/// @brief Convert array of chars to one char array, seperated by comma
/// @param size Size of array
/// @param array Array to convert
/// @param result Array to store result
/// @return Pointer to result array
char* array_to_char(int size, char** array, char* result);
/// @brief Convert array of chars to one json array
/// @param size Size of array
/// @param array Array to convert
/// @param data Array to store result
/// @param data_size Size of data array
/// @return Pointer to data array
void array_to_json_array(int size, char** array, char* data, int data_size = _max_char_size);//Convert array of chars to one json array
#ifdef ENABLE_TRACKS
bool is_valid_value(float param);//Check if recommendation value is valid
bool is_valid_value(int param);//Check if recommendation value is valid
void populate_char_values(std::map<char*, char*>& map, recommendations& recom);//Populate recommendation char values
void populate_float_values(std::map<char*, float>& map, recommendations& recom);//Populate recommendation float values
/// @brief Check if recommendation value is valid
/// @param param Float value to check
/// @return Bool if value is valid
bool is_valid_value(float param);
/// @brief Check if recommendation value is valid
/// @param param Int value to check
/// @return Bool if value is valid
bool is_valid_value(int param);
/// @brief Populate recommendation char values
/// @param map Map to populate
/// @param recom recommendation object
/// @return Void
void populate_char_values(std::map<char*, char*>& map, recommendations& recom);
/// @brief Populate recommendation float values
/// @param map Map to populate
/// @param recom recommendation object
/// @return Void
void populate_float_values(std::map<char*, float>& map, recommendations& recom);
#endif
const char * extract_endpoint(const char* rest_url);//Extract endpoint from url with regex
/// @brief Extract endpoint from url with regex
const char * extract_endpoint(const char* rest_url);
/// @brief Root CA for Spotify API
const char* _spotify_root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \

396
main.cpp Normal file
View File

@@ -0,0 +1,396 @@
#include <WiFi.h>
#include <ArduinoJson.h>
#include <base64.h>
#include <UrlEncode.h>
#include "SpotifyESP32.h"
#include <Arduino.h>
const char* ssid = "Rebweg10D";
const char* password = "Bitte_eintreten";
const char* client_id = "fc0799459cf04f1aab6bb3f861964e77";
const char* client_secret = "9ca64f76f7b54ecdaf3ae78585ff8b0f";
const char* redirect_uri = "http://localhost:8080";
const char* refresh_token="AQAichrGMfjjDHYWIAENJYyWoi_KpzLZ93_HSS30J8zULeuHRPmF9-Wh3aSEd5ju8tloWGDZ9GJodjRH51PRUPvTqPg855b3fdmQ8JifmdNAEfSapfhkihTKKXveJxie00o";
using namespace Spotify_types;
Spotify sp(refresh_token, redirect_uri, client_id, client_secret, false);
char song_id[] = "2NTCi4wGypj56t843jb3Mt";
char* track_ids[] = {"7ouMYWpwJ422jRcDASZB7P","4VqPOruhp5EdPBeR92t6lQ","2takcwOaAZWiXQijPHIx7B"};
char album_id[] = "7iLuHJkrb9KHPkMgddYigh";
char* album_ids[] = {"7iLuHJkrb9KHPkMgddYigh","4KAtLRVIfB0bKnRY01dveY","2SxoeF005n621Jca66RRdu"};
char artist_id[] = "7orlzf5LTqSnCzURkZFebN";
char* artist_ids[] = {"7orlzf5LTqSnCzURkZFebN","0lNJF6sbrXXPubqKkkyK23","3JsMj0DEzyWc0VDlHuy9Bx"};
char audiobook_id[] = "7iHfbu1YPACw6oZPAFJtqe";
char* audiobook_ids[] = {"7iHfbu1YPACw6oZPAFJtqe","1HGw3J3NxZO1TP1BTtVhpZ","7iHfbu1YPACw6oZPAFJtqe"};
char chapter_id[] = "0IsXVP0JmcB2adSE338GkK";
char* chapter_ids[] = {"0IsXVP0JmcB2adSE338GkK","3ZXb8FKZGU0EHALYX6uCzU","0D5wENdkdwbqlrHoaJ9g29"};
char country[] = "CH";
char locale[] = "de_CH";
char category_id[] = "dinner";
char episode_id[] = "3UHFkXFDAHr7cBlRoUmdiY";
char* episode_ids[] = {"4H4ZXQ07SehfQDAImiHOXF","3UHFkXFDAHr7cBlRoUmdiY"};
char playlist_id[] = "5ZJAomiAtiow9nTloNl01E";
char fields[] = "items(track(name,href,album(name,href)))";
char* user_ids[] = {"adix3gjuq0g570rwufhfcw89o"};
char user_id[] = "adix3gjuq0g570rwufhfcw89o";
char show_id[] = "5CfCWKI5pZ28U0uOzXkDHe";
char* show_ids[] = {"5CfCWKI5pZ28U0uOzXkDHe","5as3aKmN2k11yfDDDSrvaZ"};
char* artist_user_ids[] = {"2CIMQHirSU0MQqyYHq0eOx","57dN52uHvrHOxijzpIgu3E","1vCWHaC5f2uS3yhpwWbIA6"};
void connectToWifi();
void test_player();
void test_albums();
void test_artist();
void test_audiobooks();
void test_chapters();
void test_categories();
void test_episodes();
void test_genres();
void test_markets();
void test_playlist();
void test_search();
void test_shows();
void test_tracks();
void test_users();
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");
}
//working
void test_player(){
Serial.print("Currently Playing: ");
print_response(sp.currently_playing());
char uri[SIZE_OF_URI];
Serial.print("Play track: ");
sp.convert_id_to_uri(song_id,TYPE_TRACK,uri);
char* uris[] = {uri,uri};
print_response(sp.start_resume_playback(2,uris));
Serial.print("Pause: ");
print_response(sp.pause_playback());
Serial.print("Play: ");
print_response(sp.start_resume_playback());
Serial.print("Skip: ");
print_response(sp.skip());
Serial.print("Previous: ");
print_response(sp.previous());
Serial.print("Available Devices: ");
print_response(sp.available_devices());
Serial.print("Playback state: ");
print_response(sp.current_playback_state());
Serial.print("Recently played: ");
print_response(sp.recently_played_tracks(1));
Serial.print("Seek to pos: ");
print_response(sp.seek_to_position(500));
Serial.print("Add to queue: ");
print_response(sp.add_to_queue(uri));
Serial.print("Get Queue: ");
print_response(sp.get_queue());
Serial.print("Repeat: ");
print_response(sp.repeat_mode(REPEAT_CONTEXT));
Serial.print("Shuffle off: ");
print_response(sp.shuffle(SHUFFLE_OFF));
char device_id[SIZE_OF_ID];
Serial.print("Transfer Playback: ");
print_response(sp.transfer_playback(sp.current_device_id(device_id)));
Serial.print("Set Volume: ");
print_response(sp.set_volume(50));
}
//working
void test_albums(){
Serial.print("Get Album: ");
print_response(sp.get_album(album_id));
Serial.print("Get Albums: ");
print_response(sp.get_albums(3,album_ids));
Serial.print("Get Album Tracks: ");
print_response(sp.get_album_tracks(album_id, 1, 0));
Serial.print("Get Saved Albums: ");
print_response(sp.get_users_saved_albums(1, 0));
Serial.print("Remove Saved Albums: ");
print_response(sp.remove_users_saved_albums(3,album_ids));
Serial.print("Save Albums: ");
print_response(sp.save_albums_for_current_user(3,album_ids));
Serial.print("Check if Album Saved: ");
print_response(sp.check_useres_saved_albums(3,album_ids));
Serial.print("Get Releases: ");
print_response(sp.get_new_releases(1, 0));
}
//working
void test_artist(){
Serial.print("Get Artist: ");
print_response(sp.get_artist(artist_id));
Serial.print("Get Artists: ");
print_response(sp.get_several_artists(3,artist_ids));
Serial.print("Get Artist Albums: ");
char* include_groups[] = {GROUP_ALBUM, GROUP_SINGLE};
print_response(sp.get_artist_albums(artist_id, 2, include_groups, 1, 0));
Serial.print("Get Artist top Tracks: ");
print_response(sp.get_artist_top_tracks(artist_id, country));
Serial.print("Get Artists related artists: ");
print_response(sp.get_artist_related_artist(artist_id));
}
//Working, only available in US, UK, New Zealand, Australia
void test_audiobooks(){
//400
Serial.print("Get Audibook: ");
print_response(sp.get_audiobook(audiobook_id));
Serial.print("Get Audibooks: ");
print_response(sp.get_several_audiobooks(3,audiobook_ids));
//500
Serial.print("Get Audibook Chapters: ");
print_response(sp.get_audiobook_chapters(audiobook_id, 1, 0));
//400
Serial.print("Get Users Audibooks: ");
print_response(sp.get_users_audiobooks(0, 1));
Serial.print("Save Audibook for user: ");
print_response(sp.save_audiobooks_for_current_user(3,audiobook_ids));
Serial.print("Check audiobooks: ");
print_response(sp.check_users_saved_audiobooks(3,audiobook_ids));
Serial.print("Remove Audiobooks: ");
print_response(sp.remove_audiobooks_for_current_user(3,audiobook_ids));
}
//Working, only available in US, UK, New Zealand, Australia
void test_chapters(){
Serial.print("get chapter: ");
print_response(sp.get_chapter(chapter_id));
Serial.print("get chapter: ");
print_response(sp.get_several_chapters(3,chapter_ids));
}
//working
void test_categories(){
Serial.print("get_several_browse_categories: ");
print_response(sp.get_several_browse_categories());
Serial.print("get_single_browse_category: ");
print_response(sp.get_single_browse_category(category_id, country, locale));
}
//working
void test_episodes(){
Serial.print("get_episode: ");
print_response(sp.get_episode(episode_id));
Serial.print("get_several_episodes: ");
print_response(sp.get_several_episodes(2,episode_ids));
Serial.print("get_users_saved_episodes: ");
print_response(sp.get_users_saved_episodes());
Serial.print("save_episodes_for_current_user: ");
print_response(sp.save_episodes_for_current_user(2,episode_ids));
Serial.print("check_users_saved_episodes: ");
print_response(sp.check_users_saved_episodes(2,episode_ids));
Serial.print("remove_episodes_for_current_user: ");
print_response(sp.remove_episodes_for_current_user(2,episode_ids));
}
//working
void test_genres(){
Serial.print("get_available_genre_seeds: ");
print_response(sp.get_available_genre_seeds());
}
//working
void test_markets(){
Serial.print("get_available_markets: ");
print_response(sp.get_available_markets());
}
//working
void test_playlist(){
Serial.print("get_playlist: ");
print_response(sp.get_playlist(playlist_id));
Serial.print("change_playlist_details: ");
print_response(sp.change_playlist_details(playlist_id, "Hello", false, false, "WTF!!"));
Serial.print("get_playlist_items: ");
print_response(sp.get_playlist_items(playlist_id, fields));
char* track_uri[SIZE_OF_URI];
sp.convert_id_to_uri(song_id,TYPE_TRACK,track_uri[0]);
Serial.print("update_playlist_items: ");
print_response(sp.update_playlist_items(playlist_id,1, track_uri, 1));
Serial.print("add_items_to_playlist: ");
print_response(sp.add_items_to_playlist(playlist_id,1, track_uri, 1));
Serial.print("remove_playlist_items: ");
print_response(sp.remove_playlist_items(playlist_id,1, track_uri));
Serial.print("get_current_users_playlists: ");
print_response(sp.get_current_users_playlists());
Serial.print("get_user_playlists: ");
print_response(sp.get_user_playlists(user_id));
Serial.print("create_playlist: ");
print_response(sp.create_playlist(user_id, "Test", true, false, "no"));
Serial.print("get_featured_playlists: ");
print_response(sp.get_featured_playlists());
Serial.print("get_category_playlists: ");
print_response(sp.get_category_playlists("dinner"));
Serial.print("get_playlist_cover_image: ");
print_response(sp.get_playlist_cover_image(playlist_id));
Serial.print("add_custom_playlist_cover_image: ");
print_response(sp.add_custom_playlist_cover_image(playlist_id, "/9j/2wCEABoZGSccJz4lJT5CLy8vQkc9Ozs9R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0cBHCcnMyYzPSYmPUc9Mj1HR0dEREdHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR//dAAQAAf/uAA5BZG9iZQBkwAAAAAH/wAARCAABAAEDACIAAREBAhEB/8QASwABAQAAAAAAAAAAAAAAAAAAAAYBAQAAAAAAAAAAAAAAAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAARAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwAAARECEQA/AJgAH//Z"));
}
//working
void test_search(){
Serial.print("search: ");
char* types[]= {TYPE_TRACK, TYPE_ALBUM};
print_response(sp.search("hello+world", 2, types));
}
//working
void test_shows(){
Serial.print("get_show: ");
print_response(sp.get_show(show_id));
Serial.print("get_several_shows: ");
print_response(sp.get_several_shows(2,show_ids));
Serial.print("get_show_episodes: ");
print_response(sp.get_show_episodes(show_id));
Serial.print("get_users_saved_shows: ");
print_response(sp.get_users_saved_shows());
Serial.print("save_shows_for_current_user: ");
print_response(sp.save_shows_for_current_user(2,show_ids));
Serial.print("check_users_saved_shows: ");
print_response(sp.check_users_saved_shows(2,show_ids));
Serial.print("remove_shows_for_current_user: ");
print_response(sp.remove_shows_for_current_user(2,show_ids));
}
//working
void test_tracks(){
Serial.print("get_track: ");
print_response(sp.get_track(song_id));
Serial.print("get_several_tracks: ");
print_response(sp.get_several_tracks(3,track_ids));
Serial.print("get_user_saved_tracks: ");
print_response(sp.get_user_saved_tracks());
Serial.print("save_tracks_for_current_user: ");
print_response(sp.save_tracks_for_current_user(3,track_ids));
Serial.print("remove_user_saved_tracks: ");
print_response(sp.remove_user_saved_tracks(3,track_ids));
Serial.print("check_user_saved_tracks: ");
print_response(sp.check_user_saved_tracks(3,track_ids));
Serial.print("get_tracks_audio_features: ");
print_response(sp.get_tracks_audio_features(3,track_ids));
Serial.print("get_track_audio_features: ");
print_response(sp.get_track_audio_features(song_id));
Serial.print("get_track_audio_analysis: ");
print_response(sp.get_track_audio_analysis(song_id));
char* track_seeds[] = {song_id};
recommendations recom;
recom.seed_tracks = track_seeds;
recom.seed_tracks_size = 1;
recom.max_energy = 0.5;
Serial.print("get_recommendations: ");
print_response(sp.get_recommendations(recom, 1));
}
//working
void test_users(){
Serial.print("get_current_user_profile: ");
print_response(sp.get_current_user_profile());
Serial.print("get_user_top_items: ");
print_response(sp.get_user_top_items(TOP_TYPE_ARTIST, TIME_RANGE_MEDIUM));
Serial.print("get_user_profile: ");
print_response(sp.get_user_profile(user_id));
Serial.print("follow_playlist: ");
print_response(sp.follow_playlist(playlist_id, true));
Serial.print("unfollow_playlist: ");
print_response(sp.unfollow_playlist(playlist_id));
Serial.print("get_followed_artists: ");
print_response(sp.get_followed_artists(""));
Serial.print("follow_artists_or_users: ");
print_response(sp.follow_artists_or_users(TYPE_ARTIST, 3,artist_user_ids));
Serial.print("unfollow_artists_or_users: ");
print_response(sp.unfollow_artists_or_users(TYPE_ARTIST, 3,artist_user_ids));
Serial.print("check_if_user_follows_artists_or_users: ");
print_response(sp.check_if_user_follows_artists_or_users(TYPE_ARTIST,3, artist_user_ids));
Serial.print("check_if_users_follow_playlist: ");
print_response(sp.check_if_users_follow_playlist(playlist_id, 3, user_ids));
}
void setup() {
Serial.begin(115200);
connectToWifi();
test_player();
}
void loop() {
// put your main code here, to run repeatedly:
}