diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index d05495c2..00000000 --- a/.editorconfig +++ /dev/null @@ -1,230 +0,0 @@ -# top-most EditorConfig file -root = true - -[*] -indent_style = space -charset = utf-8 -end_of_line = lf -insert_final_newline = true - -# Code files -[*.{cs, csx, vb, vbx}] -indent_size = 4 - -# XML project files -[*.{csproj, vbproj, vcxproj, vcxproj.filters, proj, projitems, shproj}] -indent_size = 2 - -# XML config files -[*.{props, targets, ruleset, config, nuspec, resx, vsixmanifest, vsct}] -indent_size = 2 - -# Dotnet code style settings: -[*.{cs, vb}] - -# IDE0055: Fix formatting -dotnet_diagnostic.IDE0055.severity = warning - -# Sort using and Import directives with System.* appearing first -dotnet_sort_system_directives_first = true -dotnet_separate_import_directive_groups = false -# Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false:refactoring -dotnet_style_qualification_for_property = false:refactoring -dotnet_style_qualification_for_method = false:refactoring -dotnet_style_qualification_for_event = false:refactoring - -# Use language keywords instead of framework type names for type references -dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion -dotnet_style_predefined_type_for_member_access = true:suggestion - -# Suggest more modern language features when available -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion - -# Non-private static fields are PascalCase -dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields -dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style - -dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field -dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected -dotnet_naming_symbols.non_private_static_fields.required_modifiers = static - -dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case - -# Non-private readonly fields are PascalCase -dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields -dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style - -dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field -dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected -dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly - -dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case - -# Constants are PascalCase -dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants -dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style - -dotnet_naming_symbols.constants.applicable_kinds = field, local -dotnet_naming_symbols.constants.required_modifiers = const - -dotnet_naming_style.constant_style.capitalization = pascal_case - -# Static readonly fields are PascalCase -dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion -dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields -dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style - -dotnet_naming_symbols.static_fields.applicable_kinds = field -dotnet_naming_symbols.static_fields.required_modifiers = static, readonly - -dotnet_naming_style.static_field_style.capitalization = pascal_case - -# Instance fields are camelCase and start with _ -dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion -dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields -dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style - -dotnet_naming_symbols.instance_fields.applicable_kinds = field - -dotnet_naming_style.instance_field_style.capitalization = camel_case -dotnet_naming_style.instance_field_style.required_prefix = _ - -# Locals and parameters are camelCase -dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion -dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters -dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style - -dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local - -dotnet_naming_style.camel_case_style.capitalization = camel_case - -# Local functions are PascalCase -dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions -dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style - -dotnet_naming_symbols.local_functions.applicable_kinds = local_function - -dotnet_naming_style.local_function_style.capitalization = pascal_case - -# By default, name items with PascalCase -dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members -dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style - -dotnet_naming_symbols.all_members.applicable_kinds = * - -dotnet_naming_style.pascal_case_style.capitalization = pascal_case - -# Async methods should have "Async" suffix -dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods -dotnet_naming_rule.async_methods_end_in_async.style = end_in_async -dotnet_naming_rule.async_methods_end_in_async.severity = warning - -dotnet_naming_symbols.any_async_methods.applicable_kinds = method -dotnet_naming_symbols.any_async_methods.applicable_accessibilities = * -dotnet_naming_symbols.any_async_methods.required_modifiers = async - -dotnet_naming_style.end_in_async.required_prefix = -dotnet_naming_style.end_in_async.required_suffix = Async -dotnet_naming_style.end_in_async.capitalization = pascal_case -dotnet_naming_style.end_in_async.word_separator = - -# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}' -dotnet_diagnostic.RS2008.severity = none - -# IDE0005: Remove unnecessary import -dotnet_diagnostic.IDE0005.severity = warning - -# IDE0007: Use `var` instead of explicit type -dotnet_diagnostic.IDE0007.severity = warning - -# IDE0035: Remove unreachable code -dotnet_diagnostic.IDE0035.severity = warning - -# IDE0036: Order modifiers -dotnet_diagnostic.IDE0036.severity = warning - -# IDE0043: Format string contains invalid placeholder -dotnet_diagnostic.IDE0043.severity = warning - -# IDE0044: Make field readonly -dotnet_diagnostic.IDE0044.severity = warning - -# CSharp code style settings: -[*.cs] -# Newline settings -csharp_new_line_before_open_brace = all -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true -# csharp_new_line_before_members_in_object_initializers = true TODO seems like Rider/ReSharper has the value inverted, uncomment when its fixed -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_between_query_expression_clauses = true - -# Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = false -csharp_indent_switch_labels = true -csharp_indent_labels = flush_left - -# Prefer "var" everywhere -csharp_style_var_for_built_in_types = true:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion - -# Prefer method-like constructs to have a block body -csharp_style_expression_bodied_methods = false:none -csharp_style_expression_bodied_constructors = false:none -csharp_style_expression_bodied_operators = false:none - -# Prefer property-like constructs to have an expression-body -csharp_style_expression_bodied_properties = true:none -csharp_style_expression_bodied_indexers = true:none -csharp_style_expression_bodied_accessors = true:none - -# Suggest more modern language features when available -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_throw_expression = true:suggestion -csharp_style_conditional_delegate_call = true:suggestion - -# Space preferences -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = do_not_ignore -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - -# Blocks are allowed -csharp_prefer_braces = true:silent -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index d9e2ae9c..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Bug Report -description: File a bug report -labels: [bug] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: textarea - id: what-should-have-happened - attributes: - label: What did you expect to happen? - placeholder: I expected that... - validations: - required: true - - type: textarea - id: what-actually-happened - attributes: - label: Instead of that, what actually happened? - placeholder: ... but instead, what happened was... - validations: - required: true - - type: dropdown - id: operating-system - attributes: - label: Which operating system are you running on? - options: - - Linux - - macOS - - Windows - - Other - validations: - required: true - - type: input - id: dotnet-version - attributes: - label: Version - description: What version of DepotDownloader are you running on? - validations: - required: true - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell - - type: textarea - id: additional-info - attributes: - label: Additional Information - description: Is there anything else that you think we should know? - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 47e6660c..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: true -contact_links: - - name: Discussions - url: https://github.com/SteamRE/DepotDownloader/discussions/new - about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index 72cbe5db..00000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Feature Request -description: Suggest an idea for this project -labels: [enhancement] -body: - - type: markdown - attributes: - value: | - Thanks, we appreciate good ideas! - - type: textarea - id: problem-area - attributes: - label: What problem is this feature trying to solve? - placeholder: I'm really frustrated when... - validations: - required: true - - type: textarea - id: proposed-solution - attributes: - label: How would you like it to be solved? - placeholder: I think that it could be solved by... - validations: - required: true - - type: textarea - id: alternative-solutions - attributes: - label: Have you considered any alternative solutions - placeholder: I did think that that it also could be solved by ..., but... - validations: - required: true - - type: textarea - id: additional-info - attributes: - label: Additional Information - description: Is there anything else that you think we should know? - validations: - required: false diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index c2cad660..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 2 -updates: -- package-ecosystem: nuget - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 - -- package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: weekly - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-minor", "version-update:semver-patch"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index c0725e41..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: .NET Core CI - -on: - push: - paths-ignore: - - '.github/*' - - '.github/*_TEMPLATE/**' - - '*.md' - pull_request: - paths-ignore: - - '.github/*' - - '.github/*_TEMPLATE/**' - - '*.md' - workflow_dispatch: - -jobs: - build: - name: .NET on ${{ matrix.runs-on }} (${{ matrix.configuration }}) - runs-on: ${{ matrix.runs-on }} - strategy: - fail-fast: false - matrix: - runs-on: [macos-latest, macos-14, ubuntu-latest, windows-latest] - configuration: [Release, Debug] - env: - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET Core - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - - name: Build - run: dotnet publish DepotDownloader/DepotDownloader.csproj -c ${{ matrix.configuration }} -o artifacts - - - name: Upload artifact - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'windows-latest' - with: - name: DepotDownloader-framework - path: artifacts - if-no-files-found: error - - - name: Publish Windows-x64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'windows-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime win-x64 --output selfcontained-win-x64 - - - name: Publish Windows-arm64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'windows-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime win-arm64 --output selfcontained-win-arm64 - - - name: Publish Linux-x64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime linux-x64 --output selfcontained-linux-x64 - - - name: Publish Linux-arm - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime linux-arm --output selfcontained-linux-arm - - - name: Publish Linux-arm64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime linux-arm64 --output selfcontained-linux-arm64 - - - name: Publish macOS-x64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'macos-latest' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime osx-x64 --output selfcontained-osx-x64 - - - name: Publish macOS-arm64 - if: matrix.configuration == 'Release' && matrix.runs-on == 'macos-14' - run: dotnet publish DepotDownloader/DepotDownloader.csproj --configuration Release -p:PublishSingleFile=true -p:DebugType=embedded --self-contained --runtime osx-arm64 --output selfcontained-osx-arm64 - - - name: Upload Windows-x64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'windows-latest' - with: - name: DepotDownloader-windows-x64 - path: selfcontained-win-x64 - if-no-files-found: error - - - name: Upload Windows-arm64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'windows-latest' - with: - name: DepotDownloader-windows-arm64 - path: selfcontained-win-arm64 - if-no-files-found: error - - - name: Upload Linux-x64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - with: - name: DepotDownloader-linux-x64 - path: selfcontained-linux-x64 - if-no-files-found: error - - - name: Upload Linux-arm - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - with: - name: DepotDownloader-linux-arm - path: selfcontained-linux-arm - if-no-files-found: error - - - name: Upload Linux-arm64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'ubuntu-latest' - with: - name: DepotDownloader-linux-arm64 - path: selfcontained-linux-arm64 - if-no-files-found: error - - - name: Upload macOS-x64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'macos-latest' - with: - name: DepotDownloader-macos-x64 - path: selfcontained-osx-x64 - if-no-files-found: error - - - name: Upload macOS-arm64 - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' && matrix.runs-on == 'macos-14' - with: - name: DepotDownloader-macos-arm64 - path: selfcontained-osx-arm64 - if-no-files-found: error diff --git a/.github/workflows/sk2-ci.yml b/.github/workflows/sk2-ci.yml deleted file mode 100644 index 8827a46f..00000000 --- a/.github/workflows/sk2-ci.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: SteamKit2 Continuous Integration - -on: - schedule: - - cron: '0 1 * * SUN' - workflow_dispatch: - -jobs: - build: - name: .NET on ${{ matrix.runs-on }} (${{ matrix.configuration }}) - runs-on: ${{ matrix.runs-on }} - strategy: - fail-fast: false - matrix: - runs-on: [ macos-latest, macos-14, ubuntu-latest, windows-latest ] - configuration: [ Release, Debug ] - env: - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET Core - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - - name: Configure NuGet - run: | - dotnet nuget add source --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/SteamRE/index.json" - dotnet add DepotDownloader/DepotDownloader.csproj package SteamKit2 --prerelease - - - name: Build - run: dotnet publish DepotDownloader/DepotDownloader.csproj -c ${{ matrix.configuration }} -o artifacts - - - name: Upload artifact - uses: actions/upload-artifact@v4 - if: matrix.configuration == 'Release' - with: - name: DepotDownloader-${{ runner.os }} - path: artifacts - if-no-files-found: error diff --git a/DepotDownloader.sln b/DepotDownloader.sln deleted file mode 100644 index 631e75ec..00000000 --- a/DepotDownloader.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DepotDownloader", "DepotDownloader\DepotDownloader.csproj", "{39159C47-ACD3-449F-96CA-4F30C8ED147A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {39159C47-ACD3-449F-96CA-4F30C8ED147A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39159C47-ACD3-449F-96CA-4F30C8ED147A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39159C47-ACD3-449F-96CA-4F30C8ED147A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39159C47-ACD3-449F-96CA-4F30C8ED147A}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs index d9191610..cd14fc5c 100644 --- a/DepotDownloader/ContentDownloader.cs +++ b/DepotDownloader/ContentDownloader.cs @@ -81,11 +81,14 @@ namespace DepotDownloader static bool TestIsFileIncluded(string filename) { + if (!Config.UsingFileList) return true; filename = filename.Replace('\\', '/'); + filename = Path.GetFileName(filename); + if (Config.FilesToDownload.Contains(filename)) { return true; @@ -371,7 +374,7 @@ namespace DepotDownloader var stagingDir = Path.Combine(installDir, STAGING_DIR); var fileStagingPath = Path.Combine(stagingDir, fileName); - var fileFinalPath = Path.Combine(installDir, fileName); + var fileFinalPath = Path.Combine(installDir, Path.GetFileName(fileName)); Directory.CreateDirectory(Path.GetDirectoryName(fileFinalPath)); Directory.CreateDirectory(Path.GetDirectoryName(fileStagingPath)); @@ -379,7 +382,6 @@ namespace DepotDownloader using (var file = File.OpenWrite(fileStagingPath)) using (var client = HttpClientFactory.CreateHttpClient()) { - Console.WriteLine("Downloading {0}", fileName); var responseStream = await client.GetStreamAsync(url); await responseStream.CopyToAsync(file); } @@ -442,8 +444,6 @@ namespace DepotDownloader } else { - Console.WriteLine("Using app branch: '{0}'.", branch); - if (depots != null) { foreach (var depotSection in depots.Children) @@ -664,17 +664,12 @@ namespace DepotDownloader { await DownloadSteam3AsyncDepotFiles(cts, downloadCounter, depotFileData, allFileNamesAllDepots); } - - Console.WriteLine("Total downloaded: {0} bytes ({1} bytes uncompressed) from {2} depots", - downloadCounter.TotalBytesCompressed, downloadCounter.TotalBytesUncompressed, depots.Count); } private static async Task ProcessDepotManifestAndFiles(CancellationTokenSource cts, DepotDownloadInfo depot) { var depotCounter = new DepotDownloadCounter(); - Console.WriteLine("Processing depot {0}", depot.DepotId); - ProtoManifest oldProtoManifest = null; ProtoManifest newProtoManifest = null; var configDir = Path.Combine(depot.InstallDir, CONFIG_DIR); @@ -707,9 +702,6 @@ namespace DepotDownloader if (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum)) { - // We only have to show this warning if the old manifest ID was different - if (lastManifestId != depot.ManifestId) - Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", lastManifestId); oldProtoManifest = null; } } @@ -718,7 +710,6 @@ namespace DepotDownloader if (lastManifestId == depot.ManifestId && oldProtoManifest != null) { newProtoManifest = oldProtoManifest; - Console.WriteLine("Already have manifest {0} for depot {1}.", depot.ManifestId, depot.DepotId); } else { @@ -740,7 +731,6 @@ namespace DepotDownloader if (newProtoManifest != null && (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum))) { - Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", depot.ManifestId); newProtoManifest = null; } } @@ -751,8 +741,6 @@ namespace DepotDownloader } else { - Console.Write("Downloading depot manifest..."); - DepotManifest depotManifest = null; ulong manifestRequestCode = 0; var manifestRequestCodeExpiration = DateTime.MinValue; @@ -789,11 +777,6 @@ namespace DepotDownloader } } - DebugLog.WriteLine("ContentDownloader", - "Downloading manifest {0} from {1} with {2}", - depot.ManifestId, - connection, - cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); depotManifest = await cdnPool.CDNClient.DownloadManifestAsync( depot.DepotId, depot.ManifestId, @@ -850,15 +833,11 @@ namespace DepotDownloader newProtoManifest = new ProtoManifest(depotManifest, depot.ManifestId); newProtoManifest.SaveToFile(newManifestFileName, out var checksum); File.WriteAllBytes(newManifestFileName + ".sha", checksum); - - Console.WriteLine(" Done!"); } } newProtoManifest.Files.Sort((x, y) => string.Compare(x.FileName, y.FileName, StringComparison.Ordinal)); - Console.WriteLine("Manifest {0} ({1})", depot.ManifestId, newProtoManifest.CreationTime); - if (Config.DownloadManifestOnly) { DumpManifestToTextFile(depot, newProtoManifest); @@ -875,20 +854,8 @@ namespace DepotDownloader { allFileNames.Add(file.FileName); - var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName); - var fileStagingPath = Path.Combine(stagingDir, file.FileName); - - if (file.Flags.HasFlag(EDepotFileFlag.Directory)) - { - Directory.CreateDirectory(fileFinalPath); - Directory.CreateDirectory(fileStagingPath); - } - else + if (!file.Flags.HasFlag(EDepotFileFlag.Directory)) { - // Some manifests don't explicitly include all necessary directories - Directory.CreateDirectory(Path.GetDirectoryName(fileFinalPath)); - Directory.CreateDirectory(Path.GetDirectoryName(fileStagingPath)); - depotCounter.CompleteDownloadSize += file.TotalSize; } }); @@ -911,8 +878,6 @@ namespace DepotDownloader var depot = depotFilesData.depotDownloadInfo; var depotCounter = depotFilesData.depotCounter; - Console.WriteLine("Downloading depot {0}", depot.DepotId); - var files = depotFilesData.filteredFiles.Where(f => !f.Flags.HasFlag(EDepotFileFlag.Directory)).ToArray(); var networkChunkQueue = new ConcurrentQueue<(FileStreamData fileStreamData, ProtoManifest.FileData fileData, ProtoManifest.ChunkData chunk)>(); @@ -948,20 +913,17 @@ namespace DepotDownloader foreach (var existingFileName in previousFilteredFiles) { - var fileFinalPath = Path.Combine(depot.InstallDir, existingFileName); + var fileFinalPath = Path.Combine(depot.InstallDir, Path.GetFileName(existingFileName)); if (!File.Exists(fileFinalPath)) continue; File.Delete(fileFinalPath); - Console.WriteLine("Deleted {0}", fileFinalPath); } } DepotConfigStore.Instance.InstalledManifestIDs[depot.DepotId] = depot.ManifestId; DepotConfigStore.Save(); - - Console.WriteLine("Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.DepotId, depotCounter.DepotBytesCompressed, depotCounter.DepotBytesUncompressed); } private static void DownloadSteam3AsyncDepotFile( @@ -982,8 +944,10 @@ namespace DepotDownloader oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName); } - var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName); - var fileStagingPath = Path.Combine(stagingDir, file.FileName); + var name = Path.GetFileName(file.FileName); + + var fileFinalPath = Path.Combine(depot.InstallDir, name); + var fileStagingPath = Path.Combine(stagingDir, name); // This may still exist if the previous run exited before cleanup if (File.Exists(fileStagingPath)) @@ -996,8 +960,6 @@ namespace DepotDownloader var fileDidExist = fi.Exists; if (!fileDidExist) { - Console.WriteLine("Pre-allocating {0}", fileFinalPath); - // create new file. need all chunks using var fs = File.Create(fileFinalPath); try @@ -1021,12 +983,6 @@ namespace DepotDownloader var hashMatches = oldManifestFile.FileHash.SequenceEqual(file.FileHash); if (Config.VerifyAll || !hashMatches) { - // we have a version of this file, but it doesn't fully match what we want - if (Config.VerifyAll) - { - Console.WriteLine("Validating {0}", fileFinalPath); - } - var matchingChunks = new List(); foreach (var chunk in file.Chunks) @@ -1116,7 +1072,6 @@ namespace DepotDownloader } } - Console.WriteLine("Validating {0}", fileFinalPath); neededChunks = Util.ValidateSteam3FileChecksums(fs, [.. file.Chunks.OrderBy(x => x.Offset)]); } @@ -1125,9 +1080,9 @@ namespace DepotDownloader lock (depotDownloadCounter) { depotDownloadCounter.SizeDownloaded += file.TotalSize; - Console.WriteLine("{0,6:#00.00}% {1}", (depotDownloadCounter.SizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath); } + Console.WriteLine($"Downloaded {fileFinalPath}"); return; } @@ -1196,8 +1151,6 @@ namespace DepotDownloader try { connection = cdnPool.GetConnection(cts.Token); - - DebugLog.WriteLine("ContentDownloader", "Downloading chunk {0} from {1} with {2}", chunkID, connection, cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); chunkData = await cdnPool.CDNClient.DownloadDepotChunkAsync( depot.DepotId, data, @@ -1249,7 +1202,7 @@ namespace DepotDownloader if (fileStreamData.fileStream == null) { - var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName); + var fileFinalPath = Path.Combine(depot.InstallDir, Path.GetFileName(file.FileName)); fileStreamData.fileStream = File.Open(fileFinalPath, FileMode.Open); } @@ -1282,12 +1235,6 @@ namespace DepotDownloader downloadCounter.TotalBytesCompressed += chunk.CompressedLength; downloadCounter.TotalBytesUncompressed += chunk.UncompressedLength; } - - if (remainingChunks == 0) - { - var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName); - Console.WriteLine("{0,6:#00.00}% {1}", (sizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath); - } } static void DumpManifestToTextFile(DepotDownloadInfo depot, ProtoManifest manifest) diff --git a/DepotDownloader/DepotDownloader.csproj b/DepotDownloader/DepotDownloader.csproj deleted file mode 100644 index 47cfd284..00000000 --- a/DepotDownloader/DepotDownloader.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - Exe - net8.0 - true - LatestMajor - 2.6.0 - Steam Downloading Utility - SteamRE Team - Copyright © SteamRE Team 2024 - ..\Icon\DepotDownloader.ico - true - - - - - - - - diff --git a/DepotDownloader/Program.cs b/DepotDownloader/Program.cs deleted file mode 100644 index 14f7f88d..00000000 --- a/DepotDownloader/Program.cs +++ /dev/null @@ -1,410 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using SteamKit2; - -namespace DepotDownloader -{ - class Program - { - static int Main(string[] args) - => MainAsync(args).GetAwaiter().GetResult(); - - internal static readonly char[] newLineCharacters = ['\n', '\r']; - - static async Task MainAsync(string[] args) - { - if (args.Length == 0) - { - PrintUsage(); - return 1; - } - - DebugLog.Enabled = false; - - AccountSettingsStore.LoadFromFile("account.config"); - - #region Common Options - - if (HasParameter(args, "-debug")) - { - DebugLog.Enabled = true; - DebugLog.AddListener((category, message) => - { - Console.WriteLine("[{0}] {1}", category, message); - }); - - var httpEventListener = new HttpDiagnosticEventListener(); - - DebugLog.WriteLine("DepotDownloader", "Version: {0}", Assembly.GetExecutingAssembly().GetName().Version); - DebugLog.WriteLine("DepotDownloader", "Runtime: {0}", RuntimeInformation.FrameworkDescription); - } - - var username = GetParameter(args, "-username") ?? GetParameter(args, "-user"); - var password = GetParameter(args, "-password") ?? GetParameter(args, "-pass"); - ContentDownloader.Config.RememberPassword = HasParameter(args, "-remember-password"); - ContentDownloader.Config.UseQrCode = HasParameter(args, "-qr"); - - ContentDownloader.Config.DownloadManifestOnly = HasParameter(args, "-manifest-only"); - - var cellId = GetParameter(args, "-cellid", -1); - if (cellId == -1) - { - cellId = 0; - } - - ContentDownloader.Config.CellID = cellId; - - var fileList = GetParameter(args, "-filelist"); - - if (fileList != null) - { - const string RegexPrefix = "regex:"; - - try - { - var fileListData = await File.ReadAllTextAsync(fileList); - var files = fileListData.Split(newLineCharacters, StringSplitOptions.RemoveEmptyEntries); - - ContentDownloader.Config.UsingFileList = true; - ContentDownloader.Config.FilesToDownload = new HashSet(StringComparer.OrdinalIgnoreCase); - ContentDownloader.Config.FilesToDownloadRegex = []; - - foreach (var fileEntry in files) - { - if (fileEntry.StartsWith(RegexPrefix)) - { - var rgx = new Regex(fileEntry[RegexPrefix.Length..], RegexOptions.Compiled | RegexOptions.IgnoreCase); - ContentDownloader.Config.FilesToDownloadRegex.Add(rgx); - } - else - { - ContentDownloader.Config.FilesToDownload.Add(fileEntry.Replace('\\', '/')); - } - } - - Console.WriteLine("Using filelist: '{0}'.", fileList); - } - catch (Exception ex) - { - Console.WriteLine("Warning: Unable to load filelist: {0}", ex); - } - } - - ContentDownloader.Config.InstallDirectory = GetParameter(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(args, "-loginid") : null; - - #endregion - - var appId = GetParameter(args, "-app", ContentDownloader.INVALID_APP_ID); - if (appId == ContentDownloader.INVALID_APP_ID) - { - Console.WriteLine("Error: -app not 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) - { - #region Pubfile Downloading - - if (InitializeSteam(username, password)) - { - try - { - await ContentDownloader.DownloadPubfileAsync(appId, pubFile).ConfigureAwait(false); - } - catch (Exception ex) when ( - ex is ContentDownloaderException - || ex is OperationCanceledException) - { - Console.WriteLine(ex.Message); - return 1; - } - catch (Exception e) - { - Console.WriteLine("Download failed to due to an unhandled exception: {0}", e.Message); - throw; - } - finally - { - ContentDownloader.ShutdownSteam3(); - } - } - else - { - Console.WriteLine("Error: InitializeSteam failed"); - return 1; - } - - #endregion - } - else if (ugcId != ContentDownloader.INVALID_MANIFEST_ID) - { - #region UGC Downloading - - if (InitializeSteam(username, password)) - { - try - { - await ContentDownloader.DownloadUGCAsync(appId, ugcId).ConfigureAwait(false); - } - catch (Exception ex) when ( - ex is ContentDownloaderException - || ex is OperationCanceledException) - { - Console.WriteLine(ex.Message); - return 1; - } - catch (Exception e) - { - Console.WriteLine("Download failed to due to an unhandled exception: {0}", e.Message); - throw; - } - finally - { - ContentDownloader.ShutdownSteam3(); - } - } - else - { - Console.WriteLine("Error: InitializeSteam failed"); - return 1; - } - - #endregion - } - else - { - #region App downloading - - var branch = GetParameter(args, "-branch") ?? GetParameter(args, "-beta") ?? ContentDownloader.DEFAULT_BRANCH; - ContentDownloader.Config.BetaPassword = GetParameter(args, "-betapassword"); - - ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms"); - var os = GetParameter(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(args, "-osarch"); - - ContentDownloader.Config.DownloadAllLanguages = HasParameter(args, "-all-languages"); - var language = GetParameter(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(args, "-depot"); - var manifestIdList = GetParameterList(args, "-manifest"); - if (manifestIdList.Count > 0) - { - if (depotIdList.Count != manifestIdList.Count) - { - Console.WriteLine("Error: -manifest requires one id for every -depot specified"); - return 1; - } - - var zippedDepotManifest = depotIdList.Zip(manifestIdList, (depotId, manifestId) => (depotId, manifestId)); - depotManifestIds.AddRange(zippedDepotManifest); - } - else - { - depotManifestIds.AddRange(depotIdList.Select(depotId => (depotId, ContentDownloader.INVALID_MANIFEST_ID))); - } - - if (InitializeSteam(username, password)) - { - try - { - await ContentDownloader.DownloadAppAsync(appId, depotManifestIds, branch, os, arch, language, lv, isUGC).ConfigureAwait(false); - } - catch (Exception ex) when ( - ex is ContentDownloaderException - || ex is OperationCanceledException) - { - Console.WriteLine(ex.Message); - return 1; - } - catch (Exception e) - { - Console.WriteLine("Download failed to due to an unhandled exception: {0}", e.Message); - throw; - } - finally - { - ContentDownloader.ShutdownSteam3(); - } - } - else - { - Console.WriteLine("Error: InitializeSteam failed"); - return 1; - } - - #endregion - } - - return 0; - } - - static bool InitializeSteam(string username, string password) - { - if (!ContentDownloader.Config.UseQrCode) - { - if (username != null && password == null && (!ContentDownloader.Config.RememberPassword || !AccountSettingsStore.Instance.LoginTokens.ContainsKey(username))) - { - do - { - Console.Write("Enter account password for \"{0}\": ", username); - if (Console.IsInputRedirected) - { - password = Console.ReadLine(); - } - else - { - // Avoid console echoing of password - password = Util.ReadPassword(); - } - - Console.WriteLine(); - } while (string.Empty == password); - } - else if (username == null) - { - Console.WriteLine("No username given. Using anonymous account with dedicated server subscription."); - } - } - - return ContentDownloader.InitializeSteam3(username, password); - } - - static int IndexOfParam(string[] args, string param) - { - for (var x = 0; x < args.Length; ++x) - { - if (args[x].Equals(param, StringComparison.OrdinalIgnoreCase)) - return x; - } - - return -1; - } - - static bool HasParameter(string[] args, string param) - { - return IndexOfParam(args, param) > -1; - } - - static T GetParameter(string[] args, string param, T defaultValue = default) - { - 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) - { - return (T)converter.ConvertFromString(strParam); - } - - return default; - } - - static List GetParameterList(string[] args, string param) - { - var list = new List(); - 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) - { - list.Add((T)converter.ConvertFromString(strParam)); - } - - index++; - } - - return list; - } - - static void PrintUsage() - { - Console.WriteLine(); - Console.WriteLine("Usage - downloading one or all depots for an app:"); - Console.WriteLine("\tdepotdownloader -app [-depot [-manifest ]]"); - Console.WriteLine("\t\t[-username [-password ]] [other options]"); - Console.WriteLine(); - Console.WriteLine("Usage - downloading a workshop item using pubfile id"); - Console.WriteLine("\tdepotdownloader -app -pubfile [-username [-password ]]"); - Console.WriteLine("Usage - downloading a workshop item using ugc id"); - Console.WriteLine("\tdepotdownloader -app -ugc [-username [-password ]]"); - 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 \t\t\t- manifest id of content to download (requires -depot, default: current for branch)."); - Console.WriteLine($"\t-beta \t\t\t- download from specified branch if available (default: {ContentDownloader.DEFAULT_BRANCH})."); - Console.WriteLine("\t-betapassword \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 \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 \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 \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(); - 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(); - Console.WriteLine("\t-username \t\t- the username of the account to login to for restricted content."); - Console.WriteLine("\t-password \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. (Use -username -remember-password as login credentials)"); - Console.WriteLine(); - Console.WriteLine("\t-dir \t\t- the directory in which to place downloaded files."); - Console.WriteLine("\t-filelist \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(); - 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."); - } - } -} diff --git a/DepotDownloader/Steam3Session.cs b/DepotDownloader/Steam3Session.cs index d2ee88ab..d95f85c3 100644 --- a/DepotDownloader/Steam3Session.cs +++ b/DepotDownloader/Steam3Session.cs @@ -81,7 +81,6 @@ namespace DepotDownloader this.callbacks.Subscribe(LogOnCallback); this.callbacks.Subscribe(LicenseListCallback); - Console.Write("Connecting to Steam3..."); Connect(); } @@ -155,7 +154,6 @@ namespace DepotDownloader { var app = app_value.Value; - Console.WriteLine("Got AppInfo for {0}", app.ID); AppInfo[app.ID] = app; } @@ -250,7 +248,6 @@ namespace DepotDownloader Action cbMethod = depotKey => { completed = true; - Console.WriteLine("Got depot key for {0} result: {1}", depotKey.DepotID, depotKey.Result); if (depotKey.Result != EResult.OK) { @@ -275,10 +272,6 @@ namespace DepotDownloader var requestCode = await steamContent.GetManifestRequestCode(depotId, appId, manifestId, branch); - Console.WriteLine("Got manifest request code for {0} {1} result: {2}", - depotId, manifestId, - requestCode); - return requestCode; } @@ -431,7 +424,6 @@ namespace DepotDownloader private async void ConnectedCallback(SteamClient.ConnectedCallback connected) { - Console.WriteLine(" Done!"); bConnecting = false; bConnected = true; @@ -442,7 +434,6 @@ namespace DepotDownloader if (!authenticatedUser) { - Console.Write("Logging anonymously into Steam3..."); steamUser.LogOnAnonymous(); } else @@ -674,14 +665,11 @@ namespace DepotDownloader return; } - Console.WriteLine(" Done!"); - this.seq++; IsLoggedOn = true; if (ContentDownloader.Config.CellID == 0) { - Console.WriteLine("Using Steam3 suggested CellID: " + loggedOn.CellID); ContentDownloader.Config.CellID = (int)loggedOn.CellID; } } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..51a032f3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +WORKDIR /app + +COPY . ./ + +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/runtime:8.0 +WORKDIR /app + +COPY --from=build-env /app/out . + +ENTRYPOINT ["dotnet", "/app/SCPSL.DownloadFiles.dll"] \ No newline at end of file diff --git a/Icon/DepotDownloader.ico b/Icon/DepotDownloader.ico deleted file mode 100644 index 6b0c58ce..00000000 Binary files a/Icon/DepotDownloader.ico and /dev/null differ diff --git a/Icon/DepotDownloader.png b/Icon/DepotDownloader.png deleted file mode 100644 index dac5e74c..00000000 Binary files a/Icon/DepotDownloader.png and /dev/null differ diff --git a/Icon/DepotDownloader.svg b/Icon/DepotDownloader.svg deleted file mode 100644 index ab1d371a..00000000 --- a/Icon/DepotDownloader.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d159169d..00000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Program.cs b/Program.cs new file mode 100644 index 00000000..11827248 --- /dev/null +++ b/Program.cs @@ -0,0 +1,53 @@ +using McMaster.Extensions.CommandLineUtils; +using Microsoft.Extensions.Hosting; +using DepotDownloader; + +await Host.CreateDefaultBuilder() + .RunCommandLineApplicationAsync(args); + +[Command(Description = "Downloads SCP: SL assembly files.")] +public class AppCommand +{ + [Option(Description = "Branch.")] + public string Branch { get; set; } = ContentDownloader.DEFAULT_BRANCH; + + [Option(Description = "Files to download.")] + public string FilesToDownload { get; set; } = "Assembly-CSharp.dll"; + + public async Task OnExecute(IConsole console) + { + try + { + string refPath = ".\\References"; + + if (!Directory.Exists(refPath)) + Directory.CreateDirectory(refPath); + + AccountSettingsStore.LoadFromFile("account.config"); + + ContentDownloader.Config.InstallDirectory = refPath; + + ContentDownloader.Config.MaxServers = 20; + ContentDownloader.Config.MaxDownloads = 8; + + ContentDownloader.Config.UsingFileList = true; + ContentDownloader.Config.FilesToDownloadRegex = new(); + ContentDownloader.Config.FilesToDownload = FilesToDownload.Split(",").ToHashSet(); + + if (ContentDownloader.InitializeSteam3(null, null)) + { + Console.WriteLine("Start downloading files..."); + await ContentDownloader.DownloadAppAsync(996560, new List<(uint depotId, ulong manifestId)>(), Branch, "windows", null, null, false, false).ConfigureAwait(false); + } + + Console.WriteLine("Files downloaded!"); + return 0; + } + catch (Exception ex) + { + console.WriteLine(ex); + return 1; + } + } + +} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 68fdaffd..00000000 --- a/README.md +++ /dev/null @@ -1,67 +0,0 @@ -DepotDownloader -=============== - -Steam depot downloader utilizing the SteamKit2 library. Supports .NET 8.0 - -### Downloading one or all depots for an app -``` -dotnet DepotDownloader.dll -app [-depot [-manifest ]] - [-username [-password ]] [other options] -``` - -For example: `dotnet DepotDownloader.dll -app 730 -depot 731 -manifest 7617088375292372759` - -### Downloading a workshop item using pubfile id -``` -dotnet DepotDownloader.dll -app -pubfile [-username [-password ]] -``` - -For example: `dotnet DepotDownloader.dll -app 730 -pubfile 1885082371` - -### Downloading a workshop item using ugc id -``` -dotnet DepotDownloader.dll -app -ugc [-username [-password ]] -``` - -For example: `dotnet DepotDownloader.dll -app 730 -ugc 770604181014286929` - -## Parameters - -Parameter | Description ---------- | ----------- --app \<#> | the AppID to download. --depot \<#> | the DepotID to download. --manifest \ | manifest id of content to download (requires -depot, default: current for branch). --ugc \<#> | the UGC ID to download. --beta \ | download from specified branch if available (default: Public). --betapassword \ | branch password if applicable. --all-platforms | downloads all platform-specific depots when -app is used. --os \ | the operating system for which to download the game (windows, macos or linux, default: OS the program is currently running on) --osarch \ | the architecture for which to download the game (32 or 64, default: the host's architecture) --all-languages | download all language-specific depots when -app is used. --language \ | the language for which to download the game (default: english) --lowviolence | download low violence depots when -app is used. --pubfile \<#> | the PublishedFileId to download. (Will automatically resolve to UGC id) --username \ | the username of the account to login to for restricted content. --password \ | the password of the account to login to for restricted content. --remember-password | if set, remember the password for subsequent logins of this user. (Use -username -remember-password as login credentials) --dir \ | the directory in which to place downloaded files. --filelist \ | a list of files to download (from the manifest). Prefix file path with `regex:` if you want to match with regex. --validate | Include checksum verification of files already downloaded --manifest-only | downloads a human readable manifest for any depots that would be downloaded. --cellid \<#> | the overridden CellID of the content server to download from. --max-servers \<#> | maximum number of content servers to use. (default: 20). --max-downloads \<#> | maximum number of chunks to download concurrently. (default: 8). --loginid \<#> | a unique 32-bit integer Steam LogonID in decimal, required if running multiple instances of DepotDownloader concurrently. - - -## Frequently Asked Questions - -### Why am I prompted to enter a 2-factor code every time I run the app? -Your 2-factor code authenticates a Steam session. You need to "remember" your session with `-remember-password` which persists the login key for your Steam session. - -### Can I run DepotDownloader while an account is already connected to Steam? -Any connection to Steam will be closed if they share a LoginID. You can specify a different LoginID with `-loginid`. - -### Why doesn't my password containing special characters work? Do I have to specify the password on the command line? -If you pass the `-password` parameter with a password that contains special characters, you will need to escape the command appropriately for the shell you are using. You do not have to include the `-password` parameter on the command line as long as you include a `-username`. You will be prompted to enter your password interactively. diff --git a/SCPSL.DownloadFiles.csproj b/SCPSL.DownloadFiles.csproj new file mode 100644 index 00000000..2c67a9f9 --- /dev/null +++ b/SCPSL.DownloadFiles.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + latest + + + + + + + + + + + + diff --git a/SCPSL.DownloadFiles.sln b/SCPSL.DownloadFiles.sln new file mode 100644 index 00000000..73a72fdb --- /dev/null +++ b/SCPSL.DownloadFiles.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34607.119 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCPSL.DownloadFiles", "SCPSL.DownloadFiles.csproj", "{4BFC0F11-647F-4096-A633-58C0592B81EE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4BFC0F11-647F-4096-A633-58C0592B81EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BFC0F11-647F-4096-A633-58C0592B81EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BFC0F11-647F-4096-A633-58C0592B81EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BFC0F11-647F-4096-A633-58C0592B81EE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0760B22E-EDAA-4317-9EE2-8EC540D8BBF2} + EndGlobalSection +EndGlobal diff --git a/action.yml b/action.yml new file mode 100644 index 00000000..49286966 --- /dev/null +++ b/action.yml @@ -0,0 +1,20 @@ +name: "SCPSL.DownloadFiles" +description: "Downloads SCP: SL assembly files." +branding: + icon: file + color: blue +inputs: + filestodownload: + description: "Files which will be downloaded." + required: true + branch: + description: "From which branch files will be downloaded." + required: false +runs: + using: "docker" + image: "Dockerfile" + args: + - "--filestodownload" + - ${{ inputs.filestodownload }} + - "--branch" + - ${{ inputs.branch }} \ No newline at end of file diff --git a/global.json b/global.json deleted file mode 100644 index c19a2e05..00000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sdk": { - "version": "8.0.100", - "rollForward": "latestMinor" - } -}