#include "routes.h" #include "../servehelper.h" #include "../numberhelper.h" #include "../pixivclient.h" static inline bool is_true(const std::string& str); static inline Element generate_user_link(const httplib::Request& req, const Config& config, const Illust& illust); static inline Element generate_images(const httplib::Request& req, const Config& config, const Illust& illust); static inline Element generate_preview_images(const httplib::Request& req, const Config& config, const Illust& illust); static inline Element generate_illust_metadata(const Illust& illust); void artworks_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client) { uint64_t illust_id = to_ull(req.matches.str(1)); bool preview = is_true(req.get_param_value("preview")); Illust illust; try { illust = pixiv_client.get_illust(illust_id); } catch (const PixivException& e) { if (e.status == 404) { res.status = 404; serve_error(req, res, config, "404: Illust not found", e.what()); } else { res.status = 500; serve_error(req, res, config, "500: Internal server error", "Failed to fetch illust information", e.what()); } return; } catch (const std::exception& e) { res.status = 500; serve_error(req, res, config, "500: Internal server error", "Failed to fetch illust information", e.what()); return; } Element body("body", { Element("h2", {illust.title}), generate_user_link(req, config, illust), !preview ? generate_images(req, config, illust) : generate_preview_images(req, config, illust), Element("br"), generate_illust_metadata(illust) }); serve(req, res, config, std::move(illust.title), std::move(body)); } static inline Element generate_user_link(const httplib::Request& req, const Config& config, const Illust& illust) { std::string profile_picture = proxy_image_url(config, illust.user_profile_pictures.thumbnail_or_original()); std::string user_link = get_origin(req, config) + "/users/" + std::to_string(illust.user_id); return Element("a", {{"class", "usermetadata"}, {"href", std::move(user_link)}}, { Element("img", {{"class", "smallprofilepicture"}, {"loading", "lazy"}, {"src", std::move(profile_picture)}}, {}), Element("b", {illust.user_display_name}) }); } static inline Element generate_images(const httplib::Request& req, const Config& config, const Illust& illust) { using namespace std::string_literals; Element div("div", {{"class", "illust"}}, {}); bool show_pages = illust.images.size() > 1; div.nodes.reserve(show_pages ? illust.images.size() * 2 : illust.images.size()); for (size_t i = 0; i < illust.images.size(); i++) { const Images& images = illust.images[i]; std::string thumbnail = proxy_image_url(config, images.thumbnail_or_original()); std::string original = proxy_image_url(config, images.original_or_thumbnail()); if (show_pages) { std::string id = std::to_string(i + 1); div.nodes.push_back(Element("a", {{"class", "landmark"}, {"id", id}, {"href", "#"s + id}}, {id, "/", std::to_string(illust.images.size())})); } div.nodes.push_back(Element("a", {{"href", std::move(original)}}, { Element("img", {{"loading", "lazy"}, {"src", std::move(thumbnail)}}, {}) })); } return div; } static inline Element generate_preview_images(const httplib::Request& req, const Config& config, const Illust& illust) { Element div("div", {{"class", "grid"}}, {}); div.nodes.reserve(illust.images.size()); for (size_t i = 0; i < illust.images.size(); i++) { const Images& images = illust.images[i]; std::string thumbnail = proxy_image_url(config, images.thumbnail_or_original(1)); std::string link = get_origin(req, config) + "/artworks/" + std::to_string(illust.illust_id) + "#" + std::to_string(i + 1); div.nodes.push_back(Element("a", {{"href", std::move(link)}}, { Element("img", {{"loading", "lazy"}, {"src", std::move(thumbnail)}}, {}) })); } return div; } static inline Element generate_illust_metadata(const Illust& illust) { Element div("div", {{"class", "illustmetadata"}}, {}); if (illust.ai_generated) { div.nodes.push_back(Element("b", {"AI-Generated "})); } div.nodes.reserve(div.nodes.size() + illust.tags.size()); for (const Tag& i : illust.tags) { std::string tag = [&]() { if (i.english) return *i.english; if (i.romaji) return *i.romaji; return i.japanese; }(); div.nodes.push_back(Element("span", {"#", std::move(tag)})); } return div; } static inline bool is_true(const std::string& str) { return !str.empty() && str != "0" && str != "false" && str != "no"; }