Cleanup, Arguments

- Rewritten the Program.cs to get it clean and readable
- Rewritten the usage section
- Added ArgumentParser (!!! ATTENTION !!! some arguments have changed)
  - ProgramArgs contains all possible parameters for the command line
    Feel free to add some ;)
pull/261/head
BxNiom 4 years ago
parent 8b4dcc2339
commit ce1d61f910

3
.gitignore vendored

@ -118,3 +118,6 @@ cryptopp/
# misc
Thumbs.db
# IntelliJ Rider
.idea/

@ -0,0 +1,227 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
namespace DepotDownloader
{
/// <summary>
/// Quick argument parser
/// Need some optimisation, but it is functional ;)
/// </summary>
public static class ArgumentParser
{
/// <summary>
/// Parse command line arguments and set Properties in TContainer object
/// </summary>
/// <param name="args">Command line arguments</param>
/// <typeparam name="TContainer">Type implementing IArgumentContainer</typeparam>
/// <returns>TContainer object with properties set</returns>
/// <exception cref="ArgumentException"></exception>
public static TContainer Parse<TContainer>(string[] args) where TContainer : IArgumentContainer
{
var containerType = typeof(TContainer);
var container = (TContainer)Activator.CreateInstance(containerType);
if (container == null)
{
throw new ArgumentException($"Type {containerType} has no empty constructor");
}
var options = GetContainerOptions(containerType);
for (var i = 0; i < args.Length; i++)
{
if (!args[i].StartsWith("-"))
{
throw new ArgumentException($"Unknown argument: {args[i]}");
}
var arg = args[i].StartsWith("--") ? args[i].Substring(2) : args[i].Substring(1);
var (option, property) = (from op in options
where
arg.Length == 1 && op.Item1.ShortOption == arg[0]
|| op.Item1.LongOption.Equals(arg, StringComparison.Ordinal)
select op).FirstOrDefault();
if (option == null || property == null)
{
throw new ArgumentException($"Unknown argument: '{arg}'");
}
if (option.ParameterName != null || option.AllowMultiple)
{
if (i == args.Length - 1)
{
throw new ArgumentException($"No parameter for option '{arg}' found");
}
if (!option.AllowMultiple)
{
var parameter = args[++i];
if (parameter.StartsWith("-"))
{
throw new ArgumentException($"No parameter for option '{arg}' found");
}
property.SetValue(container,
property.PropertyType == typeof(string)
? parameter
: TypeDescriptor.GetConverter(property.PropertyType).ConvertFromString(parameter));
}
else
{
var converter = property.PropertyType.IsGenericType
? TypeDescriptor.GetConverter(property.PropertyType.GenericTypeArguments[0])
: null;
var list = (IList)property.GetValue(container);
if (list == null)
{
throw new ArgumentException("Initialize List properties first!");
}
while (i < args.Length && !args[i + 1].StartsWith("-"))
{
var parameter = converter != null ? converter.ConvertFromString(args[++i]) : args[++i];
list.Add(parameter);
}
}
}
}
return container;
}
// TODO wrap
/// <summary>
/// Creates a parameter table for given container type
/// </summary>
/// <param name="ident">number of whitespaces at the line beginning</param>
/// <param name="wrap">wrap long descriptions (not implemented yet)</param>
/// <typeparam name="T">Container type</typeparam>
/// <returns></returns>
public static string GetHelpList<T>(int ident = 4, bool wrap = false) where T : IArgumentContainer
{
var optionList = GetContainerOptions(typeof(T));
var sb = new StringBuilder();
var lines = new List<(string, string)>();
var maxOpLength = 0;
foreach (var (option, _) in optionList)
{
var opStr = option.ShortOption != '\0' ? $"-{option.ShortOption}" : "";
if (!string.IsNullOrEmpty(option.LongOption))
{
opStr += (option.ShortOption != '\0' ? ", " : " ") + $"--{option.LongOption}";
}
if (option.ParameterName != null)
{
opStr += $" <{option.ParameterName}>";
}
lines.Add((opStr, option.Description));
maxOpLength = Math.Max(maxOpLength, opStr.Length);
}
var identStr = "".PadRight(ident);
foreach (var (op, desc) in lines)
{
sb.AppendLine(identStr + op.PadRight(maxOpLength + 4) + desc);
}
return sb.ToString();
}
private static List<(OptionAttribute, PropertyInfo)> GetContainerOptions(Type containerType)
{
var resultList = new List<(OptionAttribute, PropertyInfo)>();
foreach (var prop in containerType.GetProperties())
{
// try to get OptionAttribute from property
var a = prop.GetCustomAttribute(typeof(OptionAttribute));
if (a == null)
{
continue;
}
// Check some things
var option = (OptionAttribute)a;
if (prop.SetMethod == null)
{
throw new ArgumentException($"No setter found for '{prop.Name}'");
}
// Only options with descriptions are allowed!
if (string.IsNullOrEmpty(option.Description))
{
throw new ArgumentException($"No description found for '{prop.Name}'");
}
// We need a short option or a long option
if (option.ShortOption == '\0' && string.IsNullOrEmpty(option.LongOption))
{
throw new ArgumentException(
$"You must at least permit ShortOption or LongOption. Property: '{prop.Name}");
}
// AllowMultiple only allowed on list properties
if (option.AllowMultiple && !prop.PropertyType.IsAssignableTo(typeof(IList)))
{
throw new ArgumentException(
$"Options with AllowMultiple must be assignable to IList type. Property: '{prop.Name}");
}
if (!option.AllowMultiple && option.ParameterName == null && prop.PropertyType != typeof(bool))
{
throw new ArgumentException(
$"Property must be bool if there is no parameter required. Property: '{prop.Name}");
}
// if everything is ok, add it to the result list
resultList.Add((option, prop));
}
return resultList;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class OptionAttribute : Attribute
{
/// <summary>
/// Used for lists of parameters, seperated by whitespaces
/// </summary>
public bool AllowMultiple = false;
/// <summary>
/// </summary>
public string Description = null;
/// <summary>
/// long option name (e.g. --username)
/// </summary>
public string LongOption = null;
/// <summary>
/// Name of parameter if parameter is needed (e.g. <user>)
/// </summary>
public string ParameterName = null;
/// <summary>
/// single character option (e.g. -u)
/// </summary>
public char ShortOption = '\0';
}
public interface IArgumentContainer
{
}
}

@ -8,6 +8,7 @@
<Description>Steam Downloading Utility</Description>
<Authors>SteamRE Team</Authors>
<Copyright>Copyright © SteamRE Team 2021</Copyright>
<AssemblyVersion>2.4.3</AssemblyVersion>
</PropertyGroup>
<ItemGroup>

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -9,12 +8,14 @@ using SteamKit2;
namespace DepotDownloader
{
class Program
internal partial class Program
{
static int Main(string[] args)
=> MainAsync(args).GetAwaiter().GetResult();
private static int Main(string[] args)
{
return MainAsync(args).GetAwaiter().GetResult();
}
static async Task<int> MainAsync(string[] args)
private static async Task<int> MainAsync(string[] args)
{
if (args.Length == 0)
{
@ -23,102 +24,118 @@ namespace DepotDownloader
}
DebugLog.Enabled = false;
AccountSettingsStore.LoadFromFile("account.config");
#region Common Options
// Use ArgumentParser to read args
ProgramArgs arguments = null;
try
{
arguments = ArgumentParser.Parse<ProgramArgs>(args);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
PrintUsage();
return 2;
}
#region Arguments -> ContentDownload.Config
if (HasParameter(args, "-debug"))
if (arguments.Debug)
{
// Verbose
DebugLog.Enabled = true;
DebugLog.AddListener((category, message) =>
{
Console.WriteLine("[{0}] {1}", category, message);
});
var httpEventListener = new HttpDiagnosticEventListener();
// why?
//var httpEventListener = new HttpDiagnosticEventListener();
}
var username = GetParameter<string>(args, "-username") ?? GetParameter<string>(args, "-user");
var password = GetParameter<string>(args, "-password") ?? GetParameter<string>(args, "-pass");
ContentDownloader.Config.RememberPassword = HasParameter(args, "-remember-password");
ContentDownloader.Config.RememberPassword = arguments.RememberPassword;
ContentDownloader.Config.DownloadManifestOnly = arguments.ManifestOnly;
ContentDownloader.Config.CellID = arguments.CellID;
ContentDownloader.Config.InstallDirectory = arguments.InstallDir;
ContentDownloader.Config.VerifyAll = arguments.Validate;
ContentDownloader.Config.MaxDownloads = arguments.MaxDownloads;
ContentDownloader.Config.MaxServers = Math.Max(arguments.MaxServers, arguments.MaxDownloads);
ContentDownloader.Config.LoginID = arguments.LoginID;
ContentDownloader.Config.DownloadAllPlatforms = arguments.AllPlatforms;
ContentDownloader.Config.DownloadAllLanguages = arguments.AllLanguages;
ContentDownloader.Config.BetaPassword = arguments.BetaPassword;
ContentDownloader.Config.DownloadManifestOnly = HasParameter(args, "-manifest-only");
#endregion
var cellId = GetParameter(args, "-cellid", -1);
if (cellId == -1)
if (!string.IsNullOrEmpty(arguments.FileList))
{
cellId = 0;
await LoadFileListAsync(arguments.FileList);
}
ContentDownloader.Config.CellID = cellId;
var fileList = GetParameter<string>(args, "-filelist");
if (fileList != null)
if (arguments.AppID == ContentDownloader.INVALID_APP_ID)
{
try
{
var fileListData = await File.ReadAllTextAsync(fileList);
var files = fileListData.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
ContentDownloader.Config.UsingFileList = true;
ContentDownloader.Config.FilesToDownload = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex = new List<Regex>();
Console.WriteLine("Error: App not specified");
PrintUsage();
return 1;
}
foreach (var fileEntry in files)
{
if (fileEntry.StartsWith("regex:"))
// PubFile download
if (arguments.PubFile != ContentDownloader.INVALID_MANIFEST_ID)
{
var rgx = new Regex(fileEntry.Substring(6), RegexOptions.Compiled | RegexOptions.IgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
return await DownloadPubFileAsync(arguments);
}
else
// UGC download
if (arguments.UGC != ContentDownloader.INVALID_MANIFEST_ID)
{
ContentDownloader.Config.FilesToDownload.Add(fileEntry.Replace('\\', '/'));
}
return await DownloadUGCAsync(arguments);
}
Console.WriteLine("Using filelist: '{0}'.", fileList);
}
catch (Exception ex)
// App download
if (ContentDownloader.Config.DownloadAllPlatforms && arguments.OperatingSystem != null)
{
Console.WriteLine("Warning: Unable to load filelist: {0}", ex);
}
Console.WriteLine("Error: Cannot specify --os when --all-platforms is specified.");
return 1;
}
ContentDownloader.Config.InstallDirectory = GetParameter<string>(args, "-dir");
ContentDownloader.Config.VerifyAll = HasParameter(args, "-verify-all") || HasParameter(args, "-verify_all") || HasParameter(args, "-validate");
ContentDownloader.Config.MaxServers = GetParameter(args, "-max-servers", 20);
ContentDownloader.Config.MaxDownloads = GetParameter(args, "-max-downloads", 8);
ContentDownloader.Config.MaxServers = Math.Max(ContentDownloader.Config.MaxServers, ContentDownloader.Config.MaxDownloads);
ContentDownloader.Config.LoginID = HasParameter(args, "-loginid") ? GetParameter<uint>(args, "-loginid") : null;
#endregion
if (ContentDownloader.Config.DownloadAllLanguages && arguments.Language != null)
{
Console.WriteLine("Error: Cannot specify --language when --all-languages is specified.");
return 1;
}
var appId = GetParameter(args, "-app", ContentDownloader.INVALID_APP_ID);
if (appId == ContentDownloader.INVALID_APP_ID)
var depotManifestIds = new List<(uint, ulong)>();
if (arguments.ManifestIDs.Count > 0)
{
if (arguments.DepotIDs.Count != arguments.ManifestIDs.Count)
{
Console.WriteLine("Error: -app not specified!");
Console.WriteLine("Error: --manifest requires one id for every --depot specified");
return 1;
}
var pubFile = GetParameter(args, "-pubfile", ContentDownloader.INVALID_MANIFEST_ID);
var ugcId = GetParameter(args, "-ugc", ContentDownloader.INVALID_MANIFEST_ID);
if (pubFile != ContentDownloader.INVALID_MANIFEST_ID)
var zippedDepotManifest = arguments.DepotIDs.Zip(arguments.ManifestIDs, (d, m) => (d, m));
depotManifestIds.AddRange(zippedDepotManifest);
}
else
{
#region Pubfile Downloading
depotManifestIds.AddRange(arguments.DepotIDs.Select(d => (d, ContentDownloader.INVALID_MANIFEST_ID)));
}
if (InitializeSteam(username, password))
if (InitializeSteam(arguments.Username, arguments.Password))
{
try
{
await ContentDownloader.DownloadPubfileAsync(appId, pubFile).ConfigureAwait(false);
await ContentDownloader.DownloadAppAsync(arguments.AppID,
depotManifestIds,
arguments.BetaBranchName,
arguments.OperatingSystem,
arguments.Architecture,
arguments.Language,
arguments.LowViolence,
false).ConfigureAwait(false);
}
catch (Exception ex) when (
ex is ContentDownloaderException
|| ex is OperationCanceledException)
catch (Exception ex) when (ex is ContentDownloaderException or OperationCanceledException)
{
Console.WriteLine(ex.Message);
return 1;
@ -139,21 +156,18 @@ namespace DepotDownloader
return 1;
}
#endregion
return 0;
}
else if (ugcId != ContentDownloader.INVALID_MANIFEST_ID)
{
#region UGC Downloading
if (InitializeSteam(username, password))
private static async Task<int> DownloadPubFileAsync(ProgramArgs args)
{
if (InitializeSteam(args.Username, args.Password))
{
try
{
await ContentDownloader.DownloadUGCAsync(appId, ugcId).ConfigureAwait(false);
await ContentDownloader.DownloadPubfileAsync(args.AppID, args.PubFile).ConfigureAwait(false);
}
catch (Exception ex) when (
ex is ContentDownloaderException
|| ex is OperationCanceledException)
catch (Exception ex) when (ex is ContentDownloaderException or OperationCanceledException)
{
Console.WriteLine(ex.Message);
return 1;
@ -174,67 +188,18 @@ namespace DepotDownloader
return 1;
}
#endregion
}
else
{
#region App downloading
var branch = GetParameter<string>(args, "-branch") ?? GetParameter<string>(args, "-beta") ?? ContentDownloader.DEFAULT_BRANCH;
ContentDownloader.Config.BetaPassword = GetParameter<string>(args, "-betapassword");
ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
var os = GetParameter<string>(args, "-os");
if (ContentDownloader.Config.DownloadAllPlatforms && !String.IsNullOrEmpty(os))
{
Console.WriteLine("Error: Cannot specify -os when -all-platforms is specified.");
return 1;
}
var arch = GetParameter<string>(args, "-osarch");
ContentDownloader.Config.DownloadAllLanguages = HasParameter(args, "-all-languages");
var language = GetParameter<string>(args, "-language");
if (ContentDownloader.Config.DownloadAllLanguages && !String.IsNullOrEmpty(language))
{
Console.WriteLine("Error: Cannot specify -language when -all-languages is specified.");
return 1;
}
var lv = HasParameter(args, "-lowviolence");
var depotManifestIds = new List<(uint, ulong)>();
var isUGC = false;
var depotIdList = GetParameterList<uint>(args, "-depot");
var manifestIdList = GetParameterList<ulong>(args, "-manifest");
if (manifestIdList.Count > 0)
{
if (depotIdList.Count != manifestIdList.Count)
{
Console.WriteLine("Error: -manifest requires one id for every -depot specified");
return 1;
return 0;
}
var zippedDepotManifest = depotIdList.Zip(manifestIdList, (depotId, manifestId) => (depotId, manifestId));
depotManifestIds.AddRange(zippedDepotManifest);
}
else
private static async Task<int> DownloadUGCAsync(ProgramArgs args)
{
depotManifestIds.AddRange(depotIdList.Select(depotId => (depotId, ContentDownloader.INVALID_MANIFEST_ID)));
}
if (InitializeSteam(username, password))
if (InitializeSteam(args.Username, args.Password))
{
try
{
await ContentDownloader.DownloadAppAsync(appId, depotManifestIds, branch, os, arch, language, lv, isUGC).ConfigureAwait(false);
await ContentDownloader.DownloadUGCAsync(args.AppID, args.UGC).ConfigureAwait(false);
}
catch (Exception ex) when (
ex is ContentDownloaderException
|| ex is OperationCanceledException)
catch (Exception ex) when (ex is ContentDownloaderException or OperationCanceledException)
{
Console.WriteLine(ex.Message);
return 1;
@ -255,146 +220,88 @@ namespace DepotDownloader
return 1;
}
#endregion
}
return 0;
}
static bool InitializeSteam(string username, string password)
private static async Task LoadFileListAsync(string fileList)
{
if (username != null && password == null && (!ContentDownloader.Config.RememberPassword || !AccountSettingsStore.Instance.LoginKeys.ContainsKey(username)))
try
{
do
var fileListData = await File.ReadAllTextAsync(fileList);
var files = fileListData.Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
ContentDownloader.Config.UsingFileList = true;
ContentDownloader.Config.FilesToDownload = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex = new List<Regex>();
foreach (var fileEntry in files)
{
Console.Write("Enter account password for \"{0}\": ", username);
if (Console.IsInputRedirected)
if (fileEntry.StartsWith("regex:"))
{
password = Console.ReadLine();
var rgx = new Regex(fileEntry.Substring(6), RegexOptions.Compiled | RegexOptions.IgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
}
else
{
// Avoid console echoing of password
password = Util.ReadPassword();
}
Console.WriteLine();
} while (String.Empty == password);
ContentDownloader.Config.FilesToDownload.Add(fileEntry.Replace('\\', '/'));
}
else if (username == null)
{
Console.WriteLine("No username given. Using anonymous account with dedicated server subscription.");
}
// capture the supplied password in case we need to re-use it after checking the login key
ContentDownloader.Config.SuppliedPassword = password;
return ContentDownloader.InitializeSteam3(username, password);
Console.WriteLine("Using file list: '{0}'.", fileList);
}
static int IndexOfParam(string[] args, string param)
{
for (var x = 0; x < args.Length; ++x)
catch (Exception ex)
{
if (args[x].Equals(param, StringComparison.OrdinalIgnoreCase))
return x;
Console.WriteLine("Warning: Unable to load file list: {0}", ex);
}
return -1;
}
static bool HasParameter(string[] args, string param)
private static bool InitializeSteam(string username, string password)
{
return IndexOfParam(args, param) > -1;
}
static T GetParameter<T>(string[] args, string param, T defaultValue = default(T))
if (username != null && password == null && (!ContentDownloader.Config.RememberPassword ||
!AccountSettingsStore.Instance.LoginKeys
.ContainsKey(username)))
{
var index = IndexOfParam(args, param);
if (index == -1 || index == (args.Length - 1))
return defaultValue;
var strParam = args[index + 1];
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
do
{
return (T)converter.ConvertFromString(strParam);
}
Console.Write("Enter account password for \"{0}\": ", username);
password = Console.IsInputRedirected ? Console.ReadLine() : Util.ReadPassword();
return default(T);
Console.WriteLine();
} while (string.Empty == password);
}
static List<T> GetParameterList<T>(string[] args, string param)
{
var list = new List<T>();
var index = IndexOfParam(args, param);
if (index == -1 || index == (args.Length - 1))
return list;
index++;
while (index < args.Length)
{
var strParam = args[index];
if (strParam[0] == '-') break;
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
else if (username == null)
{
list.Add((T)converter.ConvertFromString(strParam));
Console.WriteLine("No username given. Using anonymous account with dedicated server subscription.");
}
index++;
}
// capture the supplied password in case we need to re-use it after checking the login key
ContentDownloader.Config.SuppliedPassword = password;
return list;
return ContentDownloader.InitializeSteam3(username, password);
}
static void PrintUsage()
private static void PrintUsage()
{
Console.WriteLine($"DepotDownloader version {typeof(Program).Assembly.GetName().Version?.ToString(3)} - copyright SteamRE Team 2021");
Console.WriteLine();
Console.WriteLine("Usage - downloading one or all depots for an app:");
Console.WriteLine("\tdepotdownloader -app <id> [-depot <id> [-manifest <id>]]");
Console.WriteLine("\t\t[-username <username> [-password <password>]] [other options]");
Console.WriteLine(" Steam depot downloader utilizing the SteamKit2 library.");
Console.WriteLine(" https://github.com/SteamRE/DepotDownloader");
Console.WriteLine();
Console.WriteLine("Usage - downloading a workshop item using pubfile id");
Console.WriteLine("\tdepotdownloader -app <id> -pubfile <id> [-username <username> [-password <password>]]");
Console.WriteLine("Usage - downloading a workshop item using ugc id");
Console.WriteLine("\tdepotdownloader -app <id> -ugc <id> [-username <username> [-password <password>]]");
Console.WriteLine("Usage:");
Console.WriteLine();
Console.WriteLine("Parameters:");
Console.WriteLine("\t-app <#>\t\t\t\t- the AppID to download.");
Console.WriteLine("\t-depot <#>\t\t\t\t- the DepotID to download.");
Console.WriteLine("\t-manifest <id>\t\t\t- manifest id of content to download (requires -depot, default: current for branch).");
Console.WriteLine("\t-beta <branchname>\t\t\t- download from specified branch if available (default: Public).");
Console.WriteLine("\t-betapassword <pass>\t\t- branch password if applicable.");
Console.WriteLine("\t-all-platforms\t\t\t- downloads all platform-specific depots when -app is used.");
Console.WriteLine("\t-os <os>\t\t\t\t- the operating system for which to download the game (windows, macos or linux, default: OS the program is currently running on)");
Console.WriteLine("\t-osarch <arch>\t\t\t\t- the architecture for which to download the game (32 or 64, default: the host's architecture)");
Console.WriteLine("\t-all-languages\t\t\t\t- download all language-specific depots when -app is used.");
Console.WriteLine("\t-language <lang>\t\t\t\t- the language for which to download the game (default: english)");
Console.WriteLine("\t-lowviolence\t\t\t\t- download low violence depots when -app is used.");
Console.WriteLine(" Downloading one or all depots for an app:");
Console.WriteLine(" depotdownloader --app <id> [--depot <id> [--manifest <id>]]");
Console.WriteLine(" [--username <username> [--password <password>]] [other options]");
Console.WriteLine();
Console.WriteLine("\t-ugc <#>\t\t\t\t- the UGC ID to download.");
Console.WriteLine("\t-pubfile <#>\t\t\t- the PublishedFileId to download. (Will automatically resolve to UGC id)");
Console.WriteLine(" Downloading a workshop item using pubfile id");
Console.WriteLine(" depotdownloader --app <id> --pub-file <id> [--username <username> [--password <password>]]");
Console.WriteLine();
Console.WriteLine("\t-username <user>\t\t- the username of the account to login to for restricted content.");
Console.WriteLine("\t-password <pass>\t\t- the password of the account to login to for restricted content.");
Console.WriteLine("\t-remember-password\t\t- if set, remember the password for subsequent logins of this user.");
Console.WriteLine(" Downloading a workshop item using ugc id");
Console.WriteLine(" depotdownloader --app <id> --ugc <id> [--username <username> [--password <password>]]");
Console.WriteLine();
Console.WriteLine("\t-dir <installdir>\t\t- the directory in which to place downloaded files.");
Console.WriteLine("\t-filelist <file.txt>\t- a list of files to download (from the manifest). Prefix file path with 'regex:' if you want to match with regex.");
Console.WriteLine("\t-validate\t\t\t\t- Include checksum verification of files already downloaded");
Console.WriteLine("Parameters:");
Console.WriteLine();
Console.WriteLine("\t-manifest-only\t\t\t- downloads a human readable manifest for any depots that would be downloaded.");
Console.WriteLine("\t-cellid <#>\t\t\t\t- the overridden CellID of the content server to download from.");
Console.WriteLine("\t-max-servers <#>\t\t- maximum number of content servers to use. (default: 20).");
Console.WriteLine("\t-max-downloads <#>\t\t- maximum number of chunks to download concurrently. (default: 8).");
Console.WriteLine("\t-loginid <#>\t\t- a unique 32-bit integer Steam LogonID in decimal, required if running multiple instances of DepotDownloader concurrently.");
Console.WriteLine(ArgumentParser.GetHelpList<ProgramArgs>(2));
}
}
}

@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
namespace DepotDownloader
{
internal partial class Program
{
private class ProgramArgs : IArgumentContainer
{
public ProgramArgs()
{
AppID = ContentDownloader.INVALID_APP_ID;
DepotIDs = new List<uint>();
ManifestIDs = new List<ulong>();
ManifestOnly = false;
UGC = ContentDownloader.INVALID_MANIFEST_ID;
PubFile = ContentDownloader.INVALID_MANIFEST_ID;
Validate = false;
CellID = 0;
Username = "";
Password = "";
RememberPassword = false;
LoginID = null;
BetaBranchName = ContentDownloader.DEFAULT_BRANCH;
BetaPassword = "";
AllPlatforms = false;
OperatingSystem = "";
Architecture = Environment.Is64BitOperatingSystem ? "64" : "32";
AllLanguages = false;
Language = "";
LowViolence = false;
InstallDir = "";
FileList = null;
MaxServers = 20;
MaxDownloads = 8;
Debug = false;
}
[Option(ShortOption = 'a', LongOption = "app", ParameterName = "id",
Description = "The AppID to download")]
public uint AppID { get; set; }
[Option(ShortOption = 'd', LongOption = "depot", ParameterName = "id", AllowMultiple = true,
Description = "The DepotID to download, separate multiple ids with whitespace")]
public List<uint> DepotIDs { get; set;}
[Option(ShortOption = 'm', LongOption = "manifest", ParameterName = "id", AllowMultiple = true,
Description = "manifest id of content to download (requires -d|--depot, default: current for branch)")]
public List<ulong> ManifestIDs { get; set;}
[Option(LongOption = "manifest-only",
Description = "Downloads a human readable manifest for any depots that would be downloaded")]
public bool ManifestOnly { get; set;}
[Option(ShortOption = 'g', LongOption = "ugc", ParameterName = "id",
Description = "The UGC ID to download")]
public ulong UGC { get; set;}
[Option(LongOption = "pub-file", ParameterName = "id",
Description = "The Published-File-ID to download. (Will automatically resolve to UGC id)\n")]
public ulong PubFile { get; set;}
[Option(LongOption = "validate", Description = "Include checksum verification of files already downloaded")]
public bool Validate { get; set;}
[Option(ShortOption = 'c', LongOption = "cell-id", ParameterName = "id",
Description = "The overridden CellID of the content server to download from.")]
public int CellID { get; set;}
[Option(ShortOption = 'u', LongOption = "username", ParameterName = "user",
Description = "The username of the account to login to for restricted content")]
public string Username { get; set;}
[Option(ShortOption = 'p', LongOption = "password", ParameterName = "pass",
Description = "The password of the account to login to for restricted content.")]
public string Password { get;set; }
[Option(LongOption = "remember-password",
Description = "If set, remember the password for subsequent logins of this user\n")]
public bool RememberPassword { get; set;}
[Option(LongOption = "login-id", ParameterName = "id",
Description = "A unique 32-bit integer Steam LogonID in decimal, required if running multiple instances of DepotDownloader concurrently")]
public uint? LoginID { get; set;}
[Option(LongOption = "beta", ParameterName = "branch",
Description = "Download from specified beta branch if available (default: Public)")]
public string BetaBranchName { get; set;}
[Option(LongOption = "beta-password", ParameterName = "pass",
Description = "Beta branch password if applicable\n")]
public string BetaPassword { get; set;}
[Option(LongOption = "all-platforms",
Description = "Downloads all platform-specific depots when -a|--app is used")]
public bool AllPlatforms { get; set;}
[Option(ShortOption = 'o', LongOption = "os", ParameterName = "os",
Description = "The operating system for which to download the game (windows, macos or linux, default: OS the program is currently running on)")]
public string OperatingSystem { get; set;}
[Option(LongOption = "os-arch",
Description =
"The architecture for which to download the game (32 or 64, default: the host's architecture)\n",
ParameterName = "arch")]
public string Architecture { get; set;}
[Option(LongOption = "all-languages",
Description = "Download all language-specific depots when -a|--app is used")]
public bool AllLanguages { get; set;}
[Option(ShortOption = 'l', LongOption = "language", ParameterName = "lang",
Description = "The language for which to download the game (default: english)\n")]
public string Language { get; set;}
[Option(LongOption = "low-violence",
Description = "Download low violence depots when -a|--app is used")]
public bool LowViolence { get; set;}
[Option(LongOption = "install-dir", ParameterName = "dir",
Description = "The directory in which to place downloaded files")]
public string InstallDir { get; set;}
[Option(LongOption = "file-list", ParameterName = "file",
Description = "a list of files to download (from the manifest). Prefix file path with 'regex:' if you want to match with regex")]
public string FileList { get; set;}
[Option(LongOption = "max-servers", ParameterName = "count",
Description = "Maximum number of content servers to use (default: 20)")]
public int MaxServers { get; set;}
[Option(LongOption = "max-downloads", ParameterName = "count",
Description = "Maximum number of chunks to download concurrently (default: 8)")]
public int MaxDownloads { get; set;}
[Option(LongOption = "verbose",
Description = "Makes the DepotDownload more verbose/talkative. Mostly useful for debugging")]
public bool Debug { get; set;}
}
}
}
Loading…
Cancel
Save