aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-09 03:35:56 +0200
committerdec05eba <dec05eba@protonmail.com>2019-08-09 03:36:07 +0200
commit73b077835dc6085c2642451fa7dbde629b9eadfc (patch)
treed6abfaae58f9ee918fda556b36a8078825cb2799 /src
parente061971e5f1dee5a6e1541bc88a192e9ca8e9422 (diff)
Readd video seek, make search asynchronous
Diffstat (limited to 'src')
-rw-r--r--src/QuickMedia.cpp158
-rw-r--r--src/SearchBar.cpp1
-rw-r--r--src/VideoPlayer.cpp188
-rw-r--r--src/plugins/Manganelo.cpp6
-rw-r--r--src/plugins/Plugin.cpp6
-rw-r--r--src/plugins/Youtube.cpp14
6 files changed, 261 insertions, 112 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index cb58a1d..32e0b2d 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -16,7 +16,6 @@
#include <cmath>
#include <string.h>
#include <X11/Xlib.h>
-#include <X11/Xatom.h>
#include <signal.h>
const sf::Color front_color(43, 45, 47);
@@ -70,15 +69,6 @@ namespace QuickMedia {
return search_result;
}
- static void update_search_suggestions(const sf::String &text, Body *body, Plugin *plugin) {
- body->clear_items();
- if(text.isEmpty())
- return;
-
- SuggestionResult suggestion_result = plugin->update_search_suggestions(text, body->items);
- body->clamp_selection();
- }
-
static void usage() {
fprintf(stderr, "usage: QuickMedia <plugin>\n");
fprintf(stderr, "OPTIONS:\n");
@@ -216,8 +206,10 @@ namespace QuickMedia {
}
void Program::search_suggestion_page() {
- search_bar->onTextUpdateCallback = [this](const std::string &text) {
- update_search_suggestions(text, body, current_plugin);
+ std::string update_search_text;
+ bool search_running = false;
+ search_bar->onTextUpdateCallback = [&update_search_text](const std::string &text) {
+ update_search_text = text;
};
search_bar->onTextSubmitCallback = [this](const std::string &text) {
@@ -273,6 +265,23 @@ namespace QuickMedia {
search_bar->update();
+ if(!update_search_text.empty() && !search_running) {
+ search_suggestion_future = std::async(std::launch::async, [this, update_search_text]() {
+ BodyItems result;
+ SuggestionResult suggestion_result = current_plugin->update_search_suggestions(update_search_text, result);
+ return result;
+ });
+ update_search_text.clear();
+ search_running = true;
+ }
+
+ if(search_running && search_suggestion_future.valid() && search_suggestion_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ body->clear_items();
+ body->items = search_suggestion_future.get();
+ body->clamp_selection();
+ search_running = false;
+ }
+
window.clear(back_color);
body->draw(window, body_pos, body_size);
search_bar->draw(window);
@@ -353,27 +362,39 @@ namespace QuickMedia {
throw std::runtime_error("Failed to open display to X11 server");
XDisplayScope display_scope(disp);
- #if 0
- sf::RenderWindow video_window(sf::VideoMode(300, 300), "QuickMedia Video Player");
- video_window.setVerticalSyncEnabled(true);
- XReparentWindow(disp, video_window.getSystemHandle(), window.getSystemHandle(), 0, 0);
- XMapWindow(disp, video_window.getSystemHandle());
- XSync(disp, False);
- video_window.setSize(sf::Vector2u(400, 300));
- #endif
+ std::unique_ptr<sf::RenderWindow> video_player_ui_window;
+ auto on_window_create = [disp, &video_player_ui_window](sf::WindowHandle video_player_window) {
+ int screen = DefaultScreen(disp);
+ Window ui_window = XCreateWindow(disp, RootWindow(disp, screen),
+ 0, 0, 1, 1, 0,
+ DefaultDepth(disp, screen),
+ InputOutput,
+ DefaultVisual(disp, screen),
+ 0, NULL);
+
+ XReparentWindow(disp, ui_window, video_player_window, 0, 0);
+ XMapWindow(disp, ui_window);
+ XFlush(disp);
+
+ video_player_ui_window = std::make_unique<sf::RenderWindow>(ui_window);
+ };
// This variable is needed because calling play_video is not possible in onPlaybackEndedCallback
bool play_next_video = false;
+ bool ui_resize = true;
std::unique_ptr<VideoPlayer> video_player;
- auto play_video = [this, &video_player, &play_next_video]() {
+ auto play_video = [this, &video_player, &play_next_video, &on_window_create, &video_player_ui_window, &ui_resize]() {
printf("Playing video: %s\n", content_url.c_str());
watched_videos.insert(content_url);
- video_player = std::make_unique<VideoPlayer>([this, &play_next_video](const char *event_name) {
+ video_player = std::make_unique<VideoPlayer>([this, &play_next_video, &video_player_ui_window, &ui_resize](const char *event_name) {
if(strcmp(event_name, "end-file") == 0) {
+ video_player_ui_window = nullptr;
+ ui_resize = true;
+
std::string new_video_url;
- std::vector<std::unique_ptr<BodyItem>> related_media = current_plugin->get_related_media(content_url);
+ BodyItems related_media = current_plugin->get_related_media(content_url);
// Find video that hasn't been played before in this video session
for(auto it = related_media.begin(), end = related_media.end(); it != end; ++it) {
if(watched_videos.find((*it)->url) == watched_videos.end()) {
@@ -394,7 +415,7 @@ namespace QuickMedia {
// TODO: This doesn't seem to work correctly right now, it causes video to become black when changing video (context reset bug).
//video_player->load_file(video_url);
}
- });
+ }, on_window_create);
VideoPlayer::Error err = video_player->load_video(content_url.c_str(), window.getSystemHandle());
if(err != VideoPlayer::Error::OK) {
@@ -406,11 +427,18 @@ namespace QuickMedia {
};
play_video();
+ auto on_doubleclick = []() {
+ // TODO: Toggle fullscreen of video here
+ };
+
sf::Clock time_since_last_left_click;
int left_click_counter;
sf::Event event;
- sf::RectangleShape rect(sf::Vector2f(500, 500));
+ sf::RectangleShape rect;
+ rect.setFillColor(sf::Color::Red);
+ sf::Clock get_progress_timer;
+ double progress = 0.0;
while (current_page == Page::VIDEO_CONTENT) {
if(play_next_video) {
@@ -421,38 +449,16 @@ namespace QuickMedia {
while (window.pollEvent(event)) {
base_event_handler(event, Page::SEARCH_SUGGESTION);
if(event.type == sf::Event::Resized) {
- //video_window.setSize(sf::Vector2u(event.size.width, event.size.height));
- } else if(event.key.code == sf::Keyboard::Space) {
+ if(video_player_ui_window)
+ ui_resize = true;
+ } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) {
if(video_player->toggle_pause() != VideoPlayer::Error::OK) {
fprintf(stderr, "Failed to toggle pause!\n");
}
- }
- }
-
- #if 0
- while(video_window.pollEvent(event)) {
- if (event.type == sf::Event::Closed) {
- current_page = Page::EXIT;
- } else if(event.type == sf::Event::Resized) {
- sf::FloatRect visible_area(0, 0, event.size.width, event.size.height);
- video_window.setView(sf::View(visible_area));
- } else if(event.type == sf::Event::KeyPressed) {
- if(event.key.code == sf::Keyboard::Escape) {
- current_page = Page::SEARCH_SUGGESTION;
- return;
- }
-
- if(event.key.code == sf::Keyboard::Space) {
- if(video_player.toggle_pause() != VideoPlayer::Error::OK) {
- fprintf(stderr, "Failed to toggle pause!\n");
- }
- }
- }
-
- if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
+ } else if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
if(time_since_last_left_click.restart().asMilliseconds() <= DOUBLE_CLICK_TIME) {
if(++left_click_counter == 2) {
- //on_doubleclick();
+ on_doubleclick();
left_click_counter = 0;
}
} else {
@@ -460,21 +466,57 @@ namespace QuickMedia {
}
}
}
- #endif
+
+ if(video_player_ui_window) {
+ while(video_player_ui_window->pollEvent(event)) {
+ if(event.type == sf::Event::Resized) {
+ sf::FloatRect visible_area(0, 0, event.size.width, event.size.height);
+ video_player_ui_window->setView(sf::View(visible_area));
+ }
+ }
+ }
VideoPlayer::Error update_err = video_player->update();
if(update_err == VideoPlayer::Error::FAIL_TO_CONNECT_TIMEOUT) {
show_notification("Video player", "Failed to connect to mpv ipc after 5 seconds", Urgency::CRITICAL);
current_page = Page::SEARCH_SUGGESTION;
return;
+ } else if(update_err != VideoPlayer::Error::OK) {
+ show_notification("Video player", "Unexpected error while updating", Urgency::CRITICAL);
+ current_page = Page::SEARCH_SUGGESTION;
+ return;
}
- window.clear();
- window.display();
-
// TODO: Show loading video animation
- //video_window.clear(sf::Color::Red);
- //video_window.display();
+ //window.clear();
+ //window.display();
+
+ if(get_progress_timer.getElapsedTime().asMilliseconds() >= 500) {
+ get_progress_timer.restart();
+ video_player->get_progress(&progress);
+ }
+
+ if(video_player_ui_window) {
+ const float ui_height = window_size.y * 0.01f;
+ if(ui_resize) {
+ ui_resize = false;
+ video_player_ui_window->setSize(sf::Vector2u(window_size.x, ui_height));
+ video_player_ui_window->setPosition(sf::Vector2i(0, window_size.y - ui_height));
+ }
+
+ // TODO: Make window transparent, so the ui overlay for the video has transparency
+ video_player_ui_window->clear(sf::Color(33, 33, 33));
+ rect.setSize(sf::Vector2f(window_size.x * progress, window_size.y * 0.01));
+ video_player_ui_window->draw(rect);
+ video_player_ui_window->display();
+
+ if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
+ auto mouse_pos = sf::Mouse::getPosition(window);
+ if(mouse_pos.y >= window_size.y - ui_height) {
+ video_player->set_progress((double)mouse_pos.x / (double)window_size.x);
+ }
+ }
+ }
}
}
diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp
index 1094883..b967224 100644
--- a/src/SearchBar.cpp
+++ b/src/SearchBar.cpp
@@ -31,6 +31,7 @@ namespace QuickMedia {
void SearchBar::update() {
if(updated_search && time_since_search_update.getElapsedTime().asMilliseconds() >= text_autosearch_delay) {
+ time_since_search_update.restart();
updated_search = false;
sf::String str = text.getString();
if(show_placeholder)
diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp
index e1c8f73..0e6735a 100644
--- a/src/VideoPlayer.cpp
+++ b/src/VideoPlayer.cpp
@@ -2,6 +2,7 @@
#include "../include/Program.h"
#include <string>
#include <json/reader.h>
+#include <memory>
#include <assert.h>
#include <sys/socket.h>
@@ -11,18 +12,29 @@
#include <signal.h>
const int RETRY_TIME_MS = 1000;
-const int MAX_RETRIES = 5;
+const int MAX_RETRIES_CONNECT = 5;
+const int MAX_RETRIES_FIND_WINDOW = 10;
+const int READ_TIMEOUT_MS = 200;
namespace QuickMedia {
- VideoPlayer::VideoPlayer(EventCallbackFunc _event_callback) :
+ VideoPlayer::VideoPlayer(EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback) :
video_process_id(-1),
ipc_socket(-1),
connected_to_ipc(false),
connect_tries(0),
+ find_window_tries(0),
event_callback(_event_callback),
- alive(true)
+ window_create_callback(_window_create_callback),
+ window_handle(0),
+ parent_window(0),
+ display(nullptr),
+ request_id(1),
+ expected_request_id(0),
+ request_response_data(Json::nullValue)
{
-
+ display = XOpenDisplay(NULL);
+ if (!display)
+ throw std::runtime_error("Failed to open display to X11 server");
}
VideoPlayer::~VideoPlayer() {
@@ -35,12 +47,13 @@ namespace QuickMedia {
if(video_process_id != -1)
remove(ipc_server_path);
- alive = false;
- if(event_read_thread.joinable())
- event_read_thread.join();
+ if(display)
+ XCloseDisplay(display);
}
- VideoPlayer::Error VideoPlayer::launch_video_process(const char *path, sf::WindowHandle parent_window) {
+ VideoPlayer::Error VideoPlayer::launch_video_process(const char *path, sf::WindowHandle _parent_window) {
+ parent_window = _parent_window;
+
if(!tmpnam(ipc_server_path)) {
perror("Failed to generate ipc file name");
return Error::FAIL_TO_GENERATE_IPC_FILENAME;
@@ -49,7 +62,7 @@ namespace QuickMedia {
const std::string parent_window_str = std::to_string(parent_window);
const char *args[] = { "mpv", /*"--keep-open=yes", "--keep-open-pause=no",*/ "--input-ipc-server", ipc_server_path,
"--no-config", "--no-input-default-bindings", "--input-vo-keyboard=no", "--no-input-cursor",
- "--cache-secs=120", "--demuxer-max-bytes=20M", "--demuxer-max-back-bytes=10M",
+ "--cache-secs=120", "--demuxer-max-bytes=40M", "--demuxer-max-back-bytes=20M",
/*"--vo=gpu", "--hwdec=auto",*/
"--wid", parent_window_str.c_str(), "--", path, nullptr };
if(exec_program_async(args, &video_process_id) != 0)
@@ -71,40 +84,84 @@ namespace QuickMedia {
return Error::OK;
}
- VideoPlayer::Error VideoPlayer::load_video(const char *path, sf::WindowHandle parent_window) {
+ VideoPlayer::Error VideoPlayer::load_video(const char *path, sf::WindowHandle _parent_window) {
+ // This check is to make sure we dont change window that the video belongs to. This is not a usecase we will have so
+ // no need to support it for not at least.
+ assert(parent_window == 0 || parent_window == _parent_window);
if(video_process_id == -1)
- return launch_video_process(path, parent_window);
+ return launch_video_process(path, _parent_window);
std::string cmd = "loadfile ";
cmd += path;
return send_command(cmd.c_str(), cmd.size());
}
+ static std::vector<Window> get_child_window(Display *display, Window window) {
+ std::vector<Window> result;
+ Window root_window;
+ Window parent_window;
+ Window *child_window;
+ unsigned int num_children;
+ if(XQueryTree(display, window, &root_window, &parent_window, &child_window, &num_children) != 0) {
+ for(unsigned int i = 0; i < num_children; i++)
+ result.push_back(child_window[i]);
+ }
+ return result;
+ }
+
VideoPlayer::Error VideoPlayer::update() {
if(ipc_socket == -1)
return Error::INIT_FAILED;
- if(connect_tries == MAX_RETRIES)
+ if(connect_tries == MAX_RETRIES_CONNECT)
return Error::FAIL_TO_CONNECT_TIMEOUT;
- if(!connected_to_ipc && ipc_connect_retry_timer.getElapsedTime().asMilliseconds() >= RETRY_TIME_MS) {
+ if(find_window_tries == MAX_RETRIES_FIND_WINDOW)
+ return Error::FAIL_TO_FIND_WINDOW;
+
+ if(!connected_to_ipc && retry_timer.getElapsedTime().asMilliseconds() >= RETRY_TIME_MS) {
+ retry_timer.restart();
if(connect(ipc_socket, (struct sockaddr*)&ipc_addr, sizeof(ipc_addr)) == -1) {
++connect_tries;
- if(connect_tries == MAX_RETRIES) {
- fprintf(stderr, "Failed to connect to mpv ipc after 5 seconds, last error: %s\n", strerror(errno));
+ if(connect_tries == MAX_RETRIES_CONNECT) {
+ fprintf(stderr, "Failed to connect to mpv ipc after %d seconds, last error: %s\n", RETRY_TIME_MS * MAX_RETRIES_CONNECT, strerror(errno));
return Error::FAIL_TO_CONNECT_TIMEOUT;
}
} else {
connected_to_ipc = true;
- if(event_callback)
- event_read_thread = std::thread(&VideoPlayer::read_ipc_func, this);
}
}
+ if(connected_to_ipc && window_handle == 0 && retry_timer.getElapsedTime().asMilliseconds() >= RETRY_TIME_MS) {
+ retry_timer.restart();
+ std::vector<Window> child_windows = get_child_window(display, parent_window);
+ size_t num_children = child_windows.size();
+ if(num_children == 0) {
+ ++find_window_tries;
+ if(find_window_tries == MAX_RETRIES_FIND_WINDOW) {
+ fprintf(stderr, "Failed to find mpv window after %d seconds\n", RETRY_TIME_MS * MAX_RETRIES_FIND_WINDOW);
+ return Error::FAIL_TO_FIND_WINDOW_TIMEOUT;
+ }
+ } else if(num_children == 1) {
+ window_handle = child_windows[0];
+ if(window_create_callback)
+ window_create_callback(window_handle);
+ } else {
+ fprintf(stderr, "Expected window to have one child (the video player) but it has %zu\n", num_children);
+ return Error::UNEXPECTED_WINDOW_ERROR;
+ }
+ }
+
+ if(connected_to_ipc && event_callback) {
+ Error err = read_ipc_func();
+ if(err != Error::OK)
+ return err;
+ }
+
return Error::OK;
}
- void VideoPlayer::read_ipc_func() {
+ VideoPlayer::Error VideoPlayer::read_ipc_func() {
assert(connected_to_ipc);
assert(event_callback);
@@ -114,35 +171,35 @@ namespace QuickMedia {
std::string json_errors;
char buffer[2048];
- while(alive) {
- ssize_t bytes_read = read(ipc_socket, buffer, sizeof(buffer));
- if(bytes_read == -1) {
- int err = errno;
- if(err == EAGAIN) {
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ ssize_t bytes_read = read(ipc_socket, buffer, sizeof(buffer));
+ if(bytes_read == -1) {
+ int err = errno;
+ if(err != EAGAIN) {
+ fprintf(stderr, "Failed to read from ipc socket, error: %s\n", strerror(err));
+ return Error::FAIL_TO_READ;
+ }
+ } else if(bytes_read > 0) {
+ int start = 0;
+ for(int i = 0; i < bytes_read; ++i) {
+ if(buffer[i] != '\n')
continue;
- }
- fprintf(stderr, "Failed to read from ipc socket, error: %s\n", strerror(err));
- break;
- } else if(bytes_read > 0) {
- int start = 0;
- for(int i = 0; i < bytes_read; ++i) {
- if(buffer[i] != '\n')
- continue;
-
- if(json_reader->parse(buffer + start, buffer + i, &json_root, &json_errors)) {
- const Json::Value &event = json_root["event"];
- if(event.isString())
- event_callback(event.asCString());
- } else {
- fprintf(stderr, "Failed to parse json for ipc: |%.*s|, reason: %s\n", (int)bytes_read, buffer, json_errors.c_str());
+ if(json_reader->parse(buffer + start, buffer + i, &json_root, &json_errors)) {
+ const Json::Value &event = json_root["event"];
+ const Json::Value &request_id_json = json_root["request_id"];
+ if(event.isString())
+ event_callback(event.asCString());
+ else if(expected_request_id != 0 && request_id_json.isNumeric() && request_id_json.asUInt() == expected_request_id) {
+ request_response_data = json_root["data"];
}
-
- start = i + 1;
+ } else {
+ fprintf(stderr, "Failed to parse json for ipc: |%.*s|, reason: %s\n", (int)bytes_read, buffer, json_errors.c_str());
}
+
+ start = i + 1;
}
}
+ return Error::OK;
}
VideoPlayer::Error VideoPlayer::toggle_pause() {
@@ -150,6 +207,55 @@ namespace QuickMedia {
return send_command(cmd, sizeof(cmd) - 1);
}
+ VideoPlayer::Error VideoPlayer::get_progress(double *result) {
+ unsigned int cmd_request_id = request_id;
+ ++request_id;
+ // Overflow check. 0 is defined as no request, 1 is the first valid one
+ if(request_id == 0)
+ request_id = 1;
+
+ std::string cmd = "{ \"command\": [\"get_property\", \"percent-pos\"], \"request_id\": ";
+ cmd += std::to_string(cmd_request_id) + " }\n";
+ Error err = send_command(cmd.c_str(), cmd.size());
+ if(err != Error::OK)
+ return err;
+
+ sf::Clock read_timer;
+ expected_request_id = cmd_request_id;
+ do {
+ err = read_ipc_func();
+ if(err != Error::OK)
+ goto cleanup;
+
+ if(!request_response_data.isNull())
+ break;
+ } while(read_timer.getElapsedTime().asMilliseconds() < READ_TIMEOUT_MS);
+
+ if(request_response_data.isNull()) {
+ err = Error::READ_TIMEOUT;
+ goto cleanup;
+ }
+
+ if(!request_response_data.isDouble()) {
+ fprintf(stderr, "Read: expected to receive data of type double for request id %u, was type %s\n", cmd_request_id, "TODO: Fill type here");
+ err = Error::READ_INCORRECT_TYPE;
+ goto cleanup;
+ }
+
+ *result = request_response_data.asDouble() * 0.01;
+
+ cleanup:
+ expected_request_id = 0;
+ request_response_data = Json::Value(Json::nullValue);
+ return err;
+ }
+
+ VideoPlayer::Error VideoPlayer::set_progress(double progress) {
+ std::string cmd = "{ \"command\": [\"set_property\", \"percent-pos\", ";
+ cmd += std::to_string(progress * 100.0) + "] }";
+ return send_command(cmd.c_str(), cmd.size());
+ }
+
VideoPlayer::Error VideoPlayer::send_command(const char *cmd, size_t size) {
if(!connected_to_ipc)
return Error::FAIL_NOT_CONNECTED;
diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp
index e91baf0..ec522d2 100644
--- a/src/plugins/Manganelo.cpp
+++ b/src/plugins/Manganelo.cpp
@@ -3,7 +3,7 @@
#include <json/reader.h>
namespace QuickMedia {
- SearchResult Manganelo::search(const std::string &url, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ SearchResult Manganelo::search(const std::string &url, BodyItems &result_items) {
std::string website_data;
if(download_to_string(url, website_data) != DownloadResult::OK)
return SearchResult::NET_ERR;
@@ -15,7 +15,7 @@ namespace QuickMedia {
result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='chapter-list']/div[class='row']//a",
[](QuickMediaHtmlNode *node, void *userdata) {
- auto *item_data = (std::vector<std::unique_ptr<BodyItem>>*)userdata;
+ auto *item_data = (BodyItems*)userdata;
const char *href = quickmedia_html_node_get_attribute_value(node, "href");
const char *text = quickmedia_html_node_get_text(node);
if(href && text) {
@@ -50,7 +50,7 @@ namespace QuickMedia {
return true;
}
- SuggestionResult Manganelo::update_search_suggestions(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ SuggestionResult Manganelo::update_search_suggestions(const std::string &text, BodyItems &result_items) {
std::string url = "https://manganelo.com/home_json_search";
std::string search_term = "searchword=";
search_term += url_param_encode(text);
diff --git a/src/plugins/Plugin.cpp b/src/plugins/Plugin.cpp
index 5d81aad..79c6403 100644
--- a/src/plugins/Plugin.cpp
+++ b/src/plugins/Plugin.cpp
@@ -10,19 +10,19 @@ static int accumulate_string(char *data, int size, void *userdata) {
}
namespace QuickMedia {
- SearchResult Plugin::search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ SearchResult Plugin::search(const std::string &text, BodyItems &result_items) {
(void)text;
(void)result_items;
return SearchResult::OK;
}
- SuggestionResult Plugin::update_search_suggestions(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ SuggestionResult Plugin::update_search_suggestions(const std::string &text, BodyItems &result_items) {
(void)text;
(void)result_items;
return SuggestionResult::OK;
}
- std::vector<std::unique_ptr<BodyItem>> Plugin::get_related_media(const std::string &url) {
+ BodyItems Plugin::get_related_media(const std::string &url) {
(void)url;
return {};
}
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index 2a3f011..56e8574 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -12,7 +12,7 @@ namespace QuickMedia {
return strstr(str, substr);
}
- static void iterate_suggestion_result(const Json::Value &value, std::vector<std::unique_ptr<BodyItem>> &result_items, int &iterate_count) {
+ static void iterate_suggestion_result(const Json::Value &value, BodyItems &result_items, int &iterate_count) {
++iterate_count;
if(value.isArray()) {
for(const Json::Value &child : value) {
@@ -26,7 +26,7 @@ namespace QuickMedia {
}
// TODO: Speed this up by using string.find instead of parsing html
- SuggestionResult Youtube::update_search_suggestions(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ SuggestionResult Youtube::update_search_suggestions(const std::string &text, BodyItems &result_items) {
// Keep this for backup. This is using search suggestion the same way youtube does it, but the results
// are not as good as doing an actual search.
#if 0
@@ -79,7 +79,7 @@ namespace QuickMedia {
return SuggestionResult::NET_ERR;
struct ItemData {
- std::vector<std::unique_ptr<BodyItem>> *result_items;
+ BodyItems *result_items;
size_t index;
};
ItemData item_data = { &result_items, 0 };
@@ -91,7 +91,7 @@ namespace QuickMedia {
result = quickmedia_html_find_nodes_xpath(&html_search, "//h3[class=\"yt-lockup-title\"]/a",
[](QuickMediaHtmlNode *node, void *userdata) {
- auto *result_items = (std::vector<std::unique_ptr<BodyItem>>*)userdata;
+ auto *result_items = (BodyItems*)userdata;
const char *href = quickmedia_html_node_get_attribute_value(node, "href");
const char *title = quickmedia_html_node_get_attribute_value(node, "title");
// Checking for watch?v helps skipping ads
@@ -127,8 +127,8 @@ namespace QuickMedia {
return result == 0 ? SuggestionResult::OK : SuggestionResult::ERR;
}
- std::vector<std::unique_ptr<BodyItem>> Youtube::get_related_media(const std::string &url) {
- std::vector<std::unique_ptr<BodyItem>> result_items;
+ BodyItems Youtube::get_related_media(const std::string &url) {
+ BodyItems result_items;
std::string website_data;
if(download_to_string(url, website_data) != DownloadResult::OK)
@@ -141,7 +141,7 @@ namespace QuickMedia {
result = quickmedia_html_find_nodes_xpath(&html_search, "//ul[class=\"video-list\"]//div[class=\"content-wrapper\"]/a",
[](QuickMediaHtmlNode *node, void *userdata) {
- auto *result_items = (std::vector<std::unique_ptr<BodyItem>>*)userdata;
+ auto *result_items = (BodyItems*)userdata;
const char *href = quickmedia_html_node_get_attribute_value(node, "href");
// TODO: Also add title for related media
if(href && begins_with(href, "/watch?v=")) {