From dc69c8cac837641d0523bc76db2da0c554b0e161 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Sun, 21 Sep 2025 21:15:36 -0400 Subject: [PATCH 01/19] Quick funny addictions --- build.sh | 35 +++++++++++++++++++++++++++++ src/API.cpp | 63 ++++++++++++++++++++++++++--------------------------- 2 files changed, 66 insertions(+), 32 deletions(-) create mode 100755 build.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..8f09339 --- /dev/null +++ b/build.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +rm Nya.qmod + +echo "Removing oldness" +rm -rf build + +echo "Bulding da dir" +mkdir -p build +cd build + +echo "cmaking it" +cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=/home/dia/android/ndk/27.2.12479018+preview-0/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-24 \ + -DCMAKE_BUILD_TYPE=Release \ + -G Ninja + +echo "Building funnies" +ninja + +echo "Zipping bombing it" +mkdir -p Nya +cp libNya.so Nya +cp ../mod.json Nya +cp ../cover.jpg Nya + +cd Nya + +zip -r Nya.zip * + +mv Nya.zip ../../Nya.qmod + +echo "Done :3" \ No newline at end of file diff --git a/src/API.cpp b/src/API.cpp index d76e214..7c4aba8 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -66,24 +66,24 @@ inline std::map endpoint_data = { {"cosplay", "nsfw/img/cosplay"}, {"cum", "nsfw/img/cum"}, {"feet", "nsfw/img/feet"}, - // {"femdom", "nsfw/img/femdom"}, + {"femdom", "nsfw/img/femdom"}, {"futa", "nsfw/img/futa"}, {"gasm", "nsfw/img/gasm"}, {"holo", "nsfw/img/holo"}, - // {"kitsune", "nsfw/img/kitsune"}, + {"kitsune", "nsfw/img/kitsune"}, {"lewd", "nsfw/img/lewd"}, {"neko", "nsfw/img/neko"}, {"nekopara", "nsfw/img/nekopara"}, - // {"pantsu", "nsfw/img/pantsu"}, + {"pantsu", "nsfw/img/pantsu"}, {"pantyhose", "nsfw/img/pantyhose"}, {"peeing", "nsfw/img/peeing"}, {"petplay", "nsfw/img/petplay"}, {"pussy", "nsfw/img/pussy"}, {"slimes", "nsfw/img/slimes"}, {"solo", "nsfw/img/solo"}, - // {"swimsuit", "nsfw/img/swimsuit"}, - // {"tentacle", "nsfw/img/tentacle"}, - // {"thighs", "nsfw/img/thighs"}, + {"swimsuit", "nsfw/img/swimsuit"}, + {"tentacle", "nsfw/img/tentacle"}, + {"thighs", "nsfw/img/thighs"}, {"trap", "nsfw/img/trap"}, {"yaoi", "nsfw/img/yaoi"}, {"yuri", "nsfw/img/yuri"}, @@ -100,14 +100,14 @@ inline std::map endpoint_data = { {"futa gif", "nsfw/gif/futa"}, {"handjob", "nsfw/gif/handjob"}, {"hentai", "nsfw/gif/hentai"}, - // {"kitsune (not implemented yet)", "nsfw/gif/kitsune"}, + {"kitsune (not implemented yet)", "nsfw/gif/kitsune"}, {"kuni", "nsfw/gif/kuni"}, {"neko gif", "nsfw/gif/neko"}, {"pussy gif", "nsfw/gif/pussy"}, {"wank", "nsfw/gif/wank"}, {"solo gif", "nsfw/gif/solo"}, {"spank", "nsfw/gif/spank"}, - // {"femdom gif", "nsfw/gif/femdom"}, + {"femdom gif", "nsfw/gif/femdom"}, {"tentacle gif", "nsfw/gif/tentacle"}, {"toys", "nsfw/gif/toys"}, {"yuri gif", "nsfw/gif/yuri"}, @@ -147,6 +147,7 @@ inline std::map endpoint_data = { {"wink", "sfw/wink"}, {"poke", "sfw/poke"}, {"dance", "sfw/dance"}, + {"kill", "sfw/kill"}, // screw you I am adding it }, // Not including 'kill' because it's bad { {"neko", "nsfw/neko"}, @@ -157,29 +158,6 @@ inline std::map endpoint_data = { "url" } }, - // {"Anime-Images API", - // { - // "https://anime-api.hisoka17.repl.co/img/", - // DataMode::Json, - // { - // {"hug", "hug"}, - // {"kiss", "kiss"}, - // {"slap", "slap"}, - // {"wink", "wink"}, - // {"pat", "pat"}, - // {"kill", "kill"}, - // {"cuddle", "cuddle"}, - // {"punch", "punch"}, - // {"waifu", "waifu"}, - // }, - // { - // {"hentai", "hentai"}, - // {"boobs", "nsfw/boobs"}, - // {"lesbian", "nsfw/lesbian"}, - // }, - // "url" - // } - // }, {"Bocchi", { "https://boccher.pixelboom.dev/api/", @@ -218,14 +196,35 @@ inline std::map endpoint_data = { {"panda", "panda"}, {"red panda", "red_panda"}, {"bird", "bird"}, + {"birb", "birb"}, {"koala", "koala"}, {"kangaroo", "kangaroo"}, - {"raccoon", "raccoon"} + {"raccoon", "raccoon"}, + {"whale", "whale"}, }, {}, "image" } }, + {"Animu", + { + "https://api.some-random-api.com/animu/", + DataMode::Json, + { + {"nom", "nom"}, + {"poke", "poke"}, + {"cry", "cry"}, + {"kiss", "kiss"}, + {"pat", "pat"}, + {"hug", "hug"}, + {"wink", "wink"}, + {"face-palm", "face-palm"}, + {"quote", "quote"}, + }, + {}, + "link" + } + }, {"Local Files", { "", From 5a6da8c18df9b2c6f139ac39056a988e63822926 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Sun, 21 Sep 2025 22:55:32 -0400 Subject: [PATCH 02/19] small --- src/API.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/API.cpp b/src/API.cpp index 7c4aba8..d91003c 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -15,7 +15,7 @@ inline std::map endpoint_data = { {"azurlane", "sfw/img/azurlane"}, {"chibi", "sfw/img/chibi"}, {"christmas", "sfw/img/christmas"}, - // {"ddlc", "sfw/img/ddlc"}, + {"ddlc", "sfw/img/ddlc"}, {"halloween", "sfw/img/halloween"}, {"holo", "sfw/img/holo"}, {"kitsune", "sfw/img/kitsune"}, From c0c38646454463012352effeb040330de44f7a36 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:45:18 -0400 Subject: [PATCH 03/19] Funnies --- include/API.hpp | 3 ++- src/API.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/ImageView.cpp | 6 ++++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index cc19c08..da214ad 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -11,7 +11,7 @@ struct EndpointCategory { std::string url; }; -enum DataMode { Unsupported, Json, Local, Authenticated }; +enum DataMode { Unsupported, List, Json, Local, Authenticated }; struct SourceData { // SourceData( @@ -37,6 +37,7 @@ std::vector get_source_list(); void get_path_from_json_api(SourceData* source, std::string url, float timeoutInSeconds, + int indexNumber, std::function finished, std::string apiKey = ""); // void NyaAPI::downloadImageFile(); diff --git a/src/API.cpp b/src/API.cpp index d91003c..b61c06b 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -306,6 +306,46 @@ void NyaAPI::get_path_from_json_api( }).detach(); } +void NyaAPI::get_path_from_list_api( + SourceData* source, + std::string url, + float timeoutInSeconds, + int indexNumber, + std::function finished, std::string apiKey +) { + if (finished == nullptr) { + return ERROR("Can't get data async without a callback to use it with"); + } + if (source == nullptr) { + ERROR("Source is null"); + return finished(false, ""); + } + + auto options = WebUtils::URLOptions(url); + options.timeOut = timeoutInSeconds; + if (apiKey != "") { options.headers.emplace("Authorization", apiKey); } + + std::thread([propertyName = source->propertyName, options, finished] { + auto response = WebUtils::Get(options); + + if (!response.IsSuccessful()) return finished(false, ""); + + auto result = response.responseData.has_value(); + if (!result) return finished(false, ""); + + auto& document = response.responseData.value()[indexNumber]; + if(document.HasParseError() || !document.IsObject()) return finished(false, ""); + + auto itr = document.FindMember(propertyName); + if (itr != document.MemberEnd() && itr->value.IsString()) { + std::string url(itr->value.GetString(), itr->value.GetStringLength()); + return finished(true, url); + } else { + return finished(false, ""); + } + }).detach(); +} + /** * @brief Finds the string in a list * diff --git a/src/ImageView.cpp b/src/ImageView.cpp index 8389c6b..f843062 100644 --- a/src/ImageView.cpp +++ b/src/ImageView.cpp @@ -249,7 +249,7 @@ void Nya::ImageView::GetImage(std::function finished = nullp if (!NSFWEnabled) INFO("Endpoint URL: {}", endpointURL); // Get the image url from the api - NyaAPI::get_path_from_json_api(source, endpointURL, 10.0f, [this, finished, NSFWEnabled](bool success, std::string url) { + NyaAPI::get_path_from_list_api(source, endpointURL, 10.0f, 0, [this, finished, NSFWEnabled](bool success, std::string url) { // If we failed to get the image url if (!success) { // Error getting things @@ -321,7 +321,9 @@ void Nya::ImageView::GetImage(std::function finished = nullp }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); - } + } else if (source->Mode == DataMode::List) { + + } } void Nya::ImageView::SetErrorImage() From 6e8620aac7c78726ae4f7d1d4a94a1e53a0d7088 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Mon, 22 Sep 2025 15:53:34 -0400 Subject: [PATCH 04/19] Small fix --- src/ImageView.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/ImageView.cpp b/src/ImageView.cpp index f843062..d14ee9b 100644 --- a/src/ImageView.cpp +++ b/src/ImageView.cpp @@ -249,7 +249,7 @@ void Nya::ImageView::GetImage(std::function finished = nullp if (!NSFWEnabled) INFO("Endpoint URL: {}", endpointURL); // Get the image url from the api - NyaAPI::get_path_from_list_api(source, endpointURL, 10.0f, 0, [this, finished, NSFWEnabled](bool success, std::string url) { + NyaAPI::get_path_from_json_api(source, endpointURL, 10.0f, [this, finished, NSFWEnabled](bool success, std::string url) { // If we failed to get the image url if (!success) { // Error getting things @@ -322,7 +322,121 @@ void Nya::ImageView::GetImage(std::function finished = nullp }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); } else if (source->Mode == DataMode::List) { + // Better way to do this instead of ctrl+c ctrl+v of the first part, probley, will I do that instead, probley not. + // API is authenticated + bool authenticated = source->Mode == DataMode::Authenticated; + + // Construct the url + // TODO: check if endpoint from the setting exists and make it dynamic + + std::string endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, NSFWEnabled); + + // Fallback to sfw if nsfw is enabled and no nsfw endpoint is found + if (endpointValue == "" && NSFWEnabled) { + endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, false); + } + + bool nsfwEmpty = source->NsfwEndpoints.empty(); + bool sfwEmpty = source->SfwEndpoints.empty(); + + // If the endpoint is random, get a random endpoint + if (endpointValue == "random") { + if (NSFWEnabled) { + if (nsfwEmpty) { + auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); + if (endpoint != nullptr) endpointValue = endpoint->url; + } else { + auto endpoint = NyaAPI::getRandomEndpoint(&source->NsfwEndpoints); + if (endpoint != nullptr) endpointValue = endpoint->url; + } + } else { + if (sfwEmpty) { + // DO NOT FALLBACK TO NSFW since it is disabled + endpointValue = ""; + } else { + auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); + if (endpoint != nullptr) endpointValue = endpoint->url; + } + } + } + + std::string endpointURL = source->BaseEndpoint + endpointValue; + + if (!NSFWEnabled) INFO("Endpoint URL: {}", endpointURL); + + // Get the image url from the api + NyaAPI::get_path_from_list_api(source, endpointURL, 10.0f, 0, [this, finished, NSFWEnabled](bool success, std::string url) { + // If we failed to get the image url + if (!success) { + // Error getting things + ERROR("Failed to load image from api"); + + // getLogger().Backtrace(20); + BSML::MainThreadScheduler::Schedule([this, finished]{ + this->SetErrorImage(); + + // Set is loading status + this->isLoading = false; + if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); + + if (finished != nullptr) finished(false); + }); + return; + } + if (!NSFWEnabled) INFO("Image URL: {}", url); + + BSML::MainThreadScheduler::Schedule([this, url, finished, NSFWEnabled]{ + // Make temp file name + std::string fileExtension = FileUtils::GetFileFormat(url); + std::string fileName = Nya::Utils::RandomString(8); + + std::string filePath = NyaGlobals::tempPath + fileName + fileExtension; + std::string fileFullName = fileName + fileExtension; + + Nya::Utils::DownloadFile(url, filePath, [this, finished, url, NSFWEnabled, fileFullName](bool success, std::string path) { + if (!success ) { + this->SetErrorImage(); + + // Set is loading status + this->isLoading = false; + if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); + + if (finished != nullptr) finished(false); + } else { + this->lastImageURL = url; + this->tempName = fileFullName; + this->isNSFW = NSFWEnabled; + + // Check if image view is still valid and if not, don't set the image + if (this->imageView == nullptr || this->imageView->___m_CachedPtr.m_value == nullptr) { + if (finished != nullptr) finished(false); + return; + } + + BSML::Utilities::SetImage(this->imageView, "file://" + path, true, BSML::Utilities::ScaleOptions(), false, [finished, this]() { + // Set is loading status + this->isLoading = false; + if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); + + if (finished != nullptr) finished(true); + }, [finished, this](BSML::Utilities::ImageLoadError error) { + this->SetErrorImage(); + + // Set is loading status + this->isLoading = false; + if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); + + if (finished != nullptr) finished(false); + }); + } + + }); + + }); + + + }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); } } From 42970b80ea003a65a9d1d244afbff9d1f7cd501c Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:56:30 -0400 Subject: [PATCH 05/19] uhhhh --- include/API.hpp | 5 +++++ src/API.cpp | 44 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index da214ad..1462b27 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -35,6 +35,11 @@ struct SourceData { SourceData* get_data_source(std::string name); std::vector get_source_list(); void get_path_from_json_api(SourceData* source, + std::string url, + float timeoutInSeconds, + std::function finished, + std::string apiKey = ""); +void get_path_from_list_api(SourceData* source, std::string url, float timeoutInSeconds, int indexNumber, diff --git a/src/API.cpp b/src/API.cpp index b61c06b..be2ad0d 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -225,6 +225,17 @@ inline std::map endpoint_data = { "link" } }, + {"Nekos API", + { + "https://api.nekosapi.com/v4/images/random?limit=100", + DataMode::List, + { + {"random", ""}, + }, + {}, + "url" + } + }, {"Local Files", { "", @@ -311,30 +322,42 @@ void NyaAPI::get_path_from_list_api( std::string url, float timeoutInSeconds, int indexNumber, - std::function finished, std::string apiKey + std::function finished, + std::string apiKey ) { - if (finished == nullptr) { + if (!finished) { return ERROR("Can't get data async without a callback to use it with"); } - if (source == nullptr) { + if (!source) { ERROR("Source is null"); return finished(false, ""); } auto options = WebUtils::URLOptions(url); options.timeOut = timeoutInSeconds; - if (apiKey != "") { options.headers.emplace("Authorization", apiKey); } + if (!apiKey.empty()) { + options.headers.emplace("Authorization", apiKey); + } - std::thread([propertyName = source->propertyName, options, finished] { + std::thread([propertyName = std::string(source->propertyName), + options, + finished, + indexNumber] { auto response = WebUtils::Get(options); - if (!response.IsSuccessful()) return finished(false, ""); + if (!response.IsSuccessful()) + return finished(false, ""); - auto result = response.responseData.has_value(); - if (!result) return finished(false, ""); + if (!response.responseData.has_value()) + return finished(false, ""); - auto& document = response.responseData.value()[indexNumber]; - if(document.HasParseError() || !document.IsObject()) return finished(false, ""); + auto& arr = response.responseData.value(); + if (indexNumber < 0 || indexNumber >= static_cast(arr.Size())) + return finished(false, ""); + + auto& document = arr[indexNumber]; + if (!document.IsObject()) + return finished(false, ""); auto itr = document.FindMember(propertyName); if (itr != document.MemberEnd() && itr->value.IsString()) { @@ -346,6 +369,7 @@ void NyaAPI::get_path_from_list_api( }).detach(); } + /** * @brief Finds the string in a list * From f3ddf0670fdccda1f71dd7baac9235690a104dfc Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:00:49 -0400 Subject: [PATCH 06/19] FINALLY DID A TIHNG THAT WORKS AHHHHHHHHHHhh --- include/API.hpp | 8 +- src/API.cpp | 202 +++++++++++++++++++++++++++++++--------------- src/ImageView.cpp | 116 -------------------------- 3 files changed, 138 insertions(+), 188 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index 1462b27..cc19c08 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -11,7 +11,7 @@ struct EndpointCategory { std::string url; }; -enum DataMode { Unsupported, List, Json, Local, Authenticated }; +enum DataMode { Unsupported, Json, Local, Authenticated }; struct SourceData { // SourceData( @@ -39,12 +39,6 @@ void get_path_from_json_api(SourceData* source, float timeoutInSeconds, std::function finished, std::string apiKey = ""); -void get_path_from_list_api(SourceData* source, - std::string url, - float timeoutInSeconds, - int indexNumber, - std::function finished, - std::string apiKey = ""); // void NyaAPI::downloadImageFile(); std::map* getEndpoints(); diff --git a/src/API.cpp b/src/API.cpp index be2ad0d..d398c07 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -1,6 +1,9 @@ #include "API.hpp" #include "web-utils/shared/WebUtils.hpp" #include "logging.hpp" +#include +#include +#include using namespace NyaAPI; @@ -225,15 +228,106 @@ inline std::map endpoint_data = { "link" } }, - {"Nekos API", + {"nekosia.cat", { - "https://api.nekosapi.com/v4/images/random?limit=100", - DataMode::List, + "https://api.nekosia.cat/api/v1/images/", + DataMode::Json, { - {"random", ""}, + {"catgirl", "catgirl"}, + {"foxgirl", "foxgirl"}, + {"wolf-girl", "wolf-girl"}, + {"animal-ears", "animal-ears"}, + {"tail", "tail"}, + {"tail-with-ribbon", "tail-with-ribbon"}, + {"tail-from-under-skirt", "tail-from-under-skirt"}, + {"cute", "cute"}, + {"cuteness-is-justice", "cuteness-is-justice"}, + {"blue-archive", "blue-archive"}, + {"girl", "girl"}, + {"young-girl", "young-girl"}, + {"maid", "maid"}, + {"maid-uniform", "maid-uniform"}, + {"vtuber", "vtuber"}, + {"w-sitting", "w-sitting"}, + {"lying-down", "lying-down"}, + {"hands-forming-a-heart", "hands-forming-a-heart"}, + {"wink", "wink"}, + {"valentine", "valentine"}, + {"thigh-high-socks", "thigh-high-socks"}, + {"headphones", "headphones"}, + {"knee-high-socks", "knee-high-socks"}, + {"white-tights", "white-tights"}, + {"black-tights", "black-tights"}, + {"heterochromia", "heterochromia"}, + {"uniform", "uniform"}, + {"sailor-uniform", "sailor-uniform"}, + {"hoodie", "hoodie"}, + {"ribbon", "ribbon"}, + {"white-hair", "white-hair"}, + {"blue-hair", "blue-hair"}, + {"long-hair", "long-hair"}, + {"blonde", "blonde"}, + {"blue-eyes", "blue-eyes"}, + {"purple-eyes", "purple-eyes"} }, {}, - "url" + "image/original/url" + } + }, + {"nekos.best", + { + "https://nekos.best/api/v2/", + DataMode::Json, + { + {"husbando", "husbando"}, + {"kitsune", "kitsune"}, + {"neko", "neko"}, + {"waifu", "waifu"}, + {"angry", "angry"}, + {"baka", "baka"}, + {"bite", "bite"}, + {"blush", "blush"}, + {"bored", "bored"}, + {"cry", "cry"}, + {"cuddle", "cuddle"}, + {"dance", "dance"}, + {"facepalm", "facepalm"}, + {"feed", "feed"}, + {"handhold", "handhold"}, + {"handshake", "handshake"}, + {"happy", "happy"}, + {"highfive", "highfive"}, + {"hug", "hug"}, + {"kick", "kick"}, + {"kiss", "kiss"}, + {"laugh", "laugh"}, + {"lurk", "lurk"}, + {"nod", "nod"}, + {"nom", "nom"}, + {"nope", "nope"}, + {"pat", "pat"}, + {"peck", "peck"}, + {"poke", "poke"}, + {"pout", "pout"}, + {"punch", "punch"}, + {"run", "run"}, + {"shoot", "shoot"}, + {"shrug", "shrug"}, + {"slap", "slap"}, + {"sleep", "sleep"}, + {"smile", "smile"}, + {"smug", "smug"}, + {"stare", "stare"}, + {"think", "think"}, + {"thumbsup", "thumbsup"}, + {"tickle", "tickle"}, + {"wave", "wave"}, + {"wink", "wink"}, + {"yawn", "yawn"}, + {"yeet", "yeet"}, + }, + {}, + "results/0/url" } }, {"Local Files", @@ -278,11 +372,13 @@ std::vector NyaAPI::get_source_list() { * @param finished The function to run when the request is finished * @param apiKey The api key to use (optional) */ + void NyaAPI::get_path_from_json_api( SourceData* source, std::string url, float timeoutInSeconds, - std::function finished, std::string apiKey + std::function finished, + std::string apiKey ) { if (finished == nullptr) { return ERROR("Can't get data async without a callback to use it with"); @@ -294,82 +390,58 @@ void NyaAPI::get_path_from_json_api( auto options = WebUtils::URLOptions(url); options.timeOut = timeoutInSeconds; - if (apiKey != "") { options.headers.emplace("Authorization", apiKey); } + if (!apiKey.empty()) { + options.headers.emplace("Authorization", apiKey); + } std::thread([propertyName = source->propertyName, options, finished] { auto response = WebUtils::Get(options); if (!response.IsSuccessful()) return finished(false, ""); - - auto result = response.responseData.has_value(); - if (!result) return finished(false, ""); + if (!response.responseData.has_value()) return finished(false, ""); auto& document = response.responseData.value(); - if(document.HasParseError() || !document.IsObject()) return finished(false, ""); - - auto itr = document.FindMember(propertyName); - if (itr != document.MemberEnd() && itr->value.IsString()) { - std::string url(itr->value.GetString(), itr->value.GetStringLength()); - return finished(true, url); - } else { - return finished(false, ""); - } - }).detach(); -} + if (document.HasParseError() || !document.IsObject()) return finished(false, ""); -void NyaAPI::get_path_from_list_api( - SourceData* source, - std::string url, - float timeoutInSeconds, - int indexNumber, - std::function finished, - std::string apiKey -) { - if (!finished) { - return ERROR("Can't get data async without a callback to use it with"); - } - if (!source) { - ERROR("Source is null"); - return finished(false, ""); - } - - auto options = WebUtils::URLOptions(url); - options.timeOut = timeoutInSeconds; - if (!apiKey.empty()) { - options.headers.emplace("Authorization", apiKey); - } - - std::thread([propertyName = std::string(source->propertyName), - options, - finished, - indexNumber] { - auto response = WebUtils::Get(options); + rapidjson::Value* current = &document; + std::stringstream ss(propertyName); + std::string token; - if (!response.IsSuccessful()) - return finished(false, ""); - - if (!response.responseData.has_value()) - return finished(false, ""); + while (std::getline(ss, token, '/')) { + if (current->IsObject()) { + auto itr = current->FindMember(token.c_str()); + if (itr == current->MemberEnd()) { + return finished(false, ""); + } + current = &itr->value; + } + else if (current->IsArray()) { + try { + size_t idx = std::stoul(token); + if (idx >= current->Size()) { + return finished(false, ""); + } + current = &(*current)[idx]; + } + catch (...) { + return finished(false, ""); + } + } + else { + return finished(false, ""); + } + } - auto& arr = response.responseData.value(); - if (indexNumber < 0 || indexNumber >= static_cast(arr.Size())) - return finished(false, ""); - auto& document = arr[indexNumber]; - if (!document.IsObject()) - return finished(false, ""); - - auto itr = document.FindMember(propertyName); - if (itr != document.MemberEnd() && itr->value.IsString()) { - std::string url(itr->value.GetString(), itr->value.GetStringLength()); - return finished(true, url); + if (current->IsString()) { + std::string result(current->GetString(), current->GetStringLength()); + return finished(true, result); } else { return finished(false, ""); } }).detach(); } - /** * @brief Finds the string in a list * diff --git a/src/ImageView.cpp b/src/ImageView.cpp index d14ee9b..898b5e5 100644 --- a/src/ImageView.cpp +++ b/src/ImageView.cpp @@ -320,122 +320,6 @@ void Nya::ImageView::GetImage(std::function finished = nullp }); - }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); - } else if (source->Mode == DataMode::List) { - // Better way to do this instead of ctrl+c ctrl+v of the first part, probley, will I do that instead, probley not. - // API is authenticated - bool authenticated = source->Mode == DataMode::Authenticated; - - // Construct the url - // TODO: check if endpoint from the setting exists and make it dynamic - - std::string endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, NSFWEnabled); - - // Fallback to sfw if nsfw is enabled and no nsfw endpoint is found - if (endpointValue == "" && NSFWEnabled) { - endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, false); - } - - bool nsfwEmpty = source->NsfwEndpoints.empty(); - bool sfwEmpty = source->SfwEndpoints.empty(); - - // If the endpoint is random, get a random endpoint - if (endpointValue == "random") { - if (NSFWEnabled) { - if (nsfwEmpty) { - auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; - } else { - auto endpoint = NyaAPI::getRandomEndpoint(&source->NsfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; - } - } else { - if (sfwEmpty) { - // DO NOT FALLBACK TO NSFW since it is disabled - endpointValue = ""; - } else { - auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; - } - } - } - - std::string endpointURL = source->BaseEndpoint + endpointValue; - - if (!NSFWEnabled) INFO("Endpoint URL: {}", endpointURL); - - // Get the image url from the api - NyaAPI::get_path_from_list_api(source, endpointURL, 10.0f, 0, [this, finished, NSFWEnabled](bool success, std::string url) { - // If we failed to get the image url - if (!success) { - // Error getting things - ERROR("Failed to load image from api"); - - // getLogger().Backtrace(20); - BSML::MainThreadScheduler::Schedule([this, finished]{ - this->SetErrorImage(); - - // Set is loading status - this->isLoading = false; - if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); - - if (finished != nullptr) finished(false); - }); - return; - } - - if (!NSFWEnabled) INFO("Image URL: {}", url); - - BSML::MainThreadScheduler::Schedule([this, url, finished, NSFWEnabled]{ - // Make temp file name - std::string fileExtension = FileUtils::GetFileFormat(url); - std::string fileName = Nya::Utils::RandomString(8); - - std::string filePath = NyaGlobals::tempPath + fileName + fileExtension; - std::string fileFullName = fileName + fileExtension; - - Nya::Utils::DownloadFile(url, filePath, [this, finished, url, NSFWEnabled, fileFullName](bool success, std::string path) { - if (!success ) { - this->SetErrorImage(); - - // Set is loading status - this->isLoading = false; - if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); - - if (finished != nullptr) finished(false); - } else { - this->lastImageURL = url; - this->tempName = fileFullName; - this->isNSFW = NSFWEnabled; - - // Check if image view is still valid and if not, don't set the image - if (this->imageView == nullptr || this->imageView->___m_CachedPtr.m_value == nullptr) { - if (finished != nullptr) finished(false); - return; - } - - BSML::Utilities::SetImage(this->imageView, "file://" + path, true, BSML::Utilities::ScaleOptions(), false, [finished, this]() { - // Set is loading status - this->isLoading = false; - if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); - - if (finished != nullptr) finished(true); - }, [finished, this](BSML::Utilities::ImageLoadError error) { - this->SetErrorImage(); - - // Set is loading status - this->isLoading = false; - if (this->imageLoadingChange.size() > 0) this->imageLoadingChange.invoke(false); - - if (finished != nullptr) finished(false); - }); - } - - }); - - }); - - }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); } } From 34b0dd59713399f35f090d5056dbdfd393d72914 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:25:59 -0400 Subject: [PATCH 07/19] Quick change on readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 79007e4..d0be079 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Nya features a floating screen, allowing Nya to be accessed outside of the gamep * [Waifu.Pics](https://waifu.pics/) * [Fluxpoint.dev](https://fluxpoint.dev/api) * [Animals (https://some-random-api.com)](https://some-random-api.com/) +* [Animu (https://some-random-api.com)](https://some-random-api.com/) +* [Nekos.Best (https://nekos.best)](https://nekos.best/) +* [Nekosia (https://nekosia.cat)](https://nekosia.cat/) * [Local Files](#local-files) ### Local Files In order for local files to work there must be compatible images in the sfw / nsfw files found in Nya's folder in `/sdcard/Pictures/Nya/`. From 66860b8f6002f2f82d1bb4eb26f9816ce0496275 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:04:50 -0400 Subject: [PATCH 08/19] Note the apis commented didnt work in the first place --- src/API.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/API.cpp b/src/API.cpp index d398c07..fd6bc5f 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -18,7 +18,7 @@ inline std::map endpoint_data = { {"azurlane", "sfw/img/azurlane"}, {"chibi", "sfw/img/chibi"}, {"christmas", "sfw/img/christmas"}, - {"ddlc", "sfw/img/ddlc"}, + //{"ddlc", "sfw/img/ddlc"}, {"halloween", "sfw/img/halloween"}, {"holo", "sfw/img/holo"}, {"kitsune", "sfw/img/kitsune"}, @@ -69,24 +69,24 @@ inline std::map endpoint_data = { {"cosplay", "nsfw/img/cosplay"}, {"cum", "nsfw/img/cum"}, {"feet", "nsfw/img/feet"}, - {"femdom", "nsfw/img/femdom"}, + //{"femdom", "nsfw/img/femdom"}, {"futa", "nsfw/img/futa"}, {"gasm", "nsfw/img/gasm"}, {"holo", "nsfw/img/holo"}, - {"kitsune", "nsfw/img/kitsune"}, + //{"kitsune", "nsfw/img/kitsune"}, {"lewd", "nsfw/img/lewd"}, {"neko", "nsfw/img/neko"}, {"nekopara", "nsfw/img/nekopara"}, - {"pantsu", "nsfw/img/pantsu"}, + //{"pantsu", "nsfw/img/pantsu"}, {"pantyhose", "nsfw/img/pantyhose"}, {"peeing", "nsfw/img/peeing"}, {"petplay", "nsfw/img/petplay"}, {"pussy", "nsfw/img/pussy"}, {"slimes", "nsfw/img/slimes"}, {"solo", "nsfw/img/solo"}, - {"swimsuit", "nsfw/img/swimsuit"}, - {"tentacle", "nsfw/img/tentacle"}, - {"thighs", "nsfw/img/thighs"}, + //{"swimsuit", "nsfw/img/swimsuit"}, + //{"tentacle", "nsfw/img/tentacle"}, + //{"thighs", "nsfw/img/thighs"}, {"trap", "nsfw/img/trap"}, {"yaoi", "nsfw/img/yaoi"}, {"yuri", "nsfw/img/yuri"}, @@ -103,14 +103,14 @@ inline std::map endpoint_data = { {"futa gif", "nsfw/gif/futa"}, {"handjob", "nsfw/gif/handjob"}, {"hentai", "nsfw/gif/hentai"}, - {"kitsune (not implemented yet)", "nsfw/gif/kitsune"}, + //{"kitsune (not implemented yet)", "nsfw/gif/kitsune"}, {"kuni", "nsfw/gif/kuni"}, {"neko gif", "nsfw/gif/neko"}, {"pussy gif", "nsfw/gif/pussy"}, {"wank", "nsfw/gif/wank"}, {"solo gif", "nsfw/gif/solo"}, {"spank", "nsfw/gif/spank"}, - {"femdom gif", "nsfw/gif/femdom"}, + //{"femdom gif", "nsfw/gif/femdom"}, {"tentacle gif", "nsfw/gif/tentacle"}, {"toys", "nsfw/gif/toys"}, {"yuri gif", "nsfw/gif/yuri"}, From 21c3223424125c9c01e896447371a8be3647f64c Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:13:40 -0400 Subject: [PATCH 09/19] nvm they do exist --- src/API.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/API.cpp b/src/API.cpp index fd6bc5f..c712326 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -18,7 +18,7 @@ inline std::map endpoint_data = { {"azurlane", "sfw/img/azurlane"}, {"chibi", "sfw/img/chibi"}, {"christmas", "sfw/img/christmas"}, - //{"ddlc", "sfw/img/ddlc"}, + {"ddlc", "sfw/img/ddlc"}, {"halloween", "sfw/img/halloween"}, {"holo", "sfw/img/holo"}, {"kitsune", "sfw/img/kitsune"}, @@ -69,24 +69,24 @@ inline std::map endpoint_data = { {"cosplay", "nsfw/img/cosplay"}, {"cum", "nsfw/img/cum"}, {"feet", "nsfw/img/feet"}, - //{"femdom", "nsfw/img/femdom"}, + {"femdom", "nsfw/img/femdom"}, {"futa", "nsfw/img/futa"}, {"gasm", "nsfw/img/gasm"}, {"holo", "nsfw/img/holo"}, - //{"kitsune", "nsfw/img/kitsune"}, + {"kitsune", "nsfw/img/kitsune"}, {"lewd", "nsfw/img/lewd"}, {"neko", "nsfw/img/neko"}, {"nekopara", "nsfw/img/nekopara"}, - //{"pantsu", "nsfw/img/pantsu"}, + {"pantsu", "nsfw/img/pantsu"}, {"pantyhose", "nsfw/img/pantyhose"}, {"peeing", "nsfw/img/peeing"}, {"petplay", "nsfw/img/petplay"}, {"pussy", "nsfw/img/pussy"}, {"slimes", "nsfw/img/slimes"}, {"solo", "nsfw/img/solo"}, - //{"swimsuit", "nsfw/img/swimsuit"}, - //{"tentacle", "nsfw/img/tentacle"}, - //{"thighs", "nsfw/img/thighs"}, + {"swimsuit", "nsfw/img/swimsuit"}, + {"tentacle", "nsfw/img/tentacle"}, + {"thighs", "nsfw/img/thighs"}, {"trap", "nsfw/img/trap"}, {"yaoi", "nsfw/img/yaoi"}, {"yuri", "nsfw/img/yuri"}, @@ -103,14 +103,14 @@ inline std::map endpoint_data = { {"futa gif", "nsfw/gif/futa"}, {"handjob", "nsfw/gif/handjob"}, {"hentai", "nsfw/gif/hentai"}, - //{"kitsune (not implemented yet)", "nsfw/gif/kitsune"}, + {"kitsune", "nsfw/gif/kitsune"}, {"kuni", "nsfw/gif/kuni"}, {"neko gif", "nsfw/gif/neko"}, {"pussy gif", "nsfw/gif/pussy"}, {"wank", "nsfw/gif/wank"}, {"solo gif", "nsfw/gif/solo"}, {"spank", "nsfw/gif/spank"}, - //{"femdom gif", "nsfw/gif/femdom"}, + {"femdom gif", "nsfw/gif/femdom"}, {"tentacle gif", "nsfw/gif/tentacle"}, {"toys", "nsfw/gif/toys"}, {"yuri gif", "nsfw/gif/yuri"}, From 405208faed6b5ccd4e292c25544667af2e98c204 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:16:56 -0400 Subject: [PATCH 10/19] nvm 2 dont exist --- src/API.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/API.cpp b/src/API.cpp index c712326..0ff63a1 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -103,14 +103,14 @@ inline std::map endpoint_data = { {"futa gif", "nsfw/gif/futa"}, {"handjob", "nsfw/gif/handjob"}, {"hentai", "nsfw/gif/hentai"}, - {"kitsune", "nsfw/gif/kitsune"}, + //{"kitsune", "nsfw/gif/kitsune"}, {"kuni", "nsfw/gif/kuni"}, {"neko gif", "nsfw/gif/neko"}, {"pussy gif", "nsfw/gif/pussy"}, {"wank", "nsfw/gif/wank"}, {"solo gif", "nsfw/gif/solo"}, {"spank", "nsfw/gif/spank"}, - {"femdom gif", "nsfw/gif/femdom"}, + //{"femdom gif", "nsfw/gif/femdom"}, {"tentacle gif", "nsfw/gif/tentacle"}, {"toys", "nsfw/gif/toys"}, {"yuri gif", "nsfw/gif/yuri"}, From de29d97c0845e774be98b7a8b41275f335f1ac04 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:18:04 -0400 Subject: [PATCH 11/19] Update API.cpp --- src/API.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/API.cpp b/src/API.cpp index 0ff63a1..69be81a 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -4,7 +4,7 @@ #include #include #include - + using namespace NyaAPI; inline std::map endpoint_data = { @@ -505,4 +505,4 @@ EndpointCategory* NyaAPI::getRandomEndpoint(std::vector* value int index = rand() % count; // Return value at index return &((*values)[index]); -} \ No newline at end of file +} From ef324e5ab81529da8bce14c4297b2d32c8afc4cb Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:20:54 -0400 Subject: [PATCH 12/19] Remember to test later No clue if this works but cant test it since qpm on laptop went brrrrrrrrrrrrrr --- src/API.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/API.cpp b/src/API.cpp index 69be81a..ffa26d3 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -1,6 +1,7 @@ #include "API.hpp" #include "web-utils/shared/WebUtils.hpp" #include "logging.hpp" +#include "rapidjson/pointer.h" #include #include #include @@ -373,6 +374,61 @@ std::vector NyaAPI::get_source_list() { * @param apiKey The api key to use (optional) */ +void NyaAPI::get_path_from_json_api( + SourceData* source, + std::string url, + float timeoutInSeconds, + std::function finished, + std::string apiKey +) { + if (finished == nullptr) { + return ERROR("Can't get data async without a callback to use it with"); + } + if (source == nullptr) { + ERROR("Source is null"); + return finished(false, ""); + } + + auto options = WebUtils::URLOptions(url); + options.timeOut = timeoutInSeconds; + if (!apiKey.empty()) { + options.headers.emplace("Authorization", apiKey); + } + + std::thread([propertyName = source->propertyName, options, finished] { + auto response = WebUtils::Get(options); + + if (!response.IsSuccessful()) return finished(false, ""); + if (!response.responseData.has_value()) return finished(false, ""); + + auto& document = response.responseData.value(); + if (document.HasParseError() || !document.IsObject()) return finished(false, ""); + + rapidjson::Value* current = &document; + + std::string formatedPropertyName = ""; + + if (!propertyName.starts_with("/")) { + formatedPropertyName = "/"+propertyName; + } else { + formatedPropertyName = propertyName; + } + + // https://rapidjson.org/md_doc_pointer.html + current = Pointer(formatedPropertyName).Get(document); + + if (current->IsString()) { + std::string result(current->GetString(), current->GetStringLength()); + return finished(true, result); + } else { + return finished(false, ""); + } + }).detach(); +} + + +/* +// Ignore this version, just a backup just in case I mess something up. void NyaAPI::get_path_from_json_api( SourceData* source, std::string url, @@ -441,7 +497,7 @@ void NyaAPI::get_path_from_json_api( } }).detach(); } - +*/ /** * @brief Finds the string in a list * From 9ca48352c7e2d2bb9c0512d1cb7152c1be00d73d Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Wed, 24 Sep 2025 17:45:55 -0400 Subject: [PATCH 13/19] Funny changes --- include/API.hpp | 5 +++-- src/API.cpp | 34 +++++++++++++++++++--------------- src/ImageView.cpp | 2 +- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index cc19c08..d15d631 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -29,6 +29,7 @@ struct SourceData { std::vector SfwEndpoints; std::vector NsfwEndpoints; std::string propertyName; + std::string apiKey = ""; }; // Function gets url for the current selected category @@ -37,8 +38,8 @@ std::vector get_source_list(); void get_path_from_json_api(SourceData* source, std::string url, float timeoutInSeconds, - std::function finished, - std::string apiKey = ""); + std::function finished + ); // void NyaAPI::downloadImageFile(); std::map* getEndpoints(); diff --git a/src/API.cpp b/src/API.cpp index ffa26d3..ee4393d 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -1,13 +1,18 @@ #include "API.hpp" #include "web-utils/shared/WebUtils.hpp" #include "logging.hpp" -#include "rapidjson/pointer.h" +#include "beatsaber-hook/shared/rapidjson/include/rapidjson/pointer.h" + +/* +// For old path setup #include #include #include - +*/ + using namespace NyaAPI; + inline std::map endpoint_data = { {"fluxpoint.dev", { @@ -116,7 +121,8 @@ inline std::map endpoint_data = { {"toys", "nsfw/gif/toys"}, {"yuri gif", "nsfw/gif/yuri"}, }, - "file" + "file", + "FP-Public-naEjca70OhKMtq67WpzaN8Gs" } }, {"waifu.pics", @@ -159,7 +165,7 @@ inline std::map endpoint_data = { {"trap", "nsfw/trap"}, {"blowjob", "nsfw/blowjob"}, }, - "url" + "url", } }, {"Bocchi", @@ -378,8 +384,7 @@ void NyaAPI::get_path_from_json_api( SourceData* source, std::string url, float timeoutInSeconds, - std::function finished, - std::string apiKey + std::function finished ) { if (finished == nullptr) { return ERROR("Can't get data async without a callback to use it with"); @@ -388,15 +393,14 @@ void NyaAPI::get_path_from_json_api( ERROR("Source is null"); return finished(false, ""); } - - auto options = WebUtils::URLOptions(url); - options.timeOut = timeoutInSeconds; - if (!apiKey.empty()) { - options.headers.emplace("Authorization", apiKey); - } - std::thread([propertyName = source->propertyName, options, finished] { - auto response = WebUtils::Get(options); + std::thread([apiKey = source->apiKey, propertyName = source->propertyName, url, timeoutInSeconds, finished] { + auto reqOptions = WebUtils::URLOptions(url); + reqOptions.timeOut = timeoutInSeconds; + if (!apiKey.empty()) { + reqOptions.headers.emplace("Authorization", apiKey); + } + auto response = WebUtils::Get(reqOptions); if (!response.IsSuccessful()) return finished(false, ""); if (!response.responseData.has_value()) return finished(false, ""); @@ -415,7 +419,7 @@ void NyaAPI::get_path_from_json_api( } // https://rapidjson.org/md_doc_pointer.html - current = Pointer(formatedPropertyName).Get(document); + current = rapidjson::Pointer(formatedPropertyName).Get(document); if (current->IsString()) { std::string result(current->GetString(), current->GetStringLength()); diff --git a/src/ImageView.cpp b/src/ImageView.cpp index 898b5e5..07498b0 100644 --- a/src/ImageView.cpp +++ b/src/ImageView.cpp @@ -320,7 +320,7 @@ void Nya::ImageView::GetImage(std::function finished = nullp }); - }, authenticated ? "FP-Public-naEjca70OhKMtq67WpzaN8Gs" : ""); + }); } } From 4f2bf7a964c38e62836d5d02776043fa9f4ec287 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 25 Sep 2025 05:15:33 +0400 Subject: [PATCH 14/19] Clean up the codebase, improve null safety, improve random function --- include/API.hpp | 14 +++-- src/API.cpp | 146 ++++++++++---------------------------------- src/ImageView.cpp | 34 ++++------- src/Utils/Utils.cpp | 16 ++--- 4 files changed, 59 insertions(+), 151 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index d15d631..d86d6b4 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -11,7 +11,7 @@ struct EndpointCategory { std::string url; }; -enum DataMode { Unsupported, Json, Local, Authenticated }; +enum DataMode { Unsupported, Json, Local }; struct SourceData { // SourceData( @@ -35,11 +35,13 @@ struct SourceData { // Function gets url for the current selected category SourceData* get_data_source(std::string name); std::vector get_source_list(); -void get_path_from_json_api(SourceData* source, - std::string url, - float timeoutInSeconds, - std::function finished - ); +void get_path_from_json_api( + SourceData* source, + std::string endpoint, + bool nsfw, + float timeoutInSeconds, + std::function finished +); // void NyaAPI::downloadImageFile(); std::map* getEndpoints(); diff --git a/src/API.cpp b/src/API.cpp index ee4393d..5c531a1 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -2,13 +2,7 @@ #include "web-utils/shared/WebUtils.hpp" #include "logging.hpp" #include "beatsaber-hook/shared/rapidjson/include/rapidjson/pointer.h" - -/* -// For old path setup -#include -#include -#include -*/ +#include "Utils/Utils.hpp" using namespace NyaAPI; @@ -17,7 +11,7 @@ inline std::map endpoint_data = { {"fluxpoint.dev", { "https://gallery.fluxpoint.dev/api/", - DataMode::Authenticated, + DataMode::Json, { // Images {"anime", "sfw/img/anime"}, @@ -374,15 +368,14 @@ std::vector NyaAPI::get_source_list() { * @brief Get the path from a json api * WARNING: This function runs finished not on the main thread * @param source The source data - * @param url The url to get the data from + * @param endpoint The endpoint to use * @param timeoutInSeconds The timeout in seconds * @param finished The function to run when the request is finished - * @param apiKey The api key to use (optional) */ - void NyaAPI::get_path_from_json_api( SourceData* source, - std::string url, + std::string endpoint, + bool nsfw, float timeoutInSeconds, std::function finished ) { @@ -393,115 +386,47 @@ void NyaAPI::get_path_from_json_api( ERROR("Source is null"); return finished(false, ""); } - - std::thread([apiKey = source->apiKey, propertyName = source->propertyName, url, timeoutInSeconds, finished] { - auto reqOptions = WebUtils::URLOptions(url); + + std::string endpointURL = source->BaseEndpoint + endpoint; + + if (!nsfw) INFO("Endpoint URL: {}", endpointURL); + + std::thread([source, endpointURL, timeoutInSeconds, finished] { + auto reqOptions = WebUtils::URLOptions(endpointURL); reqOptions.timeOut = timeoutInSeconds; - if (!apiKey.empty()) { - reqOptions.headers.emplace("Authorization", apiKey); + if (!source->apiKey.empty()) { + reqOptions.headers.emplace("Authorization", source->apiKey); } auto response = WebUtils::Get(reqOptions); - if (!response.IsSuccessful()) return finished(false, ""); - if (!response.responseData.has_value()) return finished(false, ""); + if ( + !response.IsSuccessful() || + !response.responseData.has_value() + ) return finished(false, ""); auto& document = response.responseData.value(); - if (document.HasParseError() || !document.IsObject()) return finished(false, ""); - - rapidjson::Value* current = &document; - + if ( + document.HasParseError() || + !document.IsObject() + ) return finished(false, ""); + std::string formatedPropertyName = ""; - if (!propertyName.starts_with("/")) { - formatedPropertyName = "/"+propertyName; + if (!source->propertyName.starts_with("/")) { + formatedPropertyName = "/"+ source->propertyName; } else { - formatedPropertyName = propertyName; + formatedPropertyName = source->propertyName; } // https://rapidjson.org/md_doc_pointer.html - current = rapidjson::Pointer(formatedPropertyName).Get(document); + rapidjson::Value* current = rapidjson::Pointer(formatedPropertyName).Get(document); + if (current == nullptr || !current->IsString()) return finished(false, ""); - if (current->IsString()) { - std::string result(current->GetString(), current->GetStringLength()); - return finished(true, result); - } else { - return finished(false, ""); - } + std::string result(current->GetString(), current->GetStringLength()); + return finished(true, result); }).detach(); } - -/* -// Ignore this version, just a backup just in case I mess something up. -void NyaAPI::get_path_from_json_api( - SourceData* source, - std::string url, - float timeoutInSeconds, - std::function finished, - std::string apiKey -) { - if (finished == nullptr) { - return ERROR("Can't get data async without a callback to use it with"); - } - if (source == nullptr) { - ERROR("Source is null"); - return finished(false, ""); - } - - auto options = WebUtils::URLOptions(url); - options.timeOut = timeoutInSeconds; - if (!apiKey.empty()) { - options.headers.emplace("Authorization", apiKey); - } - - std::thread([propertyName = source->propertyName, options, finished] { - auto response = WebUtils::Get(options); - - if (!response.IsSuccessful()) return finished(false, ""); - if (!response.responseData.has_value()) return finished(false, ""); - - auto& document = response.responseData.value(); - if (document.HasParseError() || !document.IsObject()) return finished(false, ""); - - rapidjson::Value* current = &document; - std::stringstream ss(propertyName); - std::string token; - - while (std::getline(ss, token, '/')) { - if (current->IsObject()) { - auto itr = current->FindMember(token.c_str()); - if (itr == current->MemberEnd()) { - return finished(false, ""); - } - current = &itr->value; - } - else if (current->IsArray()) { - try { - size_t idx = std::stoul(token); - if (idx >= current->Size()) { - return finished(false, ""); - } - current = &(*current)[idx]; - } - catch (...) { - return finished(false, ""); - } - } - else { - return finished(false, ""); - } - } - - - if (current->IsString()) { - std::string result(current->GetString(), current->GetStringLength()); - return finished(true, result); - } else { - return finished(false, ""); - } - }).detach(); -} -*/ /** * @brief Finds the string in a list * @@ -555,14 +480,9 @@ void NyaAPI::get_path_from_json_api( } EndpointCategory* NyaAPI::getRandomEndpoint(std::vector* values) { - // If there are no values, return null int count = values->size(); - if (count == 0) { - return nullptr; - } + if (count == 0) return nullptr; - // Get random index - int index = rand() % count; - // Return value at index - return &((*values)[index]); + int index = Nya::Utils::random(0, count - 1); + return &values->at(index); } diff --git a/src/ImageView.cpp b/src/ImageView.cpp index 07498b0..be6feb4 100644 --- a/src/ImageView.cpp +++ b/src/ImageView.cpp @@ -205,51 +205,41 @@ void Nya::ImageView::GetImage(std::function finished = nullp } - } else if (source->Mode == DataMode::Json || source->Mode == DataMode::Authenticated) { + } else if (source->Mode == DataMode::Json) { + std::string selectedEndpoint = EndpointConfigUtils::getEndpointValue(currentAPI, NSFWEnabled); - // API is authenticated - bool authenticated = source->Mode == DataMode::Authenticated; - - // Construct the url - // TODO: check if endpoint from the setting exists and make it dynamic - - std::string endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, NSFWEnabled); - // Fallback to sfw if nsfw is enabled and no nsfw endpoint is found - if (endpointValue == "" && NSFWEnabled) { - endpointValue = EndpointConfigUtils::getEndpointValue(currentAPI, false); + if (selectedEndpoint == "" && NSFWEnabled) { + selectedEndpoint = EndpointConfigUtils::getEndpointValue(currentAPI, false); } bool nsfwEmpty = source->NsfwEndpoints.empty(); bool sfwEmpty = source->SfwEndpoints.empty(); // If the endpoint is random, get a random endpoint - if (endpointValue == "random") { + if (selectedEndpoint == "random") { if (NSFWEnabled) { if (nsfwEmpty) { + // Fallback to sfw since nsfw is empty + NSFWEnabled = false; auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; + if (endpoint != nullptr) selectedEndpoint = endpoint->url; } else { auto endpoint = NyaAPI::getRandomEndpoint(&source->NsfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; + if (endpoint != nullptr) selectedEndpoint = endpoint->url; } } else { if (sfwEmpty) { - // DO NOT FALLBACK TO NSFW since it is disabled - endpointValue = ""; + selectedEndpoint = ""; } else { auto endpoint = NyaAPI::getRandomEndpoint(&source->SfwEndpoints); - if (endpoint != nullptr) endpointValue = endpoint->url; + if (endpoint != nullptr) selectedEndpoint = endpoint->url; } } } - std::string endpointURL = source->BaseEndpoint + endpointValue; - - if (!NSFWEnabled) INFO("Endpoint URL: {}", endpointURL); - // Get the image url from the api - NyaAPI::get_path_from_json_api(source, endpointURL, 10.0f, [this, finished, NSFWEnabled](bool success, std::string url) { + NyaAPI::get_path_from_json_api(source, selectedEndpoint, NSFWEnabled, 10.0f, [this, finished, NSFWEnabled](bool success, std::string url) { // If we failed to get the image url if (!success) { // Error getting things diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index c13b9af..e31b4ef 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -199,16 +199,13 @@ namespace Nya::Utils { } // Generate random number - // Stolen from https://stackoverflow.com/questions/7560114/random-number-c-in-some-range - int random(int min, int max) //range : [min, max] + int random(int min, int max) { - static bool first = true; - if (first) - { - srand( time(NULL) ); //seeding for the first time only! - first = false; - } - return min + rand() % (( max + 1 ) - min); + static std::random_device rd; + static std::mt19937 generator(rd()); + + std::uniform_int_distribution distribution(min, max); + return distribution(generator); } // Checks if the path is animated @@ -323,7 +320,6 @@ namespace Nya::Utils { onFinished(true, path); }); } - return; }).detach(); } From bd52a64ecae80a47cf7c140f50c04cab2e623fa5 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 25 Sep 2025 05:25:22 +0400 Subject: [PATCH 15/19] Disable kill and fixup labels --- src/API.cpp | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/API.cpp b/src/API.cpp index 5c531a1..8c10449 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -151,8 +151,8 @@ inline std::map endpoint_data = { {"wink", "sfw/wink"}, {"poke", "sfw/poke"}, {"dance", "sfw/dance"}, - {"kill", "sfw/kill"}, // screw you I am adding it - }, // Not including 'kill' because it's bad + // {"kill", "sfw/kill"}, // Not including 'kill' because it's bad + }, { {"neko", "nsfw/neko"}, {"waifu", "nsfw/waifu"}, @@ -236,40 +236,40 @@ inline std::map endpoint_data = { { {"catgirl", "catgirl"}, {"foxgirl", "foxgirl"}, - {"wolf-girl", "wolf-girl"}, - {"animal-ears", "animal-ears"}, + {"wolf girl", "wolf-girl"}, + {"animal ears", "animal-ears"}, {"tail", "tail"}, - {"tail-with-ribbon", "tail-with-ribbon"}, - {"tail-from-under-skirt", "tail-from-under-skirt"}, + {"tail with ribbon", "tail-with-ribbon"}, + {"tail from under skirt", "tail-from-under-skirt"}, {"cute", "cute"}, - {"cuteness-is-justice", "cuteness-is-justice"}, - {"blue-archive", "blue-archive"}, + {"cuteness is justice", "cuteness-is-justice"}, + {"blue archive", "blue-archive"}, {"girl", "girl"}, - {"young-girl", "young-girl"}, + {"young girl", "young-girl"}, {"maid", "maid"}, - {"maid-uniform", "maid-uniform"}, + {"maid uniform", "maid-uniform"}, {"vtuber", "vtuber"}, - {"w-sitting", "w-sitting"}, - {"lying-down", "lying-down"}, - {"hands-forming-a-heart", "hands-forming-a-heart"}, + {"w sitting", "w-sitting"}, + {"lying down", "lying-down"}, + {"hands forming a <3", "hands-forming-a-heart"}, {"wink", "wink"}, {"valentine", "valentine"}, - {"thigh-high-socks", "thigh-high-socks"}, + {"thigh high socks", "thigh-high-socks"}, {"headphones", "headphones"}, - {"knee-high-socks", "knee-high-socks"}, - {"white-tights", "white-tights"}, - {"black-tights", "black-tights"}, + {"knee high socks", "knee-high-socks"}, + {"white tights", "white-tights"}, + {"black tights", "black-tights"}, {"heterochromia", "heterochromia"}, {"uniform", "uniform"}, - {"sailor-uniform", "sailor-uniform"}, + {"sailor uniform", "sailor-uniform"}, {"hoodie", "hoodie"}, {"ribbon", "ribbon"}, - {"white-hair", "white-hair"}, - {"blue-hair", "blue-hair"}, - {"long-hair", "long-hair"}, + {"white hair", "white-hair"}, + {"blue hair", "blue-hair"}, + {"long hair", "long-hair"}, {"blonde", "blonde"}, - {"blue-eyes", "blue-eyes"}, - {"purple-eyes", "purple-eyes"} + {"blue eyes", "blue-eyes"}, + {"purple eyes", "purple-eyes"} }, {}, "image/original/url" From efe8d65c6de28c71e3b9214a150e5c865f25e24f Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Fri, 17 Oct 2025 20:02:31 -0400 Subject: [PATCH 16/19] mmmmm --- src/API.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/API.cpp b/src/API.cpp index 8c10449..afec02f 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -162,6 +162,36 @@ inline std::map endpoint_data = { "url", } }, + /* + // Might come back to figure out why the 404 error is only happening in the mod and not in anything else + {"waifu.im", + { + "https://api.waifu.im/search?included_tags=", + DataMode::Json, + { + {"waifu", "waifu"}, + {"maid", "maid"}, + {"marin-kitagawa", "marin-kitagawa"}, + {"mori-calliope", "mori-calliope"}, + {"raiden-shogun", "raiden-shogun"}, + {"oppai", "oppai"}, + {"selfies", "selfies"}, + {"uniform", "uniform"}, + {"kamisato-ayaka", "kamisato-ayaka"}, + }, + { + {"ass", "ass"}, + {"hentai", "hentai"}, + {"milf", "milf"}, + {"oral", "oral"}, + {"paizuri", "paizuri"}, + {"ecchi", "ecchi"}, + {"ero", "ero"}, + }, + "images/0/url", + } + }, + */ {"Bocchi", { "https://boccher.pixelboom.dev/api/", @@ -229,7 +259,7 @@ inline std::map endpoint_data = { "link" } }, - {"nekosia.cat", + {"Nekosia", { "https://api.nekosia.cat/api/v1/images/", DataMode::Json, @@ -331,6 +361,42 @@ inline std::map endpoint_data = { "results/0/url" } }, + {"nekos.life", + { + "https://nekos.life/api/v2/img/", + DataMode::Json, + { + {"neko gif", "ngif"}, + {"hug", "hug"}, + {"gecg", "gecg"}, + {"pat", "pat"}, + {"cuddle", "cuddle"}, + {"meow", "meow"}, + {"gasm", "gasm"}, + {"goose (Just geese)", "goose"}, + {"bored", "bored"}, + {"cry", "cry"}, + {"cuddle", "cuddle"}, + {"feed", "feed"}, + {"slap", "slap"}, + {"wallpaper", "wallpaper"}, + {"neko", "neko"}, + {"lizard", "lizard"}, + {"woof", "woof"}, + {"fox_girl", "fox_girl"}, + {"8ball", "8ball"}, + {"kiss", "kiss"}, + {"avatar", "avatar"}, + {"waifu", "waifu"}, + {"smug", "smug"}, + }, + { + {"lewd", "lewd"}, + {"spank", "spank"}, + }, + "url" + } + }, {"Local Files", { "", From 6fb5ebc5f4bea1b8bf4ed0644da67a70722c8f79 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Fri, 21 Nov 2025 21:01:05 -0500 Subject: [PATCH 17/19] dddddd --- build.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 8f09339..2cf1324 100755 --- a/build.sh +++ b/build.sh @@ -4,21 +4,27 @@ rm Nya.qmod echo "Removing oldness" rm -rf build +rm -rf logs echo "Bulding da dir" mkdir -p build cd build +echo "Log da dir" +mkdir -p ../logs + +set -e + echo "cmaking it" cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/home/dia/android/ndk/27.2.12479018+preview-0/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ -DANDROID_PLATFORM=android-24 \ -DCMAKE_BUILD_TYPE=Release \ - -G Ninja + -G Ninja | tee ../logs/cmake_log.txt echo "Building funnies" -ninja +ninja | tee ../logs/ninja_log.txt echo "Zipping bombing it" mkdir -p Nya @@ -32,4 +38,6 @@ zip -r Nya.zip * mv Nya.zip ../../Nya.qmod -echo "Done :3" \ No newline at end of file +rm -rf Nya + +echo "Done :3" From 2a6f4a18d2986c57d894d4eba08044def98fd28e Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Sat, 7 Feb 2026 09:14:28 -0500 Subject: [PATCH 18/19] Found the problem --- build.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 2cf1324..888d388 100755 --- a/build.sh +++ b/build.sh @@ -2,9 +2,14 @@ rm Nya.qmod +echo "Installing Deps" +qpm restore + echo "Removing oldness" rm -rf build rm -rf logs +rm -rf CMakeCache.txt +rm -rf CMakeFiles echo "Bulding da dir" mkdir -p build @@ -17,7 +22,7 @@ set -e echo "cmaking it" cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=/home/dia/android/ndk/27.2.12479018+preview-0/build/cmake/android.toolchain.cmake \ + -DCMAKE_TOOLCHAIN_FILE=$HOME/android/ndk/27.3.13750724/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ -DANDROID_PLATFORM=android-24 \ -DCMAKE_BUILD_TYPE=Release \ @@ -26,6 +31,11 @@ cmake .. \ echo "Building funnies" ninja | tee ../logs/ninja_log.txt +echo "Generating mod.json" +cd .. +qpm qmod manifest +cd build + echo "Zipping bombing it" mkdir -p Nya cp libNya.so Nya From ddd52f82bef0410feeaf2471508b05f6fc13bcf6 Mon Sep 17 00:00:00 2001 From: Lexcona <229240464+Lexcona@users.noreply.github.com> Date: Wed, 20 May 2026 22:29:16 -0400 Subject: [PATCH 19/19] Removed a dead api --- src/API.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/API.cpp b/src/API.cpp index afec02f..f9b5665 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -119,6 +119,8 @@ inline std::map endpoint_data = { "FP-Public-naEjca70OhKMtq67WpzaN8Gs" } }, + /* + // This one got shutdown, or at least their domain expired. {"waifu.pics", { "https://api.waifu.pics/", @@ -162,6 +164,7 @@ inline std::map endpoint_data = { "url", } }, + */ /* // Might come back to figure out why the 404 error is only happening in the mod and not in anything else {"waifu.im",