aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Json.cpp21
-rw-r--r--src/QuickMedia.cpp10
-rw-r--r--src/plugins/Matrix.cpp51
-rw-r--r--src/plugins/Pleroma.cpp189
4 files changed, 236 insertions, 35 deletions
diff --git a/src/Json.cpp b/src/Json.cpp
new file mode 100644
index 0000000..86703b2
--- /dev/null
+++ b/src/Json.cpp
@@ -0,0 +1,21 @@
+#include "../include/Json.hpp"
+
+namespace QuickMedia {
+ static rapidjson::Value nullValue(rapidjson::kNullType);
+ const rapidjson::Value& GetMember(const rapidjson::Value &obj, const char *key) {
+ auto it = obj.FindMember(key);
+ if(it != obj.MemberEnd())
+ return it->value;
+ return nullValue;
+ }
+
+ DownloadResult download_json(rapidjson::Document &result, const std::string &url, std::vector<CommandArg> additional_args, bool use_tor, bool use_browser_useragent, std::string *err_msg) {
+ if(download_to_json(url, result, std::move(additional_args), use_tor, use_browser_useragent, err_msg == nullptr) != DownloadResult::OK) {
+ // Cant get error since we parse directly to json. TODO: Make this work somehow?
+ if(err_msg)
+ *err_msg = "Failed to download/parse json";
+ return DownloadResult::NET_ERR;
+ }
+ return DownloadResult::OK;
+ }
+} \ No newline at end of file
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 866d27d..aeb719e 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -7,6 +7,7 @@
#include "../plugins/Fourchan.hpp"
#include "../plugins/NyaaSi.hpp"
#include "../plugins/Matrix.hpp"
+#include "../plugins/Pleroma.hpp"
#include "../plugins/FileManager.hpp"
#include "../include/Scale.hpp"
#include "../include/Program.hpp"
@@ -395,7 +396,7 @@ namespace QuickMedia {
static void usage() {
fprintf(stderr, "usage: QuickMedia <plugin> [--tor] [--no-video] [--use-system-mpv-config] [--dir <directory>]\n");
fprintf(stderr, "OPTIONS:\n");
- fprintf(stderr, " plugin The plugin to use. Should be either 4chan, manganelo, mangatown, mangadex, pornhub, youtube, nyaa.si, matrix, file-manager\n");
+ fprintf(stderr, " plugin The plugin to use. Should be either 4chan, manganelo, mangatown, mangadex, pornhub, youtube, nyaa.si, matrix or file-manager\n");
fprintf(stderr, " --no-video Only play audio when playing a video. Disabled by default\n");
fprintf(stderr, " --tor Use tor. Disabled by default\n");
fprintf(stderr, " --use-system-mpv-config Use system mpv config instead of no config. Disabled by default\n");
@@ -449,6 +450,9 @@ namespace QuickMedia {
plugin_name = argv[i];
matrix = new Matrix();
plugin_logo_path = resources_root + "images/matrix_logo.png";
+ } else if(strcmp(argv[i], "mastodon") == 0 || strcmp(argv[i], "pleroma") == 0) {
+ plugin_name = argv[i];
+ plugin_logo_path = resources_root + "images/pleroma_logo.png";
} else if(strcmp(argv[i], "file-manager") == 0) {
plugin_name = argv[i];
}
@@ -608,6 +612,10 @@ namespace QuickMedia {
} else if(strcmp(plugin_name, "pornhub") == 0) {
auto search_body = create_body();
tabs.push_back(Tab{std::move(search_body), std::make_unique<PornhubSearchPage>(this), create_search_bar("Search...", 500)});
+ } else if(strcmp(plugin_name, "mastodon") == 0 || strcmp(plugin_name, "pleroma") == 0) {
+ auto pleroma = std::make_shared<Pleroma>();
+ auto search_body = create_body();
+ tabs.push_back(Tab{std::move(search_body), std::make_unique<PleromaHomePage>(this, pleroma), create_search_bar("Search...", 350)});
}
if(!tabs.empty()) {
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 653569d..1d28ed2 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -5,6 +5,7 @@
#include "../../include/Notification.hpp"
#include "../../include/Program.hpp"
#include "../../include/base64_url.hpp"
+#include "../../include/Json.hpp"
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
@@ -26,14 +27,6 @@ static const char* INITIAL_FILTER = "{\"presence\":{\"limit\":0,\"types\":[\"\"]
static const char* ADDITIONAL_MESSAGES_FILTER = "{\"presence\":{\"limit\":0,\"types\":[\"\"]},\"account_data\":{\"limit\":0,\"types\":[\"\"]},\"room\":{\"state\":{\"not_types\":[\"m.room.related_groups\",\"m.room.power_levels\",\"m.room.join_rules\",\"m.room.history_visibility\"],\"lazy_load_members\":true},\"timeline\":{\"limit\":20,\"lazy_load_members\":true},\"ephemeral\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true},\"account_data\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true}}}";
static const char* CONTINUE_FILTER = "{\"presence\":{\"limit\":0,\"types\":[\"\"]},\"account_data\":{\"limit\":0,\"types\":[\"\"]},\"room\":{\"state\":{\"not_types\":[\"m.room.related_groups\",\"m.room.power_levels\",\"m.room.join_rules\",\"m.room.history_visibility\"],\"lazy_load_members\":true},\"timeline\":{\"lazy_load_members\":true},\"ephemeral\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true},\"account_data\":{\"types\":[\"m.fully_read\",\"m.tag\"],\"lazy_load_members\":true}}}";
-static rapidjson::Value nullValue(rapidjson::kNullType);
-static const rapidjson::Value& GetMember(const rapidjson::Value &obj, const char *key) {
- auto it = obj.FindMember(key);
- if(it != obj.MemberEnd())
- return it->value;
- return nullValue;
-}
-
static std::string capitalize(const std::string &str) {
if(str.size() >= 1)
return (char)std::toupper(str[0]) + str.substr(1);
@@ -1036,7 +1029,7 @@ namespace QuickMedia {
rapidjson::Document json_root;
std::string err_msg;
- DownloadResult download_result = download_json(json_root, url, additional_args, true, &err_msg);
+ DownloadResult download_result = download_json(json_root, url, additional_args, use_tor, true, &err_msg);
if(download_result != DownloadResult::OK) {
fprintf(stderr, "/sync for additional messages failed\n");
return;
@@ -1062,7 +1055,7 @@ namespace QuickMedia {
rapidjson::Document json_root;
std::string err_msg;
- DownloadResult download_result = download_json(json_root, url, additional_args, true, &err_msg);
+ DownloadResult download_result = download_json(json_root, url, additional_args, use_tor, true, &err_msg);
if(download_result != DownloadResult::OK) {
fprintf(stderr, "/sync failed\n");
goto sync_end;
@@ -1118,7 +1111,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/notifications?limit=100&only=highlight", homeserver.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK || !json_root.IsObject()) {
fprintf(stderr, "Fetching notifications failed!\n");
return;
@@ -2382,7 +2375,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/messages?from=%s&limit=20&dir=b&filter=%s", homeserver.c_str(), room_data->id.c_str(), from.c_str(), filter.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -2536,7 +2529,7 @@ namespace QuickMedia {
snprintf(request_url, sizeof(request_url), "%s/_matrix/client/r0/rooms/%s/send/m.room.message/%s", homeserver.c_str(), room->id.c_str(), transaction_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -2679,7 +2672,7 @@ namespace QuickMedia {
snprintf(request_url, sizeof(request_url), "%s/_matrix/client/r0/rooms/%s/send/m.room.message/%s", homeserver.c_str(), room->id.c_str(), transaction_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -2763,7 +2756,7 @@ namespace QuickMedia {
snprintf(request_url, sizeof(request_url), "%s/_matrix/client/r0/rooms/%s/send/m.room.message/%s", homeserver.c_str(), room->id.c_str(), transaction_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -2809,7 +2802,7 @@ namespace QuickMedia {
snprintf(request_url, sizeof(request_url), "%s/_matrix/client/r0/rooms/%s/send/m.reaction/%s", homeserver.c_str(), room->id.c_str(), transaction_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -3011,7 +3004,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/media/r0/upload?filename=%s", homeserver.c_str(), filename_escaped.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true, &err_msg);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true, &err_msg);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject()) {
@@ -3059,7 +3052,7 @@ namespace QuickMedia {
};
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/login", std::move(additional_args), true, &err_msg);
+ DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/login", std::move(additional_args), use_tor, true, &err_msg);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
Path matrix_sync_data_path = get_cache_dir().join("matrix").join("sync_data.json");
@@ -3170,7 +3163,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/redact/%s/%s", homeserver.c_str(), room->id.c_str(), message_typed->event_id.c_str(), transaction_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true, &err_msg);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true, &err_msg);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject()) {
@@ -3392,7 +3385,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/media/r0/config", homeserver.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
if(!json_root.IsObject())
@@ -3492,7 +3485,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/profile/%s", homeserver.c_str(), user_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, {}, true);
+ DownloadResult download_result = download_json(json_root, url, {}, use_tor, true);
if(download_result != DownloadResult::OK || !json_root.IsObject()) {
fprintf(stderr, "Fetching profile for user %s failed!\n", user_id.c_str());
auto user = get_user_by_id(room, user_id);
@@ -3514,7 +3507,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/joined_members", homeserver.c_str(), room->id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK || !json_root.IsObject()) {
fprintf(stderr, "Fetching users for room %s failed!\n", room->id.c_str());
return;
@@ -3561,7 +3554,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/members?membership=join", homeserver.c_str(), room->id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK || !json_root.IsObject()) {
fprintf(stderr, "Fetching users for room %s failed!\n", room->id.c_str());
return;
@@ -3601,7 +3594,7 @@ namespace QuickMedia {
snprintf(url, sizeof(url), "%s/_matrix/client/r0/user/%s/filter", homeserver.c_str(), user_id.c_str());
rapidjson::Document json_root;
- DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
+ DownloadResult download_result = download_json(json_root, url, std::move(additional_args), use_tor, true);
if(download_result != DownloadResult::OK || !json_root.IsObject()) return FILTER;
const rapidjson::Value &filter_id_json = GetMember(json_root, "filter_id");
@@ -3619,14 +3612,4 @@ namespace QuickMedia {
return INITIAL_FILTER;
#endif
}
-
- DownloadResult Matrix::download_json(rapidjson::Document &result, const std::string &url, std::vector<CommandArg> additional_args, bool use_browser_useragent, std::string *err_msg) const {
- if(download_to_json(url, result, std::move(additional_args), use_tor, use_browser_useragent, err_msg == nullptr) != DownloadResult::OK) {
- // Cant get error since we parse directly to json. TODO: Make this work somehow?
- if(err_msg)
- *err_msg = "Failed to download/parse json";
- return DownloadResult::NET_ERR;
- }
- return DownloadResult::OK;
- }
} \ No newline at end of file
diff --git a/src/plugins/Pleroma.cpp b/src/plugins/Pleroma.cpp
new file mode 100644
index 0000000..c04482d
--- /dev/null
+++ b/src/plugins/Pleroma.cpp
@@ -0,0 +1,189 @@
+#include "../../plugins/Pleroma.hpp"
+#include "../../include/Json.hpp"
+#include "../../include/NetUtils.hpp"
+extern "C" {
+#include <HtmlParser.h>
+}
+
+namespace QuickMedia {
+ struct HtmlParseUserdata {
+ std::string result;
+ };
+
+ static void html_parse_callback(HtmlParser *html_parser, HtmlParseType parse_type, void *userdata) {
+ HtmlParseUserdata *parse_userdata = (HtmlParseUserdata*)userdata;
+ if(parse_type == HTML_PARSE_TEXT) {
+ parse_userdata->result.append(html_parser->text_stripped.data, html_parser->text_stripped.size);
+ } else if(parse_type == HTML_PARSE_TAG_END) {
+ if(html_parser->tag_name.size == 4 && strncmp(html_parser->tag_name.data, "span", 4) == 0)
+ parse_userdata->result += ' ';
+ else if(html_parser->tag_name.size == 1 && strncmp(html_parser->tag_name.data, "p", 1) == 0)
+ parse_userdata->result += "\n\n";
+ else if(html_parser->tag_name.size == 2 && strncmp(html_parser->tag_name.data, "br", 2) == 0)
+ parse_userdata->result += '\n';
+ }
+ }
+
+ std::shared_ptr<BodyItem> post_json_to_body_item(const rapidjson::Value &post_json, const std::string &instance, int &num_favorites, int &num_reblogs, int &num_replies) {
+ num_favorites = 0;
+ num_reblogs = 0;
+ num_replies = 0;
+
+ if(!post_json.IsObject())
+ return nullptr;
+
+ const rapidjson::Value &account_json = GetMember(post_json, "account");
+ if(!account_json.IsObject())
+ return nullptr;
+
+ const rapidjson::Value &acct_json = GetMember(account_json, "acct");
+ if(!acct_json.IsString())
+ return nullptr;
+
+ std::string username;
+
+ const rapidjson::Value &display_name_json = GetMember(account_json, "display_name");
+ if(display_name_json.IsString()) {
+ username.append(display_name_json.GetString(), display_name_json.GetStringLength());
+ username += ' ';
+ }
+ username.append(acct_json.GetString(), acct_json.GetStringLength());
+ if(!strchr(acct_json.GetString(), '@'))
+ username += "@" + instance;
+
+ auto body_item = BodyItem::create("");
+ body_item->set_author(std::move(username));
+
+ const rapidjson::Value &content_json = GetMember(post_json, "content");
+ if(content_json.IsString()) {
+ std::string content(content_json.GetString(), content_json.GetStringLength());
+
+ HtmlParseUserdata parse_userdata;
+ HtmlParser html_parser;
+ html_parser_init(&html_parser, content.data(), content.size(), html_parse_callback, &parse_userdata);
+ html_parser_parse(&html_parser);
+ html_parser_deinit(&html_parser);
+
+ while(!parse_userdata.result.empty() && parse_userdata.result.back() == '\n')
+ parse_userdata.result.pop_back();
+ html_unescape_sequences(parse_userdata.result);
+ body_item->set_description(std::move(parse_userdata.result));
+ }
+
+ const rapidjson::Value &avatar_json = GetMember(account_json, "avatar");
+ if(avatar_json.IsString()) {
+ body_item->thumbnail_url = std::string(avatar_json.GetString(), avatar_json.GetStringLength());
+ body_item->thumbnail_size = sf::Vector2i(48, 48);
+ body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
+ }
+
+ // TODO: Display all attached images by embedded images in Text. Each image in Text should always be on its own line
+ const rapidjson::Value &media_attachments_json = GetMember(post_json, "media_attachments");
+ if(media_attachments_json.IsArray() && !media_attachments_json.Empty() && media_attachments_json.GetArray()[0].IsObject()) {
+ const rapidjson::Value &media_attachment_json = media_attachments_json.GetArray()[0];
+ const rapidjson::Value &preview_url = GetMember(media_attachment_json, "preview_url");
+ const rapidjson::Value &type_json = GetMember(media_attachment_json, "type");
+ // TODO: Support video preview image, or display dummy image that shows there is a video
+ if(preview_url.IsString() && type_json.IsString() && strcmp(type_json.GetString(), "image") == 0) {
+ body_item->thumbnail_url = std::string(preview_url.GetString(), preview_url.GetStringLength());
+ body_item->thumbnail_size = sf::Vector2i(0, 0);
+ body_item->thumbnail_mask_type = ThumbnailMaskType::NONE;
+ }
+ }
+
+ const rapidjson::Value &favourites_count_json = GetMember(post_json, "favourites_count");
+ if(favourites_count_json.IsNumber())
+ num_favorites = favourites_count_json.GetInt();
+
+ const rapidjson::Value &reblogs_count_json = GetMember(post_json, "reblogs_count");
+ if(reblogs_count_json.IsNumber())
+ num_reblogs = reblogs_count_json.GetInt();
+
+ const rapidjson::Value &replies_count_json = GetMember(post_json, "replies_count");
+ if(replies_count_json.IsNumber())
+ num_replies = replies_count_json.GetInt();
+
+ const rapidjson::Value &id_json = GetMember(post_json, "id");
+ if(id_json.IsString())
+ body_item->url.assign(id_json.GetString(), id_json.GetStringLength());
+
+ return body_item;
+ }
+
+ PluginResult Pleroma::get_home_posts(BodyItems &results, const std::string &max_id) {
+ std::vector<CommandArg> additional_args = {
+ { "-X", "GET" },
+ { "-H", "Authorization: Bearer " + auth_token }
+ };
+
+ char request_url[512];
+ if(max_id.empty())
+ snprintf(request_url, sizeof(request_url), "https://%s/api/v1/timelines/home", instance.c_str());
+ else
+ snprintf(request_url, sizeof(request_url), "https://%s/api/v1/timelines/home?max_id=%s", instance.c_str(), max_id.c_str());
+
+ rapidjson::Document json_root;
+ DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
+ if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
+
+ if(!json_root.IsArray())
+ return PluginResult::ERR;
+
+ for(auto &post_json : json_root.GetArray()) {
+ int post_num_favourites = 0;
+ int post_num_reblogs = 0;
+ int post_num_replies = 0;
+ auto post_body_item = post_json_to_body_item(post_json, instance, post_num_favourites, post_num_reblogs, post_num_replies);
+ if(!post_body_item)
+ continue;
+
+ const rapidjson::Value &reblog_json = GetMember(post_json, "reblog");
+ if(reblog_json.IsObject()) {
+ auto reblog_body_item = post_json_to_body_item(reblog_json, instance, post_num_favourites, post_num_reblogs, post_num_replies);
+ if(reblog_body_item) {
+ post_body_item->set_author(post_body_item->get_author() + " reposted:\n" + reblog_body_item->get_author());
+ post_body_item->set_description(reblog_body_item->get_description());
+ if(reblog_body_item->thumbnail_url.empty()) {
+ post_body_item->thumbnail_url.clear();
+ post_body_item->thumbnail_size = sf::Vector2i(0, 0);
+ post_body_item->thumbnail_mask_type = ThumbnailMaskType::NONE;
+ } else {
+ post_body_item->thumbnail_url = std::move(reblog_body_item->thumbnail_url);
+ post_body_item->thumbnail_size = reblog_body_item->thumbnail_size;
+ post_body_item->thumbnail_mask_type = reblog_body_item->thumbnail_mask_type;
+ }
+ }
+ }
+
+ post_body_item->add_reaction("Replies: " + std::to_string(post_num_replies), nullptr);
+ post_body_item->add_reaction("Reposts: " + std::to_string(post_num_reblogs), nullptr);
+ post_body_item->add_reaction("👍: " + std::to_string(post_num_favourites), nullptr);
+
+ results.push_back(std::move(post_body_item));
+ }
+
+ return PluginResult::OK;
+ }
+
+ PluginResult PleromaHomePage::lazy_fetch(BodyItems &result_items) {
+ PluginResult result = pleroma->get_home_posts(result_items);
+ if(result == PluginResult::OK && !result_items.empty())
+ last_item_id = result_items.back()->url;
+ return result;
+ }
+
+ PluginResult PleromaHomePage::get_page(const std::string&, int page, BodyItems &result_items) {
+ // TODO: handle search param |arg1|
+ while(current_page < page && !last_item_id.empty()) {
+ PluginResult result = pleroma->get_home_posts(result_items, last_item_id);
+ if(result != PluginResult::OK)
+ return result;
+ ++current_page;
+ }
+ if(!result_items.empty())
+ last_item_id = result_items.back()->url;
+ else
+ last_item_id.clear();
+ return PluginResult::OK;
+ }
+} \ No newline at end of file