From 00339f0ed0f771d2f5fb09992d6ca75457e824b4 Mon Sep 17 00:00:00 2001 From: lincube Date: Fri, 3 Apr 2026 22:55:35 +0800 Subject: [PATCH] =?UTF-8?q?fix.=E4=BF=AERinshub=EF=BC=8C=E6=80=8E=E4=B9=88?= =?UTF-8?q?=E4=B8=8D=E6=98=AF=E8=89=B2=E8=89=B2=E5=B0=B1=E6=98=AF=E9=80=86?= =?UTF-8?q?=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/ComponentSettingsSnapshot.cs | 11 +- .../Services/RecommendationDataService.cs | 106 ++++++++++++++++-- 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs index 4500d2d..ee71e62 100644 --- a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs +++ b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs @@ -154,8 +154,13 @@ public sealed class ZhiJiaoHubSourceConfig public string Repo { get; init; } = string.Empty; public string Path { get; init; } = string.Empty; public string DisplayName { get; init; } = string.Empty; + public bool UseJsonIndex { get; init; } = false; + public string? JsonIndexPath { get; init; } = null; public string ApiUrl => $"https://api.github.com/repos/{Owner}/{Repo}/contents/{Path}"; public string RawUrlTemplate => $"https://raw.githubusercontent.com/{Owner}/{Repo}/main/{Path}/{{0}}"; + public string? JsonIndexUrl => JsonIndexPath != null + ? $"https://raw.githubusercontent.com/{Owner}/{Repo}/main/{JsonIndexPath}" + : null; public static ZhiJiaoHubSourceConfig GetConfig(string source) { @@ -172,8 +177,10 @@ public sealed class ZhiJiaoHubSourceConfig { Owner = "RinLit-233-shiroko", Repo = "Rin-sHub", - Path = "assets/images", - DisplayName = "Rin's 图库" + Path = "updates/images", + DisplayName = "Rin's 图库", + UseJsonIndex = true, + JsonIndexPath = "updates/images.json" }, _ => new ZhiJiaoHubSourceConfig { diff --git a/LanMountainDesktop/Services/RecommendationDataService.cs b/LanMountainDesktop/Services/RecommendationDataService.cs index 6a0ff74..6a1628f 100644 --- a/LanMountainDesktop/Services/RecommendationDataService.cs +++ b/LanMountainDesktop/Services/RecommendationDataService.cs @@ -3246,16 +3246,27 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis { var config = ZhiJiaoHubSourceConfig.GetConfig(source); - var contentsUrl = config.ApiUrl; - - if (string.Equals(mirrorSource, ZhiJiaoHubMirrorSources.GhProxy, StringComparison.OrdinalIgnoreCase)) - { - contentsUrl = ZhiJiaoHubMirrorSources.GhProxyBaseUrl.TrimEnd('/') + "/" + contentsUrl; - } - try { - var images = await FetchImagesFromContentsApi(config, contentsUrl, mirrorSource, cancellationToken); + List images; + + // 如果使用JSON索引模式(Rin's Hub) + if (config.UseJsonIndex && !string.IsNullOrEmpty(config.JsonIndexUrl)) + { + images = await FetchImagesFromJsonIndex(config, mirrorSource, cancellationToken); + } + else + { + // 标准模式(ClassIsland/SECTL) + var contentsUrl = config.ApiUrl; + + if (string.Equals(mirrorSource, ZhiJiaoHubMirrorSources.GhProxy, StringComparison.OrdinalIgnoreCase)) + { + contentsUrl = ZhiJiaoHubMirrorSources.GhProxyBaseUrl.TrimEnd('/') + "/" + contentsUrl; + } + + images = await FetchImagesFromContentsApi(config, contentsUrl, mirrorSource, cancellationToken); + } if (images.Count == 0) { @@ -3380,6 +3391,85 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis return images; } + /// + /// 从JSON索引文件获取图片列表(Rin's Hub专用) + /// + private async Task> FetchImagesFromJsonIndex( + ZhiJiaoHubSourceConfig config, + string mirrorSource, + CancellationToken cancellationToken) + { + var images = new List(); + + // 下载JSON索引文件 + var jsonUrl = config.JsonIndexUrl!; + if (string.Equals(mirrorSource, ZhiJiaoHubMirrorSources.GhProxy, StringComparison.OrdinalIgnoreCase)) + { + jsonUrl = ZhiJiaoHubMirrorSources.GhProxyBaseUrl.TrimEnd('/') + "/" + jsonUrl; + } + + using var request = new HttpRequestMessage(HttpMethod.Get, jsonUrl); + request.Headers.TryAddWithoutValidation("User-Agent", "LanMountainDesktop/1.0"); + + using var response = await _httpClient.SendAsync(request, cancellationToken); + response.EnsureSuccessStatusCode(); + + var jsonText = await response.Content.ReadAsStringAsync(cancellationToken); + using var document = JsonDocument.Parse(jsonText); + var root = document.RootElement; + + // 解析 hub_items 数组 + if (!root.TryGetProperty("hub_items", out var hubItems) || hubItems.ValueKind != JsonValueKind.Array) + { + throw new InvalidOperationException($"JSON索引文件格式无效:缺少 hub_items 数组"); + } + + int index = 0; + foreach (var item in hubItems.EnumerateArray()) + { + // 获取图片路径 + if (!item.TryGetProperty("image", out var imageProp)) + { + continue; + } + + var imagePath = imageProp.GetString(); + if (string.IsNullOrWhiteSpace(imagePath)) + { + continue; + } + + // 获取标题(用于显示名称) + string title = string.Empty; + if (item.TryGetProperty("title", out var titleProp)) + { + title = titleProp.GetString() ?? string.Empty; + } + + // 如果没有标题,使用文件名 + if (string.IsNullOrWhiteSpace(title)) + { + title = Path.GetFileNameWithoutExtension(imagePath); + } + + // 构建完整的图片URL + // imagePath 格式如: "Discord/姐姐好香.png" + // 需要拼接为: https://raw.githubusercontent.com/.../updates/images/Discord/姐姐好香.png + // 并对路径中的每个部分进行URL编码 + var pathParts = imagePath.Split('/'); + var encodedPath = string.Join("/", pathParts.Select(part => Uri.EscapeDataString(part))); + var imageUrl = $"https://raw.githubusercontent.com/{config.Owner}/{config.Repo}/main/{config.Path}/{encodedPath}"; + + // 应用镜像加速 + imageUrl = ZhiJiaoHubMirrorSources.ApplyMirror(imageUrl, mirrorSource); + + images.Add(new ZhiJiaoHubImageItem(title, imageUrl, index)); + index++; + } + + return images; + } + private bool TryGetZhiJiaoHubFromCache(string cacheKey, out ZhiJiaoHubSnapshot snapshot) { lock (_cacheGate)