Skip to content

Commit 2606755

Browse files
committed
Fixed bug where steam api is now suddenly gone
1 parent d8ea008 commit 2606755

6 files changed

Lines changed: 139 additions & 85 deletions

File tree

DeveLanCacheUI_Backend/DeveLanCacheUI_Backend.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.4" />
3232
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
3333
<PackageReference Include="Polly" Version="8.5.2" />
34-
<PackageReference Include="protobuf-net" Version="3.2.52" />
35-
<PackageReference Include="SteamKit2" Version="3.2.0" />
34+
<PackageReference Include="protobuf-net" Version="3.2.56" />
35+
<PackageReference Include="SteamKit2" Version="3.3.1" />
3636
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
3737
</ItemGroup>
3838

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
namespace DeveLanCacheUI_Backend.Helpers
2+
{
3+
/// <summary>
4+
/// Simple helper to download remote files. If the url ends with .gz it will stream-decompress and return the raw bytes.
5+
/// Keeps implementation minimal and self-contained.
6+
/// </summary>
7+
public static class RemoteFileDownloader
8+
{
9+
public static async Task<byte[]> DownloadFileAsync(string url, CancellationToken cancellationToken = default)
10+
{
11+
using var httpClient = new HttpClient();
12+
httpClient.DefaultRequestHeaders.Add("User-Agent", "request");
13+
14+
var rawBytes = await httpClient.GetByteArrayAsync(url, cancellationToken);
15+
if (url.EndsWith(".gz", StringComparison.OrdinalIgnoreCase))
16+
{
17+
using var inputMs = new MemoryStream(rawBytes);
18+
using var gzip = new GZipStream(inputMs, CompressionMode.Decompress);
19+
using var outputMs = new MemoryStream();
20+
await gzip.CopyToAsync(outputMs, cancellationToken);
21+
return outputMs.ToArray();
22+
}
23+
return rawBytes;
24+
}
25+
26+
/// <summary>
27+
/// Downloads a specific asset from the latest GitHub release for the given owner/repo.
28+
/// If the primary asset name is not found, optional alternate names will be tried in order.
29+
/// Automatically decompresses .gz assets.
30+
/// </summary>
31+
public static async Task<byte[]> DownloadGithubLatestReleaseAssetAsync(
32+
string owner,
33+
string repo,
34+
string assetName,
35+
CancellationToken cancellationToken = default)
36+
{
37+
var releaseUrl = $"https://api.github.com/repos/{owner}/{repo}/releases/latest";
38+
using var httpClient = new HttpClient();
39+
httpClient.DefaultRequestHeaders.Add("User-Agent", "request");
40+
41+
var latestJson = await httpClient.GetStringAsync(releaseUrl, cancellationToken);
42+
var release = JsonSerializer.Deserialize<DeveLanCacheUI_Backend.Services.OriginalDepotEnricher.Models.GithubLatestApiPoco>(latestJson);
43+
if (release == null)
44+
{
45+
throw new InvalidOperationException($"Could not deserialize latest release for {owner}/{repo}");
46+
}
47+
48+
var asset = release.assets.FirstOrDefault(a => string.Equals(a.name, assetName, StringComparison.OrdinalIgnoreCase));
49+
if (asset == null)
50+
{
51+
throw new FileNotFoundException($"Asset '{assetName}' not found in latest release for {owner}/{repo}");
52+
}
53+
54+
// Reuse existing download + auto .gz logic
55+
return await DownloadFileAsync(asset.browser_download_url, cancellationToken);
56+
}
57+
}
58+
}

DeveLanCacheUI_Backend/Services/OriginalDepotEnricher/SteamApi.cs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,68 @@ public static class SteamApi
1010

1111
private static SteamApiData LoadSteamApiData()
1212
{
13-
using var c = new HttpClient();
14-
var result = c.GetAsync("https://api.steampowered.com/ISteamApps/GetAppList/v2/").Result;
15-
var resultString = result.Content.ReadAsStringAsync().Result;
13+
// Pull steam-applist.json(.gz) from latest GitHub release (Steam GetAppList endpoint broken).
14+
var bytes = RemoteFileDownloader.DownloadGithubLatestReleaseAssetAsync(
15+
owner: "devedse",
16+
repo: "DeveLanCacheUI_SteamDepotFinder_Runner",
17+
assetName: "steam-applist.json.gz",
18+
cancellationToken: CancellationToken.None
19+
).Result;
1620

17-
var retval = JsonSerializer.Deserialize<SteamApiData>(resultString);
21+
var resultString = Encoding.UTF8.GetString(bytes);
22+
23+
// Deserialize from GitHub format
24+
var githubData = JsonSerializer.Deserialize<GitHubSteamApiData>(resultString);
25+
26+
if (githubData?.response?.apps == null)
27+
{
28+
throw new FileNotFoundException("Could not download / parse / find the steam-applist.json.gz file from DeveLanCacheUI_SteamDepotFinder_Runner");
29+
}
30+
31+
// Convert to original SteamApiData format
32+
var retval = new SteamApiData
33+
{
34+
applist = new Applist
35+
{
36+
apps = githubData.response.apps
37+
.Select(a => new App { appid = a.appid, name = a.name })
38+
.DistinctBy(t => t.appid)
39+
.ToArray()
40+
}
41+
};
42+
43+
return retval;
44+
45+
// OLD FALLBACK (commented out intentionally):
46+
// using var c = new HttpClient();
47+
// var result = c.GetAsync("https://api.steampowered.com/ISteamApps/GetAppList/v2/").Result;
48+
// var resultString = result.Content.ReadAsStringAsync().Result;
49+
// var retval = JsonSerializer.Deserialize<SteamApiData>(resultString) ?? new SteamApiData { applist = new Applist { apps = Array.Empty<App>() } };
50+
// retval.applist.apps = retval.applist.apps.DistinctBy(t => t.appid).ToArray();
51+
// return retval;
52+
}
1853

19-
//There was one person with an issue where one appid was added as a duplicate???, no idea how but this seems to be a bug in the steam api.
20-
//I'm just going to distinct on it
21-
retval.applist.apps = retval.applist.apps.DistinctBy(t => t.appid).ToArray();
2254

23-
return retval;
55+
56+
57+
58+
// Classes for deserializing from GitHub release JSON format
59+
private class GitHubSteamApiData
60+
{
61+
public GitHubSteamResponse response { get; set; }
62+
}
63+
64+
private class GitHubSteamResponse
65+
{
66+
public GitHubSteamApp[] apps { get; set; }
67+
}
68+
69+
private class GitHubSteamApp
70+
{
71+
public uint appid { get; set; }
72+
public string name { get; set; }
73+
public long last_modified { get; set; }
74+
public long price_change_number { get; set; }
2475
}
2576
}
2677
}

DeveLanCacheUI_Backend/Services/OriginalDepotEnricher/SteamDepotDownloaderHostedService.cs

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,35 +62,16 @@ private async Task GoRun(CancellationToken stoppingToken)
6262
{
6363
throw new UnreachableException($"New version available, but LatestVersion or DownloadUrl is null. This should not happen. LatestVersion: {shouldDownload.LatestVersion}, DownloadUrl: {shouldDownload.DownloadUrl}");
6464
}
65-
var downloadedBytes = await GoDownload(depotFileDirectory, shouldDownload);
6665

67-
if (downloadedBytes != null)
68-
{
69-
await _steamDepotEnricherHostedService.GoProcess(shouldDownload.LatestVersion, downloadedBytes, stoppingToken);
70-
}
71-
else
72-
{
73-
_logger.LogWarning("Downloaded depot file was null, not processing further.");
74-
}
75-
}
66+
_logger.LogInformation("Detected that new version '{LatestVersion}' of Depot File is available, downloading: {DownloadUrl}...", shouldDownload.LatestVersion, shouldDownload.DownloadUrl);
7667

77-
await Task.Delay(TimeSpan.FromHours(1));
78-
}
79-
}
68+
var downloadedBytes = await RemoteFileDownloader.DownloadFileAsync(shouldDownload.DownloadUrl, stoppingToken);
8069

81-
private async Task<byte[]?> GoDownload(string depotFileDirectory, (bool NewVersionAvailable, Version? LatestVersion, string? DownloadUrl) shouldDownload)
82-
{
83-
_logger.LogInformation("Detected that new version '{NewVersionAvailable}' of Depot File is available, so downloading: {DownloadUrl}...", shouldDownload.NewVersionAvailable, shouldDownload.DownloadUrl);
70+
await _steamDepotEnricherHostedService.GoProcess(shouldDownload.LatestVersion, downloadedBytes, stoppingToken);
71+
}
8472

85-
var downloadedCsv = await _httpClient.GetAsync(shouldDownload.DownloadUrl);
86-
if (!downloadedCsv.IsSuccessStatusCode)
87-
{
88-
_logger.LogWarning("Could not obtain {Url}: {StatusCode}, {ReasonPhrase}", DeveLanCacheUISteamDepotFinderLatestUrl, downloadedCsv.StatusCode, downloadedCsv.ReasonPhrase);
89-
return null;
73+
await Task.Delay(TimeSpan.FromHours(1));
9074
}
91-
92-
var bytes = await downloadedCsv.Content.ReadAsByteArrayAsync();
93-
return bytes;
9475
}
9576

9677
private async Task<(bool NewVersionAvailable, Version? LatestVersion, string? DownloadUrl)> NewDepotFileAvailable()
@@ -120,13 +101,17 @@ private async Task GoRun(CancellationToken stoppingToken)
120101
return (false, null, null);
121102
}
122103

123-
var downloadUrl = dataParsed.assets.FirstOrDefault(t => t.browser_download_url.EndsWith(".csv", StringComparison.OrdinalIgnoreCase))?.browser_download_url;
124-
if (downloadUrl == null)
104+
var asset = dataParsed.assets?.FirstOrDefault(a => a.name == "app-depot-output-cleaned.csv.gz")
105+
?? dataParsed.assets?.FirstOrDefault(a => a.name == "app-depot-output-cleaned.csv");
106+
107+
if (asset == null || string.IsNullOrWhiteSpace(asset.browser_download_url))
125108
{
126-
_logger.LogWarning("Could not find download url in: {Data}", data);
109+
_logger.LogWarning("Could not find app-depot-output-cleaned.csv.gz or .csv in release assets");
127110
return (false, null, null);
128111
}
129112

113+
var downloadUrl = asset.browser_download_url;
114+
130115
await using (var scope = Services.CreateAsyncScope())
131116
{
132117
using var dbContext = scope.ServiceProvider.GetRequiredService<DeveLanCacheUIDbContext>();

DeveLanCacheUI_Backend/Steam/AppInfoHandler.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,15 @@ public async Task<List<App>> EnsureAppsAreLoaded()
3232
{
3333
_logger.LogInformation("Retrieving all known AppIds");
3434

35-
using var steamAppsApi = _steam3Session.Configuration.GetAsyncWebAPIInterface("ISteamApps");
36-
var response = await steamAppsApi.CallAsync(HttpMethod.Get, "GetAppList", 2);
35+
// Old live API call (broken) replaced by local cached SteamApi data from GitHub release.
36+
//using var steamAppsApi = _steam3Session.Configuration.GetAsyncWebAPIInterface("ISteamApps");
37+
//var response = await steamAppsApi.CallAsync(HttpMethod.Get, "GetAppList", 2);
3738

38-
var apiApps = response["apps"].Children.Select(app =>
39-
new App()
40-
{
41-
appid = app["appid"].AsUnsignedInteger(),
42-
name = app["name"].AsString() ?? "Unknown"
43-
}
44-
).ToList();
39+
var apiApps = SteamApi.SteamApiData.applist.apps.Select(app => new App
40+
{
41+
appid = app.appid,
42+
name = string.IsNullOrWhiteSpace(app.name) ? "Unknown" : app.name
43+
}).ToList();
4544

4645
_cachedAppNames = apiApps.DistinctBy(t => t.appid).ToDictionary(t => t.appid, t => t);
4746

DeveLanCacheUI_Backend/Steam/SteamAppApi/SteamApi.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)