aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-11-11 10:50:39 +0100
committerdec05eba <dec05eba@protonmail.com>2022-11-11 10:50:39 +0100
commitd274d3a6dfc0864ec6a44e7d6948c2d873eb6f76 (patch)
treea4308da3afd0e7c567c40f8a26ab1bdcbc58a898 /src/plugins
parent25f6303ae40e9245f42545d120efa8b6f9be98d7 (diff)
Add image (custom emoji) alt text for copy-pasting, limit custom emoji size in room description, change max size to 32, 32, cache custom emoji locally
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Matrix.cpp101
1 files changed, 72 insertions, 29 deletions
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index fd5026a..e53cf71 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -28,7 +28,7 @@
namespace QuickMedia {
static const mgl::vec2i thumbnail_max_size(600, 337);
- static const mgl::vec2i custom_emoji_max_size(64, 64);
+ static const mgl::vec2i custom_emoji_max_size(32, 32);
static const char* SERVICE_NAME = "matrix";
static const char* OTHERS_ROOM_TAG = "tld.name.others";
// Filter without account data. TODO: We include pinned events but limit events to 1. That means if the last event is a pin,
@@ -640,8 +640,8 @@ namespace QuickMedia {
return message->body;
}
- static std::string message_to_room_description_text(Matrix *matrix, Message *message) {
- std::string body = strip(formatted_text_to_qm_text(matrix, message->body.c_str(), message->body.size(), true));
+ static std::string message_to_room_description_text(Matrix *matrix, Message *message, mgl::vec2i image_max_size = mgl::vec2i(0, 0)) {
+ std::string body = strip(formatted_text_to_qm_text(matrix, message->body.c_str(), message->body.size(), true, image_max_size));
if(message->type == MessageType::REACTION)
return "Reacted with: " + body;
else if(message->related_event_type == RelatedEventType::REPLY)
@@ -708,7 +708,7 @@ namespace QuickMedia {
room_desc += "Unread: ";
if(last_unread_message)
- room_desc += extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(last_unread_message), AUTHOR_MAX_LENGTH) + ": " + message_to_room_description_text(matrix, last_unread_message);
+ room_desc += extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(last_unread_message), AUTHOR_MAX_LENGTH) + ": " + message_to_room_description_text(matrix, last_unread_message, custom_emoji_max_size);
int unread_notification_count = room->unread_notification_count;
if(unread_notification_count > 0 && set_room_as_unread) {
@@ -728,7 +728,7 @@ namespace QuickMedia {
rooms_page->move_room_to_top(room);
room_tags_page->move_room_to_top(room);
} else if(last_new_message) {
- room->body_item->set_description(extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(last_new_message.get()), AUTHOR_MAX_LENGTH) + ": " + message_to_room_description_text(matrix, last_new_message.get()));
+ room->body_item->set_description(extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(last_new_message.get()), AUTHOR_MAX_LENGTH) + ": " + message_to_room_description_text(matrix, last_new_message.get(), custom_emoji_max_size));
room->body_item->set_description_color(get_theme().faded_text_color);
room->body_item->set_description_max_lines(3);
@@ -1503,12 +1503,12 @@ namespace QuickMedia {
sync_is_cache = false;
sync_running = true;
+ load_custom_emoji_from_cache();
+
sync_thread = std::thread([this, matrix_cache_dir]() {
sync_is_cache = true;
- bool cache_available = false;
FILE *sync_cache_file = fopen(matrix_cache_dir.data.c_str(), "rb");
if(sync_cache_file) {
- cache_available = true;
rapidjson::Document doc;
char read_buffer[8192];
rapidjson::FileReadStream is(sync_cache_file, read_buffer, sizeof(read_buffer));
@@ -1949,6 +1949,47 @@ namespace QuickMedia {
return PluginResult::OK;
}
+ void Matrix::parse_custom_emoji(const rapidjson::Value &custom_emoji_json) {
+ if(!custom_emoji_json.IsObject())
+ return;
+
+ std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
+ custom_emoji_by_key.clear();
+ for(auto const &emoji_json : custom_emoji_json.GetObject()) {
+ if(!emoji_json.name.IsString() || !emoji_json.value.IsObject())
+ continue;
+
+ const rapidjson::Value &url_json = GetMember(emoji_json.value, "url");
+ const rapidjson::Value &width_json = GetMember(emoji_json.value, "width");
+ const rapidjson::Value &height_json = GetMember(emoji_json.value, "height");
+ if(!url_json.IsString())
+ continue;
+
+ CustomEmoji custom_emoji;
+ custom_emoji.url = url_json.GetString();
+ if(width_json.IsInt() && height_json.IsInt()) {
+ custom_emoji.size.x = width_json.GetInt();
+ custom_emoji.size.y = height_json.GetInt();
+ }
+ custom_emoji_by_key[emoji_json.name.GetString()] = std::move(custom_emoji);
+ }
+ }
+
+ void Matrix::load_custom_emoji_from_cache() {
+ std::string custom_emoji_file_content;
+ if(file_get_content(get_cache_dir().join("matrix").join("custom_emoji.json"), custom_emoji_file_content) != 0)
+ return;
+
+ rapidjson::Document json_root;
+ rapidjson::ParseResult parse_result = json_root.Parse(custom_emoji_file_content.c_str(), custom_emoji_file_content.size());
+ if(parse_result.IsError()) {
+ fprintf(stderr, "Warning: failed to parse custom_emoji.json, error: %d\n", parse_result.Code());
+ return;
+ }
+
+ parse_custom_emoji(json_root);
+ }
+
PluginResult Matrix::parse_sync_account_data(const rapidjson::Value &account_data_json) {
if(!account_data_json.IsObject())
return PluginResult::OK;
@@ -2004,26 +2045,12 @@ namespace QuickMedia {
}
}
} else if(strcmp(type_json.GetString(), "qm.emoji") == 0) {
- std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
- for(auto const &emoji_json : content_json.GetObject()) {
- if(!emoji_json.name.IsString() || !emoji_json.value.IsObject())
- continue;
-
- const rapidjson::Value &url_json = GetMember(emoji_json.value, "url");
- const rapidjson::Value &width_json = GetMember(emoji_json.value, "width");
- const rapidjson::Value &height_json = GetMember(emoji_json.value, "height");
- if(!url_json.IsString())
- continue;
-
- CustomEmoji custom_emoji;
- custom_emoji.url = url_json.GetString();
- if(width_json.IsInt() && height_json.IsInt()) {
- custom_emoji.size.x = width_json.GetInt();
- custom_emoji.size.y = height_json.GetInt();
- }
- custom_emoji_by_key[emoji_json.name.GetString()] = std::move(custom_emoji);
- }
- }
+ parse_custom_emoji(content_json);
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ content_json.Accept(writer);
+ file_overwrite_atomic(get_cache_dir().join("matrix").join("custom_emoji.json"), std::string(buffer.GetString(), buffer.GetSize()));
+ }
}
return PluginResult::OK;
@@ -2585,9 +2612,11 @@ namespace QuickMedia {
bool supports_syntax_highlight = false;
bool inside_img_tag = false;
std::string_view img_src;
+ std::string_view img_alt;
mgl::vec2i img_size;
mgl::Color font_color = mgl::Color(255, 255, 255, 255);
Matrix *matrix = nullptr;
+ mgl::vec2i image_max_size;
};
static int accumulate_string(char *data, int size, void *userdata) {
@@ -2615,6 +2644,7 @@ namespace QuickMedia {
} else if(html_parser->tag_name.size == 3 && memcmp(html_parser->tag_name.data, "img", 3) == 0) {
parse_userdata.inside_img_tag = true;
parse_userdata.img_src = std::string_view();
+ parse_userdata.img_alt = std::string_view();
parse_userdata.img_size = { 0, 0 };
}
break;
@@ -2637,7 +2667,9 @@ namespace QuickMedia {
// TODO: Better solution when size not given?
if(img_size.x == 0 || img_size.y == 0)
img_size = custom_emoji_max_size;
- parse_userdata.result += Text::formatted_image(parse_userdata.matrix->get_media_url(image_url), false, img_size);
+ if(parse_userdata.image_max_size.x > 0 && parse_userdata.image_max_size.y > 0)
+ img_size = clamp_to_size(img_size, parse_userdata.image_max_size);
+ parse_userdata.result += Text::formatted_image(parse_userdata.matrix->get_media_url(image_url), false, img_size, std::string(parse_userdata.img_alt));
}
parse_userdata.inside_img_tag = false;
}
@@ -2659,6 +2691,8 @@ namespace QuickMedia {
} else if(html_parser->attribute_key.size == 6 && memcmp(html_parser->attribute_key.data, "height", 6) == 0) {
const std::string height(html_parser->attribute_value.data, html_parser->attribute_value.size);
parse_userdata.img_size.y = atoi(height.c_str());
+ } else if(html_parser->attribute_key.size == 3 && memcmp(html_parser->attribute_key.data, "alt", 3) == 0) {
+ parse_userdata.img_alt = std::string_view(html_parser->attribute_value.data, html_parser->attribute_value.size);
}
} else if(!parse_userdata.allow_formatted_text && parse_userdata.inside_img_tag && parse_userdata.mx_reply_depth == 0 && html_parser->attribute_key.size == 3 && memcmp(html_parser->attribute_key.data, "alt", 3) == 0) {
std::string text_to_add(html_parser->attribute_value.data, html_parser->attribute_value.size);
@@ -2712,11 +2746,12 @@ namespace QuickMedia {
return 0;
}
- std::string formatted_text_to_qm_text(Matrix *matrix, const char *str, size_t size, bool allow_formatted_text) {
+ std::string formatted_text_to_qm_text(Matrix *matrix, const char *str, size_t size, bool allow_formatted_text, mgl::vec2i image_max_size) {
FormattedTextParseUserdata parse_userdata;
parse_userdata.allow_formatted_text = allow_formatted_text;
parse_userdata.supports_syntax_highlight = is_program_executable_by_name("source-highlight");
parse_userdata.matrix = matrix;
+ parse_userdata.image_max_size = image_max_size;
html_parser_parse(str, size, formattext_text_parser_callback, &parse_userdata);
return std::move(parse_userdata.result);
}
@@ -4387,6 +4422,8 @@ namespace QuickMedia {
if(download_result != DownloadResult::OK)
return download_result_to_plugin_result(download_result);
+ // TODO: Is this even needed? (including in other /account_data/qm.emoji functions), wont we get qm.emoji update in sync?
+ file_overwrite_atomic(get_cache_dir().join("matrix").join("custom_emoji.json"), std::string(buffer.GetString(), buffer.GetSize()));
std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
custom_emoji_by_key[key] = std::move(custom_emoji);
return PluginResult::OK;
@@ -4428,6 +4465,7 @@ namespace QuickMedia {
if(download_result != DownloadResult::OK)
return false;
+ file_overwrite_atomic(get_cache_dir().join("matrix").join("custom_emoji.json"), std::string(buffer.GetString(), buffer.GetSize()));
std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
auto it = custom_emoji_by_key.find(key);
if(it != custom_emoji_by_key.end())
@@ -4445,6 +4483,10 @@ namespace QuickMedia {
if(it == custom_emoji_list_copy.end())
return false;
+ auto existing_new_it = custom_emoji_list_copy.find(new_key);
+ if(existing_new_it != custom_emoji_list_copy.end())
+ return false;
+
auto custom_emoji_copy = it->second;
custom_emoji_list_copy.erase(it);
custom_emoji_list_copy[new_key] = std::move(custom_emoji_copy);
@@ -4473,6 +4515,7 @@ namespace QuickMedia {
if(download_result != DownloadResult::OK)
return false;
+ file_overwrite_atomic(get_cache_dir().join("matrix").join("custom_emoji.json"), std::string(buffer.GetString(), buffer.GetSize()));
std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
auto it = custom_emoji_by_key.find(key);
if(it != custom_emoji_by_key.end()) {