1
0
Fork 0
mirror of https://github.com/HamletDuFromage/aio-switch-updater.git synced 2024-12-28 02:16:03 +00:00

Disabled the option to download individual cheat codes while in applet mode, except for the one game currently running. UI tweaks. Prevents crashes when requesting invalid CheatSlips cheat sheets. Bunch of refactoring.

This commit is contained in:
flb 2021-06-28 00:46:00 +02:00
parent f19b57c40c
commit 0af19943a6
38 changed files with 640 additions and 327 deletions

View file

@ -22,7 +22,7 @@ DATA := data
INCLUDES := include lib/zipper/include /lib/borealis/library/include/borealis/extern/nlohmann
APP_TITLE := All-in-One Switch Updater
APP_AUTHOR := HamletDuFromage
APP_VERSION := 2.6.1
APP_VERSION := 2.7.0
TARGET := $(notdir $(CURDIR))
ROMFS := resources

View file

@ -31,7 +31,7 @@ Copy the `aio-switch-updater/` directory to `/switch/` on your sdcard.
- For Atmosphère. Downloads sigpatches, which are patches required for launching unofficial .NSPs. Both AMS and Hekate+AMS sigpatches are available. After downloading the sigpatches archive, the program will ask you whether you want to override your existing .ini files.
### ⬦ Download firmwares
- Download firmare files to `/firmware` that can then be installed using DayBreak or ChoiDuJour.
- Download firmare files to `/firmware` that can then be installed using DayBreak.
### ⬦ Download cheats
- Downloads and extracts daily-updated cheat code. The program will only extract cheat codes for the games you own. By default, this homebrew will overwrite the existing cheats. If you have your own cheat files that you'd like to keep as is, you can turn off cheat updates for specific titles in `Tools->Cheat Menu`.

View file

@ -1,15 +1,30 @@
#pragma once
#include <borealis.hpp>
#include <json.hpp>
#include <set>
class AmsTab : public brls::List
{
private:
brls::ListItem* listItem;
brls::Label *notFound;
brls::Label *description;
int size;
bool erista;
nlohmann::ordered_json cfws;
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 std::string& key, bool hekate = true);
nlohmann::ordered_json SortDeepseaModules(const nlohmann::ordered_json& modules);
public:
AmsTab(const bool erista = true);
brls::View* getDefaultFocus() override;
};
class UnTogglableListItem : public brls::ToggleListItem
{
public:
UnTogglableListItem(std::string label, bool initialValue, std::string description = "", std::string onValue = "On", std::string offValue = "Off") : ToggleListItem(label, initialValue, description, onValue, offValue) {}
virtual bool onClick() override;
};

View file

@ -1,10 +1,11 @@
#pragma once
#include <borealis.hpp>
#include <switch.h>
#include <algorithm>
#include <set>
typedef struct app App;
static constexpr uint32_t MaxTitleCount = 64000;
enum class appPageType{
base,
@ -15,13 +16,51 @@ enum class appPageType{
class AppPage : public brls::AppletFrame
{
private:
brls::List* list;
brls::Label* label;
brls::ListItem* download;
brls::ListItem* listItem;
std::vector<App*> apps;
std::set<std::string> titles;
protected:
brls::List* list;
brls::Label* label;
brls::ListItem* listItem;
void CreateDownloadAllButton();
uint64_t GetCurrentApplicationId();
u32 InitControlData(NsApplicationControlData** controlData);
uint32_t GetControlData(u64 tid, NsApplicationControlData* controlData, u64& controlSize, std::string& name);
virtual void PopulatePage();
virtual void CreateLabel() { };
virtual void CreateGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData **controlData);
public:
AppPage(const appPageType type = appPageType::base);
AppPage();
};
class AppPage_Exclude : public AppPage
{
private:
std::set<std::pair<brls::ToggleListItem*, std::string>> items;
void PopulatePage() override;
void CreateLabel() override;
public:
AppPage_Exclude();
};
class AppPage_CheatSlips : public AppPage
{
private:
void CreateLabel() override;
void CreateGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData **controlData) override;
public:
AppPage_CheatSlips();
};
class AppPage_Gbatemp : public AppPage
{
private:
void CreateLabel() override;
void CreateGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData **controlData) override;
public:
AppPage_Gbatemp();
};

View file

@ -23,10 +23,10 @@ constexpr const char FIRMWARE_URL[] = "https://raw.githubusercontent.com/H
constexpr const char FIRMWARE_FILENAME[] = "/config/aio-switch-updater/firmware.zip";
constexpr const char FIRMWARE_PATH[] = "/firmware/";
constexpr const char CFW_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/cfw.json";
constexpr const char CFW_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/bootloaders.json";
constexpr const char CFW_FILENAME[] = "/config/aio-switch-updater/cfw.zip";
constexpr const char AMS_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/ams.json";
constexpr const char AMS_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/cfws.json";
constexpr const char SXOS_URL[] = "https://raw.githubusercontent.com/HamletDuFromage/nx-links/master/sxos.json";
constexpr const char AMS_FILENAME[] = "/config/aio-switch-updater/ams.zip";

View file

@ -7,11 +7,12 @@ constexpr int OFF = 0;
namespace download {
std::vector<std::uint8_t> downloadFile(const std::string& url, const char* output = "", int api = OFF);
long downloadFile(const std::string& url, std::vector<std::uint8_t>& res, const char* output = "", int api = OFF);
long downloadFile(const std::string& url, const char* output = "", int api = OFF);
std::vector<std::pair<std::string, std::string>> getLinks(const std::string& url);
std::vector<std::pair<std::string, std::string>> getLinksFromJson(const nlohmann::ordered_json& json_object);
std::string fetchTitle(const std::string& url);
std::string downloadPage(const std::string& url, std::vector<std::string> headers = {}, std::string body = "");
std::vector<std::uint8_t> downloadPageBinary(const std::string& url, std::vector<std::string> headers = {}, std::string body = "");
nlohmann::ordered_json getRequest(const std::string& url, std::vector<std::string> headers = {}, std::string body = "");
long downloadPage(const std::string& url, std::string& res, const std::vector<std::string>& headers = {}, const std::string& body = "");
long getRequest(const std::string& url, nlohmann::ordered_json& res, const std::vector<std::string>& headers = {}, const std::string& body = "");
}

View file

@ -14,7 +14,7 @@ class DownloadCheatsPage : public brls::AppletFrame
std::string bid = "";
u32 version = 0;
DownloadCheatsPage(uint64_t tid);
DownloadCheatsPage(uint64_t tid, const std::string& name);
void GetBuildID();
void GetBuildIDFromDmnt();
void GetVersion();
@ -47,7 +47,7 @@ class DownloadCheatsPage_CheatSlips : public DownloadCheatsPage {
void ShowCheatsContent(nlohmann::ordered_json titles);
public:
DownloadCheatsPage_CheatSlips(uint64_t tid);
DownloadCheatsPage_CheatSlips(uint64_t tid, const std::string& name);
};
class DownloadCheatsPage_GbaTemp : public DownloadCheatsPage {
@ -55,5 +55,5 @@ class DownloadCheatsPage_GbaTemp : public DownloadCheatsPage {
brls::ListItem* listItem;
public:
DownloadCheatsPage_GbaTemp(uint64_t tid);
DownloadCheatsPage_GbaTemp(uint64_t tid, const std::string& name);
};

View file

@ -25,7 +25,7 @@ namespace extract {
void extract(const std::string& filename, const std::string& workingPath = ROOT_PATH, int overwriteInis = 1);
void extract(const std::string& filename, const std::string& workingPath, const std::string& toExclude);
std::vector<std::string> getInstalledTitlesNs();
std::vector<std::string> excludeTitles(const std::string& path, std::vector<std::string> listedTitles);
std::vector<std::string> excludeTitles(const std::string& path, const std::vector<std::string>& listedTitles);
void writeTitlesToFile(std::set<std::string> titles, const std::string& path);
void extractCheats(const std::string& zipPath, std::vector<std::string> titles, CFW cfw, bool credits = false);
void extractAllCheats(const std::string& zipPath, CFW cfw);

View file

@ -8,6 +8,7 @@ private:
double _now = 0;
double _total = 0;
double _speed = 0;
long _status_code = 0;
public:
ProgressEvent(const ProgressEvent&) = delete;
@ -26,12 +27,14 @@ public:
_now = 0;
_total = 0;
_speed = 0;
_status_code = 0;
}
inline void setTotalSteps(int steps) { _max = steps; }
inline void setTotalCount(double total) { _total = total; }
inline void setSpeed(double speed) { _speed = speed; }
inline void setStep(int step) { _current = step; }
inline void setStatusCode(long status_code) { _status_code = status_code; }
inline void incrementStep(int increment) {_current += increment; }
inline void setNow(double now) { _now = now; }
inline int getStep() { return _current; }
@ -40,4 +43,5 @@ public:
inline int getMax() { return _max; }
inline double getTotal() { return _total; }
inline double getSpeed() { return _speed; }
inline double getStatusCode() { return _status_code; }
};

View file

@ -12,16 +12,17 @@ namespace util {
typedef char NsApplicationName[0x201];
typedef uint8_t NsApplicationIcon[0x20000];
struct app {
typedef struct {
uint64_t tid;
NsApplicationName name;
NsApplicationIcon icon;
brls::ListItem* listItem;
};
} app;
void clearConsole();
bool isArchive(const std::string& path);
void downloadArchive(std::string url, archiveType type);
void downloadArchive(std::string url, archiveType type, long& status_code);
void extractArchive(archiveType type, std::string tag = "0");
std::string formatListItemTitle(const std::string &str, size_t maxScore = 140);
std::string formatApplicationId(u64 ApplicationId);
@ -31,9 +32,12 @@ namespace util {
int showDialogBox(std::string text, std::string opt);
int showDialogBox(std::string text, std::string opt1, std::string opt2);
std::string getLatestTag(const std::string& url);
std::string downloadFileToString(const std::string& url);
void saveVersion(std::string version, const std::string& path);
std::string readVersion(const std::string& path);
bool isErista();
void removeSysmodulesFlags(const std::string& directory);
std::string lowerCase(const std::string& str);
std::string getErrorMessage(long status_code);
bool isApplet();
}

View file

@ -15,6 +15,7 @@ class WorkerPage : public brls::View
std::string text;
int progressValue = 0;
bool workStarted = false;
bool draw_page = true;
std::thread* workerThread;
worker_func_t workerFunc;

BIN
resources/deepsea_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
resources/gbatemp_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -73,7 +73,7 @@
"joy_con": {
"title": "Joy-Con Farbwechseler",
"desc_1": "Du kannst die Farbe deiner Joy-Cons ändern. Stell sicher, dass die Joy-Cons angeschlossen sind.\nFarbprofile werden gespeichert in: '",
"desc_2": "'. Gehe auf 'http://bit.ly/JC-color' ",
"desc_2": "'. Gehe auf 'https://git.io/jcpicker' ",
"desc_3": "um deine eigenen benutzerdefinierten Profile zu erstellen.",
"backup": "Derzeitiges Profil sichern",
"label": "Joy-Con Farbwechseler",
@ -90,7 +90,7 @@
},
"main": {
"getting": "Herunterladen: ",
"firmware_text": "\ue016 firmware von: 'https://darthsternie.net/switch-firmwares/'. Sobald runtergeladen, wird sie in '/firmware' entpackt . Danach kannst du das Update mit Daybreak oder ChoiDuJour installieren.\n\ue016 Mometnane FW: ",
"firmware_text": "\ue016 firmware von: 'https://darthsternie.net/switch-firmwares/'. Sobald runtergeladen, wird sie in '/firmware' entpackt . Danach kannst du das Update mit Daybreak installieren.\n\ue016 Mometnane FW: ",
"cheats_text": "\uE016 Lade ein täglich geupdatetes Archiv von 'gbatemp.net' runter. Cheats von Spielen die du nicht besitzt, werden nicht entpackt. Du kannst updates für ausgewählte Spiele unter 'Tools->Cheat menu' deaktivieren.\n\uE016 Momentane Cheatversion: ",
"get_cheats": "Lade GBAtemp.net Cheatarchiv herunter (ver ",
"sigpatches": "Sigpatches",
@ -112,7 +112,7 @@
"download_firmware": "Firmwares runterladen",
"download_cheats": "Cheats runterladen",
"tools": "Werkzeuge",
"launch_warning": "Bitte beachten Sie die folgenden Punkte, bevor Sie die App verwenden:\n\n\ue016 Lesen Sie zuerst, wie Sie Ihren Switch manuell aktualisieren. Auf diese Weise können Sie die App besser verstehen und wissen, was zu tun ist, wenn etwas schief geht. \n\ue016 Bitte beachten Sie, dass die Verwendung dieser App (oder eines Homebrews) auf einer exFAT SD-Karte nicht empfohlen wird, da diese höchstwahrscheinlich im laufe der Zeit ihre Daten beschädigen wird.\n\n\ue016 Some new features and/or changes regarding current features may have been introduced. Please check them out via the Tools->Changelog menu.\n\nDieser Bildschirm wird nicht mehr angezeigt."
"launch_warning": "Bitte beachten Sie die folgenden Punkte, bevor Sie die App verwenden:\n\n\ue016 Lesen Sie zuerst, wie Sie Ihren Switch manuell aktualisieren. Auf diese Weise können Sie die App besser verstehen und wissen, was zu tun ist, wenn etwas schief geht. \n\ue016 Bitte beachten Sie, dass von der Verwendung dieser App auf einer exFAT-SD-Karte DRINGEND abgeraten wird, da diese höchstwahrscheinlich im laufe der Zeit ihre Daten beschädigen wird.\n\n\ue016 Some new features and/or changes regarding current features may have been introduced. Please check them out via the Tools->Changelog menu.\n\nDieser Bildschirm wird nicht mehr angezeigt."
},
"hide": {
"title": "Tabs verstecken",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updater is licensed under GPL-3.0\n\u00a9 2020 HamletDuFromage",
"copyright": "AIO-switch-updater is licensed under GPL-3.0\n\u00a9 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 Aside from cheat codes that are mirrored from the main Gbatemp thread, HamletDuFromage isn't hosting anything. All credits go to respective owners.\n\ue016 Links are refreshed every 30 minutes. If a link remains broken after 30 minutes have passed, please open a Github issue.\n",
"donate": "\ue016 Like the app? Consider donating to support my efforts: 'https://git.io/donate_homlet'"
},
@ -9,7 +9,7 @@
"installed": "Installed cheats",
"label": "The following titles have received cheat code updates the last time you used the app. Please note that despite having been downloaded for a game, cheats may not match its current update.",
"downloading": "Downloading:\nLatest cheat codes\n\nFrom:\n",
"dl_latest": "Download latest cheat codes",
"dl_latest": "Download latest cheat codes archive",
"getting_cheats": "Getting cheat codes",
"menu": "Cheats menu",
"view": "View installed cheats",
@ -39,7 +39,8 @@
"dl_all": "Download and extract the entire GBAtemp cheats archive",
"gbatemp_dl": "Download cheat codes curated from GBAtemp. Those cheats will be added to the end of your existing cheat file.\n\uE016 Build ID: {}",
"gbatemp_dl_cheatcode": "Download cheat code",
"gbatemp_dl_successful_dl": "Successfully downloaded the following cheat code:\n{}"
"gbatemp_dl_successful_dl": "Successfully downloaded the following cheat code:\n{}",
"applet_mode_not_supported": "Due to memory constraints, in applet mode you may only fetch cheat codes for the game you're currently playing. Please launch aio-switch-updater through title redirection to download cheat codes for any game you own."
},
"common": {
"downloading": "Downloading...",
@ -57,13 +58,16 @@
"yes": "Yes",
"go_back": "Go back",
"confirm": "Confirm",
"cancel": "Cancel"
"cancel": "Cancel",
"off": "Off",
"selected": "Selected",
"applet_mode_not_supported": "This feature isn't available in applet mode. Please launch aio-switch-updater through title redirection to access it."
},
"changelog": {
"changelog": "Changelog"
},
"sigpatches": {
"reboot": "The changes will take effect at the next reboot."
"reboot": "The changes will take effect at the next boot."
},
"payloads": {
"dl_payloads": "Download payloads",
@ -78,7 +82,7 @@
"joy_con": {
"title": "Joy-Con color swapper",
"desc_1": "You can change the internal color of your Joy-Cons. Make sure they're docked.\nColor profiles are stored in '",
"desc_2": "'. Go to 'http://bit.ly/JC-color' ",
"desc_2": "'. Go to 'https://git.io/jcpicker' ",
"desc_3": "to generate your own custom profiles.",
"backup": "Backup current color profile",
"label": "Joy-Con color swapper",
@ -96,30 +100,32 @@
},
"main": {
"getting": "Getting ",
"firmware_text": "\ue016 Firmware dumps from 'https://darthsternie.net/switch-firmwares/'. Once downloaded, it will be extracted in '/firmware'. You can then install the update through Daybreak or ChoiDuJour.\n\ue016 Current FW: ",
"firmware_text": "\ue016 Firmware dumps from 'https://darthsternie.net/switch-firmwares/'. Once downloaded, it will be extracted in '/firmware'. You can then install the update through Daybreak.\n\ue016 Current FW: ",
"cheats_text": "\uE016 This will download a daily updated archive of cheat codes from 'gbatemp.net'. Cheat codes for games you don't have installed won't be extracted to your SD card. You can turn off cheat updates for specific games in 'Tools->Cheat menu'.\n\uE016 Current cheats version: ",
"get_cheats": "Download GBAtemp.net cheat archive (ver ",
"sigpatches": "sigpatches",
"sigpatches_text": "\ue016 Sigpatches allow your Switch to install and run unofficial NSP file. Make sure you pick the correct sigpatches for your setup (pure Atmosph\u00e8re or Hekate+Atmosph\u00e8re). Reboot the console to apply patches.",
"sigpatches_text": "\ue016 Sigpatches allow your Switch to install and run unofficial NSP files. Make sure you pick the correct sigpatches for your setup (pure Atmosph\u00e8re or Hekate+Atmosph\u00e8re). Reboot the console to apply patches.",
"firmware": "firmware",
"not_found": "not found",
"latest_cheats": "Latest version",
"app": "app",
"cfw": "CFW",
"ams": "Atmosphère",
"ams_text": "\ue016 From this menu, you can download and update the Atmosph\u00e8re custom firmware necessary to run homebrew software.\n\ue016 DeepSea by Team Neptune is a CFW pack that includes Atmosph\u00e8re, hekate, and various homebrew apps.",
"ams_text": "\ue016 From this menu, you can download and update the Atmosph\u00e8re custom firmware necessary to run homebrew software.",
"cfw_text": "\ue016 Alternative CFWs, bootloaders.",
"bootloaders_text": "\ue016 Download and update bootloaders.",
"cheats": "cheats",
"links_not_found": "Could not find a download link, make sure the Switch has access to the internet.\nIf this problem persists, please open an issue on Github.",
"new_update": " - New app update available",
"about": "About",
"update_ams": "Update Atmosph\u00e8re",
"update_cfw": "Update CFW",
"update_bootloaders": "Update bootloaders",
"update_sigpatches": "Update sigpatches",
"download_firmware": "Download firmwares",
"download_cheats": "Download cheats",
"tools": "Tools",
"launch_warning": "Please pay attention to the following points before using the app:\n\n\ue016 Read up on how to manually update your Switch first. This will help you understand the app better and you'll know what to do in case something goes wrong.\n\ue016 Please note that using this app (or any homebrew) on a exFAT SD card is not recommended, as those are more likely to corrupt.\n\n\ue016 Some new features and/or changes regarding current features may have been introduced. Please check them out via the Tools->Changelog menu.\n\nThis screen won't show again.",
"launch_warning": "Please pay attention to the following points before using the app:\n\n\ue016 Read up on how to manually update your Switch first. This will help you understand the app better and you'll know what to do in case something goes wrong.\n\ue016 Please note that using this app on a exFAT SD card is STRONGLY discouraged, as those are likely to corrupt.\n\n\ue016 Some new features and/or changes regarding current features may have been introduced. Please check them out via the Tools->Changelog menu.\n\nThis screen won't show again.",
"footer_text" : "v{} | {:.1f}GB available"
},
"hide": {
@ -160,13 +166,24 @@
"delete_sysmodules_flags": "Would you like to delete all the custom sysmodules startup flags? This will turn off all your sysmodules and prevent crashes if you have sysmodules that do not support the latest Atmosphère.",
"current_ams": "\ue016 Current Atmosphère: ",
"erista_rev": "\ue016 Erista revision",
"mariko_rev": "\ue016 Mariko revision"
"mariko_rev": "\ue016 Mariko revision",
"deepsea_builder": "DeepSea builder",
"show_module_description": "Show module's description",
"depends_on": "The following modules will also be installed:",
"download_custom_deepsea": "Download this custom DeepSea package",
"get_custom_deepsea": "Get custom DeepSea package",
"deepsea_label": "\ue016 DeepSea by Team Neptune is a CFW pack that includes Atmosph\u00e8re, hekate, and various homebrew apps.",
"download_deepsea_package": "Compile and download",
"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"
},
"net": {
"title": "Internet settings"
},
"errors": {
"unsufficient_storage": "There isn't enough space available on your SD card to perform this operation."
"insufficient_storage": "There isn't enough space available on your SD card to perform this operation.",
"error_message": "{}\nPlease try again in a little while. If the problem persists, open an issue on Github"
},
"language": {
"system_default": "System default",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "Actualizador Todo-en-Uno de Nintendo Switch",
"copyright": "AIO-switch-updater tiene licencia GPL-3.0\n© 2020 HamletDuFromage",
"copyright": "AIO-switch-updater tiene licencia GPL-3.0\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 Aparte de trucos obtenidos del hilo principal de Gbatemp, HamletDuFromage no provee nada. Todo el crédito pertenece a sus respectivos dueños.\n\ue016 Los enlaces se actualizan cada tres horas. Si un enlace sigue roto después de 3 horas, por favor abre un issue en Github.\n"
},
"cheats": {
@ -51,7 +51,7 @@
"joy_con": {
"title": "Cambiar color de Joy-Con",
"desc_1": "Puedes cambiar el color interno de tus Joy-Cons. Asegúrate de que están acoplados a la consola.\nLos perfiles de colores se almacenan en '",
"desc_2": "'. Ve a 'http://bit.ly/JC-color' ",
"desc_2": "'. Ve a 'https://git.io/jcpicker' ",
"desc_3": "para generar tus propios perfiles.",
"backup": "Copia de seguridad del perfil de color actual",
"label": "Cambiar color de Joy-Con",
@ -61,7 +61,7 @@
},
"main": {
"getting": "Obteniendo ",
"firmware_text": "\ue016 Firmwares de 'https://darthsternie.net/switch-firmwares/'. Una vez descargado, será extraído en '/firmware'. Entonces podrás instalar la actualización a través de Daybreak o ChoiDuJour.\n\ue016 FW actual: ",
"firmware_text": "\ue016 Firmwares de 'https://darthsternie.net/switch-firmwares/'. Una vez descargado, será extraído en '/firmware'. Entonces podrás instalar la actualización a través de Daybreak.\n\ue016 FW actual: ",
"cheats_text": "\ue016 Esto descargará un paquete actualizado diario de trucos de 'gbatemp.net'. Los trucos de juegos que no tienes instalados no se extraerán a tu tarjeta SD. Puedes desactivar los trucos actualizados en 'Herramientas->Menú de trucos'.\n\ue016 Versión de trucos actual: ",
"sigpatches": "sigpatches",
"sigpatches_text": "\ue016 Los sigpatches permiten a tu Switch instalar y ejecutar archivos NSP no oficiales. Asegúrate de escoger los sigpatches correctos para tu configuración (Atmosphère puro o Hekate+Atmosphère).",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updater est distribuée sous la license GPL-3.0\n© 2020 HamletDuFromage",
"copyright": "AIO-switch-updater est distribuée sous la license GPL-3.0\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 A part les cheat codes qui proviennent d'un mirroir d'un topic Gbatemp, HamletDuFromage n'héberge rien. Tous les crédits vont aux propriétaires respectifs\n\ue016 Les liens sont actualisés toutes les 3 heures. Si un lien reste inactif après 3 heures, merci de bien vouloir ouvrir une issue sur Github.\n"
},
"cheats": {
@ -51,7 +51,7 @@
"joy_con": {
"title": "Changement de couleur des Joy-Cons",
"desc_1": "Vous pouvez changer la couleur interne de vos Joy-Cons. Assurez vous qu'ils soient bien ancrés à la Swich.\nLes profils de couleur se trouvent dans '",
"desc_2": "'. Visitez 'http://bit.ly/JC-color' ",
"desc_2": "'. Visitez 'https://git.io/jcpicker' ",
"desc_3": "pour générer des profils personalisés.",
"backup": "Sauvegarde du profil actuel",
"label": "Échangeur de couleurs des Joy-Con",
@ -61,7 +61,7 @@
},
"main": {
"getting": "Téléchargement du ",
"firmware_text": "\ue016 Firmware depuis 'https://darthsternie.net/switch-firmwares/'. Une fois téléchargés, ils seront dans '/firmware'. Vous pouvez ensuite les installer avec Daybreak ou ChoiDuJour.\n\ue016 FW actuel : ",
"firmware_text": "\ue016 Firmware depuis 'https://darthsternie.net/switch-firmwares/'. Une fois téléchargés, ils seront dans '/firmware'. Vous pouvez ensuite les installer avec Daybreak.\n\ue016 FW actuel : ",
"cheats_text": "\ue016 Archive mise à jour quotidiennement des codes de triche de 'gbatemp.net'. Les codes de triche pour les jeux que vous ne possedez pas ne seront pas extraits sur votre carte SD. Vous pouvez désactiver les mises à jour pour pour une sélection de jeux dans le menu 'Outils->Menu de cheat'.\n\ue016 Version actuelle des cheats : ",
"sigpatches": "sigpatches",
"sigpatches_text": "\ue016 Les Sigpatches permettent à votre Switch d'installer et d'exécuter des fichiers NSP non officiels. Assurez-vous de choisir les bons patchs pour votre configuration (Atmosphère seul ou Hekate + Atmosphère).",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updater è distribuito con licenza GPL-3.0\n© 2020 HamletDuFromage",
"copyright": "AIO-switch-updater è distribuito con licenza GPL-3.0\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 Esclusi i cheat che sono presi dal thread principale su Gbatemp, HamletDuFromage non hosta niente. Tutti i crediti vanno ai rispettivi proprietari.\n\ue016 I link vengono aggiornati ognitre ore. Se un link continua a non funzionare dopo che siano passate 3 ore, apri una issue su Github.\n"
},
"cheats": {
@ -51,7 +51,7 @@
"joy_con": {
"title": "Cambia il colore dei Joy-Con",
"desc_1": "You can change the internal color of your Joy-Cons. Make sure they're docked.\nColor profiles are stored in '",
"desc_2": "'. Visita 'http://bit.ly/JC-color' ",
"desc_2": "'. Visita 'https://git.io/jcpicker' ",
"desc_3": "per generare i tuoi profili personalizzati.",
"backup": "Salva il profilo corrente",
"label": "Cambia il colore dei Joy-Con",
@ -61,7 +61,7 @@
},
"main": {
"getting": "Ottengo ",
"firmware_text": "\ue016 il dump del Firmware da 'https://darthsternie.net/switch-firmwares/'. Una volta scaricato, sarà estratto in '/firmware'. Puoi installare l'aggiornamento tramite Daybreak o ChoiDuJour.\n\ue016 FW attuale: ",
"firmware_text": "\ue016 il dump del Firmware da 'https://darthsternie.net/switch-firmwares/'. Una volta scaricato, sarà estratto in '/firmware'. Puoi installare l'aggiornamento tramite Daybreak.\n\ue016 FW attuale: ",
"cheats_text": "\ue016 Questo scaricherà quotidianamente un archivio di cheat da 'gbatemp.net'. I cheat per i giochi non installati non saranno estratti sulla tua scheda SD. Puoi disabilitare l'aggiornamento dei cheat in 'Tools->Cheat menu'.\n\ue016 Current cheats version: ",
"sigpatches": "sigpatches",
"sigpatches_text": "\ue016 Le sigpatches consentono di installare ed eseguire NSP non ufficiali sulla Switch. Assicurati di scegliere le sigpatches corrette per la tua configurazione (solo Atmosphère o Hekate+Atmosphère).",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updaterはGPL-3.0の下でライセンスされています\n© 2020 HamletDuFromage",
"copyright": "AIO-switch-updaterはGPL-3.0の下でライセンスされています\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 メインのGbatempスレッドからミラーリングされたチートコードを除いて、HamletDuFromageは何もホストしていません。すべてのクレジットはそれぞれの所有者に送られます。\n\ue016 リンクは3時間ごとに更新されます。 3時間経過してもリンクが壊れたままの場合は、Githubの問題を開いてください。\n",
"donate": "\ue016 アプリが好きですか?私の努力を支援するために寄付することを検討してください: 'https://git.io/donate_homlet'"
},
@ -73,7 +73,7 @@
"joy_con": {
"title": "Joy-Con color swapper",
"desc_1": "Joy-Conの内部の色を変更できます。それらがドッキングされていることを確認してください。\nカラープロファイルは保存されます '",
"desc_2": "'. 'http://bit.ly/JC-color'に移動 ",
"desc_2": "'. 'https://git.io/jcpicker'に移動 ",
"desc_3": "独自のカスタムプロファイルを生成します。",
"backup": "現在のカラープロファイルをバックアップする",
"label": "Joy-Con color swapper",
@ -91,7 +91,7 @@
},
"main": {
"getting": "取得中 ",
"firmware_text": "\ue016 ファームウェアは'https://darthsternie.net/switch-firmwares/'からダンプされます。 ダウンロードすると、「/ firmware」に抽出されます。 その後、DaybreakまたはChoiDuJourを介してアップデートをインストールできます。\n\ue016 現在のファームウェア: ",
"firmware_text": "\ue016 ファームウェアは'https://darthsternie.net/switch-firmwares/'からダンプされます。 ダウンロードすると、「/ firmware」に抽出されます。その後、Daybreakを介してアップデートをインストールできます。\n\ue016 現在のファームウェア: ",
"cheats_text": "Download GBAtemp.net チートアーカイブ (ver ",
"get_cheats": "GBAtemp.netチートアーカイブをダウンロード (ver ",
"sigpatches": "sigpatch",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updater jest zgodny z licencją GPL-3.0\n\u00a9 2020 HamletDuFromage",
"copyright": "AIO-switch-updater jest zgodny z licencją GPL-3.0\n\u00a9 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 Oprócz cheatów które są lustrzaną kopią tych z wątku na Gbatemp, HamletDuFromage nie hostuje żadnych innych plików. Podziękowania za nie należy kierować do ich twórców.\n\ue016 Linki są odświeżane co 30 minut. Jeśli po 30 minutach link nadal nie działa, utwórz nowy problem na Githubie.\n",
"donate": "\ue016 Podoba ci się apka? Rozważ datek na wsparcie moich starań: 'https://git.io/donate_homlet'"
},
@ -73,7 +73,7 @@
"joy_con": {
"title": "Zmień kolor Joy-Conów",
"desc_1": "Możesz zmienić kolor fabrycznie przypisany do twoich Joy-Conów. Upewnij się, że są zadokowane do konsoli.\nProfile kolorów zapisywane są w '",
"desc_2": "'. Wejdź na 'http://bit.ly/JC-color' ",
"desc_2": "'. Wejdź na 'https://git.io/jcpicker' ",
"desc_3": "żeby utworzyć swój własny profil kolorów.",
"backup": "Zrób kopię zapasową bieżącego profilu kolorów",
"label": "Zmień kolor Joy-Conów",
@ -91,7 +91,7 @@
},
"main": {
"getting": "Pobieranie ",
"firmware_text": "\ue016 Oprogramowanie z 'https://darthsternie.net/switch-firmwares/'. Po pobraniu zostanie rozpakowane do '/firmware'. Możesz je później zainstalować korzystając z Daybreak lub ChoiDuJour.\n\ue016 Bieżący FW: ",
"firmware_text": "\ue016 Oprogramowanie z 'https://darthsternie.net/switch-firmwares/'. Po pobraniu zostanie rozpakowane do '/firmware'. Możesz je później zainstalować korzystając z Daybreak.\n\ue016 Bieżący FW: ",
"cheats_text": "\uE016 Pobierze aktualizowaną codziennie paczkę cheatów z 'gbatemp.net'. Cheaty dla gier których nie masz zainstalowanych nie zostaną wypakowane na twoją kartę SD. Możesz wyłączyć aktualizację cheatów dla poszczególnych gier w 'Narzędzia->Menu cheatów'.\n\uE016 Bieżąca wersja cheatów: ",
"get_cheats": "Pobierz archiwum cheatów GBAtemp.net (wersja ",
"sigpatches": "sigpatche",
@ -114,7 +114,7 @@
"download_firmware": "Pobierz firmware",
"download_cheats": "Pobierz cheaty",
"tools": "Narzędzia",
"launch_warning": "Zwróć uwagę na następujące punkty zanim skorzystasz z aplikacji:\n\n\ue016 Dowiedz się najpierw, jak ręcznie zaktualizować twojego Switcha. Pomoże ci to lepiej zrozumieć działanie aplikacji i będziesz wiedział co zrobić gdy coś pójdzie nie tak.\n\ue016 Pamiętaj, że używanie tej aplikacji (lub innych homebrew) na karcie SD z systemem plików exFAT nie jest zalecane, ponieważ ich zawartość ma większą podatność na uszkodzenia.\n\n\ue016 Mogły zostać wprowadzone nowe funkcje i/lub zmiany obecnych funkcji. Rzuć na nie okiem w Narzędzia->Dziennik zmian.\n\nTen ekran nie wyświetli się ponownie.",
"launch_warning": "Zwróć uwagę na następujące punkty zanim skorzystasz z aplikacji:\n\n\ue016 Dowiedz się najpierw, jak ręcznie zaktualizować twojego Switcha. Pomoże ci to lepiej zrozumieć działanie aplikacji i będziesz wiedział co zrobić gdy coś pójdzie nie tak.\n\ue016 Należy pamiętać, że korzystanie z tej aplikacji na karcie SD z systemem plików exFAT jest SILNIE odradzane, ponieważ ich zawartość jest bardziej podatna na uszkodzenia.\n\n\ue016 Mogły zostać wprowadzone nowe funkcje i/lub zmiany obecnych funkcji. Rzuć na nie okiem w Narzędzia->Dziennik zmian.\n\nTen ekran nie wyświetli się ponownie.",
"footer_text" : "v{} | {:.1f}GB dostępne"
},
"hide": {

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "Atualizador tudo em um Nintendo Switch",
"copyright": "AIO-switch-updater usa a licença GPL-3.0\n© 2020 HamletDuFromage",
"copyright": "AIO-switch-updater usa a licença GPL-3.0\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 Além de trapaças obtidas no tópico principal do Gbatemp, o HamletDuFromage não fornece nada. Todo o crédito pertence aos seus respectivos proprietários.\n\ue016 Os links são atualizados a cada três horas. Se um link ainda estiver quebrado após 3 horas, abra um 'issue' no Github.\n"
},
"cheats": {
@ -51,7 +51,7 @@
"joy_con": {
"title": "Mudar a cor dos Joy-Cons",
"desc_1": "Você pode alterar a cor interna dos Joy-Cons. Certifique-se de que eles estejam encaixados no console.\nPerfis de cores são armazenados em '",
"desc_2": "'. Vamos a 'http://bit.ly/JC-color' ",
"desc_2": "'. Vamos a 'https://git.io/jcpicker' ",
"desc_3": "para gerar seus próprios perfis.",
"backup": "Fazer backup do perfil de cor atual",
"label": "Mudar a cor dos Joy-Cons",
@ -61,7 +61,7 @@
},
"main": {
"getting": "Baixando ",
"firmware_text": "\ue016 Firmwares de 'https://darthsternie.net/switch-firmwares/'. Depois de baixado, ele será extraído para '/firmware'. Você pode então instalar a atualização por meio do Daybreak ou do ChoiDuJour.\n\ue016 FW atual: ",
"firmware_text": "\ue016 Firmwares de 'https://darthsternie.net/switch-firmwares/'. Depois de baixado, ele será extraído para '/firmware'. Você pode então instalar a atualização por meio do Daybreak ou.\n\ue016 FW atual: ",
"cheats_text": "\ue016 Isso irá baixar um pacote de cheat atualizado diariamente do 'gbatemp.net'. Os cheats do jogo que você não instalou não serão extraídos para o seu cartão SD. Você pode desabilitar cheats atualizados em 'Ferramentas->Trapaças'.\n\ue016 Versão das trapaças atual: ",
"sigpatches": "sigpatches",
"sigpatches_text": "\ue016 Os Sigpatches permitem que o Switch instale e execute arquivos NSP não oficiais. Certifique-se de escolher os sigpatches corretos para sua configuração (Atmosphère Puro ou Hekate+Atmosphère).",

View file

@ -1,7 +1,7 @@
{
"about": {
"title": "多工具合一任天堂Switch更新器",
"copyright": "多工具合一任天堂Switch更新器遵循 GPL-3.0 协议\n© 2020 HamletDuFromage",
"copyright": "多工具合一任天堂Switch更新器遵循 GPL-3.0 协议\n© 2020-2021 HamletDuFromage",
"disclaimers": "\ue016 除了从主Gbatemp线程镜像的金手指外,本软件作者不拥有任何金手指。所有的信用归于各自的所有者\n\ue016 链接每三个小时刷新一次. 如果链接在3小时后仍然有问题请到Github给作者 issue.\n"
},
"cheats": {
@ -53,7 +53,7 @@
"joy_con": {
"title": "Joy-Con 颜色更换器",
"desc_1": "你可以改变游戏机里的手柄颜色确保手柄已经插入switch.\n颜色风格文件存储在 ' ",
"desc_2": "'. 去这里 'http://bit.ly/JC-color' ",
"desc_2": "'. 去这里 'https://git.io/jcpicker' ",
"desc_3": "去制作你自己的颜色主题文件",
"backup": "备份当前主题文件",
"label": "手柄颜色修改器",
@ -63,7 +63,7 @@
},
"main": {
"getting": "获取 ",
"firmware_text": "\ue016 固件从 'https://darthsternie.net/switch-firmwares/ 下载'. 下载之后,文件会被解压到 '/firmware'. 你可以使用 Daybreak 或者 ChoiDuJour (大白兔)安装他们.\n\ue016 当前FW版本: ",
"firmware_text": "\ue016 固件从 'https://darthsternie.net/switch-firmwares/ 下载'. 下载之后,文件会被解压到 '/firmware'. 您可以使用 Daybreak 来安装它 .\n\ue016 当前FW版本: ",
"cheats_text": "\ue016 这个金手指的下载和更新地址是 'gbatemp.net'. 你的机器中没有的游戏,这些金手指不会解压到你的SD卡中 你可以在'工具->金手指菜单' 关闭金手指更新.\n\ue016 当前金手指版本: ",
"sigpatches": "数字签名",
"sigpatches_text": "\ue016 数字签名允许你运行没被任天堂收录的nsp文件. 确保为您的设置选择了正确的签名 (pure Atmosphère (大气层)or Hekate+Atmosphère).",

View file

@ -73,7 +73,7 @@
"joy_con": {
"title": "Joy-Con 更換顏色工具",
"desc_1": "你可以透過置換Joy-Cons內的代碼設定來自訂控制器在系統內被辨識的顏色外觀。請確認Joy-Con已確實安裝到主機。\n顏色代碼檔案才能正確覆蓋取代。'",
"desc_2": "'. 前往控制器顏色代碼檔案產生網頁:'http://bit.ly/JC-color' ",
"desc_2": "'. 前往控制器顏色代碼檔案產生網頁:'https://git.io/jcpicker' ",
"desc_3": "製作你專屬的控制器顏色外觀",
"backup": "備份目前的控制器顏色代碼設定檔案",
"label": "Joy-Con 更換顏色工具",
@ -91,7 +91,7 @@
},
"main": {
"getting": "正在擷取 ",
"firmware_text": "\ue016 韌體檔案從'https://darthsternie.net/switch-firmwares/'進行轉存。當下載完成後,檔案會放置於資料夾'/firmware'內。你可以透過Daybreak或ChoiDuJour來安裝更新韌體。\n\ue016 目前FW: ",
"firmware_text": "\ue016 韌體檔案從'https://darthsternie.net/switch-firmwares/'進行轉存。當下載完成後,檔案會放置於資料夾'/firmware'內。您可以通过 Daybreak 安装和更新固件。\n\ue016 目前FW: ",
"cheats_text": "\uE016 下載'gbatemp.net'每日更新的金手指檔案到記憶卡時,並不會複製到主機未安裝的遊戲金手指檔案。你可以從設定的 '工具->金手指選單' 內停用金手指更新。\n\uE016 目前金手指資料庫版本: ",
"get_cheats": "下載GBAtemp.net金手指資料庫(版本 ",
"sigpatches": "sigpatches",
@ -114,7 +114,7 @@
"download_firmware": "下載韌體",
"download_cheats": "下載金手指",
"tools": "工具",
"launch_warning": "在開始使用此app前請務必注意\n\n\ue016 請先閱讀有關如何手動更新Switch系統的文件協助你瞭解app提供的各項功能以及發生問題時如何排除。\n\ue016 請注意我們不建議在exFAT格式的記憶卡上使用此app (或其他任何第三方自製軟體),可能會因此產生錯誤或造成損害。\n\n此提醒畫面將不再顯示"
"launch_warning": "在開始使用此app前請務必注意\n\n\ue016 請先閱讀有關如何手動更新Switch系統的文件協助你瞭解app提供的各項功能以及發生問題時如何排除。\n\ue016 请注意,强烈建议不要在 exFAT SD 卡上使用此应用程序,因为它们可能会损坏。\n\n此提醒畫面將不再顯示"
},
"hide": {
"title": "隱藏分頁",

View file

@ -6,21 +6,37 @@
#include "worker_page.hpp"
#include "utils.hpp"
#include "current_cfw.hpp"
#include "fs.hpp"
#include <string>
namespace i18n = brls::i18n;
using namespace i18n::literals;
AmsTab::AmsTab(const bool erista) :
brls::List()
AmsTab::AmsTab(const bool erista) : brls::List()
{
std::vector<std::pair<std::string, std::string>> links;
std::string operation("menus/main/getting"_i18n);
this->erista = erista;
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);
operation += "menus/main/ams"_i18n;
links = download::getLinks(AMS_URL);
download::getRequest(AMS_URL, cfws);
CreateDownloadItems("Atmosphere");
description = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/deepsea_label"_i18n,
true
);
this->addView(description);
CreateDownloadItems("DeepSea", false);
}
void AmsTab::CreateDownloadItems(const std::string& key, bool hekate)
{
std::string operation("menus/ams_update/getting_ams"_i18n);
std::vector<std::pair<std::string, std::string>> links;
links = download::getLinksFromJson(cfws[key]);
this->size = links.size();
if(this->size){
auto hekate_link = download::getLinks(HEKATE_URL);
@ -32,7 +48,25 @@ AmsTab::AmsTab(const bool erista) :
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([&, text, text_hekate, url, hekate_url, operation, erista](brls::View* view) {
listItem->getClickEvent()->subscribe([&, this, text, text_hekate, url, hekate_url, operation, hekate](brls::View* view) {
CreateStagedFrames(text, url, operation, erista, hekate, text_hekate, hekate_url);
});
this->addView(listItem);
}
}
else{
description = new brls::Label(
brls::LabelStyle::SMALL,
"menus/main/links_not_found"_i18n,
true
);
description->setHorizontalAlign(NVG_ALIGN_CENTER);
this->addView(description);
}
}
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)
{
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
stagedFrame->setTitle(operation);
stagedFrame->addStage(
@ -44,7 +78,7 @@ AmsTab::AmsTab(const bool erista) :
stagedFrame->addStage(
new WorkerPage(stagedFrame, "menus/common/extracting"_i18n, [](){util::extractArchive(archiveType::ams_cfw);})
);
if(url.find("DeepSea") == std::string::npos) {
if(hekate) {
stagedFrame->addStage(
new DialoguePage(stagedFrame, text_hekate, erista)
);
@ -59,25 +93,37 @@ AmsTab::AmsTab(const bool erista) :
new ConfirmPage(stagedFrame, "menus/ams_update/reboot_rcm"_i18n, false, true, erista)
);
brls::Application::pushView(stagedFrame);
});
this->addView(listItem);
}
}
else{
notFound = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/main/links_not_found"_i18n,
true
);
notFound->setHorizontalAlign(NVG_ALIGN_CENTER);
this->addView(notFound);
}
}
brls::View* AmsTab::getDefaultFocus()
std::string AmsTab::GetRepoName(const std::string& repo)
{
if(this->size)
return this->brls::List::getDefaultFocus();
else
return nullptr;
return repo.substr(repo.find("/") + 1, repo.length());
}
std::set<std::string> AmsTab::GetLastDownloadedModules(const std::string& json_path)
{
nlohmann::json package = fs::parseJsonFile(json_path);
std::set<std::string> res;
if(package.find("modules") != package.end()) {
for (const auto& module : package["modules"]) {
res.insert(module.get<std::string>());
}
}
return res;
}
nlohmann::ordered_json AmsTab::SortDeepseaModules(const nlohmann::ordered_json& modules)
{
nlohmann::ordered_json sorted_modules = nlohmann::ordered_json::object();
if(modules.find("modules") != modules.end()) {
for (const auto& module : modules["modules"].items()) {
sorted_modules[std::string(module.value()["category"])][module.key()] = module.value();
}
}
return sorted_modules;
}
bool UnTogglableListItem::onClick()
{
return true;
}

View file

@ -1,87 +1,73 @@
#include "app_page.hpp"
#include <switch.h>
#include <filesystem>
#include <fstream>
#include "current_cfw.hpp"
#include "worker_page.hpp"
#include "confirm_page.hpp"
#include "download_cheats_page.hpp"
#include "utils.hpp"
#include "extract.hpp"
#include "fs.hpp"
#include <switch.h>
#include <filesystem>
#include <fstream>
namespace i18n = brls::i18n;
using namespace i18n::literals;
AppPage::AppPage(const appPageType type) : AppletFrame(true, true)
AppPage::AppPage() : AppletFrame(true, true)
{
list = new brls::List();
switch(type){
case appPageType::base:
this->setTitle("menus/cheats/installed"_i18n);
label = new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/cheats/label"_i18n, true);
break;
case appPageType::cheatSlips:
this->setTitle("menus/cheats/cheastlips_title"_i18n);
label = new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/cheats/cheatslips_select"_i18n, true);
break;
case appPageType::gbatempCheats:
this->setTitle("menus/cheats/gbatemp_title"_i18n);
label = new brls::Label( brls::LabelStyle::DESCRIPTION,"menus/cheats/cheatslips_select"_i18n,true);
break;
}
list->addView(label);
}
NsApplicationRecord record;
uint64_t tid;
NsApplicationControlData controlData;
NacpLanguageEntry* langEntry = NULL;
void AppPage::PopulatePage()
{
this->CreateLabel();
Result rc;
size_t i = 0;
int recordCount = 0;
size_t controlSize = 0;
NsApplicationRecord *records = new NsApplicationRecord[MaxTitleCount];
NsApplicationControlData *controlData = NULL;
std::string name;
titles = fs::readLineByLine(UPDATED_TITLES_PATH);
s32 recordCount = 0;
u64 controlSize = 0;
u64 tid;
if(!titles.empty() || type == appPageType::cheatSlips || type == appPageType::gbatempCheats) {
while (true)
{
rc = nsListApplicationRecord(&record, sizeof(record), i, &recordCount);
if (R_FAILED(rc)) break;
if(recordCount <= 0) break;
//titles = fs::readLineByLine(UPDATED_TITLES_PATH);
tid = record.application_id;
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, &controlData, sizeof(controlData), &controlSize);
if (R_FAILED(rc)) break;
rc = nacpGetLanguageEntry(&controlData.nacp, &langEntry);
if (R_FAILED(rc)) break;
if (!util::isApplet()) {
if (R_SUCCEEDED(nsListApplicationRecord(records, MaxTitleCount, 0, &recordCount))){
for (s32 i = 0; i < recordCount; i++){
controlSize = 0;
if (!langEntry->name) {
i++;
continue;
}
if(type == appPageType::base && titles.find(util::formatApplicationId(tid)) == titles.end()) {
i++;
continue;
}
if(R_FAILED(InitControlData(&controlData))) break;
listItem = new brls::ListItem(std::string(langEntry->name), "", util::formatApplicationId(tid));
listItem->setThumbnail(controlData.icon, sizeof(controlData.icon));
tid = records[i].application_id;
switch(type){
case appPageType::cheatSlips:
listItem->getClickEvent()->subscribe([&, tid](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_CheatSlips(tid)); });
break;
case appPageType::gbatempCheats:
listItem->getClickEvent()->subscribe([&, tid](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_GbaTemp(tid)); });
break;
case appPageType::base:
break;
}
if R_FAILED(GetControlData(tid, controlData, controlSize, name)) continue;
this->CreateGameListItem(name, tid, &controlData);
list->addView(listItem);
i++;
free(controlData);
}
delete[] records;
}
}
else {
tid = GetCurrentApplicationId();
if (R_SUCCEEDED(InitControlData(&controlData)) && R_SUCCEEDED(GetControlData(tid, controlData, controlSize, name))) {
this->CreateGameListItem(name, tid, &controlData);
list->addView(listItem);
}
label = new brls::Label(brls::LabelStyle::SMALL, "menus/cheats/applet_mode_not_supported"_i18n, true);
list->addView(label);
}
this->CreateDownloadAllButton();
this->setContentView(list);
}
void AppPage::CreateDownloadAllButton()
{
std::string text("menus/cheats/downloading"_i18n);
std::string url = "";
switch(CurrentCfw::running_cfw){
@ -115,5 +101,165 @@ AppPage::AppPage(const appPageType type) : AppletFrame(true, true)
brls::Application::pushView(stagedFrame);
});
list->addView(download);
}
u32 AppPage::InitControlData(NsApplicationControlData** controlData) {
*controlData = (NsApplicationControlData*)malloc(sizeof(NsApplicationControlData));
if(*controlData == NULL) {
free(*controlData);
return 300;
}
else {
memset(*controlData, 0, sizeof(NsApplicationControlData));
return 0;
}
}
u32 AppPage::GetControlData(u64 tid, NsApplicationControlData* controlData, u64& controlSize, std::string& name)
{
Result rc;
NacpLanguageEntry* langEntry = NULL;
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, controlData, sizeof(NsApplicationControlData), &controlSize);
if(R_FAILED(rc)) return rc;
if(controlSize < sizeof(controlData->nacp)) return 100;
rc = nacpGetLanguageEntry(&controlData->nacp, &langEntry);
if(R_FAILED(rc)) return rc;
if (!langEntry->name) return 200;
name = langEntry->name;
return 0;
}
void AppPage::CreateGameListItem(const std::string& name, u64 tid, NsApplicationControlData **controlData)
{
listItem = new brls::ListItem(name, "", util::formatApplicationId(tid));
listItem->setThumbnail((*controlData)->icon, sizeof((*controlData)->icon));
}
uint64_t AppPage::GetCurrentApplicationId()
{
Result rc = 0;
uint64_t pid = 0;
uint64_t tid = 0;
rc = pmdmntGetApplicationProcessId(&pid);
if (rc == 0x20f || R_FAILED(rc)) return 0;
rc = pminfoGetProgramId(&tid, pid);
if (rc == 0x20f || R_FAILED(rc)) return 0;
return tid;
}
AppPage_CheatSlips::AppPage_CheatSlips() : AppPage()
{
this->PopulatePage();
}
void AppPage_CheatSlips::CreateLabel()
{
this->setTitle("menus/cheats/cheastlips_title"_i18n);
label = new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/cheats/cheatslips_select"_i18n, true);
list->addView(label);
}
void AppPage_CheatSlips::CreateGameListItem(const std::string& name, u64 tid, NsApplicationControlData **controlData)
{
AppPage::CreateGameListItem(name, tid, controlData);
listItem->getClickEvent()->subscribe([&, tid, name](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_CheatSlips(tid, name)); });
}
AppPage_Gbatemp::AppPage_Gbatemp() : AppPage()
{
this->PopulatePage();
this->setIcon("romfs:/gbatemp_icon.png");
}
void AppPage_Gbatemp::CreateLabel()
{
this->setTitle("menus/cheats/gbatemp_title"_i18n);
label = new brls::Label( brls::LabelStyle::DESCRIPTION,"menus/cheats/cheatslips_select"_i18n,true);
list->addView(label);
}
void AppPage_Gbatemp::CreateGameListItem(const std::string& name, u64 tid, NsApplicationControlData **controlData)
{
AppPage::CreateGameListItem(name, tid, controlData);
listItem->getClickEvent()->subscribe([&, tid, name](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_GbaTemp(tid, name)); });
}
AppPage_Exclude::AppPage_Exclude() : AppPage()
{
this->PopulatePage();
}
void AppPage_Exclude::CreateLabel()
{
this->setTitle("menus/cheats/exclude_titles"_i18n);
label = new brls::Label( brls::LabelStyle::DESCRIPTION, "menus/cheats/exclude_titles_desc"_i18n, true);
list->addView(label);
}
void AppPage_Exclude::PopulatePage()
{
this->CreateLabel();
NsApplicationRecord *records = new NsApplicationRecord[MaxTitleCount];
NsApplicationControlData *controlData = NULL;
std::string name;
s32 recordCount = 0;
u64 controlSize = 0;
u64 tid;
auto titles = fs::readLineByLine(CHEATS_EXCLUDE);
if (!util::isApplet()) {
if (R_SUCCEEDED(nsListApplicationRecord(records, MaxTitleCount, 0, &recordCount))){
for (s32 i = 0; i < recordCount; i++){
controlSize = 0;
if(R_FAILED(InitControlData(&controlData))) break;
tid = records[i].application_id;
if R_FAILED(GetControlData(tid, controlData, controlSize, name)) continue;
brls::ToggleListItem *listItem;
listItem = new brls::ToggleListItem(util::formatListItemTitle(std::string(name)), titles.find(util::formatApplicationId(tid)) != titles.end() ? 0 : 1);
listItem->setThumbnail(controlData->icon, sizeof(controlData->icon));
items.insert(std::make_pair(listItem, util::formatApplicationId(tid)));
list->addView(listItem);
free(controlData);
}
delete[] records;
}
}
else {
label = new brls::Label(brls::LabelStyle::SMALL, "menus/common/applet_mode_not_supported"_i18n, true);
list->addView(label);
}
list->registerAction("menus/cheats/exclude_titles_save"_i18n, brls::Key::B, [this] {
std::set<std::string> exclude;
for (const auto& item : items) {
if(!item.first->getToggleState()) {
exclude.insert(item.second);
}
}
extract::writeTitlesToFile(exclude, CHEATS_EXCLUDE);
brls::Application::popView();
return true;
});
this->CreateDownloadAllButton();
this->setContentView(list);
}

View file

@ -163,6 +163,9 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true)
verTitles.push_back("v2.6.1");
changes.push_back("\uE016 Added a safer way to inject payloads (should prevent corruption on exFAT system, not that you should be using exFAT)");
verTitles.push_back("v2.7.0");
changes.push_back("\uE016 Fixed Atmosphère updates failing when updating from a system without stratosphere.romfs present on the SD card.\n\uE016 Disabled the option to download individual cheat codes while in applet mode, except for the one game currently running.\n\uE016 UI tweaks.\n\uE016 Prevents crashes when requesting invalid CheatSlips cheat sheets.");
for(int i = verTitles.size() -1 ; i >= 0; i--){
listItem = new brls::ListItem(verTitles[i]);
change = changes[i];

View file

@ -17,15 +17,15 @@ CheatsPage::CheatsPage() : AppletFrame(true, true)
this->setTitle("menus/cheats/menu"_i18n);
list = new brls::List();
view = new brls::ListItem("menus/cheats/view"_i18n);
/* view = new brls::ListItem("menus/cheats/view"_i18n);
view->getClickEvent()->subscribe([&](brls::View* view){
brls::Application::pushView(new AppPage());
brls::Application::pushView(new AppPage_DownloadedCheats());
});
list->addView(view);
list->addView(view); */
exclude = new brls::ListItem("menus/cheats/exclude"_i18n);
exclude->getClickEvent()->subscribe([&](brls::View* view){
brls::Application::pushView(new ExcludePage());
brls::Application::pushView(new AppPage_Exclude());
});
list->addView(exclude);
@ -43,8 +43,7 @@ CheatsPage::CheatsPage() : AppletFrame(true, true)
});
list->addView(deleteCheats);
auto cheatsVerVec = download::downloadFile(CHEATS_URL_VERSION);
std::string cheatsVer(cheatsVerVec.begin(), cheatsVerVec.end());
std::string cheatsVer = util::downloadFileToString(CHEATS_URL_VERSION);
if(cheatsVer != "") {
dlAll = new brls::ListItem("menus/cheats/dl_all"_i18n);
dlAll->getClickEvent()->subscribe([&, cheatsVer](brls::View* view) {

View file

@ -120,14 +120,22 @@ namespace download {
}
}
std::vector<std::uint8_t> downloadFile(const std::string& url, const char* output, int api)
long downloadFile(const std::string& url, const char* output, int api)
{
std::vector<std::uint8_t> dummy;
return downloadFile(url, dummy, output, api);
}
long downloadFile(const std::string& url, std::vector<std::uint8_t>& res, const char* output, int api)
{
ProgressEvent::instance().reset();
CURL *curl = curl_easy_init();
ntwrk_struct_t chunk = {0};
long status_code;
time_old = std::chrono::steady_clock::now();
dlold = 0.0f;
bool can_download = true;
if (curl)
{
FILE *fp = fopen(output, "wb");
@ -157,6 +165,7 @@ std::vector<std::uint8_t> downloadFile(const std::string& url, const char* outpu
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, download_progress);
}
curl_easy_perform(curl);
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &status_code);
if (fp && chunk.offset && can_download)
fwrite(chunk.data, 1, chunk.offset, fp);
@ -169,22 +178,19 @@ std::vector<std::uint8_t> downloadFile(const std::string& url, const char* outpu
fclose(chunk.out);
if(!can_download) {
brls::Application::crash("menus/errors/unsufficient_storage"_i18n);
brls::Application::crash("menus/errors/insufficient_storage"_i18n);
usleep(2000000);
brls::Application::quit();
return (std::vector<std::uint8_t>){};
res = {};
}
if (*output == 0) {
std::vector<std::uint8_t> res(chunk.data, chunk.data + chunk.offset);
free(chunk.data);
return res;
}
else {
free(chunk.data);
return (std::vector<std::uint8_t>){};
res.assign(chunk.data, chunk.data + chunk.offset);
}
free(chunk.data);
return status_code;
}
std::string fetchTitle(const std::string& url){
@ -222,11 +228,11 @@ std::string fetchTitle(const std::string& url){
return ver;
}
std::string downloadPage(const std::string& url, std::vector<std::string> headers, std::string body){
std::string res;
long downloadPage(const std::string& url, std::string& res, const std::vector<std::string>& headers, const std::string& body){
CURL *curl_handle;
struct MemoryStruct chunk;
struct curl_slist *list = NULL;
long status_code;
chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
@ -250,64 +256,39 @@ std::string downloadPage(const std::string& url, std::vector<std::string> header
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_perform(curl_handle);
curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &status_code);
curl_easy_cleanup(curl_handle);
res = std::string(chunk.memory);
free(chunk.memory);
curl_global_cleanup();
return res;
return status_code;
}
std::vector<std::uint8_t> downloadPageBinary(const std::string& url, std::vector<std::string> headers, std::string body){
CURL *curl_handle;
struct MemoryStruct chunk;
struct curl_slist *list = NULL;
long getRequest(const std::string& url, nlohmann::ordered_json& res, const std::vector<std::string>& headers, const std::string& body) {
std::string request;
long status_code = downloadPage(url, request, headers, body);
chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
if(json::accept(request)) res = nlohmann::ordered_json::parse(request);
else res = nlohmann::ordered_json::object();
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
if(!headers.empty()){
for (auto& h : headers){
list = curl_slist_append(list, h.c_str());
}
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
}
if(body != "") {
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, body.c_str());
}
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);
std::vector<std::uint8_t> res(chunk.memory, chunk.memory + ((sizeof(chunk.memory)) * (chunk.size + 16)));
free(chunk.memory);
curl_global_cleanup();
return res;
}
nlohmann::ordered_json getRequest(const std::string& url, std::vector<std::string> headers, std::string body) {
std::string request = downloadPage(url, headers, body);
if(json::accept(request)) return nlohmann::ordered_json::parse(request);
else return nlohmann::ordered_json::object();
return status_code;
}
std::vector<std::pair<std::string, std::string>> getLinks(const std::string& url) {
std::string request;
request = downloadPage(url);
nlohmann::ordered_json jason = json::accept(request) ? nlohmann::ordered_json::parse(request) : nlohmann::ordered_json::object();
nlohmann::ordered_json request;
getRequest(url, request);
std::vector<std::pair<std::string, std::string>> res;
for (auto it = jason.begin(); it != jason.end(); ++it) {
for (auto it = request.begin(); it != request.end(); ++it) {
res.push_back(std::make_pair(it.key(), it.value()));
}
return res;
}
std::vector<std::pair<std::string, std::string>> getLinksFromJson(const nlohmann::ordered_json& json_object) {
std::vector<std::pair<std::string, std::string>> res;
for (auto it = json_object.begin(); it != json_object.end(); ++it) {
res.push_back(std::make_pair(it.key(), it.value()));
}
return res;

View file

@ -1,22 +1,23 @@
#include "download_cheats_page.hpp"
#include <fstream>
#include <filesystem>
#include "constants.hpp"
#include "download.hpp"
#include "utils.hpp"
#include "fs.hpp"
#include "current_cfw.hpp"
#include <fstream>
#include <filesystem>
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
DownloadCheatsPage::DownloadCheatsPage(uint64_t tid) : AppletFrame(true, true), tid(tid)
DownloadCheatsPage::DownloadCheatsPage(uint64_t tid, const std::string& name) : AppletFrame(true, true), tid(tid)
{
list = new brls::List();
this->setTitle(name);
this->setFooterText("Game version: v" + std::to_string(this->version / 0x10000));
GetVersion();
GetBuildID();
this->setTitle("menus/cheats/menu"_i18n);
this->setFooterText("Game version: v" + std::to_string(this->version / 0x10000));
}
void DownloadCheatsPage::GetBuildID() {
@ -56,7 +57,8 @@ void DownloadCheatsPage::GetVersion() {
}
void DownloadCheatsPage::GetBuildIDFromFile() {
json versions_json = download::getRequest(VERSIONS_DIRECTORY + util::formatApplicationId(this->tid) + ".json");
nlohmann::ordered_json versions_json;
download::getRequest(VERSIONS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", versions_json);
std::string version_str = std::to_string(this->version);
if(versions_json.find(version_str) != versions_json.end()) {
@ -87,9 +89,9 @@ void DownloadCheatsPage::WriteCheats(std::string cheatContent) {
std::ofstream cheatFile;
cheatFile.open(path, std::ios::app);
cheatFile << "\n\n" << cheatContent;
std::ofstream updated;
/* std::ofstream updated;
updated.open(UPDATED_TITLES_PATH, std::ios::app);
updated << "\n" << tidstr;
updated << "\n" << tidstr; */
}
void DownloadCheatsPage::DeleteCheats() {
@ -108,10 +110,8 @@ void DownloadCheatsPage::DeleteCheats() {
std::filesystem::remove(path + util::formatApplicationId(this->tid) + "/cheats/" + this->bid + ".txt");
}
DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid) : DownloadCheatsPage(tid)
DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
this->setTitle("menus/cheats/menu"_i18n);
list = new brls::List();
label = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/cheats/cheatslips_dl"_i18n + "\n\uE016 Build ID: " + this->bid,
@ -121,7 +121,8 @@ DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid) : Dow
if(this->bid != "") {
std::vector<std::string> headers = {"accept: application/json"};
json cheatsInfo = download::getRequest(CHEATSLIPS_CHEATS_URL + util::formatApplicationId(this->tid) + "/" + this->bid, headers);
nlohmann::ordered_json cheatsInfo;
download::getRequest(CHEATSLIPS_CHEATS_URL + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
if(cheatsInfo.find("cheats") != cheatsInfo.end()) {
for (const auto& p : cheatsInfo["cheats"].items()) {
json cheat = p.value();
@ -174,7 +175,8 @@ DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid) : Dow
if(token.find("token") != token.end()) {
headers.push_back("X-API-TOKEN: " + token["token"].get<std::string>());
}
nlohmann::ordered_json cheatsInfo = download::getRequest("https://www.cheatslips.com/api/v1/cheats/" + util::formatApplicationId(this->tid) + "/" + this->bid, headers);
nlohmann::ordered_json cheatsInfo;
download::getRequest("https://www.cheatslips.com/api/v1/cheats/" + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
if(cheatsInfo.find("cheats") != cheatsInfo.end()) {
for (const auto& p : cheatsInfo["cheats"].items()) {
if(std::find(ids.begin(), ids.end(), p.value()["id"]) != ids.end()) {
@ -274,9 +276,8 @@ void DownloadCheatsPage_CheatSlips::ShowCheatsContent(nlohmann::ordered_json tit
brls::PopupFrame::open("menus/cheats/sheet_content"_i18n, appView, "", "");
}
DownloadCheatsPage_GbaTemp::DownloadCheatsPage_GbaTemp(uint64_t tid) : DownloadCheatsPage(tid)
DownloadCheatsPage_GbaTemp::DownloadCheatsPage_GbaTemp(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
list = new brls::List();
label = new brls::Label(
brls::LabelStyle::DESCRIPTION,
fmt::format("menus/cheats/gbatemp_dl"_i18n, this->bid),
@ -285,7 +286,8 @@ DownloadCheatsPage_GbaTemp::DownloadCheatsPage_GbaTemp(uint64_t tid) : DownloadC
list->addView(label);
if(this->bid != "") {
nlohmann::ordered_json cheatsJson = download::getRequest(CHEATS_DIRECTORY + util::formatApplicationId(this->tid) + ".json");
nlohmann::ordered_json cheatsJson;
download::getRequest(CHEATS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", cheatsJson);
if(cheatsJson.find(this->bid) != cheatsJson.end()) {
for (const auto& p : cheatsJson[this->bid].items()) {
json cheat = p.value();

View file

@ -33,7 +33,7 @@ DownloadPayloadPage::DownloadPayloadPage() : AppletFrame(true, true)
new ConfirmPage(stagedFrame, text)
);
stagedFrame->addStage(
new WorkerPage(stagedFrame, "menus/common/downloading"_i18n, [url, path](){download::downloadFile(url, path.c_str(), OFF);})
new WorkerPage(stagedFrame, "menus/common/downloading"_i18n, [url, path](){ download::downloadFile(url, path.c_str(), OFF); })
);
stagedFrame->addStage(
new ConfirmPage(stagedFrame, "menus/common/all_done"_i18n, true)

View file

@ -36,7 +36,7 @@ namespace extract {
if(R_SUCCEEDED(fs::getFreeStorageSD(freeStorage))) {
if(uncompressedSize * 1.1 > freeStorage) {
unzipper.close();
brls::Application::crash("menus/errors/unsufficient_storage"_i18n);
brls::Application::crash("menus/errors/insufficient_storage"_i18n);
usleep(2000000);
brls::Application::quit();
}
@ -107,7 +107,6 @@ std::vector<std::string> getInstalledTitlesNs(){
NsApplicationRecord *records = new NsApplicationRecord[MaxTitleCount]();
NsApplicationControlData *controlData = NULL;
NacpLanguageEntry* langEntry = NULL;
s32 recordCount = 0;
u64 controlSize = 0;
@ -116,25 +115,28 @@ std::vector<std::string> getInstalledTitlesNs(){
for (s32 i = 0; i < recordCount; i++){
controlSize = 0;
controlData = (NsApplicationControlData*)malloc(sizeof(NsApplicationControlData));
if(controlData != NULL)
if(controlData == NULL) {
free(controlData);
break;
}
else {
memset(controlData, 0, sizeof(NsApplicationControlData));
}
if(R_FAILED(nsGetApplicationControlData(NsApplicationControlSource_Storage, records[i].application_id, controlData, sizeof(NsApplicationControlData), &controlSize))) continue;
if(controlSize < sizeof(controlData->nacp)) continue;
if(R_FAILED(nacpGetLanguageEntry(&controlData->nacp, &langEntry))) continue;
titles.push_back(util::formatApplicationId(records[i].application_id));
}
}
free(controlData);
}
}
delete[] records;
std::sort(titles.begin(), titles.end());
return titles;
}
std::vector<std::string> excludeTitles(const std::string& path, std::vector<std::string> listedTitles){
std::vector<std::string> excludeTitles(const std::string& path, const std::vector<std::string>& listedTitles){
std::vector<std::string> titles;
std::ifstream file(path);
std::string name;
@ -165,7 +167,7 @@ void extractCheats(const std::string& zipPath, std::vector<std::string> titles,
ProgressEvent::instance().reset();
zipper::Unzipper unzipper(zipPath);
std::vector<zipper::ZipEntry> entries = unzipper.entries();
std::set<std::string> extractedTitles;
//std::set<std::string> extractedTitles;
int offset = 0;
switch(cfw){
case CFW::ams:
@ -233,7 +235,7 @@ void extractCheats(const std::string& zipPath, std::vector<std::string> titles,
unzipper.extractEntry(parents[l]);
for(auto& e : children[l]){
unzipper.extractEntry(e);
extractedTitles.insert(id);
//extractedTitles.insert(id);
ProgressEvent::instance().setStep(j);
id = e.substr(offset, 16);
std::transform(id.begin(), id.end(), id.begin(), ::toupper);
@ -244,10 +246,8 @@ void extractCheats(const std::string& zipPath, std::vector<std::string> titles,
}
}
unzipper.close();
writeTitlesToFile(extractedTitles, UPDATED_TITLES_PATH);
auto cheatsVerVec = download::downloadFile(CHEATS_URL_VERSION);
std::string cheatsVer(cheatsVerVec.begin(), cheatsVerVec.end());
util::saveVersion(cheatsVer, CHEATS_VERSION);
//writeTitlesToFile(extractedTitles, UPDATED_TITLES_PATH);
download::downloadFile(CHEATS_URL_VERSION, CHEATS_VERSION, OFF);
ProgressEvent::instance().setStep(ProgressEvent::instance().getMax());
}
@ -284,9 +284,7 @@ void extractAllCheats(const std::string& zipPath, CFW cfw){
ProgressEvent::instance().incrementStep(1);
}
unzipper.close();
auto cheatsVerVec = download::downloadFile(CHEATS_URL_VERSION);
std::string cheatsVer(cheatsVerVec.begin(), cheatsVerVec.end());
util::saveVersion(cheatsVer, CHEATS_VERSION);
download::downloadFile(CHEATS_URL_VERSION, CHEATS_VERSION, OFF);
ProgressEvent::instance().setStep(ProgressEvent::instance().getMax());
}
@ -338,7 +336,7 @@ void removeCheats(CFW cfw){
}
ProgressEvent::instance().incrementStep(1);
}
std::filesystem::remove(UPDATED_TITLES_PATH);
//std::filesystem::remove(UPDATED_TITLES_PATH);
std::filesystem::remove(CHEATS_VERSION);
ProgressEvent::instance().setStep(ProgressEvent::instance().getMax());
}

View file

@ -39,7 +39,7 @@ HideTabsPage::HideTabsPage() : AppletFrame(true, true) {
if(hideStatus.find("cfw") != hideStatus.end()) {
status = hideStatus["cfw"];
}
cfws = new brls::ToggleListItem("menus/main/update_cfw"_i18n, status);
cfws = new brls::ToggleListItem("menus/main/update_bootloaders"_i18n, status);
list->addView(cfws);
status = false;

View file

@ -17,7 +17,8 @@ using namespace i18n::literals;
ListDownloadTab::ListDownloadTab(const archiveType type) :
brls::List()
{
std::vector<std::pair<std::string, std::string>> links, sxoslinks;
//std::vector<std::pair<std::string, std::string>> links, sxoslinks;
std::vector<std::pair<std::string, std::string>> links;
std::string operation("menus/main/getting"_i18n);
std::string firmwareText("menus/main/firmware_text"_i18n);
@ -47,16 +48,16 @@ ListDownloadTab::ListDownloadTab(const archiveType type) :
break;
case archiveType::cfw:
links = download::getLinks(CFW_URL);
sxoslinks = download::getLinks(SXOS_URL);
links.insert(links.end(), sxoslinks.begin(), sxoslinks.end());
// sxos is dead anyways
/* sxoslinks = download::getLinks(SXOS_URL);
links.insert(links.end(), sxoslinks.begin(), sxoslinks.end()); */
operation += "menus/main/cfw"_i18n;
this->description->setText(
"menus/main/cfw_text"_i18n
"menus/main/bootloaders_text"_i18n
);
break;
case archiveType::cheats:
auto cheatsVerVec = download::downloadFile(CHEATS_URL_VERSION);
std::string cheatsVer(cheatsVerVec.begin(), cheatsVerVec.end());
std::string cheatsVer = util::downloadFileToString(CHEATS_URL_VERSION);
if(cheatsVer != ""){
switch(CurrentCfw::running_cfw){
case CFW::sxos:
@ -112,7 +113,7 @@ ListDownloadTab::ListDownloadTab(const archiveType type) :
else{
notFound = new brls::Label(
brls::LabelStyle::DESCRIPTION,
brls::LabelStyle::SMALL,
"menus/main/links_not_found"_i18n,
true
);
@ -138,7 +139,7 @@ void ListDownloadTab::createCheatSlipItem() {
cheatslipsItem->setHeight(LISTITEM_HEIGHT);
cheatslipsItem->getClickEvent()->subscribe([&](brls::View* view) {
if(std::filesystem::exists(TOKEN_PATH)) {
brls::Application::pushView(new AppPage(appPageType::cheatSlips));
brls::Application::pushView(new AppPage_CheatSlips());
return true;
}
else {
@ -163,7 +164,8 @@ void ListDownloadTab::createCheatSlipItem() {
}
std::string body = "{\"email\":\"" + std::string(usr)
+ "\",\"password\":\"" + std::string(pwd) + "\"}";
nlohmann::json token = download::getRequest(CHEATSLIPS_TOKEN_URL,
nlohmann::ordered_json token;
download::getRequest(CHEATSLIPS_TOKEN_URL, token,
{"Accept: application/json",
"Content-Type: application/json",
"charset: utf-8"},
@ -172,7 +174,7 @@ void ListDownloadTab::createCheatSlipItem() {
std::ofstream tokenFile(TOKEN_PATH);
tokenFile << token.dump();
tokenFile.close();
brls::Application::pushView(new AppPage(appPageType::cheatSlips));
brls::Application::pushView(new AppPage_CheatSlips());
return true;
}
else {
@ -196,7 +198,7 @@ void ListDownloadTab::creategbatempItem() {
gbatempItem = new brls::ListItem("menus/cheats/get_gbatemp"_i18n);
gbatempItem->setHeight(LISTITEM_HEIGHT);
gbatempItem->getClickEvent()->subscribe([&](brls::View* view) {
brls::Application::pushView(new AppPage(appPageType::gbatempCheats));
brls::Application::pushView(new AppPage_Gbatemp());
return true;
});
this->addView(gbatempItem);

View file

@ -31,6 +31,7 @@ int main(int argc, char* argv[])
else
i18n::loadTranslations();
//appletInitializeGamePlayRecording();
// Setup verbose logging on PC
#ifndef __SWITCH__
@ -42,6 +43,8 @@ int main(int argc, char* argv[])
nsInitialize();
socketInitializeDefault();
nxlinkStdio();
pmdmntInitialize();
pminfoInitialize();
splInitialize();
romfsInit();
@ -63,6 +66,8 @@ int main(int argc, char* argv[])
romfsExit();
splExit();
pminfoExit();
pmdmntExit();
socketExit();
nsExit();
setsysExit();

View file

@ -40,7 +40,7 @@ MainFrame::MainFrame() : TabFrame()
this->addTab("menus/main/update_ams"_i18n, new AmsTab(erista));
if(hideStatus.find("cfw") == hideStatus.end() || !hideStatus["cfw"])
this->addTab("menus/main/update_cfw"_i18n, new ListDownloadTab(archiveType::cfw));
this->addTab("menus/main/update_bootloaders"_i18n, new ListDownloadTab(archiveType::cfw));
if(hideStatus.find("sigpatches") == hideStatus.end() || !hideStatus["sigpatches"])
this->addTab("menus/main/update_sigpatches"_i18n, new ListDownloadTab(archiveType::sigpatches));

View file

@ -124,8 +124,8 @@ ToolsTab::ToolsTab(std::string tag, bool erista) : brls::List()
else {
strcpy(url, "https://duckduckgo.com");
}
int at = appletGetAppletType();
std::string error = "";
int at = appletGetAppletType();
if(at == AppletType_Application) { // Running as a title
WebCommonConfig conf;
WebCommonReply out;

View file

@ -7,11 +7,11 @@
#include "main_frame.hpp"
#include "reboot_payload.h"
#include "unistd.h"
#include "progress_event.hpp"
#include <switch.h>
#include <filesystem>
#include <fstream>
namespace i18n = brls::i18n;
using namespace i18n::literals;
@ -28,34 +28,38 @@ bool isArchive(const std::string& path){
return fileContent.find("DOCTYPE") == std::string::npos;
}
void downloadArchive(std::string url, archiveType type){
void downloadArchive(std::string url, archiveType type) {
long status_code;
downloadArchive(url,type, status_code);
}
void downloadArchive(std::string url, archiveType type, long& status_code) {
fs::createTree(DOWNLOAD_PATH);
AppletType at;
switch(type){
case archiveType::sigpatches:
download::downloadFile(url, SIGPATCHES_FILENAME, OFF);
status_code = download::downloadFile(url, SIGPATCHES_FILENAME, OFF);
break;
case archiveType::cheats:
download::downloadFile(url, CHEATS_FILENAME, OFF);
status_code = download::downloadFile(url, CHEATS_FILENAME, OFF);
break;
case archiveType::fw:
at = appletGetAppletType();
if (at == AppletType_Application || at == AppletType_SystemApplication) {
download::downloadFile(url, FIRMWARE_FILENAME, OFF);
if (!isApplet()) {
status_code = download::downloadFile(url, FIRMWARE_FILENAME, OFF);
}
else{
brls::Application::crash("menus/utils/fw_warning"_i18n);
}
break;
case archiveType::app:
download::downloadFile(url, APP_FILENAME, OFF);
status_code = download::downloadFile(url, APP_FILENAME, OFF);
break;
case archiveType::cfw:
download::downloadFile(url, CFW_FILENAME, OFF);
status_code = download::downloadFile(url, CFW_FILENAME, OFF);
break;
case archiveType::ams_cfw:
download::downloadFile(url, AMS_FILENAME, OFF);
status_code = download::downloadFile(url, AMS_FILENAME, OFF);
}
ProgressEvent::instance().setStatusCode(status_code);
}
int showDialogBox(std::string text, std::string opt){
@ -107,9 +111,7 @@ void extractArchive(archiveType type, std::string tag){
switch(type){
case archiveType::sigpatches:
if(isArchive(SIGPATCHES_FILENAME)) {
/* std::string backup(HEKATE_IPL_PATH);
backup += ".old"; */
if(std::filesystem::exists(HEKATE_IPL_PATH)){
/* if(std::filesystem::exists(HEKATE_IPL_PATH)){
overwriteInis = showDialogBox("menus/utils/overwrite"_i18n + std::string(HEKATE_IPL_PATH) +"?", "menus/common/no"_i18n, "menus/common/yes"_i18n);
if(overwriteInis == 0){
extract::extract(SIGPATCHES_FILENAME, ROOT_PATH, HEKATE_IPL_PATH);
@ -117,10 +119,10 @@ void extractArchive(archiveType type, std::string tag){
else{
extract::extract(SIGPATCHES_FILENAME);
}
}
else{
} */
//else{
extract::extract(SIGPATCHES_FILENAME);
}
//}
}
else{
brls::Application::crash("menus/utils/wrong_type_sigpatches"_i18n);
@ -218,14 +220,22 @@ void rebootToPayload(const std::string& path) {
reboot_to_payload(path.c_str(), CurrentCfw::running_cfw != CFW::ams);
}
std::string getLatestTag(const std::string& url){
nlohmann::json tag = download::getRequest(url, {"accept: application/vnd.github.v3+json"});
std::string getLatestTag(const std::string& url) {
nlohmann::ordered_json tag;
download::getRequest(url, tag, {"accept: application/vnd.github.v3+json"});
if(tag.find("tag_name") != tag.end())
return tag["tag_name"];
else
return "";
}
std::string downloadFileToString(const std::string& url) {
std::vector<uint8_t> bytes;
download::downloadFile(url, bytes);
std::string str(bytes.begin(), bytes.end());
return str;
}
void saveVersion(std::string version, const std::string& path){
std::ofstream newVersion(path);
newVersion << version << std::endl;
@ -256,4 +266,33 @@ void removeSysmodulesFlags(const std::string& directory) {
}
}
std::string lowerCase(const std::string& str) {
std::string res = str;
std::for_each(res.begin(), res.end(), [](char & c){
c = std::tolower(c);
});
return res;
}
std::string getErrorMessage(long status_code) {
std::string res;
switch(status_code) {
case 500:
res = fmt::format("{0:}: Internal Server Error", status_code);
break;
case 503:
res = fmt::format("{0:}: Service Temporarily Unavailable", status_code);
break;
default:
res = fmt::format("error: {0:}", status_code);
break;
}
return res;
}
bool isApplet() {
AppletType at = appletGetAppletType();
return at != AppletType_Application && at != AppletType_SystemApplication;
}
}

View file

@ -1,13 +1,14 @@
#include "worker_page.hpp"
#include <string>
#include <functional>
#include "utils.hpp"
#include "download.hpp"
#include "extract.hpp"
#include "constants.hpp"
#include "progress_event.hpp"
#include <string>
#include <functional>
namespace i18n = brls::i18n;
using namespace i18n::literals;
WorkerPage::WorkerPage(brls::StagedAppletFrame* frame, const std::string& text, worker_func_t worker_func): frame(frame), workerFunc(worker_func), text(text)
{
@ -27,6 +28,8 @@ WorkerPage::WorkerPage(brls::StagedAppletFrame* frame, const std::string& text,
void WorkerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
{
if (this->draw_page)
{
if (!this->workStarted)
{
appletSetMediaPlaybackState(true);
@ -38,8 +41,15 @@ void WorkerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned hei
{
brls::Logger::debug("Worker done");
appletSetMediaPlaybackState(false);
if (ProgressEvent::instance().getStatusCode() > 399) {
this->draw_page = false;
brls::Application::crash(fmt::format("menus/errors/error_message"_i18n, util::getErrorMessage(ProgressEvent::instance().getStatusCode())));
}
else{
ProgressEvent::instance().setStatusCode(0);
frame->nextStage();
}
}
else
{
this->progressDisp->setProgress(ProgressEvent::instance().getStep(), ProgressEvent::instance().getMax());
@ -50,6 +60,7 @@ void WorkerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned hei
}
this->label->frame(ctx);
}
}
}
void WorkerPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)