From 8d0d3e8a7e76bf324b9a006dc225d91877c53051 Mon Sep 17 00:00:00 2001 From: Scighost Date: Sat, 18 Jan 2025 21:23:35 +0800 Subject: [PATCH] game chunk and patch build --- src/Starward.Core/HoYoPlay/GameBranch.cs | 2 +- src/Starward.Core/HoYoPlay/GameChunkBuild.cs | 81 +++++++++++++----- src/Starward.Core/HoYoPlay/GamePatchBuild.cs | 85 +++++++++++++++++++ src/Starward.Core/HoYoPlay/HoYoPlayClient.cs | 65 ++++++++++++-- .../HoYoPlay/HoYoPlayJsonContext.cs | 1 + 5 files changed, 205 insertions(+), 29 deletions(-) create mode 100644 src/Starward.Core/HoYoPlay/GamePatchBuild.cs diff --git a/src/Starward.Core/HoYoPlay/GameBranch.cs b/src/Starward.Core/HoYoPlay/GameBranch.cs index ed13bbd7f..62dacbd6e 100644 --- a/src/Starward.Core/HoYoPlay/GameBranch.cs +++ b/src/Starward.Core/HoYoPlay/GameBranch.cs @@ -36,7 +36,7 @@ public class GameBranchPackage [JsonPropertyName("package_id")] public string PackageId { get; set; } - + // main or pre_download [JsonPropertyName("branch")] public string Branch { get; set; } diff --git a/src/Starward.Core/HoYoPlay/GameChunkBuild.cs b/src/Starward.Core/HoYoPlay/GameChunkBuild.cs index 1ad7156ae..1fbbdded3 100644 --- a/src/Starward.Core/HoYoPlay/GameChunkBuild.cs +++ b/src/Starward.Core/HoYoPlay/GameChunkBuild.cs @@ -2,19 +2,24 @@ namespace Starward.Core.HoYoPlay; + public class GameChunkBuild { - // json string build_id [JsonPropertyName("build_id")] public string BuildId { get; set; } - // string tag + /// + /// 游戏版本 + /// [JsonPropertyName("tag")] public string Tag { get; set; } + /// + /// 文件清单 + /// [JsonPropertyName("manifests")] public List Manifests { get; set; } @@ -22,43 +27,60 @@ public class GameChunkBuild } - +/// +/// Chunk 下载模式文件清单 +/// public class GameChunkManifest { - - // string category_id + /// + /// 资源ID + /// [JsonPropertyName("category_id")] public string CategoryId { get; set; } - // string category_name + /// + /// 资源名称 + /// [JsonPropertyName("category_name")] public string CategoryName { get; set; } - // string matching_field + /// + /// 资源类型,game or 语音类型(zh-cn, en-us, ja-jp, ko-kr) + /// [JsonPropertyName("matching_field")] public string MatchingField { get; set; } - // gamechunkmanifestfile manifest + /// + /// 清单文件信息 + /// [JsonPropertyName("manifest")] public GameChunkManifestFile Manifest { get; set; } - // gamechunkmanifesturl chunk_download + /// + /// 分块文件下载链接前缀 + /// [JsonPropertyName("chunk_download")] public GameChunkManifestUrl ChunkDownload { get; set; } - // gamechunkmanifesturl manifest_download + /// + /// 清单文件下载链接前缀 + /// [JsonPropertyName("manifest_download")] public GameChunkManifestUrl ManifestDownload { get; set; } - // gamechunkmanifeststats stats + /// + /// 文件统计信息 + /// [JsonPropertyName("stats")] public GameChunkManifestStats Stats { get; set; } - // gamechunkmanifeststats deduplicated_stats + /// + /// 去重后的文件统计信息 + /// [JsonPropertyName("deduplicated_stats")] public GameChunkManifestStats DeduplicatedStats { get; set; } @@ -68,11 +90,15 @@ public class GameChunkManifest public class GameChunkManifestFile { - + /// + /// 文件名,与下载链接前缀拼接为下载链接 + /// [JsonPropertyName("id")] public string Id { get; set; } - + /// + /// 解压后的MD5 + /// [JsonPropertyName("checksum")] public string Checksum { get; set; } @@ -90,26 +116,38 @@ public class GameChunkManifestFile - +/// +/// 文件下载链接前缀 +/// public class GameChunkManifestUrl { - + /// + /// 加密 + /// [JsonPropertyName("encryption")] public int Encryption { get; set; } - + /// + /// 密码 + /// [JsonPropertyName("password")] public string Password { get; set; } - + /// + /// 压缩 + /// [JsonPropertyName("compression")] public int Compression { get; set; } - + /// + /// 前缀 + /// [JsonPropertyName("url_prefix")] public string UrlPrefix { get; set; } - + /// + /// 后缀 + /// [JsonPropertyName("url_suffix")] public string UrlSuffix { get; set; } @@ -117,6 +155,7 @@ public class GameChunkManifestUrl + public class GameChunkManifestStats { @@ -139,4 +178,6 @@ public class GameChunkManifestStats [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public int ChunkCount { get; set; } + } + diff --git a/src/Starward.Core/HoYoPlay/GamePatchBuild.cs b/src/Starward.Core/HoYoPlay/GamePatchBuild.cs new file mode 100644 index 000000000..15db31c58 --- /dev/null +++ b/src/Starward.Core/HoYoPlay/GamePatchBuild.cs @@ -0,0 +1,85 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.HoYoPlay; + + +public class GamePatchBuild +{ + + [JsonPropertyName("build_id")] + public string BuildId { get; set; } + + + [JsonPropertyName("patch_id")] + public string PatchId { get; set; } + + + /// + /// 游戏版本 + /// + [JsonPropertyName("tag")] + public string Tag { get; set; } + + + /// + /// 文件清单 + /// + [JsonPropertyName("manifests")] + public List Manifests { get; set; } + + +} + + +/// +/// Chunk 下载模式补丁文件清单 +/// +public class GamePatchManifest +{ + /// + /// 资源ID + /// + [JsonPropertyName("category_id")] + public string CategoryId { get; set; } + + /// + /// 资源名称 + /// + [JsonPropertyName("category_name")] + public string CategoryName { get; set; } + + /// + /// 资源类型,game or 语音类型(zh-cn, en-us, ja-jp, ko-kr) + /// + [JsonPropertyName("matching_field")] + public string MatchingField { get; set; } + + /// + /// 清单文件信息 + /// + [JsonPropertyName("manifest")] + public GameChunkManifestFile Manifest { get; set; } + + + /// + /// 分块文件下载链接前缀 + /// + [JsonPropertyName("diff_download")] + public GameChunkManifestUrl DiffDownload { get; set; } + + + /// + /// 清单文件下载链接前缀 + /// + [JsonPropertyName("manifest_download")] + public GameChunkManifestUrl ManifestDownload { get; set; } + + + /// + /// 文件统计信息 + /// + [JsonPropertyName("stats")] + public Dictionary Stats { get; set; } + + +} diff --git a/src/Starward.Core/HoYoPlay/HoYoPlayClient.cs b/src/Starward.Core/HoYoPlay/HoYoPlayClient.cs index 336958799..0bae6145e 100644 --- a/src/Starward.Core/HoYoPlay/HoYoPlayClient.cs +++ b/src/Starward.Core/HoYoPlay/HoYoPlayClient.cs @@ -64,6 +64,25 @@ private async Task CommonGetAsync(string url, string node, CancellationTok + private async Task CommonSendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) + { + var response = await _httpClient.SendAsync(request, cancellationToken); + response.EnsureSuccessStatusCode(); + var responseData = await response.Content.ReadFromJsonAsync(typeof(miHoYoApiWrapper), HoYoPlayJsonContext.Default, cancellationToken) as miHoYoApiWrapper; + if (responseData is null) + { + throw new miHoYoApiException(-1, "Can not parse the response body."); + } + if (responseData.Retcode != 0) + { + throw new miHoYoApiException(responseData.Retcode, responseData.Message); + } + return responseData.Data; + } + + + + private static string BuildUrl(string api, string launcherId, string language) { @@ -455,7 +474,7 @@ public async Task> GetGameBranchAsync(string launcherId, string /// - /// Chunk 下载模式清单 + /// Chunk 下载模式文件清单 /// /// /// @@ -467,17 +486,17 @@ public async Task GetGameChunkBuildAsync(GameBranch gameBranch, string? url = null; if (gameBranch.GameId.GameBiz.IsChinaServer()) { - url = "https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?plat_app=ddxf5qt290cg"; + url = "https://downloader-api.mihoyo.com/downloader/sophon_chunk/api/getBuild?"; } if (gameBranch.GameId.GameBiz.IsGlobalServer()) { - url = "https://sg-public-api.hoyoverse.com/downloader/sophon_chunk/api/getBuild?plat_app=ddxf6vlr1reo"; + url = "https://sg-downloader-api.hoyoverse.com/downloader/sophon_chunk/api/getBuild?"; } if (url is null) { throw new ArgumentOutOfRangeException(nameof(gameBranch), $"Unknown game biz ({gameBranch.GameId.GameBiz})."); } - url += $"&branch={gameBranchPackage.Branch}&package_id={gameBranchPackage.PackageId}&password={gameBranchPackage.Password}"; + url += $"branch={gameBranchPackage.Branch}&package_id={gameBranchPackage.PackageId}&password={gameBranchPackage.Password}"; return await CommonGetAsync(url, cancellationToken); } @@ -485,7 +504,7 @@ public async Task GetGameChunkBuildAsync(GameBranch gameBranch, /// - /// Chunk 下载模式清单 + /// Chunk 下载模式文件清单 /// /// /// @@ -498,22 +517,52 @@ public async Task GetGameChunkBuildAsync(GameBranch gameBranch, string? url = null; if (gameBranch.GameId.GameBiz.IsChinaServer()) { - url = "https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?plat_app=ddxf5qt290cg"; + url = "https://downloader-api.mihoyo.com/downloader/sophon_chunk/api/getBuild?"; } if (gameBranch.GameId.GameBiz.IsGlobalServer()) { - url = "https://sg-public-api.hoyoverse.com/downloader/sophon_chunk/api/getBuild?plat_app=ddxf6vlr1reo"; + url = "https://sg-downloader-api.hoyoverse.com/downloader/sophon_chunk/api/getBuild?"; } if (url is null) { throw new ArgumentOutOfRangeException(nameof(gameBranch), $"Unknown game biz ({gameBranch.GameId.GameBiz})."); } - url += $"&branch={gameBranchPackage.Branch}&package_id={gameBranchPackage.PackageId}&password={gameBranchPackage.Password}&tag={version}"; + url += $"branch={gameBranchPackage.Branch}&package_id={gameBranchPackage.PackageId}&password={gameBranchPackage.Password}&tag={version}"; return await CommonGetAsync(url, cancellationToken); } + /// + /// Chunk 下载模式的增量更新补丁文件清单 + /// + /// + /// + /// + /// + /// + public async Task GetGameChunkPatchBuildAsync(GameBranch gameBranch, GameBranchPackage gameBranchPackage, CancellationToken cancellationToken = default) + { + string? url = null; + if (gameBranch.GameId.GameBiz.IsChinaServer()) + { + url = "https://downloader-api.mihoyo.com/downloader/sophon_chunk/api/getPatchBuild?"; + } + if (gameBranch.GameId.GameBiz.IsGlobalServer()) + { + url = "https://sg-downloader-api.hoyoverse.com/downloader/sophon_chunk/api/getPatchBuild?"; + } + if (url is null) + { + throw new ArgumentOutOfRangeException(nameof(gameBranch), $"Unknown game biz ({gameBranch.GameId.GameBiz})."); + } + url += $"branch={gameBranchPackage.Branch}&package_id={gameBranchPackage.PackageId}&password={gameBranchPackage.Password}"; + var request = new HttpRequestMessage(HttpMethod.Post, url); + return await CommonSendAsync(request, cancellationToken); + } + + + } diff --git a/src/Starward.Core/HoYoPlay/HoYoPlayJsonContext.cs b/src/Starward.Core/HoYoPlay/HoYoPlayJsonContext.cs index babefba66..970bb7c4f 100644 --- a/src/Starward.Core/HoYoPlay/HoYoPlayJsonContext.cs +++ b/src/Starward.Core/HoYoPlay/HoYoPlayJsonContext.cs @@ -14,6 +14,7 @@ namespace Starward.Core.HoYoPlay; [JsonSerializable(typeof(List))] [JsonSerializable(typeof(List))] [JsonSerializable(typeof(miHoYoApiWrapper))] +[JsonSerializable(typeof(miHoYoApiWrapper))] internal partial class HoYoPlayJsonContext : JsonSerializerContext {