From 2d545017eec2a3d21205ebbc4648e04593a72da2 Mon Sep 17 00:00:00 2001 From: flb Date: Sun, 20 Sep 2020 22:58:40 +0200 Subject: [PATCH] Added possibility to conserve existing .ini when updating CFW. Other minor bug fixes --- Makefile | 2 +- README.md | 38 +++++++++----- include/choice_page.hpp | 17 +++++++ include/confirm_page.hpp | 2 +- include/constants.hpp | 1 + include/download.hpp | 8 +-- include/extract.hpp | 2 +- include/utils.hpp | 4 +- ...alis_and_minizip => borealis_and_unzipper} | 0 source/choice_page.cpp | 50 +++++++++++++++++++ source/confirm_page.cpp | 5 +- source/download.cpp | 33 ++++++++++-- source/extract.cpp | 10 +++- source/main.cpp | 2 +- source/payload_page.cpp | 2 +- source/tools_tab.cpp | 43 ++++++++-------- source/utils.cpp | 38 +++++++++++++- source/worker_page.cpp | 2 +- 18 files changed, 204 insertions(+), 55 deletions(-) create mode 100644 include/choice_page.hpp rename lib/{borealis_and_minizip => borealis_and_unzipper} (100%) create mode 100644 source/choice_page.cpp diff --git a/Makefile b/Makefile index eea6d5e..bd6e7f5 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ DATA := data INCLUDES := include lib/minizip/include APP_TITLE := AIO Switch Updater APP_AUTHOR := HamletDuFromage -APP_VERSION := 1.0 +APP_VERSION := 1.0.1 #ROMFS := $(BUILD)/romfs BOREALIS_PATH := lib/borealis diff --git a/README.md b/README.md index faabfdd..826c0d6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # AIO-switch-updater ![releases](https://img.shields.io/github/downloads/HamletDuFromage/AIO-switch-updater/total) +![tag](https://img.shields.io/github/v/release/HamletDuFromage/AIO-switch-updater) +![GitHub](https://img.shields.io/github/license/HamletDuFromage/aio-switch-updater) +[![ko-fi](https://img.shields.io/badge/ko--fi-buy%20me%20a%20coffee-ff69b4)](https://ko-fi.com/hamletdufromage) + All-in-One Nintendo Switch Updater

@@ -15,21 +19,31 @@ Copy the `aio-switch-updater/` directory to `/switch/` in your sdcard ## Extras -This app can also reboot to specific payload and change software color scheme of Joy-Cons +This app can also reboot to specific payload and change software color scheme of Joy-Cons. + +## Description of the features +### - Update CFW +Download the most popular Switch CFWs. After downloading the CFW archive, the program will ask you whether you want to override your existing .ini files. + +### - Update Sigpatches +For Atmosphere. Downloads sigpatches, which are patches required for launching unofficial .NSPs. Both AMS and Hekate+AMS sigpatches are available. + +### -Download firmares +Download firmare files to `/firmware` that can then be installed using DayBreak or ChoiDuJour. + +### - Download cheats +Downloads and extracts daily-updated cheat code. The program will only extract cheat codes for the games you own. + ## Screenshots -

-
-
-
-
-
-
-
-
-
-
+![ss](https://user-images.githubusercontent.com/61667930/93691403-30fb2e80-fad4-11ea-9701-7992a1de53e0.jpg) +![ss](https://user-images.githubusercontent.com/61667930/93691404-3193c500-fad4-11ea-9647-927c979960bc.jpg) +![ss](https://user-images.githubusercontent.com/61667930/93721670-42e6db00-fb81-11ea-9f94-1308898398f0.jpg) +![ss](https://user-images.githubusercontent.com/61667930/93721673-437f7180-fb81-11ea-9256-377575148a40.jpg) +![ss](https://user-images.githubusercontent.com/61667930/93691407-322c5b80-fad4-11ea-8879-78047724d9e7.jpg) +![ss](https://user-images.githubusercontent.com/61667930/93691465-16758500-fad5-11ea-8a5c-c0f9694cfb0e.jpg) + ## Disclaimer diff --git a/include/choice_page.hpp b/include/choice_page.hpp new file mode 100644 index 0000000..d137022 --- /dev/null +++ b/include/choice_page.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +class ChoicePage: public brls::View +{ + private: + brls::Button* yes = nullptr; + brls::Button* no = nullptr; + brls::Label* label = nullptr; + + public: + ChoicePage(brls::StagedAppletFrame* frame, std::string text); + void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override; + void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override; + brls::View* getDefaultFocus() override; +}; \ No newline at end of file diff --git a/include/confirm_page.hpp b/include/confirm_page.hpp index b0cf6bb..7c78a7e 100644 --- a/include/confirm_page.hpp +++ b/include/confirm_page.hpp @@ -10,7 +10,7 @@ class ConfirmPage : public brls::View { - private: + private: brls::Button* button = nullptr; brls::Label* label = nullptr; std::chrono::system_clock::time_point start = std::chrono::high_resolution_clock::now(); diff --git a/include/constants.hpp b/include/constants.hpp index 914765b..e92d337 100644 --- a/include/constants.hpp +++ b/include/constants.hpp @@ -5,6 +5,7 @@ #define CONFIG_PATH "/config/aio-switch-updater/" #define APP_URL "https://github.com/HamletDuFromage/aio-switch-updater/releases/latest/download/aio-switch-updater.zip" +#define TAGS_INFO "https://api.github.com/repos/HamletDuFromage/aio-switch-updater/tags" #define APP_FILENAME "/config/aio-switch-updater/app.zip" #define SIGPATCHES_URL "https://hamletdufromage.github.io/sigpatches-updater/sigpatches.html" diff --git a/include/download.hpp b/include/download.hpp index f9c312c..5450591 100644 --- a/include/download.hpp +++ b/include/download.hpp @@ -1,8 +1,5 @@ #pragma once -#ifndef _DOWNLOAD_H_ -#define _DOWNLOAD_H_ - #define ON 1 #define OFF 0 @@ -24,9 +21,6 @@ #include "progress_event.hpp" void downloadFile(const char *url, const char *output, int api); - std::tuple, std::vector> fetchLinks(const char *url); - std::string fetchTitle(const char *url); - -#endif \ No newline at end of file +std::string downloadPage(const char* url); \ No newline at end of file diff --git a/include/extract.hpp b/include/extract.hpp index 26675c6..13349ce 100644 --- a/include/extract.hpp +++ b/include/extract.hpp @@ -38,7 +38,7 @@ typedef struct Title { } } Title; -void extract(const char* filename, const char* workingPath = ROOT_PATH); +void extract(const char* filename, const char* workingPath = ROOT_PATH, int overwriteInis = 0); std::string formatApplicationId(u64 ApplicationId); std::vector getInstalledTitlesNs(); std::vector<Title> excludeTitles(const char* path, std::vector<Title> listedTitles); diff --git a/include/utils.hpp b/include/utils.hpp index 459fc80..6449861 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -7,6 +7,7 @@ #include "extract.hpp" #include "constants.hpp" #include "progress_event.hpp" +#include "json.hpp" CFW getCFW(); bool isServiceRunning(const char *serviceName); @@ -21,4 +22,5 @@ std::string formatListItemTitle(const std::string str, size_t maxScore = 140); std::string formatApplicationId(u64 ApplicationId); std::set<std::string> readLineByLine(const char * path); std::vector<std::string> fetchPayloads(); -void shut_down(bool reboot = false); \ No newline at end of file +void shut_down(bool reboot = false); +std::string getLatestTag(const char *url); \ No newline at end of file diff --git a/lib/borealis_and_minizip b/lib/borealis_and_unzipper similarity index 100% rename from lib/borealis_and_minizip rename to lib/borealis_and_unzipper diff --git a/source/choice_page.cpp b/source/choice_page.cpp new file mode 100644 index 0000000..b16335f --- /dev/null +++ b/source/choice_page.cpp @@ -0,0 +1,50 @@ + #include "choice_page.hpp" + + ChoicePage::ChoicePage(brls::StagedAppletFrame* frame, std::string text) + { + this->yes = (new brls::Button(brls::ButtonStyle::BORDERLESS))->setLabel("yes"); + this->yes->setParent(this); + this-> no = (new brls::Button(brls::ButtonStyle::BORDERLESS))->setLabel("no"); + this->no->setParent(this); + + this->label = new brls::Label(brls::LabelStyle::DIALOG, text, true); + this->label->setHorizontalAlign(NVG_ALIGN_CENTER); + this->label->setParent(this); + + } + + void ChoicePage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) +{ + +} + +brls::View* ChoicePage::getDefaultFocus() +{ + return this->no; +} + +void ChoicePage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) +{ + this->label->setWidth(this->width); + this->label->invalidate(true); + + this->label->setBoundaries( + this->x + this->width / 2 - this->label->getWidth() / 2, + this->y + (this->height - this->label->getHeight() - this->y - style->CrashFrame.buttonHeight)/2, + this->label->getWidth(), + this->label->getHeight()); + + this->yes->setBoundaries( + this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2, + this->y + (this->height-style->CrashFrame.buttonHeight*3), + style->CrashFrame.buttonWidth, + style->CrashFrame.buttonHeight); + this->yes->invalidate(); + + this->no->setBoundaries( + this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2, + this->y + (this->height-style->CrashFrame.buttonHeight*3), + style->CrashFrame.buttonWidth, + style->CrashFrame.buttonHeight); + this->no->invalidate(); +} \ No newline at end of file diff --git a/source/confirm_page.cpp b/source/confirm_page.cpp index 3d1bcc3..66fbcc2 100644 --- a/source/confirm_page.cpp +++ b/source/confirm_page.cpp @@ -26,7 +26,7 @@ void ConfirmPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned he { if(!this->done){ auto end = std::chrono::high_resolution_clock::now(); - auto missing = std::max(2l - std::chrono::duration_cast<std::chrono::seconds>(end - start).count(), 0l); + auto missing = std::max(1l - std::chrono::duration_cast<std::chrono::seconds>(end - start).count(), 0l); auto text = std::string("Continue"); if (missing > 0) { this->button->setLabel(text + " (" + std::to_string(missing) + ")"); @@ -37,6 +37,9 @@ void ConfirmPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned he } this->button->invalidate(); } + else{ + this->button->setState(brls::ButtonState::ENABLED); + } this->label->frame(ctx); this->button->frame(ctx); } diff --git a/source/download.cpp b/source/download.cpp index 442a99e..463bb0f 100644 --- a/source/download.cpp +++ b/source/download.cpp @@ -155,11 +155,11 @@ std::tuple<std::vector<std::string>, std::vector<std::string>> fetchLinks(const } std::string fetchTitle(const char *url){ - CURL *curl_handle; - struct MemoryStruct chunk; + CURL *curl_handle; + struct MemoryStruct chunk; - chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */ - chunk.size = 0; /* no data at this point */ + chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */ + chunk.size = 0; /* no data at this point */ curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); @@ -189,3 +189,28 @@ std::string fetchTitle(const char *url){ return ver; } + +std::string downloadPage(const char* url){ + std::string res; + CURL *curl_handle; + struct MemoryStruct chunk; + + chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */ + chunk.size = 0; /* no data at this point */ + + curl_global_init(CURL_GLOBAL_ALL); + curl_handle = curl_easy_init(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback2); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, API_AGENT); + + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_perform(curl_handle); + curl_easy_cleanup(curl_handle); + res = std::string(chunk.memory); + free(chunk.memory); + + curl_global_cleanup(); + return res; +} diff --git a/source/extract.cpp b/source/extract.cpp index 952eb80..1964416 100644 --- a/source/extract.cpp +++ b/source/extract.cpp @@ -1,13 +1,19 @@ #include "extract.hpp" -void extract(const char * filename, const char* workingPath){ +void extract(const char * filename, const char* workingPath, int overwriteInis){ ProgressEvent::instance().reset(); chdir(workingPath); zipper::Unzipper unzipper(filename); std::vector<zipper::ZipEntry> entries = unzipper.entries(); ProgressEvent::instance().setTotalSteps(entries.size()); for (int i = 0; i < (int) entries.size(); i++){ - unzipper.extractEntry(entries[i].name); + if(overwriteInis == 0){ + if(entries[i].name.substr(entries[i].name.length() - 4) != ".ini") + unzipper.extractEntry(entries[i].name); + } + else + unzipper.extractEntry(entries[i].name); + ProgressEvent::instance().setStep(i); } unzipper.close(); diff --git a/source/main.cpp b/source/main.cpp index cba0f8c..5b75f44 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -35,7 +35,7 @@ int main(int argc, char* argv[]) socketInitializeDefault(); nxlinkStdio(); - std::cout << R_SUCCEEDED(splInitialize()) << std::endl; + splInitialize(); createTree(CONFIG_PATH); brls::Logger::setLogLevel(brls::LogLevel::DEBUG); diff --git a/source/payload_page.cpp b/source/payload_page.cpp index 37b64e3..7097276 100644 --- a/source/payload_page.cpp +++ b/source/payload_page.cpp @@ -7,7 +7,7 @@ PayloadPage::PayloadPage() : AppletFrame(true, true) list = new brls::List(); label = new brls::Label( brls::LabelStyle::DESCRIPTION, - "Select a payload to reboot to it.", + "Select a payload to reboot to.", true ); list->addView(label); diff --git a/source/tools_tab.cpp b/source/tools_tab.cpp index d042e56..f8fb9ac 100644 --- a/source/tools_tab.cpp +++ b/source/tools_tab.cpp @@ -31,26 +31,29 @@ ToolsTab::ToolsTab() : brls::List() }); this->addView(JCcolor); - updateApp = new brls::ListItem("Update the app"); - std::string text("Downloading:\nAIO-switch-updater\n\nFrom:\n" + std::string(APP_URL)); - updateApp->getClickEvent()->subscribe([&, text](brls::View* view) { - brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame(); - stagedFrame->setTitle("Updating app"); - stagedFrame->addStage( - new ConfirmPage(stagedFrame, text) - ); - stagedFrame->addStage( - new WorkerPage(stagedFrame, "Downloading...", [](){downloadArchive(APP_URL, app);}) - ); - stagedFrame->addStage( - new WorkerPage(stagedFrame, "Extracting....", [](){extractArchive(app);}) - ); - stagedFrame->addStage( - new ConfirmPage(stagedFrame, "All done!", true) - ); - brls::Application::pushView(stagedFrame); - }); - this->addView(updateApp); + std::string tag = getLatestTag(TAGS_INFO); + if(!tag.empty()){ + updateApp = new brls::ListItem("Update the app (v" + tag +")"); + std::string text("Downloading:\nAIO-switch-updater\n\nFrom:\n" + std::string(APP_URL)); + updateApp->getClickEvent()->subscribe([&, text](brls::View* view) { + brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame(); + stagedFrame->setTitle("Updating app"); + stagedFrame->addStage( + new ConfirmPage(stagedFrame, text) + ); + stagedFrame->addStage( + new WorkerPage(stagedFrame, "Downloading...", [](){downloadArchive(APP_URL, app);}) + ); + stagedFrame->addStage( + new WorkerPage(stagedFrame, "Extracting....", [](){extractArchive(app);}) + ); + stagedFrame->addStage( + new ConfirmPage(stagedFrame, "All done!", true) + ); + brls::Application::pushView(stagedFrame); + }); + this->addView(updateApp); + } rebootPayload = new brls::ListItem("Shut down / Inject payload"); rebootPayload->getClickEvent()->subscribe([&](brls::View* view){ diff --git a/source/utils.cpp b/source/utils.cpp index 0fba0b1..10d8dfb 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -73,8 +73,24 @@ void downloadArchive(std::string url, archiveType type){ } } +int dialogResult = -1; + void extractArchive(archiveType type){ + int overwriteInis = -1; std::vector<Title> titles; + brls::Dialog* dialog = new brls::Dialog("Do you want to overwrite existing .ini files?"); + brls::GenericEvent::Callback noCallback = [dialog](brls::View* view) { + dialogResult = 0; + dialog->close(); + }; + brls::GenericEvent::Callback yesCallback = [dialog](brls::View* view) { + dialogResult = 1; + dialog->close(); + }; + dialog->addButton("No", noCallback); + dialog->addButton("Yes", yesCallback); + dialog->setCancelable(false); + switch(type){ case sigpatches: if(isArchive(SIGPATCHES_FILENAME)) extract(SIGPATCHES_FILENAME); @@ -85,6 +101,7 @@ void extractArchive(archiveType type){ extractCheats(CHEATS_FILENAME, titles, getCFW()); break; case fw: + if (std::filesystem::exists(FIRMWARE_PATH)) std::filesystem::remove_all(FIRMWARE_PATH); createTree(FIRMWARE_PATH); extract(FIRMWARE_FILENAME, FIRMWARE_PATH); break; @@ -92,7 +109,13 @@ void extractArchive(archiveType type){ extract(APP_FILENAME); break; case cfw: - extract(CFW_FILENAME); + dialog->open(); + while(overwriteInis == -1){ + usleep(1); + overwriteInis = dialogResult; + } + dialogResult = -1; + extract(CFW_FILENAME, ROOT_PATH, overwriteInis); break; } } @@ -131,7 +154,6 @@ std::set<std::string> readLineByLine(const char * path){ if(in){ while (std::getline(in, str)) { - // Line contains string of length > 0 then save it in vector if(str.size() > 0) titles.insert(str); } @@ -164,4 +186,16 @@ void shut_down(bool reboot){ if(reboot) bpcRebootSystem(); else bpcShutdownSystem(); bpcExit(); +} + +std::string getLatestTag(const char *url){ + std::string page = downloadPage(url); + try{ + nlohmann::json tags = nlohmann::json::parse(page); + nlohmann::json:: iterator latest = tags.begin(); + return latest.value()["name"]; + } + catch (...){ + return ""; + } } \ No newline at end of file diff --git a/source/worker_page.cpp b/source/worker_page.cpp index 321f8ce..86b80bd 100644 --- a/source/worker_page.cpp +++ b/source/worker_page.cpp @@ -11,13 +11,13 @@ WorkerPage::WorkerPage(brls::StagedAppletFrame* frame, const std::string& text, this->button = new brls::Button(brls::ButtonStyle::BORDERLESS); // avoid back button bug this->button->setParent(this); - appletSetMediaPlaybackState(true); } void WorkerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) { if (!this->workStarted) { + appletSetMediaPlaybackState(true); this->workStarted = true; ProgressEvent::instance().reset(); workerThread = new std::thread(&WorkerPage::doWork, this);