Use steamcmd.net for app info, remove extra Steam cmdlets
This commit is contained in:
parent
303f8720f4
commit
322f05cb26
47 changed files with 1333 additions and 511 deletions
|
|
@ -116,6 +116,7 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.7.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Localization" Version="9.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
---
|
||||
.---
|
||||
title: Cmdlets
|
||||
---
|
||||
|
||||
|
|
@ -222,9 +222,9 @@ Update-UserCustomField -Name "SteamId" -Value "34950494"
|
|||
|
||||
The following cmdlets provide functionality for interacting with SteamCMD and the Steam Store API. These cmdlets enable you to install Steam games, manage SteamCMD profiles, search for games, and retrieve Steam assets.
|
||||
|
||||
## Connection Management
|
||||
# Connection Management
|
||||
|
||||
### `Connect-SteamCmd`
|
||||
## `Connect-SteamCmd`
|
||||
Connects to SteamCMD with the specified username and optional password.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -243,7 +243,7 @@ $securePassword = ConvertTo-SecureString "mypassword" -AsPlainText -Force
|
|||
Connect-SteamCmd -Username "myusername" -Password $securePassword
|
||||
```
|
||||
|
||||
### `Disconnect-SteamCmd`
|
||||
## `Disconnect-SteamCmd`
|
||||
Disconnects from SteamCMD for the specified username.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -260,7 +260,7 @@ The `Disconnect-SteamCmd` cmdlet logs out the specified username from SteamCMD.
|
|||
Disconnect-SteamCmd -Username "myusername"
|
||||
```
|
||||
|
||||
### `Get-SteamCmdConnectionStatus`
|
||||
## `Get-SteamCmdConnectionStatus`
|
||||
Gets the connection status for a SteamCMD username.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -278,9 +278,9 @@ $status = Get-SteamCmdConnectionStatus -Username "myusername"
|
|||
Write-Host "Connected: $($status.IsConnected)"
|
||||
```
|
||||
|
||||
## SteamCMD Configuration
|
||||
# SteamCMD Configuration
|
||||
|
||||
### `Get-SteamCmdPath`
|
||||
## `Get-SteamCmdPath`
|
||||
Gets the path to the SteamCMD executable.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -299,7 +299,7 @@ if ($steamCmdPath) {
|
|||
}
|
||||
```
|
||||
|
||||
### `Get-SteamCmdProfile`
|
||||
## `Get-SteamCmdProfile`
|
||||
Gets a SteamCMD profile for the specified username.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -319,7 +319,7 @@ if ($profile) {
|
|||
}
|
||||
```
|
||||
|
||||
### `Get-SteamCmdProfiles`
|
||||
## `Get-SteamCmdProfiles`
|
||||
Gets all SteamCMD profiles.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -338,7 +338,7 @@ foreach ($profile in $profiles) {
|
|||
}
|
||||
```
|
||||
|
||||
### `Set-SteamCmdProfile`
|
||||
## `Set-SteamCmdProfile`
|
||||
Creates or updates a SteamCMD profile.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -356,7 +356,7 @@ The `Set-SteamCmdProfile` cmdlet creates or updates a SteamCMD profile with the
|
|||
Set-SteamCmdProfile -Username "myusername" -InstallDirectory "C:\Steam\Content"
|
||||
```
|
||||
|
||||
### `Remove-SteamCmdProfile`
|
||||
## `Remove-SteamCmdProfile`
|
||||
Removes a SteamCMD profile.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -373,9 +373,9 @@ The `Remove-SteamCmdProfile` cmdlet deletes the SteamCMD profile for the specifi
|
|||
Remove-SteamCmdProfile -Username "myusername"
|
||||
```
|
||||
|
||||
## Content Installation
|
||||
# Steam Content Installation
|
||||
|
||||
### `Install-SteamContent`
|
||||
## `Install-SteamContent`
|
||||
Installs Steam content (game, DLC, etc.) using SteamCMD.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -395,7 +395,7 @@ $job = Install-SteamContent -AppId 730 -InstallDirectory "C:\Games\Counter-Strik
|
|||
Write-Host "Installation job started: $($job.Id)"
|
||||
```
|
||||
|
||||
### `Remove-SteamContent`
|
||||
## `Remove-SteamContent`
|
||||
Removes Steam content from the specified install directory.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -412,66 +412,9 @@ The `Remove-SteamContent` cmdlet removes Steam content from the specified instal
|
|||
Remove-SteamContent -InstallDirectory "C:\Games\Counter-Strike 2"
|
||||
```
|
||||
|
||||
### `Get-SteamInstallJob`
|
||||
Gets a Steam installation job by its ID.
|
||||
# Steam Store
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Get-SteamInstallJob
|
||||
-JobId <Guid>
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Get-SteamInstallJob` cmdlet retrieves information about a specific Steam installation job. Returns a `SteamCmdInstallJob` object containing status, progress, and other details about the installation.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$job = Get-SteamInstallJob -JobId "12345678-1234-1234-1234-123456789012"
|
||||
Write-Host "Status: $($job.Status), Progress: $($job.Progress)%"
|
||||
```
|
||||
|
||||
### `Get-SteamInstallJobs`
|
||||
Gets all active Steam installation jobs.
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Get-SteamInstallJobs
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Get-SteamInstallJobs` cmdlet retrieves all active Steam installation jobs. Returns a collection of `SteamCmdInstallJob` objects.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$jobs = Get-SteamInstallJobs
|
||||
foreach ($job in $jobs) {
|
||||
Write-Host "$($job.AppId): $($job.Status) - $($job.Progress)%"
|
||||
}
|
||||
```
|
||||
|
||||
### `Stop-SteamInstallJob`
|
||||
Stops a Steam installation job.
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Stop-SteamInstallJob
|
||||
-JobId <Guid>
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Stop-SteamInstallJob` cmdlet cancels a running Steam installation job. Returns a boolean indicating whether the job was successfully cancelled.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$cancelled = Stop-SteamInstallJob -JobId "12345678-1234-1234-1234-123456789012"
|
||||
if ($cancelled) {
|
||||
Write-Host "Installation job cancelled"
|
||||
}
|
||||
```
|
||||
|
||||
## Steam Store
|
||||
|
||||
### `Search-SteamGames`
|
||||
## `Search-SteamGames`
|
||||
Searches for games on the Steam Store.
|
||||
|
||||
### Syntax
|
||||
|
|
@ -491,67 +434,7 @@ foreach ($result in $results) {
|
|||
}
|
||||
```
|
||||
|
||||
### `Get-SteamManual`
|
||||
Downloads a game manual from the Steam Store.
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Get-SteamManual
|
||||
-AppId <int>
|
||||
-OutputPath <string> (optional)
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Get-SteamManual` cmdlet downloads the PDF manual for the specified Steam App ID. If `OutputPath` is provided, the manual is saved to that location and the path is returned. Otherwise, the manual data is returned as a byte array.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
# Save manual to file
|
||||
Get-SteamManual -AppId 730 -OutputPath "C:\Games\CS2\manual.pdf"
|
||||
|
||||
# Get manual as byte array
|
||||
$manualData = Get-SteamManual -AppId 730
|
||||
```
|
||||
|
||||
### `Get-SteamManualUri`
|
||||
Gets the URI for a game's manual on the Steam Store.
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Get-SteamManualUri
|
||||
-AppId <int>
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Get-SteamManualUri` cmdlet returns the URI where the manual for the specified Steam App ID can be accessed. Returns a `Uri` object.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$uri = Get-SteamManualUri -AppId 730
|
||||
Write-Host "Manual URL: $uri"
|
||||
```
|
||||
|
||||
### `Test-SteamManual`
|
||||
Tests whether a game has a manual available on the Steam Store.
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Test-SteamManual
|
||||
-AppId <int>
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Test-SteamManual` cmdlet checks if a manual exists for the specified Steam App ID. Returns a boolean indicating whether a manual is available.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$hasManual = Test-SteamManual -AppId 730
|
||||
if ($hasManual) {
|
||||
Write-Host "Manual available"
|
||||
}
|
||||
```
|
||||
|
||||
### `Get-SteamWebAssetUri`
|
||||
## `Get-SteamWebAssetUri`
|
||||
Gets the URI for a Steam web asset (logo, header, etc.).
|
||||
|
||||
### Syntax
|
||||
|
|
@ -580,23 +463,25 @@ $logoUri = Get-SteamWebAssetUri -AppId 730 -WebAssetType Logo
|
|||
Write-Host "Logo URL: $logoUri"
|
||||
```
|
||||
|
||||
### `Test-SteamWebAsset`
|
||||
Tests whether a Steam web asset exists for a game.
|
||||
## `Get-SteamAppInfo`
|
||||
Gets app details from the Steam Store (no API key required) and the **changenumber** (build ID) and last updated time from Steam via SteamKit2 (PICS).
|
||||
|
||||
### Syntax
|
||||
```powershell
|
||||
Test-SteamWebAsset
|
||||
-AppId <int>
|
||||
-WebAssetType <WebAssetType>
|
||||
Get-SteamAppInfo
|
||||
-AppId <uint>
|
||||
```
|
||||
|
||||
### Description
|
||||
The `Test-SteamWebAsset` cmdlet checks if a specific web asset type exists for the specified Steam App ID. Returns a boolean indicating whether the asset is available. The `WebAssetType` parameter accepts the same values as `Get-SteamWebAssetUri`.
|
||||
The `Get-SteamAppInfo` cmdlet returns a `SteamAppInfo` object with name, short description, release date, developers, publishers, and store URL from the public Steam Store `appdetails` endpoint. It also connects to Steam via SteamKit2 (PICS) to fill **LastChangenumber** and **LastUpdated** for the public branch—no Web API key required. If SteamKit2 cannot connect or the app cannot be queried, those two properties are null.
|
||||
|
||||
### Example
|
||||
```powershell
|
||||
$hasLogo = Test-SteamWebAsset -AppId 730 -WebAssetType Logo
|
||||
if ($hasLogo) {
|
||||
Write-Host "Logo available"
|
||||
$info = Get-SteamAppInfo -AppId 413150
|
||||
if ($info) {
|
||||
Write-Host "Name: $($info.Name)"
|
||||
Write-Host "Description: $($info.Description)"
|
||||
Write-Host "Release date: $($info.ReleaseDate)"
|
||||
Write-Host "Developer: $($info.Developer)"
|
||||
}
|
||||
```
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -7,51 +8,248 @@ namespace LANCommander.SDK.PowerShell;
|
|||
|
||||
/// <summary>
|
||||
/// Base class for PowerShell cmdlets that need to execute async code.
|
||||
/// Provides a ProcessRecordAsync method that can be overridden for async operations.
|
||||
/// Based on <see href="https://github.com/jborean93/PowerShell-OpenAuthenticode">PowerShell-OpenAuthenticode</see> AsyncPSCmdlet.
|
||||
/// Override BeginProcessingAsync, ProcessRecordAsync, and/or EndProcessingAsync; WriteObject, WriteError, etc.
|
||||
/// can be called from async code and are marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public abstract class AsyncCmdlet : PSCmdlet
|
||||
public abstract class AsyncCmdlet : PSCmdlet, IDisposable
|
||||
{
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private enum PipelineType
|
||||
{
|
||||
Output,
|
||||
OutputEnumerate,
|
||||
Error,
|
||||
Warning,
|
||||
Verbose,
|
||||
Debug,
|
||||
Information,
|
||||
Progress,
|
||||
ShouldProcess,
|
||||
}
|
||||
|
||||
private readonly CancellationTokenSource _cancelSource = new();
|
||||
private BlockingCollection<(object?, PipelineType)>? _currentOutPipe;
|
||||
private BlockingCollection<object?>? _currentReplyPipe;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cancellation token for the current operation.
|
||||
/// Gets the cancellation token for the current operation. Canceled when the cmdlet is stopped.
|
||||
/// </summary>
|
||||
protected CancellationToken CancellationToken => _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||
protected CancellationToken CancellationToken => _cancelSource.Token;
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to implement async record processing.
|
||||
/// Override to perform async startup. Default implementation returns a completed task.
|
||||
/// </summary>
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
SessionState.PSVariable.Set("LANCommander.SDK.PSHostUI", Host.UI);
|
||||
RunBlockInAsync(BeginProcessingAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to perform async startup.
|
||||
/// </summary>
|
||||
protected virtual Task BeginProcessingAsync() => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Processes a single record by running ProcessRecordAsync and consuming pipeline output on the pipeline thread.
|
||||
/// </summary>
|
||||
protected override void ProcessRecord() => RunBlockInAsync(() => ProcessRecordAsync(CancellationToken));
|
||||
|
||||
/// <summary>
|
||||
/// Override to implement async record processing.
|
||||
/// </summary>
|
||||
protected abstract Task ProcessRecordAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Processes a single record synchronously by calling the async ProcessRecordAsync method.
|
||||
/// Override to perform async cleanup. Default implementation returns a completed task.
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
protected override void EndProcessing() => RunBlockInAsync(EndProcessingAsync);
|
||||
|
||||
/// <summary>
|
||||
/// Override to perform async cleanup.
|
||||
/// </summary>
|
||||
protected virtual Task EndProcessingAsync() => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the cmdlet is stopping. Cancels the cancellation token.
|
||||
/// </summary>
|
||||
protected override void StopProcessing()
|
||||
{
|
||||
_cancelSource.Cancel();
|
||||
base.StopProcessing();
|
||||
}
|
||||
|
||||
private void RunBlockInAsync(Func<Task> task)
|
||||
{
|
||||
using var outPipe = new BlockingCollection<(object?, PipelineType)>();
|
||||
using var replyPipe = new BlockingCollection<object?>();
|
||||
var blockTask = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_currentOutPipe = outPipe;
|
||||
_currentReplyPipe = replyPipe;
|
||||
await task();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentOutPipe = null;
|
||||
_currentReplyPipe = null;
|
||||
outPipe.CompleteAdding();
|
||||
replyPipe.CompleteAdding();
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
// Expose host UI in session state so application loggers can write to the PowerShell runtime
|
||||
SessionState.PSVariable.Set("LANCommander.SDK.PSHostUI", Host.UI);
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
ProcessRecordAsync(_cancellationTokenSource.Token).GetAwaiter().GetResult();
|
||||
foreach (var (data, pipelineType) in outPipe.GetConsumingEnumerable(_cancelSource.Token))
|
||||
{
|
||||
switch (pipelineType)
|
||||
{
|
||||
case PipelineType.Output:
|
||||
base.WriteObject(data);
|
||||
break;
|
||||
case PipelineType.OutputEnumerate:
|
||||
base.WriteObject(data, true);
|
||||
break;
|
||||
case PipelineType.Error:
|
||||
base.WriteError((ErrorRecord)data!);
|
||||
break;
|
||||
case PipelineType.Warning:
|
||||
base.WriteWarning((string)data!);
|
||||
break;
|
||||
case PipelineType.Verbose:
|
||||
base.WriteVerbose((string)data!);
|
||||
break;
|
||||
case PipelineType.Debug:
|
||||
base.WriteDebug((string)data!);
|
||||
break;
|
||||
case PipelineType.Information:
|
||||
base.WriteInformation((InformationRecord)data!);
|
||||
break;
|
||||
case PipelineType.Progress:
|
||||
base.WriteProgress((ProgressRecord)data!);
|
||||
break;
|
||||
case PipelineType.ShouldProcess:
|
||||
var (target, action) = (ValueTuple<string, string>)data!;
|
||||
var res = base.ShouldProcess(target, action);
|
||||
replyPipe.Add(res, _cancelSource.Token);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Expected when StopProcessing cancels
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
blockTask.GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "ProcessRecordError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
base.WriteError(new ErrorRecord(ex, "ProcessRecordError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the cmdlet is stopping.
|
||||
/// Writes an object to the pipeline. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
protected override void StopProcessing()
|
||||
public new void WriteObject(object? sendToPipeline) => WriteObject(sendToPipeline, false);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an object to the pipeline. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteObject(object? sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
base.StopProcessing();
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((sendToPipeline, enumerateCollection ? PipelineType.OutputEnumerate : PipelineType.Output));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an error record. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteError(ErrorRecord errorRecord)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((errorRecord, PipelineType.Error));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a warning. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteWarning(string message)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((message, PipelineType.Warning));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes verbose output. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteVerbose(string message)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((message, PipelineType.Verbose));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes debug output. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteDebug(string message)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((message, PipelineType.Debug));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an information record. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteInformation(InformationRecord informationRecord)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((informationRecord, PipelineType.Information));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a progress record. Safe to call from async code; marshalled to the pipeline thread.
|
||||
/// </summary>
|
||||
public new void WriteProgress(ProgressRecord progressRecord)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add((progressRecord, PipelineType.Progress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Confirms an operation with the user. Safe to call from async code; blocks until the pipeline thread returns the result.
|
||||
/// </summary>
|
||||
public new bool ShouldProcess(string target, string action)
|
||||
{
|
||||
ThrowIfStopped();
|
||||
_currentOutPipe?.Add(((target, action), PipelineType.ShouldProcess));
|
||||
return (bool)_currentReplyPipe?.Take(CancellationToken)!;
|
||||
}
|
||||
|
||||
private void ThrowIfStopped()
|
||||
{
|
||||
if (_cancelSource.IsCancellationRequested)
|
||||
throw new PipelineStoppedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the cancellation source.
|
||||
/// </summary>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
_cancelSource.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
35
LANCommander.SDK/PowerShell/Cmdlets/Get-SteamAppInfo.cs
Normal file
35
LANCommander.SDK/PowerShell/Cmdlets/Get-SteamAppInfo.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "SteamAppInfo")]
|
||||
[OutputType(typeof(AppInfo))]
|
||||
public class GetSteamAppInfoCmdlet : AsyncCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
[ValidateRange(1u, uint.MaxValue)]
|
||||
public uint AppId { get; set; }
|
||||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var steamStoreService = SteamServicesProvider.GetSteamWebApiService(SessionState);
|
||||
|
||||
try
|
||||
{
|
||||
var info = await steamStoreService.GetAppInfo(AppId);
|
||||
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
WriteObject(info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "SteamAppInfoError", ErrorCategory.OperationStopped, AppId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Services;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "SteamManual")]
|
||||
[OutputType(typeof(byte[]))]
|
||||
public class GetSteamManualCmdlet : AsyncCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public int AppId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? OutputPath { get; set; }
|
||||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var steamStoreService = SteamServicesProvider.GetSteamStoreService(SessionState);
|
||||
|
||||
try
|
||||
{
|
||||
var manualData = await steamStoreService.DownloadManualAsync(AppId);
|
||||
|
||||
if (manualData == null || manualData.Length == 0)
|
||||
{
|
||||
WriteWarning($"No manual found for App ID {AppId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(OutputPath))
|
||||
{
|
||||
await File.WriteAllBytesAsync(OutputPath, manualData, cancellationToken);
|
||||
WriteObject(OutputPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteObject(manualData);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "DownloadManualError", ErrorCategory.OperationStopped, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Services;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "SteamManualUri")]
|
||||
[OutputType(typeof(Uri))]
|
||||
public class GetSteamManualUriCmdlet : AsyncCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public int AppId { get; set; }
|
||||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var uri = SteamStoreService.GetManualUri(AppId);
|
||||
WriteObject(uri);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetManualUriError", ErrorCategory.OperationStopped, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ public class GetSteamWebAssetUriCmdlet : AsyncCmdlet
|
|||
{
|
||||
try
|
||||
{
|
||||
var uri = SteamStoreService.GetWebAssetUri(AppId, WebAssetType);
|
||||
var uri = SteamWebApiService.GetWebAssetUri(AppId, WebAssetType);
|
||||
WriteObject(uri);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class SearchSteamGamesCmdlet : AsyncCmdlet
|
|||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var steamStoreService = SteamServicesProvider.GetSteamStoreService(SessionState);
|
||||
var steamStoreService = SteamServicesProvider.GetSteamWebApiService(SessionState);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Services;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
[Cmdlet(VerbsDiagnostic.Test, "SteamManual")]
|
||||
[OutputType(typeof(bool))]
|
||||
public class TestSteamManualCmdlet : AsyncCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public int AppId { get; set; }
|
||||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var steamStoreService = SteamServicesProvider.GetSteamStoreService(SessionState);
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await steamStoreService.HasManualAsync(AppId);
|
||||
WriteObject(exists);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "HasManualError", ErrorCategory.OperationStopped, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam;
|
||||
using LANCommander.Steam.Services;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
[Cmdlet(VerbsDiagnostic.Test, "SteamWebAsset")]
|
||||
[OutputType(typeof(bool))]
|
||||
public class TestSteamWebAssetCmdlet : AsyncCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public int AppId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
public WebAssetType WebAssetType { get; set; }
|
||||
|
||||
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var steamStoreService = SteamServicesProvider.GetSteamStoreService(SessionState);
|
||||
|
||||
try
|
||||
{
|
||||
var (exists, _) = await steamStoreService.HasWebAssetAsync(AppId, WebAssetType);
|
||||
WriteObject(exists);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "HasWebAssetError", ErrorCategory.OperationStopped, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Reflection;
|
||||
using LANCommander.SDK.PowerShell.Cmdlets;
|
||||
|
||||
namespace LANCommander.SDK.PowerShell.Extensions;
|
||||
|
|
@ -28,7 +24,6 @@ public static class InitialSessionStateExtensions
|
|||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Write-GameManifest", typeof(WriteGameManifestCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Write-ReplaceContentInFile", typeof(ReplaceContentInFileCmdlet), null));
|
||||
|
||||
// SteamCMD cmdlets
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Connect-SteamCmd", typeof(ConnectSteamCmdCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Disconnect-SteamCmd", typeof(DisconnectSteamCmdCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-SteamCmdConnectionStatus", typeof(GetSteamCmdConnectionStatusCmdlet), null));
|
||||
|
|
@ -39,13 +34,8 @@ public static class InitialSessionStateExtensions
|
|||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Remove-SteamContent", typeof(RemoveSteamContentCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Remove-SteamCmdProfile", typeof(RemoveSteamCmdProfileCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Set-SteamCmdProfile", typeof(SetSteamCmdProfileCmdlet), null));
|
||||
|
||||
// Steam Store cmdlets
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-SteamManual", typeof(GetSteamManualCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-SteamManualUri", typeof(GetSteamManualUriCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-SteamAppInfo", typeof(GetSteamAppInfoCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-SteamWebAssetUri", typeof(GetSteamWebAssetUriCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Search-SteamGames", typeof(SearchSteamGamesCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Test-SteamManual", typeof(TestSteamManualCmdlet), null));
|
||||
initialSessionState.Commands.Add(new SessionStateCmdletEntry("Test-SteamWebAsset", typeof(TestSteamWebAssetCmdlet), null));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Net.Http;
|
||||
using LANCommander.Steam.Abstractions;
|
||||
using LANCommander.Steam.Options;
|
||||
using LANCommander.Steam.Services;
|
||||
|
|
@ -14,7 +15,7 @@ namespace LANCommander.SDK.PowerShell;
|
|||
public static class SteamServicesProvider
|
||||
{
|
||||
private const string SteamCmdServiceKey = "LANCommander.Steam.SteamCmdService";
|
||||
private const string SteamStoreServiceKey = "LANCommander.Steam.SteamStoreService";
|
||||
private const string SteamWebApiServiceKey = "LANCommander.Steam.SteamStoreService";
|
||||
private const string SettingsProviderKey = "LANCommander.SDK.ISettingsProvider";
|
||||
private const string PSHostUIKey = "LANCommander.SDK.PSHostUI";
|
||||
|
||||
|
|
@ -59,17 +60,19 @@ public static class SteamServicesProvider
|
|||
/// <summary>
|
||||
/// Gets or creates the Steam Store service for the current session.
|
||||
/// </summary>
|
||||
public static SteamStoreService GetSteamStoreService(SessionState sessionState)
|
||||
public static ISteamWebApiService GetSteamWebApiService(SessionState sessionState)
|
||||
{
|
||||
var existing = sessionState.PSVariable.GetValue(SteamStoreServiceKey) as SteamStoreService;
|
||||
var existing = sessionState.PSVariable.GetValue(SteamWebApiServiceKey) as SteamWebApiService;
|
||||
|
||||
if (existing != null)
|
||||
return existing;
|
||||
|
||||
var service = new SteamStoreService();
|
||||
var service = new SteamWebApiService(new HttpClient());
|
||||
|
||||
sessionState.PSVariable.Set(SteamStoreServiceKey, service);
|
||||
sessionState.PSVariable.Set(SteamWebApiServiceKey, service);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Enums;
|
||||
using LANCommander.Steam.Events;
|
||||
|
|
@ -17,6 +18,12 @@ public interface ISteamCmdService
|
|||
/// </summary>
|
||||
string? ExecutablePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get app info (changenumber / buildid and time updated) for the public branch via app_info_print.
|
||||
/// Requires SteamCMD to be installed and configured. Returns null if SteamCMD is unavailable or the app cannot be queried.
|
||||
/// </summary>
|
||||
Task<SteamCmdAppInfo?> GetAppInfoAsync(uint appId, System.Threading.CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when an install job status changes (started, completed, failed)
|
||||
/// </summary>
|
||||
|
|
|
|||
11
LANCommander.Steam/Abstractions/ISteamWebApiService.cs
Normal file
11
LANCommander.Steam/Abstractions/ISteamWebApiService.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
namespace LANCommander.Steam.Abstractions;
|
||||
|
||||
public interface ISteamWebApiService
|
||||
{
|
||||
public Task<AppInfo> GetAppInfo(uint appId);
|
||||
public Task<IEnumerable<GameSearchResult>> SearchGamesAsync(string keyword);
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ public static class ServiceCollectionExtensions
|
|||
sp.GetService<IOptions<SteamCmdOptions>>()?.Value,
|
||||
sp.GetService<ISteamCmdProfileStore>(),
|
||||
sp.GetService<ILogger<SteamCmdService>>()));
|
||||
services.AddSingleton<ISteamWebApiService, SteamWebApiService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
@ -60,6 +61,7 @@ public static class ServiceCollectionExtensions
|
|||
sp.GetService<IOptions<SteamCmdOptions>>()?.Value,
|
||||
sp.GetService<ISteamCmdProfileStore>(),
|
||||
sp.GetService<ILogger<SteamCmdService>>()));
|
||||
services.AddSingleton<ISteamWebApiService, SteamWebApiService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
@ -86,6 +88,7 @@ public static class ServiceCollectionExtensions
|
|||
sp.GetService<IOptions<SteamCmdOptions>>()?.Value,
|
||||
sp.GetService<ISteamCmdProfileStore>(),
|
||||
sp.GetService<ILogger<SteamCmdService>>()));
|
||||
services.AddSingleton<ISteamWebApiService, SteamWebApiService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
namespace LANCommander.Steam;
|
||||
|
||||
namespace LANCommander.Steam
|
||||
public class GameSearchResult
|
||||
{
|
||||
public class GameSearchResult
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int AppId { get; set; }
|
||||
}
|
||||
}
|
||||
public string Name { get; set; }
|
||||
public int AppId { get; set; }
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
|
|
|
|||
24
LANCommander.Steam/Models/SteamCmdAppInfo.cs
Normal file
24
LANCommander.Steam/Models/SteamCmdAppInfo.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace LANCommander.Steam.Models;
|
||||
|
||||
/// <summary>
|
||||
/// App info from SteamCMD (app_info_print): changenumber (buildid) and last updated time for the public branch.
|
||||
/// </summary>
|
||||
public class SteamCmdAppInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam application ID.
|
||||
/// </summary>
|
||||
public uint AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Build ID / changenumber for the public branch.
|
||||
/// </summary>
|
||||
public string? Changenumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the public branch was last updated (Unix timestamp from SteamCMD).
|
||||
/// </summary>
|
||||
public DateTimeOffset? TimeUpdated { get; set; }
|
||||
}
|
||||
12
LANCommander.Steam/Models/SteamCmdNet/AppAssociation.cs
Normal file
12
LANCommander.Steam/Models/SteamCmdNet/AppAssociation.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppAssociation
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
148
LANCommander.Steam/Models/SteamCmdNet/AppCommon.cs
Normal file
148
LANCommander.Steam/Models/SteamCmdNet/AppCommon.cs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public class AppCommon
|
||||
{
|
||||
[JsonPropertyName("associations")]
|
||||
public Dictionary<string, AppAssociation>? Associations { get; set; }
|
||||
|
||||
[JsonPropertyName("category")]
|
||||
public Dictionary<string, string>? Category { get; set; }
|
||||
|
||||
[JsonPropertyName("clienticns")]
|
||||
public string? ClientIcons { get; set; }
|
||||
|
||||
[JsonPropertyName("clienticon")]
|
||||
public string? ClientIcon { get; set; }
|
||||
|
||||
[JsonPropertyName("clienttga")]
|
||||
public string? ClientTGA { get; set; }
|
||||
|
||||
[JsonPropertyName("community_hub_visible")]
|
||||
public string? CommunityHubVisible { get; set; }
|
||||
|
||||
[JsonPropertyName("community_visible_stats")]
|
||||
public string? CommunityVisibleStats { get; set; }
|
||||
|
||||
[JsonPropertyName("content_descriptors")]
|
||||
public Dictionary<string, string>? ContentDescriptors { get; set; }
|
||||
|
||||
[JsonPropertyName("content_descriptors_including_dlc")]
|
||||
public Dictionary<string, string>? ContentDescriptorsIncludingDLC { get; set; }
|
||||
|
||||
[JsonPropertyName("controllertagwizard")]
|
||||
public string? ControllerTagWizard { get; set; }
|
||||
|
||||
[JsonPropertyName("exfgls")]
|
||||
public string? Exfgls { get; set; }
|
||||
|
||||
[JsonPropertyName("gameid")]
|
||||
public string? GameId { get; set; }
|
||||
|
||||
[JsonPropertyName("genres")]
|
||||
public Dictionary<string, string>? Genres { get; set; }
|
||||
|
||||
[JsonPropertyName("header_image")]
|
||||
public LocalizedImageMap? HeaderImageMap { get; set; }
|
||||
|
||||
[JsonPropertyName("icon")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
[JsonPropertyName("languages")]
|
||||
public Dictionary<string, string>? Languages { get; set; }
|
||||
|
||||
[JsonPropertyName("library_assets")]
|
||||
public LibraryAssets? LibraryAssets { get; set; }
|
||||
|
||||
[JsonPropertyName("library_assets_null")]
|
||||
public LibraryAssetsFull? LibraryAssetsFull { get; set; }
|
||||
|
||||
[JsonPropertyName("linuxclienticon")]
|
||||
public string? LinuxClientIcon { get; set; }
|
||||
|
||||
[JsonPropertyName("logo")]
|
||||
public string? Logo { get; set; }
|
||||
|
||||
[JsonPropertyName("logo_small")]
|
||||
public string? LogoSmall { get; set; }
|
||||
|
||||
[JsonPropertyName("market_presence")]
|
||||
public string? MarketPresence { get; set; }
|
||||
|
||||
[JsonPropertyName("metacritic_name")]
|
||||
public string? MetacriticName { get; set; }
|
||||
|
||||
[JsonPropertyName("metacritic_score")]
|
||||
public int? MetacriticScore { get; set; }
|
||||
|
||||
[JsonPropertyName("metacritic_url")]
|
||||
public string? MetacriticUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("metacritic_fullurl")]
|
||||
public string? MetacriticFullUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonPropertyName("name_localized")]
|
||||
public Dictionary<string, string>? NameLocalized { get; set; }
|
||||
|
||||
[JsonPropertyName("osarch")]
|
||||
public string? OperatingSystemArchitecture { get; set; }
|
||||
|
||||
[JsonPropertyName("osextended")]
|
||||
public string? OperatingSystemExtended { get; set; }
|
||||
|
||||
[JsonPropertyName("oslist")]
|
||||
public string? OperatingSystemList { get; set; }
|
||||
|
||||
[JsonPropertyName("original_release_date")]
|
||||
public long? OriginalReleaseDate { get; set; }
|
||||
|
||||
[JsonPropertyName("primary_genre")]
|
||||
public int? PrimaryGenre { get; set; }
|
||||
|
||||
[JsonPropertyName("releasestatesteamchina")]
|
||||
public string? ReleaseStateSteamChina { get; set; }
|
||||
|
||||
[JsonPropertyName("review_percentage")]
|
||||
public int? ReviewPercentage { get; set; }
|
||||
|
||||
[JsonPropertyName("review_score")]
|
||||
public int? ReviewScore { get; set; }
|
||||
|
||||
[JsonPropertyName("small_capsule")]
|
||||
public LocalizedImageMap? SmallCapsule { get; set; }
|
||||
|
||||
[JsonPropertyName("steam_deck_compatibility")]
|
||||
public string? SteamDeckCompatibility { get; set; }
|
||||
|
||||
[JsonPropertyName("steam_release_date")]
|
||||
public string? SteamReleaseDate { get; set; }
|
||||
|
||||
[JsonPropertyName("steamchinaapproved")]
|
||||
public string? SteamChinaApproved { get; set; }
|
||||
|
||||
[JsonPropertyName("store_asset_mtime")]
|
||||
public string? StoreAssetMTime { get; set; }
|
||||
|
||||
[JsonPropertyName("store_tags")]
|
||||
public Dictionary<string, string>? StoreTags { get; set; }
|
||||
|
||||
[JsonPropertyName("supported_languages")]
|
||||
public Dictionary<string, string>? SupportedLanguages { get; set; }
|
||||
|
||||
[JsonPropertyName("timeline_marker_svg")]
|
||||
public string? TimelineMarkerSvg { get; set; }
|
||||
|
||||
[JsonPropertyName("timeline_marker_updated")]
|
||||
public string? TimelineMarkerUpdated { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
[JsonPropertyName("workshop_visible")]
|
||||
public string? WorkshopVisible { get; set; }
|
||||
}
|
||||
133
LANCommander.Steam/Models/SteamCmdNet/AppConfig.cs
Normal file
133
LANCommander.Steam/Models/SteamCmdNet/AppConfig.cs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppConfig
|
||||
{
|
||||
[JsonPropertyName("app_mappings")]
|
||||
public Dictionary<string, AppMapping>? AppMappings { get; set; }
|
||||
|
||||
[JsonPropertyName("cegpublickey")]
|
||||
public string? CegPublicKey { get; set; }
|
||||
|
||||
[JsonPropertyName("checkforupdatesbeforelaunch")]
|
||||
public string? CheckForUpdatesBeforeLaunch { get; set; }
|
||||
|
||||
[JsonPropertyName("checkguid")]
|
||||
public string? CheckGuid { get; set; }
|
||||
|
||||
[JsonPropertyName("contenttype")]
|
||||
public string? ContentType { get; set; }
|
||||
|
||||
[JsonPropertyName("duration_control_show_interstitial")]
|
||||
public string? DurationControlShowInterstitial { get; set; }
|
||||
|
||||
[JsonPropertyName("enable_duration_control")]
|
||||
public string? EnableDurationControl { get; set; }
|
||||
|
||||
[JsonPropertyName("enabletextfiltering")]
|
||||
public string? EnableTextFiltering { get; set; }
|
||||
|
||||
[JsonPropertyName("externalarguments")]
|
||||
public ExternalArguments? ExternalArguments { get; set; }
|
||||
|
||||
[JsonPropertyName("gameoverlay_testmode")]
|
||||
public string? GameOverlayTestMode { get; set; }
|
||||
|
||||
[JsonPropertyName("installdir")]
|
||||
public string? InstallDirectory { get; set; }
|
||||
|
||||
[JsonPropertyName("installscriptoverride")]
|
||||
public string? InstallScriptOverride { get; set; }
|
||||
|
||||
[JsonPropertyName("installscriptsignature")]
|
||||
public string? InstallScriptSignature { get; set; }
|
||||
|
||||
[JsonPropertyName("launch")]
|
||||
public Dictionary<string, LaunchEntry>? Launch { get; set; }
|
||||
|
||||
[JsonPropertyName("launchwithoutworkshopupdates")]
|
||||
public string? LaunchWithoutWorkshopUpdates { get; set; }
|
||||
|
||||
[JsonPropertyName("matchmaking_mms_appidinvitenf")]
|
||||
public string? MatchmakingMmsAppIdInviteNf { get; set; }
|
||||
|
||||
[JsonPropertyName("matchmaking_rate_limit")]
|
||||
public string? MatchmakingRateLimit { get; set; }
|
||||
|
||||
[JsonPropertyName("matchmaking_uptodate")]
|
||||
public string? MatchmakingUpToDate { get; set; }
|
||||
|
||||
[JsonPropertyName("sdr-groups")]
|
||||
public string? SdrGroups { get; set; }
|
||||
|
||||
[JsonPropertyName("sdr-groups-global")]
|
||||
public string? SdrGroupsGlobal { get; set; }
|
||||
|
||||
[JsonPropertyName("signaturescheckedonlaunch")]
|
||||
public Dictionary<string, Dictionary<string, string>>? SignaturesCheckedOnLaunch { get; set; }
|
||||
|
||||
[JsonPropertyName("signedfiles")]
|
||||
public Dictionary<string, string>? SignedFiles { get; set; }
|
||||
|
||||
[JsonPropertyName("steam_china_only")]
|
||||
public Dictionary<string, string>? SteamChinaOnly { get; set; }
|
||||
|
||||
[JsonPropertyName("steamconfigurator3rdpartynative")]
|
||||
public string? SteamConfigurator3rdPartyNative { get; set; }
|
||||
|
||||
[JsonPropertyName("steamcontrollertemplateindex")]
|
||||
public string? SteamControllerTemplateIndex { get; set; }
|
||||
|
||||
[JsonPropertyName("steamdecktouchscreen")]
|
||||
public string? SteamDeckTouchscreen { get; set; }
|
||||
|
||||
[JsonPropertyName("systemprofile")]
|
||||
public string? SystemProfile { get; set; }
|
||||
|
||||
[JsonPropertyName("uselaunchcommandline")]
|
||||
public string? UseLaunchCommandLine { get; set; }
|
||||
|
||||
[JsonPropertyName("usemms")]
|
||||
public string? UseMms { get; set; }
|
||||
|
||||
[JsonPropertyName("usesfrenemies")]
|
||||
public string? UseSfrenemies { get; set; }
|
||||
|
||||
[JsonPropertyName("vacmodulefilename")]
|
||||
public string? VacModuleFileName { get; set; }
|
||||
|
||||
[JsonPropertyName("vacmodulefilename_macos")]
|
||||
public string? VacModuleFileNameMacos { get; set; }
|
||||
|
||||
[JsonPropertyName("verifyupdates")]
|
||||
public string? VerifyUpdates { get; set; }
|
||||
|
||||
[JsonPropertyName("depots")]
|
||||
public Dictionary<string, Depot>? Depots { get; set; }
|
||||
|
||||
[JsonPropertyName("appmanagesdlc")]
|
||||
public string? AppManagesDlc { get; set; }
|
||||
|
||||
[JsonPropertyName("baselanguages")]
|
||||
public string? BaseLanguages { get; set; }
|
||||
|
||||
[JsonPropertyName("branches")]
|
||||
public Dictionary<string, Branch>? Branches { get; set; }
|
||||
|
||||
[JsonPropertyName("depotdeltapatches")]
|
||||
public string? DepotDeltaPatches { get; set; }
|
||||
|
||||
[JsonPropertyName("hasdepotsindlc")]
|
||||
public string? HasDepotsInDlc { get; set; }
|
||||
|
||||
[JsonPropertyName("overridescddb")]
|
||||
public string? OverridesCddb { get; set; }
|
||||
|
||||
[JsonPropertyName("privatebranches")]
|
||||
public string? PrivateBranches { get; set; }
|
||||
|
||||
[JsonPropertyName("workshopdepot")]
|
||||
public string? WorkshopDepot { get; set; }
|
||||
}
|
||||
105
LANCommander.Steam/Models/SteamCmdNet/AppExtended.cs
Normal file
105
LANCommander.Steam/Models/SteamCmdNet/AppExtended.cs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppExtended
|
||||
{
|
||||
[JsonPropertyName("aliases")]
|
||||
public string? Aliases { get; set; }
|
||||
|
||||
[JsonPropertyName("developer")]
|
||||
public string? Developer { get; set; }
|
||||
|
||||
[JsonPropertyName("developer_url")]
|
||||
public string? DeveloperUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("dlcavailableonstore")]
|
||||
public string? DLCAvailableOnStore { get; set; }
|
||||
|
||||
[JsonPropertyName("gamedir")]
|
||||
public string? GameDirectory { get; set; }
|
||||
|
||||
[JsonPropertyName("gamemanualurl")]
|
||||
public string? GameManualUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("homepage")]
|
||||
public string? HomePage { get; set; }
|
||||
|
||||
[JsonPropertyName("icon")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
[JsonPropertyName("installscript")]
|
||||
public string? InstallScript { get; set; }
|
||||
|
||||
[JsonPropertyName("installscript_macos")]
|
||||
public string? InstallScriptMacOS { get; set; }
|
||||
|
||||
[JsonPropertyName("installscript_osx")]
|
||||
public string? InstallScriptOSX { get; set; }
|
||||
|
||||
[JsonPropertyName("isfreeapp")]
|
||||
public string? IsFreeApp { get; set; }
|
||||
|
||||
[JsonPropertyName("languages_macos")]
|
||||
public string? LanguagesMacOS { get; set; }
|
||||
|
||||
[JsonPropertyName("launcheula")]
|
||||
public string? LaunchEula { get; set; }
|
||||
|
||||
[JsonPropertyName("launchulamask")]
|
||||
public string? LaunchEulaMask { get; set; }
|
||||
|
||||
[JsonPropertyName("legacykeyregistrationmethod")]
|
||||
public string? LegacyKeyRegistrationMethod { get; set; }
|
||||
|
||||
[JsonPropertyName("legacykeyregistrylocation")]
|
||||
public string? LegacyKeyRegistryLocation { get; set; }
|
||||
|
||||
[JsonPropertyName("listofdlc")]
|
||||
public string? ListOfDLC { get; set; }
|
||||
|
||||
[JsonPropertyName("loadallbeforelaunch")]
|
||||
public string? LoadAllBeforeLaunch { get; set; }
|
||||
|
||||
[JsonPropertyName("minclientversion")]
|
||||
public string? MinimumClientVersion { get; set; }
|
||||
|
||||
[JsonPropertyName("minclientversion_pw_csgo")]
|
||||
public string? MinimumClientVersionPwCsgo { get; set; }
|
||||
|
||||
[JsonPropertyName("noservers")]
|
||||
public string? NoServers { get; set; }
|
||||
|
||||
[JsonPropertyName("order")]
|
||||
public int? Order { get; set; }
|
||||
|
||||
[JsonPropertyName("primarycache")]
|
||||
public long? PrimaryCache { get; set; }
|
||||
|
||||
[JsonPropertyName("primarycache_mac")]
|
||||
public long? PrimaryCacheMac { get; set; }
|
||||
|
||||
[JsonPropertyName("primarycache_macos")]
|
||||
public long? PrimaryCacheMacOS { get; set; }
|
||||
|
||||
[JsonPropertyName("publisher")]
|
||||
public string? Publisher { get; set; }
|
||||
|
||||
[JsonPropertyName("serverbrowsername")]
|
||||
public string? ServerBrowserName { get; set; }
|
||||
|
||||
[JsonPropertyName("state")]
|
||||
public string? State { get; set; }
|
||||
|
||||
[JsonPropertyName("vacmacmodulecache")]
|
||||
public string? VacMacModuleCache { get; set; }
|
||||
|
||||
[JsonPropertyName("vacmodulecache")]
|
||||
public string? VacModuleCache { get; set; }
|
||||
|
||||
[JsonPropertyName("vacmodulefilename")]
|
||||
public string? VacModuleFileName { get; set; }
|
||||
|
||||
[JsonPropertyName("validoslist")]
|
||||
public string? ValidOperatingSystemList { get; set; }
|
||||
}
|
||||
36
LANCommander.Steam/Models/SteamCmdNet/AppInfo.cs
Normal file
36
LANCommander.Steam/Models/SteamCmdNet/AppInfo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppInfo
|
||||
{
|
||||
[JsonPropertyName("_change_number")]
|
||||
public long? ChangeNumber { get; set; }
|
||||
|
||||
[JsonPropertyName("_missing_token")]
|
||||
public bool? MissingToken { get; set; }
|
||||
|
||||
[JsonPropertyName("_sha")]
|
||||
public string? SHA { get; set; }
|
||||
|
||||
[JsonPropertyName("_size")]
|
||||
public long? Size { get; set; }
|
||||
|
||||
[JsonPropertyName("appid")]
|
||||
public long? AppId { get; set; }
|
||||
|
||||
[JsonPropertyName("common")]
|
||||
public AppCommon? Common { get; set; }
|
||||
|
||||
[JsonPropertyName("config")]
|
||||
public AppConfig? Config { get; set; }
|
||||
|
||||
[JsonPropertyName("extended")]
|
||||
public AppExtended? Extended { get; set; }
|
||||
|
||||
[JsonPropertyName("install")]
|
||||
public AppInstall? Install { get; set; }
|
||||
|
||||
[JsonPropertyName("ufs")]
|
||||
public AppUfs? UFS { get; set; }
|
||||
}
|
||||
13
LANCommander.Steam/Models/SteamCmdNet/AppInfoResponse.cs
Normal file
13
LANCommander.Steam/Models/SteamCmdNet/AppInfoResponse.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppInfoResponse
|
||||
{
|
||||
[JsonPropertyName("data")]
|
||||
public Dictionary<uint, AppInfo>? Data { get; set; }
|
||||
|
||||
[JsonPropertyName("status")]
|
||||
public string? Status { get; set; }
|
||||
}
|
||||
12
LANCommander.Steam/Models/SteamCmdNet/AppInstall.cs
Normal file
12
LANCommander.Steam/Models/SteamCmdNet/AppInstall.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppInstall
|
||||
{
|
||||
[JsonPropertyName("registry")]
|
||||
public RegistryRoot? Registry { get; set; }
|
||||
|
||||
[JsonPropertyName("utf8_registry_strings")]
|
||||
public string? UTF8RegistryStrings { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/AppMapping.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/AppMapping.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppMapping
|
||||
{
|
||||
[JsonPropertyName("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[JsonPropertyName("platform")]
|
||||
public string? Platform { get; set; }
|
||||
|
||||
[JsonPropertyName("tool")]
|
||||
public string? Tool { get; set; }
|
||||
}
|
||||
12
LANCommander.Steam/Models/SteamCmdNet/AppUfs.cs
Normal file
12
LANCommander.Steam/Models/SteamCmdNet/AppUfs.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class AppUfs
|
||||
{
|
||||
[JsonPropertyName("maxnumfiles")]
|
||||
public string? MaxNumFiles { get; set; }
|
||||
|
||||
[JsonPropertyName("quota")]
|
||||
public string? Quota { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/Branch.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/Branch.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class Branch
|
||||
{
|
||||
[JsonPropertyName("buildid")]
|
||||
public string? BuildId { get; set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[JsonPropertyName("timeupdated")]
|
||||
public string? TimeUpdated { get; set; }
|
||||
}
|
||||
12
LANCommander.Steam/Models/SteamCmdNet/DeckTestResult.cs
Normal file
12
LANCommander.Steam/Models/SteamCmdNet/DeckTestResult.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class DeckTestResult
|
||||
{
|
||||
[JsonPropertyName("display")]
|
||||
public string? Display { get; set; }
|
||||
|
||||
[JsonPropertyName("token")]
|
||||
public string? Token { get; set; }
|
||||
}
|
||||
25
LANCommander.Steam/Models/SteamCmdNet/Depot.cs
Normal file
25
LANCommander.Steam/Models/SteamCmdNet/Depot.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class Depot
|
||||
{
|
||||
[JsonPropertyName("config")]
|
||||
public DepotConfig? Config { get; set; }
|
||||
|
||||
[JsonPropertyName("depotfromapp")]
|
||||
public string? DepotFromApp { get; set; }
|
||||
|
||||
[JsonPropertyName("sharedinstall")]
|
||||
public string? SharedInstall { get; set; }
|
||||
|
||||
[JsonPropertyName("dlcappid")]
|
||||
public string? DlcAppId { get; set; }
|
||||
|
||||
[JsonPropertyName("systemdefined")]
|
||||
public string? SystemDefined { get; set; }
|
||||
|
||||
[JsonPropertyName("manifests")]
|
||||
public Dictionary<string, Manifest>? Manifests { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/DepotConfig.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/DepotConfig.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class DepotConfig
|
||||
{
|
||||
[JsonPropertyName("oslist")]
|
||||
public string? OperatingSystemList { get; set; }
|
||||
|
||||
[JsonPropertyName("osarch")]
|
||||
public string? OperatingSystemArchitecture { get; set; }
|
||||
|
||||
[JsonPropertyName("optionaldlc")]
|
||||
public string? OptionalDlc { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class ExternalArguments
|
||||
{
|
||||
[JsonPropertyName("allowunknown")]
|
||||
public string? AllowUnknown { get; set; }
|
||||
}
|
||||
21
LANCommander.Steam/Models/SteamCmdNet/LaunchConfig.cs
Normal file
21
LANCommander.Steam/Models/SteamCmdNet/LaunchConfig.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LaunchConfig
|
||||
{
|
||||
[JsonPropertyName("osarch")]
|
||||
public string? OperatingSystemArchitecture { get; set; }
|
||||
|
||||
[JsonPropertyName("oslist")]
|
||||
public string? OperatingSystemList { get; set; }
|
||||
|
||||
[JsonPropertyName("realm")]
|
||||
public string? Realm { get; set; }
|
||||
|
||||
[JsonPropertyName("betakey")]
|
||||
public string? BetaKey { get; set; }
|
||||
|
||||
[JsonPropertyName("ownsdlc")]
|
||||
public string? OwnsDlc { get; set; }
|
||||
}
|
||||
25
LANCommander.Steam/Models/SteamCmdNet/LaunchEntry.cs
Normal file
25
LANCommander.Steam/Models/SteamCmdNet/LaunchEntry.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LaunchEntry
|
||||
{
|
||||
[JsonPropertyName("arguments")]
|
||||
public string? Arguments { get; set; }
|
||||
|
||||
[JsonPropertyName("config")]
|
||||
public LaunchConfig? Config { get; set; }
|
||||
|
||||
[JsonPropertyName("executable")]
|
||||
public string? Executable { get; set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[JsonPropertyName("description_loc")]
|
||||
public Dictionary<string, string>? DescriptionLoc { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
16
LANCommander.Steam/Models/SteamCmdNet/LibraryAssetVariant.cs
Normal file
16
LANCommander.Steam/Models/SteamCmdNet/LibraryAssetVariant.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LibraryAssetVariant
|
||||
{
|
||||
[JsonPropertyName("image")]
|
||||
public Dictionary<string, string>? Image { get; set; }
|
||||
|
||||
[JsonPropertyName("image2x")]
|
||||
public Dictionary<string, string>? ImageLarge { get; set; }
|
||||
|
||||
[JsonPropertyName("logo_position")]
|
||||
public LogoPosition? Position { get; set; }
|
||||
}
|
||||
18
LANCommander.Steam/Models/SteamCmdNet/LibraryAssets.cs
Normal file
18
LANCommander.Steam/Models/SteamCmdNet/LibraryAssets.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LibraryAssets
|
||||
{
|
||||
[JsonPropertyName("library_capsule")]
|
||||
public string? Capsule { get; set; }
|
||||
|
||||
[JsonPropertyName("library_hero")]
|
||||
public string? Hero { get; set; }
|
||||
|
||||
[JsonPropertyName("library_logo")]
|
||||
public string? Logo { get; set; }
|
||||
|
||||
[JsonPropertyName("logo_position")]
|
||||
public LogoPosition? LogoPosition { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/LibraryAssetsFull.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/LibraryAssetsFull.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LibraryAssetsFull
|
||||
{
|
||||
[JsonPropertyName("library_capsule")]
|
||||
public LibraryAssetVariant? Capsule { get; set; }
|
||||
|
||||
[JsonPropertyName("library_hero")]
|
||||
public LibraryAssetVariant? Hero { get; set; }
|
||||
|
||||
[JsonPropertyName("library_logo")]
|
||||
public LibraryAssetVariant? Logo { get; set; }
|
||||
}
|
||||
10
LANCommander.Steam/Models/SteamCmdNet/LocalizedImageMap.cs
Normal file
10
LANCommander.Steam/Models/SteamCmdNet/LocalizedImageMap.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public class LocalizedImageMap
|
||||
{
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, object>? Values { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/LogoPosition.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/LogoPosition.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class LogoPosition
|
||||
{
|
||||
[JsonPropertyName("height_pct")]
|
||||
public string? HeightPercentage { get; set; }
|
||||
|
||||
[JsonPropertyName("width_pct")]
|
||||
public string? WidthPercentage { get; set; }
|
||||
|
||||
[JsonPropertyName("pinned_position")]
|
||||
public string? PinnedPosition { get; set; }
|
||||
}
|
||||
15
LANCommander.Steam/Models/SteamCmdNet/Manifest.cs
Normal file
15
LANCommander.Steam/Models/SteamCmdNet/Manifest.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class Manifest
|
||||
{
|
||||
[JsonPropertyName("download")]
|
||||
public string? Download { get; set; }
|
||||
|
||||
[JsonPropertyName("gid")]
|
||||
public string? GID { get; set; }
|
||||
|
||||
[JsonPropertyName("size")]
|
||||
public string? Size { get; set; }
|
||||
}
|
||||
11
LANCommander.Steam/Models/SteamCmdNet/RegistryRoot.cs
Normal file
11
LANCommander.Steam/Models/SteamCmdNet/RegistryRoot.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class RegistryRoot
|
||||
{
|
||||
// Keys look like: "hkey_local_machine\\software\\valve\\cs2"
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, object>? Keys { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class SteamDeckCompatibility
|
||||
{
|
||||
[JsonPropertyName("category")]
|
||||
public string? Category { get; set; }
|
||||
|
||||
[JsonPropertyName("configuration")]
|
||||
public Dictionary<string, string>? Configuration { get; set; }
|
||||
|
||||
[JsonPropertyName("steamos_compatibility")]
|
||||
public string? SteamOsCompatibility { get; set; }
|
||||
|
||||
[JsonPropertyName("steamos_tests")]
|
||||
public Dictionary<string, DeckTestResult>? SteamOsTests { get; set; }
|
||||
|
||||
[JsonPropertyName("test_timestamp")]
|
||||
public string? TestTimestamp { get; set; }
|
||||
|
||||
[JsonPropertyName("tested_build_id")]
|
||||
public string? TestedBuildId { get; set; }
|
||||
|
||||
[JsonPropertyName("tests")]
|
||||
public Dictionary<string, DeckTestResult>? Tests { get; set; }
|
||||
}
|
||||
12
LANCommander.Steam/Models/SteamCmdNet/SupportedLanguage.cs
Normal file
12
LANCommander.Steam/Models/SteamCmdNet/SupportedLanguage.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
public sealed class SupportedLanguage
|
||||
{
|
||||
[JsonPropertyName("supported")]
|
||||
public string? Supported { get; set; }
|
||||
|
||||
[JsonPropertyName("full_audio")]
|
||||
public string? FullAudio { get; set; }
|
||||
}
|
||||
|
|
@ -473,7 +473,66 @@ public class SteamCmdService(
|
|||
await profileStore.DeleteAsync(username);
|
||||
_logger?.LogInformation("Deleted profile for username: {Username}", username);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SteamCmdAppInfo?> GetAppInfoAsync(uint appId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ExecutablePath))
|
||||
{
|
||||
if (_options.AutoDetectPath)
|
||||
{
|
||||
var detected = await AutoDetectSteamCmdPathAsync();
|
||||
if (!string.IsNullOrEmpty(detected))
|
||||
ExecutablePath = detected;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(ExecutablePath))
|
||||
{
|
||||
_logger?.LogWarning("SteamCMD path is not configured; cannot get app changenumber.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!File.Exists(ExecutablePath))
|
||||
{
|
||||
_logger?.LogWarning("SteamCMD executable not found at {Path}", ExecutablePath);
|
||||
return null;
|
||||
}
|
||||
|
||||
// +quit can suppress output on some SteamCMD versions; we parse both stdout and stderr
|
||||
var arguments = $"+login anonymous +app_info_update 1 +app_info_print {appId} +quit";
|
||||
var result = await ExecuteSteamCmdCommandAsync(arguments, TimeSpan.FromSeconds(60));
|
||||
var combined = (result.Output + "\n" + result.ErrorOutput);
|
||||
|
||||
var info = ParseAppInfoPrintOutput(appId, combined);
|
||||
if (info != null)
|
||||
_logger?.LogDebug("SteamCMD app info for {AppId}: changenumber={Changenumber}", appId, info.Changenumber);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static SteamCmdAppInfo? ParseAppInfoPrintOutput(uint appId, string output)
|
||||
{
|
||||
// VDF-like output: "buildid" "3936003" and "timeupdated" "1560990358" (often under "public" branch)
|
||||
var buildIdMatch = Regex.Match(output, @"""buildid""\s+""([^""]+)""", RegexOptions.IgnoreCase);
|
||||
var timeUpdatedMatch = Regex.Match(output, @"""timeupdated""\s+""([^""]+)""", RegexOptions.IgnoreCase);
|
||||
if (!buildIdMatch.Success)
|
||||
return null;
|
||||
|
||||
var changenumber = buildIdMatch.Groups[1].Value.Trim();
|
||||
if (string.IsNullOrEmpty(changenumber))
|
||||
return null;
|
||||
|
||||
DateTimeOffset? timeUpdated = null;
|
||||
if (timeUpdatedMatch.Success && long.TryParse(timeUpdatedMatch.Groups[1].Value.Trim(), out var unixSeconds))
|
||||
timeUpdated = DateTimeOffset.FromUnixTimeSeconds(unixSeconds);
|
||||
|
||||
return new SteamCmdAppInfo
|
||||
{
|
||||
AppId = appId,
|
||||
Changenumber = changenumber,
|
||||
TimeUpdated = timeUpdated
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<SteamCmdResult> ExecuteSteamCmdCommandWithProgressAsync(
|
||||
string arguments,
|
||||
SteamCmdInstallJob? job = null,
|
||||
|
|
@ -502,38 +561,45 @@ public class SteamCmdService(
|
|||
var output = new StringBuilder();
|
||||
var error = new StringBuilder();
|
||||
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
output.AppendLine(e.Data);
|
||||
_logger?.LogDebug("SteamCMD Output: {Output}", e.Data);
|
||||
|
||||
// Parse progress if job is provided
|
||||
if (job != null)
|
||||
{
|
||||
ParseProgressFromOutput(e.Data, job);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
process.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
error.AppendLine(e.Data);
|
||||
_logger?.LogDebug("SteamCMD Error: {Error}", e.Data);
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
// Read streams with \r and \n as line delimiters so we get progress updates in real time.
|
||||
// SteamCMD uses \r for progress lines and full buffering when piped; BeginOutputReadLine
|
||||
// only fires on \n, so output would otherwise appear only at the end.
|
||||
var readStdOut = ReadStreamByLineAsync(
|
||||
process.StandardOutput.BaseStream,
|
||||
Encoding.UTF8,
|
||||
line =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
return;
|
||||
output.AppendLine(line);
|
||||
_logger?.LogDebug("SteamCMD Output: {Output}", line);
|
||||
if (job != null)
|
||||
ParseProgressFromOutput(line, job);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
var readStdErr = ReadStreamByLineAsync(
|
||||
process.StandardError.BaseStream,
|
||||
Encoding.UTF8,
|
||||
line =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
return;
|
||||
error.AppendLine(line);
|
||||
_logger?.LogDebug("SteamCMD Error: {Error}", line);
|
||||
if (job != null)
|
||||
ParseProgressFromOutput(line, job);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
await process.WaitForExitAsync(cancellationToken);
|
||||
await Task.WhenAll(
|
||||
readStdOut,
|
||||
readStdErr,
|
||||
process.WaitForExitAsync(cancellationToken));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
|
@ -567,6 +633,43 @@ public class SteamCmdService(
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a stream and invokes the callback for each line. Lines are split on \r and \n
|
||||
/// so that progress output (often \r-only) is delivered in real time instead of buffered.
|
||||
/// </summary>
|
||||
private static async Task ReadStreamByLineAsync(
|
||||
Stream stream,
|
||||
Encoding encoding,
|
||||
Action<string> onLine,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: false, leaveOpen: true);
|
||||
var lineBuilder = new StringBuilder();
|
||||
var charBuffer = new char[256];
|
||||
int read;
|
||||
while ((read = await reader.ReadAsync(charBuffer.AsMemory(), cancellationToken).ConfigureAwait(false)) > 0)
|
||||
{
|
||||
for (var i = 0; i < read; i++)
|
||||
{
|
||||
var ch = charBuffer[i];
|
||||
if (ch == '\r' || ch == '\n')
|
||||
{
|
||||
if (lineBuilder.Length > 0)
|
||||
{
|
||||
onLine(lineBuilder.ToString());
|
||||
lineBuilder.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lineBuilder.Append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lineBuilder.Length > 0)
|
||||
onLine(lineBuilder.ToString());
|
||||
}
|
||||
|
||||
private void ParseProgressFromOutput(string line, SteamCmdInstallJob job)
|
||||
{
|
||||
// SteamCMD progress patterns:
|
||||
|
|
|
|||
|
|
@ -1,30 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
using HtmlAgilityPack;
|
||||
using LANCommander.Steam.Abstractions;
|
||||
using LANCommander.Steam.Models.SteamCmdNet;
|
||||
|
||||
namespace LANCommander.Steam.Services;
|
||||
|
||||
public class SteamStoreService
|
||||
public class SteamWebApiService(HttpClient httpClient) : ISteamWebApiService
|
||||
{
|
||||
private readonly HttpClient HttpClient;
|
||||
|
||||
public SteamStoreService()
|
||||
public async Task<AppInfo> GetAppInfo(uint appId)
|
||||
{
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.BaseAddress = new Uri("https://store.steampowered.com");
|
||||
var response = await httpClient.GetFromJsonAsync<AppInfoResponse>($"https://api.steamcmd.net/v1/info/{appId}");
|
||||
|
||||
if (response.Data?.ContainsKey(appId) ?? false)
|
||||
return response.Data[appId];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GameSearchResult>> SearchGamesAsync(string keyword)
|
||||
{
|
||||
HtmlWeb web = new HtmlWeb();
|
||||
HtmlDocument dom = await web.LoadFromWebAsync($"https://store.steampowered.com/search/suggest?term={keyword}&f=games&cc=US");
|
||||
HtmlDocument dom =
|
||||
await web.LoadFromWebAsync($"https://store.steampowered.com/search/suggest?term={keyword}&f=games&cc=US");
|
||||
|
||||
var results = new List<GameSearchResult>();
|
||||
List<GameSearchResult> results = [];
|
||||
var matches = dom.DocumentNode.SelectNodes("//a[@data-ds-appid]");
|
||||
|
||||
if (matches == null || matches.Count == 0)
|
||||
|
|
@ -48,51 +52,15 @@ public class SteamStoreService
|
|||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public async Task<(bool Exists, string MimeType)> HasWebAssetAsync(int appId, WebAssetType webAssetType)
|
||||
{
|
||||
var webAssetUri = GetWebAssetUri(appId, webAssetType);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, webAssetUri));
|
||||
|
||||
var exists = response.Content.Headers.ContentType.MediaType == MediaTypeNames.Image.Jpeg || response.Content.Headers.ContentType.MediaType == "image/png";
|
||||
|
||||
return (exists, response.Content.Headers.ContentType.MediaType);
|
||||
}
|
||||
|
||||
public async Task<bool> HasManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, manualUri));
|
||||
|
||||
return response.Content.Headers.ContentType.MediaType == MediaTypeNames.Application.Pdf;
|
||||
}
|
||||
|
||||
public async Task<byte[]> DownloadManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.GetAsync(manualUri);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
await response.Content.CopyToAsync(ms);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri GetManualUri(int appId)
|
||||
{
|
||||
return new Uri($"https://store.steampowered.com/manual/{appId}");
|
||||
}
|
||||
|
||||
|
||||
public static Uri GetWebAssetUri(int appId, WebAssetType type)
|
||||
{
|
||||
Dictionary<WebAssetType, string> webAssetTypeMap = new Dictionary<WebAssetType, string>()
|
||||
|
|
@ -1,116 +1,112 @@
|
|||
using HtmlAgilityPack;
|
||||
using SteamWebAPI2.Utilities;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LANCommander.Steam
|
||||
namespace LANCommander.Steam;
|
||||
|
||||
public class SteamClient
|
||||
{
|
||||
public class SteamClient
|
||||
private readonly HttpClient HttpClient;
|
||||
|
||||
public SteamClient()
|
||||
{
|
||||
private readonly HttpClient HttpClient;
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.BaseAddress = new Uri("https://store.steampowered.com");
|
||||
}
|
||||
|
||||
public SteamClient()
|
||||
public async Task<IEnumerable<GameSearchResult>> SearchGamesAsync(string keyword)
|
||||
{
|
||||
HtmlWeb web = new HtmlWeb();
|
||||
HtmlDocument dom = await web.LoadFromWebAsync($"https://store.steampowered.com/search/suggest?term={keyword}&f=games&cc=US");
|
||||
|
||||
var results = new List<GameSearchResult>();
|
||||
var matches = dom.DocumentNode.SelectNodes("//a[@data-ds-appid]");
|
||||
|
||||
if (matches == null || matches.Count == 0)
|
||||
return Enumerable.Empty<GameSearchResult>();
|
||||
|
||||
foreach (var match in matches)
|
||||
{
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.BaseAddress = new Uri("https://store.steampowered.com");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GameSearchResult>> SearchGamesAsync(string keyword)
|
||||
{
|
||||
HtmlWeb web = new HtmlWeb();
|
||||
HtmlDocument dom = await web.LoadFromWebAsync($"https://store.steampowered.com/search/suggest?term={keyword}&f=games&cc=US");
|
||||
|
||||
var results = new List<GameSearchResult>();
|
||||
var matches = dom.DocumentNode.SelectNodes("//a[@data-ds-appid]");
|
||||
|
||||
if (matches == null || matches.Count == 0)
|
||||
return Enumerable.Empty<GameSearchResult>();
|
||||
|
||||
foreach (var match in matches)
|
||||
try
|
||||
{
|
||||
try
|
||||
var appId = match.Attributes["data-ds-appid"].Value;
|
||||
var matchNameElement = match.SelectSingleNode(".//div[@class = 'match_name']");
|
||||
|
||||
appId = appId.Split(',').First();
|
||||
|
||||
if (matchNameElement != null)
|
||||
{
|
||||
var appId = match.Attributes["data-ds-appid"].Value;
|
||||
var matchNameElement = match.SelectSingleNode(".//div[@class = 'match_name']");
|
||||
|
||||
appId = appId.Split(',').First();
|
||||
|
||||
if (matchNameElement != null)
|
||||
results.Add(new GameSearchResult
|
||||
{
|
||||
results.Add(new GameSearchResult
|
||||
{
|
||||
Name = matchNameElement.InnerText,
|
||||
AppId = Convert.ToInt32(appId)
|
||||
});
|
||||
}
|
||||
Name = matchNameElement.InnerText,
|
||||
AppId = Convert.ToInt32(appId)
|
||||
});
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
}
|
||||
|
||||
return results;
|
||||
catch (Exception ex) { }
|
||||
}
|
||||
|
||||
public async Task<(bool Exists, string MimeType)> HasWebAssetAsync(int appId, WebAssetType webAssetType)
|
||||
return results;
|
||||
}
|
||||
|
||||
public async Task<(bool Exists, string MimeType)> HasWebAssetAsync(int appId, WebAssetType webAssetType)
|
||||
{
|
||||
var webAssetUri = GetWebAssetUri(appId, webAssetType);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, webAssetUri));
|
||||
|
||||
var exists = response.Content.Headers.ContentType.MediaType == MediaTypeNames.Image.Jpeg || response.Content.Headers.ContentType.MediaType == "image/png";
|
||||
|
||||
return (exists, response.Content.Headers.ContentType.MediaType);
|
||||
}
|
||||
|
||||
public async Task<bool> HasManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, manualUri));
|
||||
|
||||
return response.Content.Headers.ContentType.MediaType == MediaTypeNames.Application.Pdf;
|
||||
}
|
||||
|
||||
public async Task<byte[]> DownloadManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.GetAsync(manualUri);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var webAssetUri = GetWebAssetUri(appId, webAssetType);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, webAssetUri));
|
||||
await response.Content.CopyToAsync(ms);
|
||||
|
||||
var exists = response.Content.Headers.ContentType.MediaType == MediaTypeNames.Image.Jpeg || response.Content.Headers.ContentType.MediaType == "image/png";
|
||||
|
||||
return (exists, response.Content.Headers.ContentType.MediaType);
|
||||
}
|
||||
|
||||
public async Task<bool> HasManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, manualUri));
|
||||
|
||||
return response.Content.Headers.ContentType.MediaType == MediaTypeNames.Application.Pdf;
|
||||
}
|
||||
|
||||
public async Task<byte[]> DownloadManualAsync(int appId)
|
||||
{
|
||||
var manualUri = GetManualUri(appId);
|
||||
var response = await HttpClient.GetAsync(manualUri);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
await response.Content.CopyToAsync(ms);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri GetManualUri(int appId)
|
||||
{
|
||||
return new Uri($"https://store.steampowered.com/manual/{appId}");
|
||||
}
|
||||
|
||||
public static Uri GetWebAssetUri(int appId, WebAssetType type)
|
||||
{
|
||||
Dictionary<WebAssetType, string> webAssetTypeMap = new Dictionary<WebAssetType, string>()
|
||||
{
|
||||
{ WebAssetType.Capsule, "capsule_231x87.jpg" },
|
||||
{ WebAssetType.CapsuleLarge, "capsule_616x353.jpg" },
|
||||
{ WebAssetType.Header, "header.jpg" },
|
||||
{ WebAssetType.HeroCapsule, "hero_capsule.jpg" },
|
||||
{ WebAssetType.LibraryCover, "library_600x900.jpg" },
|
||||
{ WebAssetType.LibraryHeader, "library_header.jpg" },
|
||||
{ WebAssetType.LibraryHero, "library_hero.jpg" },
|
||||
{ WebAssetType.Logo, "logo.png" }
|
||||
};
|
||||
|
||||
return new Uri($"https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/{appId}/{webAssetTypeMap[type]}");
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri GetManualUri(int appId)
|
||||
{
|
||||
return new Uri($"https://store.steampowered.com/manual/{appId}");
|
||||
}
|
||||
|
||||
public static Uri GetWebAssetUri(int appId, WebAssetType type)
|
||||
{
|
||||
Dictionary<WebAssetType, string> webAssetTypeMap = new Dictionary<WebAssetType, string>()
|
||||
{
|
||||
{ WebAssetType.Capsule, "capsule_231x87.jpg" },
|
||||
{ WebAssetType.CapsuleLarge, "capsule_616x353.jpg" },
|
||||
{ WebAssetType.Header, "header.jpg" },
|
||||
{ WebAssetType.HeroCapsule, "hero_capsule.jpg" },
|
||||
{ WebAssetType.LibraryCover, "library_600x900.jpg" },
|
||||
{ WebAssetType.LibraryHeader, "library_header.jpg" },
|
||||
{ WebAssetType.LibraryHero, "library_hero.jpg" },
|
||||
{ WebAssetType.Logo, "logo.png" }
|
||||
};
|
||||
|
||||
return new Uri($"https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/{appId}/{webAssetTypeMap[type]}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LANCommander.Steam
|
||||
namespace LANCommander.Steam
|
||||
{
|
||||
public enum WebAssetType
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue