1
0
Fork 0
mirror of https://github.com/HamletDuFromage/aio-switch-updater.git synced 2024-09-16 20:13:35 +01:00

Added cheatslips support, way to hide tabs, several tweaks and cleanups

This commit is contained in:
flb 2021-02-06 18:24:47 +01:00
parent 91cf2f00b9
commit 2481533a0a
43 changed files with 566 additions and 103 deletions

View file

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

View file

@ -4,6 +4,13 @@
![tag](https://img.shields.io/github/v/release/HamletDuFromage/AIO-switch-updater)
![GitHub](https://img.shields.io/github/license/HamletDuFromage/aio-switch-updater)
[![btc](https://img.shields.io/badge/BTC-1CoFc1bY5AHLP6Noe1zmqnJnp7ZWBxyo79-yellow)](https://github.com/HamletDuFromage/aio-switch-updater#like-the-app)
[![eth](https://img.shields.io/badge/ETH-0xf68f568e21a15934e0e9a6949288c3ca009140ba-purple)](https://github.com/HamletDuFromage/aio-switch-updater#like-the-app)
[![eth](https://img.shields.io/badge/LINK-0xf68f568e21a15934e0e9a6949288c3ca009140ba-lightblue
)](https://github.com/HamletDuFromage/aio-switch-updater#like-the-app)
[//]: ([![ko-fi](https://img.shields.io/badge/ko--fi-buy%20me%20a%20coffee-ff69b4)](https://ko-fi.com/hamletdufromage))
@ -19,16 +26,17 @@ Copy the `aio-switch-updater/` directory to `/switch/` in your sdcard
## Description of the features
### ⬦ Update CFW
Download the most popular Switch CFWs. After downloading the CFW archive, the program will ask you whether you want to override your existing .ini files. 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.
- Download the most popular Switch CFWs. After downloading the CFW archive, the program will ask you whether you want to override your existing .ini files. 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.
### ⬦ Update Sigpatches
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.
- 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 or ChoiDuJour.
### ⬦ 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`.
- 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`.
- Since v2.0.0, aio-switch-updater can also download cheat sheets from [`CheatSlips.com`](https://www.cheatslips.com/).
## Extras (in the `Tools` tab)
- Reboot to specific payload.
@ -40,11 +48,12 @@ Downloads and extracts daily-updated cheat code. The program will only extract c
- Edit internet settings (DNS, IP address, MTU, etc). Add you own configs to `config/aio-switch-updater/internet.json`. You can find a template in the root of the repo.
## Screenshots
![ss](https://user-images.githubusercontent.com/61667930/105403528-263eda80-5c29-11eb-842d-c3f8c4e19466.jpg)
![ss](https://user-images.githubusercontent.com/61667930/107124480-7a41f400-68a4-11eb-9a01-d7b3c9f3e828.jpg)
![ss](https://user-images.githubusercontent.com/61667930/93721670-42e6db00-fb81-11ea-9f94-1308898398f0.jpg)
![ss](https://user-images.githubusercontent.com/61667930/93721673-437f7180-fb81-11ea-9256-377575148a40.jpg)
![ss](https://user-images.githubusercontent.com/61667930/93691404-3193c500-fad4-11ea-9647-927c979960bc.jpg)
![ss](https://user-images.githubusercontent.com/61667930/105404737-98fc8580-5c2a-11eb-9efb-eb6e69d82b7b.jpg)
![ss](https://user-images.githubusercontent.com/61667930/107124438-364eef00-68a4-11eb-97d4-57df6d8aaa9d.jpg)
![ss](https://user-images.githubusercontent.com/61667930/105404840-b9c4db00-5c2a-11eb-8385-48454465063c.jpg)
![ss](https://user-images.githubusercontent.com/61667930/105407043-80da3580-5c2d-11eb-8f35-27f77079ea53.jpg)
![ss](https://user-images.githubusercontent.com/61667930/105403520-250dad80-5c29-11eb-95e6-d9ab3822d1d6.jpg)
@ -54,45 +63,47 @@ You need to have installed devkitPro and devkitARM in order to compile this proj
Install the required dependencies:
```bash
sudo (dkp-)pacman -Sy
$ sudo (dkp-)pacman -Sy
```
```bash
sudo (dkp-)pacman -S switch-glfw \
switch-curl \
switch-glm \
switch-mbedtls \
switch-zlib
$ sudo (dkp-)pacman -S switch-glfw \
switch-curl \
switch-glm \
switch-mbedtls \
switch-zlib
```
Use [`switch-ex-curl`](https://github.com/eXhumer/switch-ex-curl) instead of `switch-curl` to use this app with an invalid SSL certificate.
Clone the repository
```bash
git clone --recursive https://github.com/HamletDuFromage/aio-switch-updater
cd aio-switch-updater
$ git clone --recursive https://github.com/HamletDuFromage/aio-switch-updater
$ cd aio-switch-updater
```
Compile
```bash
make
```
OR
```bash
make -j$(nproc)
$ cd aiosu-forwarder
$ make
$ cd ..
$ make
```
## Disclaimer
I do not own, host nor distribute any of the files that can be downloaded with this homebrew tool. At the owner's request, I will immediately remove the ability to download any problematic file.
## Special thanks
- [natinusala](https://github.com/natinusala) for the Borealis library.
- [tiansongyu](https://github.com/tiansongyu) for bringing support for multi-language and for his Chinese translation.
- [yyoossk](https://github.com/yyoossk) for the Japanese locale.
- [sergiou87](https://github.com/sergiou87) for the Spanish locale.
- [pedruhb](https://github.com/pedruhb) for the Brazilian locale.
- [AD2076](https://github.com/AD2076) for the Italian locale.
- [qazrfv1234](https://github.com/qazrfv1234) for the Traditional Chinese locale.
- [Team Neptune](https://github.com/Team-Neptune) whose rcm code I used
- [fennectech](https://github.com/fennectech) for helping test the app and providing suggestions
-
- [Team Neptune](https://github.com/Team-Neptune) whose rcm code I used.
- [fennectech](https://github.com/fennectech) for helping test the app and providing suggestions.
- Iliak for cheatslips.com.
### Like the app?
[//]: [![5cbed8a433a3f45a772abaf5_SupportMe_blue-p-500](https://user-images.githubusercontent.com/61667930/93899702-1a2b2680-fce4-11ea-9eaa-4e2b44eebe86.png)](https://ko-fi.com/hamletdufromage)
- BTC: 1CoFc1bY5AHLP6Noe1zmqnJnp7ZWBxyo79
- ETH: 0xf68f568e21a15934e0e9a6949288c3ca009140ba
- LINKCHAIN: 0xf68f568e21a15934e0e9a6949288c3ca009140ba

View file

@ -11,7 +11,7 @@
class AmsTab : public brls::List
{
private:
std::vector<brls::ListItem*> linkItems;
brls::ListItem* listItem;
brls::Label *notFound;
brls::Label *description;
public:

View file

@ -9,6 +9,7 @@
#include "worker_page.hpp"
#include "confirm_page.hpp"
#include "download_cheats_page.hpp"
typedef struct app App;
@ -19,10 +20,10 @@ class AppPage : public brls::AppletFrame
brls::List* list;
brls::Label* label;
brls::ListItem* download;
brls::ListItem* listItem;
std::vector<App*> apps;
std::set<std::string> titles;
std::vector<brls::ListItem*> items;
public:
AppPage();
AppPage(bool cheatSlips = false);
};

View file

@ -34,6 +34,9 @@
#define CHEATS_RELEASE_URL "https://github.com/HamletDuFromage/switch-cheats-db/releases/tag/v1.0"
#define CHEATS_URL_TITLES "https://github.com/HamletDuFromage/switch-cheats-db/releases/download/v1.0/titles.zip"
#define CHEATS_URL_CONTENTS "https://github.com/HamletDuFromage/switch-cheats-db/releases/download/v1.0/contents.zip"
#define LOOKUP_TABLE_URL "https://raw.githubusercontent.com/HamletDuFromage/switch-cheats-db/master/versions.json"
#define CHEATSLIPS_TOKEN_URL "https://www.cheatslips.com/api/v1/token"
#define TOKEN_PATH "/config/aio-switch-updater/token.json"
#define CHEATS_FILENAME "/config/aio-switch-updater/cheats.zip"
#define CHEATS_EXCLUDE "/config/aio-switch-updater/exclude.txt"
#define FILES_IGNORE "/config/aio-switch-updater/preserve.txt"
@ -70,6 +73,8 @@
#define SEPT_DIRECTORY_PATH "/config/aio-switch-updater/sept/"
#define FW_DIRECTORY_PATH "/firmware/"
#define HIDE_TABS_JSON "/config/aio-switch-updater/hide_tabs.json"
#define ROMFS_FORWARDER "romfs:/aiosu-forwarder.nro"
#define FORWARDER_PATH "/config/aio-switch-updater/aiosu-forwarder.nro"

View file

@ -9,12 +9,13 @@
#include <string>
#include <regex>
#include <switch.h>
#include "progress_event.hpp"
#include "json.hpp"
void downloadFile(const char *url, const char *output, int api);
std::tuple<std::vector<std::string>, std::vector<std::string>> fetchLinks(const char *url);
std::string fetchTitle(const char *url);
std::string downloadPage(const char* url);
std::string downloadPage(const char* url, std::vector<std::string> headers = {}, std::string body = "");
nlohmann::json getRequest(std::string url, std::vector<std::string> headers = {}, std::string body = "");

View file

@ -0,0 +1,24 @@
#pragma once
#include <borealis.hpp>
#include <switch.h>
#include "download.hpp"
#include "utils.hpp"
#include "json.hpp"
class DownloadCheatsPage : public brls::AppletFrame
{
private:
brls::List* list;
brls::Label* label;
brls::ListItem* del;
brls::ToggleListItem* listItem;
std::vector<std::pair<brls::ToggleListItem*, int>> toggles;
public:
DownloadCheatsPage(uint64_t tid);
std::string GetBuilID(uint64_t tid);
std::string GetCheatsTitle(nlohmann::json cheat);
void WriteCheats(uint64_t tid, std::string bid, std::string cheatContent);
void DeleteCheats(uint64_t tid, std::string bid);
};

View file

@ -0,0 +1,22 @@
#pragma once
#include <borealis.hpp>
#include "json.hpp"
#include "constants.hpp"
#include <fstream>
class HideTabsPage : public brls::AppletFrame
{
private:
brls::List* list;
brls::Label* label;
brls::ToggleListItem* about;
brls::ToggleListItem* ams;
brls::ToggleListItem* cfws;
brls::ToggleListItem* sigpatches;
brls::ToggleListItem* fws;
brls::ToggleListItem* cheats;
public:
HideTabsPage();
};

View file

@ -10,7 +10,8 @@
class ListDownloadTab : public brls::List
{
private:
std::vector<brls::ListItem*> linkItems;
brls::ListItem* listItem;
brls::ListItem *cheatslipsItem;
brls::Label *notFound;
brls::Label *description;
public:

View file

@ -6,6 +6,7 @@
#include "list_download_tab.hpp"
#include "ams_tab.hpp"
#include "tools_tab.hpp"
#include "json.hpp"
class MainFrame : public brls::TabFrame
{

View file

@ -13,6 +13,7 @@
#include "net_page.hpp"
#include "extract.hpp"
#include "utils.hpp"
#include "hide_tabs_page.hpp"
//#include "ntcp.hpp"
class ToolsTab : public brls::List
@ -27,6 +28,7 @@ class ToolsTab : public brls::List
brls::ListItem* changelog;
brls::ListItem* language;
brls::ListItem* cleanUp;
brls::ListItem* hideTabs;
brls::ListItem* ntcp;
brls::ListItem* netSettings;
brls::ListItem* browser;

View file

@ -1,7 +1,6 @@
#pragma once
#include <regex>
#include <iostream>
#include <set>
#include <switch.h>
#include "download.hpp"
@ -19,7 +18,6 @@ struct app
uint64_t tid;
NsApplicationName name;
NsApplicationIcon icon;
brls::ListItem* listItem;
};

@ -1 +1 @@
Subproject commit b81a39f73b98aa61919b251521ba1297157a3cf7
Subproject commit 1e59d4aa7c87792fe92885f4fd17bd00531793e3

@ -1 +1 @@
Subproject commit 29f02751f063c2440d363f2049b0b59f5b330b20
Subproject commit f80681569d73ffb27e85473e3bccb95b9856f1c1

View file

@ -7,5 +7,9 @@
"crash_frame": {
"button": "OK"
},
"thumbnail_sidebar": {
"save": "Save"
}
}

View file

@ -0,0 +1,5 @@
{
"first_button": "First button",
"second_button": "Second button",
"third_button": "Third button"
}

View file

@ -3,7 +3,8 @@
"About_Title": "All-in-One Nintendo Switch Updater",
"copyright": "AIO-switch-updater is licensed under GPL-3.0\n\u00A9 2020 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 three hours. If a link remains broken after 3 hours have passed, please open a Github issue.\n",
"donate": "\uE016 Like the app? Consider donating to support my efforts: 'https://git.io/donate_homlet'",
"app_page.cpp":"",
"app_title": "Installed cheats",
"app_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.",
@ -62,6 +63,8 @@
"v1_5_1_text": "\uE016 A few graphical tweaks.",
"v1_5_2": "v1.5.2",
"v1_5_2_text": "\uE016 Added support for Traditional Chinese (thanks to 'https://github.com/qazrfv1234')",
"v2_0_0": "v2.0.0",
"v2_0_0_text": "\uE016 Added ability to download cheatslips cheats\n\uE016 Added way to toggle out tabs\n\uE016 Various code improvements",
"Ok_button": "Ok",
"cheats_page.cpp":"",
@ -73,6 +76,16 @@
"cheat_Deleting": "Deleting...",
"cheat_All_done": "All done!",
"get_cheatslips": "Download CheatSlips.com cheat sheets",
"download_cheatslips": "Download a selection of cheat sheets from CheatSlips.com.\nThose cheat codes will be added to the end of your existing cheat file.",
"delete_cheat": "Delete existing cheat file",
"couldnt_dl_cheats": "Could not fetch selected cheat codes/invalid token.\nYou may have reached your daily download quota. Head on to 'https://www.cheatslips.com/subscriptions' to see increase it.\n",
"cheat_cheat_content": "Cheatsheet content: ",
"app_cheatslips_label": "Select a game to download cheats for.",
"/wrong_cheatslips_id": "Couldn't retrieve token, make you enter you login properly",
"see_more": "See more",
"download_cheats": "Download cheats and go back",
"choice_page.cpp":"",
"choice_yes":"Yes",
"choice_no":"No",
@ -132,7 +145,7 @@
"list_cfw": "CFW",
"list_ams": "\uE016 From this menu, you can download and update the Atmosphère custom firmware necessary to run homebrew software.\n\uE016 DeepSea by Team Neptune is a CFW pack that includes Atmosphère, hekate, and various homebrew apps.",
"list_main": "\uE016 Alternative CFWs, bootloaders.",
"list_latest_ver": "Latest (ver ",
"list_latest_ver": "Download GBAtemp.net cheat archive (ver ",
"list_cheats": "cheats",
"list_down": "Downloading:\n",
"list_from": "\n\nFrom:\n",
@ -163,6 +176,9 @@
"payload_shut": "Shut Down",
"payload_reboot_2": "Reboot",
"hide_tabs_page": "Hide tabs",
"hide_tabs_label": "Hide tabs from the main menu",
"tools_tab.cpp":"",
"tool_cheats": "Cheats menu",
"tool_change": "Change the Joy-Cons color",
@ -177,6 +193,7 @@
"tool_all_done": " All done!",
"tool_changelog": "Changelog",
"tool_cleanUp": "Clean up downloaded files",
"hide_tabs": "Hide tabs",
"tool_net_settings": "Edit internet settings",
"tool_browser": "Web Browser",

View file

@ -104,7 +104,6 @@
"list_app": "app",
"list_cfw": "CFW",
"list_main": "\uE016 Switch CFWs principales. Si quieres usar Atmosphère con Hekate, descarga Atmosphère, y después Hekate.",
"list_latest_ver": "Último (ver ",
"list_cheats": "trucos",
"list_down": "Descargando:\n",
"list_from": "\n\nDesde:\n",

View file

@ -7,5 +7,9 @@
"crash_frame": {
"button": "OK"
},
"thumbnail_sidebar": {
"save": "Sauvegarder"
}
}

View file

@ -0,0 +1,5 @@
{
"first_button": "Premier bouton",
"second_button": "Deuxième bouton",
"third_button": "Troisième bouton"
}

View file

@ -80,7 +80,6 @@
"list_app": "app",
"list_cfw": "CFW",
"list_main": "\uE016 Principaux CFWs. Si vous souhaitez utiliser Atmosphère avec Hekate, téléchargez Atmosphère, puis Hekate.",
"list_latest_ver": "Derniers (ver ",
"list_cheats": "codes de triche",
"list_down": "Archive à télécharger :\n",
"list_from": "\n\nLien complet de l'archive :\n",

View file

@ -106,7 +106,6 @@
"list_app": "app",
"list_cfw": "CFW",
"list_main": "\uE016 Main Switch CFWs. Se vuoi usare Atmosphère con Hekate, scarica Atmosphère, poi Hekate.",
"list_latest_ver": "Ultimi (ver ",
"list_cheats": "cheats",
"list_down": "Scarico:\n",
"list_from": "\n\nDa:\n",

View file

@ -79,7 +79,6 @@
"list_app": "アプリ",
"list_cfw": "CFW",
"list_main": "\uE016 AtmosphereをHekateで使用する場合は、Atmosphereをダウンロードしてから、Hekateをダウンロードしてください。",
"list_latest_ver": "最新 (バージョン ",
"list_cheats": "チート",
"list_down": "ダウンロード中:\n",
"list_from": "\n\n以下から:\n",

View file

@ -104,7 +104,6 @@
"list_app": "app",
"list_cfw": "CFW",
"list_main": "\uE016 Principais CFWs do Switch. Se você quiser usar o Atmosphère com Hekate, baixe o Atmosphère e, em seguida o Hekate.",
"list_latest_ver": "Último (ver ",
"list_cheats": "trapaças",
"list_down": "Baixando:\n",
"list_from": "\n\nDesde:\n",

View file

@ -97,7 +97,6 @@
"list_app": "应用",
"list_cfw": "自制系统",
"list_main": "\uE016 主要 Switch 破解系统. 如果你使用 Atmosphère with Hekate, 下载 Atmosphère, 然后 Hekate.",
"list_latest_ver": "最新版本 (版本 ",
"list_cheats": "金手指",
"list_down": "下载中:\n",
"list_from": "\n\n从:\n",

View file

@ -130,7 +130,6 @@
"list_cfw": "CFW",
"list_ams": "\uE016 請從清單進行選擇更新的項目你可以選擇包含可執行第三方自製程式韌體的Atmosphère。\n\uE016 DeepSea是由Team Neptune提供的CFW整合套件包括Atmosphère、hekate與數種第三方自製程式。",
"list_main": "\uE016 備用CFWs、引導程序",
"list_latest_ver": "最新(版本 ",
"list_cheats": "金手指",
"list_down": "正在下載:\n",
"list_from": "\n\n來源:\n",

View file

@ -28,7 +28,7 @@ AboutTab::AboutTab()
this->addView(new brls::Header("Disclaimers"));
brls::Label *links = new brls::Label(
brls::LabelStyle::SMALL,
"menus/Disclaimers"_i18n,
"menus/Disclaimers"_i18n + "\n" + "menus/donate"_i18n,
true
);
this->addView(links);

View file

@ -25,13 +25,12 @@ AmsTab::AmsTab() :
std::string hekate_url = std::get<1>(hekate_link)[0];
std::string text_hekate = "menus/list_down"_i18n + std::get<0>(hekate_link)[0];
linkItems.reserve(nbLinks);
for (int i = 0; i<nbLinks; i++){
std::string url = std::get<1>(links)[i];
std::string text("menus/list_down"_i18n + std::get<0>(links)[i] + "menus/list_from"_i18n + url);
linkItems[i] = new brls::ListItem(std::get<0>(links)[i]);
linkItems[i]->setHeight(LISTITEM_HEIGHT);
linkItems[i]->getClickEvent()->subscribe([&, text, text_hekate, url, hekate_url, operation](brls::View* view) {
listItem = new brls::ListItem(std::get<0>(links)[i]);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([&, text, text_hekate, url, hekate_url, operation](brls::View* view) {
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
stagedFrame->setTitle(operation);
stagedFrame->addStage(
@ -57,7 +56,7 @@ AmsTab::AmsTab() :
);
brls::Application::pushView(stagedFrame);
});
this->addView(linkItems[i]);
this->addView(listItem);
}
}
else{

View file

@ -1,15 +1,14 @@
#include "app_page.hpp"
//TODO: Serialize it in extract.cpp
namespace i18n = brls::i18n;
using namespace i18n::literals;
AppPage::AppPage() : AppletFrame(true, true)
AppPage::AppPage(bool cheatSlips) : AppletFrame(true, true)
{
this->setTitle("menus/app_title"_i18n );
list = new brls::List();
label = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/app_label"_i18n ,
cheatSlips ? "menus/app_cheatslips_label"_i18n : "menus/app_label"_i18n,
true
);
list->addView(label);
@ -26,42 +25,41 @@ AppPage::AppPage() : AppletFrame(true, true)
titles = readLineByLine(UPDATED_TITLES_PATH);
if(!titles.empty()){
if(!titles.empty() || cheatSlips){
while (true)
{
rc = nsListApplicationRecord(&record, sizeof(record), i, &recordCount);
if (R_FAILED(rc)) break;
if(recordCount <= 0)
break;
if(recordCount <= 0) break;
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 (!langEntry->name || titles.find(formatApplicationId(tid)) == titles.end())
{
if (!langEntry->name) {
i++;
continue;
}
if(!cheatSlips && titles.find(formatApplicationId(tid)) == titles.end()) {
i++;
continue;
}
App* app = (App*) malloc(sizeof(App));
app->tid = tid;
memset(app->name, 0, sizeof(app->name));
strncpy(app->name, langEntry->name, sizeof(app->name)-1);
listItem = new brls::ListItem(formatListItemTitle(std::string(langEntry->name)), "", formatApplicationId(tid));
listItem->setThumbnail(controlData.icon, sizeof(controlData.icon));
if(cheatSlips){
listItem->getClickEvent()->subscribe([&, tid](brls::View* view) {
brls::Application::pushView(new DownloadCheatsPage(tid));
});
}
memcpy(app->icon, controlData.icon, sizeof(app->icon));
// Add the ListItem
brls::ListItem *listItem = new brls::ListItem(formatListItemTitle(std::string(app->name)), "", formatApplicationId(app->tid));
listItem->setThumbnail(app->icon, sizeof(app->icon));
list->addView(listItem);
i++;
}
}
std::string text("text_download");
std::string text("menus/text_download"_i18n);
std::string url = "";
switch(getCFW()){
case ams:

View file

@ -79,6 +79,9 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true)
verTitles.push_back("menus/v1_5_2"_i18n );
changes.push_back("menus/v1_5_2_text"_i18n );
verTitles.push_back("menus/v2_0_0"_i18n );
changes.push_back("menus/v2_0_0_text"_i18n );
int nbVersions = verTitles.size();
items.reserve(nbVersions);
for(int i = nbVersions -1 ; i >= 0; i--){

View file

@ -14,7 +14,6 @@ ConfirmPage::ConfirmPage(brls::StagedAppletFrame* frame, std::string text, bool
brls::Application::pushView(new MainFrame());
}
else if (this->reboot){
std::cout << "rebootin" << std::endl;
reboot_to_payload(RCM_PAYLOAD_PATH);
}
});

View file

@ -7,6 +7,8 @@
#define API_AGENT "HamletDuFromage"
#define _1MiB 0x100000
using json = nlohmann::json;
typedef struct
{
char *memory;
@ -189,10 +191,11 @@ std::string fetchTitle(const char *url){
return ver;
}
std::string downloadPage(const char* url){
std::string downloadPage(const char* url, std::vector<std::string> headers, std::string body){
std::string res;
CURL *curl_handle;
struct MemoryStruct chunk;
struct curl_slist *list = NULL;
chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
@ -200,6 +203,16 @@ std::string downloadPage(const char* url){
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);
@ -213,3 +226,13 @@ std::string downloadPage(const char* url){
curl_global_cleanup();
return res;
}
json getRequest(std::string url, std::vector<std::string> headers, std::string body) {
std::string request;
request = downloadPage(url.c_str(), headers, body);
json res = {};
bool valid = json::accept(request);
if(valid) return json::parse(request);
else return json::object();
}

View file

@ -0,0 +1,183 @@
#include "download_cheats_page.hpp"
#include "constants.hpp"
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
DownloadCheatsPage::DownloadCheatsPage(uint64_t tid) : AppletFrame(true, true)
{
this->setTitle("menus/cheat_menu"_i18n );
std::string bid = GetBuilID(tid);
list = new brls::List();
label = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/download_cheatslips"_i18n + "\n\uE016 Build ID: " + bid,
true
);
list->addView(label);
if(bid != "") {
std::vector<std::string> headers = {"accept: application/json"};
json cheatsInfo = getRequest(("https://www.cheatslips.com/api/v1/cheats/" + formatApplicationId(tid) + "/" + bid).c_str(), headers);
if(cheatsInfo.find("cheats") != cheatsInfo.end()) {
for (const auto& p : cheatsInfo["cheats"].items()) {
json cheat = p.value();
listItem = new::brls::ToggleListItem(GetCheatsTitle(cheat), 0);
listItem->registerAction("menus/see_more"_i18n , brls::Key::Y, [this, cheat] {
std::string str = "menus/cheat_cheat_content"_i18n + "\n";
if(cheat.find("titles") != cheat.end()) {
for(auto& p : cheat["titles"]){
str += "[" + p.get<std::string>() + "]" + "\n";
}
str.pop_back();
}
brls::Dialog* dialog = new brls::Dialog(str);
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
dialog->close();
};
dialog->addButton("menus/Ok_button"_i18n , callback);
dialog->setCancelable(true);
dialog->open();
return true;
});
toggles.push_back(std::make_pair(listItem, cheat["id"]));
list->addView(listItem);
}
}
list->addView(new brls::ListItemGroupSpacing(true));
}
list->registerAction("menus/download_cheats"_i18n , brls::Key::B, [this, bid, tid] {
std::vector<int> ids;
for(auto& e : toggles){
if(e.first->getToggleState()){
ids.push_back(e.second);
}
}
if(!ids.empty()) {
json token;
std::ifstream tokenFile(TOKEN_PATH);
tokenFile >> token;
tokenFile.close();
std::vector<std::string> headers = {"accept: application/json"};
if(token.find("token") != token.end()) {
headers.push_back("X-API-TOKEN: " + token["token"].get<std::string>());
}
json cheatsInfo = getRequest(("https://www.cheatslips.com/api/v1/cheats/" + formatApplicationId(tid) + "/" + bid).c_str(), 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()) {
WriteCheats(tid, bid, p.value()["content"]);
}
}
}
else {
brls::Dialog* dialog = new brls::Dialog("menus/couldnt_dl_cheats"_i18n);
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
dialog->close();
};
dialog->addButton("menus/Ok_button"_i18n , callback);
dialog->setCancelable(true);
dialog->open();
}
}
brls::Application::popView();
return true;
});
del = new brls::ListItem("menus/delete_cheat"_i18n);
del->getClickEvent()->subscribe([this, tid, bid](brls::View* view) {
DeleteCheats(tid, bid);
brls::Dialog* dialog = new brls::Dialog("menus/All_done"_i18n);
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
dialog->close();
};
dialog->addButton("menus/Ok_button"_i18n , callback);
dialog->setCancelable(true);
dialog->open();
});
list->addView(del);
this->setContentView(list);
}
std::string DownloadCheatsPage::GetBuilID(uint64_t tid) {
NsApplicationContentMetaStatus *MetaSatus = new NsApplicationContentMetaStatus[100U];
s32 out;
nsListApplicationContentMetaStatus(tid, 0, MetaSatus, 100, &out);
u32 version = 0;
for(int i = 0; i < out ; i++){
if(version < MetaSatus[i].version) version = MetaSatus[i].version;
}
this->setFooterText("Game version: v" + std::to_string(version / 0x10000));
json lookupTable = getRequest(LOOKUP_TABLE_URL);
std::string tidstr = formatApplicationId(tid);
std::string versionstr = std::to_string(version);
if(lookupTable.find(tidstr) != lookupTable.end()) {
json buildIDs = lookupTable[tidstr];
if(buildIDs.find(versionstr) != buildIDs.end()) {
return buildIDs[versionstr];
}
}
return "";
}
std::string DownloadCheatsPage::GetCheatsTitle(json cheat) {
std::string res = "";
if(cheat.find("titles") != cheat.end()) {
for(auto& p : cheat["titles"]){
res += "[" + p.get<std::string>() + "]" + " - ";
}
}
res.erase(res.length() - 3);
if(res.size() > 80){
res = res.substr(0, 79) + "...";
}
return res;
}
void DownloadCheatsPage::WriteCheats(uint64_t tid, std::string bid, std::string cheatContent) {
std::string path;
std::string tidstr = formatApplicationId(tid);
switch(getCFW()){
case ams:
path = std::string(AMS_PATH) + std::string(CONTENTS_PATH);
break;
case rnx:
path = std::string(REINX_PATH) + std::string(CONTENTS_PATH);
break;
case sxos:
path = std::string(SXOS_PATH) + std::string(TITLES_PATH);
break;
}
path += tidstr + "/cheats/";
createTree(path);
path += bid + ".txt";
std::ofstream cheatFile;
cheatFile.open(path, std::ios::app);
cheatFile << "\n" << cheatContent;
std::ofstream updated;
updated.open(UPDATED_TITLES_PATH, std::ios::app);
updated << "\n" << tidstr;
}
void DownloadCheatsPage::DeleteCheats(uint64_t tid, std::string bid) {
std::string path;
switch(getCFW()){
case ams:
path = std::string(AMS_PATH) + std::string(CONTENTS_PATH);
break;
case rnx:
path = std::string(REINX_PATH) + std::string(CONTENTS_PATH);
break;
case sxos:
path = std::string(SXOS_PATH) + std::string(TITLES_PATH);
break;
}
std::filesystem::remove(path + formatApplicationId(tid) + "/cheats/" + bid + ".txt");
}

View file

@ -26,7 +26,6 @@ void extract(const char * filename, const char* workingPath, int overwriteInis){
}
while (it != ignoreList.end() ){
k = ("/" + entries[i].name).find((*it));
//std::cout << k << " " << (*it) << " " << entries[i].name << std::endl;
if(k == 0 || k == 1){
isIgnored = true;
if(!std::filesystem::exists("/" + entries[i].name)){
@ -38,15 +37,13 @@ void extract(const char * filename, const char* workingPath, int overwriteInis){
}
if(!isIgnored){
if(entries[i].name == "sept/payload.bin" || entries[i].name == "atmosphere/fusee-secondary.bin"){
//std::cout << entries[i].name << std::endl;
unzipper.extractEntry(entries[i].name, CONFIG_PATH_UNZIP);
}
else if(entries[i].name.substr(0, 13) == "hekate_ctcaer"){
std::cout << "Found hekate payload : " << entries[i].name << std::endl;
unzipper.extractEntry(entries[i].name);
int c = 0;
while(R_FAILED(CopyFile(("/" + entries[i].name).c_str(), UPDATE_BIN_PATH)) && c < 10){
std::cout << c++ << std::endl;
c++;
}
}
else{

83
source/hide_tabs_page.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "hide_tabs_page.hpp"
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
HideTabsPage::HideTabsPage() : AppletFrame(true, true) {
this->setTitle("menus/hide_tabs_page"_i18n );
list = new brls::List();
label = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/hide_tabs_label"_i18n ,
true
);
list->addView(label);
json hideStatus;
std::ifstream hideFile(HIDE_TABS_JSON);
std::string fileContent((std::istreambuf_iterator<char>(hideFile) ),
(std::istreambuf_iterator<char>() ));
if(json::accept(fileContent)) hideStatus = json::parse(fileContent);
else hideStatus = json::object();
bool status = false;
if(hideStatus.find("about") != hideStatus.end()) {
status = hideStatus["about"];
}
about = new brls::ToggleListItem("menus/main_about"_i18n, status);
list->addView(about);
status = false;
if(hideStatus.find("atmosphere") != hideStatus.end()) {
status = hideStatus["atmosphere"];
}
ams = new brls::ToggleListItem("menus/main_update_ams"_i18n, status);
list->addView(ams);
status = false;
if(hideStatus.find("cfw") != hideStatus.end()) {
status = hideStatus["cfw"];
}
cfws = new brls::ToggleListItem("menus/main_update_cfw"_i18n, status);
list->addView(cfws);
status = false;
if(hideStatus.find("sigpatches") != hideStatus.end()) {
status = hideStatus["sigpatches"];
}
sigpatches = new brls::ToggleListItem("menus/main_update_si"_i18n, status);
list->addView(sigpatches);
status = false;
if(hideStatus.find("firmwares") != hideStatus.end()) {
status = hideStatus["firmwares"];
}
fws = new brls::ToggleListItem("menus/main_firmwares"_i18n, status);
list->addView(fws);
status = false;
if(hideStatus.find("cheats") != hideStatus.end()) {
status = hideStatus["cheats"];
}
cheats = new brls::ToggleListItem("menus/Download cheats"_i18n, status);
list->addView(cheats);
list->registerAction("menus/save"_i18n , brls::Key::B, [this] {
json updatedStatus = json::object();
updatedStatus["about"] = about->getToggleState();
updatedStatus["atmosphere"] = ams->getToggleState();
updatedStatus["cfw"] = cfws->getToggleState();
updatedStatus["sigpatches"] = sigpatches->getToggleState();
updatedStatus["firmwares"] = fws->getToggleState();
updatedStatus["cheats"] = cheats->getToggleState();
std::ofstream out(HIDE_TABS_JSON);
out << updatedStatus.dump(4);
out.close();
brls::Application::popView();
return true;
});
this->setContentView(list);
}

View file

@ -8,12 +8,11 @@ ListDownloadTab::ListDownloadTab(archiveType type) :
{
std::tuple<std::vector<std::string>, std::vector<std::string>> links;
std::string operation = "menus/Getting"_i18n ;
std::string firmwareText("menus/firmware_text"_i18n
);
std::string firmwareText("menus/firmware_text"_i18n);
std::string currentCheatsVer =
"menus/currentCeatsver"_i18n ;
this->description = new brls::Label(brls::LabelStyle::DESCRIPTION, "", true);
switch(type){
case sigpatches:
@ -64,19 +63,73 @@ ListDownloadTab::ListDownloadTab(archiveType type) :
this->description->setText(currentCheatsVer);
break;
}
/* std::get<0>(links).push_back("Test");
std::get<1>(links).push_back("https://github.com"); */
this->addView(description);
if(type == cheats){
cheatslipsItem = new brls::ListItem("menus/get_cheatslips"_i18n);
cheatslipsItem->setHeight(LISTITEM_HEIGHT);
cheatslipsItem->getClickEvent()->subscribe([&](brls::View* view) {
if(std::filesystem::exists(TOKEN_PATH)) {
brls::Application::pushView(new AppPage(true));
return true;
}
else {
SwkbdConfig kbd;
char usr[0x100] = {0};
char pwd[0x100] = {0};
Result rc = swkbdCreate(&kbd, 0);
if (R_SUCCEEDED(rc)) {
swkbdConfigMakePresetDefault(&kbd);
swkbdConfigSetOkButtonText(&kbd, "Submit");
swkbdConfigSetGuideText(&kbd, "www.cheatslips.com e-mail");
swkbdShow(&kbd, usr, sizeof(usr));
swkbdClose(&kbd);
rc = swkbdCreate(&kbd, 0);
if(R_SUCCEEDED(rc)){
swkbdConfigMakePresetPassword(&kbd);
swkbdConfigSetOkButtonText(&kbd, "Submit");
swkbdConfigSetGuideText(&kbd, "www.cheatslips.com password");
swkbdShow(&kbd, pwd, sizeof(pwd));
swkbdClose(&kbd);
}
}
std::string body = "{\"email\":\"" + std::string(usr)
+ "\",\"password\":\"" + std::string(pwd) + "\"}";
nlohmann::json token = getRequest(CHEATSLIPS_TOKEN_URL,
{"Accept: application/json",
"Content-Type: application/json",
"charset: utf-8"},
body);
if(token.find("token") != token.end()) {
std::ofstream tokenFile(TOKEN_PATH);
tokenFile << token.dump();
tokenFile.close();
brls::Application::pushView(new AppPage(true));
return true;
}
else {
brls::Dialog* dialog = new brls::Dialog("menus/wrong_cheatslips_id"_i18n);
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
dialog->close();
};
dialog->addButton("menus/Ok_button"_i18n , callback);
dialog->setCancelable(true);
dialog->open();
return true;
}
}
});
this->addView(cheatslipsItem);
}
int nbLinks = std::get<0>(links).size();
if(nbLinks){
linkItems.reserve(nbLinks);
for (int i = 0; i<nbLinks; i++){
std::string url = std::get<1>(links)[i];
std::string text("menus/list_down"_i18n + std::get<0>(links)[i] + "menus/list_from"_i18n + url);
linkItems[i] = new brls::ListItem(std::get<0>(links)[i]);
linkItems[i]->setHeight(LISTITEM_HEIGHT);
linkItems[i]->getClickEvent()->subscribe([&, text, url, type, operation](brls::View* view) {
listItem = new brls::ListItem(std::get<0>(links)[i]);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([&, text, url, type, operation](brls::View* view) {
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
stagedFrame->setTitle(operation);
stagedFrame->addStage(
@ -93,8 +146,9 @@ ListDownloadTab::ListDownloadTab(archiveType type) :
);
brls::Application::pushView(stagedFrame);
});
this->addView(linkItems[i]);
this->addView(listItem);
}
}
else{
notFound = new brls::Label(

View file

@ -2,6 +2,7 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
MainFrame::MainFrame() : TabFrame()
{
@ -13,18 +14,33 @@ MainFrame::MainFrame() : TabFrame()
this->setFooterText("v" + std::string(APP_VERSION) + "menus/main_app"_i18n );
else
this->setFooterText("v" + std::string(APP_VERSION));
json hideStatus;
std::ifstream hideFile(HIDE_TABS_JSON);
std::string fileContent((std::istreambuf_iterator<char>(hideFile) ),
(std::istreambuf_iterator<char>() ));
if(json::accept(fileContent)) hideStatus = json::parse(fileContent);
else hideStatus = json::object();
if(hideStatus.find("about") == hideStatus.end() || !hideStatus["about"])
this->addTab("menus/main_about"_i18n, new AboutTab());
this->addTab("menus/main_about"_i18n , new AboutTab());
if(hideStatus.find("atmosphere") == hideStatus.end() || !hideStatus["atmosphere"])
this->addTab("menus/main_update_ams"_i18n, new AmsTab());
//this->addSeparator();
if(hideStatus.find("cfw") == hideStatus.end() || !hideStatus["cfw"])
this->addTab("menus/main_update_cfw"_i18n, new ListDownloadTab(cfw));
this->addTab("menus/main_update_ams"_i18n , new AmsTab());
this->addTab("menus/main_update_cfw"_i18n , new ListDownloadTab(cfw));
this->addTab("menus/main_update_si"_i18n , new ListDownloadTab(sigpatches));
this->addTab("menus/main_firmwares"_i18n , new ListDownloadTab(fw));
this->addTab("menus/main_cheats"_i18n , new ListDownloadTab(cheats));
if(hideStatus.find("sigpatches") == hideStatus.end() || !hideStatus["sigpatches"])
this->addTab("menus/main_update_si"_i18n, new ListDownloadTab(sigpatches));
//this->addSeparator();
if(hideStatus.find("firmwares") == hideStatus.end() || !hideStatus["firmwares"])
this->addTab("menus/main_firmwares"_i18n, new ListDownloadTab(fw));
if(hideStatus.find("cheats") == hideStatus.end() || !hideStatus["cheats"])
this->addTab("menus/main_cheats"_i18n, new ListDownloadTab(cheats));
this->addTab("menus/main_tools"_i18n , new ToolsTab(tag));

View file

@ -1,9 +1,6 @@
#include "net_page.hpp"
#include <iostream>
#include <arpa/inet.h>
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;

View file

@ -63,9 +63,19 @@ ToolsTab::ToolsTab(std::string tag) : brls::List()
browser = new brls::ListItem("menus/tool_browser"_i18n );
browser->getClickEvent()->subscribe([&](brls::View* view){
Result rc=0;
char url[0xc00] = {0};
strcpy(url, "https://duckduckgo.com");
SwkbdConfig kbd;
Result rc = swkbdCreate(&kbd, 0);
if (R_SUCCEEDED(rc)) {
swkbdConfigMakePresetDefault(&kbd);
swkbdConfigSetGuideText(&kbd, "www.cheatslips.com e-mail");
swkbdConfigSetInitialText(&kbd, "https://duckduckgo.com");
swkbdShow(&kbd, url, sizeof(url));
swkbdClose(&kbd);
}
else {
strcpy(url, "https://duckduckgo.com");
}
int at = appletGetAppletType();
std::string error = "";
if(at == AppletType_Application) { // Running as a title
@ -73,16 +83,16 @@ ToolsTab::ToolsTab(std::string tag) : brls::List()
WebCommonReply out;
rc = webPageCreate(&conf, url);
if (R_FAILED(rc))
error += "\uE016 Error starting Browser\nLookup error code for more info " + rc;
error += "\uE016 Error starting Browser\n\uE016 Lookup error code for more info " + rc;
webConfigSetJsExtension(&conf, true);
webConfigSetPageCache(&conf, true);
webConfigSetBootLoadingIcon(&conf, true);
webConfigSetWhitelist(&conf, ".*");
rc = webConfigShow(&conf, &out);
if (R_FAILED(rc))
error += "Error starting Browser\nLookup error code for more info " + rc;
error += "\uE016 Error starting Browser\n\uE016 Lookup error code for more info " + rc;
} else { // Running under applet
error += "\uE016 Running in applet mode.\nPlease launch hbmenu by holding R on an APP (e.g. a game) NOT an applet (e.g. Gallery)";
error += "\uE016 Running in applet mode.\n\uE016 Please launch hbmenu by holding [R] on a game";
}
if(!error.empty()){
brls::Dialog* dialog = new brls::Dialog(error);
@ -122,9 +132,15 @@ ToolsTab::ToolsTab(std::string tag) : brls::List()
});
cleanUp->setHeight(LISTITEM_HEIGHT);
this->addView(cleanUp);
hideTabs = new brls::ListItem("menus/hide_tabs"_i18n );
hideTabs->getClickEvent()->subscribe([&](brls::View* view) {
brls::Application::pushView(new HideTabsPage());
});
hideTabs->setHeight(LISTITEM_HEIGHT);
this->addView(hideTabs);
//tag = "1.TEST"
//std::cout << "tag: " << tag << std::endl;
if(!tag.empty() && tag != APP_VERSION){
updateApp = new brls::ListItem("menus/tool_update"_i18n + tag +")");
std::string text("menus/tool_DownLoad"_i18n + std::string(APP_URL));

View file

@ -252,7 +252,6 @@ std::vector<std::string> fetchPayloads(){
for (auto& path : payloadPaths){
for (const auto & entry : std::filesystem::directory_iterator(path)){
if(entry.path().extension().string() == ".bin"){
std::cout << entry.path().string() << std::endl;
if(entry.path().string() != FUSEE_SECONDARY && entry.path().string() != FUSEE_MTC)
res.push_back(entry.path().string().c_str());
}
@ -287,7 +286,7 @@ void cp(const char *from, const char *to){
if (src.good() && dst.good()) {
dst << src.rdbuf();
}
}
}
Result CopyFile(const char src_path[FS_MAX_PATH], const char dest_path[FS_MAX_PATH]) {

View file

@ -11,6 +11,8 @@ WorkerPage::WorkerPage(brls::StagedAppletFrame* frame, const std::string& text,
this->button = new brls::Button(brls::ButtonStyle::BORDERLESS); // avoid back button bug
this->button->setParent(this);
this->registerAction("", brls::Key::B, [this] { return true; });
}
void WorkerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)