123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- #pragma once
- #include "Body.hpp"
- #include "Page.hpp"
- #include "Tab.hpp"
- #include "MessageQueue.hpp"
- #include "AsyncTask.hpp"
- #include "../plugins/Plugin.hpp"
- #include "../plugins/FileManager.hpp"
- #include <vector>
- #include <memory>
- #include <mglpp/graphics/Font.hpp>
- #include <mglpp/graphics/Texture.hpp>
- #include <mglpp/window/Window.hpp>
- #include <mglpp/graphics/Shader.hpp>
- #include <unordered_set>
- #include <json/value.h>
- #include <future>
- #include <thread>
- #include <stack>
- typedef struct _XDisplay Display;
- namespace QuickMedia {
- class Matrix;
- class FileManager;
- class MangaImagesPage;
- class ImageBoardThreadPage;
- struct RoomData;
- class MatrixChatPage;
- class VideoPage;
- class Tabs;
- class VideoPlayer;
- class SearchBar;
- enum class ImageViewMode {
- SINGLE,
- SCROLL
- };
- struct CopyOp {
- Path source;
- Path destination;
- };
- enum class TaskResult {
- TRUE,
- FALSE,
- CANCEL
- };
- enum class FetchType {
- SEARCH,
- LAZY
- };
- struct FetchResult {
- BodyItems body_items;
- PluginResult result;
- };
- struct TabAssociatedData {
- std::string update_search_text;
- bool search_text_updated = false;
- FetchStatus fetch_status = FetchStatus::NONE;
- bool lazy_fetch_finished = false;
- FetchType fetch_type;
- bool typing = false;
- bool fetching_next_page_running = false;
- bool fetching_next_page_failed = false;
- bool search_suggestion_submitted = false;
- bool search_text_empty = true;
- bool card_view = false;
- int fetched_page = 0;
- mgl::Text search_result_text;
- AsyncTask<FetchResult> fetch_future;
- AsyncTask<BodyItems> next_page_future;
- std::string body_item_url_before_refresh;
- };
- struct LoginInput {
- std::string placeholder;
- SearchBarType type;
- };
-
- class Program {
- public:
- Program();
- ~Program();
- int run(int argc, char **argv);
- std::unique_ptr<Body> create_body(bool plain_text_list = false, bool prefer_card_view = false);
- std::unique_ptr<SearchBar> create_search_bar(const std::string &placeholder, int search_delay);
- void add_login_inputs(Tab *tab, std::vector<LoginInput> login_inputs);
- bool load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_url, const std::string &manga_id);
- void select_file(const std::string &filepath);
- bool is_window_focused();
- RoomData* get_current_chat_room();
- void set_go_to_previous_page();
- void set_pipe_selected_text(const std::string &text);
- TaskResult run_task_with_loading_screen(std::function<bool()> callback);
- const char* get_plugin_name() const;
- void manga_get_watch_history(const char *plugin_name, BodyItems &history_items, bool local_thumbnail);
- void youtube_get_watch_history(BodyItems &history_items);
- void update_manga_history(const std::string &manga_id, const std::string &thumbnail_url);
- Json::Value load_history_json();
- Json::Value load_recommended_json(const char *plugin_name);
- void fill_recommended_items_from_json(const char *plugin_name, const Json::Value &recommended_json, BodyItems &body_items);
- void save_recommendations_from_related_videos(const char *plugin_name, const std::string &video_url, const std::string &video_title, const BodyItems &related_media_body_items);
- void set_clipboard(const std::string &str);
- bool youtube_dl_extract_url(const std::string &url, std::string &video_url, std::string &audio_url);
- private:
- void init(mgl::WindowHandle parent_window, std::string &program_path, bool no_dialog);
- const char* get_youtube_dl_program_name();
- void check_youtube_dl_installed(const std::string &plugin_name);
- void load_plugin_by_name(std::vector<Tab> &tabs, int &start_tab_index, FileManagerMimeType fm_mime_type, FileSelectionHandler file_selection_handler, std::string instance);
- void common_event_handler(mgl::Event &event);
- void handle_x11_events();
- void base_event_handler(mgl::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_key_press = true, bool handle_searchbar = true);
- void event_idle_handler(const mgl::Event &event);
- void idle_active_handler();
- void update_idle_state();
- bool show_info_page(BodyItem *body_item, bool include_reverse_image_search);
- bool toggle_bookmark(BodyItem *body_item, const char *bookmark_name);
- void page_loop_render(mgl::Window &window, std::vector<Tab> &tabs, int selected_tab, TabAssociatedData &tab_associated_data, const Json::Value *json_chapters, Tabs &ui_tabs);
- using PageLoopSubmitHandler = std::function<void(const std::vector<Tab> &new_tabs)>;
- // Returns false if the page loop was escaped by user navigation (pressing escape) or if there was an error at startup
- 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, const std::string &filename, mgl::WindowHandle video_player_window = 0, bool download_no_dialog = false);
- 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 = "");
- void save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read);
- // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
- int image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off);
- // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
- int image_continuous_page(MangaImagesPage *images_page);
- void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body);
- 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, std::string download_filename, bool no_dialog);
- // 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);
- enum class LoadImageResult {
- OK,
- FAILED,
- DOWNLOAD_IN_PROGRESS
- };
- LoadImageResult load_image_by_index(int image_index, mgl::Texture &image_texture, std::string &error_message);
- void download_chapter_images_if_needed(MangaImagesPage *images_page);
- void select_episode(BodyItem *item, bool start_from_beginning);
- // Returns PageType::EXIT if empty
- PageType pop_page_stack();
- private:
- enum class UpscaleImageAction {
- NO,
- LOW_RESOLUTION,
- FORCE
- };
- enum class LaunchUrlType {
- NONE,
- YOUTUBE_VIDEO,
- YOUTUBE_CHANNEL,
- FOURCHAN_THREAD
- };
- Display *disp;
- mgl::Window window;
- Matrix *matrix = nullptr;
- bool matrix_instance_already_running = false;
- bool is_login_sync = false;
- mgl::vec2i window_size;
- const char *plugin_name = nullptr;
- mgl::Texture plugin_logo;
- mgl::Texture loading_icon;
- mgl::Sprite load_sprite;
- mgl::Clock load_sprite_timer;
- PageType current_page;
- std::stack<PageType> page_stack;
- int image_index;
- Path content_storage_file;
- Path content_cache_dir;
- std::string manga_id;
- std::string manga_id_base64;
- Json::Value content_storage_json;
- bool content_storage_file_modified = false;
- std::unordered_set<std::string> watched_videos;
- AsyncTask<BodyItems> search_suggestion_future;
- AsyncTask<std::string> autocomplete_future;
- AsyncTask<void, std::promise<int>> image_download_future;
- std::thread image_upscale_thead;
- MessageQueue<CopyOp> images_to_upscale_queue;
- std::vector<char> image_upscale_status;
- std::string downloading_chapter_url;
- bool image_download_cancel = false;
- std::future<int> num_manga_pages_future;
- int num_manga_pages = 0;
- int exit_code = 0;
- std::string resources_root;
- mgl::Shader circle_mask_shader;
- mgl::Shader rounded_rectangle_shader;
- mgl::Shader rounded_rectangle_mask_shader;
- bool no_video = false;
- bool force_no_video = false;
- UpscaleImageAction upscale_image_action = UpscaleImageAction::NO;
- // TODO: Save this to config file when switching modes
- ImageViewMode image_view_mode = ImageViewMode::SINGLE;
- std::vector<std::string> selected_files;
- bool fit_image_to_window = false;
- RoomData *current_chat_room = nullptr;
- bool go_to_previous_page = false;
- bool running_task_with_loading_screen = false;
- mgl::Vertex gradient_points[4];
- mgl::vec2f body_pos;
- mgl::vec2f body_size;
- bool show_room_side_panel = true;
- std::thread::id main_thread_id;
- mgl::Clock idle_timer;
- bool idle = true;
- bool low_cpu_mode = false;
- bool window_closed = false;
- std::string pipe_selected_text;
- std::filesystem::path file_manager_start_dir;
- std::string launch_url;
- LaunchUrlType launch_url_type = LaunchUrlType::NONE;
- std::unique_ptr<VideoPlayer> video_player;
- bool use_youtube_dl = false;
- int video_max_height = 0;
- std::mutex login_inputs_mutex;
- const char *yt_dl_name = nullptr;
- bool yt_dl_name_checked = false;
- bool show_manga_bottom_bar = true;
- };
- }
|