diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 2a8af330..72d2cd4c 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -10,7 +10,7 @@ true Assets\Images\logo.ico BetterGI - 10.39.1 + 10.39.2 x64 embedded @@ -43,6 +43,7 @@ + diff --git a/BetterGenshinImpact/Core/Video/ObsRecorder.cs b/BetterGenshinImpact/Core/Video/ObsRecorder.cs index 2d10c7e7..716de5ea 100644 --- a/BetterGenshinImpact/Core/Video/ObsRecorder.cs +++ b/BetterGenshinImpact/Core/Video/ObsRecorder.cs @@ -9,6 +9,7 @@ using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Recorder; using BetterGenshinImpact.Core.Recorder.Model; using BetterGenshinImpact.GameTask.Common; +using MediaInfo; using Microsoft.Extensions.Logging; using OBSWebsocketDotNet; using OBSWebsocketDotNet.Communication; @@ -206,14 +207,18 @@ public class ObsRecorder : IVideoRecorder { var jsonPath = Path.Combine(folderPath, $"systemInfo.json"); // 计算视频文件大小 - var fileInfo = new FileInfo(videoPath); - var fileSize = fileInfo.Length; + MediaInfo.MediaInfo mediaInfo = new MediaInfo.MediaInfo(); + mediaInfo.Open(videoPath); + + string durationString = mediaInfo.Get(StreamKind.General, 0, "Duration"); + + Console.WriteLine($"视频时长: {durationString}"); // 读取json var json = File.ReadAllText(jsonPath); var info = JsonSerializer.Deserialize(json, KeyMouseRecorderJsonLine.JsonOptions); if (info != null) { - info.VideoSize = fileSize.ToString(); + info.VideoSize = durationString; // 写入json File.WriteAllText(jsonPath, JsonSerializer.Serialize(info, KeyMouseRecorderJsonLine.JsonOptions)); } diff --git a/BetterGenshinImpact/Model/KeyMouseScriptItem.cs b/BetterGenshinImpact/Model/KeyMouseScriptItem.cs index 56b5889d..98637cff 100644 --- a/BetterGenshinImpact/Model/KeyMouseScriptItem.cs +++ b/BetterGenshinImpact/Model/KeyMouseScriptItem.cs @@ -66,16 +66,27 @@ public partial class KeyMouseScriptItem : ObservableObject [ObservableProperty] private bool _isPartiallyUploaded; + [ObservableProperty] + private string _selectedTask = ""; + + public List TaskOptions { get; } = + [ + "", "任务一", "任务二", "任务三", "任务四", "任务五", + "任务六", "任务七", "任务八", "任务九" + ]; + private string FormatSpeed(double bytesPerSecond) { if (bytesPerSecond >= 1024 * 1024) // MB/s { return $"{bytesPerSecond / (1024 * 1024):F1} MB/s"; } + if (bytesPerSecond >= 1024) // KB/s { return $"{bytesPerSecond / 1024:F1} KB/s"; } + return $"{bytesPerSecond:F0} B/s"; } @@ -84,14 +95,19 @@ public partial class KeyMouseScriptItem : ObservableObject var dirName = new DirectoryInfo(Path).Name; var userName = TaskContext.Instance().Config.CommonConfig.UserName; var uid = TaskContext.Instance().Config.CommonConfig.Uid; - + if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(uid)) { - throw new InvalidOperationException("用户名或UID未设置"); + throw new InvalidOperationException("请先设置用户名和UID"); + } + + if (string.IsNullOrEmpty(SelectedTask)) + { + throw new InvalidOperationException("请选择本条记录的任务"); } var relativePath = localFilePath.Replace(_scriptPath, "").TrimStart('\\'); - var remotePath = $"{dirName[..10]}_{userName}_{uid}/{relativePath}"; + var remotePath = $"{dirName[..10]}_{userName}_{uid}_{SelectedTask}/{relativePath}"; return remotePath.Replace(@"\", "/"); } @@ -101,17 +117,17 @@ public partial class KeyMouseScriptItem : ObservableObject { var collection = DbLiteService.Instance.UserDb.GetCollection("FileUploads"); var files = Directory.GetFiles(Path, "*.*", SearchOption.AllDirectories); - + var hasUploadedFiles = false; var allFilesUploaded = true; - + foreach (var file in files) { try { var remotePath = GetRemotePath(file); var fileUploadItem = collection.FindById(remotePath); - + if (fileUploadItem?.Status == UploadStatus.UploadSuccess.ToString()) { hasUploadedFiles = true; @@ -128,7 +144,7 @@ public partial class KeyMouseScriptItem : ObservableObject return; } } - + IsUploadSuccess = allFilesUploaded; IsPartiallyUploaded = !allFilesUploaded && hasUploadedFiles; } @@ -174,23 +190,23 @@ public partial class KeyMouseScriptItem : ObservableObject IsUploading = true; IsUploadSuccess = false; UploadProgress = 0; - + var dirName = new DirectoryInfo(Path).Name; _logger.LogDebug($"{dirName} 开始上传..."); - + await Task.Run(() => { try { var tosClient = new TosClientHelper(); var files = Directory.GetFiles(Path, "*.*", SearchOption.AllDirectories); - + // 计算所有文件的总大小 long totalSize = 0; long uploadedSize = 0; _lastUploadedSize = 0; _lastProgressUpdateTime = DateTime.Now; - + foreach (var file in files) { _uploadCts.Token.ThrowIfCancellationRequested(); @@ -201,19 +217,19 @@ public partial class KeyMouseScriptItem : ObservableObject { _uploadCts.Token.ThrowIfCancellationRequested(); var remotePath = GetRemotePath(file); - + var needUploadFileName = System.IO.Path.GetFileName(file); var fileSize = new FileInfo(file).Length; if (needUploadFileName == "video.mkv" || needUploadFileName == "video.mp4") { - tosClient.UploadLargeFile(file, remotePath, 20 * 1024 * 1024, (bytes, totalBytes, percentage) => + tosClient.UploadLargeFile(file, remotePath, 20 * 1024 * 1024, (bytes, totalBytes, percentage) => { _uploadCts.Token.ThrowIfCancellationRequested(); var currentFileProgress = bytes; var overallProgress = ((double)(uploadedSize + currentFileProgress) / totalSize) * 100; UploadProgress = Math.Min(overallProgress, 99.9); - + // 计算速度 var now = DateTime.Now; var timeDiff = (now - _lastProgressUpdateTime).TotalSeconds; @@ -222,11 +238,11 @@ public partial class KeyMouseScriptItem : ObservableObject var sizeDiff = uploadedSize + currentFileProgress - _lastUploadedSize; var speed = sizeDiff / timeDiff; UploadSpeed = FormatSpeed(speed); - + _lastProgressUpdateTime = now; _lastUploadedSize = uploadedSize + currentFileProgress; } - + _logger.LogDebug($"上传进度: {overallProgress:F}%"); }); } @@ -234,15 +250,15 @@ public partial class KeyMouseScriptItem : ObservableObject { tosClient.UploadFile(file, remotePath); } - + uploadedSize += fileSize; var progress = ((double)uploadedSize / totalSize) * 100; UploadProgress = Math.Min(progress, 99.9); } - + UploadProgress = 100; UploadSpeed = string.Empty; // 清空速度显示 - + // 上传完成后,不需要额外的文件夹状态更新 // FileUploadItem 的状态已经在 TosClientHelper 中更新 IsUploadSuccess = true; @@ -274,6 +290,7 @@ public partial class KeyMouseScriptItem : ObservableObject { UploadProgress = 0; } + _uploadCts?.Dispose(); _uploadCts = null; } @@ -290,6 +307,7 @@ public partial class KeyMouseScriptItem : ObservableObject { break; } + await Task.Delay(100); } } @@ -297,7 +315,6 @@ public partial class KeyMouseScriptItem : ObservableObject [RelayCommand] private async Task DeleteUploadedFiles() { - try { // 提前验证用户信息,避免开始上传后才发现问题 @@ -308,7 +325,7 @@ public partial class KeyMouseScriptItem : ObservableObject await MessageBox.ErrorAsync("请先设置用户名和UID"); return; } - + try { var dirName = new DirectoryInfo(Path).Name; @@ -323,9 +340,9 @@ public partial class KeyMouseScriptItem : ObservableObject IsDeleting = true; IsDeleteSuccess = false; DeleteProgress = 0; - + _logger.LogDebug($"{dirName} 开始删除..."); - + await Task.Run(() => { try @@ -333,7 +350,7 @@ public partial class KeyMouseScriptItem : ObservableObject var tosClient = new TosClientHelper(); var files = Directory.GetFiles(Path, "*.*", SearchOption.AllDirectories); var collection = DbLiteService.Instance.UserDb.GetCollection("FileUploads"); - + foreach (var file in files) { _deleteCts.Token.ThrowIfCancellationRequested(); @@ -341,10 +358,10 @@ public partial class KeyMouseScriptItem : ObservableObject try { var remotePath = GetRemotePath(file); - + // 删除对象存储中的文件 tosClient.DeleteObject(remotePath); - + // 删除数据库中的记录 collection.Delete(remotePath); } @@ -353,7 +370,7 @@ public partial class KeyMouseScriptItem : ObservableObject _logger.LogError($"删除文件失败:{ex.Message}"); } } - + IsDeleteSuccess = true; // 重置上传状态 IsUploadSuccess = false; @@ -391,7 +408,7 @@ public partial class KeyMouseScriptItem : ObservableObject { _deleteCts?.Cancel(); } - + public bool VerifyFileHashes(string pcFolder, string hashFolder) { var hashFilePath = System.IO.Path.Combine(hashFolder, "hash.json"); diff --git a/BetterGenshinImpact/View/Pages/KeyMouseRecordPage.xaml b/BetterGenshinImpact/View/Pages/KeyMouseRecordPage.xaml index a638fb7c..c373a5a6 100644 --- a/BetterGenshinImpact/View/Pages/KeyMouseRecordPage.xaml +++ b/BetterGenshinImpact/View/Pages/KeyMouseRecordPage.xaml @@ -115,14 +115,16 @@ - - + + + + - + + + + + + + + + + + + diff --git a/BetterGenshinImpact/ViewModel/Pages/KeyMouseRecordPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/KeyMouseRecordPageViewModel.cs index f3d092e3..fd47bb2c 100644 --- a/BetterGenshinImpact/ViewModel/Pages/KeyMouseRecordPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/KeyMouseRecordPageViewModel.cs @@ -75,6 +75,7 @@ public partial class KeyMouseRecordPageViewModel : ObservableObject, INavigation if (existingItem != null) { // 如果找到现有项目,保留其状态 + existingItem.InitializeUploadStatus(); updatedItems.Add(existingItem); } else