QuickMedia.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #pragma once
  2. #include "Body.hpp"
  3. #include "Page.hpp"
  4. #include "Tab.hpp"
  5. #include "MessageQueue.hpp"
  6. #include "AsyncTask.hpp"
  7. #include "../plugins/Plugin.hpp"
  8. #include "../plugins/FileManager.hpp"
  9. #include <vector>
  10. #include <memory>
  11. #include <mglpp/graphics/Font.hpp>
  12. #include <mglpp/graphics/Texture.hpp>
  13. #include <mglpp/window/Window.hpp>
  14. #include <mglpp/graphics/Shader.hpp>
  15. #include <unordered_set>
  16. #include <json/value.h>
  17. #include <future>
  18. #include <thread>
  19. #include <stack>
  20. typedef struct _XDisplay Display;
  21. namespace QuickMedia {
  22. class Matrix;
  23. class FileManager;
  24. class MangaImagesPage;
  25. class ImageBoardThreadPage;
  26. struct RoomData;
  27. class MatrixChatPage;
  28. class VideoPage;
  29. class Tabs;
  30. class VideoPlayer;
  31. class SearchBar;
  32. enum class ImageViewMode {
  33. SINGLE,
  34. SCROLL
  35. };
  36. struct CopyOp {
  37. Path source;
  38. Path destination;
  39. };
  40. enum class TaskResult {
  41. TRUE,
  42. FALSE,
  43. CANCEL
  44. };
  45. enum class FetchType {
  46. SEARCH,
  47. LAZY
  48. };
  49. struct FetchResult {
  50. BodyItems body_items;
  51. PluginResult result;
  52. };
  53. struct TabAssociatedData {
  54. std::string update_search_text;
  55. bool search_text_updated = false;
  56. FetchStatus fetch_status = FetchStatus::NONE;
  57. bool lazy_fetch_finished = false;
  58. FetchType fetch_type;
  59. bool typing = false;
  60. bool fetching_next_page_running = false;
  61. bool fetching_next_page_failed = false;
  62. bool search_suggestion_submitted = false;
  63. bool search_text_empty = true;
  64. bool card_view = false;
  65. int fetched_page = 0;
  66. mgl::Text search_result_text;
  67. AsyncTask<FetchResult> fetch_future;
  68. AsyncTask<BodyItems> next_page_future;
  69. std::string body_item_url_before_refresh;
  70. };
  71. struct LoginInput {
  72. std::string placeholder;
  73. SearchBarType type;
  74. };
  75. class Program {
  76. public:
  77. Program();
  78. ~Program();
  79. int run(int argc, char **argv);
  80. std::unique_ptr<Body> create_body(bool plain_text_list = false, bool prefer_card_view = false);
  81. std::unique_ptr<SearchBar> create_search_bar(const std::string &placeholder, int search_delay);
  82. void add_login_inputs(Tab *tab, std::vector<LoginInput> login_inputs);
  83. bool load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_url, const std::string &manga_id);
  84. void select_file(const std::string &filepath);
  85. bool is_window_focused();
  86. RoomData* get_current_chat_room();
  87. void set_go_to_previous_page();
  88. void set_pipe_selected_text(const std::string &text);
  89. TaskResult run_task_with_loading_screen(std::function<bool()> callback);
  90. const char* get_plugin_name() const;
  91. void manga_get_watch_history(const char *plugin_name, BodyItems &history_items, bool local_thumbnail);
  92. void youtube_get_watch_history(BodyItems &history_items);
  93. void update_manga_history(const std::string &manga_id, const std::string &thumbnail_url);
  94. Json::Value load_history_json();
  95. Json::Value load_recommended_json(const char *plugin_name);
  96. void fill_recommended_items_from_json(const char *plugin_name, const Json::Value &recommended_json, BodyItems &body_items);
  97. 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);
  98. void set_clipboard(const std::string &str);
  99. bool youtube_dl_extract_url(const std::string &url, std::string &video_url, std::string &audio_url);
  100. private:
  101. void init(mgl::WindowHandle parent_window, std::string &program_path, bool no_dialog);
  102. const char* get_youtube_dl_program_name();
  103. void check_youtube_dl_installed(const std::string &plugin_name);
  104. void load_plugin_by_name(std::vector<Tab> &tabs, int &start_tab_index, FileManagerMimeType fm_mime_type, FileSelectionHandler file_selection_handler, std::string instance);
  105. void common_event_handler(mgl::Event &event);
  106. void handle_x11_events();
  107. void base_event_handler(mgl::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_key_press = true, bool handle_searchbar = true);
  108. void event_idle_handler(const mgl::Event &event);
  109. void idle_active_handler();
  110. void update_idle_state();
  111. bool show_info_page(BodyItem *body_item, bool include_reverse_image_search);
  112. bool toggle_bookmark(BodyItem *body_item, const char *bookmark_name);
  113. 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);
  114. using PageLoopSubmitHandler = std::function<void(const std::vector<Tab> &new_tabs)>;
  115. // Returns false if the page loop was escaped by user navigation (pressing escape) or if there was an error at startup
  116. bool page_loop(std::vector<Tab> &tabs, int start_tab_index = 0, PageLoopSubmitHandler after_submit_handler = nullptr, bool go_to_previous_on_escape = true);
  117. void redirect_focus_to_video_player_window(mgl::WindowHandle video_player_window);
  118. void show_video_player_window(mgl::WindowHandle video_player_window);
  119. void video_page_download_video(const std::string &url, const std::string &filename, mgl::WindowHandle video_player_window = 0, bool download_no_dialog = false);
  120. 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);
  121. int video_get_max_height();
  122. 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 = "");
  123. void save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read);
  124. // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
  125. int image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off);
  126. // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
  127. int image_continuous_page(MangaImagesPage *images_page);
  128. void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body);
  129. void chat_login_page();
  130. bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room);
  131. void after_matrix_login_page();
  132. void download_page(std::string url, std::string download_filename, bool no_dialog);
  133. // Returns the full path where the file should be saved, or an empty string if the operation was cancelled
  134. std::string file_save_page(const std::string &filename);
  135. enum class LoadImageResult {
  136. OK,
  137. FAILED,
  138. DOWNLOAD_IN_PROGRESS
  139. };
  140. LoadImageResult load_image_by_index(int image_index, mgl::Texture &image_texture, std::string &error_message);
  141. void download_chapter_images_if_needed(MangaImagesPage *images_page);
  142. void select_episode(BodyItem *item, bool start_from_beginning);
  143. // Returns PageType::EXIT if empty
  144. PageType pop_page_stack();
  145. private:
  146. enum class UpscaleImageAction {
  147. NO,
  148. LOW_RESOLUTION,
  149. FORCE
  150. };
  151. enum class LaunchUrlType {
  152. NONE,
  153. YOUTUBE_VIDEO,
  154. YOUTUBE_CHANNEL,
  155. FOURCHAN_THREAD
  156. };
  157. Display *disp;
  158. mgl::Window window;
  159. Matrix *matrix = nullptr;
  160. bool matrix_instance_already_running = false;
  161. bool is_login_sync = false;
  162. mgl::vec2i window_size;
  163. const char *plugin_name = nullptr;
  164. mgl::Texture plugin_logo;
  165. mgl::Texture loading_icon;
  166. mgl::Sprite load_sprite;
  167. mgl::Clock load_sprite_timer;
  168. PageType current_page;
  169. std::stack<PageType> page_stack;
  170. int image_index;
  171. Path content_storage_file;
  172. Path content_cache_dir;
  173. std::string manga_id;
  174. std::string manga_id_base64;
  175. Json::Value content_storage_json;
  176. bool content_storage_file_modified = false;
  177. std::unordered_set<std::string> watched_videos;
  178. AsyncTask<BodyItems> search_suggestion_future;
  179. AsyncTask<std::string> autocomplete_future;
  180. AsyncTask<void, std::promise<int>> image_download_future;
  181. std::thread image_upscale_thead;
  182. MessageQueue<CopyOp> images_to_upscale_queue;
  183. std::vector<char> image_upscale_status;
  184. std::string downloading_chapter_url;
  185. bool image_download_cancel = false;
  186. std::future<int> num_manga_pages_future;
  187. int num_manga_pages = 0;
  188. int exit_code = 0;
  189. std::string resources_root;
  190. mgl::Shader circle_mask_shader;
  191. mgl::Shader rounded_rectangle_shader;
  192. mgl::Shader rounded_rectangle_mask_shader;
  193. bool no_video = false;
  194. bool force_no_video = false;
  195. UpscaleImageAction upscale_image_action = UpscaleImageAction::NO;
  196. // TODO: Save this to config file when switching modes
  197. ImageViewMode image_view_mode = ImageViewMode::SINGLE;
  198. std::vector<std::string> selected_files;
  199. bool fit_image_to_window = false;
  200. RoomData *current_chat_room = nullptr;
  201. bool go_to_previous_page = false;
  202. bool running_task_with_loading_screen = false;
  203. mgl::Vertex gradient_points[4];
  204. mgl::vec2f body_pos;
  205. mgl::vec2f body_size;
  206. bool show_room_side_panel = true;
  207. std::thread::id main_thread_id;
  208. mgl::Clock idle_timer;
  209. bool idle = true;
  210. bool low_cpu_mode = false;
  211. bool window_closed = false;
  212. std::string pipe_selected_text;
  213. std::filesystem::path file_manager_start_dir;
  214. std::string launch_url;
  215. LaunchUrlType launch_url_type = LaunchUrlType::NONE;
  216. std::unique_ptr<VideoPlayer> video_player;
  217. bool use_youtube_dl = false;
  218. int video_max_height = 0;
  219. std::mutex login_inputs_mutex;
  220. const char *yt_dl_name = nullptr;
  221. bool yt_dl_name_checked = false;
  222. bool show_manga_bottom_bar = true;
  223. };
  224. }