#include #include "Player.h" #include "CurlResult.h" void Player_init(struct Player* this) { int x, y; getmaxyx(stdscr, y,x); this->window = newwin(PLAYER_H, x, y-PLAYER_H, 0); this->paused = true; this->progress.duration = 0; this->progress.current = 0; } void Player_destroyMembers(struct Player* this) { } bool Player_handleInput(struct Player* this, int event) { if (event == 's' || event == 'c') { Player_stop(this->baseUrl); } else if (event == '>') { Player_moveForwards(this->baseUrl); } else if (event == '<') { Player_moveBackwards(this->baseUrl); } else if (event == ' ') { Player_togglePause(this->baseUrl); } else if (event == KEY_RESIZE) { int screenX, screenY; getmaxyx(stdscr, screenY, screenX); mvwin(this->window, screenY-PLAYER_H, 0); wresize(this->window, PLAYER_H, screenX); } else { return false; } return true; } void Player_draw(struct Player* this) { /* refresh(); */ /* int oldX, oldY; */ /* getyx(shows.window, oldY, oldX); */ /* refresh(); */ int screenW = getmaxx(this->window); wmove(this->window, 0,0); wprintw(this->window, "■ (c) "); wprintw(this->window, "<<(<) "); wprintw(this->window, this->paused ? "▶ " : "||"); wprintw(this->window, "( ) "); wprintw(this->window, ">>(>)"); /* draw progress bar */ if (this->paused) { this->progress.lastUpdate = time(NULL); } else { time_t now = time(NULL); double diff = difftime(now, this->progress.lastUpdate); if (diff > 0) { this->progress.current += diff; this->progress.lastUpdate = now; } } int x = sizeof("■ (c) " "<<(<) " "||" "( ) " ">>(>)")-1; int w = (screenW - x - 2 > 1) ? (screenW - x - 2) : 1; wprintw(this->window, " ["); float percent = this->progress.duration != 0 ? (float)this->progress.current / (float)this->progress.duration : 0.5f; for (int i=0; i < w; ++i) { float p = (float)i / (float)w; float nextP = (float)(i+1) / (float)w; if (p <= percent) { if (nextP <= percent) { wprintw(this->window, "="); } else { wprintw(this->window, "O"); } } else { wprintw(this->window, "─"); } } wprintw(this->window, "]"); /* wprintw(this->window, "================="); */ wrefresh(this->window); } void Player_simpleCommand(const char* baseUrl, const char* pathUrl) { char url[2048]; sprintf(url, "%s%s", baseUrl, pathUrl); struct CurlResult userdata; CURL* handle = Curl_defaultHandle(url, &userdata); curl_easy_perform(handle); CurlResult_destroyMembers(&userdata); curl_easy_cleanup(handle); } void Player_stop(const char* baseUrl) { Player_simpleCommand(baseUrl, "/api/player/stop"); } void Player_togglePause(const char* baseUrl) { Player_simpleCommand(baseUrl, "/api/player/togglePause"); } void Player_moveBackwards(const char* baseUrl) { Player_simpleCommand(baseUrl, "/api/player/backwards"); } void Player_moveForwards(const char* baseUrl) { Player_simpleCommand(baseUrl, "/api/player/forwards"); } void restoreMetadata(struct Player* this, json_value* json) { if (!json || json->type != json_object) { return; } for (int j=0; j < json->u.object.length; ++j) { char* mItemName = json->u.object.values[j].name; json_value* mValue = json->u.object.values[j].value; if (0 == strcmp(mItemName, "duration") && mValue->type == json_integer) { this->progress.duration = mValue->u.integer; } } } void Player_onServerEvent(const char* event, const char* data, void* userdata) { struct Player* this = userdata; if (0 == strcmp(event, "playbackStarted")) { json_value* json = json_parse(data, strlen(data)); if (json && json->type == json_object) { for (int i=0; i < json->u.object.length; ++i) { char* itemName = json->u.object.values[i].name; json_value* itemValue = json->u.object.values[i].value; if (0 == strcmp(itemName, "metaData") && itemValue->type == json_object) { restoreMetadata(this, itemValue); } else if (0 == strcmp(itemName, "seconds") && itemValue->type == json_integer) { this->progress.current = itemValue->u.integer; } } } this->paused = false; this->progress.lastUpdate = time(NULL); } else if (0 == strcmp(event, "playbackEnded")) { this->paused = true; this->progress.duration = 0; this->progress.current = 0; this->progress.lastUpdate = time(NULL); } else if (0 == strcmp(event, "paused")) { this->paused = true; this->progress.lastUpdate = time(NULL); } else if (0 == strcmp(event, "unpaused")) { this->paused = false; this->progress.lastUpdate = time(NULL); } else if (0 == strcmp(event, "jumped")) { /* {"seconds":3} */ json_value* json = json_parse(data, strlen(data)); if (json && json->type == json_object) { for (int i=0; i < json->u.object.length; ++i) { char* itemName = json->u.object.values[i].name; json_value* itemValue = json->u.object.values[i].value; if (0 == strcmp(itemName, "seconds") && itemValue->type == json_integer) { this->progress.current = itemValue->u.integer; } } } this->progress.lastUpdate = time(NULL); } Player_draw(this); } void restorePauseStatus(struct Player* this, json_value* json) { if (!json || json->type != json_object) { return; } for (int j=0; j < json->u.object.length; ++j) { char* mItemName = json->u.object.values[j].name; json_value* mValue = json->u.object.values[j].value; if (0 == strcmp(mItemName, "status") && mValue->type == json_string) { this->paused = 0 == strncmp("paused", mValue->u.string.ptr, sizeof("paused")-1); } } } void restoreProgress(struct Player* this, json_value* json) { if (!json || json->type != json_object) { return; } for (int j=0; j < json->u.object.length; ++j) { char* mItemName = json->u.object.values[j].name; json_value* mValue = json->u.object.values[j].value; if (0 == strcmp(mItemName, "seconds") && mValue->type == json_integer) { this->progress.current = mValue->u.integer; } } } void fetchGeneric(struct Player* this, const char* pathUrl, void (*restoreFn)(struct Player*,json_value*)) { char url[2048]; sprintf(url, "%s%s", this->baseUrl, pathUrl); struct CurlResult userdata; CURL* handle = Curl_defaultHandle(url, &userdata); curl_easy_perform(handle); json_value* json = CurlResult_parse(&userdata); restoreFn(this, json); json_value_free(json); CurlResult_destroyMembers(&userdata); curl_easy_cleanup(handle); } void fetchMetadata(struct Player* this) { fetchGeneric(this, "/api/player/metaData", restoreMetadata); } void fetchPauseStatus(struct Player* this) { fetchGeneric(this, "/api/player/pauseStatus", restorePauseStatus); } void fetchProgress(struct Player* this) { fetchGeneric(this, "/api/player/progress", restoreProgress); } void Player_fetch(struct Player* this, const char* url) { this->baseUrl = url; fetchMetadata(this); fetchPauseStatus(this); fetchProgress(this); Player_draw(this); }