v1.4.2 - Added Updater

This commit is contained in:
Elwador 2024-05-05 18:03:07 +02:00
parent 54fc08fa24
commit f911489021
5 changed files with 158 additions and 29 deletions

View File

@ -699,7 +699,7 @@ public class Crunchyroll{
StreamDetailsPop? curStream = null;
if (!dlFailed){
// Validate or adjust options.kstream
options.Kstream = options.Kstream >= 1 && options.Kstream <= streams.Count
? options.Kstream
: 1;
@ -741,7 +741,7 @@ public class Crunchyroll{
MPDParsed streamPlaylists = MPDParser.Parse(streamPlaylistsReqResponse.ResponseContent, Languages.FindLang(crLocal), matchedUrl);
List<string> streamServers = new List<string>(streamPlaylists.Data.Keys);
options.X = options.X > streamServers.Count ? 1 : options.X;
options.StreamServer = options.StreamServer > streamServers.Count ? 1 : options.StreamServer;
if (streamServers.Count == 0){
return new DownloadResponse{
@ -751,11 +751,11 @@ public class Crunchyroll{
};
}
if (options.X == 0){
options.X = 1;
if (options.StreamServer == 0){
options.StreamServer = 1;
}
string selectedServer = streamServers[options.X - 1];
string selectedServer = streamServers[options.StreamServer - 1];
ServerData selectedList = streamPlaylists.Data[selectedServer];
var videos = selectedList.video.Select(item => new VideoItem{

View File

@ -0,0 +1,95 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CRD.Utils.Updater;
public class Updater{
#region Singelton
private static Updater? _instance;
private static readonly object Padlock = new();
public static Updater Instance{
get{
if (_instance == null){
lock (Padlock){
if (_instance == null){
_instance = new Updater();
}
}
}
return _instance;
}
}
#endregion
private string downloadUrl = "";
private readonly string tempPath = Path.Combine(Path.GetTempPath(), "Update.zip");
private readonly string extractPath = Path.Combine(Path.GetTempPath(), "ExtractedUpdate");
private readonly string apiEndpoint = "https://api.github.com/repos/Crunchy-DL/Crunchy-Downloader/releases/latest";
public async Task<bool> CheckForUpdatesAsync(){
try{
using (var client = new HttpClient()){
client.DefaultRequestHeaders.Add("User-Agent", "C# App"); // GitHub API requires a user agent
var response = await client.GetStringAsync(apiEndpoint);
var releaseInfo = JsonConvert.DeserializeObject<dynamic>(response);
var latestVersion = releaseInfo.tag_name;
downloadUrl = releaseInfo.assets[0].browser_download_url;
var version = Assembly.GetExecutingAssembly().GetName().Version;
var currentVersion = $"v{version?.Major}.{version?.Minor}.{version?.Build}";
if (latestVersion != currentVersion){
Console.WriteLine("Update available: " + latestVersion + " - Current Version: " + currentVersion);
return true;
} else{
Console.WriteLine("No updates available.");
return false;
}
}
} catch (Exception e){
Console.WriteLine("Failed to get Update information");
return false;
}
}
public async Task DownloadAndUpdateAsync(){
try{
using (var client = new HttpClient()){
// Download the zip file
var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
using (var stream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None)){
await stream.CopyToAsync(fileStream);
}
ZipFile.ExtractToDirectory(tempPath, extractPath, true);
ApplyUpdate(extractPath);
}
} catch (Exception e){
Console.WriteLine("Failed to get Update");
}
}
private void ApplyUpdate(string updateFolder){
var currentPath = AppDomain.CurrentDomain.BaseDirectory;
var updaterPath = Path.Combine(currentPath, "Updater.exe");
var arguments = $"\"{currentPath.Substring(0, currentPath.Length - 1)}\" \"{updateFolder}\"";
System.Diagnostics.Process.Start(updaterPath, arguments);
Environment.Exit(0);
}
}

View File

@ -1,29 +1,42 @@
using Avalonia;
using System;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Media;
using Avalonia.Styling;
using CommunityToolkit.Mvvm.ComponentModel;
using CRD.Downloader;
using CRD.Utils.Updater;
using FluentAvalonia.Styling;
using Newtonsoft.Json;
namespace CRD.ViewModels;
public partial class MainWindowViewModel : ViewModelBase{
private readonly FluentAvaloniaTheme _faTheme;
[ObservableProperty]
private bool _updateAvailable = true;
public MainWindowViewModel(){
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
Init();
}
public async void Init(){
UpdateAvailable = await Updater.Instance.CheckForUpdatesAsync();
await Crunchyroll.Instance.Init();
if (Crunchyroll.Instance.CrunOptions.AccentColor != null){
_faTheme.CustomAccentColor = Color.Parse(Crunchyroll.Instance.CrunOptions.AccentColor);
}
if (Crunchyroll.Instance.CrunOptions.Theme == "System"){
_faTheme.PreferSystemTheme = true;
} else if (Crunchyroll.Instance.CrunOptions.Theme == "Dark"){
@ -34,5 +47,4 @@ public partial class MainWindowViewModel : ViewModelBase{
Application.Current.RequestedThemeVariant = ThemeVariant.Light;
}
}
}

View File

@ -38,9 +38,8 @@
</Image>
<TextBlock Grid.Column="1"
Text="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
VerticalAlignment="Center"
>
Text="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
VerticalAlignment="Center">
</TextBlock>
</Grid>
</Border>
@ -65,6 +64,8 @@
IconSource="Library" />
</ui:NavigationView.MenuItems>
<ui:NavigationView.FooterMenuItems>
<ui:NavigationViewItem Classes="SampleAppNav" Content="Update Available" Tag="UpdateAvailable"
IconSource="CloudDownload" Focusable="False" IsVisible="{Binding UpdateAvailable}" />
<ui:NavigationViewItem Classes="SampleAppNav" Content="Account" Tag="Account"
IconSource="Contact" />
<ui:NavigationViewItem Classes="SampleAppNav" Content="Settings" Tag="Settings"

View File

@ -1,15 +1,22 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Reactive.Disposables;
using System.Reflection;
using System.Threading.Tasks;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CRD.Downloader;
using CRD.Utils.Updater;
using CRD.ViewModels;
using CRD.Views.Utils;
using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
using FluentAvalonia.UI.Windowing;
using Newtonsoft.Json;
using ReactiveUI;
namespace CRD.Views;
@ -17,9 +24,12 @@ namespace CRD.Views;
public partial class MainWindow : AppWindow{
private Stack<object> navigationStack = new Stack<object>();
private object selectedNavVieItem;
public MainWindow(){
InitializeComponent();
TitleBar.ExtendsContentIntoTitleBar = true;
TitleBar.TitleBarHitTestType = TitleBarHitTestType.Complex;
@ -27,7 +37,8 @@ public partial class MainWindow : AppWindow{
//select first element as default
var nv = this.FindControl<NavigationView>("NavView");
nv.SelectedItem = nv.MenuItems.ElementAt(0);
selectedNavVieItem = nv.SelectedItem;
MessageBus.Current.Listen<NavigationMessage>()
.Subscribe(message => {
if (message.Refresh){
@ -48,11 +59,9 @@ public partial class MainWindow : AppWindow{
MessageBus.Current.Listen<ToastMessage>()
.Subscribe(message => ShowToast(message.Message, message.Type, message.Seconds));
}
public static void ShowError(string message){
var window = new ErrorWindow();
window.SetErrorMessage(message);
@ -63,39 +72,51 @@ public partial class MainWindow : AppWindow{
this.FindControl<ToastNotification>("Toast").Show(message, type, durationInSeconds);
}
private void NavView_SelectionChanged(object? sender, NavigationViewSelectionChangedEventArgs e){
if (sender is NavigationView navView){
var selectedItem = navView.SelectedItem as NavigationViewItem;
if (selectedItem != null){
switch (selectedItem.Tag){
case "DownloadQueue":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(DownloadsPageViewModel));
navView.Content = Activator.CreateInstance(typeof(DownloadsPageViewModel));
selectedNavVieItem = selectedItem;
break;
case "AddDownload":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(AddDownloadPageViewModel));
navView.Content = Activator.CreateInstance(typeof(AddDownloadPageViewModel));
selectedNavVieItem = selectedItem;
break;
case "Calendar":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(CalendarPageViewModel));
navView.Content = Activator.CreateInstance(typeof(CalendarPageViewModel));
selectedNavVieItem = selectedItem;
break;
case "History":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(HistoryPageViewModel));
navView.Content = Activator.CreateInstance(typeof(HistoryPageViewModel));
navigationStack.Clear();
navigationStack.Push((sender as NavigationView).Content);
navigationStack.Push(navView.Content);
selectedNavVieItem = selectedItem;
break;
case "Account":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(AccountPageViewModel));
navView.Content = Activator.CreateInstance(typeof(AccountPageViewModel));
selectedNavVieItem = selectedItem;
break;
case "Settings":
(sender as NavigationView).Content = Activator.CreateInstance(typeof(SettingsPageViewModel));
navView.Content = Activator.CreateInstance(typeof(SettingsPageViewModel));
selectedNavVieItem = selectedItem;
break;
case "UpdateAvailable":
Updater.Instance.DownloadAndUpdateAsync();
break;
default:
(sender as NavigationView).Content = Activator.CreateInstance(typeof(DownloadsPageViewModel));
// (sender as NavigationView).Content = Activator.CreateInstance(typeof(DownloadsPageViewModel));
break;
}
}
}
}
}
public class ToastMessage(string message, ToastType type, int i){