diff --git a/BetterGenshinImpact/App.xaml.cs b/BetterGenshinImpact/App.xaml.cs index 0de15b06..ffbb5f69 100644 --- a/BetterGenshinImpact/App.xaml.cs +++ b/BetterGenshinImpact/App.xaml.cs @@ -84,7 +84,8 @@ public partial class App : Application "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning); + .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning) + .MinimumLevel.Override("Quartz", LogEventLevel.Information); if (all.MaskWindowConfig.MaskEnabled) { loggerConfiguration.WriteTo.RichTextBox(richTextBox, LogEventLevel.Information, @@ -107,6 +108,7 @@ public partial class App : Application logging.SetMinimumLevel(LogLevel.Debug); logging.AddFilter("Microsoft", LogLevel.Warning); logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning); + logging.AddFilter("Quartz", LogLevel.Information); logging.Services.AddSingleton(); }); } diff --git a/BetterGenshinImpact/View/Windows/GearTask/JsScriptSelectionWindow.xaml b/BetterGenshinImpact/View/Windows/GearTask/JsScriptSelectionWindow.xaml index 5fbe1b5e..86c52f1a 100644 --- a/BetterGenshinImpact/View/Windows/GearTask/JsScriptSelectionWindow.xaml +++ b/BetterGenshinImpact/View/Windows/GearTask/JsScriptSelectionWindow.xaml @@ -108,7 +108,7 @@ - \ No newline at end of file + diff --git a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs index 1e8cba26..7fcb039d 100644 --- a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs @@ -354,7 +354,7 @@ public partial class GearTaskListPageViewModel : ViewModel if (jsSelectionWindow.DialogResult && jsSelectionWindow.ViewModel.SelectedScript != null) { var selectedScript = jsSelectionWindow.ViewModel.SelectedScript; - newTask = new GearTaskViewModel(selectedScript.Manifest.Name) + newTask = new GearTaskViewModel(string.IsNullOrWhiteSpace(selectedScript.Name) ? selectedScript.FolderName : selectedScript.Name) { TaskType = "Javascript", Path = @$"{{jsUserFolder}}\{selectedScript.FolderName}\" @@ -659,4 +659,4 @@ public partial class GearTaskListPageViewModel : ViewModel /// /// 刷新当前任务树显示 /// -} \ No newline at end of file +} diff --git a/BetterGenshinImpact/ViewModel/Windows/GearTask/JsScriptSelectionViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/GearTask/JsScriptSelectionViewModel.cs index 835295b6..b47ab918 100644 --- a/BetterGenshinImpact/ViewModel/Windows/GearTask/JsScriptSelectionViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Windows/GearTask/JsScriptSelectionViewModel.cs @@ -4,10 +4,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using BetterGenshinImpact.Core.Script; -using BetterGenshinImpact.Core.Script.Project; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; namespace BetterGenshinImpact.ViewModel.Windows.GearTask; @@ -45,39 +45,82 @@ public partial class JsScriptSelectionViewModel : ViewModel { try { - var jsPath = Path.Combine(ScriptRepoUpdater.CenterRepoPath, "repo", "js"); - if (!Directory.Exists(jsPath)) + string? repoJsonContent = ScriptRepoUpdater.Instance.ReadFileFromCenterRepo("repo.json"); + if (string.IsNullOrWhiteSpace(repoJsonContent)) { - _logger.LogWarning($"JS脚本目录不存在: {jsPath}"); + var repoJsonPath = Directory.GetFiles(ScriptRepoUpdater.CenterRepoPath, "repo.json", SearchOption.AllDirectories).FirstOrDefault(); + if (!string.IsNullOrWhiteSpace(repoJsonPath) && File.Exists(repoJsonPath)) + { + repoJsonContent = File.ReadAllText(repoJsonPath); + } + } + + if (string.IsNullOrWhiteSpace(repoJsonContent)) + { + _logger.LogWarning("repo/repo.json 不存在或内容为空"); + return; + } + + var repoJson = JObject.Parse(repoJsonContent); + if (repoJson["indexes"] is not JArray indexes) + { + _logger.LogWarning("repo/repo.json 缺少 indexes 节点"); + return; + } + + var jsNode = indexes + .OfType() + .FirstOrDefault(x => string.Equals(x["name"]?.ToString(), "js", StringComparison.OrdinalIgnoreCase)); + + if (jsNode?["children"] is not JArray jsChildren) + { + _logger.LogWarning("repo/repo.json 缺少 js.children 节点"); return; } - var scriptDirectories = Directory.GetDirectories(jsPath); var scripts = new ObservableCollection(); - foreach (var scriptDir in scriptDirectories) + foreach (var child in jsChildren.OfType()) { try { - var manifestPath = Path.Combine(scriptDir, "manifest.json"); - if (File.Exists(manifestPath)) + var folderName = child["name"]?.ToString(); + if (string.IsNullOrWhiteSpace(folderName)) { - var manifestContent = File.ReadAllText(manifestPath); - var manifest = Manifest.FromJson(manifestContent); - - var scriptInfo = new JsScriptInfo - { - FolderName = Path.GetFileName(scriptDir), - FolderPath = scriptDir, - Manifest = manifest - }; - - scripts.Add(scriptInfo); + continue; } + + var rawDescription = child["description"]?.ToString() ?? string.Empty; + var (name, shortDescription) = SplitRepoDescription(rawDescription, folderName); + + var scriptInfo = new JsScriptInfo + { + FolderName = folderName, + RepoRelDir = $"js/{folderName}", + Name = name, + ShortDescription = shortDescription, + Version = child["version"]?.ToString() ?? string.Empty, + Author = child["author"]?.ToString() ?? string.Empty, + RawDescription = rawDescription, + LastUpdated = child["lastUpdated"]?.ToString() ?? string.Empty, + Tags = child["tags"] is JArray tags + ? tags.Values().Where(t => !string.IsNullOrWhiteSpace(t)).ToArray() + : [], + Authors = child["authors"] is JArray authors + ? authors + .OfType() + .Select(a => a["name"]?.ToString()) + .Where(a => !string.IsNullOrWhiteSpace(a)) + .Cast() + .ToArray() + : [], + }; + + scripts.Add(scriptInfo); } catch (Exception ex) { - _logger.LogWarning(ex, $"加载JS脚本失败: {scriptDir}"); + _logger.LogWarning(ex, "加载JS脚本失败"); } } @@ -139,15 +182,9 @@ public partial class JsScriptSelectionViewModel : ViewModel try { - var readmePath = Path.Combine(SelectedScript.FolderPath, "README.md"); - if (File.Exists(readmePath)) - { - ReadmeContent = File.ReadAllText(readmePath); - } - else - { - ReadmeContent = "README.md 文件不存在"; - } + var relPath = $"{SelectedScript.RepoRelDir}/README.md"; + string? content = ScriptRepoUpdater.Instance.ReadFileFromCenterRepo(relPath); + ReadmeContent = content ?? "README.md 文件不存在"; } catch (Exception ex) { @@ -162,15 +199,9 @@ public partial class JsScriptSelectionViewModel : ViewModel try { - var mainJsPath = Path.Combine(SelectedScript.FolderPath, SelectedScript.Manifest.Main); - if (File.Exists(mainJsPath)) - { - MainJsContent = File.ReadAllText(mainJsPath); - } - else - { - MainJsContent = "main.js 文件不存在"; - } + var relPath = $"{SelectedScript.RepoRelDir}/main.js"; + string? content = ScriptRepoUpdater.Instance.ReadFileFromCenterRepo(relPath); + MainJsContent = content ?? "main.js 文件不存在"; } catch (Exception ex) { @@ -195,7 +226,7 @@ public partial class JsScriptSelectionViewModel : ViewModel { var filtered = JsScripts.Where(script => script.FolderName.Contains(SearchText, StringComparison.OrdinalIgnoreCase) || - script.Manifest.Name.Contains(SearchText, StringComparison.OrdinalIgnoreCase) || + script.Name.Contains(SearchText, StringComparison.OrdinalIgnoreCase) || script.Description.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ).ToList(); FilteredJsScripts = new ObservableCollection(filtered); @@ -219,14 +250,46 @@ public partial class JsScriptSelectionViewModel : ViewModel { LoadJsScripts(); } + + private static (string Name, string ShortDescription) SplitRepoDescription(string rawDescription, string fallbackName) + { + if (string.IsNullOrWhiteSpace(rawDescription)) + { + return (fallbackName, string.Empty); + } + + const string separator = "~|~"; + var idx = rawDescription.IndexOf(separator, StringComparison.Ordinal); + if (idx < 0) + { + return (fallbackName, rawDescription.Trim()); + } + + var name = rawDescription[..idx].Trim(); + var desc = rawDescription[(idx + separator.Length)..].Trim(); + + if (string.IsNullOrWhiteSpace(name)) + { + name = fallbackName; + } + + return (name, desc); + } } public class JsScriptInfo { public string FolderName { get; set; } = string.Empty; - public string FolderPath { get; set; } = string.Empty; - public Manifest Manifest { get; set; } = new(); + public string RepoRelDir { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string ShortDescription { get; set; } = string.Empty; + public string RawDescription { get; set; } = string.Empty; + public string Version { get; set; } = string.Empty; + public string Author { get; set; } = string.Empty; + public string LastUpdated { get; set; } = string.Empty; + public string[] Tags { get; set; } = []; + public string[] Authors { get; set; } = []; - public string DisplayName => $"{Manifest.Name}({FolderName})"; - public string Description => Manifest.ShortDescription; -} \ No newline at end of file + public string DisplayName => string.IsNullOrWhiteSpace(Name) ? FolderName : $"{Name}({FolderName})"; + public string Description => ShortDescription; +}