Mercurial > wgsdk
annotate src/deezer.c @ 12:dd427b7cc459 default tip
json: replace with nxjson library
more lightweight, reduces the binary size by about 40 kb
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Fri, 15 Mar 2024 20:46:18 -0400 |
parents | e6a594f16403 |
children |
rev | line source |
---|---|
11 | 1 #include "json.h" |
2 #include "utils.h" | |
3 | |
4 #include <windef.h> | |
5 #include <minwinbase.h> | |
6 #include <winhttp.h> | |
7 #include <winuser.h> | |
8 | |
9 HINTERNET session = NULL; | |
10 HINTERNET connection = NULL; | |
11 | |
12 /* preferably we would use some other API for this, but | |
13 * meh | |
14 */ | |
15 static int init_winhttp(void) { | |
16 session = WinHttpOpen( | |
17 NULL, | |
18 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, | |
19 WINHTTP_NO_PROXY_NAME, | |
20 WINHTTP_NO_PROXY_BYPASS, | |
21 0 | |
22 ); | |
23 | |
24 return !!session; | |
25 } | |
26 | |
27 static int init_connect(void) { | |
28 if (!session) | |
29 return 0; | |
30 | |
31 connection = WinHttpConnect( | |
32 session, | |
33 L"api.deezer.com", | |
34 /* require HTTPS, we aren't in 2001 anymore */ | |
35 INTERNET_DEFAULT_HTTPS_PORT, | |
36 0 | |
37 ); | |
38 | |
39 return !!connection; | |
40 } | |
41 | |
42 /* do this on exit */ | |
43 void close_open_http_handles(void) { | |
44 if (session) WinHttpCloseHandle(session); | |
45 if (connection) WinHttpCloseHandle(connection); | |
46 } | |
47 | |
48 /* return MUST be free'd */ | |
49 static LPCWSTR deezer_get_thumbnail_build_query(LPCWSTR restrict artist, LPCWSTR restrict album) { | |
50 static LPCWSTR begin = L"/search/track?strict=on&q=artist:\""; | |
51 static LPCWSTR album_query = L" album:\""; | |
52 | |
53 size_t len = wcslen(begin) + wcslen(artist) + 1 /* quote */; | |
54 if (album && album[0]) { | |
55 len += 1 /* space */ + wcslen(album_query) + wcslen(album) + 1 /* quote */; | |
56 } | |
57 | |
58 LPWSTR final = calloc(len + 1, sizeof(WCHAR)); | |
59 | |
60 wcscpy(final, begin); | |
61 wcscat(final, artist); | |
62 wcscat(final, L"\""); | |
63 if (album && album[0]) { | |
64 wcscat(final, album_query); | |
65 wcscat(final, album); | |
66 wcscat(final, L"\""); | |
67 } | |
68 | |
69 return final; | |
70 } | |
71 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
72 static int deezer_album_object_get_cover(const nx_json* album, const char* name, char** url) { |
11 | 73 if (!url) return 0; |
74 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
75 const nx_json* cover = nx_json_get(album, name); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
76 if (!cover) |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
77 return 0; |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
78 |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
79 free(*url); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
80 |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
81 size_t len = strlen(cover->text_value); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
82 *url = malloc((len + 1) * sizeof(char)); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
83 (*url)[len] = '\0'; |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
84 |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
85 strncpy(*url, cover->text_value, len); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
86 return 1; |
11 | 87 } |
88 | |
89 | |
90 static int deezer_get_thumbnail_download_url(LPCWSTR restrict query, char** restrict data, size_t* restrict size) { | |
91 if (!data || !size) | |
92 return -1; | |
93 | |
94 HINTERNET request = WinHttpOpenRequest( | |
95 connection, | |
96 L"GET", | |
97 query, | |
98 NULL, | |
99 WINHTTP_NO_REFERER, | |
100 WINHTTP_DEFAULT_ACCEPT_TYPES, | |
101 WINHTTP_FLAG_SECURE | WINHTTP_FLAG_ESCAPE_PERCENT | |
102 ); | |
103 if (!request) | |
104 return -1; | |
105 | |
106 BOOL result = WinHttpSendRequest( | |
107 request, | |
108 L"Content-Type: application/json; charset=utf-8", | |
109 0, | |
110 WINHTTP_NO_REQUEST_DATA, | |
111 0, | |
112 0, | |
113 0 | |
114 ); | |
115 if (!result) { | |
116 WinHttpCloseHandle(request); | |
117 return -1; | |
118 } | |
119 | |
120 result = WinHttpReceiveResponse(request, NULL); | |
121 if (!result) { | |
122 WinHttpCloseHandle(request); | |
123 return -1; | |
124 } | |
125 | |
126 DWORD data_available = 0; | |
127 DWORD data_downloaded = 0; | |
128 do { | |
129 data_available = 0; | |
130 if (!WinHttpQueryDataAvailable(request, &data_available)) { | |
131 WinHttpCloseHandle(request); | |
132 return -1; | |
133 } | |
134 | |
135 if (!data_available) | |
136 break; | |
137 | |
138 *data = realloc(*data, *size + data_available + 1); | |
139 (*data)[*size + data_available] = '\0'; | |
140 if (!WinHttpReadData(request, *data + *size, data_available, &data_downloaded)) { | |
141 WinHttpCloseHandle(request); | |
142 return -1; | |
143 } | |
144 *size += data_downloaded; | |
145 } while (data_available > 0); | |
146 | |
147 WinHttpCloseHandle(request); | |
148 return 0; | |
149 } | |
150 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
151 /* note: please prefix these */ |
11 | 152 enum deezer_thumbnail_state { |
153 ERROR = 0, | |
154 ALBUM, | |
155 ARTIST, | |
156 }; | |
157 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
158 static enum deezer_thumbnail_state deezer_get_thumbnail_parse_search_result(const nx_json* json, char** cover_url, int get_artist) { |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
159 const nx_json* album = nx_json_get(json, "album"); |
11 | 160 |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
161 if (album->type == NX_JSON_OBJECT) { |
11 | 162 if (deezer_album_object_get_cover(album, "cover_medium", cover_url) |
163 || deezer_album_object_get_cover(album, "cover_large", cover_url) | |
164 || deezer_album_object_get_cover(album, "cover_small", cover_url) | |
165 || deezer_album_object_get_cover(album, "cover_xl", cover_url)) | |
166 return ALBUM; | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
167 } |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
168 |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
169 if (get_artist) { |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
170 const nx_json* artist = nx_json_get(json, "artist"); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
171 if (artist->type != NX_JSON_OBJECT) |
11 | 172 return ERROR; |
173 | |
174 /* treat artist pictures as a fallback and only retrieve them once */ | |
175 if (deezer_album_object_get_cover(artist, "picture_medium", cover_url) | |
176 || deezer_album_object_get_cover(artist, "picture_large", cover_url) | |
177 || deezer_album_object_get_cover(artist, "picture_small", cover_url) | |
178 || deezer_album_object_get_cover(artist, "picture_xl", cover_url)) | |
179 return ARTIST; | |
180 } | |
181 | |
182 return ERROR; | |
183 } | |
184 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
185 /* THIS MODIFIES `data` IN PLACE!! */ |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
186 static int deezer_get_thumbnail_parse_json(char** cover_url, char* data) { |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
187 const nx_json* json = nx_json_parse(data, NULL); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
188 if (!json) |
11 | 189 return -1; |
190 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
191 const nx_json* json_data = nx_json_get(json, "data"); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
192 if (json_data->type != NX_JSON_ARRAY || !json_data->children.length) |
11 | 193 return -1; |
194 | |
195 int have_artist = 0; | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
196 for (size_t i = 0; i < json_data->children.length; i++) { |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
197 const nx_json* result = nx_json_item(json_data, i); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
198 if (result->type != NX_JSON_OBJECT) |
11 | 199 return -1; |
200 | |
201 enum deezer_thumbnail_state state = deezer_get_thumbnail_parse_search_result(result, cover_url, have_artist); | |
202 switch (state) { | |
203 case ERROR: return -1; | |
204 case ARTIST: have_artist = 1; break; | |
205 case ALBUM: return 0; | |
206 } | |
207 } | |
208 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
209 nx_json_free(json); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
210 |
11 | 211 return !have_artist; |
212 } | |
213 | |
214 char* deezer_get_thumbnail(LPCWSTR restrict artist, LPCWSTR restrict album) { | |
215 char* response_data = NULL; | |
216 size_t response_size = 0; | |
217 LPCWSTR query = NULL; | |
218 char* cover_url = NULL; | |
219 | |
220 /* make sure everything is OK */ | |
221 if (!(session || init_winhttp()) || !(connection || init_connect()) || (!artist || !artist[0])) | |
222 return NULL; | |
223 | |
224 query = deezer_get_thumbnail_build_query(artist, album); | |
225 if (!query) | |
226 return NULL; | |
227 | |
228 if (deezer_get_thumbnail_download_url(query, &response_data, &response_size)) | |
229 return NULL; | |
230 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
231 if (deezer_get_thumbnail_parse_json(&cover_url, response_data)) |
11 | 232 return NULL; |
233 | |
12
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
234 free(response_data); |
dd427b7cc459
json: replace with nxjson library
Paper <paper@paper.us.eu.org>
parents:
11
diff
changeset
|
235 |
11 | 236 return cover_url; |
237 } |