pixwhile/routes/users/illustrations.cpp

114 lines
4.3 KiB
C++
Raw Normal View History

2023-04-07 15:06:31 +00:00
#include <utility>
#include "../routes.h"
#include "../../servehelper.h"
#include "../../pixivclient.h"
#include "common.h"
static inline uint64_t to_ull(const std::string& str);
static Element generate_pager(size_t page, size_t items, size_t items_per_page);
static inline Element generate_content(const std::vector<uint64_t>& illust_ids, size_t page, size_t items_per_page);
static inline size_t page_count(size_t items, size_t items_per_page);
static inline std::pair<size_t, size_t> page_to_offsets(size_t page, size_t items, size_t items_per_page);
void user_illustrations_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client) {
uint64_t user_id = to_ull(req.matches[1].str());
uint64_t page = req.has_param("p") ? to_ull(req.get_param_value("p")) - 1 : 0;
User user;
std::vector<uint64_t> illust_ids;
try {
user = pixiv_client.get_user(user_id);
illust_ids = pixiv_client.get_illusts(user_id);
} catch (const PixivException& e) {
if (e.status == 404) {
res.status = 404;
serve_error(req, res, config, "404: User not found", e.what());
} else {
res.status = 500;
serve_error(req, res, config, "500: Internal server error", "Failed to fetch user information", e.what());
}
return;
} catch (const std::exception& e) {
res.status = 500;
serve_error(req, res, config, "500: Internal server error", "Failed to fetch user information", e.what());
return;
}
const constexpr size_t items_per_page = 18; // on pixiv touch
Element body("body", {
generate_user_header(std::move(user), config),
generate_pager(page, illust_ids.size(), items_per_page),
Element("br"),
generate_content(std::move(illust_ids), page, items_per_page),
generate_pager(page, illust_ids.size(), items_per_page)
});
(void)page_to_offsets;
serve(req, res, config, user.display_name + " illustrations", std::move(body));
}
static inline uint64_t to_ull(const std::string& str) {
char* endptr;
errno = 0;
uint64_t res = strtoull(str.c_str(), &endptr, 10);
if (res == ULLONG_MAX && errno == ERANGE) {
throw std::overflow_error(str + " is too big");
} else if (endptr[0] != '\0') {
throw std::invalid_argument(str + " contains trailing text or is not an integer");
}
return res;
}
static Element generate_pager(size_t page, size_t items, size_t items_per_page) {
using namespace std::string_literals;
size_t total_pages = page_count(items, items_per_page);
auto link = [](std::string href, const char* text, bool add_link) {
Element b("b");
if (add_link) {
b.nodes.push_back(Element("a", {{"href", std::move(href)}}, {text}));
} else {
b.nodes.push_back(text);
}
return b;
};
return Element("div", {{"class", "center"}}, {
link("?p=1", "First", page != 0), " ",
link("?p="s + std::to_string(page), "Prev", page != 0), " ",
std::to_string(page + 1), "/", std::to_string(total_pages), " ",
link("?p="s + std::to_string(page + 2), "Next", page + 1 < total_pages), " ",
link("?p="s + std::to_string(total_pages), "Last", page + 1 < total_pages)
});
}
static inline Element generate_content(const std::vector<uint64_t>& illust_ids, size_t page, size_t items_per_page) {
// TODO be real
Element ul("ul");
std::pair<size_t, size_t> illust_ids_offsets = page_to_offsets(page, illust_ids.size(), items_per_page);
ul.nodes.reserve(items_per_page);
for (size_t i = illust_ids_offsets.first; i < illust_ids_offsets.second; i++) {
ul.nodes.push_back(Element("li", {
std::to_string(illust_ids[i])
}));
}
return ul;
}
static inline size_t page_count(size_t items, size_t items_per_page) {
size_t ret = items / items_per_page;
if (items % items_per_page != 0) {
ret++;
}
return ret;
}
static inline std::pair<size_t, size_t> page_to_offsets(size_t page, size_t items, size_t items_per_page) {
size_t start_offset = page * items_per_page;
size_t end_offset = start_offset + items_per_page;
return {items > start_offset ? start_offset : items, items > end_offset ? end_offset : items};
}