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 excludeTitles(const char* path, std::vector 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 readLineByLine(const char * path);
std::vector 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(end - start).count(), 0l);
+ auto missing = std::max(1l - std::chrono::duration_cast(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> fetchLinks(const
}
std::string fetchTitle(const char *url){
- CURL *curl_handle;
- struct MemoryStruct chunk;
+ CURL *curl_handle;
+ struct MemoryStruct chunk;
- chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */
- chunk.size = 0; /* no data at this point */
+ chunk.memory = static_cast(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(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 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 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 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);