Merge pull request #1 from FinianLandes/workspace_prettify_etc

Workspace prettify etc
This commit is contained in:
Chaerne
2024-03-10 17:28:09 +01:00
committed by GitHub
18 changed files with 2873 additions and 80 deletions

105
README.md
View File

@@ -2,37 +2,90 @@
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>
- [WebServer](https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/src/WebServer.h) </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>
1. Create a new application on the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/applications) and copy the Client ID and Client Secret into your code. Leave the developer dashboard open as you will need to set the callback url later. </br>
2. Now you will have to use the login without a refresh token which can be implemented the following way:
```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");
#include <Arduino.h>
#include <WiFi.h>
#include "SpotifyESP32.h"
const char* SSID = "your_ssid";
const char* PASSWORD = "your_password";
const char* CLIENT_ID = "your_client_id";
const char* CLIENT_SECRET = "your_client_secret";
//Create an instance of the Spotify class Optional: you can set the Port for the webserver the debug mode(This prints out data to the serial monitor) and number of retries
Spotify sp(CLIENT_ID, CLIENT_SECRET);
void setup() {
Serial.begin(115200);
connect_to_wifi();//Connect to your wifi
sp.begin();//Start the webserver
while(!sp.is_auth()){//Wait for the user to authenticate
sp.handle_client();//Handle the client, this is necessary otherwise the webserver won't work
}
Serial.println("Authenticated");
}
void loop() {
//Add your code here
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}
```
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>
3. When exectuting this code you will have to open the serial monitor and copy the url into your browser. On this page you Login with your spotify account (Most endpoints only work with premium) and authorize your application to access your data. Now you will be redirected to page where your refresh token will be shown. So you don't have to open the browser every time you restart your esp i would recommend to copy the refresh token and use the other constructor afterwards:
```c++
#include <Arduino.h>
#include <WiFi.h>
#include "SpotifyESP32.h"
const char* SSID = "your_ssid";
const char* PASSWORD = "your_password";
const char* CLIENT_ID = "your_client_id";
const char* CLIENT_SECRET = "your_client_secret";
const char* REFRESH_TOKEN = "your_refresh_token";
//Create an instance of the Spotify class Optional: Debug mode and number of retries
Spotify sp(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN);
void setup() {
Serial.begin(115200);
connect_to_wifi();//Connect to your wifi
}
void loop() {
//Add your code here
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}
```
4. Now you can use the library. </br>
## Usage
- 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>
- To search for methods you can use the [Spotify Web API Reference](https://developer.spotify.com/documentation/web-api/reference/), all of the methods shown there are implemented </br>
- 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();
@@ -59,7 +112,11 @@ To print the response you can use the ```print_response(response_obj)``` functio
//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>
### Working Devices
- 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>
## Trouble Shooting
- If you have any problems with the library you can use the debug mode to print out the data to the serial monitor. I recommend not setting the baud rate lower than 115200 as the data printed can be quite large which can lead to crash if the Serial communication is too slow. </br>
- If you have any problems with the library you can also use the [Spotify Web API Console](https://developer.spotify.com/console/) to test the endpoints. </br>
- If there are still issues you can open an issue on this repository. </br>
## Working Devices
- ESP32 WROOM</br>
- Should also work on ESP2866 and other ESP32 models(Untested).</br>

View File

@@ -0,0 +1,12 @@
{
"folders": [
{
"path": "."
},
{
"name": "Spotify_v3",
"path": "Spotify_v3"
}
],
"settings": {}
}

7
Spotify_v3/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
src/config.h
TODO.txt

10
Spotify_v3/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

39
Spotify_v3/include/README Normal file
View File

@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
Spotify_v3/lib/README Normal file
View File

@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@@ -0,0 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x180000,
app1, app, ota_1, 0x190000,0x180000,
eeprom, data, 0x99, 0x310000,0x1000,
coredump, data, coredump,0x311000,0x10000,
spiffs, data, spiffs, 0x321000,0xDF000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x180000
5 app1 app ota_1 0x190000 0x180000
6 eeprom data 0x99 0x310000 0x1000
7 coredump data coredump 0x311000 0x10000
8 spiffs data spiffs 0x321000 0xDF000

22
Spotify_v3/platformio.ini Normal file
View File

@@ -0,0 +1,22 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
board_build.partitions = partitions.csv
lib_deps =
plageoj/UrlEncode@^1.0.1
bblanchon/ArduinoJson@^7.0.3
esphome/AsyncTCP-esphome@^2.1.2
monitor_filters = esp32_exception_decoder
monitor_speed = 115200
build_flags = -Og

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,830 @@
#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_USER
#define ENABLE_SIMPIFIED
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <UrlEncode.h>
#include <base64.h>
#include <iostream>
#include <functional>
#include <map>
#include <regex>
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_SHOW;
extern char* TYPE_EPISODE;
extern char* TYPE_AUDIOBOOK;
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 char* FOLLOW_TYPE_ARTIST;
extern char* FOLLOW_TYPE_USER;
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;
/// @brief Recommendation object, used to create recommendations
struct recommendations {
char** seed_artists;
int seed_artists_size = 0;
char** seed_genres;
int seed_genres_size = 0;
char** seed_tracks;
int seed_tracks_size = 0;
float min_acousticness = -1.0;
float max_acousticness = -1.0;
float target_acousticness = -1.0;
float min_danceability = -1.0;
float max_danceability = -1.0;
float target_danceability = -1.0;
float min_duration_ms = -1.0;
float max_duration_ms = -1.0;
float target_duration_ms = -1.0;
float min_energy = -1.0;
float max_energy = -1.0;
float target_energy = -1.0;
float min_instrumentalness = -1.0;
float max_instrumentalness = -1.0;
float target_instrumentalness = -1.0;
float min_key = -1.0;
float max_key = -1.0;
float target_key = -1.0;
float min_liveness = -1.0;
float max_liveness = -1.0;
float target_liveness = -1.0;
float min_loudness = -1.0;
float max_loudness = -1.0;
float target_loudness = -1.0;
float min_mode = -1.0;
float max_mode = -1.0;
float target_mode = -1.0;
float min_popularity = -1.0;
float max_popularity = -1.0;
float target_popularity = -1.0;
float min_speechiness = -1.0;
float max_speechiness = -1.0;
float target_speechiness = -1.0;
float min_tempo = -1.0;
float max_tempo = -1.0;
float target_tempo = -1.0;
float min_time_signature = -1.0;
float max_time_signature = -1.0;
float target_time_signature = -1.0;
float min_valence = -1.0;
float max_valence = -1.0;
float target_valence = -1.0;
};
/// @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 without refresh token
///@param client_id Client id from Spotify(Required)
///@param client_secret Client secret from Spotify(Required)
///@param server_port Port for the server to run on(default 80, if 80 is already used use anything above 1024)
///@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* client_id,const char* client_secret, int server_port = 80, bool debug_on = false, int max_num_retry = 3);
///@brief Constructor for Spotify object with refresh token
///@param client_id Client id from Spotify(Required)
///@param client_secret Client secret from Spotify(Required)
///@param refresh_token Refresh token from Spotify(Required) if not authenticated use other constructor
///@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* client_id,const char* client_secret,const char* refresh_token, bool debug_on = false, int max_num_retry = 3);
/// @brief start the server and begin authentication
void begin();
/// @brief handle client requests necessary for authentication
void handle_client();
/// @brief Check if user is authenticated
/// @return true if user is authenticated
bool is_auth();
#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.
///@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. NEEDS TO BE SET (0) IF ONLY URI IS PROVIDED
///@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, int position_ms = 0, char* device_id = nullptr);
///@brief Start or resume playback. If no device_id is provided, the user's currently active device is the target.
///@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. If no device_id is provided, the user's currently active device is the target. Targets the currently playing context.
///@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
response pause_playback();
///@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
response previous();
///@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
response current_playback_state();
///@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
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
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
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
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
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
response set_volume(int value);
///@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
///@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);
///@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 = nullptr);
#endif
#ifdef ENABLE_ARTIST
///@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);
///@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
///@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(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(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 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(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(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(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
///@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
///@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
///@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
///@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
///@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
///@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);
/// @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
/// @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
/// @param type An array of item types to search across
/// @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 the list of returned items to be relevant to a particular country.
/// @return response object containing http status code and reply
response search(char* q,int type_size , char** type , int limit = 10, int offset = 0, char* market = nullptr);
#endif
#ifdef ENABLE_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
/// @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_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
/// @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
/// @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:
WebServer _server;
WiFiClientSecure _client;
const char* _host = "api.spotify.com";
/// @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;
/// @brief Maximum number of items in one request
int _max_num_retry = 3;
/// @brief Users set redirect uri
char _redirect_uri[100] = "";
/// @brief Users refresh token
char _refresh_token[200] = "";
/// @brief user auth code
char _auth_code[800] = "";
/// @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;
/// @brief port
int _port;
/// @brief Access token
String _access_token;
/// @brief Root login Page
void server_on_root();
/// @brief Get refresh token from auth code
bool get_refresh_token();
/// @brief Currying function for callback_login_page
friend std::function<void()> callback_fn(Spotify *spotify);
/// @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 request to Spotify API
/// @param rest_url URL to make request to
/// @param type Type of request
/// @param payload_size Size of payload
/// @param payload Payload to send
response RestApi(char* rest_url, char* type, int payload_size = 0, char* payload = nullptr);
/// @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);
/// @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
/// @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
/// @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 PROGMEM= \
"-----BEGIN CERTIFICATE-----\n"\
"MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh\n"\
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"\
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"\
"MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\n"\
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh\n"\
"bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD\n"\
"ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV\n"\
"cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy\n"\
"FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc\n"\
"3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8\n"\
"osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT\n"\
"zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud\n"\
"EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G\n"\
"A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd\n"\
"BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG\n"\
"CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG\n"\
"NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH\n"\
"Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t\n"\
"L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC\n"\
"ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG\n"\
"9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t\n"\
"wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS\n"\
"slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R\n"\
"bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4\n"\
"chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN\n"\
"JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA==\n"\
"-----END CERTIFICATE-----\n";
const char* _login_page PROGMEM = R"=====(
<HTML>
<HEAD>
<TITLE>ESP Spotify Login</TITLE>
</HEAD>
<BODY>
<CENTER>
<H1>Spotify Login</H1>
<a href="https://accounts.spotify.com/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=ugc-image-upload playlist-read-collaborative playlist-modify-private playlist-modify-public playlist-read-private user-read-playback-position user-read-recently-played user-top-read user-modify-playback-state user-read-currently-playing user-read-playback-state user-read-private user-read-email user-library-modify user-library-read user-follow-modify user-follow-read streaming app-remote-control">Log in to spotify</a>
</CENTER>
</BODY>
</HTML>
)=====";
};
#endif

8
Spotify_v3/src/config.h Normal file
View File

@@ -0,0 +1,8 @@
const char* SSID = "Rebweg10D";
const char* PASSWORD = "Bitte_eintreten";
/*const char* SSID = "rdv-66754";
const char* PASSWORD = "1234567890";*/
const char* CLIENT_ID = "4a60dc25e5eb43e29161a0b00d296ff7";
const char* CLIENT_SECRET = "d65a695928b34a4ea3a0e66d9120b911";
const char* REFRESH_TOKEN = "AQC_3lM_jUt1Zgag5UO4qtOZcqCHSprkjsq6tvamaH2nXjn5xSyU0yuFXpi1M1YTNPyHEaBHpe1nWTOA_PkalojPGY8XfxS0kxFjFaZxbE2B4sQvVvSfgi6JIZrwYIwWYuo";
int PORT = 8000;

149
Spotify_v3/src/main.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include <Arduino.h>
#include <WiFi.h>
#include "SpotifyESP32.h"
#include "config.h"
using namespace Spotify_types;
void connect_to_wifi();
void check_all();
void check_one(response r);
Spotify sp(CLIENT_ID, CLIENT_SECRET,REFRESH_TOKEN, false);
void setup() {
Serial.begin(115200);
connect_to_wifi();
sp.begin();
while(!sp.is_auth()){
sp.handle_client();
}
Serial.println("Authenticated");
Serial.println(sp.current_artist_names());
Serial.println("Done");
}
void loop() {
// put your main code here, to run repeatedly:
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}
void check_all(){
Serial.println("Player");
check_one(sp.currently_playing());
/*check_one(sp.start_resume_playback("spotify:track:6xaMXvpkmVow1RAinlthUT"));
check_one(sp.pause_playback());
check_one(sp.start_resume_playback());
check_one(sp.skip());
check_one(sp.previous());
check_one(sp.available_devices());
check_one(sp.current_playback_state());
check_one(sp.recently_played_tracks());
check_one(sp.seek_to_position(1000));
check_one(sp.add_to_queue("spotify:track:6xaMXvpkmVow1RAinlthUT"));
check_one(sp.get_queue());
check_one(sp.repeat_mode(REPEAT_OFF));
check_one(sp.shuffle(SHUFFLE_ON));
check_one(sp.transfer_playback("956f01ff586ece9abaa152dd26bc5cc565be5a22"));
check_one(sp.set_volume(100));
Serial.println("Album");
check_one(sp.get_album("22pMyI5Ra0xRPDpf21ZWNb"));
char* albums[] = {"22pMyI5Ra0xRPDpf21ZWNb", "5AXd8wp7NNydXNzFAxlXmf"};
check_one(sp.get_albums(2, albums));
check_one(sp.get_album_tracks("22pMyI5Ra0xRPDpf21ZWNb"));
check_one(sp.get_users_saved_albums());
check_one(sp.remove_users_saved_albums(2, albums));
check_one(sp.save_albums_for_current_user(2, albums));
check_one(sp.check_useres_saved_albums(2, albums));
check_one(sp.get_new_releases());
Serial.println("Artist");
check_one(sp.get_artist("7keGfmQR4X5w0two1xKZ7d"));
char* artists[] = {"7keGfmQR4X5w0two1xKZ7d", "6LtXxYMIiKSy2EGHnz1f5j"};
check_one(sp.get_several_artists(2, artists));
char * group[] = {GROUP_ALBUM, GROUP_SINGLE, GROUP_APPEARS_ON, GROUP_COMPILATION};
check_one(sp.get_artist_albums("7keGfmQR4X5w0two1xKZ7d", 4, group));
check_one(sp.get_artist_top_tracks("7keGfmQR4X5w0two1xKZ7d", "DE"));
check_one(sp.get_artist_related_artist("7keGfmQR4X5w0two1xKZ7d"));
Serial.println("Browse");
check_one(sp.get_several_browse_categories());
check_one(sp.get_single_browse_category("dinner"));
Serial.println("Episode");
check_one(sp.get_episode("3mbWNOW6PwYGrXANw2JJDU"));
char* episodes[] = {"3mbWNOW6PwYGrXANw2JJDU", "4hwEvITXPZvcvL8UCVEp6Q"};
check_one(sp.get_several_episodes(2, episodes));
check_one(sp.get_users_saved_episodes());
check_one(sp.save_episodes_for_current_user(2, episodes));
check_one(sp.remove_episodes_for_current_user(2, episodes));
check_one(sp.check_users_saved_episodes(2, episodes));
Serial.println("Markets and Genres");
check_one(sp.get_available_genre_seeds());
check_one(sp.get_available_markets());
Serial.println("Playlists");
check_one(sp.get_playlist("37i9dQZF1EQn4jwNIohw50"));
check_one(sp.change_playlist_details("39Swnx8UEHw4FK9FlQHCov", "New Name", false, false, "New Description"));
check_one(sp.get_playlist_items("37i9dQZF1EQn4jwNIohw50","items(added_by.id,track(name,href,album(name,href)))"));
char* tracks[] = {"spotify:track:6xaMXvpkmVow1RAinlthUT", "spotify:track:6xaMXvpkmVow1RAinlthUT"};
check_one(sp.update_playlist_items("39Swnx8UEHw4FK9FlQHCov", 2, tracks));
check_one(sp.remove_playlist_items("39Swnx8UEHw4FK9FlQHCov", 2, tracks));
check_one(sp.add_items_to_playlist("39Swnx8UEHw4FK9FlQHCov", 2, tracks));
check_one(sp.get_current_users_playlists());
check_one(sp.get_user_playlists("spotify"));
check_one(sp.create_playlist("adix3gjuq0g570rwufhfcw89o","New Playlist", false,true, "New Description"));
check_one(sp.get_featured_playlists());
check_one(sp.get_category_playlists("dinner"));
check_one(sp.get_playlist_cover_image("37i9dQZF1EQn4jwNIohw50"));
check_one(sp.add_custom_playlist_cover_image("39Swnx8UEHw4FK9FlQHCov", "/9j/2wCEABoZGSccJz4lJT5CLy8vQkc9Ozs9R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0cBHCcnMyYzPSYmPUc9Mj1HR0dEREdHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR//dAAQAAf/uAA5BZG9iZQBkwAAAAAH/wAARCAABAAEDACIAAREBAhEB/8QASwABAQAAAAAAAAAAAAAAAAAAAAYBAQAAAAAAAAAAAAAAAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAARAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwAAARECEQA/AJgAH//Z"));
Serial.println("Search");
char* types[] = {TYPE_ALBUM, TYPE_ARTIST, TYPE_PLAYLIST, TYPE_TRACK};
check_one(sp.search("remaster%2520track%3ADoxy%2520artist%3AMiles%2520Davis", 4, types));
Serial.println("Shows");
check_one(sp.get_show("5icRmO26ZsDWsNjUy5rssH"));
char* shows[] = {"5icRmO26ZsDWsNjUy5rssH", "3wBfqov60qDZbEVjPHo0a8"};
check_one(sp.get_several_shows(2, shows));
check_one(sp.get_show_episodes("5icRmO26ZsDWsNjUy5rssH"));
check_one(sp.get_users_saved_shows());
check_one(sp.save_shows_for_current_user(2, shows));
check_one(sp.remove_shows_for_current_user(2, shows));
check_one(sp.check_users_saved_shows(2, shows));
Serial.println("Tracks");
check_one(sp.get_track("49A10weBfgwg4TUM3My7iv"));
char* tracks[] = {"49A10weBfgwg4TUM3My7iv", "3qhlB30KknSejmIvZZLjOD"};
check_one(sp.get_several_tracks(2, tracks));
check_one(sp.get_user_saved_tracks());
check_one(sp.save_tracks_for_current_user(2, tracks));
check_one(sp.remove_user_saved_tracks(2, tracks));
check_one(sp.check_user_saved_tracks(2, tracks));
check_one(sp.get_tracks_audio_features(2, tracks));
check_one(sp.get_track_audio_analysis("49A10weBfgwg4TUM3My7iv"));
check_one(sp.get_track_audio_features("49A10weBfgwg4TUM3My7iv"));
recommendations r;
char* seed_artists[] = {"4NHQUGzhtTLFvgF5SZesLK"};
r.seed_artists = seed_artists;
r.seed_artists_size = 1;
r.target_acousticness = 0.5;
r.target_danceability = 0.5;
check_one(sp.get_recommendations(r, 2));
Serial.println("User");
check_one(sp.get_current_user_profile());
check_one(sp.get_user_profile("spotify"));
check_one(sp.get_user_top_items(TOP_TYPE_ARTIST));
check_one(sp.follow_playlist("37i9dQZF1EQn4jwNIohw50", false));
check_one(sp.unfollow_playlist("37i9dQZF1EQn4jwNIohw50"));
char* users[] = {"spotify"};
check_one(sp.check_if_users_follow_playlist("37i9dQZF1EQn4jwNIohw50",1, users));
check_one(sp.get_followed_artists(""));
check_one(sp.follow_artists_or_users(FOLLOW_TYPE_USER, 1, users));
check_one(sp.unfollow_artists_or_users(FOLLOW_TYPE_USER, 1, users));
check_one(sp.check_if_user_follows_artists_or_users(FOLLOW_TYPE_USER, 1, users));*/
}
void check_one(response r){
if(r.status_code < 200 or r.status_code > 300){
Serial.printf("Error: %d\n", r.status_code);
Serial.println(r.reply);
}
}

11
Spotify_v3/test/README Normal file
View File

@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

View File

@@ -0,0 +1,39 @@
/*
An example of how to use the Spotify library using a refresh token.
This example is useful as it does not require the user to authenticate in the browser every time they want to use the library.
20.02.2024
Created by: Finian Landes
Documentation: https://github.com/FinianLandes/Spotify_Esp32
*/
// Include the required libraries
#include <Arduino.h>
#include <WiFi.h>
#include <SpotifyESP32.h>
const char* SSID = "YOUR WIFI SSID";
const char* PASSWORD = "YOUR WIFI PASSWORD";
const char* CLIENT_ID = "YOUR CLIENT ID FROM THE SPOTIFY DASHBOARD";
const char* CLIENT_SECRET = "YOUR CLIENT SECRET FROM THE SPOTIFY DASHBOARD";
const char* REFRESH_TOKEN = "YOUR REFRESH TOKEN";
Spotify sp(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN);
void setup() {
Serial.begin(115200);
connect_to_wifi();
}
void loop() {
// put your main code here, to run repeatedly:
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}

View File

@@ -1,25 +0,0 @@
#include <Arduino.h>
#include <WiFi.h>
#include "SpotifyESP32.h"
#include "config.h"
using namespace Spotify_types;
Spotify sp(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN);
void setup() {
Serial.begin(115200);
connect_to_wifi();
}
void loop() {
// put your main code here, to run repeatedly:
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}

View File

@@ -0,0 +1,45 @@
/*
An example of how to authenticate with Spotify without using a refresh token.
This example is useful to get the refresh token for the first time. It can also be used to authenticate every time without using the refresh token.
20.02.2024
Created by: Finian Landes
Documentation: https://github.com/FinianLandes/Spotify_Esp32
*/
// Include the required libraries
#include <Arduino.h>
#include <WiFi.h>
#include <SpotifyESP32.h>
const char* SSID = "YOUR WIFI SSID";
const char* PASSWORD = "YOUR WIFI PASSWORD";
const char* CLIENT_ID = "YOUR CLIENT ID FROM THE SPOTIFY DASHBOARD";
const char* CLIENT_SECRET = "YOUR CLIENT SECRET FROM THE SPOTIFY DASHBOARD";
Spotify sp(CLIENT_ID, CLIENT_SECRET);
void setup() {
Serial.begin(115200);
connect_to_wifi();
sp.begin();
while(!sp.is_auth()){
sp.handle_client();
}
Serial.println("Authenticated");
}
void loop() {
// put your main code here, to run repeatedly:
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}

View File

@@ -1,31 +0,0 @@
#include <Arduino.h>
#include <WiFi.h>
#include "SpotifyESP32.h"
#include "config.h"
using namespace Spotify_types;
Spotify sp(CLIENT_ID, CLIENT_SECRET);
void setup() {
Serial.begin(115200);
connect_to_wifi();
sp.begin();
while(!sp.is_auth()){
sp.handle_client();
}
Serial.println("Authenticated");
}
void loop() {
// put your main code here, to run repeatedly:
}
void connect_to_wifi(){
WiFi.begin(SSID, PASSWORD);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.printf("\nConnected to WiFi\n");
}

10
library.properties Normal file
View File

@@ -0,0 +1,10 @@
name = Spotify_Esp32
version = 1.0.0
author = Finian Landes, Pia Piekarek
maintainer = Finian Landes <landesfinian@gmail.com>
sentence = A client to interact with the Spotify API
paragraph = This library provides a client to interact with the Spotify API. It is designed to be used with the ESP32 microcontroller.
category = Communication
url = https://github.com/FinianLandes/Spotify_Esp32
architectures = *
depends = WiFi, WiFiClientSecure, HTTPClient, ArduinoJson, UrlEncode, WebServer, base64