From 23aab6ada90e94f0074b6e637f8c8d801beb3af2 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Fri, 20 Mar 2020 03:46:09 -0500 Subject: [PATCH] Download previous versions (#20) * WIP: Start adding downloading pervious versions * Oops this was in here * Properly add Download previous Releases. * Finally fix it. Co-authored-by: StackZ <47382115+SuperSaiyajinStackZ@users.noreply.github.com> --- include/download/download.hpp | 15 +- include/utils/scriptHelper.hpp | 2 +- romfs/lang/en/app.json | 11 +- source/download/download.cpp | 249 +++++++++++++++++++++++++++++++-- source/gfx.cpp | 1 + source/screens/mainMenu.cpp | 8 ++ source/screens/scriptlist.cpp | 6 +- source/screens/unistore.cpp | 6 +- source/utils/scriptHelper.cpp | 8 +- 9 files changed, 281 insertions(+), 25 deletions(-) diff --git a/include/download/download.hpp b/include/download/download.hpp index 11ca685..cbd31f5 100644 --- a/include/download/download.hpp +++ b/include/download/download.hpp @@ -30,7 +30,17 @@ #include "common.hpp" #define APP_TITLE "Universal-Updater" -#define VERSION_STRING "2.2.1" +#define VERSION_STRING "2.3.0" + +// The Release Fetch struct. +struct ReleaseFetch { + std::string Target; + std::string TagName; + std::string ReleaseName; + std::string Created; + std::string Published; + bool PreRelease; +}; enum DownloadError { DL_ERROR_NONE = 0, @@ -38,10 +48,11 @@ enum DownloadError { DL_ERROR_ALLOC, DL_ERROR_STATUSCODE, DL_ERROR_GIT, + DL_CANCEL, // No clue if that's needed tho. }; Result downloadToFile(std::string url, std::string path); -Result downloadFromRelease(std::string url, std::string asset, std::string path, bool includePrereleases); +Result downloadFromRelease(std::string url, std::string asset, std::string path, std::string Message, bool includePrereleases, bool showVersions); void displayProgressBar(); diff --git a/include/utils/scriptHelper.hpp b/include/utils/scriptHelper.hpp index 0a4c5cb..d6410d2 100644 --- a/include/utils/scriptHelper.hpp +++ b/include/utils/scriptHelper.hpp @@ -53,7 +53,7 @@ namespace ScriptHelper { int getNum(nlohmann::json json, const std::string &key, const std::string &key2); // Script Functions. - void downloadRelease(std::string repo, std::string file, std::string output, bool includePrereleases, std::string message); + void downloadRelease(std::string repo, std::string file, std::string output, bool includePrereleases, bool showVersions, std::string message); void downloadFile(std::string file, std::string output, std::string message); void removeFile(std::string file, std::string message); diff --git a/romfs/lang/en/app.json b/romfs/lang/en/app.json index 097c610..9f76610 100644 --- a/romfs/lang/en/app.json +++ b/romfs/lang/en/app.json @@ -158,5 +158,14 @@ "REFRESH_BROWSE_DDM": "Refresh", "VIEW_DDM": "Change ViewMode", "DELETE_DDM": "Delete", - "UPDATE_DDM": "Update" + "UPDATE_DDM": "Update", + + "TAG_NAME": "Tag name: ", + "TARGET": "Target: ", + "RELEASE_NAME": "Release Name: ", + "CREATED_AT": "Created at: ", + "PUBLISHED_AT": "Published at: ", + "FETCHING_RELEASES": "Fetching Releases... please wait.", + "VERSION_SELECT": "Select the Release you want to download.", + "IS_PRERELEASE": "PreRelease: " } diff --git a/source/download/download.cpp b/source/download/download.cpp index 002ac7c..f348e81 100644 --- a/source/download/download.cpp +++ b/source/download/download.cpp @@ -28,8 +28,10 @@ #include "download.hpp" #include "formatting.hpp" #include "gui.hpp" +#include "keyboard.hpp" #include "lang.hpp" #include "screenCommon.hpp" +#include "thread.hpp" #include #include @@ -57,6 +59,7 @@ bool progressBarType = 0; // 0 = Download | 1 = Extract extern u32 progressBar; extern bool isScriptSelected; +extern u32 TextColor; curl_off_t downloadTotal = 1; //Dont initialize with 0 to avoid division by zero later curl_off_t downloadNow = 0; @@ -301,9 +304,200 @@ static Result setupContext(CURL *hnd, const char * url) return 0; } -Result downloadFromRelease(std::string url, std::string asset, std::string path, bool includePrereleases) +// Fetch GitHub Releases. +std::vector fetchReleases(nlohmann::json API) { + ReleaseFetch fetch[API.size()]; + std::vector fetchVector; + + for (int i = 0; i < (int)API.size(); i++) { + // Get Stuff. + fetch[i].Target = (std::string)API[i]["target_commitish"]; + fetch[i].TagName = (std::string)API[i]["tag_name"]; + fetch[i].ReleaseName = (std::string)API[i]["name"]; + fetch[i].Created = (std::string)API[i]["created_at"]; + fetch[i].Published = (std::string)API[i]["published_at"]; + fetch[i].PreRelease = API[i]["prerelease"]; + // Push to the Vector. + fetchVector.push_back(fetch[i]); + } + return fetchVector; +} + +extern touchPosition touch; +extern bool touching(touchPosition touch, Structs::ButtonPos button); +std::vector arrowPos = { + {295, 0, 25, 25}, // Arrow Up. + {295, 215, 25, 25} // Arrow Down. +}; + +int SelectRelease(std::vector bruh) { + std::string line1; + std::string line2; + int selectedRelease = 0; + int keyRepeatDelay = 4; + bool fastMode = false; + int screenPos = 0; + int screenPosList = 0; + + while (1) { + std::string releaseAmount = std::to_string(selectedRelease+1) + " | " + std::to_string(bruh.size()); + // Draw Part. + Gui::clearTextBufs(); + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C2D_TargetClear(Top, BLACK); + C2D_TargetClear(Bottom, BLACK); + GFX::DrawTop(); + if (Config::UseBars == true) { + Gui::DrawStringCentered(0, 0, 0.7f, TextColor, Lang::get("VERSION_SELECT"), 400); + Gui::DrawString(397-Gui::GetStringWidth(0.6f, releaseAmount), 239-Gui::GetStringHeight(0.6f, releaseAmount), 0.6f, TextColor, releaseAmount); + } else { + Gui::DrawStringCentered(0, 2, 0.7f, TextColor, Lang::get("VERSION_SELECT"), 400); + Gui::DrawString(397-Gui::GetStringWidth(0.6f, releaseAmount), 237-Gui::GetStringHeight(0.6f, releaseAmount), 0.6f, TextColor, releaseAmount); + } + // Display Informations. + Gui::DrawStringCentered(0, 35, 0.7f, TextColor, Lang::get("TAG_NAME") + std::string(bruh[selectedRelease].TagName), 400); + Gui::DrawStringCentered(0, 65, 0.7f, TextColor, Lang::get("TARGET") + std::string(bruh[selectedRelease].Target), 400); + Gui::DrawStringCentered(0, 95, 0.7f, TextColor, Lang::get("RELEASE_NAME") + std::string(bruh[selectedRelease].ReleaseName), 400); + Gui::DrawStringCentered(0, 125, 0.7f, TextColor, Lang::get("CREATED_AT") + std::string(bruh[selectedRelease].Created), 400); + Gui::DrawStringCentered(0, 155, 0.7f, TextColor, Lang::get("PUBLISHED_AT") + std::string(bruh[selectedRelease].Published), 400); + if (bruh[selectedRelease].PreRelease) Gui::DrawStringCentered(0, 185, 0.7f, TextColor, Lang::get("IS_PRERELEASE") + Lang::get("YES"), 400); + else Gui::DrawStringCentered(0, 185, 0.7f, TextColor, Lang::get("IS_PRERELEASE") + Lang::get("NO"), 400); + + GFX::DrawBottom(); + GFX::DrawArrow(295, -1); + GFX::DrawArrow(315, 240, 180.0); + + if (Config::viewMode == 0) { + for(int i=0;i 0) selectedRelease--; + } + + if (hidKeysDown() & KEY_TOUCH && touching(touch, arrowPos[1])) { + if ((uint)selectedRelease < bruh.size()-1) selectedRelease++; + } + + if (hHeld & KEY_UP) { + if (selectedRelease > 0 && !keyRepeatDelay) { + selectedRelease--; + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } + } + } else if (hHeld & KEY_DOWN && !keyRepeatDelay) { + if ((uint)selectedRelease < bruh.size()-1) { + selectedRelease++; + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } + } + } + + if (hidKeysDown() & KEY_R) { + fastMode = true; + } + + if (hidKeysDown() & KEY_L) { + fastMode = false; + } + + if (hDown & KEY_START) { + return -2; // Cancel. + } + + if (hDown & KEY_TOUCH) { + if (Config::viewMode == 0) { + for(int i=0;i 40+(i*57) && touch.py < 40+(i*57)+45) { + if (bruh.size() != 0) { + return screenPos + i; + } + } + } + } else if (Config::viewMode == 1) { + for(int i=0;i (i+1)*27 && touch.py < (i+2)*27) { + if (bruh.size() != 0) { + return screenPosList + i; + } + } + } + } + } + + if (Config::viewMode == 0) { + if(selectedRelease < screenPos) { + screenPos = selectedRelease; + } else if (selectedRelease > screenPos + ENTRIES_PER_SCREEN - 1) { + screenPos = selectedRelease - ENTRIES_PER_SCREEN + 1; + } + } else if (Config::viewMode == 1) { + if(selectedRelease < screenPosList) { + screenPosList = selectedRelease; + } else if (selectedRelease > screenPosList + ENTRIES_PER_LIST - 1) { + screenPosList = selectedRelease - ENTRIES_PER_LIST + 1; + } + } + } +} + +Result downloadFromRelease(std::string url, std::string asset, std::string path, std::string Message, bool includePrereleases, bool showVersions) { Result ret = 0; + // Do not display progressbar. + if (showVersions) { + showProgressBar = false; + Msg::DisplayMsg(Lang::get("FETCHING_RELEASES")); + } + void *socubuf = memalign(0x1000, 0x100000); if (!socubuf) { @@ -324,7 +518,7 @@ Result downloadFromRelease(std::string url, std::string asset, std::string path, std::string repoOwner = result[1].str(), repoName = result[2].str(); std::stringstream apiurlStream; - apiurlStream << "https://api.github.com/repos/" << repoOwner << "/" << repoName << (includePrereleases ? "/releases" : "/releases/latest"); + apiurlStream << "https://api.github.com/repos/" << repoOwner << "/" << repoName << (includePrereleases || showVersions ? "/releases" : "/releases/latest"); std::string apiurl = apiurlStream.str(); printf("Downloading latest release from repo:\n%s\nby:\n%s\n", repoName.c_str(), repoOwner.c_str()); @@ -363,7 +557,37 @@ Result downloadFromRelease(std::string url, std::string asset, std::string path, printf("Looking for asset with matching name:\n%s\n", asset.c_str()); std::string assetUrl; json parsedAPI = json::parse(result_buf); - if(includePrereleases) parsedAPI = parsedAPI[0]; + if(showVersions) { + if(!includePrereleases) { + for(auto it = parsedAPI.begin(); it != parsedAPI.end();) { + if((*it)["prerelease"]) { + parsedAPI.erase(it); + } else { + it++; + } + } + } + if(parsedAPI.size() == 0) { + // All were prereleases and those are being ignored + return -2; // TODO: Maybe change this? I'm note sure what good return values are -Pk11 + } + std::vector fetchResult = fetchReleases(parsedAPI); + int release = SelectRelease(fetchResult); + + if (release == -2) { + socExit(); + free(result_buf); + free(socubuf); + result_buf = NULL; + result_sz = 0; + result_written = 0; + return -1; + } + + parsedAPI = parsedAPI[release]; + } else if(includePrereleases) { + parsedAPI = parsedAPI[0]; + } if (parsedAPI["assets"].is_array()) { for (auto jsonAsset : parsedAPI["assets"]) { if (jsonAsset.is_object() && jsonAsset["name"].is_string() && jsonAsset["browser_download_url"].is_string()) { @@ -381,12 +605,15 @@ Result downloadFromRelease(std::string url, std::string asset, std::string path, result_buf = NULL; result_sz = 0; result_written = 0; - - if (assetUrl.empty()) + if (assetUrl.empty()) { ret = DL_ERROR_GIT; - else + } else { + snprintf(progressBarMsg, sizeof(progressBarMsg), Message.c_str()); + showProgressBar = true; + progressBarType = 0; + Threads::create((ThreadFunc)displayProgressBar); ret = downloadToFile(assetUrl, path); - + } return ret; } @@ -653,17 +880,17 @@ void displayProgressBar() { C2D_TargetClear(Top, BLACK); C2D_TargetClear(Bottom, BLACK); GFX::DrawTop(); - Gui::DrawStringCentered(0, 1, 0.7f, Config::TxtColor, progressBarMsg, 400); + Gui::DrawStringCentered(0, 1, 0.7f, TextColor, progressBarMsg, 400); // Display 'Currently Extracting: '. if (progressBarType == 1) { - Gui::DrawStringCentered(0, 140, 0.6f, Config::TxtColor, str, 400); - Gui::DrawStringCentered(0, 60, 0.6f, Config::TxtColor, Lang::get("CURRENTLY_EXTRACTING") + extractingFile, 400); + Gui::DrawStringCentered(0, 140, 0.6f, TextColor, str, 400); + Gui::DrawStringCentered(0, 60, 0.6f, TextColor, Lang::get("CURRENTLY_EXTRACTING") + extractingFile, 400); } // Only display this by downloading. if (progressBarType == 0) { - Gui::DrawStringCentered(0, 80, 0.6f, Config::TxtColor, str, 400); + Gui::DrawStringCentered(0, 80, 0.6f, TextColor, str, 400); Gui::Draw_Rect(30, 120, 340, 30, BLACK); if (isScriptSelected == true) { Animation::DrawProgressBar(downloadNow, downloadTotal, 1); diff --git a/source/gfx.cpp b/source/gfx.cpp index 717dcc3..77be1e5 100644 --- a/source/gfx.cpp +++ b/source/gfx.cpp @@ -25,6 +25,7 @@ */ #include "common.hpp" +#include "gfx.hpp" extern bool isScriptSelected; extern u32 barColor; diff --git a/source/screens/mainMenu.cpp b/source/screens/mainMenu.cpp index ae143de..2329fff 100644 --- a/source/screens/mainMenu.cpp +++ b/source/screens/mainMenu.cpp @@ -27,6 +27,7 @@ #include "config.hpp" #include "ftpScreen.hpp" #include "mainMenu.hpp" +#include "scriptHelper.hpp" #include "scriptlist.hpp" #include "settings.hpp" #include "unistore.hpp" @@ -35,6 +36,7 @@ extern bool exiting; extern bool touching(touchPosition touch, Structs::ButtonPos button); extern int fadealpha; extern bool fadein; +extern u32 TextColor; void MainMenu::Draw(void) const { GFX::DrawTop(); @@ -126,4 +128,10 @@ void MainMenu::Logic(u32 hDown, u32 hHeld, touchPosition touch) { Gui::setScreen(std::make_unique()); } } + + /* That was a test. + if (hDown & KEY_X) { + TextColor = Config::TxtColor; + ScriptHelper::downloadRelease("Universal-Team/extras", "Universal-Updater.3dsx", "/3ds/Universal-Updater.3dsx", true, true, "Downloading Universal-Updater..."); + }*/ } \ No newline at end of file diff --git a/source/screens/scriptlist.cpp b/source/screens/scriptlist.cpp index f7ba35e..34f0da5 100644 --- a/source/screens/scriptlist.cpp +++ b/source/screens/scriptlist.cpp @@ -907,7 +907,7 @@ void ScriptList::runFunctions(nlohmann::json &json) { if(!missing) ScriptHelper::downloadFile(file, output, message); } else if(type == "downloadRelease") { - bool missing = false, includePrereleases = false; + bool missing = false, includePrereleases = false, showVersions = false; std::string repo, file, output, message; if(json.at(choice).at(i).contains("repo")) repo = json.at(choice).at(i).at("repo"); else missing = true; @@ -917,8 +917,10 @@ void ScriptList::runFunctions(nlohmann::json &json) { else missing = true; if(json.at(choice).at(i).contains("includePrereleases") && json.at(choice).at(i).at("includePrereleases").is_boolean()) includePrereleases = json.at(choice).at(i).at("includePrereleases"); + if(json.at(choice).at(i).contains("showVersions") && json.at(choice).at(i).at("showVersions").is_boolean()) + showVersions = json.at(choice).at(i).at("showVersions"); if(json.at(choice).at(i).contains("message")) message = json.at(choice).at(i).at("message"); - if(!missing) ScriptHelper::downloadRelease(repo, file, output, includePrereleases, message); + if(!missing) ScriptHelper::downloadRelease(repo, file, output, includePrereleases, showVersions, message); } else if(type == "extractFile") { bool missing = false; diff --git a/source/screens/unistore.cpp b/source/screens/unistore.cpp index c72a768..17c50f4 100644 --- a/source/screens/unistore.cpp +++ b/source/screens/unistore.cpp @@ -1239,7 +1239,7 @@ void UniStore::execute() { if(!missing) ScriptHelper::downloadFile(file, output, message); } else if(type == "downloadRelease") { - bool missing = false, includePrereleases = false; + bool missing = false, includePrereleases = false, showVersions = false; std::string repo, file, output, message; if(appStoreJson.at("storeContent").at(Selection).at("script").at(i).contains("repo")) repo = appStoreJson.at("storeContent").at(Selection).at("script").at(i).at("repo"); else missing = true; @@ -1249,8 +1249,10 @@ void UniStore::execute() { else missing = true; if(appStoreJson.at("storeContent").at(Selection).at("script").at(i).contains("includePrereleases") && appStoreJson.at("storeContent").at(Selection).at("script").at(i).at("includePrereleases").is_boolean()) includePrereleases = appStoreJson.at(Selection).at("script").at(i).at("includePrereleases"); + if(appStoreJson.at("storeContent").at(Selection).at("script").at(i).contains("showVersions") && appStoreJson.at("storeContent").at(Selection).at("script").at(i).at("showVersions").is_boolean()) + showVersions = appStoreJson.at(Selection).at("script").at(i).at("showVersions"); if(appStoreJson.at("storeContent").at(Selection).at("script").at(i).contains("message")) message = appStoreJson.at("storeContent").at(Selection).at("script").at(i).at("message"); - if(!missing) ScriptHelper::downloadRelease(repo, file, output, includePrereleases, message); + if(!missing) ScriptHelper::downloadRelease(repo, file, output, includePrereleases, showVersions, message); } else if(type == "extractFile") { bool missing = false; diff --git a/source/utils/scriptHelper.cpp b/source/utils/scriptHelper.cpp index 811d43b..8eb4dd6 100644 --- a/source/utils/scriptHelper.cpp +++ b/source/utils/scriptHelper.cpp @@ -66,12 +66,8 @@ int ScriptHelper::getNum(nlohmann::json json, const std::string &key, const std: } // Download from a Github Release. -void ScriptHelper::downloadRelease(std::string repo, std::string file, std::string output, bool includePrereleases, std::string message) { - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; - progressBarType = 0; - Threads::create((ThreadFunc)displayProgressBar); - if (downloadFromRelease("https://github.com/" + repo, file, output, includePrereleases) != 0) { +void ScriptHelper::downloadRelease(std::string repo, std::string file, std::string output, bool includePrereleases, bool showVersions, std::string message) { + if (downloadFromRelease("https://github.com/" + repo, file, output, message, includePrereleases, showVersions) != 0) { showProgressBar = false; downloadFailed(); return;