From 021c7ff2458026adf186c2f0f774de03bc1c1622 Mon Sep 17 00:00:00 2001 From: lincube Date: Fri, 3 Apr 2026 22:07:38 +0800 Subject: [PATCH] =?UTF-8?q?fix.=E8=BF=98=E6=98=AF=E5=9C=A8=E4=BF=AE?= =?UTF-8?q?=E6=99=BA=E6=95=99Hub=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/ComponentSettingsSnapshot.cs | 49 ++++++++++++++++++ .../Services/IRecommendationDataService.cs | 2 + .../Services/RecommendationDataService.cs | 51 ++++++++++--------- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs index 570790a..4500d2d 100644 --- a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs +++ b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs @@ -135,6 +135,55 @@ public static class ZhiJiaoHubSources _ => ClassIsland }; } + + public static string GetDisplayName(string source) + { + return source?.ToLowerInvariant() switch + { + Sectl => "SECTL 图库", + RinLit => "Rin's 图库", + _ => "ClassIsland 图库" + }; + } +} + +// 智教Hub数据源配置 +public sealed class ZhiJiaoHubSourceConfig +{ + public string Owner { get; init; } = string.Empty; + public string Repo { get; init; } = string.Empty; + public string Path { get; init; } = string.Empty; + public string DisplayName { get; init; } = string.Empty; + 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 static ZhiJiaoHubSourceConfig GetConfig(string source) + { + return source?.ToLowerInvariant() switch + { + ZhiJiaoHubSources.Sectl => new ZhiJiaoHubSourceConfig + { + Owner = "SECTL", + Repo = "SECTL-hub", + Path = "docs/.vuepress/public/images", + DisplayName = "SECTL 图库" + }, + ZhiJiaoHubSources.RinLit => new ZhiJiaoHubSourceConfig + { + Owner = "RinLit-233-shiroko", + Repo = "Rin-sHub", + Path = "assets/images", + DisplayName = "Rin's 图库" + }, + _ => new ZhiJiaoHubSourceConfig + { + Owner = "ClassIsland", + Repo = "classisland-hub", + Path = "images", + DisplayName = "ClassIsland 图库" + } + }; + } } // 智教Hub镜像加速源常量 diff --git a/LanMountainDesktop/Services/IRecommendationDataService.cs b/LanMountainDesktop/Services/IRecommendationDataService.cs index 89a0710..a189742 100644 --- a/LanMountainDesktop/Services/IRecommendationDataService.cs +++ b/LanMountainDesktop/Services/IRecommendationDataService.cs @@ -319,6 +319,8 @@ public sealed record RecommendationApiOptions public string SectlHubApiUrl { get; init; } = "https://api.github.com/repos/SECTL/SECTL-hub/contents/docs/.vuepress/public/images"; + public string RinLitHubApiUrl { get; init; } = "https://api.github.com/repos/RinLit-233-shiroko/Rin-sHub/contents/images"; + public string ClassIslandHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/ClassIsland/classisland-hub/main/images/{0}"; public string SectlHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/SECTL/SECTL-hub/main/docs/.vuepress/public/images/{0}"; diff --git a/LanMountainDesktop/Services/RecommendationDataService.cs b/LanMountainDesktop/Services/RecommendationDataService.cs index c04fb3c..6a0ff74 100644 --- a/LanMountainDesktop/Services/RecommendationDataService.cs +++ b/LanMountainDesktop/Services/RecommendationDataService.cs @@ -3244,16 +3244,10 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis private async Task FetchZhiJiaoHubSnapshotAsync(string source, string mirrorSource, CancellationToken cancellationToken) { - var (owner, repo, path, rawUrlTemplate) = source switch - { - ZhiJiaoHubSources.Sectl => ("SECTL", "SECTL-hub", "docs/.vuepress/public/images", _options.SectlHubRawUrlTemplate), - ZhiJiaoHubSources.RinLit => ("RinLit-233-shiroko", "Rin-sHub", "images", _options.RinLitHubRawUrlTemplate), - _ => ("ClassIsland", "classisland-hub", "images", _options.ClassIslandHubRawUrlTemplate) - }; + var config = ZhiJiaoHubSourceConfig.GetConfig(source); - var contentsUrl = $"https://api.github.com/repos/{owner}/{repo}/contents/{path}"; + var contentsUrl = config.ApiUrl; - // 如果使用镜像加速,代理 GitHub API 请求 if (string.Equals(mirrorSource, ZhiJiaoHubMirrorSources.GhProxy, StringComparison.OrdinalIgnoreCase)) { contentsUrl = ZhiJiaoHubMirrorSources.GhProxyBaseUrl.TrimEnd('/') + "/" + contentsUrl; @@ -3261,18 +3255,16 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis try { - var images = await FetchImagesFromContentsApi(owner, repo, path, rawUrlTemplate, contentsUrl, mirrorSource, cancellationToken); + var images = await FetchImagesFromContentsApi(config, contentsUrl, mirrorSource, cancellationToken); if (images.Count == 0) { - throw new InvalidOperationException("未找到图片文件"); + throw new InvalidOperationException($"在 {config.DisplayName} 中未找到图片文件"); } - // 随机打乱图片顺序 var random = new Random(); var shuffled = images.OrderBy(_ => random.Next()).ToList(); - // 重新设置索引 for (int i = 0; i < shuffled.Count; i++) { var item = shuffled[i]; @@ -3287,11 +3279,15 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis } catch (Exception ex) { - throw new HttpRequestException($"获取图片列表失败: {ex.Message}"); + throw new HttpRequestException($"从 {config.DisplayName} 获取图片列表失败: {ex.Message}"); } } - private async Task> FetchImagesFromContentsApi(string owner, string repo, string path, string rawUrlTemplate, string contentsUrl, string mirrorSource, CancellationToken cancellationToken) + private async Task> FetchImagesFromContentsApi( + ZhiJiaoHubSourceConfig config, + string contentsUrl, + string mirrorSource, + CancellationToken cancellationToken) { var images = new List(); @@ -3309,7 +3305,17 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis { throw new HttpRequestException("GitHub API 速率限制,请稍后重试"); } - throw new HttpRequestException($"API 返回错误: {(int)response.StatusCode} - {Truncate(errorText, 200)}"); + + if ((int)response.StatusCode == 404) + { + throw new HttpRequestException( + $"在 {config.DisplayName} 中找不到图片目录。请检查仓库结构和路径配置。\n" + + $"仓库: {config.Owner}/{config.Repo}\n" + + $"路径: {config.Path}"); + } + + throw new HttpRequestException( + $"从 {config.DisplayName} 获取数据失败: {(int)response.StatusCode} - {Truncate(errorText, 200)}"); } var responseText = await response.Content.ReadAsStringAsync(cancellationToken); @@ -3321,9 +3327,9 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty("message", out var messageNode)) { var errorMessage = messageNode.GetString(); - throw new InvalidOperationException($"GitHub API 错误: {errorMessage}"); + throw new InvalidOperationException($"GitHub API 错误 ({config.DisplayName}): {errorMessage}"); } - throw new InvalidOperationException("Invalid response format from GitHub API."); + throw new InvalidOperationException($"从 {config.DisplayName} 返回的数据格式无效"); } int index = 0; @@ -3343,18 +3349,15 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis continue; } - // 只处理图片文件 var extension = Path.GetExtension(name).ToLowerInvariant(); if (extension != ".png" && extension != ".jpg" && extension != ".jpeg" && extension != ".gif" && extension != ".webp") { continue; } - // 解码文件名 var decodedName = Uri.UnescapeDataString(name); decodedName = Path.GetFileNameWithoutExtension(decodedName); - // 构造图片 URL string imageUrl; if (!string.IsNullOrWhiteSpace(downloadUrl)) { @@ -3362,12 +3365,12 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis } else { - // 使用为每个数据源专门配置的 raw URL 模板 - // 注意:模板已经包含了正确的路径,只需要传入文件名 - imageUrl = string.Format(rawUrlTemplate, Uri.EscapeDataString(name)); + imageUrl = string.Format( + CultureInfo.InvariantCulture, + config.RawUrlTemplate, + Uri.EscapeDataString(name)); } - // 应用镜像加速到图片 URL imageUrl = ZhiJiaoHubMirrorSources.ApplyMirror(imageUrl, mirrorSource); images.Add(new ZhiJiaoHubImageItem(decodedName, imageUrl, index));