1
0
Fork 0
mirror of https://github.com/HamletDuFromage/aio-switch-updater.git synced 2025-01-30 18:13:47 +00:00

Added possibility to conserve existing .ini when updating CFW. Other minor bug fixes

This commit is contained in:
flb 2020-09-20 22:58:40 +02:00
parent 5b0e8096c1
commit 2d545017ee
18 changed files with 204 additions and 55 deletions

View file

@ -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

View file

@ -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
<p align="center">
@ -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
<div class="flex-container" style=" display: flex; flex-direction: row;">
<div><img src = "https://user-images.githubusercontent.com/61667930/93691403-30fb2e80-fad4-11ea-9701-7992a1de53e0.jpg"\></div>
</div>
<div class="flex-container" style=" display: flex; flex-direction: row;">
<div><img src = "https://user-images.githubusercontent.com/61667930/93691404-3193c500-fad4-11ea-9647-927c979960bc.jpg"\></div>
<div><img src = "https://user-images.githubusercontent.com/61667930/93691405-3193c500-fad4-11ea-960d-b68d413aedd4.jpg"\></div>
</div>
<div class="flex-container" style=" display: flex; flex-direction: row;">
<div><img src = "https://user-images.githubusercontent.com/61667930/93691407-322c5b80-fad4-11ea-8879-78047724d9e7.jpg"\></div>
<div><img src = "https://user-images.githubusercontent.com/61667930/93691465-16758500-fad5-11ea-8a5c-c0f9694cfb0e.jpg"\></div>
</div>
![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

17
include/choice_page.hpp Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <borealis.hpp>
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;
};

View file

@ -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();

View file

@ -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"

View file

@ -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<std::string>, std::vector<std::string>> fetchLinks(const char *url);
std::string fetchTitle(const char *url);
#endif
std::string downloadPage(const char* url);

View file

@ -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<Title> getInstalledTitlesNs();
std::vector<Title> excludeTitles(const char* path, std::vector<Title> listedTitles);

View file

@ -7,6 +7,7 @@
#include "extract.hpp"
#include "constants.hpp"
#include "progress_event.hpp"
#include "json.hpp"
CFW getCFW();
bool isServiceRunning(const char *serviceName);
@ -22,3 +23,4 @@ std::string formatApplicationId(u64 ApplicationId);
std::set<std::string> readLineByLine(const char * path);
std::vector<std::string> fetchPayloads();
void shut_down(bool reboot = false);
std::string getLatestTag(const char *url);

50
source/choice_page.cpp Normal file
View file

@ -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();
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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){

View file

@ -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);
}
@ -165,3 +187,15 @@ void shut_down(bool reboot){
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 "";
}
}

View file

@ -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);