Guess the size of thumbnails

This commit is contained in:
blankie 2023-05-08 00:22:48 +07:00
parent b0b8e5c3c9
commit 421bbcd6a0
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
5 changed files with 84 additions and 33 deletions

View File

@ -11,9 +11,10 @@ static inline std::optional<std::string> get_original_profile_picture(blankie::m
static inline std::optional<std::string> get_360x360_illust_thumbnail(blankie::murl::Url url);
static Images get_profile_pictures(const nlohmann::json& j);
static Images get_profile_pictures(const std::string& url);
static Images get_illust_image(const nlohmann::json& j);
static std::optional<std::pair<uint64_t, uint64_t>> get_thumbnail_size(blankie::murl::Url thumbnail_url, std::optional<std::pair<uint64_t, uint64_t>> original_size);
static Images get_illust_images(const nlohmann::json& image, std::optional<nlohmann::json> image_metadata);
const std::string& Images::original_or_thumbnail() const {
const Image& Images::original_or_thumbnail() const {
if (this->original) {
return *this->original;
}
@ -23,7 +24,7 @@ const std::string& Images::original_or_thumbnail() const {
throw std::runtime_error("Images does not contain any images");
}
const std::string& Images::thumbnail_or_original(size_t back) const {
const Image& Images::thumbnail_or_original(size_t back) const {
if (this->thumbnails.size() > back) {
return this->thumbnails[this->thumbnails.size() - back - 1];
}
@ -91,6 +92,7 @@ void from_json(const nlohmann::json& j, Illust& illust) {
bool full_data = j.contains("illust_details");
const nlohmann::json& author_details = j.at("author_details");
const nlohmann::json& illust_details = full_data ? j.at("illust_details") : j;
const nlohmann::json& images_metadata = illust_details.at("illust_images");
author_details.at("user_account").get_to(illust.username);
author_details.at("user_name").get_to(illust.user_display_name);
@ -114,11 +116,12 @@ void from_json(const nlohmann::json& j, Illust& illust) {
if (illust_details.contains("manga_a")) {
const nlohmann::json& manga_a = illust_details["manga_a"];
illust.images.reserve(manga_a.size());
for (auto &[_, i] : manga_a.items()) {
illust.images.push_back(get_illust_image(i));
for (size_t i = 0; i < manga_a.size(); i++) {
illust.images.push_back(get_illust_images(manga_a[i], images_metadata.at(i)));
}
} else {
illust.images = {get_illust_image(illust_details)};
illust.images = {get_illust_images(illust_details, images_metadata.at(0))};
}
illust.page_count = to_ull(illust_details.at("page_count").get_ref<const nlohmann::json::string_t&>());
}
@ -168,7 +171,7 @@ void from_json(const nlohmann::json& j, SearchResults& search_results) {
.comment = std::nullopt,
.tags = std::move(tags),
.images = {get_illust_image(i)},
.images = {get_illust_images(i, std::nullopt)},
.page_count = i.at("pageCount").get<size_t>()
};
search_results.illusts.illusts.push_back(illust);
@ -247,7 +250,7 @@ static Images get_profile_pictures(const nlohmann::json& j) {
images.thumbnails.push_back(j["main_s"].get<std::string>());
}
images.thumbnails.push_back(j.at("main").get<std::string>());
images.original = get_original_profile_picture(images.thumbnails.back());
images.original = get_original_profile_picture(images.thumbnails.back().url);
return images;
}
@ -274,16 +277,50 @@ static inline std::optional<std::string> get_360x360_illust_thumbnail(blankie::m
return url.to_string();
}
static Images get_illust_image(const nlohmann::json& j) {
static std::regex illust_size_regex(
"/c/(\\d+)x(\\d+)[/_].+"
);
static std::optional<std::pair<uint64_t, uint64_t>> get_thumbnail_size(blankie::murl::Url thumbnail_url, std::optional<std::pair<uint64_t, uint64_t>> original_size) {
if (!original_size) {
return std::nullopt;
}
std::smatch sm;
if (!std::regex_match(thumbnail_url.path, sm, illust_size_regex)) {
return std::nullopt;
}
uint64_t thumbnail_width = to_ull(sm.str(1));
// uint64_t thumbnail_height = to_ull(sm.str(2));
std::pair<uint64_t, uint64_t> real_thumbnail_size = {
thumbnail_width,
// derived from original_size->second / (original_size->first / thumbnail_width)
// to make it more accurate without using floats
original_size->second * thumbnail_width / original_size->first
};
return real_thumbnail_size;
}
static Images get_illust_images(const nlohmann::json& image, std::optional<nlohmann::json> image_metadata) {
Images images;
ssize_t add_360x360_to = -1;
std::optional<std::pair<uint64_t, uint64_t>> original_size;
if (image_metadata) {
original_size = {
to_ull(image_metadata->at("illust_image_width").get_ref<const nlohmann::json::string_t&>()),
to_ull(image_metadata->at("illust_image_height").get_ref<const nlohmann::json::string_t&>())
};
}
auto add_if_exists = [&](const char* key) {
if (j.contains(key) && j[key].is_string()) {
images.thumbnails.push_back(j[key].get<std::string>());
return true;
if (!image.contains(key) || !image[key].is_string()) {
return false;
}
return false;
std::string url = image[key].get<std::string>();
images.thumbnails.push_back({url, get_thumbnail_size(url, original_size)});
return true;
};
add_if_exists("url_ss");
add_if_exists("url_placeholder");
@ -292,14 +329,14 @@ static Images get_illust_image(const nlohmann::json& j) {
add_360x360_to = static_cast<ssize_t>(images.thumbnails.size());
}
add_if_exists("url");
if (j.contains("url_big") && j["url_big"].is_string()) {
images.original = j["url_big"].get<std::string>();
if (image.contains("url_big") && image["url_big"].is_string()) {
images.original = {image["url_big"].get<std::string>(), original_size};
}
if (add_360x360_to >= 0) {
std::optional<std::string> c_360x360 = get_360x360_illust_thumbnail(images.original_or_thumbnail());
std::optional<std::string> c_360x360 = get_360x360_illust_thumbnail(images.original_or_thumbnail().url);
if (c_360x360) {
images.thumbnails.insert(images.thumbnails.begin() + add_360x360_to, std::move(*c_360x360));
images.thumbnails.insert(images.thumbnails.begin() + add_360x360_to, {*c_360x360, get_thumbnail_size(*c_360x360, original_size)});
}
}

View File

@ -7,12 +7,20 @@
#include <nlohmann/json.hpp>
struct Images {
std::optional<std::string> original;
std::vector<std::string> thumbnails;
struct Image {
std::string url;
std::optional<std::pair<uint64_t, uint64_t>> size;
const std::string& original_or_thumbnail() const;
const std::string& thumbnail_or_original(size_t back = 0) const;
Image(std::string url_) : url(std::move(url_)) {}
Image(std::string url_, std::optional<std::pair<uint64_t, uint64_t>> size_) : url(std::move(url_)), size(std::move(size_)) {}
};
struct Images {
std::optional<Image> original;
std::vector<Image> thumbnails;
const Image& original_or_thumbnail() const;
const Image& thumbnail_or_original(size_t back = 0) const;
};
struct User {

View File

@ -55,7 +55,7 @@ void artworks_route(const httplib::Request& req, httplib::Response& res, const C
}
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 profile_picture = proxy_image_url(config, illust.user_profile_pictures.thumbnail_or_original().url);
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)}}, {
@ -76,15 +76,21 @@ static inline Element generate_images(const httplib::Request& req, const Config&
div.nodes.reserve(div.nodes.size() + (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());
const Image& thumbnail = images.thumbnail_or_original();
const Image& original = 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)}}, {})
Element img("img", {{"loading", "lazy"}, {"src", proxy_image_url(config, thumbnail.url)}}, {});
if (thumbnail.size) {
img.attributes.push_back({"width", std::to_string(thumbnail.size->first)});
img.attributes.push_back({"height", std::to_string(thumbnail.size->second)});
}
div.nodes.push_back(Element("a", {{"href", proxy_image_url(config, original.url)}}, {
std::move(img)
}));
}
@ -102,7 +108,7 @@ static inline Element generate_preview_images(const httplib::Request& req, const
grid.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 thumbnail = proxy_image_url(config, images.thumbnail_or_original(1).url);
std::string link = no_preview_link + '#' + std::to_string(i + 1);
grid.nodes.push_back(Element("a", {{"href", std::move(link)}}, {

View File

@ -8,15 +8,15 @@ static inline Element generate_user_links(const User& user);
Element generate_user_header(const User& user, const Config& config) {
Element header("header");
if (user.cover_images) {
std::string cover_original = proxy_image_url(config, user.cover_images->original_or_thumbnail());
std::string cover_thumbnail = proxy_image_url(config, user.cover_images->thumbnail_or_original());
std::string cover_original = proxy_image_url(config, user.cover_images->original_or_thumbnail().url);
std::string cover_thumbnail = proxy_image_url(config, user.cover_images->thumbnail_or_original().url);
header.nodes.push_back(Element("a", {{"href", std::move(cover_original)}}, {
Element("img", {{"class", "profilecover"}, {"loading", "lazy"}, {"src", std::move(cover_thumbnail)}}, {})
}));
}
std::string profile_picture_original = proxy_image_url(config, user.profile_pictures.original_or_thumbnail());
std::string profile_picture_thumbnail = proxy_image_url(config, user.profile_pictures.thumbnail_or_original());
std::string profile_picture_original = proxy_image_url(config, user.profile_pictures.original_or_thumbnail().url);
std::string profile_picture_thumbnail = proxy_image_url(config, user.profile_pictures.thumbnail_or_original().url);
header.nodes.push_back(Element("div", {{"class", "usermetadata"}}, {
Element("a", {{"href", std::move(profile_picture_original)}}, {
Element("img", {{"class", "profilepicture"}, {"loading", "lazy"}, {"src", std::move(profile_picture_thumbnail)}}, {})

View File

@ -147,7 +147,7 @@ static inline Element generate_illusts_grid(const httplib::Request& req, const C
static inline Element generate_illusts_grid_item(const httplib::Request& req, const Config& config, const Illust& illust) {
std::string illust_url = get_origin(req, config) + "/artworks/" + std::to_string(illust.illust_id);
std::string image_url = proxy_image_url(config, illust.images[0].thumbnail_or_original(1));
std::string image_url = proxy_image_url(config, illust.images[0].thumbnail_or_original(1).url);
Element div("div", {{"class", "illustsgriditem"}}, {
Element("a", {{"href", illust_url}}, {