Load metadata from JSONs
This commit is contained in:
parent
620367672a
commit
384367b56c
2 changed files with 137 additions and 152 deletions
|
@ -1,4 +1,5 @@
|
|||
using LibHac;
|
||||
using JsonPrettyPrinterPlus;
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.FsSystem.NcaUtils;
|
||||
|
@ -10,28 +11,20 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
using Utf8Json;
|
||||
using Utf8Json.Resolvers;
|
||||
using SystemState = Ryujinx.HLE.HOS.SystemState;
|
||||
|
||||
namespace Ryujinx.UI
|
||||
{
|
||||
public class ApplicationLibrary
|
||||
{
|
||||
private static Keyset KeySet;
|
||||
private static SystemState.TitleLanguage DesiredTitleLanguage;
|
||||
|
||||
private const double SecondsPerMinute = 60.0;
|
||||
private const double SecondsPerHour = SecondsPerMinute * 60;
|
||||
private const double SecondsPerDay = SecondsPerHour * 24;
|
||||
|
||||
public static byte[] RyujinxNspIcon { get; private set; }
|
||||
public static byte[] RyujinxXciIcon { get; private set; }
|
||||
public static byte[] RyujinxNcaIcon { get; private set; }
|
||||
public static byte[] RyujinxNroIcon { get; private set; }
|
||||
public static byte[] RyujinxNsoIcon { get; private set; }
|
||||
|
||||
public static List<ApplicationData> ApplicationLibraryData { get; private set; }
|
||||
|
||||
public struct ApplicationData
|
||||
{
|
||||
public bool Fav;
|
||||
|
@ -47,6 +40,24 @@ namespace Ryujinx.UI
|
|||
public string Path;
|
||||
}
|
||||
|
||||
public static List<ApplicationData> ApplicationLibraryData { get; private set; }
|
||||
|
||||
private static Keyset KeySet;
|
||||
private static SystemState.TitleLanguage DesiredTitleLanguage;
|
||||
|
||||
private const double SecondsPerMinute = 60.0;
|
||||
private const double SecondsPerHour = SecondsPerMinute * 60;
|
||||
private const double SecondsPerDay = SecondsPerHour * 24;
|
||||
|
||||
private struct ApplicationMetadata
|
||||
{
|
||||
public bool Fav;
|
||||
public double TimePlayed;
|
||||
public string LastPlayed;
|
||||
}
|
||||
|
||||
private static ApplicationMetadata AppMetadata;
|
||||
|
||||
public static void Init(List<string> AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage)
|
||||
{
|
||||
KeySet = keySet;
|
||||
|
@ -297,7 +308,7 @@ namespace Ryujinx.UI
|
|||
if (Path.GetExtension(applicationPath) == ".nca")
|
||||
{
|
||||
Nca nca = new Nca(KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage(false));
|
||||
if (nca.Header.ContentType != ContentType.Program)
|
||||
if (nca.Header.ContentType != NcaContentType.Program)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -323,18 +334,18 @@ namespace Ryujinx.UI
|
|||
}
|
||||
}
|
||||
|
||||
string[] userData = GetUserData(titleId, "00000000000000000000000000000001");
|
||||
(bool, string, string) metaData = GetMetadata(titleId);
|
||||
|
||||
ApplicationData data = new ApplicationData()
|
||||
{
|
||||
Fav = bool.Parse(userData[2]),
|
||||
Fav = metaData.Item1,
|
||||
Icon = applicationIcon,
|
||||
TitleName = titleName,
|
||||
TitleId = titleId,
|
||||
Developer = developer,
|
||||
Version = version,
|
||||
TimePlayed = userData[0],
|
||||
LastPlayed = userData[1],
|
||||
TimePlayed = metaData.Item2,
|
||||
LastPlayed = metaData.Item3,
|
||||
FileExt = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1),
|
||||
FileSize = (filesize < 1) ? (filesize * 1024).ToString("0.##") + "MB" : filesize.ToString("0.##") + "GB",
|
||||
Path = applicationPath,
|
||||
|
@ -388,82 +399,53 @@ namespace Ryujinx.UI
|
|||
return controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
|
||||
}
|
||||
|
||||
private static string[] GetUserData(string TitleId, string UserId)
|
||||
private static (bool, string, string) GetMetadata(string TitleId)
|
||||
{
|
||||
try
|
||||
string metadataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "games", TitleId, "gui");
|
||||
string metadataFile = Path.Combine(metadataFolder, "metadata.json");
|
||||
|
||||
IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
|
||||
|
||||
if (!File.Exists(metadataFile))
|
||||
{
|
||||
string[] userData = new string[3];
|
||||
string savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "GUI", UserId, TitleId);
|
||||
Directory.CreateDirectory(metadataFolder);
|
||||
|
||||
//Time Played
|
||||
if (File.Exists(Path.Combine(savePath, "TimePlayed.dat")) == false)
|
||||
AppMetadata = new ApplicationMetadata
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
using (FileStream file = File.OpenWrite(Path.Combine(savePath, "TimePlayed.dat")))
|
||||
{
|
||||
file.Write(Encoding.ASCII.GetBytes("0"));
|
||||
}
|
||||
}
|
||||
Fav = false,
|
||||
TimePlayed = 0,
|
||||
LastPlayed = "Never"
|
||||
};
|
||||
|
||||
using (FileStream fs = File.OpenRead(Path.Combine(savePath, "TimePlayed.dat")))
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(fs))
|
||||
{
|
||||
float timePlayed = float.Parse(sr.ReadLine());
|
||||
|
||||
if (timePlayed < SecondsPerMinute)
|
||||
{
|
||||
userData[0] = $"{timePlayed}s";
|
||||
}
|
||||
else if (timePlayed < SecondsPerHour)
|
||||
{
|
||||
userData[0] = $"{Math.Round(timePlayed / SecondsPerMinute, 2, MidpointRounding.AwayFromZero)} mins";
|
||||
}
|
||||
else if (timePlayed < SecondsPerDay)
|
||||
{
|
||||
userData[0] = $"{Math.Round(timePlayed / SecondsPerHour , 2, MidpointRounding.AwayFromZero)} hrs";
|
||||
}
|
||||
else
|
||||
{
|
||||
userData[0] = $"{Math.Round(timePlayed / SecondsPerDay , 2, MidpointRounding.AwayFromZero)} days";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Last Played
|
||||
if (File.Exists(Path.Combine(savePath, "LastPlayed.dat")) == false)
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
using (FileStream file = File.OpenWrite(Path.Combine(savePath, "LastPlayed.dat")))
|
||||
{
|
||||
file.Write(Encoding.ASCII.GetBytes("Never"));
|
||||
}
|
||||
}
|
||||
|
||||
using (FileStream fs = File.OpenRead(Path.Combine(savePath, "LastPlayed.dat")))
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(fs))
|
||||
{
|
||||
userData[1] = sr.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
//Fav Games
|
||||
if (File.Exists(Path.Combine(savePath, "Fav.dat")))
|
||||
{
|
||||
userData[2] = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
userData[2] = "false";
|
||||
}
|
||||
|
||||
return userData;
|
||||
byte[] saveData = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
|
||||
}
|
||||
catch
|
||||
|
||||
using (Stream stream = File.OpenRead(metadataFile))
|
||||
{
|
||||
return new string[] { "Unknown", "Unknown", "false" };
|
||||
AppMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
|
||||
}
|
||||
|
||||
string timePlayed;
|
||||
|
||||
if (AppMetadata.TimePlayed < SecondsPerMinute)
|
||||
{
|
||||
timePlayed = $"{AppMetadata.TimePlayed}s";
|
||||
}
|
||||
else if (AppMetadata.TimePlayed < SecondsPerHour)
|
||||
{
|
||||
timePlayed = $"{Math.Round(AppMetadata.TimePlayed / SecondsPerMinute, 2, MidpointRounding.AwayFromZero)} mins";
|
||||
}
|
||||
else if (AppMetadata.TimePlayed < SecondsPerDay)
|
||||
{
|
||||
timePlayed = $"{Math.Round(AppMetadata.TimePlayed / SecondsPerHour, 2, MidpointRounding.AwayFromZero)} hrs";
|
||||
}
|
||||
else
|
||||
{
|
||||
timePlayed = $"{Math.Round(AppMetadata.TimePlayed / SecondsPerDay, 2, MidpointRounding.AwayFromZero)} days";
|
||||
}
|
||||
|
||||
return (AppMetadata.Fav, timePlayed, AppMetadata.LastPlayed);
|
||||
}
|
||||
|
||||
private static byte[] NspOrXciIcon(string applicationPath)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using JsonPrettyPrinterPlus;
|
||||
using DiscordRPC;
|
||||
using Gtk;
|
||||
using GUI = Gtk.Builder.ObjectAttribute;
|
||||
|
@ -13,6 +14,8 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Utf8Json;
|
||||
using Utf8Json.Resolvers;
|
||||
|
||||
namespace Ryujinx.UI
|
||||
{
|
||||
|
@ -36,8 +39,6 @@ namespace Ryujinx.UI
|
|||
|
||||
private static bool _firstLoadComplete = false;
|
||||
|
||||
private static string _userId = "00000000000000000000000000000001";
|
||||
|
||||
private static TreeViewColumn favColumn;
|
||||
private static TreeViewColumn appColumn;
|
||||
private static TreeViewColumn devColumn;
|
||||
|
@ -48,6 +49,15 @@ namespace Ryujinx.UI
|
|||
private static TreeViewColumn fileSizeColumn;
|
||||
private static TreeViewColumn pathColumn;
|
||||
|
||||
private struct ApplicationMetadata
|
||||
{
|
||||
public bool Fav;
|
||||
public double TimePlayed;
|
||||
public string LastPlayed;
|
||||
}
|
||||
|
||||
private static ApplicationMetadata AppMetadata;
|
||||
|
||||
public static bool DiscordIntegrationEnabled { get; set; }
|
||||
|
||||
public static DiscordRpcClient DiscordClient;
|
||||
|
@ -355,40 +365,35 @@ namespace Ryujinx.UI
|
|||
DiscordClient.SetPresence(DiscordPresence);
|
||||
}
|
||||
|
||||
try
|
||||
string metadataFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "games", _device.System.TitleID, "gui");
|
||||
string metadataFile = System.IO.Path.Combine(metadataFolder, "metadata.json");
|
||||
|
||||
IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
|
||||
|
||||
if (!File.Exists(metadataFile))
|
||||
{
|
||||
string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "GUI", _userId, _device.System.TitleID);
|
||||
Directory.CreateDirectory(metadataFolder);
|
||||
|
||||
if (File.Exists(System.IO.Path.Combine(savePath, "TimePlayed.dat")) == false)
|
||||
AppMetadata = new ApplicationMetadata
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
|
||||
{
|
||||
stream.Write(Encoding.ASCII.GetBytes("0"));
|
||||
}
|
||||
}
|
||||
Fav = false,
|
||||
TimePlayed = 0,
|
||||
LastPlayed = "Never"
|
||||
};
|
||||
|
||||
if (File.Exists(System.IO.Path.Combine(savePath, "LastPlayed.dat")) == false)
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
|
||||
{
|
||||
stream.Write(Encoding.ASCII.GetBytes("Never"));
|
||||
}
|
||||
}
|
||||
|
||||
using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(stream))
|
||||
{
|
||||
writer.WriteLine(DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
byte[] data = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson());
|
||||
}
|
||||
catch (ArgumentNullException)
|
||||
|
||||
using (Stream stream = File.OpenRead(metadataFile))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
|
||||
AppMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
|
||||
}
|
||||
|
||||
AppMetadata.LastPlayed = DateTime.UtcNow.ToString();
|
||||
|
||||
byte[] saveData = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,39 +417,35 @@ namespace Ryujinx.UI
|
|||
|
||||
if (_gameLoaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "GUI", _userId, _device.System.TitleID);
|
||||
double currentPlayTime = 0;
|
||||
string metadataFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "games", _device.System.TitleID, "gui");
|
||||
string metadataFile = System.IO.Path.Combine(metadataFolder, "metadata.json");
|
||||
|
||||
using (FileStream stream = File.OpenRead(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
|
||||
IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
|
||||
|
||||
if (!File.Exists(metadataFile))
|
||||
{
|
||||
Directory.CreateDirectory(metadataFolder);
|
||||
|
||||
AppMetadata = new ApplicationMetadata
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
DateTime startTime = DateTime.Parse(reader.ReadLine());
|
||||
Fav = false,
|
||||
TimePlayed = 0,
|
||||
LastPlayed = "Never"
|
||||
};
|
||||
|
||||
using (FileStream lastPlayedStream = File.OpenRead(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
|
||||
{
|
||||
using (StreamReader lastPlayedReader = new StreamReader(lastPlayedStream))
|
||||
{
|
||||
currentPlayTime = double.Parse(lastPlayedReader.ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
using (FileStream timePlayedStream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
|
||||
{
|
||||
using (StreamWriter timePlayedWriter = new StreamWriter(timePlayedStream))
|
||||
{
|
||||
timePlayedWriter.WriteLine(currentPlayTime + Math.Round(DateTime.UtcNow.Subtract(startTime).TotalSeconds, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] data = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson());
|
||||
}
|
||||
catch (ArgumentNullException)
|
||||
|
||||
using (Stream stream = File.OpenRead(metadataFile))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
|
||||
AppMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
|
||||
}
|
||||
|
||||
AppMetadata.TimePlayed += Math.Round(DateTime.UtcNow.Subtract(DateTime.Parse(AppMetadata.LastPlayed)).TotalSeconds, MidpointRounding.AwayFromZero);
|
||||
|
||||
byte[] saveData = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
|
||||
}
|
||||
|
||||
Profile.FinishProfiling();
|
||||
|
@ -480,26 +481,31 @@ namespace Ryujinx.UI
|
|||
private void FavToggle_Toggled(object o, ToggledArgs args)
|
||||
{
|
||||
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
||||
string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "GUI", _userId, _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower());
|
||||
string titleid = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
||||
string metadataPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "games", titleid, "gui", "metadata.json");
|
||||
|
||||
IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
|
||||
|
||||
using (Stream stream = File.OpenRead(metadataPath))
|
||||
{
|
||||
AppMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
|
||||
}
|
||||
|
||||
if ((bool)_tableStore.GetValue(treeIter, 0))
|
||||
{
|
||||
_tableStore.SetValue(treeIter, 0, false);
|
||||
|
||||
if (File.Exists(System.IO.Path.Combine(savePath, "Fav.dat")))
|
||||
{
|
||||
File.Delete(System.IO.Path.Combine(savePath, "Fav.dat"));
|
||||
}
|
||||
AppMetadata.Fav = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tableStore.SetValue(treeIter, 0, true);
|
||||
|
||||
if (!File.Exists(System.IO.Path.Combine(savePath, "Fav.dat")))
|
||||
{
|
||||
using (File.Create(System.IO.Path.Combine(savePath, "Fav.dat"))) { };
|
||||
}
|
||||
AppMetadata.Fav = true;
|
||||
}
|
||||
|
||||
byte[] saveData = JsonSerializer.Serialize(AppMetadata, resolver);
|
||||
File.WriteAllText(metadataPath, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
|
||||
}
|
||||
|
||||
private void Row_Activated(object o, RowActivatedArgs args)
|
||||
|
@ -710,9 +716,6 @@ namespace Ryujinx.UI
|
|||
string aValue = model.GetValue(a, 5).ToString();
|
||||
string bValue = model.GetValue(b, 5).ToString();
|
||||
|
||||
if (aValue == "Unknown") { aValue = "0s"; }
|
||||
if (bValue == "Unknown") { bValue = "0s"; }
|
||||
|
||||
if (aValue.Length > 4 && aValue.Substring(aValue.Length - 4) == "mins")
|
||||
{
|
||||
aValue = (float.Parse(aValue.Substring(0, aValue.Length - 5)) * 60).ToString();
|
||||
|
|
Loading…
Add table
Reference in a new issue