diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9996c74..80d0b13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: - name: Build run: | $sha = "${{ steps.sha.outputs.sha }}" - New-Item -Path "build/Starward/" -Type Directory + New-Item -Path "build/NonsPlayer/" -Type Directory msbuild NonsPlayer.Launcher "-property:Configuration=$env:Configuration;Platform=$env:Platform;OutDir=$(Resolve-Path "build/NonsPlayer/")" dotnet build NonsPlayer -c $env:Configuration -o "build/NonsPlayer/app-build.$sha" -p:Platform=$env:Platform -p:Version="0.0.1-build.$sha" -p:DefineConstants=CI Add-Content "build/NonsPlayer/version.ini" -Value "app_folder=app-build.$sha`r`nexe_name=NonsPlayer.exe" diff --git a/NonsPlayer.Core/Services/ExpectionService.cs b/NonsPlayer.Core/Services/ExpectionService.cs index 42359b3..6e30994 100644 --- a/NonsPlayer.Core/Services/ExpectionService.cs +++ b/NonsPlayer.Core/Services/ExpectionService.cs @@ -4,16 +4,21 @@ namespace NonsPlayer.Core.Services; public class ExceptionService { - public delegate void ExceptionThrewHandle(Exception exception); - + public delegate void ExceptionThrewHandle(string content); public static ExceptionService Instance { get; } = new(); - + public event ExceptionThrewHandle ExceptionThrew; + public void Throw(string content) + { + Debug.WriteLine($"抛出了一个异常: {content}"); + ExceptionThrew?.Invoke(content); + } + public void Throw(Exception exception) { Debug.WriteLine($"抛出了一个异常: {exception}"); - ExceptionThrew?.Invoke(exception); + ExceptionThrew?.Invoke(exception.Message); } } \ No newline at end of file diff --git a/NonsPlayer.Updater/Metadata/LocalFile.cs b/NonsPlayer.Updater/Metadata/LocalFile.cs index 557d893..4b1c540 100644 --- a/NonsPlayer.Updater/Metadata/LocalFile.cs +++ b/NonsPlayer.Updater/Metadata/LocalFile.cs @@ -7,7 +7,7 @@ public class LocalFile public string To { get; set; } public string Path { get; set; } - + public string Hash { get; set; } public bool IsMoving { get; set; } diff --git a/NonsPlayer.Updater/Metadata/MetadataJsonContext.cs b/NonsPlayer.Updater/Metadata/MetadataJsonContext.cs new file mode 100644 index 0000000..f072f5c --- /dev/null +++ b/NonsPlayer.Updater/Metadata/MetadataJsonContext.cs @@ -0,0 +1,12 @@ +using NonsPlayer.Updater.Github; +using System.Text.Json.Serialization; + +namespace NonsPlayer.Updater.Metadata; + +[JsonSerializable(typeof(ReleaseVersion))] +[JsonSerializable(typeof(GithubRelease))] +[JsonSerializable(typeof(List))] +internal partial class MetadataJsonContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/NonsPlayer.Updater/NonsPlayer.Updater.csproj b/NonsPlayer.Updater/NonsPlayer.Updater.csproj index eafe84f..c15de4d 100644 --- a/NonsPlayer.Updater/NonsPlayer.Updater.csproj +++ b/NonsPlayer.Updater/NonsPlayer.Updater.csproj @@ -8,6 +8,7 @@ + diff --git a/NonsPlayer.Updater/Update/UpdateClient.cs b/NonsPlayer.Updater/Update/UpdateClient.cs index 1d17529..5656030 100644 --- a/NonsPlayer.Updater/Update/UpdateClient.cs +++ b/NonsPlayer.Updater/Update/UpdateClient.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Text.Json; using NonsPlayer.Updater.Github; +using NonsPlayer.Updater.Metadata; namespace NonsPlayer.Updater.Update; @@ -33,7 +34,8 @@ private string GetUrl(string suffix) } - public async Task GetLatestVersionAsync(bool isPrerelease, Architecture architecture) + public async Task GetLatestVersionAsync(bool isPrerelease, Architecture architecture, + CancellationToken cancellationToken = default) { #if DEV isPrerelease = true; @@ -47,21 +49,27 @@ public async Task GetLatestVersionAsync(bool isPrerelease, Archi _ => throw new PlatformNotSupportedException($"{architecture} is not supported.") }; var url = GetUrl(name); - return await ParseResponse(url); + return await ParseResponse(url, cancellationToken); } - public async Task GetGithubReleaseAsync(string tag) + public async Task GetGithubReleaseAsync(string tag, CancellationToken cancellationToken = default) { var url = $"https://api.github.com/repos/Miaoyww/NonsPlayer/releases/tags/{tag}"; - return await ParseResponse(url); + return await ParseResponse(url, cancellationToken); } - private async Task ParseResponse(string url) where T : class + private async Task ParseResponse(string url, CancellationToken cancellationToken = default) where T : class { - var res = await _httpClient.GetFromJsonAsync(url, typeof(T)) as T; - if (res == null) throw new NullReferenceException($"尝试ParseResponse失败,res为空.URL= {url}"); - - return res; + var res = + await _httpClient.GetFromJsonAsync(url, typeof(T), MetadataJsonContext.Default, cancellationToken) as T; + if (res == null) + { + throw new NullReferenceException($"尝试ParseResponse失败,res为空.URL= {url}"); + } + else + { + return res; + } } public async Task RenderGithubMarkdownAsync(string markdown, CancellationToken cancellationToken = default) diff --git a/NonsPlayer.Updater/Update/UpdateService.cs b/NonsPlayer.Updater/Update/UpdateService.cs index 32b1c88..1c81b28 100644 --- a/NonsPlayer.Updater/Update/UpdateService.cs +++ b/NonsPlayer.Updater/Update/UpdateService.cs @@ -6,6 +6,7 @@ using NonsPlayer.Core.Services; using NonsPlayer.Updater.Github; using NonsPlayer.Updater.Metadata; +using NuGet.Versioning; using SevenZipExtractor; namespace NonsPlayer.Updater.Update; @@ -42,16 +43,23 @@ public enum UpdateState private ReleaseVersion _releaseVersion; - private string _updateFolder; + private string _appFolder; private string _unzipFolder; + public long Progress_BytesToDownload { get; private set; } + private long progress_BytesDownloaded; + public long Progress_BytesDownloaded => progress_BytesDownloaded; + + + private int progress_FileCountDownloaded; private List localFiles; private List targetFiles; + public UpdateService(UpdateClient _inUpdateClient) { _httpClient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All }) @@ -60,24 +68,22 @@ public UpdateService(UpdateClient _inUpdateClient) } public UpdateState State { get; private set; } - - - public long Progress_BytesToDownload { get; private set; } - public long Progress_BytesDownloaded => progress_BytesDownloaded; - - + public string ErrorMessage { get; set; } - public async Task CheckUpdateAsync(Version currentVersion, Architecture architecture, + public async Task CheckUpdateAsync(string version, Architecture architecture, bool enablePreviewRelease = false, bool disableIgnore = false) { + NuGetVersion.TryParse(version, out var currentVersion); // _logger.LogInformation("Start to check update (Preview: {preview}, Arch: {arch})", AppConfig.EnablePreviewRelease, RuntimeInformation.OSArchitecture); var latestRelease = await _updateClient.GetLatestVersionAsync(enablePreviewRelease, architecture); // _logger.LogInformation("Current version: {0}, latest version: {1}, ignore version: {2}", AppConfig.AppVersion, release?.Version, ignoreVersion); - Version? latestVersion; - Version.TryParse(latestRelease.Version, out latestVersion); - if (currentVersion.CompareTo(latestVersion) < 0) return latestRelease; + NuGetVersion.TryParse(latestRelease.Version, out var latestVersion); + if (latestVersion! > currentVersion!) + { + return latestRelease; + } return null; } @@ -93,11 +99,8 @@ public async Task PrepareForUpdateAsync(ReleaseVersion release) ErrorMessage = string.Empty; _releaseVersion = release; State = UpdateState.Preparing; - _updateFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "NonsPlayer\\data"); - _unzipFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "NonsPlayer\\data\\unzip"); - Directory.CreateDirectory(_updateFolder); + _appFolder = AppContext.BaseDirectory; + _unzipFolder = Path.Combine(_appFolder, "unzip"); GetDownloadFile(); progress_BytesDownloaded = 0; Progress_BytesToDownload = _downloadFile.Release.PortableSize; @@ -113,7 +116,7 @@ public async Task PrepareForUpdateAsync(ReleaseVersion release) private void GetDownloadFile() { - var targetFilePath = Path.Combine(_updateFolder, + var targetFilePath = Path.Combine(_appFolder, $"NonsPlayer_Portable_{_releaseVersion.Version}_{_releaseVersion.Architecture}.7z"); var localFile = new LocalFile { @@ -151,15 +154,17 @@ public void Stop() } - public async Task UpdateAsync() + public async Task UpdateAsync(CancellationToken cancellationToken = default) { try { + progress_BytesDownloaded = 0; + Progress_BytesToDownload = _downloadFile.Release.PortableSize; cancelSource?.Cancel(); cancelSource = new CancellationTokenSource(); var source = cancelSource; State = UpdateState.Downloading; - await DownloadFilesAsync(source.Token); + await DownloadFileAsync(_downloadFile, source.Token); if (source.IsCancellationRequested) throw new TaskCanceledException(); var check = CheckDownloadFile(); @@ -172,8 +177,7 @@ public async Task UpdateAsync() await Task.Run(() => { UnzipFile(); - GetUnzipFiles(); - MovingFiles(); + MovingFolder(); }); State = UpdateState.Finish; } @@ -190,14 +194,6 @@ await Task.Run(() => } - private async Task DownloadFilesAsync(CancellationToken cancellationToken = default) - { - progress_BytesDownloaded = 0; - Progress_BytesToDownload = _downloadFile.Release.PortableSize; - await DownloadFileAsync(_downloadFile, cancellationToken); - } - - private async Task DownloadFileAsync(ReleaseFile releaseFile, CancellationToken cancellationToken = default) { var readLength = 0; @@ -225,6 +221,7 @@ private async Task DownloadFileAsync(ReleaseFile releaseFile, CancellationToken } await File.WriteAllBytesAsync(file, ms.ToArray(), cancellationToken); + Interlocked.Increment(ref progress_FileCountDownloaded); } using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); @@ -262,52 +259,36 @@ private bool CheckDownloadFile() private void UnzipFile() { - Directory.CreateDirectory(Path.GetDirectoryName(_downloadFile.File.To)!); + Directory.CreateDirectory(_appFolder); using (var archiveFile = new ArchiveFile(_downloadFile.File.Path)) { archiveFile.Extract(_downloadFile.File.To); } } - private void GetUnzipFiles() + private void MovingFolder() { - if (targetFiles == null) + try { - var files = Directory.GetFiles(_downloadFile.File.To, "*", SearchOption.AllDirectories); - var releaseFiles = new List(files.Length); - foreach (var file in files) - { - using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); - var len = (int)fs.Length; - var bytes = ArrayPool.Shared.Rent(len); - fs.Read(bytes, 0, len); - var span = bytes.AsSpan(0, len); - var sha256 = SHA256.HashData(span); - ArrayPool.Shared.Return(bytes); - releaseFiles.Add(new LocalFile - { - Path = file, - To = Path.Combine(AppContext.BaseDirectory, Path.GetFileName(file)), - Hash = Convert.ToHexString(sha256) - }); + var tagertFolder = new DirectoryInfo(AppContext.BaseDirectory).Parent?.FullName; + var appVersionFolder = $"app-{_downloadFile.Release.Version}"; + File.Copy(Path.Combine(_unzipFolder, "NonsPlayer", "version.ini"), + Path.Combine(tagertFolder, "version.ini"), + overwrite: true); + var launcherFile = Path.Combine(tagertFolder, "NonsPlayer.exe"); + if (!File.Exists(launcherFile)) + { + File.Copy(Path.Combine(_unzipFolder, "NonsPlayer", "NonsPlayer.exe"), + launcherFile, + overwrite: true); } - - targetFiles = releaseFiles; + + Directory.Move(Path.Combine(_unzipFolder, "NonsPlayer", appVersionFolder), + Path.Combine(tagertFolder, appVersionFolder)); } - } - - private void MovingFiles() - { - foreach (var file in targetFiles) + catch (Exception ex) { - if (file.IsMoving) - { - File.Move(file.Path, file.To, true); - } - else - { - File.Copy(file.Path, file.To, true); - } + ExceptionService.Instance.Throw("更新失败~建议手动下载并覆盖"); } } diff --git a/NonsPlayer.sln b/NonsPlayer.sln index b2d930c..e90fd7f 100644 --- a/NonsPlayer.sln +++ b/NonsPlayer.sln @@ -49,8 +49,18 @@ Global {803AEE18-AC5A-426D-B41A-D5115C5F9A58}.Release|x86.Deploy.0 = Release|x86 {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|arm64.ActiveCfg = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|arm64.Build.0 = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|x64.ActiveCfg = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|x64.Build.0 = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Debug|x86.Build.0 = Debug|Any CPU {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|Any CPU.Build.0 = Release|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|arm64.ActiveCfg = Release|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|arm64.Build.0 = Release|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|x64.ActiveCfg = Release|Any CPU + {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|x64.Build.0 = Release|Any CPU {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|x86.ActiveCfg = Debug|Any CPU {4F8E4835-D244-4999-8ACC-8F1A2D9DD8E1}.Release|x86.Build.0 = Debug|Any CPU {750DDD97-204B-46EB-90DC-17148DA7D785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/NonsPlayer/App.xaml.cs b/NonsPlayer/App.xaml.cs index b3a7626..88f44a2 100644 --- a/NonsPlayer/App.xaml.cs +++ b/NonsPlayer/App.xaml.cs @@ -46,6 +46,7 @@ public App() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // Core Services services.AddSingleton(); diff --git a/NonsPlayer/AppConfig.cs b/NonsPlayer/AppConfig.cs new file mode 100644 index 0000000..2c76f7f --- /dev/null +++ b/NonsPlayer/AppConfig.cs @@ -0,0 +1,45 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.UI.Dispatching; +using Microsoft.UI.Xaml; +using NonsPlayer.Activation; +using NonsPlayer.Components.ViewModels; +using NonsPlayer.Contracts.Services; +using NonsPlayer.Core.Contracts.Services; +using NonsPlayer.Core.Services; +using NonsPlayer.Helpers; +using NonsPlayer.Models; +using NonsPlayer.Services; +using NonsPlayer.Updater.Update; +using NonsPlayer.ViewModels; +using NonsPlayer.Views; +using NonsPlayer.Views.Pages; +using WinRT; +using UnhandledExceptionEventArgs = Microsoft.UI.Xaml.UnhandledExceptionEventArgs; + +namespace NonsPlayer; + +internal static class AppConfig +{ + public static string LogFile { get; private set; } + + static AppConfig() + { + Initialize(); + } + + public static string? IgnoreVersion { get; set; } + public static string? AppVersion { get; set; } + + private static void Initialize() + { +#if DEBUG + AppVersion = "0.4.0"; +#else + AppVersion = typeof(AppConfig).Assembly.GetCustomAttribute() + ?.InformationalVersion; +#endif + } +} \ No newline at end of file diff --git a/NonsPlayer/NonsPlayer.csproj b/NonsPlayer/NonsPlayer.csproj index b2d3ad3..4e49316 100644 --- a/NonsPlayer/NonsPlayer.csproj +++ b/NonsPlayer/NonsPlayer.csproj @@ -14,8 +14,6 @@ true true zh-cn - 0.4.0 - 0.4.0 NonsPlayer True Assets/WindowIcon.ico diff --git a/NonsPlayer/Services/VersionServcie.cs b/NonsPlayer/Services/VersionServcie.cs index da8a44a..a990a6a 100644 --- a/NonsPlayer/Services/VersionServcie.cs +++ b/NonsPlayer/Services/VersionServcie.cs @@ -5,8 +5,15 @@ namespace NonsPlayer.Services; public partial class VersionService : ObservableObject { - [ObservableProperty] private Version currentVersion; + /// + /// 不带v + /// + [ObservableProperty] private string currentVersion; + [ObservableProperty] private string currentVersionDescription = string.Empty; + /// + /// 带v + /// public VersionService() @@ -15,9 +22,9 @@ public VersionService() GetVersionDescription(); } - public Version GetCurrentVersion() + public string GetCurrentVersion() { - if (CurrentVersion == null) CurrentVersion = Assembly.GetExecutingAssembly().GetName().Version!; + if (CurrentVersion == null) CurrentVersion = AppConfig.AppVersion!; return CurrentVersion; } @@ -26,7 +33,7 @@ public string GetVersionDescription() { if (CurrentVersion == null) GetCurrentVersion(); if (CurrentVersionDescription == string.Empty) - CurrentVersionDescription = $"v{CurrentVersion.Major}.{CurrentVersion.Minor}.{CurrentVersion.Build}"; + CurrentVersionDescription = $"v{CurrentVersion}"; return CurrentVersionDescription; } diff --git a/NonsPlayer/ViewModels/SettingsViewModel.cs b/NonsPlayer/ViewModels/SettingsViewModel.cs index 310ef2a..c46bade 100644 --- a/NonsPlayer/ViewModels/SettingsViewModel.cs +++ b/NonsPlayer/ViewModels/SettingsViewModel.cs @@ -20,7 +20,7 @@ public partial class SettingsViewModel : ObservableRecipient public SettingsViewModel(IThemeSelectorService themeSelectorService) { - VersionDescription = GetVersionDescription(); + VersionDescription = _versionService.CurrentVersionDescription; } [RelayCommand] @@ -37,23 +37,5 @@ public async void CheckUpdate() await _updateService.CheckUpdateAsync(_versionService.CurrentVersion, RuntimeInformation.OSArchitecture); if (release != null) ServiceHelper.NavigationService.NavigateTo(typeof(UpdateViewModel).FullName, release); } - - private static string GetVersionDescription() - { - Version version; - - if (RuntimeHelper.IsMSIX) - { - var packageVersion = Package.Current.Id.Version; - - version = new Version(packageVersion.Major, packageVersion.Minor, packageVersion.Build, - packageVersion.Revision); - } - else - { - version = Assembly.GetExecutingAssembly().GetName().Version!; - } - - return $"v{version.Major}.{version.Minor}.{version.Build}"; - } + } \ No newline at end of file diff --git a/NonsPlayer/ViewModels/UpdateViewModel.cs b/NonsPlayer/ViewModels/UpdateViewModel.cs index fd978dd..5e83e03 100644 --- a/NonsPlayer/ViewModels/UpdateViewModel.cs +++ b/NonsPlayer/ViewModels/UpdateViewModel.cs @@ -1,17 +1,25 @@ -using Windows.System; +using System.Runtime.InteropServices; +using Windows.System; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using Microsoft.UI.Xaml; +using Microsoft.Web.WebView2.Core; using NonsPlayer.Contracts.ViewModels; using NonsPlayer.Core.Services; +using NonsPlayer.Helpers; using NonsPlayer.Services; using NonsPlayer.Updater.Github; +using NonsPlayer.Updater.Update; namespace NonsPlayer.ViewModels; public partial class UpdateViewModel : ObservableRecipient, INavigationAware { [ObservableProperty] private ReleaseVersion latestVersion; + [ObservableProperty] private string newVersion; + + public VersionService VersionService = App.GetService(); public void OnNavigatedTo(object parameter) @@ -23,25 +31,4 @@ public void OnNavigatedTo(object parameter) public void OnNavigatedFrom() { } - - [RelayCommand] - public async Task ReferToUrl(string tag) - { - try - { - var url = tag switch - { - "github" => LatestVersion.ReleasePageURL, - "portable" => LatestVersion.Portable, - _ => null - }; - // _logger.LogInformation("Open url: {url}", url); - if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri)) await Launcher.LaunchUriAsync(uri); - } - - catch (Exception e) - { - ExceptionService.Instance.Throw(e); - } - } } \ No newline at end of file diff --git a/NonsPlayer/Views/Pages/UpdatePage.xaml b/NonsPlayer/Views/Pages/UpdatePage.xaml index 4cb14aa..d499498 100644 --- a/NonsPlayer/Views/Pages/UpdatePage.xaml +++ b/NonsPlayer/Views/Pages/UpdatePage.xaml @@ -73,10 +73,10 @@ VerticalAlignment="Top" Text="相关链接" /> - - @@ -99,7 +99,7 @@ Orientation="Horizontal" Spacing="24"> -