1
0
Fork 0
mirror of https://github.com/HamletDuFromage/aio-switch-updater.git synced 2024-11-24 18:42:05 +00:00

Add Custom Downloads tab

This commit is contained in:
flb 2022-09-06 20:45:26 +02:00
parent 7b34afc414
commit d71dcc1807
13 changed files with 83 additions and 62 deletions

View file

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

View file

@ -15,7 +15,7 @@
<img src = "https://user-images.githubusercontent.com/61667930/93691188-7833f000-fad1-11ea-866d-42e19be54425.jpg"\><br>
</p>
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.

View file

@ -1,4 +0,0 @@
{
"Name of pack": "link_to_zip",
"Name of anther pack": "link_to_zip"
}

9
custom_packs.json Normal file
View file

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

View file

@ -5,7 +5,6 @@
"cfw": true,
"cheats": true,
"firmwares": true,
"sigpatches": true,
"jccolor": true,
"pccolor": true,
"downloadpayload": true,

View file

@ -4,23 +4,24 @@
#include <json.hpp>
#include <set>
#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<std::string> 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

View file

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

View file

@ -13,7 +13,6 @@ private:
std::string currentCheatsVer = "";
std::string newCheatsVer = "";
contentType type;
int size = 0;
void createList();
void createList(contentType type);
void createCheatSlipItem();

View file

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

View file

@ -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<std::pair<std::string, std::string>> 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;
});

View file

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

View file

@ -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<void()> 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<std::string>& titles, CFW cfw, const std::string& version, bool extractAll)
{
preWork(archivePath, "/");
ensureAvailableStorage(archivePath);
unzFile zfile = unzOpen(archivePath.c_str());
unz_global_info gi;

View file

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