From cd1f042c7a0fb2694b9481b0877393921d704b34 Mon Sep 17 00:00:00 2001 From: Andreas Aronsson Date: Mon, 27 Oct 2025 13:41:47 +0100 Subject: [PATCH] Add -output-json option to output -manifest-only as JSON Adds the System.Text.Json Nuget package Option alias -json Readme and help updated Verified through tests of deep matching original output with JSON output across 1000+ depots (until I got ratelimited) --- DepotDownloader/ContentDownloader.cs | 73 ++++++++++++++++++++------ DepotDownloader/DepotDownloader.csproj | 1 + DepotDownloader/DownloadConfig.cs | 1 + DepotDownloader/Program.cs | 2 + README.md | 1 + 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs index 967cc499..ff07d9d5 100644 --- a/DepotDownloader/ContentDownloader.cs +++ b/DepotDownloader/ContentDownloader.cs @@ -5,9 +5,11 @@ using System; using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Data.SqlTypes; using System.IO; using System.Linq; using System.Net; +using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using SteamKit2; @@ -864,7 +866,7 @@ namespace DepotDownloader if (Config.DownloadManifestOnly) { - DumpManifestToTextFile(depot, newManifest); + DumpManifestToTextFile(depot, newManifest, Config.OutputJson); return null; } @@ -1352,18 +1354,17 @@ namespace DepotDownloader } } - static void DumpManifestToTextFile(DepotDownloadInfo depot, DepotManifest manifest) + static void DumpManifestToTextFile(DepotDownloadInfo depot, DepotManifest manifest, bool asJson) { - var txtManifest = Path.Combine(depot.InstallDir, $"manifest_{depot.DepotId}_{depot.ManifestId}.txt"); + var outputFileExtension = asJson ? "json" : "txt"; + var txtManifest = Path.Combine(depot.InstallDir, $"manifest_{depot.DepotId}_{depot.ManifestId}.{outputFileExtension}"); using var sw = new StreamWriter(txtManifest); - sw.WriteLine($"Content Manifest for Depot {depot.DepotId} "); - sw.WriteLine(); - sw.WriteLine($"Manifest ID / date : {depot.ManifestId} / {manifest.CreationTime} "); + var manifestFiles = manifest.Files ?? []; var uniqueChunks = new HashSet(new ChunkIdComparer()); - foreach (var file in manifest.Files) + foreach (var file in manifestFiles) { foreach (var chunk in file.Chunks) { @@ -1371,18 +1372,56 @@ namespace DepotDownloader } } - sw.WriteLine($"Total number of files : {manifest.Files.Count} "); - sw.WriteLine($"Total number of chunks : {uniqueChunks.Count} "); - sw.WriteLine($"Total bytes on disk : {manifest.TotalUncompressedSize} "); - sw.WriteLine($"Total bytes compressed : {manifest.TotalCompressedSize} "); - sw.WriteLine(); - sw.WriteLine(); - sw.WriteLine(" Size Chunks File SHA Flags Name"); + if (asJson) + { + var filesArray = new JsonArray(); + foreach (var file in manifestFiles) + { + var sha1Hash = Convert.ToHexString(file.FileHash).ToLower(); + var fileObject = new JsonObject + { + { "size", file.TotalSize }, + { "chunks", file.Chunks.Count }, + { "sha", sha1Hash }, + { "flags", Convert.ToString((int) file.Flags, 16) }, + { "name", file.FileName } + }; + filesArray.Add(fileObject); + } - foreach (var file in manifest.Files) + var manifestObject = new JsonObject + { + { "description", $"Content Manifest for Depot {depot.DepotId}" }, + { "depotId", depot.DepotId }, + { "manifestId", depot.ManifestId }, + { "manifestCreationTime", manifest.CreationTime }, + { "totalFiles", manifestFiles.Count }, + { "totalChunks", uniqueChunks.Count }, + { "totalBytesOnDisk", manifest.TotalUncompressedSize }, + { "totalBytesCompressed", manifest.TotalCompressedSize }, + { "files", filesArray } + }; + sw.WriteLine(manifestObject.ToJsonString()); + } + else { - var sha1Hash = Convert.ToHexString(file.FileHash).ToLower(); - sw.WriteLine($"{file.TotalSize,14:d} {file.Chunks.Count,6:d} {sha1Hash} {(int)file.Flags,5:x} {file.FileName}"); + sw.WriteLine($"Content Manifest for Depot {depot.DepotId} "); + sw.WriteLine(); + sw.WriteLine($"Manifest ID / date : {depot.ManifestId} / {manifest.CreationTime} "); + + sw.WriteLine($"Total number of files : {manifestFiles.Count} "); + sw.WriteLine($"Total number of chunks : {uniqueChunks.Count} "); + sw.WriteLine($"Total bytes on disk : {manifest.TotalUncompressedSize} "); + sw.WriteLine($"Total bytes compressed : {manifest.TotalCompressedSize} "); + sw.WriteLine(); + sw.WriteLine(); + sw.WriteLine(" Size Chunks File SHA Flags Name"); + + foreach (var file in manifestFiles) + { + var sha1Hash = Convert.ToHexString(file.FileHash).ToLower(); + sw.WriteLine($"{file.TotalSize,14:d} {file.Chunks.Count,6:d} {sha1Hash} {(int)file.Flags,5:x} {file.FileName}"); + } } } } diff --git a/DepotDownloader/DepotDownloader.csproj b/DepotDownloader/DepotDownloader.csproj index f1aa115d..f8180112 100644 --- a/DepotDownloader/DepotDownloader.csproj +++ b/DepotDownloader/DepotDownloader.csproj @@ -28,5 +28,6 @@ + diff --git a/DepotDownloader/DownloadConfig.cs b/DepotDownloader/DownloadConfig.cs index 144853bf..2877773a 100644 --- a/DepotDownloader/DownloadConfig.cs +++ b/DepotDownloader/DownloadConfig.cs @@ -32,5 +32,6 @@ namespace DepotDownloader public bool UseQrCode { get; set; } public bool SkipAppConfirmation { get; set; } + public bool OutputJson { get; set; } } } diff --git a/DepotDownloader/Program.cs b/DepotDownloader/Program.cs index 26b7f16f..0d8e4f4b 100644 --- a/DepotDownloader/Program.cs +++ b/DepotDownloader/Program.cs @@ -156,6 +156,7 @@ namespace DepotDownloader ContentDownloader.Config.MaxDownloads = GetParameter(args, "-max-downloads", 8); ContentDownloader.Config.LoginID = HasParameter(args, "-loginid") ? GetParameter(args, "-loginid") : null; + ContentDownloader.Config.OutputJson = HasParameter(args, "-output-json") || HasParameter(args, "-json"); #endregion @@ -529,6 +530,7 @@ namespace DepotDownloader Console.WriteLine(" -max-downloads <#> - maximum number of chunks to download concurrently. (default: 8)."); Console.WriteLine(" -loginid <#> - a unique 32-bit integer Steam LogonID in decimal, required if running multiple instances of DepotDownloader concurrently."); Console.WriteLine(" -use-lancache - forces downloads over the local network via a Lancache instance."); + Console.WriteLine(" -output-json - outputs -manifest-only manifest as JSON."); Console.WriteLine(); Console.WriteLine(" -debug - enable verbose debug logging."); Console.WriteLine(" -V or --version - print version and runtime."); diff --git a/README.md b/README.md index 810c9466..9c1416c0 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ Parameter | Description `-cellid <#>` | the overridden CellID of the content server to download from. `-max-downloads <#>` | maximum number of chunks to download concurrently. (default: 8). `-use-lancache` | forces downloads over the local network via a Lancache instance. +`-output-json` | outputs -manifest-only manifest as JSON. #### Other