From b9a5d95635a2f0094cd919f0b11f37336012dc24 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 14 Nov 2020 06:15:06 +0100 Subject: Resume video when navigating back from related/channel videos --- include/VideoPlayer.hpp | 10 +++++++--- plugins/Matrix.hpp | 1 + src/QuickMedia.cpp | 34 ++++++++++++++++++++++++++-------- src/VideoPlayer.cpp | 29 ++++++++++++++++++++++++++--- src/plugins/Matrix.cpp | 7 ++++++- 5 files changed, 66 insertions(+), 15 deletions(-) diff --git a/include/VideoPlayer.hpp b/include/VideoPlayer.hpp index 86410da..abd715a 100644 --- a/include/VideoPlayer.hpp +++ b/include/VideoPlayer.hpp @@ -36,7 +36,7 @@ namespace QuickMedia { }; // @event_callback is called from another thread - VideoPlayer(bool use_tor, bool no_video, bool use_system_mpv_config, EventCallbackFunc event_callback, VideoPlayerWindowCreateCallback window_create_callback, const std::string &resource_root); + VideoPlayer(bool use_tor, bool no_video, bool use_system_mpv_config, bool resume_playback, EventCallbackFunc event_callback, VideoPlayerWindowCreateCallback window_create_callback, const std::string &resource_root); ~VideoPlayer(); VideoPlayer(const VideoPlayer&) = delete; VideoPlayer& operator=(const VideoPlayer&) = delete; @@ -60,12 +60,15 @@ namespace QuickMedia { Error is_seekable(bool *result); + Error quit_and_save_watch_later(); + bool is_connected() const { return connected_to_ipc; } - int exit_status; - private: Error set_property(const std::string &property_name, const Json::Value &value); Error get_property(const std::string &property_name, Json::Value *result, Json::ValueType result_type); + + int exit_status; + private: Error send_command(const char *cmd, size_t size); Error launch_video_process(const char *path, sf::WindowHandle parent_window, const std::string &plugin_name); VideoPlayer::Error read_ipc_func(); @@ -73,6 +76,7 @@ namespace QuickMedia { bool use_tor; bool no_video; bool use_system_mpv_config; + bool resume_playback; pid_t video_process_id; int ipc_socket; bool connected_to_ipc; diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 25225d7..30cfa92 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -525,6 +525,7 @@ namespace QuickMedia { std::thread sync_thread; std::thread sync_additional_messages_thread; std::thread notification_thread; + MessageQueue additional_messages_queue; bool sync_running = false; bool sync_failed = false; bool sync_is_cache = false; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 644ed6f..6e9fcf3 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1688,7 +1688,14 @@ namespace QuickMedia { video_loaded = false; added_recommendations = false; watched_videos.insert(video_url); - VideoPlayer::Error err = video_player->load_video(video_url.c_str(), window.getSystemHandle(), plugin_name); + std::string video_url_converted; + std::string dummy_id; + if(youtube_url_extract_id(video_url, dummy_id)) { + video_url_converted = "ytdl://" + video_url; + } else { + video_url_converted = video_url; + } + 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: "; err_msg += video_url; @@ -1747,6 +1754,8 @@ namespace QuickMedia { } 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) { video_loaded = false; @@ -1779,7 +1788,7 @@ namespace QuickMedia { } }; - video_player = std::make_unique(use_tor, no_video, use_system_mpv_config, video_event_callback, on_window_create, resources_root); + video_player = std::make_unique(use_tor, no_video, use_system_mpv_config, false, video_event_callback, on_window_create, resources_root); load_video_error_check(); sf::Event event; @@ -1865,15 +1874,23 @@ namespace QuickMedia { bool page_changed = false; page_loop(tabs, 1, [this, &video_player, &page_changed]() { window.setMouseCursorVisible(true); + video_player->quit_and_save_watch_later(); + while(true) { + VideoPlayer::Error update_err = video_player->update(); + if(update_err != VideoPlayer::Error::OK) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } video_player.reset(); page_changed = true; }); if(page_changed) { - if(fullscreen) - window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::UNSET); - current_page = previous_page; - return; + current_page = PageType::VIDEO_CONTENT; + video_player_window = None; + has_video_started = true; + video_player = std::make_unique(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); XSync(disp, False); @@ -3747,7 +3764,7 @@ namespace QuickMedia { // TODO: Optimize auto update_pinned_messages_authors = [&tabs, ¤t_room]() { - fprintf(stderr, "updated pinned messages author for all users\n"); + fprintf(stderr, "updated pinned messages author for all users in room: %s\n", current_room->id.c_str()); for(auto &pinned_body_item : tabs[PINNED_TAB_INDEX].body->items) { Message *message = static_cast(pinned_body_item->userdata)->message; // Its fine if we dont set it now. When the message is fetches, it will have updated user info since its fetched later @@ -3766,7 +3783,7 @@ namespace QuickMedia { // TODO: Optimize auto update_messages_authors = [&tabs, ¤t_room]() { - fprintf(stderr, "updated messages author for all users\n"); + fprintf(stderr, "updated messages author for all users in room: %s\n", current_room->id.c_str()); for(auto &message_body_items : tabs[MESSAGES_TAB_INDEX].body->items) { Message *message = static_cast(message_body_items->userdata); message_body_items->set_author(current_room->get_user_display_name(message->user)); @@ -3807,6 +3824,7 @@ namespace QuickMedia { // TODO: Remove this once synapse bug has been resolved where /sync does not include user info for new messages when using message filter that limits number of messages for initial sync, // and then only call this when viewing the users tab for the first time. + // Note that this is not needed when new users join the room, as those will be included in the sync timeline (with membership events) if(current_room->users_fetched) { //TODO BLABLA //update_ diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index c7d2697..157d2b8 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -18,11 +18,12 @@ const int MAX_RETRIES_CONNECT = 20; const int READ_TIMEOUT_MS = 200; namespace QuickMedia { - VideoPlayer::VideoPlayer(bool use_tor, bool no_video, bool use_system_mpv_config, EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback, const std::string &resource_root) : + VideoPlayer::VideoPlayer(bool use_tor, bool no_video, bool use_system_mpv_config, bool resume_playback, EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback, const std::string &resource_root) : exit_status(0), use_tor(use_tor), no_video(no_video), use_system_mpv_config(use_system_mpv_config), + resume_playback(resume_playback), video_process_id(-1), ipc_socket(-1), connected_to_ipc(false), @@ -83,20 +84,29 @@ namespace QuickMedia { create_directory_recursive(video_cache_dir); std::string cache_dir = "--cache-dir=" + video_cache_dir.data; + Path mpv_watch_later_dir = get_storage_dir().join("mpv").join("watch_later"); + create_directory_recursive(mpv_watch_later_dir); + std::string watch_later_dir = "--watch-later-directory=" + mpv_watch_later_dir.data; + // 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", input_ipc_server_arg.c_str(), - "--no-resume-playback", + "mpv", "--keep-open=yes", + input_ipc_server_arg.c_str(), "--cursor-autohide=no", /* "--no-input-default-bindings", "--input-vo-keyboard=no", "--no-input-cursor", */ "--no-terminal", + "--save-position-on-quit=yes", "--profile=pseudo-gui", // For gui when playing audio, requires a version of mpv that isn't ancient cache_dir.c_str(), + watch_later_dir.c_str(), "--cache-on-disk=yes", "--ytdl-raw-options=sub-lang=\"en,eng,enUS,en-US\",write-sub=", input_conf.c_str(), wid_arg.c_str() }); + if(!resume_playback) + args.push_back("--no-resume-playback"); + if(!use_system_mpv_config) { args.insert(args.end(), { "--no-config", /*"--demuxer-max-bytes=40M", "--demuxer-max-back-bytes=20M",*/ @@ -413,6 +423,19 @@ namespace QuickMedia { return err; } + VideoPlayer::Error VideoPlayer::quit_and_save_watch_later() { + Json::Value command_data(Json::arrayValue); + command_data.append("quit-watch-later"); + Json::Value command(Json::objectValue); + command["command"] = command_data; + + Json::StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = ""; + const std::string cmd_str = Json::writeString(builder, command) + "\n"; + return send_command(cmd_str.c_str(), cmd_str.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/Matrix.cpp b/src/plugins/Matrix.cpp index a48bcdd..4b78978 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -1015,6 +1015,7 @@ namespace QuickMedia { //if(next_batch.empty()) // clear_sync_cache_for_new_sync(); + additional_messages_queue.pop_wait(); parse_sync_response(json_root, true); }); @@ -1055,8 +1056,10 @@ namespace QuickMedia { } } - if(next_batch.empty()) + if(next_batch.empty()) { + additional_messages_queue.push(true); clear_sync_cache_for_new_sync(); + } result = parse_sync_response(json_root, false); if(result != PluginResult::OK) { @@ -1137,7 +1140,9 @@ namespace QuickMedia { if(sync_additional_messages_thread.joinable()) { program_kill_in_thread(sync_additional_messages_thread.get_id()); + additional_messages_queue.close(); sync_additional_messages_thread.join(); + additional_messages_queue.restart(); } if(notification_thread.joinable()) { -- cgit v1.2.3