Formatting changes
This commit is contained in:
@@ -14,16 +14,16 @@ find_path (CPPCODEC_INCLUDE_DIRS "cppcodec/base32_crockford.hpp")
|
|||||||
|
|
||||||
|
|
||||||
set (SOURCES
|
set (SOURCES
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/SpotifyDemo.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/SpotifyDemo.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set (SD_INCLUDE_DIR
|
set (SD_INCLUDE_DIR
|
||||||
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
)
|
)
|
||||||
|
|
||||||
set (HEADERS
|
set (HEADERS
|
||||||
"${SD_INCLUDE_DIR}/Models.h"
|
"${SD_INCLUDE_DIR}/Models.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories ("${SD_INCLUDE_DIR}")
|
include_directories ("${SD_INCLUDE_DIR}")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"client_id": "id",
|
"client_id": "id",
|
||||||
"client_secret": "secret"
|
"client_secret": "secret"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,71 +6,71 @@
|
|||||||
|
|
||||||
namespace Models
|
namespace Models
|
||||||
{
|
{
|
||||||
template<typename Str = std::string,
|
template<typename Str = std::string,
|
||||||
typename Num = int,
|
typename Num = int,
|
||||||
typename Dur = long>
|
typename Dur = long>
|
||||||
class Song
|
class Song
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Song() = default;
|
Song() = default;
|
||||||
|
|
||||||
Str title;
|
Str title;
|
||||||
Str artist;
|
Str artist;
|
||||||
Str album;
|
Str album;
|
||||||
Str released;
|
Str released;
|
||||||
Dur duration;
|
Dur duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Str = std::string,
|
template<typename Str = std::string,
|
||||||
typename Num = int>
|
typename Num = int>
|
||||||
class Album
|
class Album
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Album() = default;
|
Album() = default;
|
||||||
|
|
||||||
Str title;
|
Str title;
|
||||||
Str released;
|
Str released;
|
||||||
std::vector<Song<>> songs;
|
std::vector<Song<>> songs;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Str = std::string>
|
template<typename Str = std::string>
|
||||||
class ClientInformation
|
class ClientInformation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClientInformation() = default;
|
ClientInformation() = default;
|
||||||
ClientInformation(Str& id, Str& secret) :
|
ClientInformation(Str& id, Str& secret) :
|
||||||
client_id(std::move(id)), client_secret(std::move(secret))
|
client_id(std::move(id)), client_secret(std::move(secret))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ClientInformation(Str&& id, Str&& secret) :
|
ClientInformation(Str&& id, Str&& secret) :
|
||||||
client_id(id), client_secret(secret)
|
client_id(id), client_secret(secret)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
auto is_empty()
|
auto is_empty()
|
||||||
{
|
{
|
||||||
return (client_id.empty() && client_secret.empty()) ? true : false;
|
return (client_id.empty() && client_secret.empty()) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Str client_id;
|
Str client_id;
|
||||||
Str client_secret;
|
Str client_secret;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Str = std::string,
|
template<typename Str = std::string,
|
||||||
typename Num = int>
|
typename Num = int>
|
||||||
class TokenResp
|
class TokenResp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
auto is_empty()
|
auto is_empty()
|
||||||
{
|
{
|
||||||
return this->access_token.empty();
|
return this->access_token.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
Str access_token;
|
Str access_token;
|
||||||
Str token_type;
|
Str token_type;
|
||||||
Num expires_in;
|
Num expires_in;
|
||||||
Str scope;
|
Str scope;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+122
-122
@@ -13,163 +13,163 @@
|
|||||||
|
|
||||||
namespace Spotify
|
namespace Spotify
|
||||||
{
|
{
|
||||||
template<typename Tok = Models::TokenResp<std::string>>
|
template<typename Tok = Models::TokenResp<std::string>>
|
||||||
class SpotifyCall
|
class SpotifyCall
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SpotifyCall() = default;
|
SpotifyCall() = default;
|
||||||
SpotifyCall(Tok& tok) : token(tok)
|
SpotifyCall(Tok& tok) : token(tok)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
SpotifyCall(Tok&& tok) : token(std::move(tok))
|
SpotifyCall(Tok&& tok) : token(std::move(tok))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Str = std::string>
|
template<typename Str = std::string>
|
||||||
auto search_songs(Str&& title)
|
auto search_songs(Str&& title)
|
||||||
{
|
{
|
||||||
constexpr auto limit = 49;
|
constexpr auto limit = 49;
|
||||||
|
|
||||||
std::vector<Models::Album<>> albums;
|
std::vector<Models::Album<>> albums;
|
||||||
albums.reserve(limit);
|
albums.reserve(limit);
|
||||||
|
|
||||||
std::string search_query("name:");
|
std::string search_query("name:");
|
||||||
search_query.append(delimit_search_query(title));
|
search_query.append(delimit_search_query(title));
|
||||||
|
|
||||||
|
|
||||||
const auto uri = search_uri();
|
const auto uri = search_uri();
|
||||||
const auto authorization = bearer_authorization();
|
const auto authorization = bearer_authorization();
|
||||||
|
|
||||||
Str limit_str(std::to_string(limit));
|
Str limit_str(std::to_string(limit));
|
||||||
|
|
||||||
auto resp = cpr::Get(cpr::Url{ uri },
|
auto resp = cpr::Get(cpr::Url{ uri },
|
||||||
cpr::Parameters{ {"type", "track"},
|
cpr::Parameters{ {"type", "track"},
|
||||||
{"limit", limit_str},
|
{"limit", limit_str},
|
||||||
{"q", search_query} },
|
{"q", search_query} },
|
||||||
cpr::Header{ {"Authorization", authorization.c_str()} });
|
cpr::Header{ {"Authorization", authorization.c_str()} });
|
||||||
|
|
||||||
if (resp.status_code == 200) {
|
if (resp.status_code == 200) {
|
||||||
parse_albums(albums, std::move(resp.text));
|
parse_albums(albums, std::move(resp.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return albums;
|
return albums;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Cont = std::vector<Models::Album<std::string>>>
|
template<typename Cont = std::vector<Models::Album<std::string>>>
|
||||||
void print_songs_to_console(Cont &albums)
|
void print_songs_to_console(Cont &albums)
|
||||||
{
|
{
|
||||||
std::cout << "Printing songs to the console\n";
|
std::cout << "Printing songs to the console\n";
|
||||||
|
|
||||||
std::for_each(albums.begin(), albums.end(), [](auto album) {
|
std::for_each(albums.begin(), albums.end(), [](auto album) {
|
||||||
auto song = album.songs.at(0);
|
auto song = album.songs.at(0);
|
||||||
|
|
||||||
std::cout << "Title: " << song.title << "\n";
|
std::cout << "Title: " << song.title << "\n";
|
||||||
std::cout << "Artist: " << song.artist << "\n";
|
std::cout << "Artist: " << song.artist << "\n";
|
||||||
std::cout << "Album: " << album.title << "\n";
|
std::cout << "Album: " << album.title << "\n";
|
||||||
std::cout << "Released Date: " << song.released << "\n";
|
std::cout << "Released Date: " << song.released << "\n";
|
||||||
std::cout << "Duration (ms): " << song.duration << "\n";
|
std::cout << "Duration (ms): " << song.duration << "\n";
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
});
|
});
|
||||||
|
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Str = std::string>
|
template<typename Str = std::string>
|
||||||
auto delimit_search_query(Str &&title)
|
auto delimit_search_query(Str &&title)
|
||||||
{
|
{
|
||||||
return std::regex_replace(title, std::regex(" "), "%20");
|
return std::regex_replace(title, std::regex(" "), "%20");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bearer_authorization()
|
auto bearer_authorization()
|
||||||
{
|
{
|
||||||
std::string authorization("Bearer ");
|
std::string authorization("Bearer ");
|
||||||
authorization.append(this->token.access_token);
|
authorization.append(this->token.access_token);
|
||||||
|
|
||||||
return authorization;
|
return authorization;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Alb = Models::Album<>, typename Vec = std::vector<Alb>,
|
template<typename Alb = Models::Album<>, typename Vec = std::vector<Alb>,
|
||||||
typename Str = std::string>
|
typename Str = std::string>
|
||||||
void parse_albums(Vec &alb, Str &&resp)
|
void parse_albums(Vec &alb, Str &&resp)
|
||||||
{
|
{
|
||||||
auto obj = nlohmann::json::parse(resp);
|
auto obj = nlohmann::json::parse(resp);
|
||||||
|
|
||||||
for (auto& item : obj["tracks"]["items"]) {
|
for (auto& item : obj["tracks"]["items"]) {
|
||||||
auto album_json = item["album"];
|
auto album_json = item["album"];
|
||||||
auto artists_json = item["artists"];
|
auto artists_json = item["artists"];
|
||||||
|
|
||||||
Alb album;
|
Alb album;
|
||||||
album.title = album_json["name"].get<std::string>();
|
album.title = album_json["name"].get<std::string>();
|
||||||
album.released = album_json["release_date"].get<std::string>();
|
album.released = album_json["release_date"].get<std::string>();
|
||||||
|
|
||||||
Models::Song<> song;
|
Models::Song<> song;
|
||||||
song.title = item["name"].get<std::string>();
|
song.title = item["name"].get<std::string>();
|
||||||
song.duration = item["duration_ms"].get<long>();
|
song.duration = item["duration_ms"].get<long>();
|
||||||
song.artist = artists_json[0]["name"].get<std::string>();
|
song.artist = artists_json[0]["name"].get<std::string>();
|
||||||
song.released = album.released;
|
song.released = album.released;
|
||||||
song.album = album.title;
|
song.album = album.title;
|
||||||
|
|
||||||
std::vector<Models::Song<>> songs;
|
std::vector<Models::Song<>> songs;
|
||||||
songs.push_back(song);
|
songs.push_back(song);
|
||||||
|
|
||||||
album.songs = songs;
|
album.songs = songs;
|
||||||
|
|
||||||
alb.push_back(album);
|
alb.push_back(album);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto saved_albums_response_body()
|
auto saved_albums_response_body()
|
||||||
{
|
{
|
||||||
nlohmann::json obj;
|
nlohmann::json obj;
|
||||||
|
|
||||||
std::string uri(base_uri());
|
std::string uri(base_uri());
|
||||||
uri.append("/");
|
uri.append("/");
|
||||||
uri.append(album_saved());
|
uri.append(album_saved());
|
||||||
|
|
||||||
std::string auth_header("Bearer ");
|
std::string auth_header("Bearer ");
|
||||||
auth_header.append(this->token.access_token);
|
auth_header.append(this->token.access_token);
|
||||||
|
|
||||||
auto resp = cpr::Get(cpr::Url(uri),
|
auto resp = cpr::Get(cpr::Url(uri),
|
||||||
cpr::Header{{"Authorization", auth_header.c_str()}}
|
cpr::Header{{"Authorization", auth_header.c_str()}}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (resp.status_code == 200) {
|
if (resp.status_code == 200) {
|
||||||
obj = nlohmann::json::parse(resp.text);
|
obj = nlohmann::json::parse(resp.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Str = std::string>
|
template<typename Str = std::string>
|
||||||
auto search_uri()
|
auto search_uri()
|
||||||
{
|
{
|
||||||
Str uri(base_uri());
|
Str uri(base_uri());
|
||||||
uri.append("/");
|
uri.append("/");
|
||||||
uri.append(search_item_endpoint());
|
uri.append(search_item_endpoint());
|
||||||
|
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto base_uri() noexcept
|
constexpr auto base_uri() noexcept
|
||||||
{
|
{
|
||||||
return "https://api.spotify.com/v1";
|
return "https://api.spotify.com/v1";
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto album_saved() noexcept
|
constexpr auto album_saved() noexcept
|
||||||
{
|
{
|
||||||
return "me/albums";
|
return "me/albums";
|
||||||
}
|
}
|
||||||
constexpr auto search_item_endpoint() noexcept
|
constexpr auto search_item_endpoint() noexcept
|
||||||
{
|
{
|
||||||
return "search";
|
return "search";
|
||||||
}
|
}
|
||||||
|
|
||||||
Tok token;
|
Tok token;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,100 +14,100 @@
|
|||||||
|
|
||||||
namespace Manager
|
namespace Manager
|
||||||
{
|
{
|
||||||
template<typename Str = std::string>
|
template<typename Str = std::string>
|
||||||
class TokenRetrieval
|
class TokenRetrieval
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TokenRetrieval() = default;
|
TokenRetrieval() = default;
|
||||||
TokenRetrieval(Models::ClientInformation<Str> &info) :
|
TokenRetrieval(Models::ClientInformation<Str> &info) :
|
||||||
client_information(std::move(info))
|
client_information(std::move(info))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
TokenRetrieval(Models::ClientInformation<Str> &&info) :
|
TokenRetrieval(Models::ClientInformation<Str> &&info) :
|
||||||
client_information(info)
|
client_information(info)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TokResp>
|
template<typename TokResp>
|
||||||
auto retrieve_token()
|
auto retrieve_token()
|
||||||
{
|
{
|
||||||
if (this->client_information.is_empty()) {
|
if (this->client_information.is_empty()) {
|
||||||
return TokResp();
|
return TokResp();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto token = make_call<TokResp>();
|
auto token = make_call<TokResp>();
|
||||||
|
|
||||||
|
|
||||||
return (token.is_empty()) ? TokResp() : token;
|
return (token.is_empty()) ? TokResp() : token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename TokResp>
|
template<typename TokResp>
|
||||||
auto make_call()
|
auto make_call()
|
||||||
{
|
{
|
||||||
TokResp resp;
|
TokResp resp;
|
||||||
|
|
||||||
Str authorization("Basic ");
|
Str authorization("Basic ");
|
||||||
authorization.append(encoded_authorization());
|
authorization.append(encoded_authorization());
|
||||||
|
|
||||||
|
|
||||||
const auto uri = construct_uri(spotify_uri(), spotify_token_endpoint());
|
const auto uri = construct_uri(spotify_uri(), spotify_token_endpoint());
|
||||||
auto r = cpr::Post(cpr::Url{ uri },
|
auto r = cpr::Post(cpr::Url{ uri },
|
||||||
cpr::Parameters{ {"grant_type", "client_credentials" }},
|
cpr::Parameters{ {"grant_type", "client_credentials" }},
|
||||||
cpr::Header{ {"Authorization", authorization.c_str()} }
|
cpr::Header{ {"Authorization", authorization.c_str()} }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (r.status_code == 200) {
|
if (r.status_code == 200) {
|
||||||
auto token = nlohmann::json::parse(r.text);
|
auto token = nlohmann::json::parse(r.text);
|
||||||
resp.access_token = token["access_token"].get<Str>();
|
resp.access_token = token["access_token"].get<Str>();
|
||||||
resp.token_type = token["token_type"].get<Str>();
|
resp.token_type = token["token_type"].get<Str>();
|
||||||
resp.expires_in = token["expires_in"].get<int>();
|
resp.expires_in = token["expires_in"].get<int>();
|
||||||
resp.scope = token["scope"].get<Str>();
|
resp.scope = token["scope"].get<Str>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto encoded_authorization()
|
auto encoded_authorization()
|
||||||
{
|
{
|
||||||
Str unencoded(client_information.client_id);
|
Str unencoded(client_information.client_id);
|
||||||
unencoded.append(":");
|
unencoded.append(":");
|
||||||
unencoded.append(client_information.client_secret);
|
unencoded.append(client_information.client_secret);
|
||||||
|
|
||||||
std::vector<char> v(unencoded.begin(), unencoded.end());
|
std::vector<char> v(unencoded.begin(), unencoded.end());
|
||||||
|
|
||||||
return cppcodec::base64_rfc4648::encode(v);
|
return cppcodec::base64_rfc4648::encode(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ch = char>
|
template<typename Ch = char>
|
||||||
auto construct_uri(Ch *base, Ch *endpoint)
|
auto construct_uri(Ch *base, Ch *endpoint)
|
||||||
{
|
{
|
||||||
Str uri(base);
|
Str uri(base);
|
||||||
|
|
||||||
if (uri.at(uri.size() - 1) != '/') {
|
if (uri.at(uri.size() - 1) != '/') {
|
||||||
uri.append("/");
|
uri.append("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
uri.append(endpoint);
|
uri.append(endpoint);
|
||||||
|
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr spotify_uri() noexcept
|
auto constexpr spotify_uri() noexcept
|
||||||
{
|
{
|
||||||
return "https://accounts.spotify.com";
|
return "https://accounts.spotify.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr spotify_token_endpoint() noexcept
|
auto constexpr spotify_token_endpoint() noexcept
|
||||||
{
|
{
|
||||||
return "api/token";
|
return "api/token";
|
||||||
}
|
}
|
||||||
|
|
||||||
Models::ClientInformation<Str> client_information;
|
Models::ClientInformation<Str> client_information;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,47 +19,47 @@ using namespace Models;
|
|||||||
template<typename Conf, typename Str>
|
template<typename Conf, typename Str>
|
||||||
auto retrieve_client_information(Str &&path)
|
auto retrieve_client_information(Str &&path)
|
||||||
{
|
{
|
||||||
std::fstream config_file(path, std::ios::in);
|
std::fstream config_file(path, std::ios::in);
|
||||||
|
|
||||||
std::stringstream buffer;
|
std::stringstream buffer;
|
||||||
buffer << config_file.rdbuf();
|
buffer << config_file.rdbuf();
|
||||||
|
|
||||||
config_file.close();
|
config_file.close();
|
||||||
|
|
||||||
auto client_json = nlohmann::json::parse(buffer.str());
|
auto client_json = nlohmann::json::parse(buffer.str());
|
||||||
std::string id(client_json["client_id"].get<std::string>());
|
std::string id(client_json["client_id"].get<std::string>());
|
||||||
std::string secret(client_json["client_secret"].get<std::string>());
|
std::string secret(client_json["client_secret"].get<std::string>());
|
||||||
|
|
||||||
Conf client_information(std::move(id), std::move(secret));
|
Conf client_information(std::move(id), std::move(secret));
|
||||||
|
|
||||||
return client_information;
|
return client_information;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
std::cout << "Starting SpotfyDemo\n";
|
std::cout << "Starting SpotfyDemo\n";
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
std::cout << "Provide path to the client information json file\n";
|
std::cout << "Provide path to the client information json file\n";
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path(std::move(argv[1]));
|
std::string path(std::move(argv[1]));
|
||||||
|
|
||||||
auto client_info = retrieve_client_information<ClientInformation<std::string>,
|
auto client_info = retrieve_client_information<ClientInformation<std::string>,
|
||||||
std::string>(std::move(path));
|
std::string>(std::move(path));
|
||||||
|
|
||||||
Manager::TokenRetrieval<> tok_mgr(std::move(client_info));
|
Manager::TokenRetrieval<> tok_mgr(std::move(client_info));
|
||||||
auto resp = tok_mgr.retrieve_token<Models::TokenResp<std::string>>();
|
auto resp = tok_mgr.retrieve_token<Models::TokenResp<std::string>>();
|
||||||
|
|
||||||
Spotify::SpotifyCall<> spotify(std::move(resp));
|
Spotify::SpotifyCall<> spotify(std::move(resp));
|
||||||
std::string song_title("Heave");
|
std::string song_title("Heave");
|
||||||
|
|
||||||
auto albums = spotify.search_songs(song_title);
|
auto albums = spotify.search_songs(song_title);
|
||||||
spotify.print_songs_to_console(albums);
|
spotify.print_songs_to_console(albums);
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user