Add version and update date to local TitleDB cache, display on screen.

This commit is contained in:
Steven Smith 2018-02-24 15:02:59 -08:00
parent 6ee8f666ac
commit 0f4031d256
10 changed files with 219 additions and 113 deletions

View File

@ -1,3 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -6,6 +7,7 @@
#include "error.h"
#include "fs.h"
#include "linkedlist.h"
#include "stringutil.h"
bool fs_is_dir(FS_Archive archive, const char* path) {
Result res = 0;
@ -171,6 +173,20 @@ void fs_set_3dsx_path(const char* path) {
}
}
int fs_make_3dsx_path(char* out, const char* name, size_t size) {
char filename[FILE_NAME_MAX];
string_escape_file_name(filename, name, sizeof(filename));
return snprintf(out, size, "/3ds/%s/%s.3dsx", filename, filename);
}
int fs_make_smdh_path(char* out, const char* name, size_t size) {
char filename[FILE_NAME_MAX];
string_escape_file_name(filename, name, sizeof(filename));
return snprintf(out, size, "/3ds/%s/%s.smdh", filename, filename);
}
FS_MediaType fs_get_title_destination(u64 titleId) {
u16 platform = (u16) ((titleId >> 48) & 0xFFFF);
u16 category = (u16) ((titleId >> 32) & 0xFFFF);

View File

@ -17,6 +17,9 @@ Result fs_close_archive(FS_Archive archive);
const char* fs_get_3dsx_path();
void fs_set_3dsx_path(const char* path);
int fs_make_3dsx_path(char* out, const char* name, size_t size);
int fs_make_smdh_path(char* out, const char* name, size_t size);
FS_MediaType fs_get_title_destination(u64 titleId);
bool fs_filter_cias(void* data, const char* name, u32 attributes);

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <3ds.h>
@ -27,7 +28,18 @@ static void action_install_titledb_finished_url(void* data, u32 index) {
list_item* item = installData->selected;
titledb_info* info = (titledb_info*) item->data;
task_populate_titledb_cache_installed(info->id, installData->cia ? info->cia.id : info->tdsx.id, installData->cia);
titledb_cache_entry entry;
if(installData->cia) {
entry.id = info->cia.id;
strncpy(entry.updatedAt, info->cia.updatedAt, sizeof(entry.updatedAt));
strncpy(entry.version, info->cia.version, sizeof(entry.version));
} else {
entry.id = info->tdsx.id;
strncpy(entry.updatedAt, info->tdsx.updatedAt, sizeof(entry.updatedAt));
strncpy(entry.version, info->tdsx.version, sizeof(entry.version));
}
task_populate_titledb_cache_set(info->id, installData->cia, &entry);
task_populate_titledb_update_status(item);
}
@ -53,18 +65,20 @@ void action_install_titledb(linked_list* items, list_item* selected, bool cia) {
if(data->cia) {
snprintf(urls, sizeof(urls), "https://3ds.titledb.com/v1/cia/%lu/download", info->cia.id);
} else {
char name[FILE_NAME_MAX];
string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
char filePath[FILE_PATH_MAX];
fs_make_3dsx_path(filePath, info->meta.shortDescription, sizeof(filePath));
u32 urlsPos = 0;
u32 pathsPos = 0;
urlsPos += snprintf(urls + urlsPos, sizeof(urls) - urlsPos, "https://3ds.titledb.com/v1/tdsx/%lu/download\n", info->tdsx.id);
pathsPos += snprintf(paths + pathsPos, sizeof(paths) - pathsPos, "/3ds/%s/%s.3dsx\n", name, name);
pathsPos += snprintf(paths + pathsPos, sizeof(paths) - pathsPos, "%s\n", filePath);
if(info->tdsx.smdh.exists) {
fs_make_smdh_path(filePath, info->meta.shortDescription, sizeof(filePath));
snprintf(urls + urlsPos, sizeof(urls) - urlsPos, "https://3ds.titledb.com/v1/smdh/%lu/download\n", info->tdsx.smdh.id);
snprintf(paths + pathsPos, sizeof(paths) - pathsPos, "/3ds/%s/%s.smdh\n", name, name);
snprintf(paths + pathsPos, sizeof(paths) - pathsPos, "%s\n", filePath);
}
}

View File

@ -33,7 +33,18 @@ static void action_update_titledb_finished_url(void* data, u32 index) {
list_item* item = updateData->items[index];
titledb_info* info = (titledb_info*) item->data;
task_populate_titledb_cache_installed(info->id, updateData->cia[index] ? info->cia.id : info->tdsx.id, updateData->cia[index]);
titledb_cache_entry entry;
if(updateData->cia[index]) {
entry.id = info->cia.id;
strncpy(entry.updatedAt, info->cia.updatedAt, sizeof(entry.updatedAt));
strncpy(entry.version, info->cia.version, sizeof(entry.version));
} else {
entry.id = info->tdsx.id;
strncpy(entry.updatedAt, info->tdsx.updatedAt, sizeof(entry.updatedAt));
strncpy(entry.version, info->tdsx.version, sizeof(entry.version));
}
task_populate_titledb_cache_set(info->id, updateData->cia[index], &entry);
task_populate_titledb_update_status(item);
}
@ -59,7 +70,7 @@ void action_update_titledb(linked_list* items, list_item* selected) {
list_item* item = linked_list_iter_next(&iter);
titledb_info* info = (titledb_info*) item->data;
if(info->cia.outdated) {
if(info->cia.installed && info->cia.installedInfo.id != info->cia.id) {
urlsPos += snprintf(data->urls + urlsPos, INSTALL_URLS_MAX * DOWNLOAD_URL_MAX - urlsPos,
"https://3ds.titledb.com/v1/cia/%lu/download\n",
info->cia.id);
@ -72,20 +83,22 @@ void action_update_titledb(linked_list* items, list_item* selected) {
index++;
}
if(info->tdsx.outdated && (!info->tdsx.smdh.exists || index < INSTALL_URLS_MAX - 1)) {
char name[FILE_NAME_MAX];
string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
if(info->tdsx.installed && info->tdsx.installedInfo.id != info->tdsx.id && (!info->tdsx.smdh.exists || index < INSTALL_URLS_MAX - 1)) {
char filePath[FILE_PATH_MAX];
fs_make_3dsx_path(filePath, info->meta.shortDescription, sizeof(filePath));
urlsPos += snprintf(data->urls + urlsPos, INSTALL_URLS_MAX * DOWNLOAD_URL_MAX - urlsPos, "https://3ds.titledb.com/v1/tdsx/%lu/download\n", info->tdsx.id);
pathsPos += snprintf(data->paths + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "/3ds/%s/%s.3dsx\n", name, name);
pathsPos += snprintf(data->paths + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "%s\n", filePath);
data->cia[index] = false;
data->items[index] = item;
index++;
if(info->tdsx.smdh.exists) {
fs_make_smdh_path(filePath, info->meta.shortDescription, sizeof(filePath));
urlsPos += snprintf(data->urls + urlsPos, INSTALL_URLS_MAX * DOWNLOAD_URL_MAX - urlsPos, "https://3ds.titledb.com/v1/smdh/%lu/download\n", info->tdsx.smdh.id);
pathsPos += snprintf(data->paths + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "/3ds/%s/%s.smdh\n", name, name);
pathsPos += snprintf(data->paths + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "%s\n", filePath);
data->cia[index] = false;
data->items[index] = item;

View File

@ -155,7 +155,7 @@ void init() {
void cleanup() {
clipboard_clear();
task_populate_titledb_unload_cache();
task_populate_titledb_cache_unload();
task_exit();
ui_exit();

View File

@ -22,7 +22,7 @@
static json_t* installedApps = NULL;
static void task_populate_titledb_load_cache() {
static void task_populate_titledb_cache_load() {
if(installedApps != NULL) {
json_decref(installedApps);
}
@ -39,7 +39,7 @@ static void task_populate_titledb_load_cache() {
}
}
static void task_populate_titledb_save_cache() {
static void task_populate_titledb_cache_save() {
if(json_is_object(installedApps)) {
mkdir(TITLEDB_CACHE_DIR, 755);
@ -47,18 +47,18 @@ static void task_populate_titledb_save_cache() {
}
}
void task_populate_titledb_unload_cache() {
void task_populate_titledb_cache_unload() {
if(json_is_object(installedApps)) {
task_populate_titledb_save_cache();
task_populate_titledb_cache_save();
json_decref(installedApps);
installedApps = NULL;
}
}
static json_t* task_populate_titledb_get_cache_entry(u32 id) {
static json_t* task_populate_titledb_cache_get_base(u32 id, bool cia, bool create) {
if(!json_is_object(installedApps)) {
task_populate_titledb_load_cache();
task_populate_titledb_cache_load();
}
if(json_is_object(installedApps)) {
@ -67,26 +67,68 @@ static json_t* task_populate_titledb_get_cache_entry(u32 id) {
json_t* cache = json_object_get(installedApps, idString);
if(!json_is_object(cache)) {
cache = json_object();
json_object_set(installedApps, idString, cache);
if(create) {
cache = json_object();
json_object_set(installedApps, idString, cache);
} else {
cache = NULL;
}
}
return cache;
} else {
return NULL;
if(json_is_object(cache)) {
// Get old cache entry.
const char* objIdKey = cia ? "cia_id" : "tdsx_id";
json_t* objId = json_object_get(cache, objIdKey);
const char* objKey = cia ? "cia" : "tdsx";
json_t* obj = json_object_get(cache, objKey);
if(!json_is_object(obj)) {
// Force creation if old value to migrate exists.
if(create || json_is_integer(objId)) {
obj = json_object();
json_object_set(cache, objKey, obj);
} else {
obj = NULL;
}
}
// Migrate old cache entry.
if(json_is_integer(objId)) {
json_object_set(obj, "id", json_integer(json_integer_value(objId)));
json_object_del(cache, objIdKey);
}
return obj;
}
}
return NULL;
}
void task_populate_titledb_cache_installed(u32 id, u32 subId, bool cia) {
json_t* cache = task_populate_titledb_get_cache_entry(id);
if(json_is_object(cache)) {
if(cia) {
json_object_set(cache, "cia_id", json_integer(subId));
} else {
json_object_set(cache, "tdsx_id", json_integer(subId));
}
static bool task_populate_titledb_cache_get(u32 id, bool cia, titledb_cache_entry* entry) {
json_t* obj = task_populate_titledb_cache_get_base(id, cia, false);
if(json_is_object(obj)) {
json_t* idJson = json_object_get(obj, "id");
if(json_is_integer(idJson)) {
entry->id = (u32) json_integer_value(idJson);
strncpy(entry->updatedAt, json_object_get_string(obj, "updated_at", "Unknown"), sizeof(entry->updatedAt));
strncpy(entry->version, json_object_get_string(obj, "version", "Unknown"), sizeof(entry->version));
task_populate_titledb_save_cache();
return true;
}
}
return false;
}
void task_populate_titledb_cache_set(u32 id, bool cia, titledb_cache_entry* entry) {
json_t* obj = task_populate_titledb_cache_get_base(id, cia, true);
if(json_is_object(obj)) {
json_object_set(obj, "id", json_integer(entry->id));
json_object_set(obj, "updated_at", json_string(entry->updatedAt));
json_object_set(obj, "version", json_string(entry->version));
task_populate_titledb_cache_save();
}
}
@ -94,22 +136,17 @@ void task_populate_titledb_update_status(list_item* item) {
titledb_info* info = (titledb_info*) item->data;
info->cia.installed = false;
info->cia.outdated = false;
info->tdsx.installed = false;
info->tdsx.outdated = false;
if(info->cia.exists) {
AM_TitleEntry entry;
info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry));
info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry))
&& task_populate_titledb_cache_get(info->id, true, &info->cia.installedInfo);
}
if(info->tdsx.exists) {
char name[FILE_NAME_MAX];
string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
char path3dsx[FILE_PATH_MAX];
snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name);
fs_make_3dsx_path(path3dsx, info->meta.shortDescription, sizeof(path3dsx));
FS_Path* fsPath = fs_make_path_utf8(path3dsx);
if(fsPath != NULL) {
@ -117,37 +154,14 @@ void task_populate_titledb_update_status(list_item* item) {
if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) {
FSFILE_Close(handle);
info->tdsx.installed = true;
info->tdsx.installed = task_populate_titledb_cache_get(info->id, false, &info->tdsx.installedInfo);
}
fs_free_path_utf8(fsPath);
}
}
if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) {
json_t* cache = task_populate_titledb_get_cache_entry(info->id);
if(json_is_object(cache)) {
json_t* ciaId = json_object_get(cache, "cia_id");
json_t* tdsxId = json_object_get(cache, "tdsx_id");
info->cia.installed = info->cia.installed && json_is_integer(ciaId);
info->cia.outdated = info->cia.installed && json_integer_value(ciaId) < info->cia.id;
info->tdsx.installed = info->tdsx.installed && json_is_integer(tdsxId);
info->tdsx.outdated = info->tdsx.installed && json_integer_value(tdsxId) < info->tdsx.id;
} else {
// If no cache entry exists, consider this entry as not installed.
// Assuming an entry is outdated can cause issues with multiple entries that have the same name/title ID.
info->cia.installed = false;
info->cia.outdated = false;
info->tdsx.installed = false;
info->tdsx.outdated = false;
}
}
if(info->cia.outdated || info->tdsx.outdated) {
if((info->cia.installed && info->cia.installedInfo.id != info->cia.id) || (info->tdsx.installed && info->tdsx.installedInfo.id != info->tdsx.id)) {
item->color = COLOR_TITLEDB_OUTDATED;
} else if(info->cia.installed || info->tdsx.installed) {
item->color = COLOR_TITLEDB_INSTALLED;
@ -156,6 +170,21 @@ void task_populate_titledb_update_status(list_item* item) {
}
}
static int task_populate_titledb_compare_dates(const char* date1, const char* date2, size_t size) {
bool unk1 = strncmp(date1, "Unknown", size) == 0;
bool unk2 = strncmp(date2, "Unknown", size) == 0;
if(unk1 && !unk2) {
return -1;
} else if(!unk1 && unk2) {
return 1;
} else if(unk1 && unk2) {
return 0;
}
return strncmp(date1, date2, size);
}
static void task_populate_titledb_thread(void* arg) {
populate_titledb_data* data = (populate_titledb_data*) arg;
@ -185,7 +214,7 @@ static void task_populate_titledb_thread(void* arg) {
if(titledbInfo != NULL) {
titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0);
strncpy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category));
strncpy(titledbInfo->updatedAt, json_object_get_string(entry, "updated_at", ""), sizeof(titledbInfo->updatedAt));
strncpy(titledbInfo->updatedAt, json_object_get_string(entry, "updated_at", "Unknown"), sizeof(titledbInfo->updatedAt));
strncpy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription));
strncpy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher));
@ -207,8 +236,8 @@ static void task_populate_titledb_thread(void* arg) {
for(u32 j = 0; j < json_array_size(cias); j++) {
json_t* cia = json_array_get(cias, j);
if(json_is_object(cia)) {
const char* updatedAt = json_object_get_string(cia, "updated_at", "");
if(!titledbInfo->cia.exists || strncmp(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) {
const char* updatedAt = json_object_get_string(cia, "updated_at", "Unknown");
if(!titledbInfo->cia.exists || task_populate_titledb_compare_dates(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) {
titledbInfo->cia.exists = true;
titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0);
@ -226,8 +255,8 @@ static void task_populate_titledb_thread(void* arg) {
for(u32 j = 0; j < json_array_size(tdsxs); j++) {
json_t* tdsx = json_array_get(tdsxs, j);
if(json_is_object(tdsx)) {
const char* updatedAt = json_object_get_string(tdsx, "updated_at", "");
if(!titledbInfo->tdsx.exists || strncmp(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) {
const char* updatedAt = json_object_get_string(tdsx, "updated_at", "Unknown");
if(!titledbInfo->tdsx.exists || task_populate_titledb_compare_dates(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) {
titledbInfo->tdsx.exists = true;
titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0);

View File

@ -3,6 +3,12 @@
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct titledb_cache_entry_s {
u32 id;
char updatedAt[32];
char version[32];
} titledb_cache_entry;
typedef struct titledb_cia_info_s {
bool exists;
@ -13,7 +19,7 @@ typedef struct titledb_cia_info_s {
u64 titleId;
bool installed;
bool outdated;
titledb_cache_entry installedInfo;
} titledb_cia_info;
typedef struct titledb_smdh_info_s {
@ -32,7 +38,7 @@ typedef struct titledb_tdsx_info_s {
titledb_smdh_info smdh;
bool installed;
bool outdated;
titledb_cache_entry installedInfo;
} titledb_tdsx_info;
typedef struct titledb_info_s {
@ -60,8 +66,8 @@ typedef struct populate_titledb_data_s {
Handle resumeEvent;
} populate_titledb_data;
void task_populate_titledb_unload_cache();
void task_populate_titledb_cache_installed(u32 id, u32 subId, bool cia);
void task_populate_titledb_cache_unload();
void task_populate_titledb_cache_set(u32 id, bool cia, titledb_cache_entry* entry);
void task_populate_titledb_update_status(list_item* item);
void task_free_titledb(list_item* item);

View File

@ -262,15 +262,25 @@ void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
static void task_format_date(char* out, const char* date, size_t size) {
if(strncmp(date, "Unknown", size) == 0) {
strncpy(out, date, size);
} else {
char updatedDate[32] = "";
char updatedTime[32] = "";
sscanf(date, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
snprintf(out, size, "%s %s", updatedDate, updatedTime);
}
}
void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
titledb_info* info = (titledb_info*) data;
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
sscanf(info->updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char updatedAt[32];
task_format_date(updatedAt, info->updatedAt, sizeof(updatedAt));
char infoText[1024];
@ -278,12 +288,12 @@ void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float
"%s\n"
"\n"
"Category: %s\n"
"Updated At: %s %s\n"
"Updated At: %s\n"
"Update Available: %s",
info->headline,
info->category,
updatedDate, updatedTime,
info->cia.outdated || info->tdsx.outdated ? "Yes" : "No");
updatedAt,
(info->cia.installed && info->cia.installedInfo.id != info->cia.id) || (info->tdsx.installed && info->tdsx.installedInfo.id != info->tdsx.id) ? "Yes" : "No");
float infoWidth;
screen_get_string_size_wrap(&infoWidth, NULL, infoText, 0.5f, 0.5f, x2 - x1 - 10);
@ -298,24 +308,29 @@ void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, f
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
char dbUpdatedAt[32];
task_format_date(dbUpdatedAt, info->cia.updatedAt, sizeof(dbUpdatedAt));
sscanf(info->cia.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char localUpdatedAt[32];
task_format_date(localUpdatedAt, info->cia.installedInfo.updatedAt, sizeof(localUpdatedAt));
char infoText[512];
snprintf(infoText, sizeof(infoText),
"Title ID: %016llX\n"
"TitleDB Version: %s\n"
"Size: %.2f %s\n"
"Updated At: %s %s\n"
"TitleDB Updated At: %s\n"
"Local Updated At: %s\n"
"TitleDB Version: %s\n"
"Local Version: %s\n"
"Update Available: %s",
info->cia.titleId,
info->cia.version,
ui_get_display_size(info->cia.size), ui_get_display_size_units(info->cia.size),
updatedDate, updatedTime,
info->cia.outdated ? "Yes" : "No");
dbUpdatedAt,
info->cia.installed ? localUpdatedAt : "Not Installed",
info->cia.version,
info->cia.installed ? info->cia.installedInfo.version : "Not Installed",
info->cia.installed && info->cia.installedInfo.id != info->cia.id ? "Yes" : "No");
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
@ -330,22 +345,27 @@ void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1,
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
char dbUpdatedAt[32];
task_format_date(dbUpdatedAt, info->tdsx.updatedAt, sizeof(dbUpdatedAt));
sscanf(info->tdsx.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char localUpdatedAt[32];
task_format_date(localUpdatedAt, info->tdsx.installedInfo.updatedAt, sizeof(localUpdatedAt));
char infoText[512];
snprintf(infoText, sizeof(infoText),
"TitleDB Version: %s\n"
"Size: %.2f %s\n"
"Updated At: %s %s\n"
"Size: %.2f %s\n"
"TitleDB Updated At: %s\n"
"Local Updated At: %s\n"
"TitleDB Version: %s\n"
"Local Version: %s\n"
"Update Available: %s",
info->tdsx.version,
ui_get_display_size(info->tdsx.size), ui_get_display_size_units(info->tdsx.size),
updatedDate, updatedTime,
info->tdsx.outdated ? "Yes" : "No");
dbUpdatedAt,
info->tdsx.installed ? localUpdatedAt : "Not Installed",
info->tdsx.version,
info->tdsx.installed ? info->tdsx.installedInfo.version : "Not Installed",
info->tdsx.installed && info->tdsx.installedInfo.id != info->tdsx.id ? "Yes" : "No");
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);

View File

@ -138,7 +138,7 @@ static void titledb_entry_update(ui_view* view, void* data, linked_list* items,
if(item != NULL) {
strncpy(item->name, "CIA", sizeof(item->name));
item->data = (void*) true;
item->color = info->cia.installed ? info->cia.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
item->color = info->cia.installed ? info->cia.installedInfo.id != info->cia.id ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
linked_list_add(items, item);
}
@ -149,7 +149,7 @@ static void titledb_entry_update(ui_view* view, void* data, linked_list* items,
if(item != NULL) {
strncpy(item->name, "3DSX", sizeof(item->name));
item->data = (void*) false;
item->color = info->tdsx.installed ? info->tdsx.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
item->color = info->tdsx.installed ? info->tdsx.installedInfo.id != info->tdsx.id ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
linked_list_add(items, item);
}
@ -162,9 +162,9 @@ static void titledb_entry_update(ui_view* view, void* data, linked_list* items,
list_item* item = (list_item*) linked_list_iter_next(&iter);
if((bool) item->data) {
item->color = info->cia.installed ? info->cia.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
item->color = info->cia.installed ? info->cia.installedInfo.id != info->cia.id ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
} else {
item->color = info->tdsx.installed ? info->tdsx.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
item->color = info->tdsx.installed ? info->tdsx.installedInfo.id != info->tdsx.id ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
}
}
}

View File

@ -13,14 +13,14 @@
typedef struct {
u32 id;
u32 subId;
bool cia;
titledb_cache_entry data;
} update_data;
static void update_finished_url(void* data, u32 index) {
update_data* updateData = (update_data*) data;
task_populate_titledb_cache_installed(updateData->id, updateData->subId, updateData->cia);
task_populate_titledb_cache_set(updateData->id, updateData->cia, &updateData->data);
}
static void update_finished_all(void* data) {
@ -36,7 +36,10 @@ static void update_check_update(ui_view* view, void* data, float* progress, char
Result res = 0;
json_t* json = NULL;
if(R_SUCCEEDED(res = http_download_json("https://api.titledb.com/v1/entry?nested=true&only=id&only=cia.id&only=cia.version&only=tdsx.id&only=tdsx.version&_filters=%7B%22name%22%3A%20%22FBI%22%7D", &json, 16 * 1024))) {
if(R_SUCCEEDED(res = http_download_json("https://api.titledb.com/v1/entry?nested=true&only=id"
"&only=cia.id&only=cia.version&only=cia.updated_at"
"&only=tdsx.id&only=tdsx.version&only=tdsx.updated_at"
"&_filters=%7B%22name%22%3A%20%22FBI%22%7D", &json, 16 * 1024))) {
const char* type = fs_get_3dsx_path() != NULL ? "tdsx" : "cia";
json_t* entry = NULL;
@ -48,8 +51,8 @@ static void update_check_update(ui_view* view, void* data, float* progress, char
&& json_is_array(objs = json_object_get(entry, type))) {
if(json_array_size(json) > 0) {
updateData->id = (u32) json_integer_value(idJson);
updateData->cia = fs_get_3dsx_path() != NULL;
u32 latestSubId = 0;
u32 latestMajor = 0;
u32 latestMinor = 0;
u32 latestMicro = 0;
@ -59,9 +62,11 @@ static void update_check_update(ui_view* view, void* data, float* progress, char
if(json_is_object(obj)) {
json_t* subIdJson = json_object_get(obj, "id");
json_t* versionJson = json_object_get(obj, "version");
if(json_is_integer(subIdJson) && json_is_string(versionJson)) {
json_t* updatedAtJson = json_object_get(obj, "updated_at");
if(json_is_integer(subIdJson) && json_is_string(versionJson) && json_is_string(updatedAtJson)) {
u32 subId = (u32) json_integer_value(subIdJson);
const char* version = json_string_value(versionJson);
const char* updatedAt = json_string_value(updatedAtJson);
u32 major = 0;
u32 minor = 0;
@ -71,7 +76,10 @@ static void update_check_update(ui_view* view, void* data, float* progress, char
if(major > latestMajor
|| (major == latestMajor && minor > latestMinor)
|| (major == latestMajor && minor == latestMinor && micro > latestMicro)) {
latestSubId = subId;
updateData->data.id = subId;
strncpy(updateData->data.updatedAt, updatedAt, sizeof(updateData->data.updatedAt));
strncpy(updateData->data.version, version, sizeof(updateData->data.version));
latestMajor = major;
latestMinor = minor;
latestMicro = micro;
@ -80,13 +88,10 @@ static void update_check_update(ui_view* view, void* data, float* progress, char
}
}
updateData->subId = latestSubId;
updateData->cia = fs_get_3dsx_path() != NULL;
if(latestMajor > VERSION_MAJOR
|| (latestMajor == VERSION_MAJOR && latestMinor > VERSION_MINOR)
|| (latestMajor == VERSION_MAJOR && latestMinor == VERSION_MINOR && latestMicro > VERSION_MICRO)) {
snprintf(updateURL, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/%s/%lu/download", type, latestSubId);
snprintf(updateURL, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/%s/%lu/download", type, updateData->data.id);
hasUpdate = true;
}
}