Discman
Loading...
Searching...
No Matches
spotify.cc
Go to the documentation of this file.
1
6
7#include "spotify.h"
8
9std::string Spotify::_accessToken;
10
12 if (!std::getenv("SPOTIFY_CLIENT_ID") || !std::getenv("SPOTIFY_CLIENT_SECRET")) {
14 }
15}
16
18 std::string clientId = std::getenv("SPOTIFY_CLIENT_ID");
19 std::string clientSecret = std::getenv("SPOTIFY_CLIENT_SECRET");
20
21 cURLpp::Cleanup cleanup;
22 cURLpp::Easy easyhandle;
23
24 std::string request_url = "https://accounts.spotify.com/api/token";
25
26 std::list<std::string> headers;
27 headers.push_back("Authorization: Basic "+base64_encode(clientId+":"+clientSecret));
28 headers.push_back("Content-Type: application/x-www-form-urlencoded");
29
30 std::string form = "grant_type=client_credentials";
31
32 std::stringstream ss;
33 easyhandle.setOpt(cURLpp::Options::Url(request_url));
34 easyhandle.setOpt(cURLpp::Options::HttpHeader(headers));
35 easyhandle.setOpt(new curlpp::options::PostFields(form));
36 easyhandle.setOpt(new curlpp::options::PostFieldSize(form.size()));
37 easyhandle.setOpt(cURLpp::Options::WriteStream(&ss));
38 easyhandle.perform();
39
40 Json::Value response;
41 ss >> response;
42
43 Spotify::_accessToken = response["access_token"].asString();
44}
45
46std::vector<AlbumArtProvider::AlbumArt> Spotify::album_art(const std::string& artist, const std::string& title, const int width, const int height) {
47 cURLpp::Cleanup cleanup;
48 cURLpp::Easy easyhandle;
49
50 std::string request_url = url(Method::SearchForItem, {
51 {"q", "artist:"+artist+" album:"+title},
52 {"type", "album"},
53 {"limit", "10"},
54 });
55
56 std::list<std::string> headers;
57 headers.push_back("Authorization: Bearer "+_accessToken);
58
59 std::stringstream ss;
60 easyhandle.setOpt(cURLpp::Options::Url(request_url));
61 easyhandle.setOpt(cURLpp::Options::HttpHeader(headers));
62 easyhandle.setOpt(cURLpp::Options::WriteStream(&ss));
63 easyhandle.perform();
64
65 int httpCode = curlpp::infos::ResponseCode::get(easyhandle);
66
67 if (httpCode == 401) {
68 init();
69
70 ss.str("");
71 easyhandle.perform();
72 }
73
74 Json::Value root;
75 ss >> root;
76
77 std::map<int, std::vector<std::string>> urlsBySize;
78
79 Json::Value items = root["albums"]["items"];
80
81 for (unsigned int i = 0; i < items.size(); i++) {
82 Json::Value images = items[i]["images"];
83
84 for (unsigned int j = 0; j < images.size(); j++) {
85 int size = images[j]["width"].asInt() * images[j]["height"].asInt();
86 std::string url = images[j]["url"].asString();
87
88 if (urlsBySize.contains(size)) {
89 urlsBySize[size].push_back(url);
90 }
91 else {
92 urlsBySize[size] = {{ url }};
93 }
94 }
95 }
96
97 std::vector<AlbumArt> arts;
98
99 for (auto it = urlsBySize.rbegin(); it != urlsBySize.rend(); ++it) {
100 for (const std::string& url : it->second) {
101 easyhandle.setOpt(cURLpp::Options::Url(url));
102
103 ss.str("");
104 easyhandle.perform();
105
106 std::string data = ss.str();
107 Glib::RefPtr<Glib::Bytes> bytes = Glib::Bytes::create(data.c_str(), data.size());
108 Glib::RefPtr<Gio::MemoryInputStream> is = Gio::MemoryInputStream::create();
109 is->add_bytes(bytes);
110
112 .art = Gdk::Pixbuf::create_from_stream_at_scale(is, width, height, true),
113 .url = url
114 };
115
116 arts.push_back(art);
117 }
118 }
119
120 if (arts.empty()) {
122 }
123
124 return arts;
125}
126
127std::string Spotify::base64_encode(const std::string& input) {
128 BIO* b64 = BIO_new(BIO_f_base64());
129 BIO* bio = BIO_new(BIO_s_mem());
130 bio = BIO_push(b64, bio);
131
132 BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
133
134 BIO_write(bio, input.c_str(), input.length());
135 BIO_flush(bio);
136
137 BUF_MEM* bufferPtr;
138 BIO_get_mem_ptr(bio, &bufferPtr);
139
140 std::string output(bufferPtr->data, bufferPtr->length);
141
142 BIO_free_all(bio);
143
144 return output;
145}
146
147std::string Spotify::method_name(const Spotify::Method method) {
148 switch (method) {
149 default:
150 case SearchForItem:
151 return "search";
152 }
153}
154
155std::string Spotify::url(const Method method, const std::map<std::string, std::string>& params) {
156 return url_with_params(BASE_URL+method_name(method), params);
157}
static std::string url_with_params(const std::string &url, const std::map< std::string, std::string > &params)
Returns the URL of the API endpoint with the given parameters encoded as query parameters.
static std::string base64_encode(const std::string &input)
Encodes a string into base64. Used to encode an HTTP authorization header.
Definition spotify.cc:127
static std::string url(const Method method, const std::map< std::string, std::string > &params)
Calls url_with_params() with the Spotify API method URL.
Definition spotify.cc:155
void init() override
Retrieves the Spotify client ID and secret as environment variables.
Definition spotify.cc:17
Method
Spotify API methods.
Definition spotify.h:35
@ SearchForItem
Definition spotify.h:36
std::vector< AlbumArt > album_art(const std::string &artist, const std::string &title, const int width, const int height) override
Retrieves all album art matching the artist and title.
Definition spotify.cc:46
static constexpr const char * BASE_URL
The Spotify API base URL.
Definition spotify.h:40
static std::string method_name(const Method method)
Conversion method to convert a Spotify::Method to a string.
Definition spotify.cc:147
static std::string _accessToken
The Spotify API key retrieved.
Definition spotify.h:59
Spotify()
Spotify constructor.
Definition spotify.cc:11
An album art image and its URL.
Thrown when the provider cannot be reached.
Thrown when the provider cannot find album art images.