diff --git a/Makefile b/Makefile
index 4ac18ab..ab207fe 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ DATA := data
INCLUDES := include /lib/borealis/library/include/borealis/extern/nlohmann
APP_TITLE := All-in-One Switch Updater
APP_AUTHOR := HamletDuFromage
-APP_VERSION := 2.19.3
+APP_VERSION := 2.20.0
TARGET := $(notdir $(CURDIR))
ROMFS := resources
diff --git a/README.md b/README.md
index ea75d8e..ba61462 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
-A Nintendo Switch homebrew app to download and update CFWs, sigpatches, FWs and cheat codes. Supports Atmosphère, ReiNX and SXOS.
+A Nintendo Switch homebrew app to download and update CFWs, FWs and cheat codes. Supports Atmosphère, ReiNX and SXOS.
Works on **unpatched** (Erista) and **patched** (v2/Mariko) Switches.
@@ -27,13 +27,12 @@ Copy the `aio-switch-updater/` directory to `/switch/` on your sdcard.
- Update the Atmosphère Switch Custom Firmware. AIO-Switch-Updater uses a custom RCM payload to finalise the install as it can't be performed while HOS is running.
- If you would like to preserve additional files or directories, write their path (one line each) in `/config/aio-switch-updater/preserve.txt` and they won't be overwritten when updating.
- Place [this file](https://github.com/HamletDuFromage/aio-switch-updater/blob/master/copy_files.txt) in `/config/aio-switch-updater/copy_files.txt` in order to have specific copy operations performed after each download. This is mainly meant for users with trinkets who want payloads automatically copied to a directory.
- - A custom Atmosphère url can be entered in [this file](https://github.com/HamletDuFromage/aio-switch-updater/blob/master/customPacks.json). Once moved to `/config/aio-switch-updater/customPacks.json`, it will show on the `Update Atmopshère` menu. This can be used to support third-party packs through AIO-Switch-Updater
### ⬦ Update Hekate/Payload
- Download and update Hekate, as well as a selection of RCM payloads
-### ⬦ Update Sigpatches
-- Dowload sigpatches, which are patches required to launch homebrew .NSPs on the Atmosphère CFW.
+### ⬦ Custom Downloads
+- A custom Atmosphère url can be entered in [this file](https://github.com/HamletDuFromage/aio-switch-updater/blob/master/custom_packs.json). Once moved to `/config/aio-switch-updater/custom_packs.json`, it will show on the `Custom Download` menu. This can be used to support third-party packs through AIO-Switch-Updater. Non-Atmosphère downloads can also be added in the `misc` category.
### ⬦ Download firmwares
- Download firmware files to `/firmware` that can then be installed using DayBreak.
diff --git a/customPacks.json b/customPacks.json
deleted file mode 100644
index a138a50..0000000
--- a/customPacks.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "Name of pack": "link_to_zip",
- "Name of anther pack": "link_to_zip"
-}
\ No newline at end of file
diff --git a/custom_packs.json b/custom_packs.json
new file mode 100644
index 0000000..2413b12
--- /dev/null
+++ b/custom_packs.json
@@ -0,0 +1,9 @@
+{
+ "ams": {
+ "Name of Atmosphère pack": "link_to_zip",
+ "Name of anther pack": "link_to_zip"
+ },
+ "misc": {
+ "name of download": "link"
+ }
+}
\ No newline at end of file
diff --git a/hide_tabs.json b/hide_tabs.json
index d2813c0..0392cb2 100644
--- a/hide_tabs.json
+++ b/hide_tabs.json
@@ -5,7 +5,6 @@
"cfw": true,
"cheats": true,
"firmwares": true,
- "sigpatches": true,
"jccolor": true,
"pccolor": true,
"downloadpayload": true,
diff --git a/include/ams_tab.hpp b/include/ams_tab.hpp
index a04490a..f288bf9 100644
--- a/include/ams_tab.hpp
+++ b/include/ams_tab.hpp
@@ -4,23 +4,24 @@
#include
#include
+#include "constants.hpp"
+
class AmsTab : public brls::List
{
private:
brls::ListItem* listItem;
- brls::Label* description;
- int size = 0;
bool erista;
+ contentType type;
nlohmann::ordered_json hekate;
std::string GetRepoName(const std::string& repo);
std::set GetLastDownloadedModules(const std::string& json_path);
- void CreateStagedFrames(const std::string& text, const std::string& url, const std::string& operation, bool erista, bool hekate = false, const std::string& text_hekate = "", const std::string& hekate_url = "");
- void CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate = true);
+ void CreateStagedFrames(const std::string& text, const std::string& url, bool erista, bool ams = true, bool hekate = false, const std::string& text_hekate = "", const std::string& hekate_url = "");
+ void CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate = true, bool ams = true);
nlohmann::ordered_json SortDeepseaModules(const nlohmann::ordered_json& modules);
void ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules);
public:
- AmsTab(const nlohmann::json& nxlinks, const bool erista = true, const bool hideStandardEntries = false);
+ AmsTab(const nlohmann::json& nxlinks, const bool erista = true, const bool custom = false);
};
class UnTogglableListItem : public brls::ToggleListItem
diff --git a/include/constants.hpp b/include/constants.hpp
index b4768bc..c48b09f 100644
--- a/include/constants.hpp
+++ b/include/constants.hpp
@@ -18,7 +18,6 @@ constexpr const char APP_FILENAME[] = "/config/aio-switch-updater/app.zip";
constexpr const char NXLINKS_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/nx-links.json";
-constexpr const char SIGPATCHES_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/sigpatches.json";
constexpr const char SIGPATCHES_FILENAME[] = "/config/aio-switch-updater/sigpatches.zip";
constexpr const char HEKATE_IPL_PATH[] = "/bootloader/hekate_ipl.ini";
@@ -41,7 +40,7 @@ constexpr const char DEEPSEA_META_JSON[] = "https://builder.teamneptune.net/meta
constexpr const char DEEPSEA_BUILD_URL[] = "https://builder.teamneptune.net/build/";
constexpr const char DEEPSEA_PACKAGE_PATH[] = "/config/deepsea/customPackage.json";
-constexpr const char CUSTOM_PACKS_PATH[] = "/config/aio-switch-updater/customPacks.json";
+constexpr const char CUSTOM_PACKS_PATH[] = "/config/aio-switch-updater/custom_packs.json";
constexpr const char CHEATS_URL_TITLES[] = "https://github.com/HamletDuFromage/switch-cheats-db/releases/latest/download/titles.zip";
constexpr const char CHEATS_URL_CONTENTS[] = "https://github.com/HamletDuFromage/switch-cheats-db/releases/latest/download/contents.zip";
diff --git a/include/list_download_tab.hpp b/include/list_download_tab.hpp
index a4c03cf..e76be5e 100644
--- a/include/list_download_tab.hpp
+++ b/include/list_download_tab.hpp
@@ -13,7 +13,6 @@ private:
std::string currentCheatsVer = "";
std::string newCheatsVer = "";
contentType type;
- int size = 0;
void createList();
void createList(contentType type);
void createCheatSlipItem();
diff --git a/resources/i18n/en-US/menus.json b/resources/i18n/en-US/menus.json
index 1defd78..474dc3a 100644
--- a/resources/i18n/en-US/menus.json
+++ b/resources/i18n/en-US/menus.json
@@ -127,6 +127,7 @@
"new_update": " - New app update available",
"about": "About",
"update_ams": "Update Atmosphère",
+ "custom_downloads": "Custom Downloads",
"update_cfw": "Update CFW",
"update_bootloaders": "Update bootloaders",
"update_sigpatches": "Update sigpatches",
@@ -191,7 +192,10 @@
"cant_fetch_deepsea": "Couldn't fetch packages. Open a Github issue if this persists.",
"build_your_deepsea": "Build your own custom DeepSea package by selecting packages",
"getting_ams": "Getting Atmosphère",
- "custom_packs_label": "\u25c6 Here are packs listed in the {} file. Be aware that those are not endorsed by AIO-Switch-Updater so make sure you trust their source."
+ "custom_packs_label": "\u25c6 Here are packs listed in the {} file. Be aware that those are not endorsed by AIO-Switch-Updater so make sure you trust their source.",
+ "custom_packs_ams": "\u25c6 Downloads containing the Atmosphère custom firmware.",
+ "custom_packs_misc": "\u25c6 Downloads containing homebrew and tools.",
+ "custom_download" : "Custom Download"
},
"firmware": {
"launch_daybreak": "Do you want to launch Daybreak to install the downloaded sysupdate?"
diff --git a/source/ams_tab.cpp b/source/ams_tab.cpp
index ea42110..5de61a0 100644
--- a/source/ams_tab.cpp
+++ b/source/ams_tab.cpp
@@ -15,22 +15,22 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
-AmsTab::AmsTab(const nlohmann::json& nxlinks, const bool erista, const bool hideStandardEntries) : brls::List()
+AmsTab::AmsTab(const nlohmann::json& nxlinks, const bool erista, const bool custom) : brls::List()
{
this->erista = erista;
this->hekate = util::getValueFromKey(nxlinks, "hekate");
- auto cfws = util::getValueFromKey(nxlinks, "cfws");
- if (!hideStandardEntries) {
- this->description = new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/main/ams_text"_i18n + (CurrentCfw::running_cfw == CFW::ams ? "\n" + "menus/ams_update/current_ams"_i18n + CurrentCfw::getAmsInfo() : "") + (erista ? "\n" + "menus/ams_update/erista_rev"_i18n : "\n" + "menus/ams_update/mariko_rev"_i18n), true);
- this->addView(description);
+ if (!custom) {
+ this->type = contentType::ams_cfw;
+ auto cfws = util::getValueFromKey(nxlinks, "cfws");
+
+ this->addView(new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/main/ams_text"_i18n + (CurrentCfw::running_cfw == CFW::ams ? "\n" + "menus/ams_update/current_ams"_i18n + CurrentCfw::getAmsInfo() : "") + (erista ? "\n" + "menus/ams_update/erista_rev"_i18n : "\n" + "menus/ams_update/mariko_rev"_i18n), true));
CreateDownloadItems(util::getValueFromKey(cfws, "Atmosphere"));
- description = new brls::Label(
+ this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/deepsea_label"_i18n,
- true);
- this->addView(description);
+ true));
listItem = new brls::ListItem("menus/ams_update/get_custom_deepsea"_i18n);
listItem->setHeight(LISTITEM_HEIGHT);
@@ -40,25 +40,36 @@ AmsTab::AmsTab(const nlohmann::json& nxlinks, const bool erista, const bool hide
this->ShowCustomDeepseaBuilder(modules);
});
this->addView(listItem);
-
CreateDownloadItems(util::getValueFromKey(cfws, "DeepSea"), false);
}
- auto custom_pack = fs::parseJsonFile(CUSTOM_PACKS_PATH);
- if (custom_pack.size() != 0) {
- description = new brls::Label(
+ else {
+ auto custom_pack = fs::parseJsonFile(CUSTOM_PACKS_PATH);
+ this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
fmt::format("menus/ams_update/custom_packs_label"_i18n, CUSTOM_PACKS_PATH),
- true);
- this->addView(description);
-
- CreateDownloadItems(cfws.size() ? custom_pack : nlohmann::ordered_json::object(), true); // TODO: better way to check for availability of the links
+ true));
+ if (custom_pack.contains("ams") && custom_pack["ams"].size() != 0) {
+ this->type = contentType::ams_cfw;
+ this->addView(new brls::Label(
+ brls::LabelStyle::DESCRIPTION,
+ "menus/ams_update/custom_packs_ams"_i18n,
+ true));
+ CreateDownloadItems(custom_pack["ams"], true); // TODO: check for internet
+ }
+ if (custom_pack.contains("misc") && custom_pack["misc"].size() != 0) {
+ this->type = contentType::bootloaders;
+ this->addView(new brls::Label(
+ brls::LabelStyle::DESCRIPTION,
+ "menus/ams_update/custom_packs_misc"_i18n,
+ true));
+ CreateDownloadItems(custom_pack["misc"], false, false);
+ }
}
}
-void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate)
+void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate, bool ams)
{
- std::string operation("menus/ams_update/getting_ams"_i18n);
std::vector> links;
links = download::getLinksFromJson(cfw_links);
if (links.size()) {
@@ -71,19 +82,19 @@ void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool h
std::string text("menus/common/download"_i18n + link.first + "menus/common/from"_i18n + url);
listItem = new brls::ListItem(link.first);
listItem->setHeight(LISTITEM_HEIGHT);
- listItem->getClickEvent()->subscribe([this, text, text_hekate, url, hekate_url, operation, hekate](brls::View* view) {
+ listItem->getClickEvent()->subscribe([this, text, text_hekate, url, hekate_url, hekate, ams](brls::View* view) {
if (!erista && !std::filesystem::exists(MARIKO_PAYLOAD_PATH)) {
brls::Application::crash("menus/errors/mariko_payload_missing"_i18n);
}
else {
- CreateStagedFrames(text, url, operation, erista, hekate, text_hekate, hekate_url);
+ CreateStagedFrames(text, url, erista, ams, hekate, text_hekate, hekate_url);
}
});
this->addView(listItem);
}
}
else {
- description = new brls::Label(
+ brls::Label* description = new brls::Label(
brls::LabelStyle::SMALL,
"menus/main/links_not_found"_i18n,
true);
@@ -92,16 +103,16 @@ void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool h
}
}
-void AmsTab::CreateStagedFrames(const std::string& text, const std::string& url, const std::string& operation, bool erista, bool hekate, const std::string& text_hekate, const std::string& hekate_url)
+void AmsTab::CreateStagedFrames(const std::string& text, const std::string& url, bool erista, bool ams, bool hekate, const std::string& text_hekate, const std::string& hekate_url)
{
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
- stagedFrame->setTitle(operation);
+ stagedFrame->setTitle(this->type == contentType::ams_cfw ? "menus/ams_update/getting_ams"_i18n : "menus/ams_update/custom_download"_i18n);
stagedFrame->addStage(
new ConfirmPage(stagedFrame, text));
stagedFrame->addStage(
- new WorkerPage(stagedFrame, "menus/common/downloading"_i18n, [url]() { util::downloadArchive(url, contentType::ams_cfw); }));
+ new WorkerPage(stagedFrame, "menus/common/downloading"_i18n, [&, url]() { util::downloadArchive(url, this->type); }));
stagedFrame->addStage(
- new WorkerPage(stagedFrame, "menus/common/extracting"_i18n, []() { util::extractArchive(contentType::ams_cfw); }));
+ new WorkerPage(stagedFrame, "menus/common/extracting"_i18n, [&]() { util::extractArchive(this->type); }));
if (hekate) {
stagedFrame->addStage(
new DialoguePage_ams(stagedFrame, text_hekate, erista));
@@ -110,8 +121,10 @@ void AmsTab::CreateStagedFrames(const std::string& text, const std::string& url,
stagedFrame->addStage(
new WorkerPage(stagedFrame, "menus/common/extracting"_i18n, []() { util::extractArchive(contentType::bootloaders); }));
}
- stagedFrame->addStage(
- new ConfirmPage(stagedFrame, "menus/ams_update/reboot_rcm"_i18n, false, true, erista));
+ if (ams)
+ stagedFrame->addStage(new ConfirmPage(stagedFrame, "menus/ams_update/reboot_rcm"_i18n, false, true, erista));
+ else
+ stagedFrame->addStage(new ConfirmPage(stagedFrame, "menus/common/all_done"_i18n, true));
brls::Application::pushView(stagedFrame);
}
@@ -207,7 +220,6 @@ void AmsTab::ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules)
this->CreateStagedFrames("menus/common/download"_i18n + "Custom DeepSea package" + "menus/common/from"_i18n + request_url,
request_url,
- "menus/ams_update/get_custom_deepsea"_i18n,
this->erista);
return true;
});
diff --git a/source/changelog_page.cpp b/source/changelog_page.cpp
index 73e3635..1c1eda8 100644
--- a/source/changelog_page.cpp
+++ b/source/changelog_page.cpp
@@ -249,6 +249,10 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true)
verTitles.push_back("v2.19.3");
changes.push_back("\uE016 Fix wrong bid for titles overriden by HBL.\n\uE016 Improve Korean localisation (https://github.com/DDinghoya).\n\uE016 Improve Italian localisation (https://github.com/clamintus).");
+ verTitles.push_back("v2.20.0");
+ changes.push_back("\uE016 Significantly increase extraction speed (https://github.com/PoloNX).\n\uE016 Create a \"Custom Downloads\" tab that supports user-provided links for Atmosphère packs as well as regular downloads.");
+
+
for (int i = verTitles.size() - 1; i >= 0; i--) {
listItem = new brls::ListItem(verTitles[i]);
change = changes[i];
diff --git a/source/extract.cpp b/source/extract.cpp
index f209bd9..eab3b76 100644
--- a/source/extract.cpp
+++ b/source/extract.cpp
@@ -53,9 +53,8 @@ namespace extract {
return size; // in B
}
- void preWork(const std::string& archivePath, const std::string& workingPath)
+ void ensureAvailableStorage(const std::string& archivePath)
{
- chdir(workingPath.c_str());
s64 uncompressedSize = getUncompressedSize(archivePath);
s64 freeStorage;
@@ -91,7 +90,7 @@ namespace extract {
void extract(const std::string& archivePath, const std::string& workingPath, int overwriteInis, std::function func)
{
- preWork(archivePath, workingPath);
+ ensureAvailableStorage(archivePath);
unzFile zfile = unzOpen(archivePath.c_str());
unz_global_info gi;
@@ -107,28 +106,28 @@ namespace extract {
char szFilename[0x301] = "";
unzOpenCurrentFile(zfile);
unzGetCurrentFileInfo(zfile, NULL, szFilename, sizeof(szFilename), NULL, 0, NULL, 0);
- std::string filename = szFilename;
+ std::string filename = workingPath + szFilename;
if (ProgressEvent::instance().getInterupt()) {
unzCloseCurrentFile(zfile);
break;
}
- if (appPath != workingPath + filename) {
- if ((overwriteInis == 0 && filename.substr(filename.length() - 4) == ".ini") || std::find_if(ignoreList.begin(), ignoreList.end(), [&filename, &workingPath](std::string ignored) {
- u8 res = (workingPath + filename).find(ignored);
+ if (appPath != filename) {
+ if ((overwriteInis == 0 && filename.substr(filename.length() - 4) == ".ini") || std::find_if(ignoreList.begin(), ignoreList.end(), [&filename](std::string ignored) {
+ u8 res = (filename).find(ignored);
return (res == 0 || res == 1); }) != ignoreList.end()) {
- if (!std::filesystem::exists(workingPath + filename)) {
+ if (!std::filesystem::exists(filename)) {
extractEntry(filename, zfile);
}
}
else {
- if ((filename == "atmosphere/package3") || (filename == "atmosphere/stratosphere.romfs")) {
+ if ((filename == "/atmosphere/package3") || (filename == "/atmosphere/stratosphere.romfs")) {
extractEntry(filename + ".aio", zfile);
}
else {
extractEntry(filename, zfile);
if (filename.substr(0, 13) == "hekate_ctcaer") {
- fs::copyFile(workingPath + filename, UPDATE_BIN_PATH);
+ fs::copyFile(filename, UPDATE_BIN_PATH);
if (CurrentCfw::running_cfw == CFW::ams && util::showDialogBoxBlocking(fmt::format("menus/utils/set_hekate_reboot_payload"_i18n, UPDATE_BIN_PATH, REBOOT_PAYLOAD_PATH), "menus/common/yes"_i18n, "menus/common/no"_i18n) == 0) {
fs::copyFile(UPDATE_BIN_PATH, REBOOT_PAYLOAD_PATH);
}
@@ -235,7 +234,7 @@ namespace extract {
void extractCheats(const std::string& archivePath, const std::vector& titles, CFW cfw, const std::string& version, bool extractAll)
{
- preWork(archivePath, "/");
+ ensureAvailableStorage(archivePath);
unzFile zfile = unzOpen(archivePath.c_str());
unz_global_info gi;
diff --git a/source/main_frame.cpp b/source/main_frame.cpp
index de26e9c..1c2bd7b 100644
--- a/source/main_frame.cpp
+++ b/source/main_frame.cpp
@@ -41,20 +41,20 @@ MainFrame::MainFrame() : TabFrame()
this->addTab("menus/main/about"_i18n, new AboutTab());
if (!util::getBoolValue(hideStatus, "atmosphere"))
- this->addTab("menus/main/update_ams"_i18n, new AmsTab(nxlinks, erista, util::getBoolValue(hideStatus, "atmosphereentries")));
+ this->addTab("menus/main/update_ams"_i18n, new AmsTab(nxlinks, erista, false));
if (!util::getBoolValue(hideStatus, "cfw"))
this->addTab("menus/main/update_bootloaders"_i18n, new ListDownloadTab(contentType::bootloaders, nxlinks));
- if (!util::getBoolValue(hideStatus, "sigpatches"))
- this->addTab("menus/main/update_sigpatches"_i18n, new ListDownloadTab(contentType::sigpatches, nxlinks));
-
if (!util::getBoolValue(hideStatus, "firmwares"))
this->addTab("menus/main/download_firmware"_i18n, new ListDownloadTab(contentType::fw, nxlinks));
if (!util::getBoolValue(hideStatus, "cheats"))
this->addTab("menus/main/download_cheats"_i18n, new ListDownloadTab(contentType::cheats));
+ if (!util::getBoolValue(hideStatus, "custom"))
+ this->addTab("menus/main/custom_downloads"_i18n, new AmsTab(nxlinks, erista, true));
+
if (!util::getBoolValue(hideStatus, "tools"))
this->addTab("menus/main/tools"_i18n, new ToolsTab(tag, util::getValueFromKey(nxlinks, "payloads"), erista, hideStatus));