#include "StringReplace.h" #include "EpisodeList.h" #include "CurlResult.h" #include "EpisodeListToJson.h" #include "urlcode.h" #include #include #include #include #include "utils.h" void EpisodeList_init(struct EpisodeList* this) { this->name = NULL; this->episodes = List_create(); this->rewatchMarker = NOT_REWATCHING; } void EpisodeList_destroyMembers(struct EpisodeList* this) { safe_free(this->name); List_destroyWithContent(this->episodes, Episode_destroy); } DEFAULT_CREATE_DESTROY(EpisodeList) struct EpisodeList* EpisodeList_fetch(const char* baseurl, const char* tvShow) { char url[2048]; char* escapedTvShow = url_encode((char*)tvShow); sprintf(url, "%s/api/library/tvshow/%s/details", baseurl, escapedTvShow); CURL* handle = curl_easy_init(); struct CurlResult userdata; CurlResult_init(&userdata); curl_easy_setopt(handle, CURLOPT_URL, url); curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15); curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &userdata); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, CurlResult_write); curl_easy_perform(handle); json_value* json = CurlResult_parse(&userdata); struct EpisodeList* this = EpisodeList_restore(json); if (json) { json_value_free(json); } CurlResult_destroyMembers(&userdata); curl_easy_cleanup(handle); free(escapedTvShow); return this; } struct EpisodeList* EpisodeList_restore(json_value* json) { if (!json || json->type != json_object) { return NULL; } struct EpisodeList* this = EpisodeList_create(); for (int i=0; i < json->u.object.length; ++i) { json_value* value = json->u.object.values[i].value; if (0 == strcmp(json->u.object.values[i].name, "rewatchMarker")) { this->rewatchMarker = value->type == json_double ? value->u.dbl : value->type == json_integer ? value->u.integer : NOT_REWATCHING; } else if (0 == strcmp(json->u.object.values[i].name, "episodes") && value->type == json_array) { json_value* array = value; for (int j=0; j < array->u.array.length; ++j) { struct Episode* ep = Episode_restore(array->u.array.values[j]); if (ep) { List_pushBack(this->episodes, ep); } } } } List_qSort(this->episodes, Episode_compare); return this; } List* EpisodeList_contstructPlaylist(struct EpisodeList* this) { List* list = List_create(); // unwatched normal episodes for (ListNode* it = this->episodes->first; it; it = it->next) { struct Episode* ep = it->data; if (!ep->watched && ep->number > EPISODE_SPECIAL) { List_pushBack(list, ep->path); } } if (list->first) { return list; } // rewatching for (ListNode* it = this->episodes->first; it; it = it->next) { struct Episode* ep = it->data; if (this->rewatchMarker != NOT_REWATCHING && ep->number > this->rewatchMarker) { List_pushBack(list, ep->path); } } if (list->first) { return list; } // unwatched extras for (ListNode* it = this->episodes->first; it; it = it->next) { struct Episode* ep = it->data; if (!ep->watched) { List_pushBack(list, ep->path); } } if (list->first) { return list; } // already watched for (ListNode* it = this->episodes->first; it; it = it->next) { struct Episode* ep = it->data; if (ep->watched) { List_pushBack(list, ep->path); } } if (!list->first) { List_destroy(list); return NULL; } return list; } void EpisodeList_play(struct EpisodeList* this, const char* baseUrl, List* playList) { if (!playList) { return; } char* jsonResponse = EpisodeList_toJsonString(playList); /* size_t jsonResponse_lenght = strlen(jsonResponse); */ char url[2048]; sprintf(url, "%s/api/player/setPlaylist", baseUrl); CURL* handle = curl_easy_init(); struct CurlResult userdata; CurlResult_init(&userdata); curl_easy_setopt(handle, CURLOPT_URL, url); curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15); curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &userdata); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, CurlResult_write); curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "POST"); /* curl_easy_setopt(handle, CURLOPT_HTTPPOST, true); */ curl_easy_setopt(handle, CURLOPT_POSTFIELDS, jsonResponse); /* curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, jsonResponse_lenght); */ curl_easy_perform(handle); /* json_value* json = CurlResult_parse(&userdata); */ printw(userdata.buffer.buffer); CurlResult_destroyMembers(&userdata); curl_easy_cleanup(handle); List_destroy(playList); } void Episode_init(struct Episode* this) { this->path = NULL; this->number = EPISODE_INVALID; this->numberStr = NULL; this->releaseGroup = NULL; this->episodeName = NULL; this->watched = false; } void Episode_destroyMembers(struct Episode* this) { if (this->path) { free(this->path); } if (this->numberStr) { free(this->numberStr); } } DEFAULT_CREATE_DESTROY(Episode) /* void Episode_draw(struct Episode* this, WINDOW* window) { */ /* wprintw() */ /* } */ struct Episode* Episode_restore(json_value* json) { if (json->type != json_object) { return NULL; } struct Episode* this = Episode_create(); for (int i=0; i < json->u.object.length; ++i) { const char* key = json->u.object.values[i].name; json_value* value = json->u.object.values[i].value; if (0 == strcmp(key, "path") && value->type == json_string) { this->path = copy_string(value->u.string.ptr, value->u.string.length); } else if (0 == strcmp(key, "releaseGroup") && value->type == json_string) { this->releaseGroup = copy_string(value->u.string.ptr, value->u.string.length); } else if (0 == strcmp(key, "episodeName") && value->type == json_string) { this->episodeName = copy_string(value->u.string.ptr, value->u.string.length); } else if (0 == strcmp(key, "episodeNumber") && value->type == json_string) { this->numberStr = copy_string(value->u.string.ptr, value->u.string.length); } else if (0 == strcmp(key, "numericEpisodeNumber")) { this->number = value->type == json_double ? value->u.dbl : value->type == json_integer ? value->u.integer : EPISODE_INVALID; } else if (0 == strcmp(key, "watched") && value->type == json_boolean) { this->watched = value->u.boolean; } } return this; } int Episode_compare(void* av, void* bv) { struct Episode* a = av; struct Episode* b = bv; if (a->number < 0 && b->number >= 0) { return 1; } if (b->number < 0 && a->number >= 0) { return -1; } if (a->number != b->number) { if (a->number < -1 && b->number >= -1) { return 1; } if (b->number < -1 && a->number >= -1) { return -1; } return a->number < b->number ? -1 : a->number > b->number ? 1 : 0; } int strNumCmp = strcmp(a->numberStr, b->numberStr); int strNum = strNumCmp < 0 ? -1 : strNumCmp > 0 ? 1 : 0; if (strNum != 0) { return strNum; } int epNameCmp = strcmp(a->episodeName, b->episodeName); return epNameCmp < 0 ? -1 : epNameCmp > 0 ? 1 : 0; }