Parse and process Steam AppIDs and DepotIDs (#961)

* Recreate PR

* Implement first round of fixes.
This commit is contained in:
HeroponRikiBestest
2026-03-18 18:17:22 -07:00
committed by GitHub
parent 29601f130a
commit f819632a40
2 changed files with 260 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -157,6 +158,255 @@ namespace MPF.Frontend.Tools
#endregion
#region Computer
/// <summary>
/// Get info for discs containing Steam2 (sis/sim/sid) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam2 information on success, null otherwise</returns>
public static string? GetSteamSimSidInfo(Drive? drive)
{
// If there's no drive path, we can't get any sis files
if (string.IsNullOrEmpty(drive?.Name))
return null;
// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;
try
{
string steamInfo = string.Empty;
var steamDepotIdList = new List<long>();
// ? needed due to note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
var options = new EnumerationOptions
{
MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true
};
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#else
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
#endif
foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;
long sisSize = new FileInfo(sis).Length;
// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
if (sisSize > 10000)
continue;
// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();
var skuSis = skuSisDeserializer.Deserialize(fileStream);
if (skuSis?.Sku is not null)
{
var sku = skuSis.Sku;
// Skips csm/csd sku sis files
if (sku.Manifests is not null)
continue;
// There should always be depots.
if (sku.Depots is null)
continue;
steamDepotIdList.AddRange([.. sku.Depots.Values]);
}
}
long[] sortedArray = [.. steamDepotIdList.Distinct()];
Array.Sort(sortedArray);
steamInfo = string.Join("\n", Array.ConvertAll(sortedArray, l => l.ToString()));
if (string.IsNullOrEmpty(steamInfo))
return null;
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}
/// <summary>
/// Get info for discs containing Steam3 (sis/csm/csd) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam Csm/Csd information on success, null otherwise</returns>
public static string? GetSteamCsmCsdInfo(Drive? drive)
{
// If there's no drive path, we can't get exe name
if (string.IsNullOrEmpty(drive?.Name))
return null;
// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;
try
{
string steamInfo = string.Empty;
var steamDepotIdDict = new SortedDictionary<long, long>();
// ? needed due to note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
var options = new EnumerationOptions
{
MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true
};
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#else
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
#endif
foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;
long sisSize = new FileInfo(sis).Length;
// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
if (sisSize > 10000)
continue;
// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();
var skuSis = skuSisDeserializer.Deserialize(fileStream);
if (skuSis?.Sku is not null)
{
var sku = skuSis.Sku;
if (sku is null)
continue;
// Skips steam2 sku sis files. Steam3 csm/csd sis files always have manifests.
if (sku.Manifests is not null)
{
foreach (var depot in sku.Manifests)
{
#if NETFRAMEWORK
steamDepotIdDict.Add(depot.Key, depot.Value); // Always fine in practice.
#else
steamDepotIdDict.TryAdd(depot.Key,
depot.Value); // Mainly here to allow easier bulk testing.
#endif
}
}
}
}
foreach (var depot in steamDepotIdDict)
{
steamInfo += $"{depot.Key} ({depot.Value})\n";
}
if (string.IsNullOrEmpty(steamInfo))
return null;
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}
/// <summary>
/// Get info for discs containing Steam2 (sis/sim/sid) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam2 information on success, null otherwise</returns>
public static string? GetSteamAppInfo(Drive? drive)
{
// If there's no drive path, we can't get exe name
if (string.IsNullOrEmpty(drive?.Name))
return null;
// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;
try
{
string steamInfo = string.Empty;
var steamAppIdList = new List<long>();
// ? needed due to note in note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
var options = new EnumerationOptions
{
MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true
};
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#else
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
#endif
// Looping needed in case i.e. this is a coverdisc with multiple steam game installers on it.
foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;
string filename = Path.GetFileName(sis);
// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
long sisSize = new FileInfo(sis).Length;
if (sisSize > 10000)
continue;
// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();
var skuSis = skuSisDeserializer.Deserialize(fileStream);
if (skuSis?.Sku is not null)
{
var sku = skuSis.Sku;
// There should always be apps
if (sku.Apps is null)
continue;
steamAppIdList.AddRange([.. sku.Apps.Values]);
}
}
long[] sortedArray = [.. steamAppIdList.Distinct()];
Array.Sort(sortedArray);
steamInfo = string.Join(", ", Array.ConvertAll(sortedArray, l => l.ToString()));
if (string.IsNullOrEmpty(steamInfo))
return null;
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}
#endregion
#region PlayStation
/// <summary>

View File

@@ -851,6 +851,16 @@ namespace MPF.Frontend.Tools
info.CommonDiscInfo.Category ??= DiscCategory.Multimedia;
break;
case RedumpSystem.IBMPCcompatible:
case RedumpSystem.AppleMacintosh:
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SteamAppID] =
PhysicalTool.GetSteamAppInfo(drive) ?? string.Empty;
info.CommonDiscInfo.ContentsSpecialFields[SiteCode.SteamSimSidDepotID] =
PhysicalTool.GetSteamSimSidInfo(drive) ?? string.Empty;
info.CommonDiscInfo.ContentsSpecialFields[SiteCode.SteamCsmCsdDepotID] =
PhysicalTool.GetSteamCsmCsdInfo(drive) ?? string.Empty;
break;
case RedumpSystem.IncredibleTechnologiesEagle:
info.CommonDiscInfo.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
break;