Fix fetching original illust images
This commit is contained in:
parent
7c772b924c
commit
773f75543e
20
main.cpp
20
main.cpp
|
@ -72,6 +72,26 @@ int main(int argc, char** argv) {
|
||||||
serve_redirect(req, res, config, get_origin(req, config) + "/tags/" + blankie::murl::escape(std::move(q)));
|
serve_redirect(req, res, config, get_origin(req, config) + "/tags/" + blankie::murl::escape(std::move(q)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.Get("/guess_extension/i.pximg.net(/.+)", [&](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
// rip query parameters, but they're not important anyway
|
||||||
|
std::string path = req.matches.str(1);
|
||||||
|
auto serve_extension = [&](const char* extension) {
|
||||||
|
if (!pixiv_client.i_pximg_url_valid(path + '.' + extension)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
serve_redirect(req, res, config, proxy_image_url(req, config, "https://i.pximg.net" + path + '.' + extension), true);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (serve_extension("png") || serve_extension("jpg")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.status = 500;
|
||||||
|
serve_error(req, res, config, "500: Internal Server Error", "Failed to guess file extension for https://i.pximg.net"s + path);
|
||||||
|
});
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
server.Get("/debug/exception/known", [](const httplib::Request& req, httplib::Response& res) {
|
server.Get("/debug/exception/known", [](const httplib::Request& req, httplib::Response& res) {
|
||||||
throw std::runtime_error("awoo");
|
throw std::runtime_error("awoo");
|
||||||
|
|
|
@ -10,6 +10,10 @@ PixivClient::PixivClient() {
|
||||||
this->_www_pixiv_net_client.set_default_headers({
|
this->_www_pixiv_net_client.set_default_headers({
|
||||||
{"Cookie", "webp_available=1"}
|
{"Cookie", "webp_available=1"}
|
||||||
});
|
});
|
||||||
|
this->_i_pximg_net_client.set_keep_alive(true);
|
||||||
|
this->_i_pximg_net_client.set_default_headers({
|
||||||
|
{"Referer", "https://www.pixiv.net/"}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
User PixivClient::get_user(uint64_t user_id) {
|
User PixivClient::get_user(uint64_t user_id) {
|
||||||
|
@ -83,3 +87,11 @@ nlohmann::json PixivClient::_handle_result(httplib::Result res) {
|
||||||
}
|
}
|
||||||
return j.at("body");
|
return j.at("body");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PixivClient::i_pximg_url_valid(const std::string& path) {
|
||||||
|
httplib::Result res = this->_i_pximg_net_client.Head(path, {{"User-Agent", touch_user_agent}});
|
||||||
|
if (!res) {
|
||||||
|
throw HTTPLibException(res.error());
|
||||||
|
}
|
||||||
|
return res->status >= 200 && res->status <= 200;
|
||||||
|
}
|
||||||
|
|
|
@ -17,9 +17,12 @@ public:
|
||||||
SearchResults search_illusts(const std::string& query, size_t page, const std::string& order);
|
SearchResults search_illusts(const std::string& query, size_t page, const std::string& order);
|
||||||
std::vector<SearchSuggestion> get_search_suggestions(const std::string& query);
|
std::vector<SearchSuggestion> get_search_suggestions(const std::string& query);
|
||||||
|
|
||||||
|
bool i_pximg_url_valid(const std::string& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nlohmann::json _handle_result(httplib::Result res);
|
nlohmann::json _handle_result(httplib::Result res);
|
||||||
httplib::Client _www_pixiv_net_client{"https://www.pixiv.net"};
|
httplib::Client _www_pixiv_net_client{"https://www.pixiv.net"};
|
||||||
|
httplib::Client _i_pximg_net_client{"https://i.pximg.net"};
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPLibException : public std::exception {
|
class HTTPLibException : public std::exception {
|
||||||
|
|
|
@ -9,6 +9,7 @@ static inline std::optional<std::string> get_1920x960_cover_image(blankie::murl:
|
||||||
static inline std::optional<std::string> get_original_cover_image(blankie::murl::Url url, const nlohmann::json& cover_image);
|
static inline std::optional<std::string> get_original_cover_image(blankie::murl::Url url, const nlohmann::json& cover_image);
|
||||||
static inline std::optional<std::string> get_original_profile_picture(blankie::murl::Url url);
|
static inline std::optional<std::string> get_original_profile_picture(blankie::murl::Url url);
|
||||||
static inline std::optional<std::string> get_360x360_illust_thumbnail(blankie::murl::Url url);
|
static inline std::optional<std::string> get_360x360_illust_thumbnail(blankie::murl::Url url);
|
||||||
|
static inline std::optional<std::string> get_original_illust_image(blankie::murl::Url url);
|
||||||
static Images get_profile_pictures(const nlohmann::json& j);
|
static Images get_profile_pictures(const nlohmann::json& j);
|
||||||
static Images get_profile_pictures(const std::string& url);
|
static Images get_profile_pictures(const std::string& url);
|
||||||
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 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);
|
||||||
|
@ -286,6 +287,19 @@ static inline std::optional<std::string> get_360x360_illust_thumbnail(blankie::m
|
||||||
return url.to_string();
|
return url.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::regex illust_original_image_path_regex("/c/.+?/(img/.+)(?:_master1200|square1200)\\.\\w{3,4}");
|
||||||
|
static inline std::optional<std::string> get_original_illust_image(blankie::murl::Url url) {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
std::smatch sm;
|
||||||
|
if (!std::regex_match(url.path, sm, illust_original_image_path_regex)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
url.path = "/img-original/"s + sm.str(1);
|
||||||
|
url.fragment = "guess_extension";
|
||||||
|
return url.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
static std::regex illust_size_regex(
|
static std::regex illust_size_regex(
|
||||||
"/c/(\\d+)x(\\d+)[/_].+"
|
"/c/(\\d+)x(\\d+)[/_].+"
|
||||||
);
|
);
|
||||||
|
@ -340,6 +354,11 @@ static Images get_illust_images(const nlohmann::json& image, std::optional<nlohm
|
||||||
add_if_exists("url");
|
add_if_exists("url");
|
||||||
if (image.contains("url_big") && image["url_big"].is_string()) {
|
if (image.contains("url_big") && image["url_big"].is_string()) {
|
||||||
images.original = {image["url_big"].get<std::string>(), original_size};
|
images.original = {image["url_big"].get<std::string>(), original_size};
|
||||||
|
} else {
|
||||||
|
std::optional<std::string> original_url = get_original_illust_image(images.thumbnail_or_original().url);
|
||||||
|
if (original_url) {
|
||||||
|
images.original = {std::move(*original_url), original_size};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_360x360_to >= 0) {
|
if (add_360x360_to >= 0) {
|
||||||
|
|
|
@ -57,7 +57,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) {
|
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().url);
|
std::string profile_picture = proxy_image_url(req, config, illust.user_profile_pictures.thumbnail_or_original().url);
|
||||||
std::string user_link = get_origin(req, config) + "/users/" + std::to_string(illust.user_id);
|
std::string user_link = get_origin(req, config) + "/users/" + std::to_string(illust.user_id);
|
||||||
|
|
||||||
return Element("a", {{"class", "user_metadata"}, {"href", std::move(user_link)}}, {
|
return Element("a", {{"class", "user_metadata"}, {"href", std::move(user_link)}}, {
|
||||||
|
@ -86,12 +86,12 @@ static inline Element generate_images(const httplib::Request& req, const Config&
|
||||||
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", {{"class", "landmark"}, {"id", id}, {"href", "#"s + id}}, {id, "/", std::to_string(illust.images.size())}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Element img("img", {{"loading", "lazy"}, {"src", proxy_image_url(config, thumbnail.url)}}, {});
|
Element img("img", {{"loading", "lazy"}, {"src", proxy_image_url(req, config, thumbnail.url)}}, {});
|
||||||
if (thumbnail.size) {
|
if (thumbnail.size) {
|
||||||
img.attributes.push_back({"width", std::to_string(thumbnail.size->first)});
|
img.attributes.push_back({"width", std::to_string(thumbnail.size->first)});
|
||||||
img.attributes.push_back({"height", std::to_string(thumbnail.size->second)});
|
img.attributes.push_back({"height", std::to_string(thumbnail.size->second)});
|
||||||
}
|
}
|
||||||
div.nodes.push_back(Element("a", {{"href", proxy_image_url(config, original.url)}}, {
|
div.nodes.push_back(Element("a", {{"href", proxy_image_url(req, config, original.url)}}, {
|
||||||
std::move(img)
|
std::move(img)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ static inline Element generate_preview_images(const httplib::Request& req, const
|
||||||
grid.nodes.reserve(illust.images.size());
|
grid.nodes.reserve(illust.images.size());
|
||||||
for (size_t i = 0; i < illust.images.size(); i++) {
|
for (size_t i = 0; i < illust.images.size(); i++) {
|
||||||
const Images& images = illust.images[i];
|
const Images& images = illust.images[i];
|
||||||
std::string thumbnail = proxy_image_url(config, images.thumbnail_or_original(1).url);
|
std::string thumbnail = proxy_image_url(req, config, images.thumbnail_or_original(1).url);
|
||||||
std::string link = no_preview_link + '#' + std::to_string(i + 1);
|
std::string link = no_preview_link + '#' + std::to_string(i + 1);
|
||||||
|
|
||||||
grid.nodes.push_back(Element("a", {{"href", std::move(link)}}, {
|
grid.nodes.push_back(Element("a", {{"href", std::move(link)}}, {
|
||||||
|
@ -247,7 +247,7 @@ static inline Nodes generate_ogp_nodes(const httplib::Request& req, const Config
|
||||||
nodes.reserve(nodes.size() + illust.images.size() * 3);
|
nodes.reserve(nodes.size() + illust.images.size() * 3);
|
||||||
for (const Images& images : illust.images) {
|
for (const Images& images : illust.images) {
|
||||||
const Image& image = images.thumbnail_or_original();
|
const Image& image = images.thumbnail_or_original();
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(config, image.url)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(req, config, image.url)}}, {}));
|
||||||
if (image.size) {
|
if (image.size) {
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image:width"}, {"content", std::to_string(image.size->first)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image:width"}, {"content", std::to_string(image.size->first)}}, {}));
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image:height"}, {"content", std::to_string(image.size->second)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image:height"}, {"content", std::to_string(image.size->second)}}, {}));
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
|
|
||||||
static inline Element generate_user_links(const User& user);
|
static inline Element generate_user_links(const User& user);
|
||||||
|
|
||||||
Element generate_user_header(const User& user, const Config& config) {
|
Element generate_user_header(const User& user, const httplib::Request& req, const Config& config) {
|
||||||
Element header("header");
|
Element header("header");
|
||||||
if (user.cover_images) {
|
if (user.cover_images) {
|
||||||
std::string cover_original = proxy_image_url(config, user.cover_images->original_or_thumbnail().url);
|
std::string cover_original = proxy_image_url(req, config, user.cover_images->original_or_thumbnail().url);
|
||||||
std::string cover_thumbnail = proxy_image_url(config, user.cover_images->thumbnail_or_original().url);
|
std::string cover_thumbnail = proxy_image_url(req, config, user.cover_images->thumbnail_or_original().url);
|
||||||
header.nodes.push_back(Element("a", {{"href", std::move(cover_original)}}, {
|
header.nodes.push_back(Element("a", {{"href", std::move(cover_original)}}, {
|
||||||
Element("img", {{"class", "user-cover"}, {"loading", "lazy"}, {"src", std::move(cover_thumbnail)}}, {})
|
Element("img", {{"class", "user-cover"}, {"loading", "lazy"}, {"src", std::move(cover_thumbnail)}}, {})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string profile_picture_original = proxy_image_url(config, user.profile_pictures.original_or_thumbnail().url);
|
std::string profile_picture_original = proxy_image_url(req, config, user.profile_pictures.original_or_thumbnail().url);
|
||||||
std::string profile_picture_thumbnail = proxy_image_url(config, user.profile_pictures.thumbnail_or_original().url);
|
std::string profile_picture_thumbnail = proxy_image_url(req, config, user.profile_pictures.thumbnail_or_original().url);
|
||||||
header.nodes.push_back(Element("div", {{"class", "user_metadata"}}, {
|
header.nodes.push_back(Element("div", {{"class", "user_metadata"}}, {
|
||||||
Element("a", {{"href", std::move(profile_picture_original)}}, {
|
Element("a", {{"href", std::move(profile_picture_original)}}, {
|
||||||
Element("img", {{"class", "user_profile_picture"}, {"loading", "lazy"}, {"src", std::move(profile_picture_thumbnail)}}, {})
|
Element("img", {{"class", "user_profile_picture"}, {"loading", "lazy"}, {"src", std::move(profile_picture_thumbnail)}}, {})
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <httplib/httplib.h>
|
||||||
#include "../../blankie/serializer.h"
|
#include "../../blankie/serializer.h"
|
||||||
struct User; // forward declaration from ../../pixivmodels.h
|
struct User; // forward declaration from ../../pixivmodels.h
|
||||||
struct Config; // forward declaration from ../../config.h
|
struct Config; // forward declaration from ../../config.h
|
||||||
|
|
||||||
using Element = blankie::html::Element;
|
using Element = blankie::html::Element;
|
||||||
|
|
||||||
Element generate_user_header(const User& user, const Config& config);
|
Element generate_user_header(const User& user, const httplib::Request& req, const Config& config);
|
||||||
|
|
|
@ -33,7 +33,7 @@ void user_illustrations_route(const httplib::Request& req, httplib::Response& re
|
||||||
}
|
}
|
||||||
|
|
||||||
Element body("body", {
|
Element body("body", {
|
||||||
generate_user_header(std::move(user), config),
|
generate_user_header(std::move(user), req, config),
|
||||||
generate_illusts_pager(req, config, illusts, page, "illusts")
|
generate_illusts_pager(req, config, illusts, page, "illusts")
|
||||||
});
|
});
|
||||||
serve(req, res, config, user.display_name + "'s illustrations", std::move(body), generate_ogp_nodes(req, config, user, page));
|
serve(req, res, config, user.display_name + "'s illustrations", std::move(body), generate_ogp_nodes(req, config, user, page));
|
||||||
|
@ -53,10 +53,10 @@ static inline Nodes generate_ogp_nodes(const httplib::Request& req, const Config
|
||||||
Element("meta", {{"property", "og:url"}, {"content", std::move(url)}}, {})
|
Element("meta", {{"property", "og:url"}, {"content", std::move(url)}}, {})
|
||||||
});
|
});
|
||||||
if (user.ogp_image) {
|
if (user.ogp_image) {
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(config, *user.ogp_image)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(req, config, *user.ogp_image)}}, {}));
|
||||||
} else {
|
} else {
|
||||||
const Image& image = user.profile_pictures.thumbnail_or_original();
|
const Image& image = user.profile_pictures.thumbnail_or_original();
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(config, image.url)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image"}, {"content", proxy_image_url(req, config, image.url)}}, {}));
|
||||||
if (image.size) {
|
if (image.size) {
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image:width"}, {"content", std::to_string(image.size->first)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image:width"}, {"content", std::to_string(image.size->first)}}, {}));
|
||||||
nodes.push_back(Element("meta", {{"property", "og:image:height"}, {"content", std::to_string(image.size->second)}}, {}));
|
nodes.push_back(Element("meta", {{"property", "og:image:height"}, {"content", std::to_string(image.size->second)}}, {}));
|
||||||
|
|
|
@ -64,7 +64,7 @@ void serve_error(const httplib::Request& req, httplib::Response& res, const Conf
|
||||||
serve(req, res, config, std::move(title), std::move(body));
|
serve(req, res, config, std::move(title), std::move(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
void serve_redirect(const httplib::Request& req, httplib::Response& res, const Config& config, std::string url) {
|
void serve_redirect(const httplib::Request& req, httplib::Response& res, const Config& config, std::string url, bool permanent) {
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
Element body("body", {
|
Element body("body", {
|
||||||
|
@ -72,7 +72,7 @@ void serve_redirect(const httplib::Request& req, httplib::Response& res, const C
|
||||||
Element("a", {{"href", url}}, {url}),
|
Element("a", {{"href", url}}, {url}),
|
||||||
"…"
|
"…"
|
||||||
});
|
});
|
||||||
res.set_redirect(url);
|
res.set_redirect(url, permanent ? 301 : 302);
|
||||||
serve(req, res, config, "Redirecting to "s + std::move(url) + "…", std::move(body));
|
serve(req, res, config, "Redirecting to "s + std::move(url) + "…", std::move(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +111,13 @@ std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url) {
|
||||||
return base.to_string();
|
return base.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string proxy_image_url(const Config& config, blankie::murl::Url url) {
|
std::string proxy_image_url(const httplib::Request& req, const Config& config, blankie::murl::Url url) {
|
||||||
if (url.is_host_equal("s.pximg.net") || url.is_host_equal("embed.pixiv.net")) {
|
if (!url.is_host_equal("i.pximg.net")) {
|
||||||
return url.to_string();
|
return url.to_string();
|
||||||
}
|
}
|
||||||
return proxy_url(config.image_proxy_url, std::move(url));
|
return url.fragment != "guess_extension"
|
||||||
|
? proxy_url(config.image_proxy_url, std::move(url))
|
||||||
|
: get_origin(req, config) + "/guess_extension/i.pximg.net" + url.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_send_304(const httplib::Request& req, uint64_t hash) {
|
bool should_send_304(const httplib::Request& req, uint64_t hash) {
|
||||||
|
@ -175,7 +177,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) {
|
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 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).url);
|
std::string image_url = proxy_image_url(req, config, illust.images[0].thumbnail_or_original(1).url);
|
||||||
|
|
||||||
Element div("div", {{"class", "illusts_grid-illust"}}, {
|
Element div("div", {{"class", "illusts_grid-illust"}}, {
|
||||||
Element("a", {{"href", illust_url}}, {
|
Element("a", {{"href", illust_url}}, {
|
||||||
|
|
|
@ -15,11 +15,11 @@ using Nodes = std::vector<Node>;
|
||||||
void serve(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, Element element, Nodes extra_head = {});
|
void serve(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, Element element, Nodes extra_head = {});
|
||||||
void serve_error(const httplib::Request& req, httplib::Response& res, const Config& config,
|
void serve_error(const httplib::Request& req, httplib::Response& res, const Config& config,
|
||||||
std::string title, std::optional<std::string> subtitle = std::nullopt, std::optional<std::string> info = std::nullopt);
|
std::string title, std::optional<std::string> subtitle = std::nullopt, std::optional<std::string> info = std::nullopt);
|
||||||
void serve_redirect(const httplib::Request& req, httplib::Response& res, const Config& config, std::string url);
|
void serve_redirect(const httplib::Request& req, httplib::Response& res, const Config& config, std::string url, bool permanent = false);
|
||||||
|
|
||||||
std::string get_origin(const httplib::Request& req, const Config& config);
|
std::string get_origin(const httplib::Request& req, const Config& config);
|
||||||
std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url);
|
std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url);
|
||||||
std::string proxy_image_url(const Config& config, blankie::murl::Url url);
|
std::string proxy_image_url(const httplib::Request& req, const Config& config, blankie::murl::Url url);
|
||||||
bool should_send_304(const httplib::Request& req, uint64_t hash);
|
bool should_send_304(const httplib::Request& req, uint64_t hash);
|
||||||
|
|
||||||
Element generate_illusts_pager(const httplib::Request& req, const Config& config, const Illusts& illusts, size_t page, const char* id);
|
Element generate_illusts_pager(const httplib::Request& req, const Config& config, const Illusts& illusts, size_t page, const char* id);
|
||||||
|
|
Loading…
Reference in New Issue