otakugifs.c 1.0.0
A simple, lightweight c wrapper the otakugifs.xyz API
otakugifs.h
Go to the documentation of this file.
1/// \file otakugifs.h This file contains structs and functions for interacting with the otakugifs.xyz API.
2
3#ifndef OTAKUGIFS_H
4#define OTAKUGIFS_H
5
6#ifdef __cplusplus
7extern "C" {
8#endif
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <stdbool.h>
13#include <string.h>
14#include <curl/curl.h>
15#include <cjson/cJSON.h>
16
17/// Base URL for the otakugifs.xyz API.
18#define OTAKU_BASE_URL "https://api.otakugifs.xyz/gif"
19
20/// Status codes for the otakugifs.xyz c wrapper.
21typedef enum {
22 OTAKU_OK, ///< Indicates that the operation was successful.
23 OTAKU_MEM_ERR, ///< Indicates that there was a memory allocation error.
24 OTAKU_LIBCURL_ERR, ///< Indicates that there was an error with libcurl.
25 OTAKU_CJSON_ERR ///< Indicates that there was an error with cJSON.
27
28/// Enum for the format of the image.
29typedef enum {
30 OTAKU_GIF, ///< Indicates that the response image is a gif.
31 OTAKU_WEBP, ///< Indicates that the response image is a webp.
32 OTAKU_AVIF ///< Indicates that the response image is a avif.
34
35/// Struct for a list of reactions.
36typedef struct {
37 char **reactions; ///< [out] Array of reactions.
38 size_t len; ///< [out] Amount of reactions.
40
41/// Struct for a result.
42typedef struct {
43 otaku_format format; ///< [out] Format of the result.
44 char* url; ///< [out] URL to the result.
46
47/**
48 * Struct for an http response.
49 */
50typedef struct {
51 char *text; ///< [out] Non-nullterminated text of the response.
52 size_t len; ///< [out] Length of the response text.
54
55#ifndef OTAKUGIFS_IMPL
56
57/**
58 * Get a list of reactions.
59 *
60 * This function fetches the `allreactions` endpoint of the api
61 * and parses the response into a list of reactions.
62 *
63 * It will allocate memory for the list of reactions and the reactions themselves.
64 *
65 * \param [out] reactions
66 * Pointer to a \link otaku_reaction_list otaku_reaction_list \endlink to store the reactions in.
67 *
68 * \return
69 * ::OTAKU_OK \n
70 * ::OTAKU_MEM_ERR \n
71 * ::OTAKU_LIBCURL_ERR \n
72 * ::OTAKU_CJSON_ERR
73 */
75
76/**
77 * Check if a reaction exists.
78 *
79 * This function searches for a specific reaction in a list of reactions by name.
80 *
81 * \param [in] reactions
82 * Pointer to a \link otaku_reaction_list otaku_reaction_list \endlink to search in.
83 * \param [in] name
84 * Name of the reaction to search for.
85 *
86 * \return
87 * True if the reaction exists, false otherwise.
88 */
89bool otaku_is_reaction(const otaku_reaction_list* reactions, const char* name);
90
91/**
92 * Fetch a reaction.
93 *
94 * This function fetches the specified reaction endpoint of the api
95 * and parses the response into a result reaction.
96 *
97 * It will allocate memory for the result.
98 *
99 * \param [out] result
100 * Pointer to a \link otaku_result otaku_result \endlink to store the result in.
101 * \param [in] reaction
102 * Reaction to fetch. Must be a valid reaction.
103 * \param [in] format
104 * Format of the result.
105 *
106 * \return
107 * ::OTAKU_OK \n
108 * ::OTAKU_MEM_ERR \n
109 * ::OTAKU_LIBCURL_ERR \n
110 * ::OTAKU_CJSON_ERR \n
111 */
112otaku_status otaku_reaction(otaku_result *result, const char *reaction, otaku_format format);
113
114/**
115 * Download an image.
116 *
117 * This function fetches the specified image url
118 * and stores the response in a \link otaku_http_response otaku_http_response \endlink.
119 *
120 * It will allocate memory for the response text.
121 *
122 * \param [out] http_response
123 * Pointer to a \link otaku_http_response otaku_http_response \endlink to store the response in.
124 * \param [in] url
125 * URL of the image to download.
126 *
127 * \return
128 * ::OTAKU_OK \n
129 * ::OTAKU_MEM_ERR \n
130 * ::OTAKU_LIBCURL_ERR
131 */
132otaku_status otaku_download(otaku_http_response *http_response, const char* url);
133
134/**
135 * Free a list of reactions.
136 *
137 * This function frees the memory allocated for the list of reactions and the reactions themselves.
138 *
139 * \param [in] reactions
140 * Pointer to a \link otaku_reaction_list otaku_reaction_list \endlink to free.
141 */
143
144/**
145 * Free a result.
146 *
147 * This function frees the memory allocated for the result.
148 *
149 * \param [in] result
150 * Pointer to a \link otaku_result otaku_result \endlink to free.
151 */
152void otaku_free_result(const otaku_result* result);
153
154/**
155 * Free an http response.
156 *
157 * This function frees the memory allocated for the response text.
158 *
159 * \param [in] http_response
160 * Pointer to a \link otaku_http_response otaku_http_response \endlink to free.
161 */
163
164#else // OTAKUGIFS_IMPL
165
166static size_t otaku_write_callback(const void *ptr, size_t count, size_t nmemb, otaku_http_response *http_response) {
167 size_t size = count * nmemb;
168 size_t new_len = http_response->len + size;
169
170 // resize response text
171 char* new_text = (char*) realloc(http_response->text, new_len + 1);
172 if (!new_text) {
173 free(http_response->text);
174 return CURLE_ABORTED_BY_CALLBACK;
175 }
176
177 // copy new data to response text
178 memcpy(new_text + http_response->len, ptr, size);
179 http_response->text = new_text;
180 http_response->len = new_len;
181 return size;
182}
183
184static otaku_status otaku_do_request(otaku_http_response *http_response, const char* url) {
185 // initialize http response object
186 http_response->len = 0;
187 http_response->text = (char*) malloc(1);
188 if (!http_response->text)
189 return OTAKU_MEM_ERR;
190
191 // initialize curl
192 CURL *curl = curl_easy_init();
193 if (!curl)
194 return OTAKU_LIBCURL_ERR;
195
196 // configure curl request
197 curl_easy_setopt(curl, CURLOPT_URL, url);
198 curl_easy_setopt(curl, CURLOPT_CA_CACHE_TIMEOUT, 604800L);
199 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, otaku_write_callback);
200 curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response);
201
202 // make request
203 CURLcode res = curl_easy_perform(curl);
204 if (res != CURLE_OK)
205 return OTAKU_LIBCURL_ERR;
206
207 // cleanup curl
208 curl_easy_cleanup(curl);
209 return OTAKU_OK;
210}
211
213 // make request
214 otaku_http_response http_response;
215 otaku_status http_status = otaku_do_request(&http_response, OTAKU_BASE_URL "/allreactions");
216 if (http_status != OTAKU_OK)
217 return http_status;
218
219 // parse response
220 cJSON *json = cJSON_ParseWithLength(http_response.text, http_response.len);
221 if (!json || !cJSON_IsObject(json) || !cJSON_HasObjectItem(json, "reactions"))
222 return OTAKU_CJSON_ERR;
223
224 // parse json
225 cJSON *reactions_obj = cJSON_GetObjectItemCaseSensitive(json, "reactions");
226 reactions->len = cJSON_GetArraySize(reactions_obj);
227 reactions->reactions = (char**) malloc(reactions->len * sizeof(char*));
228
229 // iterate through reactions
230 const cJSON *reactions_item;
231 size_t i = 0;
232 cJSON_ArrayForEach(reactions_item, reactions_obj) {
233 reactions->reactions[i] = (char*) malloc(strlen(reactions_item->valuestring) + 1);
234 if (!reactions->reactions[i])
235 return OTAKU_MEM_ERR;
236
237 strcpy(reactions->reactions[i], reactions_item->valuestring);
238 i++;
239 }
240
241 // cleanup
242 cJSON_Delete(json);
243 free(http_response.text);
244 return OTAKU_OK;
245}
246
247bool otaku_is_reaction(const otaku_reaction_list* reactions, const char* name) {
248 for (size_t i = 0; i < reactions->len; i++) {
249 if (strcmp(reactions->reactions[i], name) == 0)
250 return true;
251 }
252
253 return false;
254}
255
256otaku_status otaku_reaction(otaku_result *result, const char *reaction, otaku_format format) {
257 // create reaction url
258 char url[96];
259 snprintf(url, 96, OTAKU_BASE_URL "?reaction=%s&format=%s", reaction, format == OTAKU_GIF ? (format == OTAKU_AVIF ? "avif" : "gif") : "webp");
260
261 // make request
262 otaku_http_response http_response;
263 otaku_status http_status = otaku_do_request(&http_response, url);
264 if (http_status != OTAKU_OK)
265 return http_status;
266
267 // parse response
268 cJSON *json = cJSON_ParseWithLength(http_response.text, http_response.len);
269 if (!json || !cJSON_IsObject(json) || !cJSON_HasObjectItem(json, "url"))
270 return OTAKU_CJSON_ERR;
271
272 // parse json
273 cJSON *url_obj = cJSON_GetObjectItemCaseSensitive(json, "url");
274 result->url = (char*) malloc(strlen(url_obj->valuestring) + 1);
275 if (!result->url)
276 return OTAKU_MEM_ERR;
277 result->url = strcpy(result->url, url_obj->valuestring);
278 result->format = format;
279
280 // cleanup
281 cJSON_Delete(json);
282 free(http_response.text);
283 return OTAKU_OK;
284}
285
286otaku_status otaku_download(otaku_http_response *http_response, const char* url) {
287 return otaku_do_request(http_response, url);
288}
289
290void otaku_free_reactions(const otaku_reaction_list* reactions) {
291 for (size_t i = 0; i < reactions->len; i++)
292 free(reactions->reactions[i]);
293
294 free(reactions->reactions);
295}
296
297void otaku_free_result(const otaku_result* result) {
298 free(result->url);
299}
300
301void otaku_free_http_response(const otaku_http_response* http_response) {
302 free(http_response->text);
303}
304
305#endif // OTAKUGIFS_IMPL
306
307#ifdef __cplusplus
308}
309#endif
310
311#endif // OTAKUGIFS_H
otaku_format
Enum for the format of the image.
Definition otakugifs.h:29
@ OTAKU_GIF
Indicates that the response image is a gif.
Definition otakugifs.h:30
@ OTAKU_WEBP
Indicates that the response image is a webp.
Definition otakugifs.h:31
@ OTAKU_AVIF
Indicates that the response image is a avif.
Definition otakugifs.h:32
void otaku_free_http_response(const otaku_http_response *http_response)
Free an http response.
otaku_status otaku_reactions(otaku_reaction_list *reactions)
Get a list of reactions.
otaku_status otaku_reaction(otaku_result *result, const char *reaction, otaku_format format)
Fetch a reaction.
bool otaku_is_reaction(const otaku_reaction_list *reactions, const char *name)
Check if a reaction exists.
void otaku_free_reactions(const otaku_reaction_list *reactions)
Free a list of reactions.
otaku_status
Status codes for the otakugifs.xyz c wrapper.
Definition otakugifs.h:21
@ OTAKU_OK
Indicates that the operation was successful.
Definition otakugifs.h:22
@ OTAKU_MEM_ERR
Indicates that there was a memory allocation error.
Definition otakugifs.h:23
@ OTAKU_CJSON_ERR
Indicates that there was an error with cJSON.
Definition otakugifs.h:25
@ OTAKU_LIBCURL_ERR
Indicates that there was an error with libcurl.
Definition otakugifs.h:24
#define OTAKU_BASE_URL
Base URL for the otakugifs.xyz API.
Definition otakugifs.h:18
void otaku_free_result(const otaku_result *result)
Free a result.
otaku_status otaku_download(otaku_http_response *http_response, const char *url)
Download an image.
Struct for an http response.
Definition otakugifs.h:50
char * text
[out] Non-nullterminated text of the response.
Definition otakugifs.h:51
size_t len
[out] Length of the response text.
Definition otakugifs.h:52
Struct for a list of reactions.
Definition otakugifs.h:36
size_t len
[out] Amount of reactions.
Definition otakugifs.h:38
char ** reactions
[out] Array of reactions.
Definition otakugifs.h:37
Struct for a result.
Definition otakugifs.h:42
otaku_format format
[out] Format of the result.
Definition otakugifs.h:43
char * url
[out] URL to the result.
Definition otakugifs.h:44