#include #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& 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 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 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& illust_ids, size_t page, size_t items_per_page) { // TODO be real Element ul("ul"); std::pair 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 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}; }