diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index b18bd47..27fbd48 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -5,7 +5,7 @@ True Resources\ini.ico true - 3.2.2.5 + 3.2.3.0 Resources\ini.ico LICENSE 2021, pointfeev (https://github.com/pointfeev) diff --git a/CreamInstaller/Epic/EpicLibrary.cs b/CreamInstaller/Epic/EpicLibrary.cs index 5a2e52a..675cfea 100644 --- a/CreamInstaller/Epic/EpicLibrary.cs +++ b/CreamInstaller/Epic/EpicLibrary.cs @@ -27,21 +27,18 @@ internal static class EpicLibrary if (!Directory.Exists(EpicAppDataPath)) return games; string manifests = EpicAppDataPath + @"\Manifests"; if (!Directory.Exists(manifests)) return games; - string[] files = Directory.GetFiles(manifests); + string[] files = Directory.GetFiles(manifests, "*.item"); foreach (string file in files) { if (Program.Canceled) return games; - if (Path.GetExtension(file) == ".item") + string json = File.ReadAllText(file); + try { - string json = File.ReadAllText(file); - try - { - Manifest manifest = JsonSerializer.Deserialize(json); - if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId) - games.Add(manifest); - } - catch { }; + Manifest manifest = JsonSerializer.Deserialize(json); + if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId) + games.Add(manifest); } + catch { }; } return games; }); diff --git a/CreamInstaller/Epic/EpicStore.cs b/CreamInstaller/Epic/EpicStore.cs index e3ab371..31a71cc 100644 --- a/CreamInstaller/Epic/EpicStore.cs +++ b/CreamInstaller/Epic/EpicStore.cs @@ -16,36 +16,42 @@ namespace CreamInstaller.Epic; internal static class EpicStore { + //private const int COOLDOWN_CATALOG_ITEM = 600; + /* need a method to query catalog items internal static async Task QueryCatalogItems(Manifest manifest) { }*/ + private const int COOLDOWN_ENTITLEMENT = 600; internal static async Task> QueryEntitlements(string categoryNamespace) { List<(string id, string name, string product, string icon, string developer)> dlcIds = new(); - Response response = await QueryGraphQL(categoryNamespace); string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json"; + bool cachedExists = Directory.Exists(Directory.GetDirectoryRoot(cacheFile)) && File.Exists(cacheFile); + Response response = null; + if (!cachedExists || ProgramData.CheckCooldown(categoryNamespace, COOLDOWN_ENTITLEMENT)) + { + response = await QueryGraphQL(categoryNamespace); + try + { + File.WriteAllText(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented)); + } + catch { } + } + else if (cachedExists) + { + try + { + response = JsonConvert.DeserializeObject(File.ReadAllText(cacheFile)); + } + catch + { + File.Delete(cacheFile); + } + } if (response is null) - if (Directory.Exists(Directory.GetDirectoryRoot(cacheFile)) && File.Exists(cacheFile)) - try - { - response = JsonConvert.DeserializeObject(File.ReadAllText(cacheFile)); - } - catch - { - File.Delete(cacheFile); - } - if (response is null) return dlcIds; - try - { - File.WriteAllText(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented)); - } - catch //(Exception e) - { - //using DialogForm dialogForm = new(null); - //dialogForm.Show(SystemIcons.Error, "Unsuccessful serialization of query for category namespace " + categoryNamespace + ":\n\n" + e.ToString(), "FUCK"); - } + return dlcIds; List searchStore = new(response.Data.Catalog.SearchStore.Elements); foreach (Element element in searchStore) { diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index f06961c..020c38b 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -144,7 +144,7 @@ internal partial class SelectForm : CustomForm RemoveFromRemainingGames(name); return; } - AppData appData = await SteamStore.QueryStoreAPI(appId, 60); + AppData appData = await SteamStore.QueryStoreAPI(appId); VProperty appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId); if (appData is null && appInfo is null) { @@ -169,7 +169,7 @@ internal partial class SelectForm : CustomForm Thread.Sleep(0); string dlcName = null; string dlcIcon = null; - AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId); + AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId, true); if (dlcAppData is not null) { dlcName = dlcAppData.name; diff --git a/CreamInstaller/Properties/Resources.resx b/CreamInstaller/Properties/Resources.resx index 4b5dcaf..0989eea 100644 --- a/CreamInstaller/Properties/Resources.resx +++ b/CreamInstaller/Properties/Resources.resx @@ -112,12 +112,12 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\resources\ini.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/CreamInstaller/Steam/SteamLibrary.cs b/CreamInstaller/Steam/SteamLibrary.cs index d56aa55..3bcb8ec 100644 --- a/CreamInstaller/Steam/SteamLibrary.cs +++ b/CreamInstaller/Steam/SteamLibrary.cs @@ -68,11 +68,11 @@ internal static class SteamLibrary { List> games = new(); if (Program.Canceled || !Directory.Exists(libraryDirectory)) return null; - string[] files = Directory.GetFiles(libraryDirectory); + string[] files = Directory.GetFiles(libraryDirectory, "*.acf"); foreach (string file in files) { if (Program.Canceled) return null; - if (Path.GetExtension(file) == ".acf" && ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result)) + if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result)) { string appId = result.Value.GetChild("appid")?.ToString(); string installdir = result.Value.GetChild("installdir")?.ToString(); diff --git a/CreamInstaller/Steam/SteamStore.cs b/CreamInstaller/Steam/SteamStore.cs index 68c9102..c2a1227 100644 --- a/CreamInstaller/Steam/SteamStore.cs +++ b/CreamInstaller/Steam/SteamStore.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Threading; using System.Threading.Tasks; using CreamInstaller.Utility; @@ -23,23 +20,22 @@ internal static class SteamStore return dlcIds; }); - private static readonly ConcurrentDictionary lastQueries = new(); - internal static async Task QueryStoreAPI(string appId, int cooldown = 10) + private const int COOLDOWN_GAME = 600; + private const int COOLDOWN_DLC = 1200; + + internal static async Task QueryStoreAPI(string appId, bool isDlc = false) { if (Program.Canceled) return null; - Thread.Sleep(0); string cacheFile = ProgramData.AppInfoPath + @$"\{appId}.json"; - DateTime now = DateTime.UtcNow; - if (!lastQueries.TryGetValue(appId, out DateTime lastQuery) || (now - lastQuery).TotalSeconds > cooldown) + bool cachedExists = Directory.Exists(Directory.GetDirectoryRoot(cacheFile)) && File.Exists(cacheFile); + if (!cachedExists || ProgramData.CheckCooldown(appId, isDlc ? COOLDOWN_DLC : COOLDOWN_GAME)) { - lastQueries[appId] = now; string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}"); if (response is not null) { IDictionary apps = (dynamic)JsonConvert.DeserializeObject(response); foreach (KeyValuePair app in apps) { - Thread.Sleep(0); try { AppData data = JsonConvert.DeserializeObject(app.Value.ToString()).data; @@ -65,7 +61,7 @@ internal static class SteamStore } } } - if (Directory.Exists(Directory.GetDirectoryRoot(cacheFile)) && File.Exists(cacheFile)) + if (cachedExists) { try { diff --git a/CreamInstaller/Utility/ProgramData.cs b/CreamInstaller/Utility/ProgramData.cs index 1a7281c..9228e51 100644 --- a/CreamInstaller/Utility/ProgramData.cs +++ b/CreamInstaller/Utility/ProgramData.cs @@ -16,6 +16,8 @@ internal static class ProgramData internal static readonly Version MinimumAppInfoVersion = Version.Parse("3.2.0.0"); + internal static readonly string CooldownPath = DirectoryPath + @"\cooldown"; + internal static async Task Setup() => await Task.Run(() => { if (Directory.Exists(DirectoryPathOld)) @@ -30,5 +32,45 @@ internal static class ProgramData Directory.CreateDirectory(AppInfoPath); File.WriteAllText(AppInfoVersionPath, Application.ProductVersion, Encoding.UTF8); } + if (!Directory.Exists(CooldownPath)) + Directory.CreateDirectory(CooldownPath); }); + + internal static bool CheckCooldown(string identifier, int cooldown) + { + DateTime now = DateTime.UtcNow; + DateTime lastCheck = GetCooldown(identifier) ?? now; + bool cooldownOver = (now - lastCheck).TotalSeconds > cooldown; + if (cooldownOver || now == lastCheck) + SetCooldown(identifier, now); + return cooldownOver; + } + private static DateTime? GetCooldown(string identifier) + { + if (Directory.Exists(CooldownPath)) + { + string cooldownFile = CooldownPath + @$"\{identifier}.txt"; + if (File.Exists(cooldownFile)) + { + try + { + if (DateTime.TryParse(File.ReadAllText(cooldownFile), out DateTime cooldown)) + return cooldown; + } + catch { } + } + } + return null; + } + private static void SetCooldown(string identifier, DateTime time) + { + if (!Directory.Exists(CooldownPath)) + Directory.CreateDirectory(CooldownPath); + string cooldownFile = CooldownPath + @$"\{identifier}.txt"; + try + { + File.WriteAllText(cooldownFile, time.ToString()); + } + catch { } + } }