aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-10-23 07:26:39 +0200
committerdec05eba <dec05eba@protonmail.com>2020-10-23 07:26:39 +0200
commit261b0263f34ffcbe439d68b2e901fd3abbfc1eaf (patch)
tree735d49f2050b52a414766675e4226f3fa8ef0d08 /src
parent05ce6bac22d498fb2827df72f4c2b86d02826042 (diff)
Re-add creators page
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp20
-rw-r--r--src/QuickMedia.cpp257
-rw-r--r--src/SearchBar.cpp25
-rw-r--r--src/plugins/FileManager.cpp1
-rw-r--r--src/plugins/Fourchan.cpp2
-rw-r--r--src/plugins/Manga.cpp6
-rw-r--r--src/plugins/Mangadex.cpp13
-rw-r--r--src/plugins/Manganelo.cpp159
-rw-r--r--src/plugins/Mangatown.cpp20
-rw-r--r--src/plugins/NyaaSi.cpp2
10 files changed, 285 insertions, 220 deletions
diff --git a/src/Body.cpp b/src/Body.cpp
index ee32b08..20e7404 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -86,7 +86,7 @@ namespace QuickMedia {
progress_text("", *font, 14),
replies_text("", *font, 14),
embedded_item_load_text("", *font, 14),
- draw_thumbnails(false),
+ draw_thumbnails(true),
wrap_around(false),
line_separator_color(sf::Color(32, 37, 43, 255)),
body_item_render_callback(nullptr),
@@ -574,15 +574,15 @@ namespace QuickMedia {
}
// TODO: Better message? maybe fallback to the reply message, or message status (such as message redacted)
- static const char* embedded_item_status_to_string(EmbeddedItemStatus embedded_item_status) {
+ static const char* embedded_item_status_to_string(FetchStatus embedded_item_status) {
switch(embedded_item_status) {
- case EmbeddedItemStatus::NONE:
+ case FetchStatus::NONE:
return "";
- case EmbeddedItemStatus::LOADING:
+ case FetchStatus::LOADING:
return "Loading message...";
- case EmbeddedItemStatus::FINISHED_LOADING:
+ case FetchStatus::FINISHED_LOADING:
return "Finished loading message...";
- case EmbeddedItemStatus::FAILED_TO_LOAD:
+ case FetchStatus::FAILED_TO_LOAD:
return "Failed to load message!";
}
return "";
@@ -591,7 +591,7 @@ namespace QuickMedia {
void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item) {
// TODO: Instead of generating a new hash everytime to access textures, cache the hash of the thumbnail url
std::shared_ptr<ThumbnailData> item_thumbnail;
- if(draw_thumbnails) {
+ if(draw_thumbnails && !item->thumbnail_url.empty()) {
auto item_thumbnail_it = item_thumbnail_textures.find(item->thumbnail_url);
if(item_thumbnail_it == item_thumbnail_textures.end()) {
item_thumbnail = std::make_shared<ThumbnailData>();
@@ -620,7 +620,7 @@ namespace QuickMedia {
}
float text_offset_x = padding_x;
- if(draw_thumbnails) {
+ if(draw_thumbnails && !item->thumbnail_url.empty()) {
double elapsed_time_thumbnail = 0.0;
if(item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE)
elapsed_time_thumbnail = item_thumbnail->texture_applied_time.getElapsedTime().asSeconds(); //thumbnail_fade_duration_sec
@@ -707,7 +707,7 @@ namespace QuickMedia {
item_pos.y += item->author_text->getHeight() - 2.0f;
}
- if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) {
+ if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) {
float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), true, false) : (embedded_item_load_text.getLocalBounds().height + embedded_item_padding_y * 2.0f);
const float border_width = 4.0f;
sf::RectangleShape border_left(sf::Vector2f(border_width, std::floor(embedded_item_height)));
@@ -776,7 +776,7 @@ namespace QuickMedia {
if(item->author_text) {
item_height += item->author_text->getHeight() - 2.0f;
}
- if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) {
+ if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) {
if(item->embedded_item)
item_height += (get_item_height(item->embedded_item.get(), load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f);
else
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 046ba9d..c9950a0 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -40,7 +40,7 @@
static const sf::Color back_color(21, 25, 30);
static const std::string fourchan_google_captcha_api_key = "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc";
-static const float tab_text_size = 18.0f;
+static const float tab_text_size = 16.0f;
static const float tab_height = tab_text_size + 10.0f;
static const sf::Color tab_selected_color(55, 60, 68);
static const float tab_margin_x = 10.0f;
@@ -188,6 +188,11 @@ namespace QuickMedia {
Page *search_page;
};
+ template <typename T>
+ static bool is_future_ready(const std::future<T> &future) {
+ return future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
+ }
+
static Path get_recommended_filepath(const char *plugin_name) {
Path video_history_dir = get_storage_dir().join("recommended");
if(create_directory_recursive(video_history_dir) != 0) {
@@ -555,7 +560,6 @@ namespace QuickMedia {
if(strcmp(plugin_name, "manganelo") == 0) {
auto search_body = create_body();
- search_body->draw_thumbnails = true;
tabs.push_back(Tab{std::move(search_body), std::make_unique<ManganeloSearchPage>(this), create_search_bar("Search...", 200)});
auto history_body = create_body();
@@ -563,7 +567,6 @@ namespace QuickMedia {
tabs.push_back(Tab{std::move(history_body), std::make_unique<HistoryPage>(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "mangatown") == 0) {
auto search_body = create_body();
- search_body->draw_thumbnails = true;
tabs.push_back(Tab{std::move(search_body), std::make_unique<MangatownSearchPage>(this), create_search_bar("Search...", 200)});
auto history_body = create_body();
@@ -571,7 +574,6 @@ namespace QuickMedia {
tabs.push_back(Tab{std::move(history_body), std::make_unique<HistoryPage>(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "mangadex") == 0) {
auto search_body = create_body();
- search_body->draw_thumbnails = true;
tabs.push_back(Tab{std::move(search_body), std::make_unique<MangadexSearchPage>(this), create_search_bar("Search...", 300)});
auto history_body = create_body();
@@ -598,21 +600,17 @@ namespace QuickMedia {
tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "youtube") == 0) {
auto search_body = create_body();
- search_body->draw_thumbnails = true;
tabs.push_back(Tab{std::move(search_body), std::make_unique<YoutubeSearchPage>(this), create_search_bar("Search...", 350)});
auto history_body = create_body();
- history_body->draw_thumbnails = true;
youtube_get_watch_history(history_body->items);
tabs.push_back(Tab{std::move(history_body), std::make_unique<HistoryPage>(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
auto recommended_body = create_body();
- recommended_body->draw_thumbnails = true;
fill_recommended_items_from_json(plugin_name, load_recommended_json(), recommended_body->items);
tabs.push_back(Tab{std::move(recommended_body), std::make_unique<RecommendedPage>(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "pornhub") == 0) {
auto search_body = create_body();
- search_body->draw_thumbnails = true;
tabs.push_back(Tab{std::move(search_body), std::make_unique<PornhubSearchPage>(this), create_search_bar("Search...", 500)});
}
@@ -928,6 +926,7 @@ namespace QuickMedia {
for(Tab &tab : tabs) {
tab.body->thumbnail_max_size = tab.page->get_thumbnail_max_size();
+ tab.page->on_navigate_to_page();
}
const Json::Value *json_chapters = &Json::Value::nullSingleton();
@@ -937,15 +936,27 @@ namespace QuickMedia {
json_chapters = &chapters_json;
}
+ enum class FetchType {
+ SEARCH,
+ LAZY
+ };
+
+ struct FetchResult {
+ BodyItems body_items;
+ PluginResult result;
+ };
+
struct TabAssociatedData {
std::string update_search_text;
bool search_text_updated = false;
- bool search_running = false;
+ FetchStatus fetch_status = FetchStatus::NONE;
+ bool lazy_fetch_finished = false;
+ FetchType fetch_type;
bool typing = false;
bool fetching_next_page_running = false;
int fetched_page = 0;
sf::Text search_result_text;
- std::future<BodyItems> search_future;
+ std::future<FetchResult> fetch_future;
std::future<BodyItems> next_page_future;
};
@@ -969,7 +980,7 @@ namespace QuickMedia {
bool loop_running = true;
bool redraw = true;
- auto submit_handler = [this, &tabs, &selected_tab, &loop_running, &redraw]() {
+ auto submit_handler = [this, &json_chapters, &tabs, &selected_tab, &loop_running, &redraw]() {
BodyItem *selected_item = tabs[selected_tab].body->get_selected();
if(!selected_item)
return;
@@ -1039,6 +1050,10 @@ namespace QuickMedia {
redraw = true;
} else {
page_loop(std::move(new_tabs));
+ tabs[selected_tab].page->on_navigate_to_page();
+ const Json::Value &chapters_json = content_storage_json["chapters"];
+ if(chapters_json.isObject())
+ json_chapters = &chapters_json;
}
} else {
// TODO: Show the exact cause of error (get error message from curl).
@@ -1093,6 +1108,8 @@ namespace QuickMedia {
while (window.isOpen() && loop_running) {
sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds();
+ Tab &current_tab = tabs[selected_tab];
+ TabAssociatedData &current_tab_associated_data = tab_associated_data[selected_tab];
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
@@ -1104,10 +1121,10 @@ namespace QuickMedia {
window.setView(sf::View(visible_area));
}
- if(tabs[selected_tab].search_bar) {
+ if(current_tab.search_bar) {
if(event.type == sf::Event::TextEntered)
- tabs[selected_tab].search_bar->onTextEntered(event.text.unicode);
- tabs[selected_tab].search_bar->on_event(event);
+ current_tab.search_bar->onTextEntered(event.text.unicode);
+ current_tab.search_bar->on_event(event);
}
if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus)
@@ -1117,26 +1134,26 @@ namespace QuickMedia {
bool hit_bottom = false;
switch(event.key.code) {
case sf::Keyboard::Down:
- hit_bottom = !tabs[selected_tab].body->select_next_item();
+ hit_bottom = !current_tab.body->select_next_item();
break;
case sf::Keyboard::PageDown:
- hit_bottom = !tabs[selected_tab].body->select_next_page();
+ hit_bottom = !current_tab.body->select_next_page();
break;
case sf::Keyboard::End:
- tabs[selected_tab].body->select_last_item();
+ current_tab.body->select_last_item();
hit_bottom = true;
break;
default:
hit_bottom = false;
break;
}
- if(hit_bottom && !tab_associated_data[selected_tab].search_running && !tab_associated_data[selected_tab].fetching_next_page_running && tabs[selected_tab].page) {
+ if(hit_bottom && current_tab_associated_data.fetch_status == FetchStatus::NONE && !current_tab_associated_data.fetching_next_page_running && current_tab.page) {
gradient_inc = 0.0;
- tab_associated_data[selected_tab].fetching_next_page_running = true;
- int next_page = tab_associated_data[selected_tab].fetched_page + 1;
- Page *page = tabs[selected_tab].page.get();
- std::string update_search_text = tab_associated_data[selected_tab].update_search_text;
- tab_associated_data[selected_tab].next_page_future = std::async(std::launch::async, [update_search_text, next_page, page]() {
+ current_tab_associated_data.fetching_next_page_running = true;
+ int next_page = current_tab_associated_data.fetched_page + 1;
+ Page *page = current_tab.page.get();
+ std::string update_search_text = current_tab_associated_data.update_search_text;
+ current_tab_associated_data.next_page_future = std::async(std::launch::async, [update_search_text, next_page, page]() {
BodyItems result_items;
if(page->get_page(update_search_text, next_page, result_items) != PluginResult::OK)
fprintf(stderr, "Failed to get next page (page %d)\n", next_page);
@@ -1144,33 +1161,33 @@ namespace QuickMedia {
});
}
} else if(event.key.code == sf::Keyboard::Up) {
- tabs[selected_tab].body->select_previous_item();
+ current_tab.body->select_previous_item();
} else if(event.key.code == sf::Keyboard::PageUp) {
- tabs[selected_tab].body->select_previous_page();
+ current_tab.body->select_previous_page();
} else if(event.key.code == sf::Keyboard::Home) {
- tabs[selected_tab].body->select_first_item();
+ current_tab.body->select_first_item();
} else if(event.key.code == sf::Keyboard::Escape) {
goto page_end;
} else if(event.key.code == sf::Keyboard::Left) {
if(selected_tab > 0) {
- tabs[selected_tab].body->clear_cache();
+ current_tab.body->clear_cache();
--selected_tab;
redraw = true;
}
} else if(event.key.code == sf::Keyboard::Right) {
if(selected_tab < (int)tabs.size() - 1) {
- tabs[selected_tab].body->clear_cache();
+ current_tab.body->clear_cache();
++selected_tab;
redraw = true;
}
} else if(event.key.code == sf::Keyboard::Tab) {
- if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->set_to_autocomplete();
+ if(current_tab.search_bar) current_tab.search_bar->set_to_autocomplete();
} else if(event.key.code == sf::Keyboard::Enter) {
- if(!tabs[selected_tab].search_bar) submit_handler();
+ if(!current_tab.search_bar) submit_handler();
} else if(event.key.code == sf::Keyboard::T && event.key.control) {
- BodyItem *selected_item = tabs[selected_tab].body->get_selected();
- if(selected_item && tabs[selected_tab].page && tabs[selected_tab].page->is_trackable()) {
- TrackablePage *trackable_page = static_cast<TrackablePage*>(tabs[selected_tab].page.get());
+ BodyItem *selected_item = current_tab.body->get_selected();
+ if(selected_item && current_tab.page && current_tab.page->is_trackable()) {
+ TrackablePage *trackable_page = static_cast<TrackablePage*>(current_tab.page.get());
TrackResult track_result = trackable_page->track(selected_item->get_title());
// TODO: Show proper error message when this fails. For example if we are already tracking the manga
if(track_result == TrackResult::OK) {
@@ -1185,9 +1202,9 @@ namespace QuickMedia {
if(redraw) {
redraw = false;
- if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->onWindowResize(window_size);
+ if(current_tab.search_bar) current_tab.search_bar->onWindowResize(window_size);
// TODO: Dont show tabs if there is only one tab
- get_body_dimensions(window_size, tabs[selected_tab].search_bar.get(), body_pos, body_size, true);
+ get_body_dimensions(window_size, current_tab.search_bar.get(), body_pos, body_size, true);
gradient_points[0].position.x = 0.0f;
gradient_points[0].position.y = window_size.y - gradient_height;
@@ -1202,12 +1219,24 @@ namespace QuickMedia {
gradient_points[3].position.y = window_size.y;
}
- if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->update();
+ if(current_tab.search_bar) current_tab.search_bar->update();
+
+ if(current_tab.page->is_lazy_fetch_page() && current_tab_associated_data.fetch_status == FetchStatus::NONE && !current_tab_associated_data.lazy_fetch_finished) {
+ current_tab_associated_data.fetch_status = FetchStatus::LOADING;
+ current_tab_associated_data.fetch_type = FetchType::LAZY;
+ current_tab_associated_data.search_result_text.setString("Fetching page...");
+ LazyFetchPage *lazy_fetch_page = static_cast<LazyFetchPage*>(current_tab.page.get());
+ current_tab_associated_data.fetch_future = std::async(std::launch::async, [lazy_fetch_page]() {
+ FetchResult fetch_result;
+ fetch_result.result = lazy_fetch_page->lazy_fetch(fetch_result.body_items);
+ return fetch_result;
+ });
+ }
for(size_t i = 0; i < tabs.size(); ++i) {
TabAssociatedData &associated_data = tab_associated_data[i];
- if(associated_data.fetching_next_page_running && associated_data.next_page_future.valid() && associated_data.next_page_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(associated_data.fetching_next_page_running && is_future_ready(associated_data.next_page_future)) {
BodyItems new_body_items = associated_data.next_page_future.get();
fprintf(stderr, "Finished fetching page %d, num new messages: %zu\n", associated_data.fetched_page + 1, new_body_items.size());
size_t num_new_messages = new_body_items.size();
@@ -1218,65 +1247,66 @@ namespace QuickMedia {
associated_data.fetching_next_page_running = false;
}
- if(associated_data.search_text_updated && !associated_data.search_running && !associated_data.fetching_next_page_running) {
- Page *page = tabs[i].page.get();
+ if(associated_data.search_text_updated && associated_data.fetch_status == FetchStatus::NONE && !associated_data.fetching_next_page_running) {
std::string update_search_text = associated_data.update_search_text;
- associated_data.search_future = std::async(std::launch::async, [update_search_text, page]() {
- BodyItems result_items;
- if(page->search(update_search_text, result_items) != SearchResult::OK) {
- show_notification("QuickMedia", "Search failed!", Urgency::CRITICAL);
- }
- return result_items;
- });
- update_search_text.clear();
+ associated_data.update_search_text.clear();
associated_data.search_text_updated = false;
- associated_data.search_running = true;
+ associated_data.fetch_status = FetchStatus::LOADING;
+ associated_data.fetch_type = FetchType::SEARCH;
associated_data.search_result_text.setString("Searching...");
+ Page *page = tabs[i].page.get();
+ associated_data.fetch_future = std::async(std::launch::async, [update_search_text, page]() {
+ FetchResult fetch_result;
+ fetch_result.result = search_result_to_plugin_result(page->search(update_search_text, fetch_result.body_items));
+ return fetch_result;
+ });
}
- if(associated_data.search_running && associated_data.search_future.valid() && associated_data.search_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && is_future_ready(associated_data.fetch_future)) {
if(!associated_data.search_text_updated) {
- BodyItems result_items = associated_data.search_future.get();
- tabs[i].body->items = std::move(result_items);
+ FetchResult fetch_result = associated_data.fetch_future.get();
+ tabs[i].body->items = std::move(fetch_result.body_items);
tabs[i].body->select_first_item();
associated_data.fetched_page = 0;
- if(tabs[i].body->items.empty())
+ if(fetch_result.result != PluginResult::OK)
+ associated_data.search_result_text.setString("Search failed!");
+ else if(tabs[i].body->items.empty())
associated_data.search_result_text.setString("No results found");
else
associated_data.search_result_text.setString("");
} else {
- associated_data.search_future.get();
+ associated_data.fetch_future.get();
}
- associated_data.search_running = false;
+ associated_data.fetch_status = FetchStatus::NONE;
}
- }
-
- // if(!autocomplete_text.empty() && !autocomplete_running) {
- // autocomplete_future = std::async(std::launch::async, [this, autocomplete_text]() {
- // return current_plugin->autocomplete_search(autocomplete_text);
- // });
- // autocomplete_text.clear();
- // autocomplete_running = true;
- // }
- // if(autocomplete_running && autocomplete_future.valid() && autocomplete_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
- // if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->set_autocomplete_text(autocomplete_future.get());
- // autocomplete_running = false;
- // }
+ if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::LAZY && is_future_ready(associated_data.fetch_future)) {
+ associated_data.lazy_fetch_finished = true;
+ FetchResult fetch_result = associated_data.fetch_future.get();
+ tabs[i].body->items = std::move(fetch_result.body_items);
+ if(fetch_result.result != PluginResult::OK)
+ associated_data.search_result_text.setString("Failed to fetch page!");
+ else if(tabs[i].body->items.empty())
+ associated_data.search_result_text.setString("No results found");
+ else
+ associated_data.search_result_text.setString("");
+ associated_data.fetch_status = FetchStatus::NONE;
+ }
+ }
window.clear(back_color);
- if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->draw(window, false);
+ if(current_tab.search_bar) current_tab.search_bar->draw(window, false);
{
float shade_extra_height = 0.0f;
- if(!tabs[selected_tab].search_bar)
+ if(!current_tab.search_bar)
shade_extra_height = 10.0f;
const float width_per_tab = window_size.x / tabs.size();
tab_background.setSize(sf::Vector2f(std::floor(width_per_tab - tab_margin_x * 2.0f), tab_height));
- float tab_vertical_offset = tabs[selected_tab].search_bar ? tabs[selected_tab].search_bar->getBottomWithoutShadow() : 0.0f;
- tabs[selected_tab].body->draw(window, body_pos, body_size, *json_chapters);
+ float tab_vertical_offset = current_tab.search_bar ? current_tab.search_bar->getBottomWithoutShadow() : 0.0f;
+ current_tab.body->draw(window, body_pos, body_size, *json_chapters);
const float tab_y = tab_spacer_height + std::floor(tab_vertical_offset + tab_height * 0.5f - (tab_text_size + 5.0f) * 0.5f) + shade_extra_height;
tab_shade.setPosition(0.0f, tab_spacer_height + std::floor(tab_vertical_offset));
@@ -1299,7 +1329,7 @@ namespace QuickMedia {
}
}
- if(tab_associated_data[selected_tab].fetching_next_page_running) {
+ if(current_tab_associated_data.fetching_next_page_running) {
double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5;
gradient_inc += (frame_time_ms * 0.5);
sf::Color bottom_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress);
@@ -1311,12 +1341,12 @@ namespace QuickMedia {
window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl
}
- if(!tab_associated_data[selected_tab].search_result_text.getString().isEmpty()) {
- auto search_result_text_bounds = tab_associated_data[selected_tab].search_result_text.getLocalBounds();
- tab_associated_data[selected_tab].search_result_text.setPosition(
+ if(!current_tab_associated_data.search_result_text.getString().isEmpty()) {
+ auto search_result_text_bounds = current_tab_associated_data.search_result_text.getLocalBounds();
+ current_tab_associated_data.search_result_text.setPosition(
std::floor(body_pos.x + body_size.x * 0.5f - search_result_text_bounds.width * 0.5f),
std::floor(body_pos.y + body_size.y * 0.5f - search_result_text_bounds.height * 0.5f));
- window.draw(tab_associated_data[selected_tab].search_result_text);
+ window.draw(current_tab_associated_data.search_result_text);
}
window.display();
@@ -1328,8 +1358,8 @@ namespace QuickMedia {
for(TabAssociatedData &associated_data : tab_associated_data) {
if(associated_data.next_page_future.valid())
associated_data.next_page_future.get();
- if(associated_data.search_future.valid())
- associated_data.search_future.get();
+ if(associated_data.fetch_future.valid())
+ associated_data.fetch_future.get();
}
}
@@ -1491,7 +1521,6 @@ namespace QuickMedia {
const float related_videos_text_height = related_videos_text.getCharacterSize();
auto related_media_body = create_body();
- related_media_body->draw_thumbnails = true;
sf::WindowHandle video_player_window = None;
auto on_window_create = [this, &video_player_window](sf::WindowHandle _video_player_window) mutable {
@@ -2440,12 +2469,14 @@ namespace QuickMedia {
comment_input_shade.setFillColor(sf::Color(33, 38, 44));
sf::Sprite logo_sprite(plugin_logo);
+ logo_sprite.setScale(0.8f, 0.8f);
+ sf::Vector2f logo_size(plugin_logo.getSize().x * logo_sprite.getScale().x, plugin_logo.getSize().y * logo_sprite.getScale().y);
float prev_chat_height = comment_input.get_height();
float chat_input_height_full = 0.0f;
const float logo_padding_x = 15.0f;
- const float chat_input_padding_x = 15.0f;
- const float chat_input_padding_y = 15.0f;
+ const float chat_input_padding_x = 10.0f;
+ const float chat_input_padding_y = 10.0f;
sf::Vector2f body_pos;
sf::Vector2f body_size;
@@ -2641,8 +2672,8 @@ namespace QuickMedia {
redraw = false;
comment_input.set_max_width(window_size.x);
- comment_input.set_max_width(window_size.x - (logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x * 2.0f));
- comment_input.set_position(sf::Vector2f(logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x, chat_input_padding_y));
+ comment_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x));
+ comment_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), chat_input_padding_y));
float body_padding_horizontal = 25.0f;
float body_padding_vertical = 5.0f;
@@ -2658,7 +2689,7 @@ namespace QuickMedia {
body_pos = sf::Vector2f(body_padding_horizontal, comment_input_shade.getSize().y + body_padding_vertical);
body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y - body_padding_vertical);
- logo_sprite.setPosition(logo_padding_x, comment_input_shade.getSize().y * 0.5f - plugin_logo.getSize().y * 0.5f);
+ logo_sprite.setPosition(logo_padding_x, std::floor(comment_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f));
}
//comment_input.update();
@@ -2702,7 +2733,7 @@ namespace QuickMedia {
} else if(navigation_stage == NavigationStage::VIEWING_ATTACHED_IMAGE) {
// TODO: Use image instead of data with string. texture->loadFromMemory creates a temporary image anyways that parses the string.
std::string image_data;
- if(downloading_image && load_image_future.valid() && load_image_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(downloading_image && is_future_ready(load_image_future)) {
downloading_image = false;
image_data = load_image_future.get();
@@ -2932,16 +2963,9 @@ namespace QuickMedia {
return result_items;
}
- enum class PinnedEventStatus {
- NONE,
- LOADING,
- FINISHED_LOADING,
- FAILED_TO_LOAD
- };
-
struct PinnedEventData {
std::string event_id;
- PinnedEventStatus status = PinnedEventStatus::NONE;
+ FetchStatus status = FetchStatus::NONE;
};
void Program::chat_page() {
@@ -2953,7 +2977,6 @@ namespace QuickMedia {
ChatTab pinned_tab;
pinned_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
- pinned_tab.body->draw_thumbnails = true;
pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE;
pinned_tab.body->thumbnail_mask_shader = &circle_mask_shader;
//pinned_tab.body->line_separator_color = sf::Color::Transparent;
@@ -2962,7 +2985,6 @@ namespace QuickMedia {
ChatTab messages_tab;
messages_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
- messages_tab.body->draw_thumbnails = true;
messages_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE;
messages_tab.body->thumbnail_mask_shader = &circle_mask_shader;
//messages_tab.body->line_separator_color = sf::Color::Transparent;
@@ -2971,7 +2993,6 @@ namespace QuickMedia {
ChatTab rooms_tab;
rooms_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
- rooms_tab.body->draw_thumbnails = true;
//rooms_tab.body->line_separator_color = sf::Color::Transparent;
rooms_tab.body->thumbnail_mask_shader = &circle_mask_shader;
rooms_tab.text = sf::Text("Rooms", *font, tab_text_size);
@@ -3106,6 +3127,8 @@ namespace QuickMedia {
sf::Text replying_to_text("Replying to:", *font, 18);
sf::Sprite logo_sprite(plugin_logo);
+ logo_sprite.setScale(0.8f, 0.8f);
+ sf::Vector2f logo_size(plugin_logo.getSize().x * logo_sprite.getScale().x, plugin_logo.getSize().y * logo_sprite.getScale().y);
sf::Text room_name_text("", *bold_font, 18);
const float room_name_text_height = 20.0f;
@@ -3141,7 +3164,7 @@ namespace QuickMedia {
auto set_body_as_deleted = [](Message *message, BodyItem *body_item) {
body_item->embedded_item = nullptr;
- body_item->embedded_item_status = EmbeddedItemStatus::NONE;
+ body_item->embedded_item_status = FetchStatus::NONE;
body_item->thumbnail_url = message->user->avatar_url;
body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
body_item->set_description_color(sf::Color::White);
@@ -3196,7 +3219,7 @@ namespace QuickMedia {
body->set_description("Loading message...");
PinnedEventData *event_data = new PinnedEventData();
event_data->event_id = event;
- event_data->status = PinnedEventStatus::NONE;
+ event_data->status = FetchStatus::NONE;
body->userdata = event_data;
tabs[PINNED_TAB_INDEX].body->items.push_back(std::move(body));
}
@@ -3346,14 +3369,14 @@ namespace QuickMedia {
return;
PinnedEventData *event_data = static_cast<PinnedEventData*>(body_item->userdata);
- if(!event_data || event_data->status != PinnedEventStatus::NONE)
+ if(!event_data || event_data->status != FetchStatus::NONE)
return;
// Check if we already have the referenced message as a body item in the messages list, so we dont create a new one
auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), event_data->event_id);
if(related_body_item) {
*body_item = *related_body_item;
- event_data->status = PinnedEventStatus::FINISHED_LOADING;
+ event_data->status = FetchStatus::FINISHED_LOADING;
body_item->userdata = event_data;
return;
}
@@ -3362,7 +3385,7 @@ namespace QuickMedia {
std::string message_event_id = event_data->event_id;
fetch_future_room = current_room;
fetch_body_item = body_item;
- body_item->embedded_item_status = EmbeddedItemStatus::LOADING;
+ body_item->embedded_item_status = FetchStatus::LOADING;
fetch_message_tab = PINNED_TAB_INDEX;
// TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive?
fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() {
@@ -3378,14 +3401,14 @@ namespace QuickMedia {
Message *message = static_cast<Message*>(body_item->userdata);
assert(message);
- if(message->related_event_id.empty() || body_item->embedded_item_status != EmbeddedItemStatus::NONE)
+ if(message->related_event_id.empty() || body_item->embedded_item_status != FetchStatus::NONE)
return;
// Check if we already have the referenced message as a body item, so we dont create a new one
auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id);
if(related_body_item) {
body_item->embedded_item = related_body_item;
- body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING;
+ body_item->embedded_item_status = FetchStatus::FINISHED_LOADING;
return;
}
@@ -3393,7 +3416,7 @@ namespace QuickMedia {
std::string message_event_id = message->related_event_id;
fetch_future_room = current_room;
fetch_body_item = body_item;
- body_item->embedded_item_status = EmbeddedItemStatus::LOADING;
+ body_item->embedded_item_status = FetchStatus::LOADING;
fetch_message_tab = MESSAGES_TAB_INDEX;
// TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive?
fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() {
@@ -3442,8 +3465,8 @@ namespace QuickMedia {
float prev_chat_height = chat_input.get_height();
float chat_input_height_full = 0.0f;
const float logo_padding_x = 15.0f;
- const float chat_input_padding_x = 15.0f;
- const float chat_input_padding_y = 15.0f;
+ const float chat_input_padding_x = 10.0f;
+ const float chat_input_padding_y = 10.0f;
Body url_selection_body(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
@@ -3902,8 +3925,8 @@ namespace QuickMedia {
tab_shade_height = tab_spacer_height + std::floor(tab_vertical_offset) + tab_height + room_name_padding_y + padding_bottom;
- chat_input.set_max_width(window_size.x - (logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x * 2.0f));
- chat_input.set_position(sf::Vector2f(logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x, window_size.y - chat_height - chat_input_padding_y));
+ chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x));
+ chat_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y));
float body_padding_horizontal = 25.0f;
float body_padding_vertical = 5.0f;
@@ -3922,7 +3945,7 @@ namespace QuickMedia {
more_messages_below_rect.setSize(sf::Vector2f(window_size.x, gradient_height));
more_messages_below_rect.setPosition(0.0f, std::floor(window_size.y - chat_input_shade.getSize().y - gradient_height));
- logo_sprite.setPosition(logo_padding_x, window_size.y - chat_input_shade.getSize().y * 0.5f - plugin_logo.getSize().y * 0.5f);
+ logo_sprite.setPosition(logo_padding_x, std::floor(window_size.y - chat_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f));
}
room_search_bar.update();
@@ -3945,7 +3968,7 @@ namespace QuickMedia {
});
}
- if(sync_future.valid() && sync_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(is_future_ready(sync_future)) {
SyncFutureResult sync_result = sync_future.get();
add_new_rooms(sync_result.rooms);
@@ -3962,13 +3985,13 @@ namespace QuickMedia {
synced = true;
}
- if(set_read_marker_future.valid() && set_read_marker_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(is_future_ready(set_read_marker_future)) {
set_read_marker_future.get();
read_marker_timer.restart();
setting_read_marker = false;
}
- if(fetching_previous_messages_running && previous_messages_future.valid() && previous_messages_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(fetching_previous_messages_running && is_future_ready(previous_messages_future)) {
Messages new_messages = previous_messages_future.get();
fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_messages.size());
// Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again
@@ -3989,7 +4012,7 @@ namespace QuickMedia {
fetching_previous_messages_running = false;
}
- if(fetching_message_running && fetch_message_future.valid() && fetch_message_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ if(fetching_message_running && is_future_ready(fetch_message_future)) {
std::shared_ptr<Message> message = fetch_message_future.get();
fprintf(stderr, "Finished fetching message: %s\n", message ? message->event_id.c_str() : "(null)");
// Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again
@@ -3998,18 +4021,18 @@ namespace QuickMedia {
PinnedEventData *event_data = static_cast<PinnedEventData*>(fetch_body_item->userdata);
if(message) {
*fetch_body_item = *message_to_body_item(message.get(), matrix->get_me(current_room).get());
- event_data->status = PinnedEventStatus::FINISHED_LOADING;
+ event_data->status = FetchStatus::FINISHED_LOADING;
fetch_body_item->userdata = event_data;
} else {
fetch_body_item->set_description("Failed to load message!");
- event_data->status = PinnedEventStatus::FAILED_TO_LOAD;
+ event_data->status = FetchStatus::FAILED_TO_LOAD;
}
} else if(fetch_message_tab == MESSAGES_TAB_INDEX) {
if(message) {
fetch_body_item->embedded_item = message_to_body_item(message.get(), matrix->get_me(current_room).get());
- fetch_body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING;
+ fetch_body_item->embedded_item_status = FetchStatus::FINISHED_LOADING;
} else {
- fetch_body_item->embedded_item_status = EmbeddedItemStatus::FAILED_TO_LOAD;
+ fetch_body_item->embedded_item_status = FetchStatus::FAILED_TO_LOAD;
}
}
}
diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp
index 382b06a..6895dcb 100644
--- a/src/SearchBar.cpp
+++ b/src/SearchBar.cpp
@@ -8,10 +8,13 @@
// TODO: Use a seperate placeholder sf::Text instead of switching the text to placeholder text....
-const sf::Color text_placeholder_color(255, 255, 255, 100);
-const sf::Color front_color(55, 60, 68);
-const float background_margin_horizontal = 15.0f;
-const float PADDING_HORIZONTAL = 25.0f;
+static const sf::Color text_placeholder_color(255, 255, 255, 100);
+static const sf::Color front_color(55, 60, 68);
+static const float background_margin_horizontal = 15.0f;
+static const float PADDING_HORIZONTAL = 25.0f;
+static const float padding_top = 10.0f;
+static const float padding_bottom = 15.0f;
+static const float background_margin_vertical = 4.0f;
namespace QuickMedia {
SearchBar::SearchBar(sf::Font &font, sf::Texture *plugin_logo, const std::string &placeholder, bool input_masked) :
@@ -22,8 +25,8 @@ namespace QuickMedia {
text_autosearch_delay(0),
autocomplete_search_delay(0),
caret_visible(true),
- text(placeholder, font, 18),
- autocomplete_text("", font, 18),
+ text(placeholder, font, 16),
+ autocomplete_text("", font, 16),
background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10),
placeholder_str(placeholder),
show_placeholder(true),
@@ -127,20 +130,20 @@ namespace QuickMedia {
sf::Vector2f texture_size_f(texture_size.x, texture_size.y);
sf::Vector2f new_size = wrap_to_size(texture_size_f, sf::Vector2f(200.0f, one_line_height));
plugin_logo_sprite.setScale(get_ratio(texture_size_f, new_size));
- plugin_logo_sprite.setPosition(25.0f, padding_vertical + vertical_pos);
+ plugin_logo_sprite.setPosition(25.0f, padding_top + vertical_pos);
offset_x = 25.0f + new_size.x + 25.0f;
}
const float width = std::floor(window_size.x - offset_x - padding_horizontal);
background.setSize(sf::Vector2f(width, rect_height));
- shade.setSize(sf::Vector2f(window_size.x, padding_vertical + rect_height + padding_vertical));
+ shade.setSize(sf::Vector2f(window_size.x, padding_top + rect_height + padding_bottom));
caret.setSize(sf::Vector2f(2.0f, text.getCharacterSize() + 2.0f));
background_shadow.setSize(sf::Vector2f(window_size.x, 5.0f));
- background.setPosition(offset_x, padding_vertical + vertical_pos);
+ background.setPosition(offset_x, padding_top + vertical_pos);
shade.setPosition(0.0f, vertical_pos);
background_shadow.setPosition(0.0f, std::floor(shade.getSize().y + vertical_pos));
- sf::Vector2f font_position(std::floor(offset_x + background_margin_horizontal), std::floor(padding_vertical + background_margin_vertical + vertical_pos));
+ sf::Vector2f font_position(std::floor(offset_x + background_margin_horizontal), std::floor(padding_top + background_margin_vertical + vertical_pos));
autocomplete_text.setPosition(font_position);
text.setPosition(font_position);
}
@@ -302,7 +305,7 @@ namespace QuickMedia {
float SearchBar::getBottomWithoutShadow() const {
float font_height = text.getCharacterSize() + 7.0f;
- return std::floor(font_height + background_margin_vertical * 2.0f) + padding_vertical + padding_vertical;
+ return std::floor(font_height + background_margin_vertical * 2.0f) + padding_top + padding_bottom;
}
std::string SearchBar::get_text() const {
diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp
index 5fac79c..f65486e 100644
--- a/src/plugins/FileManager.cpp
+++ b/src/plugins/FileManager.cpp
@@ -48,7 +48,6 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(result_items);
- body->draw_thumbnails = true;
result_tabs.push_back(Tab{std::move(body), nullptr, nullptr});
return PluginResult::OK;
}
diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp
index 7f8008c..d042a2a 100644
--- a/src/plugins/Fourchan.cpp
+++ b/src/plugins/Fourchan.cpp
@@ -267,7 +267,6 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(result_items);
- body->draw_thumbnails = true;
result_tabs.push_back(Tab{std::move(body), std::make_unique<FourchanThreadListPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
return PluginResult::OK;
}
@@ -459,7 +458,6 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(result_items);
- body->draw_thumbnails = true;
result_tabs.push_back(Tab{std::move(body), std::make_unique<FourchanThreadPage>(program, board_id, url, std::move(cached_media_urls)), nullptr});
return PluginResult::OK;
}
diff --git a/src/plugins/Manga.cpp b/src/plugins/Manga.cpp
index 70a1664..323794c 100644
--- a/src/plugins/Manga.cpp
+++ b/src/plugins/Manga.cpp
@@ -9,4 +9,10 @@ namespace QuickMedia {
else
return TrackResult::ERR;
}
+
+ void MangaChaptersPage::on_navigate_to_page() {
+ std::string manga_id;
+ if(extract_id_from_url(content_url, manga_id))
+ load_manga_content_storage(get_service_name(), content_title, manga_id);
+ }
} \ No newline at end of file
diff --git a/src/plugins/Mangadex.cpp b/src/plugins/Mangadex.cpp
index 3574914..e798b60 100644
--- a/src/plugins/Mangadex.cpp
+++ b/src/plugins/Mangadex.cpp
@@ -112,8 +112,7 @@ namespace QuickMedia {
}
PluginResult MangadexSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
- std::string manga_id = title_url_extract_manga_id(url);
- std::string request_url = "https://mangadex.org/api/?id=" + manga_id + "&type=manga";
+ std::string request_url = "https://mangadex.org/api/?id=" + title_url_extract_manga_id(url) + "&type=manga";
rapidjson::Document json_root;
DownloadResult result = download_to_json(request_url, json_root, {}, is_tor_enabled(), true);
@@ -169,10 +168,7 @@ namespace QuickMedia {
}
result_tabs.push_back(Tab{std::move(body), std::make_unique<MangadexChaptersPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
-
- if(load_manga_content_storage("mangadex", title, manga_id))
- return PluginResult::OK;
- return PluginResult::ERR;
+ return PluginResult::OK;
}
bool MangadexSearchPage::get_rememberme_token(std::string &rememberme_token_output) {
@@ -212,6 +208,11 @@ namespace QuickMedia {
return PluginResult::OK;
}
+ bool MangadexChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const {
+ manga_id = title_url_extract_manga_id(url);
+ return true;
+ }
+
ImageResult MangadexImagesPage::get_number_of_images(int &num_images) {
num_images = 0;
ImageResult image_result = get_image_urls_for_chapter(url);
diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp
index b260dea..7f0a2f9 100644
--- a/src/plugins/Manganelo.cpp
+++ b/src/plugins/Manganelo.cpp
@@ -25,49 +25,12 @@ namespace QuickMedia {
return true;
}
- SearchResult ManganeloSearchPage::search(const std::string &str, BodyItems &result_items) {
- std::string url = "https://manganelo.com/getstorysearchjson";
- std::string search_term = "searchword=";
- search_term += url_param_encode(str);
- CommandArg data_arg = { "--data", std::move(search_term) };
-
- Json::Value json_root;
- DownloadResult result = download_json(json_root, url, {data_arg}, true);
- if(result != DownloadResult::OK) return download_result_to_search_result(result);
-
- if(json_root.isNull())
- return SearchResult::OK;
-
- if(!json_root.isArray())
- return SearchResult::ERR;
-
- for(const Json::Value &child : json_root) {
- if(!child.isObject())
- continue;
-
- Json::Value name = child.get("name", "");
- Json::Value nameunsigned = child.get("nameunsigned", "");
- if(name.isString() && name.asCString()[0] != '\0' && nameunsigned.isString() && nameunsigned.asCString()[0] != '\0') {
- std::string name_str = name.asString();
- while(remove_html_span(name_str)) {}
- auto item = BodyItem::create(strip(name_str));
- item->url = "https://manganelo.com/manga/" + url_param_encode(nameunsigned.asString());
- Json::Value image = child.get("image", "");
- if(image.isString() && image.asCString()[0] != '\0')
- item->thumbnail_url = image.asString();
- result_items.push_back(std::move(item));
- }
- }
-
- return SearchResult::OK;
- }
-
- PluginResult ManganeloSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ static PluginResult submit_manga(Page *page, const std::string &title, const std::string &url, std::vector<Tab> &result_tabs, bool use_tor) {
BodyItems chapters_items;
std::vector<Creator> creators;
std::string website_data;
- if(download_to_string(url, website_data, {}, is_tor_enabled(), true) != DownloadResult::OK)
+ if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK)
return PluginResult::NET_ERR;
QuickMediaHtmlSearch html_search;
@@ -105,23 +68,64 @@ namespace QuickMedia {
if(result != 0)
return PluginResult::ERR;
- auto chapters_body = create_body();
+ auto chapters_body = page->create_body();
chapters_body->items = std::move(chapters_items);
- result_tabs.push_back(Tab{std::move(chapters_body), std::make_unique<ManganeloChaptersPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ result_tabs.push_back(Tab{std::move(chapters_body), std::make_unique<ManganeloChaptersPage>(page->program, title, url), page->create_search_bar("Search...", SEARCH_DELAY_FILTER)});
for(Creator &creator : creators) {
- result_tabs.push_back(Tab{create_body(), std::make_unique<ManganeloCreatorPage>(program, std::move(creator)), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ result_tabs.push_back(Tab{page->create_body(), std::make_unique<ManganeloCreatorPage>(page->program, std::move(creator)), page->create_search_bar("Search...", SEARCH_DELAY_FILTER)});
}
- std::string manga_id;
- if(extract_id_from_url(url, manga_id)) {
- if(load_manga_content_storage("manganelo", title, manga_id))
- return PluginResult::OK;
+ return PluginResult::OK;
+ }
+
+ SearchResult ManganeloSearchPage::search(const std::string &str, BodyItems &result_items) {
+ std::string url = "https://manganelo.com/getstorysearchjson";
+ std::string search_term = "searchword=";
+ search_term += url_param_encode(str);
+ CommandArg data_arg = { "--data", std::move(search_term) };
+
+ Json::Value json_root;
+ DownloadResult result = download_json(json_root, url, {data_arg}, true);
+ if(result != DownloadResult::OK) return download_result_to_search_result(result);
+
+ if(json_root.isNull())
+ return SearchResult::OK;
+
+ if(!json_root.isArray())
+ return SearchResult::ERR;
+
+ for(const Json::Value &child : json_root) {
+ if(!child.isObject())
+ continue;
+
+ Json::Value name = child.get("name", "");
+ Json::Value nameunsigned = child.get("nameunsigned", "");
+ if(name.isString() && name.asCString()[0] != '\0' && nameunsigned.isString() && nameunsigned.asCString()[0] != '\0') {
+ std::string name_str = name.asString();
+ while(remove_html_span(name_str)) {}
+ auto item = BodyItem::create(strip(name_str));
+ item->url = "https://manganelo.com/manga/" + url_param_encode(nameunsigned.asString());
+ Json::Value image = child.get("image", "");
+ if(image.isString() && image.asCString()[0] != '\0')
+ item->thumbnail_url = image.asString();
+ result_items.push_back(std::move(item));
+ }
}
- return PluginResult::ERR;
+
+ return SearchResult::OK;
+ }
+
+ PluginResult ManganeloSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ return submit_manga(this, title, url, result_tabs, is_tor_enabled());
+ }
+
+ PluginResult ManganeloChaptersPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ result_tabs.push_back(Tab{create_body(), std::make_unique<ManganeloImagesPage>(program, content_title, title, url), nullptr});
+ return PluginResult::OK;
}
-
- bool ManganeloSearchPage::extract_id_from_url(const std::string &url, std::string &manga_id) const {
+
+ bool ManganeloChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const {
bool manganelo_website = false;
if(url.find("mangakakalot") != std::string::npos || url.find("manganelo") != std::string::npos)
manganelo_website = true;
@@ -154,17 +158,56 @@ namespace QuickMedia {
}
}
- PluginResult ManganeloChaptersPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
- result_tabs.push_back(Tab{create_body(), std::make_unique<ManganeloImagesPage>(program, content_title, title, url), nullptr});
- return PluginResult::OK;
+ PluginResult ManganeloCreatorPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ return submit_manga(this, title, url, result_tabs, is_tor_enabled());
}
- PluginResult ManganeloCreatorPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
- (void)title;
- (void)url;
- (void)result_tabs;
- // TODO: Implement
- return PluginResult::ERR;
+ PluginResult ManganeloCreatorPage::lazy_fetch(BodyItems &result_items) {
+ std::string website_data;
+ if(download_to_string(creator.url, website_data, {}, is_tor_enabled(), true) != DownloadResult::OK)
+ return PluginResult::NET_ERR;
+
+ QuickMediaHtmlSearch html_search;
+ int result = quickmedia_html_search_init(&html_search, website_data.c_str());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ auto *item_data = (BodyItems*)userdata;
+ const char *href = quickmedia_html_node_get_attribute_value(node, "href");
+ const char *title = quickmedia_html_node_get_attribute_value(node, "title");
+ if(href && title && strstr(href, "/manga/")) {
+ auto body_item = BodyItem::create(title);
+ body_item->url = href;
+ item_data->push_back(std::move(body_item));
+ }
+ }, &result_items);
+
+ if(result != 0)
+ goto cleanup;
+
+ BodyItemImageContext body_item_image_context;
+ body_item_image_context.body_items = &result_items;
+ body_item_image_context.index = 0;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']//img",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ auto *item_data = (BodyItemImageContext*)userdata;
+ const char *src = quickmedia_html_node_get_attribute_value(node, "src");
+ if(src && item_data->index < item_data->body_items->size()) {
+ (*item_data->body_items)[item_data->index]->thumbnail_url = src;
+ item_data->index++;
+ }
+ }, &body_item_image_context);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ if(result != 0) {
+ result_items.clear();
+ return PluginResult::ERR;
+ }
+ return PluginResult::OK;
}
ImageResult ManganeloImagesPage::get_number_of_images(int &num_images) {
diff --git a/src/plugins/Mangatown.cpp b/src/plugins/Mangatown.cpp
index d9013f7..89bf447 100644
--- a/src/plugins/Mangatown.cpp
+++ b/src/plugins/Mangatown.cpp
@@ -106,16 +106,15 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(chapters_items);
result_tabs.push_back(Tab{std::move(body), std::make_unique<MangatownChaptersPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ return PluginResult::OK;
+ }
- std::string manga_id;
- if(extract_id_from_url(url, manga_id)) {
- if(load_manga_content_storage("mangatown", title, manga_id))
- return PluginResult::OK;
- }
- return PluginResult::ERR;
+ PluginResult MangatownChaptersPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ result_tabs.push_back(Tab{create_body(), std::make_unique<MangatownImagesPage>(program, content_title, title, url), nullptr});
+ return PluginResult::OK;
}
-
- bool MangatownSearchPage::extract_id_from_url(const std::string &url, std::string &manga_id) const {
+
+ bool MangatownChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const {
size_t start_index = url.find("/manga/");
if(start_index == std::string::npos)
return false;
@@ -131,11 +130,6 @@ namespace QuickMedia {
return true;
}
- PluginResult MangatownChaptersPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
- result_tabs.push_back(Tab{create_body(), std::make_unique<MangatownImagesPage>(program, content_title, title, url), nullptr});
- return PluginResult::OK;
- }
-
ImageResult MangatownImagesPage::get_number_of_images(int &num_images) {
num_images = 0;
ImageResult image_result = get_image_urls_for_chapter(url);
diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp
index fa4e94f..b6a6488 100644
--- a/src/plugins/NyaaSi.cpp
+++ b/src/plugins/NyaaSi.cpp
@@ -184,7 +184,6 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(result_items);
- body->draw_thumbnails = true;
result_tabs.push_back(Tab{std::move(body), std::make_unique<NyaaSiSearchPage>(program, strip(title), url), create_search_bar("Search...", 200)});
return PluginResult::OK;
}
@@ -372,7 +371,6 @@ namespace QuickMedia {
auto body = create_body();
body->items = std::move(result_items);
- body->draw_thumbnails = true;
result_tabs.push_back(Tab{std::move(body), std::make_unique<NyaaSiTorrentPage>(program), nullptr});
return PluginResult::OK;
}