aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AsyncImageLoader.cpp140
-rw-r--r--src/Body.cpp2
-rw-r--r--src/DownloadUtils.cpp25
-rw-r--r--src/QuickMedia.cpp20
4 files changed, 134 insertions, 53 deletions
diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp
index 00ca7ee..2f0f869 100644
--- a/src/AsyncImageLoader.cpp
+++ b/src/AsyncImageLoader.cpp
@@ -1,9 +1,8 @@
#include "../include/AsyncImageLoader.hpp"
-#include "../include/base64_url.hpp"
-#include "../include/Storage.hpp"
#include "../include/DownloadUtils.hpp"
#include "../include/ImageUtils.hpp"
#include "../include/Scale.hpp"
+#include "../external/hash-library/sha256.h"
#include <assert.h>
namespace QuickMedia {
@@ -90,70 +89,141 @@ namespace QuickMedia {
return "";
}
- // TODO: Run in 5 different threads, and add download_to_file(_cache) to reduce memory usage in each (use -O curl option)
- bool AsyncImageLoader::load_thumbnail(const std::string &url, bool local, sf::Vector2i resize_target_size, bool use_tor, std::shared_ptr<ThumbnailData> thumbnail_data) {
- if(loading_image)
- return false;
+ static void create_thumbnail_if_thumbnail_smaller_than_image(const std::string &original_url, const Path &thumbnail_path, ThumbnailData *thumbnail_data, sf::Vector2i resize_target_size) {
+ sf::Vector2u new_image_size = to_vec2u(
+ clamp_to_size(
+ to_vec2f(thumbnail_data->image->getSize()), to_vec2f(resize_target_size)));
+ if(new_image_size.x < thumbnail_data->image->getSize().x || new_image_size.y < thumbnail_data->image->getSize().y) {
+ auto destination_image = std::make_unique<sf::Image>();
+ copy_resize(*thumbnail_data->image, *destination_image, new_image_size);
+ thumbnail_data->image = std::move(destination_image);
+ save_image_as_thumbnail_atomic(*thumbnail_data->image, thumbnail_path, get_ext(original_url));
+ thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
+ }
+ }
- loading_image = true;
+ AsyncImageLoader::AsyncImageLoader() {
+ for(size_t i = 0; i < NUM_IMAGE_LOAD_THREADS; ++i) {
+ loading_image[i] = false;
+ }
- assert(thumbnail_data->loading_state == LoadingState::NOT_LOADED);
- thumbnail_data->loading_state = LoadingState::LOADING;
+ load_image_thread = std::thread([this]{
+ ThumbnailLoadData thumbnail_load_data;
+ while(true) {
+ {
+ std::unique_lock<std::mutex> lock(load_image_mutex);
+ while(images_to_load.empty() && running) load_image_cv.wait(lock);
+ if(!running)
+ break;
+ thumbnail_load_data = images_to_load.front();
+ images_to_load.pop_front();
+ }
+
+ thumbnail_load_data.thumbnail_data->image = std::make_unique<sf::Image>();
+ if(thumbnail_load_data.thumbnail_data->image->loadFromFile(thumbnail_load_data.thumbnail_path.data)) {
+ fprintf(stderr, "Loaded %s from thumbnail cache\n", thumbnail_load_data.path.data.c_str());
+ thumbnail_load_data.thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
+ continue;
+ }
+
+ if(thumbnail_load_data.local) {
+ if(thumbnail_load_data.thumbnail_data->image->loadFromFile(thumbnail_load_data.path.data)
+ && thumbnail_load_data.resize_target_size.x != 0 && thumbnail_load_data.resize_target_size.y != 0)
+ {
+ create_thumbnail_if_thumbnail_smaller_than_image(thumbnail_load_data.path.data, thumbnail_load_data.thumbnail_path, thumbnail_load_data.thumbnail_data.get(), thumbnail_load_data.resize_target_size);
+ }
+ thumbnail_load_data.thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
+ } else {
+ thumbnail_load_data.thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
+ }
+ }
+ });
+ }
+
+ AsyncImageLoader::~AsyncImageLoader() {
+ running = false;
+ {
+ std::unique_lock<std::mutex> lock(load_image_mutex);
+ load_image_cv.notify_one();
+ }
+ load_image_thread.join();
+ }
+
+ void AsyncImageLoader::load_thumbnail(const std::string &url, bool local, sf::Vector2i resize_target_size, bool use_tor, std::shared_ptr<ThumbnailData> thumbnail_data) {
+ if(thumbnail_data->loading_state != LoadingState::NOT_LOADED)
+ return;
if(url.empty()) {
thumbnail_data->image = std::make_unique<sf::Image>();
thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
- return true;
+ return;
+ }
+
+ SHA256 sha256;
+ sha256.add(url.data(), url.size());
+ Path thumbnail_path = get_cache_dir().join("thumbnails").join(sha256.getHash());
+ if(get_file_type(thumbnail_path) == FileType::REGULAR) {
+ thumbnail_data->loading_state = LoadingState::LOADING;
+ std::unique_lock<std::mutex> lock(load_image_mutex);
+ images_to_load.push_back({ url, thumbnail_path, local, thumbnail_data, resize_target_size });
+ load_image_cv.notify_one();
+ return;
+ } else if(local && get_file_type(url) == FileType::REGULAR) {
+ thumbnail_data->loading_state = LoadingState::LOADING;
+ std::unique_lock<std::mutex> lock(load_image_mutex);
+ images_to_load.push_back({ url, thumbnail_path, true, thumbnail_data, resize_target_size });
+ load_image_cv.notify_one();
+ return;
}
- // TODO: Keep the thread running and use conditional variable instead to sleep until a new image should be loaded. Same in ImageViewer.
- load_image_thread = std::thread([this, url, local, resize_target_size, thumbnail_data, use_tor]() mutable {
- // TODO: Use sha256 instead of base64_url encoding
- Path thumbnail_path = get_cache_dir().join("thumbnails").join(base64_url::encode(url));
+ int free_index = get_free_load_index();
+ if(free_index == -1)
+ return;
+
+ loading_image[free_index] = true;
+ thumbnail_data->loading_state = LoadingState::LOADING;
+ // TODO: Keep the thread running and use conditional variable instead to sleep until a new image should be loaded. Same in ImageViewer.
+ download_image_thread[free_index] = std::thread([this, free_index, thumbnail_path, url, local, resize_target_size, thumbnail_data, use_tor]() mutable {
thumbnail_data->image = std::make_unique<sf::Image>();
if(thumbnail_data->image->loadFromFile(thumbnail_path.data)) {
fprintf(stderr, "Loaded %s from thumbnail cache\n", url.c_str());
thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
+ loading_image[free_index] = false;
return;
} else {
if(local) {
if(!thumbnail_data->image->loadFromFile(url)) {
thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
+ loading_image[free_index] = false;
return;
}
} else {
- std::string texture_data;
- if(download_to_string_cache(url, texture_data, {}, use_tor, true) != DownloadResult::OK || !thumbnail_data->image->loadFromMemory(texture_data.data(), texture_data.size())) {
+ Path download_path = thumbnail_path;
+ download_path.append(".orig");
+ if(download_to_file(url, download_path.data, {}, use_tor, true) != DownloadResult::OK || !thumbnail_data->image->loadFromFile(download_path.data)) {
thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
+ loading_image[free_index] = false;
return;
}
}
}
- if(resize_target_size.x != 0 && resize_target_size.y != 0) {
- sf::Vector2u new_image_size = to_vec2u(clamp_to_size(to_vec2f(thumbnail_data->image->getSize()), to_vec2f(resize_target_size)));
- if(new_image_size.x < thumbnail_data->image->getSize().x || new_image_size.y < thumbnail_data->image->getSize().y) {
- auto destination_image = std::make_unique<sf::Image>();
- copy_resize(*thumbnail_data->image, *destination_image, new_image_size);
- thumbnail_data->image = std::move(destination_image);
- save_image_as_thumbnail_atomic(*thumbnail_data->image, thumbnail_path, get_ext(url));
- thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
- return;
- }
- }
+ if(resize_target_size.x != 0 && resize_target_size.y != 0)
+ create_thumbnail_if_thumbnail_smaller_than_image(url, thumbnail_path, thumbnail_data.get(), resize_target_size);
thumbnail_data->loading_state = LoadingState::FINISHED_LOADING;
- loading_image = false;
+ loading_image[free_index] = false;
return;
});
- load_image_thread.detach();
+ download_image_thread[free_index].detach();
+ }
- return true;
+ int AsyncImageLoader::get_free_load_index() const {
+ for(int i = 0; i < NUM_IMAGE_LOAD_THREADS; ++i) {
+ if(!loading_image[i])
+ return i;
+ }
+ return -1;
}
} \ No newline at end of file
diff --git a/src/Body.cpp b/src/Body.cpp
index a22f3ff..0294d97 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -14,7 +14,7 @@ static const float padding_x = 10.0f;
static const float image_padding_x = 5.0f;
static const float padding_y = 5.0f;
static const float embedded_item_padding_y = 0.0f;
-static const double thumbnail_fade_duration_sec = 0.25;
+static const double thumbnail_fade_duration_sec = 0.1;
namespace QuickMedia {
BodyItem::BodyItem(std::string _title) :
diff --git a/src/DownloadUtils.cpp b/src/DownloadUtils.cpp
index 8782020..fd7e7d1 100644
--- a/src/DownloadUtils.cpp
+++ b/src/DownloadUtils.cpp
@@ -80,6 +80,31 @@ namespace QuickMedia {
}
}
+ // TODO: Use this everywhere we want to save to file (such as manga download)
+ DownloadResult download_to_file(const std::string &url, const std::string &destination_filepath, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent) {
+ Path tmp_filepath = destination_filepath;
+ tmp_filepath.append(".tmp");
+
+ // TODO: Optimize with temporary '\0'
+ size_t dir_end = tmp_filepath.data.rfind('/');
+ if(dir_end != std::string::npos && create_directory_recursive(tmp_filepath.data.substr(0, dir_end)) != 0)
+ return DownloadResult::ERR;
+
+ std::vector<CommandArg> args = additional_args;
+ args.push_back({ "-o", tmp_filepath.data.c_str() });
+
+ std::string dummy;
+ DownloadResult res = download_to_string(url, dummy, std::move(args), use_tor, use_browser_useragent);
+ if(res != DownloadResult::OK) return res;
+
+ if(rename(tmp_filepath.data.c_str(), destination_filepath.c_str()) != 0) {
+ perror("rename");
+ return DownloadResult::ERR;
+ }
+
+ return DownloadResult::OK;
+ }
+
// TODO: Add timeout
DownloadResult download_to_json(const std::string &url, rapidjson::Document &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent, bool fail_on_error) {
sf::Clock timer;
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 54af0fa..659e59c 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -380,16 +380,6 @@ namespace QuickMedia {
}
Program::~Program() {
- if(upscale_image_action != UpscaleImageAction::NO && running) {
- running = false;
- {
- std::unique_lock<std::mutex> lock(image_upscale_mutex);
- image_upscale_cv.notify_one();
- }
- image_upscale_thead.join();
- } else {
- running = false;
- }
if(matrix)
delete matrix;
if(disp)
@@ -506,15 +496,12 @@ namespace QuickMedia {
return -2;
}
- running = true;
image_upscale_thead = std::thread([this]{
CopyOp copy_op;
- while(running) {
+ while(true) {
{
std::unique_lock<std::mutex> lock(image_upscale_mutex);
- while(images_to_upscale.empty() && running) image_upscale_cv.wait(lock);
- if(!running)
- break;
+ while(images_to_upscale.empty()) image_upscale_cv.wait(lock);
copy_op = images_to_upscale.front();
images_to_upscale.pop_front();
}
@@ -539,8 +526,7 @@ namespace QuickMedia {
file_overwrite(copy_op.destination.data.c_str(), "1");
}
});
- } else {
- running = true;
+ image_upscale_thead.detach();
}
if(strcmp(plugin_name, "file-manager") != 0 && start_dir) {