diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | include/Body.hpp | 8 | ||||
-rw-r--r-- | input.conf | 4 | ||||
-rw-r--r-- | src/Body.cpp | 62 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 95 | ||||
-rw-r--r-- | src/VideoPlayer.cpp | 2 | ||||
-rw-r--r-- | src/main.cpp | 4 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 1 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 2 |
10 files changed, 102 insertions, 80 deletions
@@ -31,6 +31,7 @@ Press `Page up` to scroll up and entire page or `Page down` to scroll down an en Press `Home` to scroll to the top or `End` to scroll to the bottom.\ Press `Enter` (aka `Return`) to select the item.\ Press `ESC` to go back to the previous menu.\ +Press `ESC` or `Backspace` to close the video.\ Press `Ctrl + F` to switch between window mode and fullscreen mode when watching a video.\ Press `Space` to pause/unpause a video.\ Press `Ctrl + R` to show related/channels video menu when watching a video (if supported).\ @@ -150,4 +150,5 @@ Comparing latest message for unread message should be done by comparing event id Support replying to messages with media, by typing /upload in the reply text. Instead of doing a GET for the first N bytes to check if a video is streamable, start streaming the video and if the first bytes doesn't contain MOOV then wait until the whole video has downloaded before playing it. Create thumbnail when uploading an image in matrix. -If a message reply is edited and its a reply to us, then we want the text to be red even if its edited.
\ No newline at end of file +If a message reply is edited and its a reply to us, then we want the text to be red even if its edited. +Implement matrix spoiler, see: https://github.com/matrix-org/matrix-doc/blob/master/proposals/2010-spoilers.md
\ No newline at end of file diff --git a/include/Body.hpp b/include/Body.hpp index 525cee5..fb3f20e 100644 --- a/include/Body.hpp +++ b/include/Body.hpp @@ -236,8 +236,8 @@ namespace QuickMedia { float get_page_scroll() const { return page_scroll; } // This is the item we can see the end of bool is_last_item_fully_visible() const { return last_item_fully_visible; } - - bool is_body_full_with_items() const { return items_cut_off; } + bool is_body_full_with_items() const { return body_full; } + int get_num_visible_items() const { return num_visible_items; }; sf::Text progress_text; sf::Text replies_text; @@ -275,7 +275,9 @@ namespace QuickMedia { double elapsed_time_sec = 0.0; bool selected_line_top_visible = true; bool selected_line_bottom_visible = true; - bool items_cut_off = false; + bool top_cut_off = false; + bool bottom_cut_off = false; + bool body_full = false; float offset_to_top = 0.0f; float offset_to_bottom = 0.0f; }; @@ -1 +1,3 @@ -Ctrl+c ignore
\ No newline at end of file +Ctrl+c ignore +Backspace ignore +q ignore
\ No newline at end of file diff --git a/src/Body.cpp b/src/Body.cpp index 2d429f8..6f1d9ae 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -18,10 +18,11 @@ static const float padding_y = 5.0f; static const float embedded_item_padding_y = 0.0f; static const double thumbnail_fade_duration_sec = 0.1; -const float reaction_background_padding_x = 7.0f; -const float reaction_background_padding_y = 3.0f; -const float reaction_spacing_x = 5.0f; +static const float reaction_background_padding_x = 7.0f; +static const float reaction_background_padding_y = 3.0f; +static const float reaction_spacing_x = 5.0f; static const float reaction_padding_y = 7.0f; +static const int embedded_item_font_size = 14; namespace QuickMedia { BodyItem::BodyItem(std::string _title) : @@ -101,7 +102,7 @@ namespace QuickMedia { Body::Body(Program *program, sf::Texture &loading_icon_texture) : progress_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), 14), replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), 14), - embedded_item_load_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), 14), + embedded_item_load_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), embedded_item_font_size), draw_thumbnails(true), wrap_around(false), line_separator_color(sf::Color(32, 37, 43, 255)), @@ -373,7 +374,9 @@ namespace QuickMedia { clear_body_item_cache(body_item->embedded_item.get()); } last_item_fully_visible = true; - items_cut_off = false; + top_cut_off = false; + bottom_cut_off = false; + body_full = false; offset_to_top = 0.0f; offset_to_bottom = 0.0f; return; @@ -439,22 +442,25 @@ namespace QuickMedia { page_scroll = 0.0f; } - if(items_cut_off) { - if(offset_to_top > 0.0f) + if(top_cut_off || bottom_cut_off) { + if(attach_side == AttachSide::TOP && offset_to_top > 0.0f) { page_scroll -= offset_to_top; - else if(offset_to_bottom > 0.0f) + } else if(attach_side == AttachSide::BOTTOM && offset_to_bottom > 0.0f) { page_scroll += offset_to_bottom; + } } else { - if(attach_side == AttachSide::TOP) + if(attach_side == AttachSide::TOP) { page_scroll -= offset_to_top; - else if(attach_side == AttachSide::BOTTOM) + } else if(attach_side == AttachSide::BOTTOM) { page_scroll += offset_to_bottom; + } } pos.y += page_scroll; - bool last_item_fully_visible_set = false; - bool items_cut_off_set = false; + last_item_fully_visible = true; + top_cut_off = false; + bottom_cut_off = false; sf::Vector2u window_size = window.getSize(); @@ -471,10 +477,8 @@ namespace QuickMedia { float item_height = get_item_height(item.get(), size.x); prev_pos.y -= (item_height + spacing_y); - if(prev_pos.y < start_y) { - items_cut_off = true; - items_cut_off_set = true; - } + if(prev_pos.y < start_y) + top_cut_off = true; if(prev_pos.y + item_height + spacing_y <= start_y) break; @@ -497,11 +501,12 @@ namespace QuickMedia { if(!item->visible) continue; + if(after_pos.y < start_y) + top_cut_off = true; + if(after_pos.y - start_y >= size.y) { last_item_fully_visible = false; - items_cut_off = true; - last_item_fully_visible_set = true; - items_cut_off_set = true; + bottom_cut_off = true; break; } @@ -518,9 +523,7 @@ namespace QuickMedia { if(after_pos.y - start_y > size.y) { last_item_fully_visible = false; - items_cut_off = true; - last_item_fully_visible_set = true; - items_cut_off_set = true; + bottom_cut_off = true; } else { last_fully_visible_item = i; } @@ -530,11 +533,10 @@ namespace QuickMedia { last_fully_visible_item = selected_item; offset_to_bottom = size.y - (after_pos.y - start_y); - - if(!last_item_fully_visible_set) - last_item_fully_visible = true; - if(!items_cut_off_set) - items_cut_off = false; + if(top_cut_off && (bottom_cut_off || offset_to_bottom < 5.0f)) + body_full = true; + else + body_full = false; for(auto it = item_thumbnail_textures.begin(); it != item_thumbnail_textures.end();) { if(!it->second->referenced) @@ -794,7 +796,7 @@ namespace QuickMedia { if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { const float border_width = 4.0f; const float embedded_item_width = std::floor(size.x - text_offset_x - border_width - padding_x); - float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : (embedded_item_load_text.getLocalBounds().height + embedded_item_padding_y * 2.0f); + float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : ((embedded_item_font_size + 5.0f) + embedded_item_padding_y * 2.0f); sf::RectangleShape border_left(sf::Vector2f(border_width, std::floor(embedded_item_height))); border_left.setFillColor(sf::Color::White); border_left.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + 4.0f)); @@ -806,7 +808,7 @@ namespace QuickMedia { draw_item(window, item->embedded_item.get(), embedded_item_pos, embedded_item_size, false); } else { embedded_item_load_text.setString(embedded_item_status_to_string(item->embedded_item_status)); - embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - embedded_item_load_text.getLocalBounds().height * 0.5f + 4.0f)); + embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - (embedded_item_font_size + 5.0f) * 0.5f + 4.0f)); window.draw(embedded_item_load_text); } item_pos.y += embedded_item_height + 4.0f; @@ -939,7 +941,7 @@ namespace QuickMedia { if(item->embedded_item) item_height += (get_item_height(item->embedded_item.get(), width, load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f); else - item_height += (embedded_item_load_text.getLocalBounds().height + 4.0f + embedded_item_padding_y * 2.0f); + item_height += ((embedded_item_font_size + 5.0f) + 4.0f + embedded_item_padding_y * 2.0f); } if(item->description_text) { item_height += item->description_text->getHeight() - 2.0f; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 89ced4a..9a47420 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1696,9 +1696,15 @@ namespace QuickMedia { XSync(disp, False); }; - auto load_video_error_check = [this, &related_videos, &channel_url, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, &added_recommendations, video_page]() mutable { + bool has_video_started = true; + bool end_of_file = false; + std::function<void(const char*)> video_event_callback; + + auto load_video_error_check = [this, &related_videos, &channel_url, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, &end_of_file, &added_recommendations, video_page, &video_event_callback, &on_window_create, &video_player_window]() mutable { time_watched_timer.restart(); video_loaded = false; + end_of_file = false; + video_player_window = None; added_recommendations = false; watched_videos.insert(video_url); std::string video_url_converted; @@ -1708,6 +1714,8 @@ namespace QuickMedia { } else { video_url_converted = video_url; } + + video_player = std::make_unique<VideoPlayer>(use_tor, no_video, use_system_mpv_config, false, video_event_callback, on_window_create, resources_root); VideoPlayer::Error err = video_player->load_video(video_url_converted.c_str(), window.getSystemHandle(), plugin_name); if(err != VideoPlayer::Error::OK) { std::string err_msg = "Failed to play url: "; @@ -1755,53 +1763,32 @@ namespace QuickMedia { } }; - bool has_video_started = true; - auto video_event_callback = [this, &related_videos, &video_url, &video_title, &video_player, &load_video_error_check, previous_page, &has_video_started, &time_watched_timer, &video_loaded](const char *event_name) mutable { - bool end_of_file = false; + video_event_callback = [this, &related_videos, &video_url, &video_title, &video_player, &load_video_error_check, previous_page, &has_video_started, &end_of_file, &time_watched_timer, &video_loaded](const char *event_name) mutable { if(strcmp(event_name, "pause") == 0) { - double time_remaining = 9999.0; - if(video_player->get_time_remaining(&time_remaining) == VideoPlayer::Error::OK && time_remaining <= 1.0) - end_of_file = true; + //double time_remaining = 9999.0; + //if(video_player->get_time_remaining(&time_remaining) == VideoPlayer::Error::OK && time_remaining <= 1.0) + // end_of_file = true; } else if(strcmp(event_name, "playback-restart") == 0) { - video_player->set_paused(false); + //video_player->set_paused(false); } else if(strcmp(event_name, "file-loaded") == 0) { has_video_started = true; time_watched_timer.restart(); if(!video_loaded) video_player->set_property("no-resume-playback", true); video_loaded = true; - } else if(strcmp(event_name, "end-file") == 0) { + } else if(strcmp(event_name, "video-reconfig") == 0 || strcmp(event_name, "audio-reconfig") == 0) { + if(!video_loaded) { + video_loaded = true; + time_watched_timer.restart(); + } + } else if(strcmp(event_name, "end-file") == 0 && current_page == PageType::VIDEO_CONTENT) { video_loaded = false; + end_of_file = true; } - if(end_of_file && has_video_started) { - has_video_started = false; - std::string new_video_url; - std::string new_video_title; - // Find video that hasn't been played before in this video session - // TODO: Remove duplicates - for(auto it = related_videos.begin(), end = related_videos.end(); it != end; ++it) { - if(watched_videos.find((*it)->url) == watched_videos.end()) { - new_video_url = (*it)->url; - new_video_title = (*it)->get_title(); - break; - } - } - - // If there are no videos to play, then dont play any... - if(new_video_url.empty()) { - show_notification("QuickMedia", "No more related videos to play"); - current_page = previous_page; - return; - } - - video_url = std::move(new_video_url); - video_title = std::move(new_video_title); - load_video_error_check(); - } + fprintf(stderr, "event name: %s\n", event_name); }; - video_player = std::make_unique<VideoPlayer>(use_tor, no_video, use_system_mpv_config, false, video_event_callback, on_window_create, resources_root); load_video_error_check(); sf::Event event; @@ -1848,8 +1835,9 @@ namespace QuickMedia { KeySym pressed_keysym = XKeycodeToKeysym(disp, xev.xkey.keycode, 0); #pragma GCC diagnostic pop bool pressing_ctrl = (CLEANMASK(xev.xkey.state) == ControlMask); - if(pressed_keysym == XK_Escape) { + if(pressed_keysym == XK_Escape || pressed_keysym == XK_BackSpace || pressed_keysym == XK_q) { current_page = previous_page; + break; } else if(pressed_keysym == XK_f && pressing_ctrl) { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); } else if(pressed_keysym == XK_r && pressing_ctrl) { @@ -1898,7 +1886,7 @@ namespace QuickMedia { current_page = PageType::VIDEO_CONTENT; video_player_window = None; has_video_started = true; - video_player = std::make_unique<VideoPlayer>(use_tor, no_video, use_system_mpv_config, true, video_event_callback, on_window_create, resources_root); + //video_player = std::make_unique<VideoPlayer>(use_tor, no_video, use_system_mpv_config, true, video_event_callback, on_window_create, resources_root); load_video_error_check(); } else { XMapWindow(disp, video_player_window); @@ -1924,9 +1912,29 @@ namespace QuickMedia { current_page = previous_page; break; } else if(update_err == VideoPlayer::Error::EXITED && video_player->exit_status == 0) { - fprintf(stderr, "mpv exited with status 0, the user most likely closed mpv with 'q'\n"); - current_page = previous_page; - break; + has_video_started = false; + std::string new_video_url; + std::string new_video_title; + // Find video that hasn't been played before in this video session + // TODO: Remove duplicates + for(auto it = related_videos.begin(), end = related_videos.end(); it != end; ++it) { + if(watched_videos.find((*it)->url) == watched_videos.end()) { + new_video_url = (*it)->url; + new_video_title = (*it)->get_title(); + break; + } + } + + // If there are no videos to play, then dont play any... + if(new_video_url.empty()) { + show_notification("QuickMedia", "No more related videos to play"); + current_page = previous_page; + break; + } + + video_url = std::move(new_video_url); + video_title = std::move(new_video_title); + load_video_error_check(); } else if(update_err != VideoPlayer::Error::OK) { show_notification("QuickMedia", "Failed to play the video (error code " + std::to_string((int)update_err) + ")", Urgency::CRITICAL); current_page = previous_page; @@ -3665,6 +3673,7 @@ namespace QuickMedia { body_item->set_description_color(sf::Color(255, 100, 100)); body_item->embedded_item = std::make_shared<BodyItem>(""); *body_item->embedded_item = *related_body_item; + body_item->reactions.clear(); body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; return; } @@ -3690,6 +3699,7 @@ namespace QuickMedia { if(related_body_item->userdata && static_cast<Message*>(related_body_item->userdata)->user == me) body_item->set_description_color(sf::Color(255, 100, 100)); *body_item = *related_body_item; + body_item->reactions.clear(); event_data->status = FetchStatus::FINISHED_LOADING; event_data->message = static_cast<Message*>(related_body_item->userdata); body_item->userdata = event_data; @@ -3743,6 +3753,7 @@ namespace QuickMedia { body_item->set_description_color(sf::Color(255, 100, 100)); body_item->embedded_item = std::make_shared<BodyItem>(""); *body_item->embedded_item = *related_body_item; + body_item->reactions.clear(); body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; return; } @@ -3778,7 +3789,7 @@ namespace QuickMedia { auto fetch_more_previous_messages_if_needed = [this, &tabs, ¤t_room, &fetched_enough_messages, &previous_messages_future]() { if(!fetched_enough_messages && !previous_messages_future.valid()) { - if(!tabs[MESSAGES_TAB_INDEX].body->is_body_full_with_items()) { + if(tabs[MESSAGES_TAB_INDEX].body->items.size() < 30) { previous_messages_future = [this, ¤t_room]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages, true) != PluginResult::OK) @@ -4706,9 +4717,9 @@ namespace QuickMedia { goto chat_page_end; } } - //all_messages.clear(); + tabs[MESSAGES_TAB_INDEX].body->clear_items(); Messages all_messages_new; diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 157d2b8..0510a4c 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -90,7 +90,7 @@ namespace QuickMedia { // TODO: Resume playback if the last video played matches the first video played next time QuickMedia is launched args.insert(args.end(), { - "mpv", "--keep-open=yes", + "mpv", input_ipc_server_arg.c_str(), "--cursor-autohide=no", /* "--no-input-default-bindings", "--input-vo-keyboard=no", "--no-input-cursor", */ "--no-terminal", diff --git a/src/main.cpp b/src/main.cpp index 3383363..869b165 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,12 @@ #include "../include/QuickMedia.hpp" -#include <X11/Xlib.h> +//#include <X11/Xlib.h> #include <libgen.h> #include <unistd.h> int main(int argc, char **argv) { chdir(dirname(argv[0])); setlocale(LC_ALL, "C"); // Sigh... stupid C - XInitThreads(); + //XInitThreads(); QuickMedia::Program program; return program.run(argc, argv); } diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index a39c247..44dfa3a 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -2623,6 +2623,7 @@ namespace QuickMedia { html_escape_sequences(formatted_body); html_escape_sequences(related_to_body); // TODO: Add keybind to navigate to the reply message, which would also depend on this formatting. + // Note: user id and event id is not url escaped here on purpose, because that messes up riot.im replies for certain user ids... return "<mx-reply>" "<blockquote>" "<a href=\"https://matrix.to/#/" + room->id + "/" + message->event_id + "?via=" + extract_homeserver_from_room_id(room->id) + "\">In reply to</a>" diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index 89058f5..96d767f 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -154,6 +154,7 @@ namespace QuickMedia { if(description_snippet) { if(!desc.empty()) desc += '\n'; + desc += '\n'; desc += description_snippet.value(); } body_item->set_description(std::move(desc)); @@ -211,6 +212,7 @@ namespace QuickMedia { if(description) { if(!desc.empty()) desc += '\n'; + desc += '\n'; desc += description.value(); } body_item->set_description(std::move(desc)); |