Mercurial > wgsdk
view 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 |
line wrap: on
line source
#include "json.h" #include "utils.h" #include <windef.h> #include <minwinbase.h> #include <winhttp.h> #include <winuser.h> HINTERNET session = NULL; HINTERNET connection = NULL; /* preferably we would use some other API for this, but * meh */ static int init_winhttp(void) { session = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ); return !!session; } static int init_connect(void) { if (!session) return 0; connection = WinHttpConnect( session, L"api.deezer.com", /* require HTTPS, we aren't in 2001 anymore */ INTERNET_DEFAULT_HTTPS_PORT, 0 ); return !!connection; } /* do this on exit */ void close_open_http_handles(void) { if (session) WinHttpCloseHandle(session); if (connection) WinHttpCloseHandle(connection); } /* return MUST be free'd */ static LPCWSTR deezer_get_thumbnail_build_query(LPCWSTR restrict artist, LPCWSTR restrict album) { static LPCWSTR begin = L"/search/track?strict=on&q=artist:\""; static LPCWSTR album_query = L" album:\""; size_t len = wcslen(begin) + wcslen(artist) + 1 /* quote */; if (album && album[0]) { len += 1 /* space */ + wcslen(album_query) + wcslen(album) + 1 /* quote */; } LPWSTR final = calloc(len + 1, sizeof(WCHAR)); wcscpy(final, begin); wcscat(final, artist); wcscat(final, L"\""); if (album && album[0]) { wcscat(final, album_query); wcscat(final, album); wcscat(final, L"\""); } return final; } static int deezer_album_object_get_cover(const nx_json* album, const char* name, char** url) { if (!url) return 0; const nx_json* cover = nx_json_get(album, name); if (!cover) return 0; free(*url); size_t len = strlen(cover->text_value); *url = malloc((len + 1) * sizeof(char)); (*url)[len] = '\0'; strncpy(*url, cover->text_value, len); return 1; } static int deezer_get_thumbnail_download_url(LPCWSTR restrict query, char** restrict data, size_t* restrict size) { if (!data || !size) return -1; HINTERNET request = WinHttpOpenRequest( connection, L"GET", query, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE | WINHTTP_FLAG_ESCAPE_PERCENT ); if (!request) return -1; BOOL result = WinHttpSendRequest( request, L"Content-Type: application/json; charset=utf-8", 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0 ); if (!result) { WinHttpCloseHandle(request); return -1; } result = WinHttpReceiveResponse(request, NULL); if (!result) { WinHttpCloseHandle(request); return -1; } DWORD data_available = 0; DWORD data_downloaded = 0; do { data_available = 0; if (!WinHttpQueryDataAvailable(request, &data_available)) { WinHttpCloseHandle(request); return -1; } if (!data_available) break; *data = realloc(*data, *size + data_available + 1); (*data)[*size + data_available] = '\0'; if (!WinHttpReadData(request, *data + *size, data_available, &data_downloaded)) { WinHttpCloseHandle(request); return -1; } *size += data_downloaded; } while (data_available > 0); WinHttpCloseHandle(request); return 0; } /* note: please prefix these */ enum deezer_thumbnail_state { ERROR = 0, ALBUM, ARTIST, }; static enum deezer_thumbnail_state deezer_get_thumbnail_parse_search_result(const nx_json* json, char** cover_url, int get_artist) { const nx_json* album = nx_json_get(json, "album"); if (album->type == NX_JSON_OBJECT) { if (deezer_album_object_get_cover(album, "cover_medium", cover_url) || deezer_album_object_get_cover(album, "cover_large", cover_url) || deezer_album_object_get_cover(album, "cover_small", cover_url) || deezer_album_object_get_cover(album, "cover_xl", cover_url)) return ALBUM; } if (get_artist) { const nx_json* artist = nx_json_get(json, "artist"); if (artist->type != NX_JSON_OBJECT) return ERROR; /* treat artist pictures as a fallback and only retrieve them once */ if (deezer_album_object_get_cover(artist, "picture_medium", cover_url) || deezer_album_object_get_cover(artist, "picture_large", cover_url) || deezer_album_object_get_cover(artist, "picture_small", cover_url) || deezer_album_object_get_cover(artist, "picture_xl", cover_url)) return ARTIST; } return ERROR; } /* THIS MODIFIES `data` IN PLACE!! */ static int deezer_get_thumbnail_parse_json(char** cover_url, char* data) { const nx_json* json = nx_json_parse(data, NULL); if (!json) return -1; const nx_json* json_data = nx_json_get(json, "data"); if (json_data->type != NX_JSON_ARRAY || !json_data->children.length) return -1; int have_artist = 0; for (size_t i = 0; i < json_data->children.length; i++) { const nx_json* result = nx_json_item(json_data, i); if (result->type != NX_JSON_OBJECT) return -1; enum deezer_thumbnail_state state = deezer_get_thumbnail_parse_search_result(result, cover_url, have_artist); switch (state) { case ERROR: return -1; case ARTIST: have_artist = 1; break; case ALBUM: return 0; } } nx_json_free(json); return !have_artist; } char* deezer_get_thumbnail(LPCWSTR restrict artist, LPCWSTR restrict album) { char* response_data = NULL; size_t response_size = 0; LPCWSTR query = NULL; char* cover_url = NULL; /* make sure everything is OK */ if (!(session || init_winhttp()) || !(connection || init_connect()) || (!artist || !artist[0])) return NULL; query = deezer_get_thumbnail_build_query(artist, album); if (!query) return NULL; if (deezer_get_thumbnail_download_url(query, &response_data, &response_size)) return NULL; if (deezer_get_thumbnail_parse_json(&cover_url, response_data)) return NULL; free(response_data); return cover_url; }