aboutsummaryrefslogtreecommitdiff
path: root/src/QuickMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r--src/QuickMedia.cpp298
1 files changed, 245 insertions, 53 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index b4fa915..13b9369 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -29,6 +29,7 @@
#include "../include/ResourceLoader.hpp"
#include "../include/Utils.hpp"
#include "../include/Tabs.hpp"
+#include "../include/gui/Button.hpp"
#include "../external/hash-library/sha256.h"
#include <assert.h>
@@ -599,7 +600,7 @@ namespace QuickMedia {
window.create(x11_window);
- if(program_path.back() != '/')
+ if(!program_path.empty() && program_path.back() != '/')
program_path += '/';
resources_root = "/usr/share/quickmedia/";
@@ -1531,6 +1532,7 @@ namespace QuickMedia {
if(tabs[selected_tab].page->is_single_page()) {
if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->clear();
if(new_tabs.size() == 1 && !new_tabs[0].page) {
+ tabs[selected_tab].body->clear_thumbnails();
tabs[selected_tab].body = std::move(new_tabs[0].body);
tabs[selected_tab].page->submit_body_item = prev_selected_item;
return;
@@ -1854,6 +1856,7 @@ namespace QuickMedia {
if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && associated_data.fetch_future.ready()) {
if(!associated_data.search_text_updated) {
FetchResult fetch_result = associated_data.fetch_future.get();
+ tabs[i].body->clear_thumbnails();
tabs[i].body->items = std::move(fetch_result.body_items);
tabs[i].body->select_first_item();
associated_data.fetched_page = 0;
@@ -2270,7 +2273,7 @@ namespace QuickMedia {
} else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C && event.key.control) {
save_video_url_to_clipboard();
} else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::S && event.key.control) {
- download_async_gui(original_video_url, true, force_no_video);
+ download_async_gui(original_video_url, true, no_video);
}
}
handle_window_close();
@@ -2287,7 +2290,7 @@ namespace QuickMedia {
} else if(pressed_keysym == XK_f && pressing_ctrl) {
window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE);
} else if(pressed_keysym == XK_s && pressing_ctrl) {
- download_async_gui(original_video_url, true, force_no_video);
+ download_async_gui(original_video_url, true, no_video);
} else if(pressed_keysym == XK_r && pressing_ctrl) {
if(!cursor_visible)
window.setMouseCursorVisible(true);
@@ -2595,7 +2598,7 @@ namespace QuickMedia {
};
} else if(website_url && website_url[0] != '\0') {
std::string website_url_str = website_url;
- if(website_url_str.back() != '/')
+ if(!website_url_str.empty() && website_url_str.back() != '/')
website_url_str.push_back('/');
extra_args = {
CommandArg { "-H", "referer: " + std::move(website_url_str) },
@@ -4733,7 +4736,7 @@ namespace QuickMedia {
if(selected_item_message) {
MessageType message_type = selected_item_message->type;
if(!selected->url.empty() && (message_type == MessageType::VIDEO || message_type == MessageType::IMAGE || message_type == MessageType::AUDIO)) {
- download_async_gui(selected->url, false, force_no_video);
+ download_async_gui(selected->url, false, no_video);
return true;
}
}
@@ -5919,60 +5922,57 @@ namespace QuickMedia {
bool no_video;
};
- static const char* get_filename(const char *path) {
- const char *p = (const char*)memrchr(path, '/', strlen(path));
- return p ? p + 1 : path;
+ static int accumulate_string(char *data, int size, void *userdata) {
+ std::string *str = (std::string*)userdata;
+ if(str->size() + size > 1024 * 1024 * 100) // 100mb sane limit, TODO: make configurable
+ return 1;
+ str->append(data, size);
+ return 0;
}
- class ConfirmationPage : public Page {
- public:
- ConfirmationPage(Program *program, FileManagerPage *file_manager_page, bool *file_overwrite, const std::string &title) : Page(program), file_manager_page(file_manager_page), file_overwrite(file_overwrite), title(title) {}
- const char* get_title() const override { return title.c_str(); }
- PluginResult submit(const std::string &title, const std::string&, std::vector<Tab>&) override {
- if(title == "Yes") {
- *file_overwrite = true;
- file_manager_page->close = true;
- } else {
- *file_overwrite = false;
+ void Program::download_page(const char *url, bool download_use_youtube_dl) {
+ window.setTitle("QuickMedia - Select where you want to save " + std::string(url));
+
+ std::string filename;
+ TaskResult task_result = run_task_with_loading_screen([this, url, &filename]{
+ std::string json_str;
+ std::vector<const char*> args = { "youtube-dl", "--skip-download", "--print-json", "--no-warnings" };
+ if(no_video)
+ args.push_back("-x");
+ args.insert(args.end(), { "--", url, nullptr });
+ if(exec_program(args.data(), accumulate_string, &json_str) != 0)
+ return false;
+
+ Json::Value result;
+ Json::CharReaderBuilder json_builder;
+ std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader());
+ std::string json_errors;
+ if(!json_reader->parse(json_str.data(), json_str.data() + json_str.size(), &result, &json_errors)) {
+ fprintf(stderr, "Failed to json response, error: %s\n", json_errors.c_str());
+ return false;
}
- program->set_go_to_previous_page();
- return PluginResult::OK;
- }
- static void add_items(BodyItems &items) {
- items.push_back(BodyItem::create("No"));
- items.push_back(BodyItem::create("Yes"));
- }
- private:
- FileManagerPage *file_manager_page;
- bool *file_overwrite;
- std::string title;
- };
+ const Json::Value &title_json = result["title"];
+ const Json::Value &ext_json = result["ext"];
+ if(title_json.isString())
+ filename = title_json.asString();
- void Program::download_page(const char *url, bool download_use_youtube_dl) {
- bool file_overwrite = true;
- FileSelectionHandler overwrite_confirm_handler = [this, &file_overwrite](FileManagerPage *file_manager_page, const std::filesystem::path &path) {
- file_overwrite = true;
- std::vector<Tab> tabs;
- if(std::filesystem::exists(path)) {
- auto body = create_body();
- ConfirmationPage::add_items(body->items);
- tabs.push_back(Tab{ std::move(body), std::make_unique<ConfirmationPage>(this, file_manager_page, &file_overwrite, "Are you sure you want to overwrite " + path.string() + "?"), nullptr });
+ if(ext_json.isString()) {
+ if(ext_json.asCString()[0] != '.' && (filename.empty() || filename.back() != '.'))
+ filename += ".";
+ filename += ext_json.asString();
}
- return tabs;
- };
- auto file_manager_page = std::make_unique<FileManagerPage>(this, FILE_MANAGER_MIME_TYPE_ALL, std::move(overwrite_confirm_handler), true, "Where do you want to save the file? Current directory: ");
- file_manager_page->set_current_directory(get_home_dir().data);
- auto file_manager_body = create_body();
- file_manager_page->get_files_in_directory(file_manager_body->items);
- std::vector<Tab> file_manager_tabs;
- file_manager_tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ return !filename.empty();
+ });
- selected_files.clear();
- page_loop(file_manager_tabs);
+ if(task_result == TaskResult::CANCEL) {
+ exit_code = 1;
+ return;
+ }
- if(!window.isOpen() || selected_files.empty() || !file_overwrite) {
+ std::string output_filepath = file_save_page(filename);
+ if(!window.isOpen() || output_filepath.empty()) {
exit_code = 1;
return;
}
@@ -5998,7 +5998,6 @@ namespace QuickMedia {
}
window.setPosition(sf::Vector2i(focused_monitor_center.x - window_size.x * 0.5f, focused_monitor_center.y - window_size.y * 0.5f));
- std::string output_filepath = selected_files[0];
std::string output_filepath_s = output_filepath;
char *output_dir = dirname(output_filepath_s.data());
if(create_directory_recursive(output_dir) != 0) {
@@ -6022,7 +6021,7 @@ namespace QuickMedia {
sf::Text progress_text("0kb/Unknown", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(20.0f * get_ui_scale()));
sf::Text status_text("Downloading", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(20.0f * get_ui_scale()));
- sf::Text filename_text(get_filename(output_filepath.c_str()), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale()));
+ sf::Text filename_text(filename.c_str(), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale()));
filename_text.setFillColor(sf::Color(179, 179, 179));
sf::Text download_speed_text("0 bytes/s", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale()));
download_speed_text.setFillColor(sf::Color(179, 179, 179));
@@ -6032,7 +6031,7 @@ namespace QuickMedia {
std::unique_ptr<Downloader> downloader;
if(download_use_youtube_dl)
- downloader = std::make_unique<YoutubeDlDownloader>(url, output_filepath, force_no_video);
+ downloader = std::make_unique<YoutubeDlDownloader>(url, output_filepath, no_video);
else
downloader = std::make_unique<CurlDownloader>(url, output_filepath);
@@ -6139,4 +6138,197 @@ namespace QuickMedia {
}
exit(exit_code);
}
+
+ class ConfirmationPage : public Page {
+ public:
+ ConfirmationPage(Program *program, bool *file_overwrite, const std::string &title) : Page(program), file_overwrite(file_overwrite), title(title) {}
+ const char* get_title() const override { return title.c_str(); }
+ PluginResult submit(const std::string &title, const std::string&, std::vector<Tab>&) override {
+ if(title == "Yes")
+ *file_overwrite = true;
+ else
+ *file_overwrite = false;
+
+ program->set_go_to_previous_page();
+ return PluginResult::OK;
+ }
+
+ static void add_items(BodyItems &items) {
+ items.push_back(BodyItem::create("No"));
+ items.push_back(BodyItem::create("Yes"));
+ }
+ private:
+ bool *file_overwrite;
+ std::string title;
+ };
+
+ std::string Program::file_save_page(const std::string &filename) {
+ sf::Vector2f body_pos;
+ sf::Vector2f body_size;
+ bool redraw = true;
+ sf::Event event;
+
+ auto file_manager_page = std::make_unique<FileManagerPage>(this);
+ std::string home_dir = get_home_dir().data;
+ file_manager_page->set_current_directory(home_dir);
+ auto file_manager_body = create_body();
+ file_manager_page->get_files_in_directory(file_manager_body->items);
+ auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER);
+
+ Tabs ui_tabs(&rounded_rectangle_shader);
+ const int tab_path_index = ui_tabs.add_tab(home_dir);
+
+ search_bar->onTextUpdateCallback = [&file_manager_body](const std::string &text) {
+ file_manager_body->filter_search_fuzzy(text);
+ file_manager_body->select_first_item();
+ };
+
+ search_bar->onTextSubmitCallback = [this, &search_bar, &file_manager_body, &file_manager_page, &ui_tabs, tab_path_index](const std::string&) {
+ if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
+ return;
+
+ BodyItem *selected = file_manager_body->get_selected();
+ if(!selected)
+ return;
+
+ std::vector<Tab> new_tabs;
+ TaskResult task_result = run_task_with_loading_screen([selected, &file_manager_page, &new_tabs]() {
+ return file_manager_page->submit(selected->get_title(), selected->url, new_tabs) == PluginResult::OK;
+ });
+
+ if(task_result == TaskResult::TRUE) {
+ if(!new_tabs.empty()) {
+ file_manager_body->clear_thumbnails();
+ file_manager_body->items = std::move(new_tabs[0].body->items);
+ }
+ } else if(task_result == TaskResult::FALSE) {
+ show_notification("QuickMedia", "Failed to change directory", Urgency::CRITICAL);
+ }
+
+ search_bar->clear();
+ ui_tabs.set_text(tab_path_index, file_manager_page->get_current_directory().string());
+ };
+
+ const float bottom_panel_padding = 10.0f;
+ const float bottom_panel_spacing = 10.0f;
+
+ Button cancel_button("Cancel", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale());
+ cancel_button.set_background_color(sf::Color(104, 2, 2));
+
+ Button save_button("Save", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale());
+ save_button.set_background_color(sf::Color(35, 35, 236));
+
+ sf::Text file_name_label("File name:", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16.0f * get_ui_scale()));
+
+ Entry file_name_entry("", &rounded_rectangle_shader);
+ file_name_entry.set_text(filename);
+ file_name_entry.set_single_line(true);
+ file_name_entry.set_editable(false);
+
+ sf::RectangleShape bottom_panel_background;
+ bottom_panel_background.setFillColor(sf::Color(33, 37, 44));
+
+ auto save_file = [this, &file_name_entry, &file_manager_page]() -> std::string {
+ auto u8 = file_name_entry.get_text().toUtf8();
+ std::string *filename = (std::string*)&u8;
+
+ Path filename_full_path = file_manager_page->get_current_directory().string();
+ filename_full_path.join(*filename);
+
+ if(filename->empty()) {
+ show_notification("QuickMedia", "The file name can't be empty", Urgency::CRITICAL);
+ } else if(*filename == "." || *filename == ".." || filename->find('/') != std::string::npos) {
+ show_notification("QuickMedia", "Invalid file name. File can't be ., .. or contain /", Urgency::CRITICAL);
+ } else if(filename->size() >= 255 || filename_full_path.data.size() >= 4096) {
+ show_notification("QuickMedia", "The file name has to be less than 255 characters and the full path has to be less than 4096 characters", Urgency::CRITICAL);
+ } else {
+ if(std::filesystem::exists(filename_full_path.data)) {
+ bool overwrite = false;
+ std::vector<Tab> tabs;
+ auto body = create_body();
+ ConfirmationPage::add_items(body->items);
+ tabs.push_back(Tab{ std::move(body), std::make_unique<ConfirmationPage>(this, &overwrite, "Are you sure you want to overwrite " + filename_full_path.data + "?"), nullptr });
+ page_loop(tabs);
+ if(overwrite)
+ return std::move(filename_full_path.data);
+ } else {
+ return std::move(filename_full_path.data);
+ }
+ }
+
+ return "";
+ };
+
+ while (window.isOpen()) {
+ while (window.pollEvent(event)) {
+ if(file_manager_body->on_event(window, event, !file_name_entry.is_editable()))
+ idle_active_handler();
+ else
+ event_idle_handler(event);
+
+ search_bar->on_event(event);
+ if(cancel_button.on_event(event) & BUTTON_EVENT_CLICKED)
+ return "";
+ if(save_button.on_event(event) & BUTTON_EVENT_CLICKED) {
+ std::string save_path = save_file();
+ if(!save_path.empty())
+ return save_path;
+ }
+ file_name_entry.process_event(event);
+
+ if(event.type == sf::Event::Resized) {
+ window_size.x = event.size.width;
+ window_size.y = event.size.height;
+ sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
+ window.setView(sf::View(visible_area));
+ redraw = true;
+ idle_active_handler();
+ } else if(event.type == sf::Event::GainedFocus) {
+ redraw = true;
+ } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Tab) {
+ file_name_entry.set_editable(!file_name_entry.is_editable());
+ search_bar->set_editable(!file_name_entry.is_editable());
+ } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Enter && event.key.control) {
+ std::string save_path = save_file();
+ if(!save_path.empty())
+ return save_path;
+ }
+ }
+
+ update_idle_state();
+ handle_window_close();
+ search_bar->update();
+
+ if(redraw) {
+ redraw = false;
+ get_body_dimensions(window_size, search_bar.get(), body_pos, body_size);
+ body_pos.y += std::floor(10.0f * get_ui_scale()) + Tabs::get_height();
+ body_size.y -= std::floor(10.0f * get_ui_scale()) + Tabs::get_height();
+ save_button.set_position(window_size - sf::Vector2f(save_button.get_width(), save_button.get_height()) - sf::Vector2f(bottom_panel_padding, bottom_panel_padding));
+ cancel_button.set_position(save_button.get_position() - sf::Vector2f(cancel_button.get_width() + bottom_panel_spacing, 0.0f));
+ file_name_label.setPosition(sf::Vector2f(bottom_panel_spacing, std::floor(window_size.y - bottom_panel_padding - file_name_entry.get_height() * 0.5f - file_name_label.getLocalBounds().height * 0.5f - 5.0f * get_ui_scale())));
+ file_name_entry.set_position(sf::Vector2f(file_name_label.getPosition().x + file_name_label.getLocalBounds().width + bottom_panel_spacing, window_size.y - file_name_entry.get_height() - bottom_panel_padding));
+ file_name_entry.set_max_width(std::floor(cancel_button.get_position().x - bottom_panel_spacing - file_name_label.getLocalBounds().width - bottom_panel_spacing - bottom_panel_spacing));
+ bottom_panel_background.setPosition(0.0f, window_size.y - std::floor(bottom_panel_padding * 2.0f + file_name_entry.get_height()));
+ bottom_panel_background.setSize(sf::Vector2f(window_size.x, std::floor(bottom_panel_padding * 2.0f + file_name_entry.get_height())));
+ }
+
+ window.clear(back_color);
+
+ ui_tabs.draw(window, sf::Vector2f(0.0f, search_bar->getBottomWithoutShadow()), window_size.x);
+ search_bar->draw(window, window_size, true);
+
+ file_manager_body->draw(window, body_pos, body_size - sf::Vector2f(0.0f, bottom_panel_background.getSize().y));
+
+ window.draw(bottom_panel_background);
+ window.draw(file_name_label);
+ cancel_button.draw(window);
+ save_button.draw(window);
+ file_name_entry.draw(window);
+
+ window.display();
+ }
+
+ return "";
+ }
}