aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--include/AsyncImageLoader.hpp3
-rw-r--r--src/AsyncImageLoader.cpp25
-rw-r--r--src/FileAnalyzer.cpp10
-rw-r--r--src/plugins/Matrix.cpp2
-rw-r--r--src/plugins/Youtube.cpp15
6 files changed, 43 insertions, 13 deletions
diff --git a/TODO b/TODO
index fb29f2a..6d06090 100644
--- a/TODO
+++ b/TODO
@@ -78,7 +78,6 @@ Implement our own encryption for matrix. This is also needed to make forwarded m
Modify matrix sync to download and parse json but not handle it, and then add a function to handle the json. This would allow us to remove all the mutex code if we would call that new method from the main thread (similar to chromium multithreading).
Fetch replies/pinned message using multiple threads.
Show in room tags list when there is a message in any of the rooms in the tag.
-Support webp. Then switch to the youtube thumbnails from the response json instead of hqdefault, to remove the black bars.
Show images while they download by showing them as scanlines starting from the top. Needed for slow websites such as 4chan.
Use curl parallel download instead of downloading with multiple threads. This can be done with multiple -O parameters.
Add functionality to ignore users in matrix. This is done with an ignore request and we wont get messages and invites from that user anymore. Also add option to ignore in the invites page.
diff --git a/include/AsyncImageLoader.hpp b/include/AsyncImageLoader.hpp
index 4acae5e..0384a71 100644
--- a/include/AsyncImageLoader.hpp
+++ b/include/AsyncImageLoader.hpp
@@ -2,6 +2,7 @@
#include "../include/Storage.hpp"
#include "../include/MessageQueue.hpp"
+#include "../include/FileAnalyzer.hpp"
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/System/Clock.hpp>
@@ -26,7 +27,7 @@ namespace QuickMedia {
};
// This function is async
- bool create_thumbnail(const Path &thumbnail_path, const Path &thumbnail_path_resized, sf::Vector2i resize_target_size);
+ bool create_thumbnail(const Path &thumbnail_path, const Path &thumbnail_path_resized, sf::Vector2i resize_target_size, ContentType content_type);
constexpr int NUM_IMAGE_LOAD_THREADS = 4;
diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp
index 34df062..6504992 100644
--- a/src/AsyncImageLoader.cpp
+++ b/src/AsyncImageLoader.cpp
@@ -1,5 +1,4 @@
#include "../include/AsyncImageLoader.hpp"
-#include "../include/FileAnalyzer.hpp"
#include "../include/DownloadUtils.hpp"
#include "../include/Program.hpp"
#include "../include/ImageUtils.hpp"
@@ -11,18 +10,34 @@
#include <assert.h>
namespace QuickMedia {
- bool create_thumbnail(const Path &thumbnail_path, const Path &thumbnail_path_resized, sf::Vector2i resize_target_size) {
+ bool create_thumbnail(const Path &thumbnail_path, const Path &thumbnail_path_resized, sf::Vector2i resize_target_size, ContentType content_type) {
+ Path input_path = thumbnail_path;
+
+ // TODO: Remove this when imagemagick supports webp
+ // Convert webp to png
+ if(content_type == ContentType::IMAGE_WEBP) {
+ Path result_path_tmp = input_path;
+ result_path_tmp.append(".tmp.png");
+
+ const char *args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", input_path.data.c_str(), "--", result_path_tmp.data.c_str(), nullptr};
+ int res = exec_program(args, nullptr, nullptr);
+ if(res != 0)
+ return false;
+
+ input_path = std::move(result_path_tmp);
+ }
+
// > is to only shrink image if smaller than the target size
std::string new_size = std::to_string(resize_target_size.x) + "x" + std::to_string(resize_target_size.y) + ">";
// We only want the first frame if its a gif
- Path thumbnail_path_first_frame = thumbnail_path;
+ Path thumbnail_path_first_frame = std::move(input_path);
thumbnail_path_first_frame.append("[0]");
Path result_path_tmp = thumbnail_path_resized;
result_path_tmp.append(".tmp");
- const char *args[] = { "convert", thumbnail_path_first_frame.data.c_str(), "-thumbnail", new_size.c_str(), result_path_tmp.data.c_str(), nullptr};
+ const char *args[] = { "convert", thumbnail_path_first_frame.data.c_str(), "-thumbnail", new_size.c_str(), result_path_tmp.data.c_str(), nullptr};
int convert_res = exec_program(args, nullptr, nullptr);
if(convert_res == 0 && rename_atomic(result_path_tmp.data.c_str(), thumbnail_path_resized.data.c_str()) == 0)
return true;
@@ -46,7 +61,7 @@ namespace QuickMedia {
return;
}
- if(create_thumbnail(thumbnail_path, thumbnail_path_resized, resize_target_size)) {
+ if(create_thumbnail(thumbnail_path, thumbnail_path_resized, resize_target_size, file_analyzer.get_content_type())) {
load_image_from_file(*thumbnail_data->image, thumbnail_path_resized.data);
} else {
load_image_from_file(*thumbnail_data->image, thumbnail_path.data);
diff --git a/src/FileAnalyzer.cpp b/src/FileAnalyzer.cpp
index 9f05919..bd13a01 100644
--- a/src/FileAnalyzer.cpp
+++ b/src/FileAnalyzer.cpp
@@ -21,7 +21,7 @@ namespace QuickMedia {
// What about audio ogg files that are not opus?
// TODO: Test all of these
- static const std::array<MagicNumber, 25> magic_numbers = {
+ static const std::array<MagicNumber, 26> magic_numbers = {
MagicNumber{ {'R', 'I', 'F', 'F', -1, -1, -1, -1, 'A', 'V', 'I', ' '}, 12, ContentType::VIDEO_AVI },
MagicNumber{ {0x00, 0x00, 0x00, -1, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm'}, 12, ContentType::VIDEO_MP4 },
MagicNumber{ {0x00, 0x00, 0x00, -1, 'f', 't', 'y', 'p', 'm', 'p', '4', '2'}, 12, ContentType::VIDEO_MP4 },
@@ -47,7 +47,8 @@ namespace QuickMedia {
MagicNumber{ {'G', 'I', 'F', '8', '7', 'a'}, 6, ContentType::IMAGE_GIF },
MagicNumber{ {'G', 'I', 'F', '8', '9', 'a'}, 6, ContentType::IMAGE_GIF },
MagicNumber{ {'B', 'M'}, 2, ContentType::IMAGE_BMP },
- MagicNumber{ {'R', 'I', 'F', 'F', -1, -1, -1, -1, 'W', 'E', 'B', 'V', 'P'}, 6, ContentType::IMAGE_WEBP }
+ MagicNumber{ {'R', 'I', 'F', 'F', -1, -1, -1, -1, 'W', 'E', 'B', 'P'}, 12, ContentType::IMAGE_WEBP },
+ MagicNumber{ {'R', 'I', 'F', 'F', -1, -1, -1, -1, 'W', 'E', 'B', 'V', 'P'}, 13, ContentType::IMAGE_WEBP }
};
bool is_content_type_video(ContentType content_type) {
@@ -121,7 +122,7 @@ namespace QuickMedia {
Path destination_path_tmp = destination_path;
destination_path_tmp.append(".ftmp");
- const char *program_args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", filepath, "-vframes", "1", "-f", "singlejpeg", destination_path_tmp.data.c_str(), nullptr };
+ const char *program_args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", filepath, "-vframes", "1", "-f", "singlejpeg", "--", destination_path_tmp.data.c_str(), nullptr };
std::string ffmpeg_result;
if(exec_program(program_args, nullptr, nullptr) != 0) {
fprintf(stderr, "Failed to execute ffmpeg, maybe its not installed?\n");
@@ -129,7 +130,8 @@ namespace QuickMedia {
}
if(width > 0 && height > 0) {
- if(create_thumbnail(destination_path_tmp, destination_path, sf::Vector2i(width, height))) {
+ FileAnalyzer file_analyzer;
+ if(file_analyzer.load_file(destination_path_tmp.data.c_str(), false) && create_thumbnail(destination_path_tmp, destination_path, sf::Vector2i(width, height), file_analyzer.get_content_type())) {
remove(destination_path_tmp.data.c_str());
return true;
}
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 77d8f32..6f8b30b 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -3278,7 +3278,7 @@ namespace QuickMedia {
int tmp_file = mkstemp(tmp_filename);
if(tmp_file != -1) {
std::string thumbnail_path;
- if(create_thumbnail(filepath, tmp_filename, thumbnail_max_size))
+ if(create_thumbnail(filepath, tmp_filename, thumbnail_max_size, file_analyzer.get_content_type()))
thumbnail_path = tmp_filename;
else
thumbnail_path = filepath;
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index 993c861..cf3bbe4 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -53,10 +53,10 @@ namespace QuickMedia {
enum class ThumbnailSize {
SMALLEST,
+ MEDIUM,
LARGEST
};
- // TODO: Use this in |parse_common_video_item| when QuickMedia supports webp
static std::optional<Thumbnail> yt_json_get_thumbnail(const Json::Value &thumbnail_json, ThumbnailSize thumbnail_size) {
if(!thumbnail_json.isObject())
return std::nullopt;
@@ -85,6 +85,9 @@ namespace QuickMedia {
thumbnails.push_back({ url_json.asCString(), width_json.asInt(), height_json.asInt() });
}
+ if(thumbnails.empty())
+ return std::nullopt;
+
switch(thumbnail_size) {
case ThumbnailSize::SMALLEST:
return *std::min_element(thumbnails.begin(), thumbnails.end(), [](const Thumbnail &thumbnail1, const Thumbnail &thumbnail2) {
@@ -92,6 +95,14 @@ namespace QuickMedia {
int size2 = thumbnail2.width * thumbnail2.height;
return size1 < size2;
});
+ case ThumbnailSize::MEDIUM: {
+ std::sort(thumbnails.begin(), thumbnails.end(), [](const Thumbnail &thumbnail1, const Thumbnail &thumbnail2) {
+ int size1 = thumbnail1.width * thumbnail1.height;
+ int size2 = thumbnail2.width * thumbnail2.height;
+ return size1 < size2;
+ });
+ return thumbnails[thumbnails.size() / 2];
+ }
case ThumbnailSize::LARGEST:
return *std::max_element(thumbnails.begin(), thumbnails.end(), [](const Thumbnail &thumbnail1, const Thumbnail &thumbnail2) {
int size1 = thumbnail1.width * thumbnail1.height;
@@ -184,8 +195,10 @@ namespace QuickMedia {
body_item->set_description_color(sf::Color(179, 179, 179));
if(scheduled_text.empty())
body_item->url = "https://www.youtube.com/watch?v=" + video_id_str;
+
body_item->thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg";
body_item->thumbnail_size = sf::Vector2i(175, 131);
+
added_videos.insert(video_id_str);
return body_item;
}