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:
parent
5b0e8096c1
commit
2d545017ee
18 changed files with 204 additions and 55 deletions
2
Makefile
2
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
|
||||
|
|
38
README.md
38
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
|
||||
<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
17
include/choice_page.hpp
Normal 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;
|
||||
};
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -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
50
source/choice_page.cpp
Normal 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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++){
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -31,7 +31,9 @@ ToolsTab::ToolsTab() : brls::List()
|
|||
});
|
||||
this->addView(JCcolor);
|
||||
|
||||
updateApp = new brls::ListItem("Update the app");
|
||||
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();
|
||||
|
@ -51,6 +53,7 @@ ToolsTab::ToolsTab() : brls::List()
|
|||
brls::Application::pushView(stagedFrame);
|
||||
});
|
||||
this->addView(updateApp);
|
||||
}
|
||||
|
||||
rebootPayload = new brls::ListItem("Shut down / Inject payload");
|
||||
rebootPayload->getClickEvent()->subscribe([&](brls::View* view){
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue