aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--include/Body.hpp2
-rw-r--r--include/QuickMedia.hpp5
-rw-r--r--include/StringUtils.hpp1
-rw-r--r--src/Body.cpp2
-rw-r--r--src/QuickMedia.cpp83
-rw-r--r--src/StringUtils.cpp6
-rw-r--r--src/plugins/Fourchan.cpp11
8 files changed, 74 insertions, 39 deletions
diff --git a/README.md b/README.md
index 3ce0e43..abeaf90 100644
--- a/README.md
+++ b/README.md
@@ -63,4 +63,5 @@ Show list of replies to a comment (for image boards).\
Wrap text that is too long.\
Add greentext support for quotes.\
Add support for special formatting for posts by admins on imageboards.\
-For image boards, track (You)'s and show notification when somebody replies to your post. \ No newline at end of file
+For image boards, track (You)'s and show notification when somebody replies to your post.\
+In image boards when viewing videos, automatically play the next one after the current one has finished playing (just like the youtube plugin does). \ No newline at end of file
diff --git a/include/Body.hpp b/include/Body.hpp
index e727244..a485aac 100644
--- a/include/Body.hpp
+++ b/include/Body.hpp
@@ -29,7 +29,7 @@ namespace QuickMedia {
std::string title;
std::string url;
std::string thumbnail_url;
- std::string fullsize_image_url;
+ std::string attached_content_url;
std::string author;
bool visible;
// Used by image boards for example. The elements are indices to other body items
diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp
index abfe270..9cc85d5 100644
--- a/include/QuickMedia.hpp
+++ b/include/QuickMedia.hpp
@@ -11,6 +11,7 @@
#include <json/value.h>
#include <unordered_set>
#include <future>
+#include <stack>
namespace QuickMedia {
class Plugin;
@@ -44,6 +45,9 @@ namespace QuickMedia {
LoadImageResult load_image_by_index(int image_index, sf::Texture &image_texture, sf::String &error_message);
void download_chapter_images_if_needed(Manganelo *image_plugin);
void select_episode(BodyItem *item, bool start_from_beginning);
+
+ // Returns Page::EXIT if empty
+ Page pop_page_stack();
private:
sf::RenderWindow window;
sf::Vector2f window_size;
@@ -54,6 +58,7 @@ namespace QuickMedia {
sf::Texture plugin_logo;
std::unique_ptr<SearchBar> search_bar;
Page current_page;
+ std::stack<Page> page_stack;
// TODO: Combine these
std::string images_url;
std::string content_title;
diff --git a/include/StringUtils.hpp b/include/StringUtils.hpp
index c6ae244..dd4b99b 100644
--- a/include/StringUtils.hpp
+++ b/include/StringUtils.hpp
@@ -10,4 +10,5 @@ namespace QuickMedia {
void string_split(const std::string &str, char delimiter, StringSplitCallback callback_func);
void string_replace_all(std::string &str, const std::string &old_str, const std::string &new_str);
std::string strip(const std::string &str);
+ bool string_ends_with(const std::string &str, const std::string &ends_with_str);
} \ No newline at end of file
diff --git a/src/Body.cpp b/src/Body.cpp
index be5267a..27e09f9 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -309,7 +309,7 @@ namespace QuickMedia {
if(current_json.isNumeric() && total_json.isNumeric()) {
progress_text.setString(std::string("Page: ") + std::to_string(current_json.asInt()) + "/" + std::to_string(total_json.asInt()));
auto bounds = progress_text.getLocalBounds();
- progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - padding_x), std::floor(item_pos.y));
+ progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - padding_x), std::floor(item_pos.y + padding_y));
window.draw(progress_text);
}
}
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index f3b4b7b..e2fc237 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -434,6 +434,9 @@ namespace QuickMedia {
watched_videos.clear();
if(content_url.empty())
next_page = Page::SEARCH_RESULT;
+ else {
+ page_stack.push(Page::SEARCH_SUGGESTION);
+ }
} else if(next_page == Page::CONTENT_LIST) {
content_list_url = content_url;
} else if(next_page == Page::IMAGE_BOARD_THREAD_LIST) {
@@ -661,6 +664,8 @@ namespace QuickMedia {
search_bar->onTextUpdateCallback = nullptr;
search_bar->onTextSubmitCallback = nullptr;
+ Page previous_page = pop_page_stack();
+
Display* disp = XOpenDisplay(NULL);
if (!disp)
throw std::runtime_error("Failed to open display to X11 server");
@@ -689,18 +694,18 @@ namespace QuickMedia {
std::unique_ptr<VideoPlayer> video_player;
- auto load_video_error_check = [this, &video_player]() {
+ auto load_video_error_check = [this, &video_player, previous_page]() {
watched_videos.insert(content_url);
VideoPlayer::Error err = video_player->load_video(content_url.c_str(), window.getSystemHandle());
if(err != VideoPlayer::Error::OK) {
std::string err_msg = "Failed to play url: ";
err_msg += content_url;
show_notification("Video player", err_msg.c_str(), Urgency::CRITICAL);
- current_page = Page::SEARCH_SUGGESTION;
+ current_page = previous_page;
}
};
- video_player = std::make_unique<VideoPlayer>(current_plugin->use_tor, [this, &video_player, &seekable, &load_video_error_check](const char *event_name) {
+ video_player = std::make_unique<VideoPlayer>(current_plugin->use_tor, [this, &video_player, &seekable, &load_video_error_check, previous_page](const char *event_name) {
bool end_of_file = false;
if(strcmp(event_name, "pause") == 0) {
double time_remaining = 0.0;
@@ -725,7 +730,7 @@ namespace QuickMedia {
// If there are no videos to play, then dont play any...
if(new_video_url.empty()) {
show_notification("Video player", "No more related videos to play");
- current_page = Page::SEARCH_SUGGESTION;
+ current_page = previous_page;
return;
}
@@ -759,7 +764,7 @@ namespace QuickMedia {
while (current_page == Page::VIDEO_CONTENT) {
while (window.pollEvent(event)) {
- base_event_handler(event, Page::SEARCH_SUGGESTION);
+ base_event_handler(event, previous_page);
if(event.type == sf::Event::Resized) {
if(video_player_ui_window)
ui_resize = true;
@@ -798,11 +803,11 @@ namespace QuickMedia {
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;
+ current_page = previous_page;
return;
} else if(update_err != VideoPlayer::Error::OK) {
show_notification("Video player", "Unexpected error while updating", Urgency::CRITICAL);
- current_page = Page::SEARCH_SUGGESTION;
+ current_page = previous_page;
return;
}
@@ -899,6 +904,15 @@ namespace QuickMedia {
}
}
+ Page Program::pop_page_stack() {
+ if(!page_stack.empty()) {
+ Page previous_page = page_stack.top();
+ page_stack.pop();
+ return previous_page;
+ }
+ return Page::EXIT;
+ }
+
void Program::episode_list_page() {
search_bar->onTextUpdateCallback = [this](const std::string &text) {
body->filter_search_fuzzy(text);
@@ -1422,6 +1436,10 @@ namespace QuickMedia {
}
}
+ static bool is_url_video(const std::string &url) {
+ return string_ends_with(url, ".webm") || string_ends_with(url, ".mp4") || string_ends_with(url, ".gif");
+ }
+
void Program::image_board_thread_page() {
assert(current_plugin->is_image_board());
// TODO: Support image board other than 4chan. To make this work, the captcha code needs to be changed
@@ -1608,28 +1626,37 @@ namespace QuickMedia {
} else if(event.key.code == sf::Keyboard::P) {
// TODO: Make this work when thumbnail is preview for a video/gif instead of a static image
BodyItem *selected_item = body->get_selected();
- if(selected_item && !selected_item->fullsize_image_url.empty()) {
- navigation_stage = NavigationStage::VIEWING_ATTACHED_IMAGE;
- load_image_future = std::async(std::launch::async, [this, &image_board, &attached_image_texture, &attached_image_sprite, &attachment_load_mutex]() -> bool {
- BodyItem *selected_item = body->get_selected();
- if(!selected_item || selected_item->fullsize_image_url.empty()) {
- return false;
- }
- std::string image_data;
- if(download_to_string(selected_item->fullsize_image_url, image_data, {}, image_board->use_tor) != DownloadResult::OK) {
- show_notification(image_board->name, "Failed to download image: " + selected_item->fullsize_image_url, Urgency::CRITICAL);
- return false;
- }
+ if(selected_item && !selected_item->attached_content_url.empty()) {
+ if(is_url_video(selected_item->attached_content_url)) {
+ page_stack.push(Page::IMAGE_BOARD_THREAD);
+ current_page = Page::VIDEO_CONTENT;
+ std::string prev_content_url = content_url;
+ content_url = selected_item->attached_content_url;
+ video_content_page();
+ content_url = std::move(prev_content_url);
+ } else {
+ navigation_stage = NavigationStage::VIEWING_ATTACHED_IMAGE;
+ load_image_future = std::async(std::launch::async, [this, &image_board, &attached_image_texture, &attached_image_sprite, &attachment_load_mutex]() -> bool {
+ BodyItem *selected_item = body->get_selected();
+ if(!selected_item || selected_item->attached_content_url.empty()) {
+ return false;
+ }
+ std::string image_data;
+ if(download_to_string(selected_item->attached_content_url, image_data, {}, image_board->use_tor) != DownloadResult::OK) {
+ show_notification(image_board->name, "Failed to download image: " + selected_item->attached_content_url, Urgency::CRITICAL);
+ return false;
+ }
- std::lock_guard<std::mutex> lock(attachment_load_mutex);
- if(!attached_image_texture->loadFromMemory(image_data.data(), image_data.size())) {
- show_notification(image_board->name, "Failed to load image downloaded from url: " + selected_item->fullsize_image_url, Urgency::CRITICAL);
- return false;
- }
- attached_image_texture->setSmooth(true);
- attached_image_sprite.setTexture(*attached_image_texture, true);
- return true;
- });
+ std::lock_guard<std::mutex> lock(attachment_load_mutex);
+ if(!attached_image_texture->loadFromMemory(image_data.data(), image_data.size())) {
+ show_notification(image_board->name, "Failed to load image downloaded from url: " + selected_item->attached_content_url, Urgency::CRITICAL);
+ return false;
+ }
+ attached_image_texture->setSmooth(true);
+ attached_image_sprite.setTexture(*attached_image_texture, true);
+ return true;
+ });
+ }
}
}
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 16d3b48..981b227 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -1,4 +1,5 @@
#include "../include/StringUtils.hpp"
+#include <string.h>
namespace QuickMedia {
void string_split(const std::string &str, char delimiter, StringSplitCallback callback_func) {
@@ -47,4 +48,9 @@ namespace QuickMedia {
return str.substr(start, end - start + 1);
}
+
+ bool string_ends_with(const std::string &str, const std::string &ends_with_str) {
+ size_t ends_len = ends_with_str.size();
+ return ends_len == 0 || (str.size() >= ends_len && memcmp(&str[str.size() - ends_len], ends_with_str.data(), ends_len) == 0);
+ }
} \ No newline at end of file
diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp
index 17fefdc..f19d3aa 100644
--- a/src/plugins/Fourchan.cpp
+++ b/src/plugins/Fourchan.cpp
@@ -52,11 +52,6 @@ namespace QuickMedia {
return SuggestionResult::OK;
}
- static bool string_ends_with(const std::string &str, const std::string &ends_with_str) {
- size_t ends_len = ends_with_str.size();
- return ends_len == 0 || (str.size() >= ends_len && memcmp(&str[str.size() - ends_len], ends_with_str.data(), ends_len) == 0);
- }
-
struct CommentPiece {
enum class Type {
TEXT,
@@ -236,7 +231,7 @@ namespace QuickMedia {
const Json::Value &tim = thread["tim"];
if(tim.isNumeric() && ext.isString()) {
std::string ext_str = ext.asString();
- if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg") {
+ if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg" || ext_str == ".webm" || ext_str == ".mp4" || ext_str == ".gif") {
} else {
fprintf(stderr, "TODO: Support file extension: %s\n", ext_str.c_str());
}
@@ -347,7 +342,7 @@ namespace QuickMedia {
const Json::Value &tim = post["tim"];
if(tim.isNumeric() && ext.isString()) {
std::string ext_str = ext.asString();
- if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg") {
+ if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg" || ext_str == ".webm" || ext_str == ".mp4" || ext_str == ".gif") {
} else {
fprintf(stderr, "TODO: Support file extension: %s\n", ext_str.c_str());
}
@@ -355,7 +350,7 @@ namespace QuickMedia {
// thumbnails always has .jpg extension even if they are gifs or webm.
std::string tim_str = std::to_string(tim.asInt64());
body_item->thumbnail_url = fourchan_image_url + list_url + "/" + tim_str + "s.jpg";
- body_item->fullsize_image_url = fourchan_image_url + list_url + "/" + tim_str + ext_str;
+ body_item->attached_content_url = fourchan_image_url + list_url + "/" + tim_str + ext_str;
}
++body_item_index;