Cover Finder (#216)

Adds functionality to search and add game cover images automatically.

Co-authored-by: Conn O'Griofa <connogriofa@gmail.com>
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
This commit is contained in:
Mariotaku 2022-11-19 01:07:22 +09:00 committed by GitHub
commit 01b8ba353a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 314 additions and 12 deletions

View file

@ -13,6 +13,8 @@
#include <boost/asio/ssl/context.hpp>
#include <boost/filesystem.hpp>
#include <Simple-Web-Server/crypto.hpp>
#include <Simple-Web-Server/server_https.hpp>
#include <boost/asio/ssl/context_base.hpp>
@ -164,9 +166,12 @@ void getAppsPage(resp_https_t response, req_https_t request) {
print_req(request);
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Access-Control-Allow-Origin", "https://images.igdb.com/");
std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "apps.html");
response->write(header + content);
response->write(header + content, headers);
}
void getClientsPage(resp_https_t response, req_https_t request) {
@ -411,6 +416,67 @@ void deleteApp(resp_https_t response, req_https_t request) {
proc::refresh(config::stream.file_apps);
}
void uploadCover(resp_https_t response, req_https_t request) {
if(!authenticate(response, request)) return;
std::stringstream ss;
std::stringstream configStream;
ss << request->content.rdbuf();
pt::ptree outputTree;
auto g = util::fail_guard([&]() {
std::ostringstream data;
SimpleWeb::StatusCode code = SimpleWeb::StatusCode::success_ok;
if(outputTree.get_child_optional("error").has_value()) {
code = SimpleWeb::StatusCode::client_error_bad_request;
}
pt::write_json(data, outputTree);
response->write(code, data.str());
});
pt::ptree inputTree;
try {
pt::read_json(ss, inputTree);
}
catch(std::exception &e) {
BOOST_LOG(warning) << "UploadCover: "sv << e.what();
outputTree.put("status", "false");
outputTree.put("error", e.what());
return;
}
auto key = inputTree.get("key", "");
if(key.empty()) {
outputTree.put("error", "Cover key is required");
return;
}
auto url = inputTree.get("url", "");
const std::string coverdir = platf::appdata().string() + "/covers/";
if(!boost::filesystem::exists(coverdir)) {
boost::filesystem::create_directory(coverdir);
}
std::basic_string path = coverdir + http::url_escape(key) + ".png";
if(!url.empty()) {
if(http::url_get_host(url) != "images.igdb.com") {
outputTree.put("error", "Only images.igdb.com is allowed");
return;
}
if(!http::download_file(url, path)) {
outputTree.put("error", "Failed to download cover");
return;
}
}
else {
auto data = SimpleWeb::Crypto::Base64::decode(inputTree.get<std::string>("data"));
std::ofstream imgfile(path);
imgfile.write(data.data(), (int)data.size());
}
outputTree.put("path", path);
}
void getConfig(resp_https_t response, req_https_t request) {
if(!authenticate(response, request)) return;
@ -616,6 +682,7 @@ void start() {
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
server.resource["^/api/clients/unpair$"]["POST"] = unpairAll;
server.resource["^/api/apps/close"]["POST"] = closeApp;
server.resource["^/api/covers/upload$"]["POST"] = uploadCover;
server.resource["^/images/favicon.ico$"]["GET"] = getFaviconImage;
server.resource["^/images/logo-sunshine-45.png$"]["GET"] = getSunshineLogoImage;
server.resource["^/third_party/bootstrap.min.css$"]["GET"] = getBootstrapCss;