#include "EpisodePage.h" #include #include "TvShows.h" #include "Colors.h" #include "utils.h" #include "CurlResult.h" #include "urlcode.h" void EpisodePage_init(struct EpisodePage* this) { this->name = NULL; this->startPage = NULL; this->baseUrl = NULL; this->episodes = NULL; this->selectedLi = NULL; int y, x; getmaxyx(stdscr, y, x); this->window = newwin(y-PLAYER_H, x, 0, 0); } void EpisodePage_destroyMembers(struct EpisodePage* this) { safe_free(this->name); safe_free(this->episodes); } bool EpisodePage_handleInput(struct EpisodePage* this, int c) { if (this != *this->activePage && c != KEY_RESIZE) { return false; } if (c == 'n' || c == 'j' || c == KEY_DOWN) { EpisodePage_selectDelta(this, +1); } else if (c == 'p' || c == 'k' || c == KEY_UP) { EpisodePage_selectDelta(this, -1); } else if (c == PAGE_UP) { EpisodePage_selectDelta(this, -10); } else if (c == PAGE_DOWN || c == '<') { EpisodePage_selectDelta(this, +10); } else if (c == KEY_HOME || c == '>') { EpisodePage_selectFirstOrLast(this, true); } else if (c == KEY_END) { EpisodePage_selectFirstOrLast(this, false); } else if (c == 'b' || c == 'h' || c == KEY_LEFT) { *this->activePage = this->startPage; wclear(this->startPage->window); TvShows_printAll(this->startPage, NULL); /* TODO select chapters */ } else if (c == 'f' || c == 'l' || c == KEY_RIGHT) { /* TODO select chapters */ } else if (c == '/') { // TODO search } else if (c == KEY_ENTER || c == 'a') { EpisodePage_playSelected(this); } else if (c == 'u') { if (this->episodes || this->name) { EpisodePage_fetch(this, (this->name ? this->name : this->episodes->name)); } } else if (c == '+' || c == '-' || c == 't') { EpisodePage_toggleWatchedLi(this); } else if (c == KEY_RESIZE) { int screenX, screenY; getmaxyx(stdscr, screenY, screenX); wresize(this->window, screenY-PLAYER_H, screenX); EpisodePage_draw(this); return false; } else { return false; } EpisodePage_draw(this); return true; } void EpisodePage_draw(struct EpisodePage* this) { if (this != *this->activePage) { return; } wclear(this->window); wmove(this->window, 0, 0); wprintw(this->window, "Episode list"); if (!this->episodes) { return; } int y = 1; int screenY = getmaxy(stdscr); for (ListNode* it = this->episodes->episodes->first; it; it=it->next) { if (y >= screenY - PLAYER_H) { break; } struct Episode* ep = it->data; EpisodePage_drawEpisode(this, ep, y); ++y; } wrefresh(this->window); } void EpisodePage_drawEpisode(struct EpisodePage* this, struct Episode* ep, int y) { char buffer[2048]; char watchedChar = ep->watched ? '+' : '-'; const char* epNameSeparator = strlen(ep->episodeName) > 0 ? " - " : " "; bool isRewatch = this->episodes->rewatchMarker != -1 && (this->episodes->rewatchMarker+1) == ep->number; bool isSelected = this->selectedLi && ep == this->selectedLi->data; if (isRewatch) { Colors_wset(this->window, Colors_Rewatch); } if (isSelected) { Colors_wset(this->window, Colors_Selected); } sprintf(buffer, "%c %s %s%s%s %s -> chapters", watchedChar, ep->numberStr, (this->name ? this->name : ""), epNameSeparator, ep->episodeName, ep->releaseGroup); wmove(this->window, y, 0); wprintw(this->window, buffer); if (isRewatch) { Colors_wset(this->window, Colors_Default); } if (isSelected) { Colors_wset(this->window, Colors_Default); } } void EpisodePage_selectFirstOrLast(struct EpisodePage* this, bool direction) { this->selectedLi = direction ? this->episodes->episodes->first : this->episodes->episodes->last; } void EpisodePage_selectDelta(struct EpisodePage* this, int delta) { if (!this->episodes) { return; } if (!this->selectedLi) { this->selectedLi = this->episodes->episodes->first; return; } while (delta > 0 && this->selectedLi->next) { this->selectedLi = this->selectedLi->next; --delta; } while (delta < 0 && this->selectedLi->previous) { this->selectedLi = this->selectedLi->previous; ++delta; } } void EpisodePage_playSelected(struct EpisodePage* this) { if (this->selectedLi) { List* playlist = List_create(); bool passedCurrent = false; for (ListNode* it = this->episodes->episodes->first; it; it=it->next) { struct Episode* ep = it->data; if (it == this->selectedLi) { passedCurrent = true; } if (passedCurrent) { List_pushBack(playlist, ep->path); } } EpisodeList_play(this->episodes, this->baseUrl, playlist); } else { List* playlist = EpisodeList_contstructPlaylist(this->episodes); EpisodeList_play(this->episodes, this->baseUrl, playlist); } } void EpisodePage_fetch(struct EpisodePage* this, const char* name) { struct EpisodeList* oldList = this->episodes; this->episodes = EpisodeList_fetch(this->baseUrl, name); if (oldList && this->episodes) { /* try to keep selection */ if (this->selectedLi && this->selectedLi->data) { /* const char* path = ((struct Episode*)this->selectedLi->data)->path; */ float number = ((struct Episode*)this->selectedLi->data)->number; ListNode* newLi = NULL; for (ListNode* it = this->episodes->episodes->first; it; it=it->next) { struct Episode* ep = it->data; if (ep && ep->number == number /* 0 == strcmp(path, ep->path) */) { newLi = it; break; } } this->selectedLi = newLi; } EpisodeList_destroy(oldList); } EpisodePage_draw(this); } void EpisodePage_activate(struct EpisodePage* this) { char url[2048]; char* encoded = url_encode(this->name); sprintf(url, "%s/api/assurePage/TvShowPage?%s", this->baseUrl, encoded); struct CurlResult userdata; CURL* handle = Curl_defaultHandle(url, &userdata); curl_easy_perform(handle); CurlResult_destroyMembers(&userdata); curl_easy_cleanup(handle); safe_free(encoded); } void EpisodePage_toggleWatched(const char* baseUrl, const char* path) { struct CurlResult userdata; CurlResult_init(&userdata); char url[1024]; char* encoded = url_encode(path); sprintf(url, "%s/api/library/toggleWatched?%s", baseUrl, encoded); CURL* handle = Curl_defaultHandle(url, &userdata); curl_easy_perform(handle); curl_easy_cleanup(handle); free(encoded); } void EpisodePage_toggleWatchedLi(struct EpisodePage* this) { if (!this->selectedLi) { return; } struct Episode* ep = this->selectedLi->data; EpisodePage_toggleWatched(this->baseUrl, ep->path); ep->watched = !ep->watched; } DEFAULT_CREATE_DESTROY(EpisodePage) void EpisodePage_onServerEvent(const char* event, const char* data, void* userdata) { struct EpisodePage* this = userdata; if (!this->name) { return; } if (0 == strcmp(event, "playbackEnded")) { EpisodePage_fetch(this, this->name); } }