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; StreamDetailsPop? curStream = null;
if (!dlFailed){ if (!dlFailed){
// Validate or adjust options.kstream
options.Kstream = options.Kstream >= 1 && options.Kstream <= streams.Count options.Kstream = options.Kstream >= 1 && options.Kstream <= streams.Count
? options.Kstream ? options.Kstream
: 1; : 1;
@ -741,7 +741,7 @@ public class Crunchyroll{
MPDParsed streamPlaylists = MPDParser.Parse(streamPlaylistsReqResponse.ResponseContent, Languages.FindLang(crLocal), matchedUrl); MPDParsed streamPlaylists = MPDParser.Parse(streamPlaylistsReqResponse.ResponseContent, Languages.FindLang(crLocal), matchedUrl);
List<string> streamServers = new List<string>(streamPlaylists.Data.Keys); 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){ if (streamServers.Count == 0){
return new DownloadResponse{ return new DownloadResponse{
@ -751,11 +751,11 @@ public class Crunchyroll{
}; };
} }
if (options.X == 0){ if (options.StreamServer == 0){
options.X = 1; options.StreamServer = 1;
} }
string selectedServer = streamServers[options.X - 1]; string selectedServer = streamServers[options.StreamServer - 1];
ServerData selectedList = streamPlaylists.Data[selectedServer]; ServerData selectedList = streamPlaylists.Data[selectedServer];
var videos = selectedList.video.Select(item => new VideoItem{ 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,23 +1,36 @@
using Avalonia; using System;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
using CommunityToolkit.Mvvm.ComponentModel;
using CRD.Downloader; using CRD.Downloader;
using CRD.Utils.Updater;
using FluentAvalonia.Styling; using FluentAvalonia.Styling;
using Newtonsoft.Json;
namespace CRD.ViewModels; namespace CRD.ViewModels;
public partial class MainWindowViewModel : ViewModelBase{ public partial class MainWindowViewModel : ViewModelBase{
private readonly FluentAvaloniaTheme _faTheme; private readonly FluentAvaloniaTheme _faTheme;
public MainWindowViewModel(){ [ObservableProperty]
private bool _updateAvailable = true;
public MainWindowViewModel(){
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme; _faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
Init(); Init();
} }
public async void Init(){ public async void Init(){
UpdateAvailable = await Updater.Instance.CheckForUpdatesAsync();
await Crunchyroll.Instance.Init(); await Crunchyroll.Instance.Init();
if (Crunchyroll.Instance.CrunOptions.AccentColor != null){ if (Crunchyroll.Instance.CrunOptions.AccentColor != null){
@ -34,5 +47,4 @@ public partial class MainWindowViewModel : ViewModelBase{
Application.Current.RequestedThemeVariant = ThemeVariant.Light; Application.Current.RequestedThemeVariant = ThemeVariant.Light;
} }
} }
} }

View File

@ -39,8 +39,7 @@
<TextBlock Grid.Column="1" <TextBlock Grid.Column="1"
Text="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Text="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
VerticalAlignment="Center" VerticalAlignment="Center">
>
</TextBlock> </TextBlock>
</Grid> </Grid>
</Border> </Border>
@ -65,6 +64,8 @@
IconSource="Library" /> IconSource="Library" />
</ui:NavigationView.MenuItems> </ui:NavigationView.MenuItems>
<ui:NavigationView.FooterMenuItems> <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" <ui:NavigationViewItem Classes="SampleAppNav" Content="Account" Tag="Account"
IconSource="Contact" /> IconSource="Contact" />
<ui:NavigationViewItem Classes="SampleAppNav" Content="Settings" Tag="Settings" <ui:NavigationViewItem Classes="SampleAppNav" Content="Settings" Tag="Settings"

View File

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