diff options
-rw-r--r-- | include/DownloadUtils.hpp | 2 | ||||
-rw-r--r-- | include/QuickMedia.hpp | 4 | ||||
-rw-r--r-- | plugins/Matrix.hpp | 10 | ||||
-rw-r--r-- | plugins/Page.hpp | 1 | ||||
-rw-r--r-- | src/DownloadUtils.cpp | 7 | ||||
-rw-r--r-- | src/Program.cpp | 2 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 74 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 6 |
8 files changed, 73 insertions, 33 deletions
diff --git a/include/DownloadUtils.hpp b/include/DownloadUtils.hpp index 7e46d8b..48ee309 100644 --- a/include/DownloadUtils.hpp +++ b/include/DownloadUtils.hpp @@ -32,6 +32,6 @@ namespace QuickMedia { // Note: if |cloudflare_bypass| is set to true then tls is limited to version 1.1 and the user agent is changed. DownloadResult download_to_file(const std::string &url, const std::string &destination_filepath, const std::vector<CommandArg> &additional_args, bool use_browser_useragent = false, bool cloudflare_bypass = false); // Returns false if there was an error trying to create the download process - bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool no_video); + bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool no_video, const std::string &filename); DownloadResult download_to_json(const std::string &url, rapidjson::Document &result, const std::vector<CommandArg> &additional_args, bool use_browser_useragent = false, bool fail_on_error = true); }
\ No newline at end of file diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index 4011ca0..8dca09e 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -134,7 +134,7 @@ namespace QuickMedia { bool page_loop(std::vector<Tab> &tabs, int start_tab_index = 0, PageLoopSubmitHandler after_submit_handler = nullptr, bool go_to_previous_on_escape = true); void redirect_focus_to_video_player_window(mgl::WindowHandle video_player_window); void show_video_player_window(mgl::WindowHandle video_player_window); - void video_page_download_video(const std::string &url, mgl::WindowHandle video_player_window = 0); + void video_page_download_video(const std::string &url, const std::string &filename, mgl::WindowHandle video_player_window = 0); bool video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page); int video_get_max_height(); void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = ""); @@ -147,7 +147,7 @@ namespace QuickMedia { void chat_login_page(); bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room); void after_matrix_login_page(); - void download_page(std::string url); + void download_page(std::string url, std::string download_filename); // Returns the full path where the file should be saved, or an empty string if the operation was cancelled std::string file_save_page(const std::string &filename); diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 0c12831..45dd1f7 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -412,11 +412,14 @@ namespace QuickMedia { const std::string title; }; - // Dummy, only play one video. TODO: Play all videos in room, as related videos? + // Only play one video. TODO: Play all videos in room, as related videos? class MatrixVideoPage : public VideoPage { public: - MatrixVideoPage(Program *program) : VideoPage(program, "") {} + MatrixVideoPage(Program *program, std::string filename) : VideoPage(program, ""), filename(std::move(filename)) {} const char* get_title() const override { return ""; } + std::string get_filename() override { return filename; } + private: + std::string filename; }; class MatrixChatPage : public Page { @@ -543,7 +546,8 @@ namespace QuickMedia { // |relates_to| is from |BodyItem.userdata| and is of type |Message*| PluginResult post_reaction(RoomData *room, const std::string &body, void *relates_to, std::string &event_id_response); - PluginResult post_file(RoomData *room, const std::string &filepath, std::string &event_id_response, std::string &err_msg); + // If filename is empty then the filename is extracted from filepath + PluginResult post_file(RoomData *room, const std::string &filepath, std::string filename, std::string &event_id_response, std::string &err_msg); PluginResult login(const std::string &username, const std::string &password, const std::string &homeserver, std::string &err_msg); PluginResult logout(); diff --git a/plugins/Page.hpp b/plugins/Page.hpp index 2fa2b6c..97b0340 100644 --- a/plugins/Page.hpp +++ b/plugins/Page.hpp @@ -184,6 +184,7 @@ namespace QuickMedia { virtual void mark_watched() {}; // Should not do any network request to not slow down video loading virtual void get_subtitles(SubtitleData &subtitle_data) { (void)subtitle_data; } + virtual std::string get_filename() { return ""; } virtual bool is_local() const { return false; } diff --git a/src/DownloadUtils.cpp b/src/DownloadUtils.cpp index 8685662..484afeb 100644 --- a/src/DownloadUtils.cpp +++ b/src/DownloadUtils.cpp @@ -318,7 +318,7 @@ namespace QuickMedia { return DownloadResult::OK; } - bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool no_video) { + bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool no_video, const std::string &filename) { char quickmedia_path[PATH_MAX]; ssize_t bytes_written = readlink("/proc/self/exe", quickmedia_path, sizeof(quickmedia_path) - 1); if(bytes_written == -1) @@ -327,7 +327,10 @@ namespace QuickMedia { quickmedia_path[bytes_written] = '\0'; std::vector<const char*> args = { quickmedia_path, "download", "-u", url.c_str(), "--dir", file_manager_start_dir.c_str() }; - if(no_video) args.push_back("--no-video"); + if(no_video) + args.push_back("--no-video"); + if(!filename.empty()) + args.insert(args.end(), { "--download-filename", filename.c_str() }); args.push_back(nullptr); return exec_program_async(args.data(), nullptr) == 0; } diff --git a/src/Program.cpp b/src/Program.cpp index 513ce8c..c66611d 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -219,6 +219,8 @@ int wait_program_non_blocking(pid_t process_id, int *status) { return 1; } +// TODO: Verify if this can cause issues when |result_process_id| is null, because |args| may be deallocated +// by the time its used in the last execvp. int exec_program_async(const char **args, pid_t *result_process_id) { /* 1 arguments */ if(args[0] == NULL) diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 97eb939..fa8dd66 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -387,6 +387,7 @@ namespace QuickMedia { const char *url = nullptr; std::string program_path = dirname(argv[0]); std::string instance; + std::string download_filename; for(int i = 1; i < argc; ++i) { if(!plugin_name) { @@ -469,6 +470,15 @@ namespace QuickMedia { usage(); return -1; } + } else if(strcmp(argv[i], "--download-filename") == 0) { + if(i < argc - 1) { + download_filename = argv[i + 1]; + ++i; + } else { + fprintf(stderr, "Missing filename after --download-filename argument\n"); + usage(); + return -1; + } } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { usage(); return 0; @@ -559,7 +569,7 @@ namespace QuickMedia { usage(); return -1; } - download_page(url); + download_page(url, download_filename); return exit_code; } @@ -2984,7 +2994,7 @@ namespace QuickMedia { redirect_focus_to_video_player_window(video_player_window); } - void Program::video_page_download_video(const std::string &url, mgl::WindowHandle video_player_window) { + void Program::video_page_download_video(const std::string &url, const std::string &filename, mgl::WindowHandle video_player_window) { bool separate_audio_option = url_should_download_with_youtube_dl(url); std::string video_id; separate_audio_option |= youtube_url_extract_id(url, video_id); @@ -2993,7 +3003,7 @@ namespace QuickMedia { separate_audio_option = false; if(!separate_audio_option) { - download_async_gui(url, file_manager_start_dir.string(), no_video); + download_async_gui(url, file_manager_start_dir.string(), no_video, filename); return; } @@ -3023,7 +3033,7 @@ namespace QuickMedia { if(!selected) return; - download_async_gui(url, file_manager_start_dir.string(), audio_only); + download_async_gui(url, file_manager_start_dir.string(), audio_only, filename); } bool Program::video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page) { @@ -3487,7 +3497,7 @@ namespace QuickMedia { } else if(pressed_keysym == XK_f && pressing_ctrl) { video_player->cycle_fullscreen(); } else if(pressed_keysym == XK_s && pressing_ctrl && !video_page->is_local()) { - video_page_download_video(video_page->get_download_url(video_get_max_height()), video_player_window); + video_page_download_video(video_page->get_download_url(video_get_max_height()), video_page->get_filename(), video_player_window); } else if(pressed_keysym == XK_F5 && !video_page->is_local()) { double resume_start_time = 0.0; video_player->get_time_in_file(&resume_start_time); @@ -4654,7 +4664,7 @@ namespace QuickMedia { } else if(event.key.code == mgl::Keyboard::S && event.key.control) { BodyItem *selected_item = thread_body->get_selected(); if(selected_item && !selected_item->url.empty()) - download_async_gui(selected_item->url, file_manager_start_dir.string(), false); + download_async_gui(selected_item->url, file_manager_start_dir.string(), false, ""); } BodyItem *selected_item = thread_body->get_selected(); @@ -4782,7 +4792,7 @@ namespace QuickMedia { redraw = true; frame_skip_text_entry = true; } else if(event.key.code == mgl::Keyboard::S && event.key.control) { - download_async_gui(attached_image_url, file_manager_start_dir.string(), false); + download_async_gui(attached_image_url, file_manager_start_dir.string(), false, ""); } } } @@ -5331,7 +5341,6 @@ namespace QuickMedia { } window.set_title(("QuickMedia - matrix - " + current_room->get_name()).c_str()); - auto video_page = std::make_unique<MatrixVideoPage>(this); bool move_room = false; std::vector<ChatTab> tabs; @@ -5751,15 +5760,15 @@ namespace QuickMedia { } }; - auto upload_file = [this, ¤t_room](const std::string &filepath) { - run_task_with_loading_screen([this, ¤t_room, filepath]() { + auto upload_file = [this, ¤t_room](const std::string &filepath, const std::string &filename) { + run_task_with_loading_screen([this, ¤t_room, filepath, filename]() { std::string filepath_mod = filepath; if(string_starts_with(filepath_mod, "file://")) filepath_mod.erase(filepath_mod.begin(), filepath_mod.begin() + 7); std::string event_id_response; std::string err_msg; - if(matrix->post_file(current_room, filepath_mod, event_id_response, err_msg) == PluginResult::OK) { + if(matrix->post_file(current_room, filepath_mod, filename, event_id_response, err_msg) == PluginResult::OK) { return true; } else { show_notification("QuickMedia", "Failed to upload media to room, error: " + err_msg, Urgency::CRITICAL); @@ -6379,7 +6388,7 @@ namespace QuickMedia { tabs[MESSAGES_TAB_INDEX].body->select_last_item(); }; - auto display_url_or_image = [this, matrix_chat_page, &ui_tabs, &redraw, &video_page, &launch_url, &chat_state, &url_selection_body, &avatar_applied, PINNED_TAB_INDEX, MESSAGES_TAB_INDEX](BodyItem *selected) { + auto display_url_or_image = [this, matrix_chat_page, &ui_tabs, &redraw, &launch_url, &chat_state, &url_selection_body, &avatar_applied, PINNED_TAB_INDEX, MESSAGES_TAB_INDEX](BodyItem *selected) { if(!selected) return false; @@ -6401,6 +6410,7 @@ namespace QuickMedia { bool is_audio = (message_type == MessageType::AUDIO); bool prev_no_video = no_video; no_video = is_audio; + auto video_page = std::make_unique<MatrixVideoPage>(this, selected_item_message->body); video_page->set_url(selected->url); video_content_page(matrix_chat_page, video_page.get(), selected_item_message->body, message_type == MessageType::VIDEO || message_type == MessageType::AUDIO, nullptr, 0); no_video = prev_no_video; @@ -6408,7 +6418,7 @@ namespace QuickMedia { avatar_applied = false; return true; } else if(message_type == MessageType::FILE) { - download_async_gui(selected->url, file_manager_start_dir.string(), no_video); + download_async_gui(selected->url, file_manager_start_dir.string(), no_video, selected_item_message->body); return true; } @@ -6449,7 +6459,7 @@ namespace QuickMedia { if(selected_item_message) { MessageType message_type = selected_item_message->type; if(!selected->url.empty() && message_type >= MessageType::IMAGE && message_type <= MessageType::FILE) { - download_async_gui(selected->url, file_manager_start_dir.string(), no_video); + download_async_gui(selected->url, file_manager_start_dir.string(), no_video, selected_item_message->body); return true; } } @@ -6763,8 +6773,9 @@ namespace QuickMedia { std::string clipboard_text; char tmp_filename[] = "/tmp/quickmedia_clipboard_XXXXXX"; int tmp_file = -1; + std::string file_ext; - const bool clipboard_success = window.get_clipboard([&first_part, &clipboard_text, &tmp_filename, &tmp_file](const unsigned char *data, size_t size, mgl_clipboard_type clipboard_type) { + const bool clipboard_success = window.get_clipboard([&first_part, &clipboard_text, &tmp_filename, &tmp_file, &file_ext](const unsigned char *data, size_t size, mgl_clipboard_type clipboard_type) { if(first_part) { first_part = false; if(clipboard_type != MGL_CLIPBOARD_TYPE_STRING) { @@ -6773,6 +6784,13 @@ namespace QuickMedia { show_notification("QuickMedia", "Failed to create temporary file " + std::string(tmp_filename) + " from clipboard (failed to create file)", Urgency::CRITICAL); return false; } + + if(clipboard_type == MGL_CLIPBOARD_TYPE_IMAGE_PNG) + file_ext = ".png"; + else if(clipboard_type == MGL_CLIPBOARD_TYPE_IMAGE_JPG) + file_ext = ".jpg"; + else if(clipboard_type == MGL_CLIPBOARD_TYPE_IMAGE_GIF) + file_ext = ".gif"; } } @@ -6792,8 +6810,14 @@ namespace QuickMedia { if(tmp_file != -1) clipboard_text = tmp_filename; - if(clipboard_success && !clipboard_text.empty() && get_file_type(clipboard_text) == FileType::REGULAR) - upload_file(clipboard_text); + if(clipboard_success && !clipboard_text.empty() && get_file_type(clipboard_text) == FileType::REGULAR) { + const time_t now = time(nullptr); + const struct tm *t = localtime(&now); + char filename[256]; + strftime(filename, sizeof(filename)-1, "Clipboard_%Y-%m-%d_%H-%M-%S", t); + strcat(filename, file_ext.c_str()); + upload_file(clipboard_text, filename); + } if(tmp_file != -1) { close(tmp_file); @@ -7034,7 +7058,7 @@ namespace QuickMedia { fprintf(stderr, "No files selected!\n"); } else { // TODO: Upload multiple files. - upload_file(selected_files[0]); + upload_file(selected_files[0], ""); } redraw = true; avatar_applied = false; @@ -7621,7 +7645,7 @@ namespace QuickMedia { return 0; } - void Program::download_page(std::string url) { + void Program::download_page(std::string url, std::string download_filename) { window.set_title(("QuickMedia - Select where you want to save " + std::string(url)).c_str()); url = invidious_url_to_youtube_url(url); @@ -7636,7 +7660,7 @@ namespace QuickMedia { int64_t video_content_length = 0; int64_t audio_content_length = 0; - TaskResult task_result; + TaskResult task_result = TaskResult::TRUE; if(download_use_youtube_dl) { if(!is_program_executable_by_name("youtube-dl")) { show_notification("QuickMedia", "youtube-dl needs to be installed to download the video/music", Urgency::CRITICAL); @@ -7753,9 +7777,13 @@ namespace QuickMedia { return; } } else { - task_result = run_task_with_loading_screen([url, &filename]{ - return url_get_remote_name(url, filename, true) == DownloadResult::OK; - }); + if(download_filename.empty()) { + task_result = run_task_with_loading_screen([url, &filename]{ + return url_get_remote_name(url, filename, true) == DownloadResult::OK; + }); + } else { + filename = std::move(download_filename); + } } if(task_result == TaskResult::CANCEL) { diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index f8ee2a2..00009fd 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -3671,7 +3671,7 @@ namespace QuickMedia { return filepath.c_str() + index + 1; } - PluginResult Matrix::post_file(RoomData *room, const std::string &filepath, std::string &event_id_response, std::string &err_msg) { + PluginResult Matrix::post_file(RoomData *room, const std::string &filepath, std::string filename, std::string &event_id_response, std::string &err_msg) { UploadInfo file_info; UploadInfo thumbnail_info; PluginResult upload_file_result = upload_file(room, filepath, file_info, thumbnail_info, err_msg); @@ -3683,7 +3683,9 @@ namespace QuickMedia { if(!thumbnail_info.content_uri.empty()) thumbnail_info_opt = std::move(thumbnail_info); - const char *filename = file_get_filename(filepath); + if(filename.empty()) + filename = file_get_filename(filepath); + return post_message(room, filename, event_id_response, file_info_opt, thumbnail_info_opt); } |