From 044042d436a05ac8aab5ec1e94bda38ca07073d3 Mon Sep 17 00:00:00 2001 From: Finian Landes Date: Tue, 2 Jan 2024 12:07:00 +0100 Subject: [PATCH] Added some Doxy comments, Version Unstable --- SpotifyESP32.cpp | 1355 +++++++++++++++++++++------------------- SpotifyESP32.h | 320 +++++++--- Spotify_Esp32_test.ino | 29 +- 3 files changed, 934 insertions(+), 770 deletions(-) diff --git a/SpotifyESP32.cpp b/SpotifyESP32.cpp index a20e316..da47f4a 100644 --- a/SpotifyESP32.cpp +++ b/SpotifyESP32.cpp @@ -22,22 +22,8 @@ namespace Spotify_types{ int SIZE_OF_ID = 40; int SIZE_OF_URI = 50; } -Spotify::Spotify(const char* refresh_token, const char* redirect_uri, const char* client_id,const char* client_secret){ - _retry = 0; - _refresh_token = refresh_token; - _redirect_uri = redirect_uri; - _client_id = client_id; - _client_secret = client_secret; - _debug_on = false; -} -Spotify::Spotify(const char* refresh_token, const char* redirect_uri, const char* client_id,const 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; -} + + 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; @@ -257,7 +243,7 @@ bool Spotify::get_token(){ } if ((http_code >=200)&&(http_code<=299)) { String response = http.getString(); - DynamicJsonDocument doc(1024); + StaticJsonDocument<500> doc; deserializeJson(doc, response); _access_token = doc["access_token"].as(); reply = true; @@ -272,8 +258,7 @@ void Spotify::init_response(response* response_obj){ response_obj -> status_code = -1; response_obj -> reply ="If you see this something went wrong"; } -char* Spotify::array_to_char(int size, char** array) { - char result[_max_char_size]; +char* Spotify::array_to_char(int size, char** array, char* result) { result[0] = '\0'; for (int i = 0; i < size; ++i) { strcat(result, array[i]); @@ -293,6 +278,658 @@ void Spotify::array_to_json_array(int size,char** array, char* data, int data_si serializeJson(json_array,data,data_size); } + +const char* Spotify::extract_endpoint(const char* url){ + std::regex pattern(R"(https://api\.spotify\.com/v1/([^?]+))"); + + std::cmatch match; + if (std::regex_search(url, match, pattern)) { + return match[1].str().c_str(); + } + + return nullptr; +} +//API functions +//Player +#ifdef ENABLE_PLAYER +response Spotify::currently_playing(){ + char url[] = "https://api.spotify.com/v1/me/player/currently-playing"; + return RestApiGet(url); +} +response Spotify::current_playback_state(){ + char url[] = "https://api.spotify.com/v1/me/player"; + return RestApiGet(url); +} +response Spotify::start_resume_playback(char* context_uri, int offset, int position_ms, char* device_id){ + char url[] = "https://api.spotify.com/v1/me/player/play"; + if(device_id != nullptr){ + sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); + } + char payload[_max_char_size]; + int payload_size = 0; + if(context_uri != nullptr){ + if (strncmp(context_uri, "spotify:track:", 14) == 0) { + sprintf(payload, "{\"uris\":[\"%s\"]}", context_uri); + + } else { + sprintf(payload, "{\"context_uri\":\"%s\",\"offset\":{\"position\":%d},\"position_ms\":%d}",context_uri, offset, position_ms); + } + payload_size = strlen(payload); + } + else{ + payload_size = 0; + payload[0] = '\0'; + } + + return RestApiPut(url, payload_size, payload); +} +response Spotify::start_resume_playback(int size, char** uris, char* device_id){ + char url[] = "https://api.spotify.com/v1/me/player/play"; + if(device_id != nullptr){ + sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); + } + char payload[_max_char_size]; + int payload_size = 0; + char arr[_max_char_size]; + array_to_json_array(size, uris, arr); + sprintf(payload, "{\"uris\":%s}", arr); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::start_resume_playback(char* device_id){ + char url[100]; + if(device_id != nullptr){ + sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); + } + else{ + sprintf(url, "https://api.spotify.com/v1/me/player/play"); + } + + return RestApiPut(url); +} +response Spotify::pause_playback(){ + char url[] = "https://api.spotify.com/v1/me/player/pause"; + + return RestApiPut(url); +} +response Spotify::skip(){ + char url[] = "https://api.spotify.com/v1/me/player/next"; + + return RestApiPost(url); +} +response Spotify::previous(){ + char url[] = "https://api.spotify.com/v1/me/player/previous"; + + return RestApiPost(url); +} +response Spotify::available_devices(){ + char url[] = "https://api.spotify.com/v1/me/player/devices"; + + return RestApiGet(url); +} +response Spotify::recently_played_tracks(int limit){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/recently-played?limit=%d", limit); + + return RestApiGet(url); +} +response Spotify::get_queue(){ + char url[] = "https://api.spotify.com/v1/me/player/queue"; + + return RestApiGet(url); +} +response Spotify::transfer_playback(char* device_id){ + char url[] = "https://api.spotify.com/v1/me/player"; + char payload[100]; + int payload_size = 0; + sprintf(payload, "{\"device_ids\":[\"%s\"]}", device_id); + payload_size = strlen(payload); + return RestApiPut(url,payload_size, payload); +} +response Spotify::seek_to_position(int time_ms){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/seek?position_ms=%d", time_ms); + + return RestApiPut(url); +} +response Spotify::repeat_mode(char* mode){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/repeat?state=%s", mode); + + return RestApiPut(url); +} +response Spotify::set_volume(int value){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/volume?volume_percent=%d", value); + + return RestApiPut(url); +} +response Spotify::shuffle(bool mode){ + char state[6]; + sprintf(state, "%s", mode ? "true" : "false"); + + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/shuffle?state=%s", state); + + return RestApiPut(url); +} +response Spotify::add_to_queue(char* context_uri){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/player/queue?uri=%s", context_uri); + + return RestApiPost(url); +} +#endif +#ifdef ENABLE_ALBUM +//Albums +response Spotify::get_album(char* album_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/albums/%s", album_id); + + return RestApiGet(url); +} +response Spotify::get_albums(int size, char ** album_ids){ + char url[_max_char_size]; + char arr[_max_char_size]; + sprintf(url, "https://api.spotify.com/v1/albums?ids=%s", array_to_char(size, album_ids,arr)); + + return RestApiGet(url); +} +response Spotify::get_album_tracks(char* album_id, int limit, int offset){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/albums/%s/tracks?limit=%d&offset=%d", album_id, limit, offset); + + return RestApiGet(url); +} +response Spotify::get_users_saved_albums(int limit, int offset){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/albums?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +response Spotify::save_albums_for_current_user(int size, char ** album_ids){ + char url[] = "https://api.spotify.com/v1/me/albums"; + char payload[_max_char_size]; + int payload_size = 0; + array_to_json_array(size, album_ids, payload); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::remove_users_saved_albums(int size,char ** album_ids){ + char url[] = "https://api.spotify.com/v1/me/albums"; + char payload[_max_char_size]; + array_to_json_array(size, album_ids, payload); + + return RestApiDelete(url, payload); +} +response Spotify::check_useres_saved_albums(int size,char ** album_ids){ + char url[_max_char_size]; + char arr[_max_char_size]; + sprintf(url, "https://api.spotify.com/v1/me/albums/contains?ids=%s", array_to_char(size, album_ids, arr)); + + return RestApiGet(url); +} +response Spotify::get_new_releases(int limit, int offset, char* country){ + char url[120]; + if(country == nullptr){ + sprintf(url, "https://api.spotify.com/v1/browse/new-releases?limit=%d&offset=%d", limit, offset); + } + else{ + sprintf(url, "https://api.spotify.com/v1/browse/new-releases?country=%s&limit=%d&offset=%d", country, limit, offset); + } + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_ARTIST +//Artists +response Spotify::get_artist(char* artist_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/artists/%s", artist_id); + + return RestApiGet(url); +} +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)); + + 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); + + return RestApiGet(url); +} +response Spotify::get_artist_top_tracks(char* artist_id, char* country){ + char url[100]; + if(country == nullptr){ + sprintf(url, "https://api.spotify.com/v1/artists/%s/top-tracks", artist_id); + } + else{ + sprintf(url, "https://api.spotify.com/v1/artists/%s/top-tracks?country=%s", artist_id, country); + } + + return RestApiGet(url); +} +response Spotify::get_artist_related_artist(char* artist_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/artists/%s/related-artists", artist_id); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_AUDIOBOOKS +//Audiobooks +response Spotify::get_audiobook(char* audiobook_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/audiobooks/%s", audiobook_id); + + return RestApiGet(url); +} +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)); + + return RestApiGet(url); +} +response Spotify::get_audiobook_chapters(char* audiobook_id, int limit, int offset){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/audiobooks/%s/chapters?limit=%d&offset=%d", audiobook_id, limit, offset); + + return RestApiGet(url); +} +response Spotify::get_users_audiobooks(int limit, int offset){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/audiobooks?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +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)); + + 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)); + + 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)); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_CATEGORIES +//Categories +response Spotify::get_several_browse_categories(char* country, char* locale, int limit, int offset){ + char url[200]; + 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); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_CHAPTERS +//Chapters +response Spotify::get_chapter(char* chapter_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/chapters/%s", chapter_id); + + return RestApiGet(url); +} +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)); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_EPISODES +//Episodes +response Spotify::get_episode(char* episode_id){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/episodes/%s", episode_id); + + return RestApiGet(url); +} +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)); + + return RestApiGet(url); +} +response Spotify::get_users_saved_episodes(int limit, int offset){ + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/episodes?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +response Spotify::save_episodes_for_current_user(int size,char** episode_ids){ + char url[] = "https://api.spotify.com/v1/me/episodes"; + char payload[_max_char_size]; + int payload_size = 0; + array_to_json_array(size, episode_ids, payload); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::remove_episodes_for_current_user(int size,char** episode_ids){ + char url[] = "https://api.spotify.com/v1/me/episodes"; + char payload[_max_char_size]; + array_to_json_array(size, episode_ids, payload); + + return RestApiDelete(url, payload); +} +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)); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_GENRES +//Genres +response Spotify::get_available_genre_seeds(){ + char url[] = "https://api.spotify.com/v1/recommendations/available-genre-seeds"; + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_MARKETS +//Markets +response Spotify::get_available_markets(){ + char url[] = "https://api.spotify.com/v1/markets"; + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_PLAYLISTS +//Playlist +response Spotify::get_playlist(char* playlist_id, char* fields) { + char url[200]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s?fields=%s", playlist_id, fields); + + return RestApiGet(url); +} +response Spotify::change_playlist_details(char* playlist_id, char* name, bool is_public, bool is_collaborative, char* description) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s", playlist_id); + + DynamicJsonDocument doc(400); + if (is_public && is_collaborative){ + is_collaborative = false; + } + doc["collaborative"] = is_collaborative; + doc["name"] = name; + doc["public"] = is_public; + doc["description"] = description; + + char payload[200]; + int payload_size = 0; + serializeJson(doc, payload); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::get_playlist_items(char* playlist_id, char* fields, int limit, int offset) { + char url[200]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks?fields=%s&limit=%d&offset=%d", playlist_id, fields, limit, offset); + + return RestApiGet(url); +} +response Spotify::update_playlist_items(char* playlist_id,int size, char** uris, int range_length, int range_start, int insert_before) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks", playlist_id); + + DynamicJsonDocument doc(_max_char_size); + char arr[_max_char_size]; + array_to_json_array(size, uris, arr); + doc["uris"] = arr; + doc["range_start"] = range_start; + doc["insert_before"] = insert_before; + doc["range_length"] = range_length; + + char payload[_max_char_size]; + int payload_size = 0; + serializeJson(doc, payload); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::add_items_to_playlist(char* playlist_id, int size, char ** uris, int position) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks", playlist_id); + + DynamicJsonDocument doc(1000); + char arr[_max_char_size]; + array_to_json_array(size, uris, arr); + doc["uris"] = arr; + doc["position"] = position; + + char payload[_max_char_size]; + int payload_size = 0; + serializeJson(doc, payload); + payload_size = strlen(payload); + + return RestApiPost(url, payload_size, payload); +} +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); + + + return RestApiDelete(url, payload); +} +response Spotify::get_current_users_playlists(int limit, int offset) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/playlists?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +response Spotify::get_user_playlists(char* user_id, int limit, int offset) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/users/%s/playlists?limit=%d&offset=%d", user_id, limit, offset); + + return RestApiGet(url); +} +response Spotify::create_playlist(char* user_id, char* name, bool is_public, bool is_collaborative, char* description) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/users/%s/playlists", user_id); + + if (is_public && is_collaborative){ + is_collaborative = false; + } + + DynamicJsonDocument doc(256); + doc["name"] = name; + doc["public"] = is_public; + doc["collaborative"] = is_collaborative; + doc["description"] = description; + char payload[256]; + int payload_size = 0; + serializeJson(doc, payload); + payload_size = strlen(payload); + + return RestApiPost(url, payload_size, payload); +} +response Spotify::get_featured_playlists(char* country, char* locale, char* timestamp, int limit, int offset) { + char url[200]; + sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&locale=%s×tamp=%s&limit=%d&offset=%d", country, locale, timestamp, limit, offset); + + return RestApiGet(url); +} +response Spotify::get_category_playlists(char* category_id, char* country, int limit, int offset) { + 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); + + return RestApiGet(url); +} +response Spotify::get_playlist_cover_image(char* playlist_id) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s/images", playlist_id); + + return RestApiGet(url); +} +response Spotify::add_custom_playlist_cover_image(char* playlist_id, char* data) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/playlists/%s/images", playlist_id); + int payload_size = strlen(data); + + return RestApiPut(url, payload_size, data); +} +#endif +#ifdef ENABLE_SEARCH +//Search +response Spotify::search(char* q, char* type, int limit, int offset){ + 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); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_SHOWS +//Shows +response Spotify::get_show(char* show_id) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/shows/%s", show_id); + + return RestApiGet(url); +} +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)); + + return RestApiGet(url); +} +response Spotify::get_show_episodes(char* show_id, int limit, int offset) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/shows/%s/episodes?limit=%d&offset=%d", show_id, limit, offset); + + return RestApiGet(url); +} +response Spotify::get_users_saved_shows(int limit, int offset) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/shows?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +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)); + + 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)); + + 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)); + + return RestApiGet(url); +} +#endif +#ifdef ENABLE_TRACKS +//Tracks +response Spotify::get_track(char* track_id) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/tracks/%s", track_id); + + return RestApiGet(url); +} +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)); + + return RestApiGet(url); +} +response Spotify::get_user_saved_tracks(int limit, int offset) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/me/tracks?limit=%d&offset=%d", limit, offset); + + return RestApiGet(url); +} +response Spotify::save_tracks_for_current_user(int size,char ** track_ids) { + char url[] = "https://api.spotify.com/v1/me/tracks"; + char payload[_max_char_size]; + int payload_size = 0; + array_to_json_array(size, track_ids, payload); + payload_size = strlen(payload); + + return RestApiPut(url, payload_size, payload); +} +response Spotify::remove_user_saved_tracks(int size,char ** track_ids) { + char url[] = "https://api.spotify.com/v1/me/tracks"; + char payload[_max_char_size]; + array_to_json_array(size, track_ids, payload); + + return RestApiDelete(url, payload); +} +response Spotify::check_user_saved_tracks(int size,char ** track_ids) { + char url[_max_char_size]; + char arr[_max_char_size]; + sprintf(url, "https://api.spotify.com/v1/me/tracks/contains?ids=%s", array_to_char(size, track_ids, arr)); + + return RestApiGet(url); +} +response Spotify::get_tracks_audio_features(int size,char ** track_ids) { + char url[_max_char_size]; + char arr[_max_char_size]; + sprintf(url, "https://api.spotify.com/v1/audio-features?ids=%s", array_to_char(size, track_ids, arr)); + + return RestApiGet(url); +} +response Spotify::get_track_audio_features(char* track_id) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/audio-features/%s", track_id); + + return RestApiGet(url); +} +response Spotify::get_track_audio_analysis(char* track_id) { + char url[100]; + sprintf(url, "https://api.spotify.com/v1/audio-analysis/%s", track_id); + + return RestApiGet(url); +} +response Spotify::get_recommendations(recommendations& recom, int limit){ + char url[2000]; + sprintf(url, "https://api.spotify.com/v1/recommendations?limit=%d", limit); + + std::map char_params; + std::map float_params; + populate_float_values(float_params, recom); + populate_char_values(char_params, recom); + + for (const auto& param : char_params) { + char value[100]; + sprintf(value, "&%s%s",param.first, param.second); + strcat(url, value); + } + for(const auto& param : float_params){ + char value[100]; + sprintf(value, "&%s=%f",param.first, param.second); + strcat(url, value); + } + + return RestApiGet(url); +} bool Spotify::is_valid_value(float param) { return param >= 0.0 && param <= 1.0; } @@ -441,642 +1078,19 @@ void Spotify::populate_float_values(std::map& float_params, recomm } } void Spotify::populate_char_values(std::map& char_params, recommendations& recom){ + char arr[_max_char_size]; if(is_valid_value(recom.seed_artists_size)){ - char_params["seed_artists"] = array_to_char(recom.seed_artists_size, recom.seed_artists); + char_params["seed_artists"] = array_to_char(recom.seed_artists_size, recom.seed_artists, arr); } if(is_valid_value(recom.seed_genres_size)){ - char_params["seed_genres"] = array_to_char(recom.seed_genres_size, recom.seed_genres); + char_params["seed_genres"] = array_to_char(recom.seed_genres_size, recom.seed_genres, arr); } if(is_valid_value(recom.seed_tracks_size)){ - char_params["seed_tracks"] = array_to_char(recom.seed_tracks_size, recom.seed_tracks); + char_params["seed_tracks"] = array_to_char(recom.seed_tracks_size, recom.seed_tracks,arr); } } -const char* Spotify::extract_endpoint(char* url){ - std::regex pattern(R"(https://api\.spotify\.com/v1/([^/?]+))"); - - std::cmatch match; - if (std::regex_search(url, match, pattern)) { - return match[1].str().c_str(); - } - - return nullptr; -} -//API functions -//Player -response Spotify::currently_playing(){ - char url[] = "https://api.spotify.com/v1/me/player/currently-playing"; - return RestApiGet(url); -} -response Spotify::current_playback_state(){ - char url[] = "https://api.spotify.com/v1/me/player"; - return RestApiGet(url); -} -response Spotify::start_resume_playback(char* context_uri, int offset, int position_ms, char* device_id){ - char url[] = "https://api.spotify.com/v1/me/player/play"; - if(device_id != nullptr){ - sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); - } - char payload[_max_char_size]; - int payload_size = 0; - if(context_uri != nullptr){ - if (strncmp(context_uri, "spotify:track:", 14) == 0) { - sprintf(payload, "{\"uris\":[\"%s\"]}", context_uri); - - } else { - sprintf(payload, "{\"context_uri\":\"%s\",\"offset\":{\"position\":%d},\"position_ms\":%d}",context_uri, offset, position_ms); - } - payload_size = strlen(payload); - } - else{ - payload_size = 0; - payload[0] = '\0'; - } - - return RestApiPut(url, payload_size, payload); -} -response Spotify::start_resume_playback(int size, char** uris, char* device_id){ - char url[] = "https://api.spotify.com/v1/me/player/play"; - if(device_id != nullptr){ - sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); - } - char payload[_max_char_size]; - int payload_size = 0; - char arr[_max_char_size]; - array_to_json_array(size, uris, arr); - sprintf(payload, "{\"uris\":%s}", arr); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::start_resume_playback(char* device_id){ - char url[100]; - if(device_id != nullptr){ - sprintf(url, "https://api.spotify.com/v1/me/player/play?device_id=%s", device_id); - } - else{ - sprintf(url, "https://api.spotify.com/v1/me/player/play"); - } - - return RestApiPut(url); -} -response Spotify::pause_playback(){ - char url[] = "https://api.spotify.com/v1/me/player/pause"; - - return RestApiPut(url); -} -response Spotify::skip(){ - char url[] = "https://api.spotify.com/v1/me/player/next"; - - return RestApiPost(url); -} -response Spotify::previous(){ - char url[] = "https://api.spotify.com/v1/me/player/previous"; - - return RestApiPost(url); -} -response Spotify::available_devices(){ - char url[] = "https://api.spotify.com/v1/me/player/devices"; - - return RestApiGet(url); -} -response Spotify::recently_played_tracks(int limit){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/recently-played?limit=%d", limit); - - return RestApiGet(url); -} -response Spotify::get_queue(){ - char url[] = "https://api.spotify.com/v1/me/player/queue"; - - return RestApiGet(url); -} -response Spotify::transfer_playback(char* device_id){ - char url[] = "https://api.spotify.com/v1/me/player"; - char payload[100]; - int payload_size = 0; - sprintf(payload, "{\"device_ids\":[\"%s\"]}", device_id); - payload_size = strlen(payload); - return RestApiPut(url,payload_size, payload); -} -response Spotify::seek_to_position(int time_ms){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/seek?position_ms=%d", time_ms); - - return RestApiPut(url); -} -response Spotify::repeat_mode(char* mode){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/repeat?state=%s", mode); - - return RestApiPut(url); -} -response Spotify::set_volume(int value){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/volume?volume_percent=%d", value); - - return RestApiPut(url); -} -response Spotify::shuffle(bool mode){ - char state[6]; - sprintf(state, "%s", mode ? "true" : "false"); - - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/shuffle?state=%s", state); - - return RestApiPut(url); -} -response Spotify::add_to_queue(char* context_uri){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/player/queue?uri=%s", context_uri); - - return RestApiPost(url); -} - -//Albums -response Spotify::get_album(char* album_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/albums/%s", album_id); - - return RestApiGet(url); -} -response Spotify::get_albums(int size, char ** album_ids){ - char url[_max_char_size]; - sprintf(url, "https://api.spotify.com/v1/albums?ids=%s", array_to_char(size, album_ids)); - Serial.println(url); - - return RestApiGet(url); -} -response Spotify::get_album_tracks(char* album_id, int limit, int offset){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/albums/%s/tracks?limit=%d&offset=%d", album_id, limit, offset); - - return RestApiGet(url); -} -response Spotify::get_users_saved_albums(int limit, int offset){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/albums?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -response Spotify::save_albums_for_current_user(int size, char ** album_ids){ - char url[] = "https://api.spotify.com/v1/me/albums"; - char payload[_max_char_size]; - int payload_size = 0; - array_to_json_array(size, album_ids, payload); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::remove_users_saved_albums(int size,char ** album_ids){ - char url[] = "https://api.spotify.com/v1/me/albums"; - char payload[_max_char_size]; - array_to_json_array(size, album_ids, payload); - - return RestApiDelete(url, payload); -} -response Spotify::check_useres_saved_albums(int size,char ** album_ids){ - char url[_max_char_size]; - sprintf(url, "https://api.spotify.com/v1/me/albums/contains?ids=%s", array_to_char(size, album_ids)); - - return RestApiGet(url); -} -response Spotify::get_new_releases(char* country, int limit, int offset){ - char url[120]; - sprintf(url, "https://api.spotify.com/v1/browse/new-releases?country=%s&limit=%d&offset=%d", country, limit, offset); - - return RestApiGet(url); -} - -//Artists -response Spotify::get_artist(char* artist_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/artists/%s", artist_id); - - return RestApiGet(url); -} -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)); - - 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); - - return RestApiGet(url); -} -response Spotify::get_artist_top_tracks(char* artist_id, char* country){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/artists/%s/top-tracks?country=%s", artist_id, country); - - return RestApiGet(url); -} -response Spotify::get_artist_related_artist(char* artist_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/artists/%s/related-artists", artist_id); - - return RestApiGet(url); -} - -//Audiobooks -response Spotify::get_audiobook(char* audiobook_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/audiobooks/%s", audiobook_id); - - return RestApiGet(url); -} -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)); - - return RestApiGet(url); -} -response Spotify::get_audiobook_chapters(char* audiobook_id, int limit, int offset){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/audiobooks/%s/chapters?limit=%d&offset=%d", audiobook_id, limit, offset); - - return RestApiGet(url); -} -response Spotify::get_users_audiobooks(int limit, int offset){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/audiobooks?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -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)); - - 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)); - - 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)); - - return RestApiGet(url); -} - -//Categories -response Spotify::get_several_browse_categories(char* country, char* locale, int limit, int offset){ - char url[200]; - 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); - - return RestApiGet(url); -} - -//Chapters -response Spotify::get_chapter(char* chapter_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/chapters/%s", chapter_id); - - return RestApiGet(url); -} -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)); - - return RestApiGet(url); -} - -//Episodes -response Spotify::get_episode(char* episode_id){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/episodes/%s", episode_id); - - return RestApiGet(url); -} -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)); - - return RestApiGet(url); -} -response Spotify::get_users_saved_episodes(int limit, int offset){ - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/episodes?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -response Spotify::save_episodes_for_current_user(int size,char** episode_ids){ - char url[] = "https://api.spotify.com/v1/me/episodes"; - char payload[_max_char_size]; - int payload_size = 0; - array_to_json_array(size, episode_ids, payload); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::remove_episodes_for_current_user(int size,char** episode_ids){ - char url[] = "https://api.spotify.com/v1/me/episodes"; - char payload[_max_char_size]; - array_to_json_array(size, episode_ids, payload); - - return RestApiDelete(url, payload); -} -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)); - - return RestApiGet(url); -} - -//Genres -response Spotify::get_available_genre_seeds(){ - char url[] = "https://api.spotify.com/v1/recommendations/available-genre-seeds"; - - return RestApiGet(url); -} - -//Markets -response Spotify::get_available_markets(){ - char url[] = "https://api.spotify.com/v1/markets"; - - return RestApiGet(url); -} - -//Playlist -response Spotify::get_playlist(char* playlist_id, char* fields) { - char url[200]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s?fields=%s", playlist_id, fields); - - return RestApiGet(url); -} -response Spotify::change_playlist_details(char* playlist_id, char* name, bool is_public, bool is_collaborative, char* description) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s", playlist_id); - - DynamicJsonDocument doc(400); - if (is_public && is_collaborative){ - is_collaborative = false; - } - doc["collaborative"] = is_collaborative; - doc["name"] = name; - doc["public"] = is_public; - doc["description"] = description; - - char payload[200]; - int payload_size = 0; - serializeJson(doc, payload); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::get_playlist_items(char* playlist_id, char* fields, int limit, int offset) { - char url[200]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks?fields=%s&limit=%d&offset=%d", playlist_id, fields, limit, offset); - - return RestApiGet(url); -} -response Spotify::update_playlist_items(char* playlist_id,int size, char** uris, int range_length, int range_start, int insert_before) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks", playlist_id); - - DynamicJsonDocument doc(_max_char_size); - char arr[_max_char_size]; - array_to_json_array(size, uris, arr); - doc["uris"] = arr; - doc["range_start"] = range_start; - doc["insert_before"] = insert_before; - doc["range_length"] = range_length; - - char payload[_max_char_size]; - int payload_size = 0; - serializeJson(doc, payload); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::add_items_to_playlist(char* playlist_id, int size, char ** uris, int position) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s/tracks", playlist_id); - - DynamicJsonDocument doc(1000); - char arr[_max_char_size]; - array_to_json_array(size, uris, arr); - doc["uris"] = arr; - doc["position"] = position; - - char payload[_max_char_size]; - int payload_size = 0; - serializeJson(doc, payload); - payload_size = strlen(payload); - - return RestApiPost(url, payload_size, payload); -} -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); - - - return RestApiDelete(url, payload); -} -response Spotify::get_current_users_playlists(int limit, int offset) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/playlists?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -response Spotify::get_user_playlists(char* user_id, int limit, int offset) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/users/%s/playlists?limit=%d&offset=%d", user_id, limit, offset); - - return RestApiGet(url); -} -response Spotify::create_playlist(char* user_id, char* name, bool is_public, bool is_collaborative, char* description) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/users/%s/playlists", user_id); - - if (is_public && is_collaborative){ - is_collaborative = false; - } - - DynamicJsonDocument doc(256); - doc["name"] = name; - doc["public"] = is_public; - doc["collaborative"] = is_collaborative; - doc["description"] = description; - char payload[256]; - int payload_size = 0; - serializeJson(doc, payload); - payload_size = strlen(payload); - - return RestApiPost(url, payload_size, payload); -} -response Spotify::get_featured_playlists(char* country, char* locale, char* timestamp, int limit, int offset) { - char url[200]; - sprintf(url, "https://api.spotify.com/v1/browse/featured-playlists?country=%s&locale=%s×tamp=%s&limit=%d&offset=%d", country, locale, timestamp, limit, offset); - - return RestApiGet(url); -} -response Spotify::get_category_playlists(char* category_id, char* country, int limit, int offset) { - 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); - - return RestApiGet(url); -} -response Spotify::get_playlist_cover_image(char* playlist_id) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s/images", playlist_id); - - return RestApiGet(url); -} -response Spotify::add_custom_playlist_cover_image(char* playlist_id, char* data) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/playlists/%s/images", playlist_id); - int payload_size = strlen(data); - - return RestApiPut(url, payload_size, data); -} - -//Search -response Spotify::search(char* q, char* type, int limit, int offset){ - 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); - - return RestApiGet(url); -} - -//Shows -response Spotify::get_show(char* show_id) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/shows/%s", show_id); - - return RestApiGet(url); -} -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)); - - return RestApiGet(url); -} -response Spotify::get_show_episodes(char* show_id, int limit, int offset) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/shows/%s/episodes?limit=%d&offset=%d", show_id, limit, offset); - - return RestApiGet(url); -} -response Spotify::get_users_saved_shows(int limit, int offset) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/shows?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -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)); - - 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)); - - 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)); - - return RestApiGet(url); -} - -//Tracks -response Spotify::get_track(char* track_id) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/tracks/%s", track_id); - - return RestApiGet(url); -} -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)); - - return RestApiGet(url); -} -response Spotify::get_user_saved_tracks(int limit, int offset) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/me/tracks?limit=%d&offset=%d", limit, offset); - - return RestApiGet(url); -} -response Spotify::save_tracks_for_current_user(int size,char ** track_ids) { - char url[] = "https://api.spotify.com/v1/me/tracks"; - char payload[_max_char_size]; - int payload_size = 0; - array_to_json_array(size, track_ids, payload); - payload_size = strlen(payload); - - return RestApiPut(url, payload_size, payload); -} -response Spotify::remove_user_saved_tracks(int size,char ** track_ids) { - char url[] = "https://api.spotify.com/v1/me/tracks"; - char payload[_max_char_size]; - array_to_json_array(size, track_ids, payload); - - return RestApiDelete(url, payload); -} -response Spotify::check_user_saved_tracks(int size,char ** track_ids) { - char url[_max_char_size]; - sprintf(url, "https://api.spotify.com/v1/me/tracks/contains?ids=%s", array_to_char(size, track_ids)); - - return RestApiGet(url); -} -response Spotify::get_tracks_audio_features(int size,char ** track_ids) { - char url[_max_char_size]; - sprintf(url, "https://api.spotify.com/v1/audio-features?ids=%s", array_to_char(size, track_ids)); - - return RestApiGet(url); -} -response Spotify::get_track_audio_features(char* track_id) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/audio-features/%s", track_id); - - return RestApiGet(url); -} -response Spotify::get_track_audio_analysis(char* track_id) { - char url[100]; - sprintf(url, "https://api.spotify.com/v1/audio-analysis/%s", track_id); - - return RestApiGet(url); -} -response Spotify::get_recommendations(recommendations& recom, int limit){ - char url[2000]; - sprintf(url, "https://api.spotify.com/v1/recommendations?limit=%d", limit); - - std::map char_params; - std::map float_params; - populate_float_values(float_params, recom); - populate_char_values(char_params, recom); - - for (const auto& param : char_params) { - char value[100]; - sprintf(value, "&%s%s",param.first, param.second); - strcat(url, value); - } - for(const auto& param : float_params){ - char value[100]; - sprintf(value, "&%s=%f",param.first, param.second); - strcat(url, value); - } - - return RestApiGet(url); -} - +#endif +#ifdef ENABLE_USER //Users response Spotify::get_current_user_profile() { char url[] = "https://api.spotify.com/v1/me"; @@ -1147,7 +1161,8 @@ response Spotify::check_if_users_follow_playlist(char* playlist_id,int size, cha return RestApiGet(url); } - +#endif +#ifdef ENABLE_SIMPIFIED //Simplified functions, formatting functions String Spotify::current_track_name(){ String track_name = "Something went wrong"; @@ -1224,6 +1239,41 @@ char* Spotify::current_device_id(char * device_id){ } return device_id; } +char* Spotify::current_track_name(char * track_name){ + response data = currently_playing(); + if((data.status_code>=200)&&(data.status_code<=299)){ + DynamicJsonDocument doc(10000); + deserializeJson(doc,data.reply); + sprintf(track_name, "%s", doc["item"]["name"].as().c_str()); + } + return track_name; +} +char* Spotify::current_track_id(char * track_id){ + response data = currently_playing(); + if((data.status_code>=200)&&(data.status_code<=299)){ + DynamicJsonDocument doc(10000); + deserializeJson(doc,data.reply); + sprintf(track_id, "%s", doc["item"]["id"].as().c_str()); + } + return track_id; +} +char* Spotify::current_artist_names(char * artist_names){ + 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[0] = '\0'; + for (int i = 0; i().c_str()); + if (i #include @@ -9,29 +25,35 @@ #include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + + namespace Spotify_types{ - extern bool SHUFFLE_ON;//Shuffle on - extern bool SHUFFLE_OFF;//Shuffle off - extern char* REPEAT_OFF;//Repeat off - extern char* REPEAT_TRACK;//Repeat track - extern char* REPEAT_CONTEXT;//Repeat context - extern char* TYPE_ALBUM;//URI type album - extern char* TYPE_ARTIST;//URI type artist - extern char* TYPE_TRACK;//URI type track - extern char* TYPE_PLAYLIST;//URI type playlist - extern char* GROUP_ALBUM;//Get artist's albums include groups album - extern char* GROUP_SINGLE;//Get artist's albums include groups single - extern char* GROUP_APPEARS_ON;//Get artist's albums include groups appears on - extern char* GROUP_COMPILATION;//Get artist's albums include groups compilation - extern char* TIME_RANGE_SHORT;//4 weeks - extern char* TIME_RANGE_MEDIUM;//6 months - extern char* TIME_RANGE_LONG;//Several years - extern char* TOP_TYPE_ARTIST;//Users top artist's - extern char* TOP_TYPE_TRACKS;//Users top tracks - extern int SIZE_OF_URI;//Size to allocate for uri - extern int SIZE_OF_ID;//Size to allocate for id + 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 }; + + typedef struct{ int status_code; String reply; @@ -93,120 +115,203 @@ void print_response(response response_obj);//Print response object class Spotify { public: - Spotify(const char* refresh_token, const char* redirect_uri,const char* client_id,const char* client_secret, bool debug_on); - Spotify(const char* refresh_token, const char* redirect_uri,const char* client_id,const char* client_secret, bool debug_on, int max_num_retry); - Spotify(const char* refresh_token, const char* redirect_uri,const char* client_id,const char* client_secret); + ///@brief Constructor for Spotify object + ///@param refresh_token Refresh token from Spotify(Required) + ///@param redirect_uri Redirect uri from Spotify(Required) + ///@param client_id Client id from Spotify(Required) + ///@param client_secret Client secret from Spotify(Required) + ///@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 - /*@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 - */ + #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 response currently_playing(); - /*@brief Start or resume playback. If no device_id is provided, the user's currently active device is the target. If no context is provided, the user's currently playing context (e.g. album, playlist, etc.) is the target. - * @param context_uri Spotify URI of the context to play (Required) - * @param offset Indicates from where in the context playback should start, Only works with albums or Playlists(Optional) - * @param position_ms Indicates from what position in the context playback should start in milliseconds(Optional) - * @param device_id Id of the device this command is targeting (Optional) - * @return response object containing http status code and reply - */ + ///@brief Start or resume playback. If no device_id is provided, the user's currently active device is the target. If no context is provided, the user's currently playing context (e.g. album, playlist, etc.) is the target. + ///@param context_uri Spotify URI of the context to play (Required) + ///@param offset Indicates from where in the context playback should start, Only works with albums or Playlists(Optional) + ///@param position_ms Indicates from what position in the context playback should start in milliseconds(Optional) + ///@param device_id Id of the device this command is targeting (Optional) + ///@return response object containing http status code and reply response start_resume_playback(char* context_uri, int offset = 0, int position_ms = 0, char* device_id = nullptr); - /*@brief Start or resume playback. - * @param size Number of uris in uris array - * @param uris Array of Spotify URIs of the tracks to play - * @param device_id Id of the device this command is targeting (Optional) - * @return response object containing http status code and reply - */ + ///@brief Start or resume playback. + ///@param size Number of uris in uris array + ///@param uris Array of Spotify URIs of the tracks to play + ///@param device_id Id of the device this command is targeting (Optional) + ///@return response object containing http status code and reply response start_resume_playback(int size, char ** uris ,char* device_id = nullptr); - /*@brief Start or resume playback on provided device - * @param device_id Id of the device this command is targeting(Optional) - * @return response object containing http status code and reply - */ + ///@brief Start or resume playback on provided device + ///@param device_id Id of the device this command is targeting(Optional) + ///@return response object containing http status code and reply response start_resume_playback(char* device_id = nullptr); - /*@brief Pause playback on Spotify - * @return response object containing http status code and reply - */ + ///@brief Pause playback on Spotify + ///@return response object containing http status code and reply response pause_playback(); - /*@brief Skip to next track - * @return response object containing http status code and reply - */ + ///@brief Skip to next track + ///@return response object containing http status code and reply response skip(); - /*@brief Skip to previous track - * @return response object containing http status code and reply - */ + ///@brief Skip to previous track + ///@return response object containing http status code and reply response previous(); - /*@brief get information about the user's available devices - * @return response object containing http status code and reply - */ + ///@brief get information about the user's available devices + ///@return response object containing http status code and reply response available_devices(); - /*@brief get information about the user's current playback state, including track, track progress, and active device, shuffle etc. - * @return response object containing http status code and reply - */ + ///@brief get information about the user's current playback state, including track, track progress, and active device, shuffle etc. + ///@return response object containing http status code and reply response current_playback_state(); - /*@brief Get recently played tracks - * @param limit The maximum number of items to return. Default: 10. Minimum: 1. Maximum: 50 - */ + ///@brief Get recently played tracks + ///@param limit The maximum number of items to return. Default: 10. Minimum: 1. Maximum: 50 response recently_played_tracks(int limit = 10); - /*@brief Seek to position of current context - * @param time_ms Position in milliseconds to seek to, if the value is greater than the length of the track the player will skip to the next track - * @return response object containing http status code and reply - */ + ///@brief Seek to position of current context + ///@param time_ms Position in milliseconds to seek to, if the value is greater than the length of the track the player will skip to the next track + ///@return response object containing http status code and reply response seek_to_position(int time_ms); - /*@brief get users queue, response can be empty or containing episode or track objects - * @return response object containing http status code and reply - */ + ///@brief get users queue, response can be empty or containing episode or track objects + ///@return response object containing http status code and reply response get_queue(); - /*@Brief Set repeat mode, allowed values are REPEAT_OFF, REPEAT_TRACK, REPEAT_CONTEXT - * @param mode Repeat mode - * @return response object containing http status code and reply - */ + ///@Brief Set repeat mode, allowed values are REPEAT_OFF, REPEAT_TRACK, REPEAT_CONTEXT + ///@param mode Repeat mode + ///@return response object containing http status code and reply response repeat_mode(char* mode); - /*@Brief Set shuffle mode, allowed values are SHUFFLE_ON, SHUFFLE_OFF - * @param mode Shuffle mode - * @return response object containing http status code and reply - */ + ///@Brief Set shuffle mode, allowed values are SHUFFLE_ON, SHUFFLE_OFF + ///@param mode Shuffle mode + ///@return response object containing http status code and reply response shuffle(bool mode); - /*@Brief Transfer playback to another device - * @param device_id Id of the device this command is targeting - * @return response object containing http status code and reply - */ + ///@Brief Transfer playback to another device + ///@param device_id Id of the device this command is targeting + ///@return response object containing http status code and reply response transfer_playback(char* device_id); - /*@Brief Set volume, does not work with all devices(eg. does not work on Phones) - * @param value Volume value between 0 and 100 - * @return response object containing http status code and reply - */ + ///@Brief Set volume, does not work with all devices(eg. does not work on Phones) + ///@param value Volume value between 0 and 100 + ///@return response object containing http status code and reply response set_volume(int value); - /*@Brief Add context to queue - * @param context_uri Spotify URI of the context to add to queue - */ + ///@Brief Add context to queue + ///@param context_uri Spotify URI of the context to add to queue 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 response get_album(char* album_id); + ///@brief Get Spotify information for multiple albums identified by their Spotify IDs. + ///@param size Number of album ids in album_ids array + ///@param album_ids Array of Spotify IDs of the albums + ///@return response object containing http status code and reply response get_albums(int size, char** album_ids); + ///@brief Get Spotify information about an album's tracks. + ///@param album_id Spotify ID of the album + ///@param limit The maximum number of tracks to return. Default: 10. Minimum: 1. Maximum: 50 + ///@param offset The index of the first track to return. Default: 0 (the first object). Use with limit to get the next set of tracks. + ///@return response object containing http status code and reply response get_album_tracks(char* album_id, int limit = 10, int offset = 0); + ///@brief Get Albums saved to the current user's music library. + ///@param limit The maximum number of albums to return. Default: 10. Minimum: 1. Maximum: 50 + ///@param offset The index of the first album to return. Default: 0 (the first object). Use with limit to get the next set of albums. + ///@return response object containing http status code and reply response get_users_saved_albums(int limit = 10, int offset = 0); + ///@brief Save one or more albums to the current user's music library. + ///@param size Number of album ids in album_ids array + ///@param album_ids Array of Spotify IDs of the albums + ///@return response object containing http status code and reply response save_albums_for_current_user(int size, char** album_ids); + ///@brief Remove one or more albums from the current user's music library. + ///@param size Number of album ids in album_ids array + ///@param album_ids Array of Spotify IDs of the albums + ///@return response object containing http status code and reply response remove_users_saved_albums(int size, char** album_ids); + ///@brief Check if one or more albums is already saved in the current Spotify user's music library. + ///@param size Number of album ids in album_ids array + ///@param album_ids Array of Spotify IDs of the albums + ///@return response object containing http status code and reply response check_useres_saved_albums(int size, char** album_ids); - response get_new_releases(char* country, int limit = 10, int offset = 0); + ///@brief Get a list of new album releases featured in Spotify + ///@param limit The maximum number of items to return. Default: 10. Minimum: 1. Maximum: 50 + ///@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 =""); + #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 response get_artist(char* artist_id); + ///@brief Get Spotify information for multiple artists + ///@param size Number of artist ids in artist_ids array + ///@param artist_ids Array of Spotify IDs of the artists + ///@return response object containing http status code and reply response get_several_artists(int size, char** artist_ids); + ///@brief Get Spotify information about an artist's albums + ///@param artist_id Spotify ID of the artist + ///@param size_groups Number of groups in include_groups array + ///@param include_groups Array of groups to include in the response. Valid values are GROUP_ALBUM, GROUP_SINGLE, GROUP_APPEARS_ON, GROUP_COMPILATION or any combination of these. + ///@param limit The maximum number of items to return. Default: 10. Minimum: 1. Maximum: 50 + ///@param offset The index of the first album to return. Default: 0 (the first object). Use with limit to get the next set of albums. + ///@return response object containing http status code and reply response get_artist_albums(char* artist_id,int size_groups, char** include_groups, int limit = 10, int offset = 0); - response get_artist_top_tracks(char* artist_id, char* country); + ///@brief Get Spotify information about an artist's top tracks + ///@param artist_id Spotify ID of the artist + ///@param country An ISO 3166-1 alpha-2 country code or the string from_token. 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_artist_top_tracks(char* artist_id, char* country = nullptr); + ///@brief Get Spotify information about artists related to a single artist + ///@param artist_id Spotify ID of the artist + ///@return response object containing http status code and reply 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 + ///@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 + ///@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 + ///@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 response get_users_audiobooks(int limit = 10, int offset = 0); + /// @brief Save one or more audiobooks to the current user's music library + /// @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 + /// @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 + /// @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); + #endif + #ifdef ENABLE_CHAPTERS //Chapters (Only Available in US, UK, Canada, Ireland, New Zealand and Australia) response get_chapter(char* chapter_id); response get_several_chapters(int size, char** chapter_ids); + #endif + #ifdef ENABLE_EPISODES //Episodes response get_episode(char* episode_id); response get_several_episodes(int size, char** episode_ids); @@ -214,10 +319,16 @@ class Spotify { response save_episodes_for_current_user(int size, char** episode_ids); response remove_episodes_for_current_user(int size, char** episode_ids); response check_users_saved_episodes(int size, char** episode_ids); + #endif + #ifdef ENABLE_GENRES //Genres response get_available_genre_seeds(); + #endif + #ifdef ENABLE_MARKETS //Markets response get_available_markets(); + #endif + #ifdef ENABLE_PLAYLISTS //Playlists response get_playlist(char* playlist_id, char* fields); response change_playlist_details(char* playlist_id, char* name, bool is_public, bool is_collaborative, char* description); @@ -232,8 +343,12 @@ class Spotify { response get_category_playlists(char* category_id, char* country, int limit = 10, int offset = 0); response get_playlist_cover_image(char* playlist_id); 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); + #endif + #ifdef ENABLE_SHOWS //Shows response get_show(char* show_id); response get_several_shows(int size, char** show_ids); @@ -242,6 +357,8 @@ class Spotify { response save_shows_for_current_user(int size, char** show_ids); response remove_shows_for_current_user(int size, char** show_ids); response check_users_saved_shows(int size, char** show_ids); + #endif + #ifdef ENABLE_TRACKS //Tracks response get_track(char* track_id); response get_several_tracks(int size, char** track_ids); @@ -253,7 +370,8 @@ class Spotify { response get_track_audio_features(char* track_id); response get_track_audio_analysis(char* track_id); response get_recommendations(recommendations& recom, int limit = 10); - + #endif + #ifdef ENABLE_USERS //Users response get_current_user_profile(); response get_user_top_items(char* type, char* time_range = "medium_term", int limit = 10, int offset = 0); @@ -265,21 +383,25 @@ class Spotify { response unfollow_artists_or_users(char* type, int size, char** artist_user_ids); response check_if_user_follows_artists_or_users(char* type, int size, char** artist_user_ids); response check_if_users_follow_playlist(char* playlist_id, int size, char** user_ids); - + #endif + #ifdef ENABLE_SIMPIFIED //Simplified versions of the above String current_track_name(); String current_track_id(); String current_device_id(); String current_artist_names(); char* current_device_id(char* device_id); - + char* current_track_id(char* track_id); + char* current_track_name(char* track_name); + char* current_artist_names(char* artist_names); + bool is_playing(); + #endif //String convert_id_to_uri(String id, String type); char convert_id_to_uri(char* id, char* type); char* convert_id_to_uri(char* id, char* type, char* uri); - bool is_playing(); + 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. static const int _size_of_uri = 45; @@ -300,16 +422,16 @@ class Spotify { response RestApiDelete(char* rest_url, char* payload = nullptr); response RestApiGet(char* rest_url); - char* array_to_char(int size, char** array);//Convert array of chars to one comma separated char + char* array_to_char(int size, char** array, char* result);//Convert array of chars to one comma separated char 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& map, recommendations& recom);//Populate recommendation char values void populate_float_values(std::map& map, recommendations& recom);//Populate recommendation float values - const char * extract_endpoint(char* rest_url);//Extract endpoint from url with regex - - - + #endif + const char * extract_endpoint(const char* rest_url);//Extract endpoint from url with regex + const char* _spotify_root_ca = \ "-----BEGIN CERTIFICATE-----\n" \ "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \ diff --git a/Spotify_Esp32_test.ino b/Spotify_Esp32_test.ino index 73e7fd1..5f8bd3b 100644 --- a/Spotify_Esp32_test.ino +++ b/Spotify_Esp32_test.ino @@ -1,7 +1,9 @@ #include +#include #include #include #include +#include #include "SpotifyESP32.h" /*const char* ssid = "Rebweg10D"; @@ -13,7 +15,7 @@ const char* client_secret = "9ca64f76f7b54ecdaf3ae78585ff8b0f"; const char* redirect_uri = "http://localhost:8080"; const char* refresh_token="AQAichrGMfjjDHYWIAENJYyWoi_KpzLZ93_HSS30J8zULeuHRPmF9-Wh3aSEd5ju8tloWGDZ9GJodjRH51PRUPvTqPg855b3fdmQ8JifmdNAEfSapfhkihTKKXveJxie00o"; -using namespace Spotify_types; +//using namespace Spotify_types; Spotify sp(refresh_token, redirect_uri, client_id, client_secret, true); @@ -52,20 +54,7 @@ char* artist_user_ids[] = {"2CIMQHirSU0MQqyYHq0eOx","57dN52uHvrHOxijzpIgu3E","1v void setup() { Serial.begin(115200); connectToWifi(); - test_player(); test_albums(); - test_artist(); - test_audiobooks(); - test_chapters(); - test_categories(); - test_episodes(); - test_genres(); - test_markets(); - test_playlist(); - test_search(); - test_shows(); - test_tracks(); - test_users(); } @@ -85,14 +74,15 @@ void connectToWifi(){ Serial.println("Connected to WiFi"); } //working -void test_player(){ +/*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); - print_response(sp.start_resume_playback(uri, 0, 0)); + char* uris[] = {uri,uri}; + print_response(sp.start_resume_playback(2,uris)); Serial.print("Pause: "); print_response(sp.pause_playback()); @@ -136,7 +126,7 @@ void test_player(){ Serial.print("Set Volume: "); print_response(sp.set_volume(50)); -} +}*/ //working void test_albums(){ Serial.print("Get Album: "); @@ -161,9 +151,10 @@ void test_albums(){ print_response(sp.check_useres_saved_albums(3,album_ids)); Serial.print("Get Releases: "); - print_response(sp.get_new_releases("CH", 1, 0)); + print_response(sp.get_new_releases(1, 0)); } //working +/* void test_artist(){ Serial.print("Get Artist: "); print_response(sp.get_artist(artist_id)); @@ -388,4 +379,4 @@ void test_users(){ Serial.print("check_if_users_follow_playlist: "); print_response(sp.check_if_users_follow_playlist(playlist_id, 3, user_ids)); -} \ No newline at end of file +}*/ \ No newline at end of file