Convert SteamCMD VDF to JSON to prepare for compatibility with web API
This commit is contained in:
parent
a198b7f9e5
commit
eb8c75d249
8 changed files with 172 additions and 118 deletions
|
@ -154,6 +154,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
||||||
|
<PackageReference Include="Gameloop.Vdf.JsonConverter" Version="0.2.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.ServiceModel.Primitives" Version="8.0.0" />
|
<PackageReference Include="System.ServiceModel.Primitives" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -201,10 +201,10 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
|
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
AppData appData = await SteamStore.QueryStoreAPI(appId);
|
StoreAppData storeAppData = await SteamStore.QueryStoreAPI(appId);
|
||||||
_ = Interlocked.Decrement(ref steamGamesToCheck);
|
_ = Interlocked.Decrement(ref steamGamesToCheck);
|
||||||
VProperty appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
|
CmdAppData cmdAppData = await SteamCMD.GetAppInfo(appId, branch, buildId);
|
||||||
if (appData is null && appInfo is null)
|
if (storeAppData is null && cmdAppData is null)
|
||||||
{
|
{
|
||||||
RemoveFromRemainingGames(name);
|
RemoveFromRemainingGames(name);
|
||||||
return;
|
return;
|
||||||
|
@ -213,13 +213,13 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
ConcurrentDictionary<SelectionDLC, byte> dlc = new();
|
ConcurrentDictionary<SelectionDLC, byte> dlc = new();
|
||||||
List<Task> dlcTasks = new();
|
List<Task> dlcTasks = [];
|
||||||
HashSet<string> dlcIds = new();
|
HashSet<string> dlcIds = [];
|
||||||
if (appData is not null)
|
if (storeAppData is not null)
|
||||||
foreach (string dlcId in await SteamStore.ParseDlcAppIds(appData))
|
foreach (string dlcId in await SteamStore.ParseDlcAppIds(storeAppData))
|
||||||
_ = dlcIds.Add(dlcId);
|
_ = dlcIds.Add(dlcId);
|
||||||
if (appInfo is not null)
|
if (cmdAppData is not null)
|
||||||
foreach (string dlcId in await SteamCMD.ParseDlcAppIds(appInfo))
|
foreach (string dlcId in await SteamCMD.ParseDlcAppIds(cmdAppData))
|
||||||
_ = dlcIds.Add(dlcId);
|
_ = dlcIds.Add(dlcId);
|
||||||
if (dlcIds.Count > 0)
|
if (dlcIds.Count > 0)
|
||||||
foreach (string dlcAppId in dlcIds)
|
foreach (string dlcAppId in dlcIds)
|
||||||
|
@ -240,31 +240,27 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
string dlcName = null;
|
string dlcName = null;
|
||||||
string dlcIcon = null;
|
string dlcIcon = null;
|
||||||
bool onSteamStore = false;
|
bool onSteamStore = false;
|
||||||
AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId, true);
|
StoreAppData dlcStoreAppData = await SteamStore.QueryStoreAPI(dlcAppId, true);
|
||||||
if (dlcAppData is not null)
|
if (dlcStoreAppData is not null)
|
||||||
{
|
{
|
||||||
dlcName = dlcAppData.Name;
|
dlcName = dlcStoreAppData.Name;
|
||||||
dlcIcon = dlcAppData.HeaderImage;
|
dlcIcon = dlcStoreAppData.HeaderImage;
|
||||||
onSteamStore = true;
|
onSteamStore = true;
|
||||||
fullGameAppId = dlcAppData.FullGame?.AppId;
|
fullGameAppId = dlcStoreAppData.FullGame?.AppId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VProperty dlcAppInfo = await SteamCMD.GetAppInfo(dlcAppId);
|
CmdAppData dlcCmdAppData = await SteamCMD.GetAppInfo(dlcAppId);
|
||||||
if (dlcAppInfo is not null)
|
if (dlcCmdAppData is not null)
|
||||||
{
|
{
|
||||||
dlcName = dlcAppInfo.Value.GetChild("common")?.GetChild("name")?.ToString();
|
dlcName = dlcCmdAppData.Common?.Name;
|
||||||
string dlcIconStaticId = dlcAppInfo.Value.GetChild("common")?.GetChild("icon")
|
string dlcIconStaticId = dlcCmdAppData.Common?.Icon;
|
||||||
?.ToString();
|
dlcIconStaticId ??= dlcCmdAppData.Common?.LogoSmall;
|
||||||
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo_small")
|
dlcIconStaticId ??= dlcCmdAppData.Common?.Logo;
|
||||||
?.ToString();
|
|
||||||
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo")
|
|
||||||
?.ToString();
|
|
||||||
if (dlcIconStaticId is not null)
|
if (dlcIconStaticId is not null)
|
||||||
dlcIcon = IconGrabber.SteamAppImagesPath +
|
dlcIcon = IconGrabber.SteamAppImagesPath +
|
||||||
@$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
@$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
||||||
fullGameAppId = dlcAppInfo.Value.GetChild("common")?.GetChild("parent")
|
fullGameAppId = dlcCmdAppData.Common?.Parent;
|
||||||
?.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,26 +269,23 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
string fullGameName = null;
|
string fullGameName = null;
|
||||||
string fullGameIcon = null;
|
string fullGameIcon = null;
|
||||||
bool fullGameOnSteamStore = false;
|
bool fullGameOnSteamStore = false;
|
||||||
AppData fullGameAppData = await SteamStore.QueryStoreAPI(fullGameAppId, true);
|
StoreAppData fullGameStoreAppData =
|
||||||
if (fullGameAppData is not null)
|
await SteamStore.QueryStoreAPI(fullGameAppId, true);
|
||||||
|
if (fullGameStoreAppData is not null)
|
||||||
{
|
{
|
||||||
fullGameName = fullGameAppData.Name;
|
fullGameName = fullGameStoreAppData.Name;
|
||||||
fullGameIcon = fullGameAppData.HeaderImage;
|
fullGameIcon = fullGameStoreAppData.HeaderImage;
|
||||||
fullGameOnSteamStore = true;
|
fullGameOnSteamStore = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VProperty fullGameAppInfo = await SteamCMD.GetAppInfo(fullGameAppId);
|
CmdAppData fullGameAppInfo = await SteamCMD.GetAppInfo(fullGameAppId);
|
||||||
if (fullGameAppInfo is not null)
|
if (fullGameAppInfo is not null)
|
||||||
{
|
{
|
||||||
fullGameName = fullGameAppInfo.Value.GetChild("common")?.GetChild("name")
|
fullGameName = fullGameAppInfo.Common?.Name;
|
||||||
?.ToString();
|
string fullGameIconStaticId = fullGameAppInfo.Common?.Icon;
|
||||||
string fullGameIconStaticId = fullGameAppInfo.Value.GetChild("common")
|
fullGameIconStaticId ??= fullGameAppInfo.Common?.LogoSmall;
|
||||||
?.GetChild("icon")?.ToString();
|
fullGameIconStaticId ??= fullGameAppInfo.Common?.Logo;
|
||||||
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")
|
|
||||||
?.GetChild("logo_small")?.ToString();
|
|
||||||
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")
|
|
||||||
?.GetChild("logo")?.ToString();
|
|
||||||
if (fullGameIconStaticId is not null)
|
if (fullGameIconStaticId is not null)
|
||||||
dlcIcon = IconGrabber.SteamAppImagesPath +
|
dlcIcon = IconGrabber.SteamAppImagesPath +
|
||||||
@$"\{fullGameAppId}\{fullGameIconStaticId}.jpg";
|
@$"\{fullGameAppId}\{fullGameIconStaticId}.jpg";
|
||||||
|
@ -345,17 +338,15 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name,
|
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, storeAppData?.Name ?? name,
|
||||||
gameDirectory, dllDirectories,
|
gameDirectory, dllDirectories,
|
||||||
await gameDirectory.GetExecutableDirectories(true));
|
await gameDirectory.GetExecutableDirectories(true));
|
||||||
selection.Product = "https://store.steampowered.com/app/" + appId;
|
selection.Product = "https://store.steampowered.com/app/" + appId;
|
||||||
selection.Icon = IconGrabber.SteamAppImagesPath +
|
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{cmdAppData?.Common?.Icon}.jpg";
|
||||||
@$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
|
selection.SubIcon = storeAppData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
|
||||||
selection.SubIcon = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
|
+ @$"\{appId}\{cmdAppData?.Common?.ClientIcon}.ico";
|
||||||
+ @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("clienticon")}.ico";
|
selection.Publisher = storeAppData?.Publishers[0] ?? cmdAppData?.Extended?.Publisher;
|
||||||
selection.Publisher = appData?.Publishers[0] ??
|
selection.Website = storeAppData?.Website;
|
||||||
appInfo?.Value.GetChild("extended")?.GetChild("publisher")?.ToString();
|
|
||||||
selection.Website = appData?.Website;
|
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
Invoke(delegate
|
Invoke(delegate
|
||||||
|
|
53
CreamInstaller/Platforms/Steam/CmdAppDetails.cs
Normal file
53
CreamInstaller/Platforms/Steam/CmdAppDetails.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CreamInstaller.Platforms.Steam;
|
||||||
|
|
||||||
|
public class CmdAppCommon
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "type")] public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "name")] public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "icon")] public string Icon { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "clienticon")]
|
||||||
|
public string ClientIcon { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "logo_small")]
|
||||||
|
public string LogoSmall { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "logo")] public string Logo { set; get; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "parent")]
|
||||||
|
public string Parent { set; get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CmdAppExtended
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "listofdlc")]
|
||||||
|
public string Dlc { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "publisher")]
|
||||||
|
public string Publisher { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CmdAppData
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "common")]
|
||||||
|
public CmdAppCommon Common { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "depots")]
|
||||||
|
public Dictionary<string, dynamic> Depots { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "extended")]
|
||||||
|
public CmdAppExtended Extended { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CmdAppDetails
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "status")]
|
||||||
|
public string Status { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "data")] public Dictionary<string, CmdAppData> Data { get; set; }
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CreamInstaller.Resources;
|
using CreamInstaller.Resources;
|
||||||
using CreamInstaller.Utility;
|
using CreamInstaller.Utility;
|
||||||
|
using Gameloop.Vdf.JsonConverter;
|
||||||
using Gameloop.Vdf.Linq;
|
using Gameloop.Vdf.Linq;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
using CreamInstaller.Forms;
|
using CreamInstaller.Forms;
|
||||||
|
@ -17,7 +18,7 @@ using CreamInstaller.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Steam;
|
namespace CreamInstaller.Platforms.Steam;
|
||||||
|
|
||||||
internal static class SteamCMD
|
internal static partial class SteamCMD
|
||||||
{
|
{
|
||||||
private const int ProcessLimit = 20;
|
private const int ProcessLimit = 20;
|
||||||
|
|
||||||
|
@ -32,10 +33,6 @@ internal static class SteamCMD
|
||||||
private static readonly string DllPath = DirectoryPath + @"\steamclient.dll";
|
private static readonly string DllPath = DirectoryPath + @"\steamclient.dll";
|
||||||
|
|
||||||
private static readonly string AppCachePath = DirectoryPath + @"\appcache";
|
private static readonly string AppCachePath = DirectoryPath + @"\appcache";
|
||||||
private static readonly string ConfigPath = DirectoryPath + @"\config";
|
|
||||||
private static readonly string DumpsPath = DirectoryPath + @"\dumps";
|
|
||||||
private static readonly string LogsPath = DirectoryPath + @"\logs";
|
|
||||||
private static readonly string SteamAppsPath = DirectoryPath + @"\steamapps";
|
|
||||||
|
|
||||||
private static string DirectoryPath => ProgramData.DirectoryPath;
|
private static string DirectoryPath => ProgramData.DirectoryPath;
|
||||||
internal static string AppInfoPath => ProgramData.AppInfoPath;
|
internal static string AppInfoPath => ProgramData.AppInfoPath;
|
||||||
|
@ -179,22 +176,7 @@ internal static class SteamCMD
|
||||||
await Kill();
|
await Kill();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (ConfigPath.DirectoryExists())
|
AppCachePath.DeleteDirectory();
|
||||||
foreach (string file in ConfigPath.EnumerateDirectory("*.tmp"))
|
|
||||||
file.DeleteFile();
|
|
||||||
foreach (string file in DirectoryPath.EnumerateDirectory("*.old"))
|
|
||||||
file.DeleteFile();
|
|
||||||
foreach (string file in DirectoryPath.EnumerateDirectory("*.delete"))
|
|
||||||
file.DeleteFile();
|
|
||||||
foreach (string file in DirectoryPath.EnumerateDirectory("*.crash"))
|
|
||||||
file.DeleteFile();
|
|
||||||
foreach (string file in DirectoryPath.EnumerateDirectory("*.ntfs_transaction_failed"))
|
|
||||||
file.DeleteFile();
|
|
||||||
AppCachePath
|
|
||||||
.DeleteDirectory(); // this is definitely needed, so SteamCMD gets the latest information for us
|
|
||||||
DumpsPath.DeleteDirectory();
|
|
||||||
LogsPath.DeleteDirectory();
|
|
||||||
SteamAppsPath.DeleteDirectory(); // this is just a useless folder created from +app_update 4
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -202,7 +184,7 @@ internal static class SteamCMD
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static async Task<VProperty> GetAppInfo(string appId, string branch = "public", int buildId = 0)
|
internal static async Task<CmdAppData> GetAppInfo(string appId, string branch = "public", int buildId = 0)
|
||||||
{
|
{
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
while (!Program.Canceled)
|
while (!Program.Canceled)
|
||||||
|
@ -254,18 +236,49 @@ internal static class SteamCMD
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!appInfo.Value.Children().Any())
|
CmdAppData appData;
|
||||||
return appInfo;
|
try
|
||||||
VToken type = appInfo.Value.GetChild("common")?.GetChild("type");
|
{
|
||||||
if (type is not null && type.ToString() != "Game")
|
if (appInfo.ToJson().Value.ToObject<CmdAppData>() is not { } cmdAppData)
|
||||||
return appInfo;
|
{
|
||||||
string buildid = appInfo.Value.GetChild("depots")?.GetChild("branches")?.GetChild(branch)
|
appUpdateFile.DeleteFile();
|
||||||
?.GetChild("buildid")?.ToString();
|
#if DEBUG
|
||||||
|
DebugForm.Current.Log(
|
||||||
|
"SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch +
|
||||||
|
"): VDF-JSON conversion failed",
|
||||||
|
LogTextBox.Warning);
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
appData = cmdAppData;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
#if DEBUG
|
||||||
|
(Exception e)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
appUpdateFile.DeleteFile();
|
||||||
|
#if DEBUG
|
||||||
|
DebugForm.Current.Log(
|
||||||
|
"SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch +
|
||||||
|
"): VDF-JSON conversion failed (" + e.Message + ")",
|
||||||
|
LogTextBox.Warning);
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string type = appData.Common?.Type;
|
||||||
|
if (type is not null && type != "Game")
|
||||||
|
return appData;
|
||||||
|
if (appData.Depots is null || !appData.Depots.TryGetValue("branches", out dynamic appBranch))
|
||||||
|
return appData;
|
||||||
|
string buildid = appBranch?[branch]?.buildid;
|
||||||
if (buildid is null && type is not null)
|
if (buildid is null && type is not null)
|
||||||
return appInfo;
|
return appData;
|
||||||
if (type is not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId))
|
if (type is not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId))
|
||||||
return appInfo;
|
return appData;
|
||||||
HashSet<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
HashSet<string> dlcAppIds = await ParseDlcAppIds(appData);
|
||||||
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
||||||
dlcAppUpdateFile.DeleteFile();
|
dlcAppUpdateFile.DeleteFile();
|
||||||
appUpdateFile.DeleteFile();
|
appUpdateFile.DeleteFile();
|
||||||
|
@ -279,30 +292,27 @@ internal static class SteamCMD
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<HashSet<string>> ParseDlcAppIds(VProperty appInfo)
|
internal static async Task<HashSet<string>> ParseDlcAppIds(CmdAppData appData)
|
||||||
=> await Task.Run(() =>
|
=> await Task.Run(() =>
|
||||||
{
|
{
|
||||||
HashSet<string> dlcIds = [];
|
HashSet<string> dlcIds = [];
|
||||||
if (Program.Canceled || appInfo is null)
|
if (Program.Canceled || appData is null)
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
VToken extended = appInfo.Value.GetChild("extended");
|
|
||||||
if (extended is not null)
|
|
||||||
foreach (VToken vToken in extended.Where(p => p is VProperty { Key: "listofdlc" }))
|
|
||||||
{
|
|
||||||
VProperty property = (VProperty)vToken;
|
|
||||||
foreach (string id in property.Value.ToString().Split(","))
|
|
||||||
if (int.TryParse(id, out int appId) && appId > 0)
|
|
||||||
_ = dlcIds.Add("" + appId);
|
|
||||||
}
|
|
||||||
|
|
||||||
VToken depots = appInfo.Value.GetChild("depots");
|
CmdAppExtended extended = appData.Extended;
|
||||||
|
if (extended?.Dlc != null)
|
||||||
|
foreach (string id in extended.Dlc.Split(","))
|
||||||
|
if (int.TryParse(id, out int appId) && appId > 0)
|
||||||
|
_ = dlcIds.Add("" + appId);
|
||||||
|
|
||||||
|
Dictionary<string, dynamic> depots = appData.Depots;
|
||||||
if (depots is null)
|
if (depots is null)
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
foreach (VToken vToken in depots.Where(
|
|
||||||
p => p is VProperty property && int.TryParse(property.Key, out int _)))
|
foreach ((_, dynamic depot) in depots.Where(p => int.TryParse(p.Key, out _)))
|
||||||
{
|
{
|
||||||
VProperty property = (VProperty)vToken;
|
string dlcAppId = depot.dlcappid;
|
||||||
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0)
|
if (dlcAppId is not null && int.TryParse(dlcAppId, out int appId) && appId > 0)
|
||||||
_ = dlcIds.Add("" + appId);
|
_ = dlcIds.Add("" + appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,20 @@ internal static class SteamStore
|
||||||
private const int CooldownGame = 600;
|
private const int CooldownGame = 600;
|
||||||
private const int CooldownDlc = 1200;
|
private const int CooldownDlc = 1200;
|
||||||
|
|
||||||
internal static async Task<HashSet<string>> ParseDlcAppIds(AppData appData)
|
internal static async Task<HashSet<string>> ParseDlcAppIds(StoreAppData storeAppData)
|
||||||
=> await Task.Run(() =>
|
=> await Task.Run(() =>
|
||||||
{
|
{
|
||||||
HashSet<string> dlcIds = new();
|
HashSet<string> dlcIds = new();
|
||||||
if (appData.DLC is null)
|
if (storeAppData.DLC is null)
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
foreach (string dlcId in from appId in appData.DLC
|
foreach (string dlcId in from appId in storeAppData.DLC
|
||||||
where appId > 0
|
where appId > 0
|
||||||
select appId.ToString(CultureInfo.InvariantCulture))
|
select appId.ToString(CultureInfo.InvariantCulture))
|
||||||
_ = dlcIds.Add(dlcId);
|
_ = dlcIds.Add(dlcId);
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false, int attempts = 0)
|
internal static async Task<StoreAppData> QueryStoreAPI(string appId, bool isDlc = false, int attempts = 0)
|
||||||
{
|
{
|
||||||
while (!Program.Canceled)
|
while (!Program.Canceled)
|
||||||
{
|
{
|
||||||
|
@ -50,11 +50,12 @@ internal static class SteamStore
|
||||||
foreach (KeyValuePair<string, JToken> app in apps)
|
foreach (KeyValuePair<string, JToken> app in apps)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AppDetails appDetails = JsonConvert.DeserializeObject<AppDetails>(app.Value.ToString());
|
StoreAppDetails storeAppDetails =
|
||||||
if (appDetails is not null)
|
JsonConvert.DeserializeObject<StoreAppDetails>(app.Value.ToString());
|
||||||
|
if (storeAppDetails is not null)
|
||||||
{
|
{
|
||||||
AppData data = appDetails.Data;
|
StoreAppData data = storeAppDetails.Data;
|
||||||
if (!appDetails.Success)
|
if (!storeAppDetails.Success)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugForm.Current.Log(
|
DebugForm.Current.Log(
|
||||||
|
@ -123,21 +124,19 @@ internal static class SteamStore
|
||||||
+ ": Response deserialization null");
|
+ ": Response deserialization null");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
else
|
||||||
DebugForm.Current.Log(
|
DebugForm.Current.Log(
|
||||||
"Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "") +
|
"Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "") +
|
||||||
": Response null",
|
": Response null",
|
||||||
LogTextBox.Warning);
|
LogTextBox.Warning);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cachedExists)
|
if (cachedExists)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject<AppData>(cacheFile.ReadFile());
|
return JsonConvert.DeserializeObject<StoreAppData>(cacheFile.ReadFile());
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,14 +3,14 @@ using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Steam;
|
namespace CreamInstaller.Platforms.Steam;
|
||||||
|
|
||||||
public class AppFullGame
|
public class StoreAppFullGame
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "appid")] public string AppId { get; set; }
|
[JsonProperty(PropertyName = "appid")] public string AppId { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "name")] public string Name { get; set; }
|
[JsonProperty(PropertyName = "name")] public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AppData
|
public class StoreAppData
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "type")] public string Type { get; set; }
|
[JsonProperty(PropertyName = "type")] public string Type { get; set; }
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ public class AppData
|
||||||
public int SteamAppId { get; set; }
|
public int SteamAppId { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "fullgame")]
|
[JsonProperty(PropertyName = "fullgame")]
|
||||||
public AppFullGame FullGame { get; set; }
|
public StoreAppFullGame FullGame { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "dlc")] public List<int> DLC { get; set; }
|
[JsonProperty(PropertyName = "dlc")] public List<int> DLC { get; set; }
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ public class AppData
|
||||||
public List<int> Packages { get; set; }
|
public List<int> Packages { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AppDetails
|
public class StoreAppDetails
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "success")]
|
[JsonProperty(PropertyName = "success")]
|
||||||
public bool Success { get; set; }
|
public bool Success { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "data")] public AppData Data { get; set; }
|
[JsonProperty(PropertyName = "data")] public StoreAppData Data { get; set; }
|
||||||
}
|
}
|
|
@ -111,7 +111,7 @@ internal static class ProgramData
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enumerable.Empty<(Platform platform, string id)>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteProgramChoices(IEnumerable<(Platform platform, string id)> choices)
|
internal static void WriteProgramChoices(IEnumerable<(Platform platform, string id)> choices)
|
||||||
|
@ -144,7 +144,7 @@ internal static class ProgramData
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enumerable.Empty<(Platform platform, string gameId, string dlcId)>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteDlcChoices(List<(Platform platform, string gameId, string dlcId)> choices)
|
internal static void WriteDlcChoices(List<(Platform platform, string gameId, string dlcId)> choices)
|
||||||
|
@ -177,7 +177,7 @@ internal static class ProgramData
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enumerable.Empty<(Platform platform, string id, string proxy, bool enabled)>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteProxyChoices(
|
internal static void WriteProxyChoices(
|
||||||
|
|
|
@ -75,7 +75,7 @@ internal static class SafeIO
|
||||||
Form form = null)
|
Form form = null)
|
||||||
{
|
{
|
||||||
if (!directoryPath.DirectoryExists())
|
if (!directoryPath.DirectoryExists())
|
||||||
return Enumerable.Empty<string>();
|
return [];
|
||||||
while (!Program.Canceled)
|
while (!Program.Canceled)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ internal static class SafeIO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enumerable.Empty<string>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IEnumerable<string> EnumerateSubdirectories(this string directoryPath, string directoryPattern,
|
internal static IEnumerable<string> EnumerateSubdirectories(this string directoryPath, string directoryPattern,
|
||||||
|
@ -100,7 +100,7 @@ internal static class SafeIO
|
||||||
bool crucial = false, Form form = null)
|
bool crucial = false, Form form = null)
|
||||||
{
|
{
|
||||||
if (!directoryPath.DirectoryExists())
|
if (!directoryPath.DirectoryExists())
|
||||||
return Enumerable.Empty<string>();
|
return [];
|
||||||
while (!Program.Canceled)
|
while (!Program.Canceled)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ internal static class SafeIO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enumerable.Empty<string>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool FileExists(this string filePath) => File.Exists(filePath);
|
internal static bool FileExists(this string filePath) => File.Exists(filePath);
|
||||||
|
|
Loading…
Reference in a new issue