Add - Added edit button for history overview and series

Chg - Detect special episodes in series to ignore them from new episodes
Chg - History always tries to take the original version to not have multiple versions of the same season

Fix - Updater failed because it couldn't update itself (for the fix you need to download the new updater)
This commit is contained in:
Elwador 2024-05-11 13:08:24 +02:00
parent 76ddd9241a
commit 3e33843bc0
8 changed files with 197 additions and 73 deletions

View File

@ -137,7 +137,7 @@ public class CrSeries(Crunchyroll crunInstance){
var s = result[season][key];
if (data?.S != null && s.Id != data.Value.S) continue;
int fallbackIndex = 0;
var seasonData = await GetSeasonDataById(s);
var seasonData = await GetSeasonDataById(s.Id);
if (seasonData.Data != null){
if (crunInstance.CrunOptions.History){
@ -268,7 +268,7 @@ public class CrSeries(Crunchyroll crunInstance){
return crunchySeriesList;
}
public async Task<CrunchyEpisodeList> GetSeasonDataById(SeriesSearchItem item, bool log = false){
public async Task<CrunchyEpisodeList> GetSeasonDataById(string seasonID, bool log = false){
CrunchyEpisodeList episodeList = new CrunchyEpisodeList(){ Data = new List<CrunchyEpisode>(), Total = 0, Meta = new Meta() };
if (crunInstance.CmsToken?.Cms == null){
@ -277,7 +277,7 @@ public class CrSeries(Crunchyroll crunInstance){
}
if (log){
var showRequest = HttpClientReq.CreateRequestMessage($"{Api.Cms}/seasons/{item.Id}?preferred_audio_language=ja-JP", HttpMethod.Get, true, true, null);
var showRequest = HttpClientReq.CreateRequestMessage($"{Api.Cms}/seasons/{seasonID}?preferred_audio_language=ja-JP", HttpMethod.Get, true, true, null);
var response = await HttpClientReq.Instance.SendHttpRequest(showRequest);
@ -290,7 +290,7 @@ public class CrSeries(Crunchyroll crunInstance){
//TODO
var episodeRequest = new HttpRequestMessage(HttpMethod.Get, $"{Api.Cms}/seasons/{item.Id}/episodes?preferred_audio_language=ja-JP");
var episodeRequest = new HttpRequestMessage(HttpMethod.Get, $"{Api.Cms}/seasons/{seasonID}/episodes?preferred_audio_language=ja-JP");
episodeRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", crunInstance.Token?.access_token);

View File

@ -35,7 +35,20 @@ public class History(Crunchyroll crunInstance){
foreach (var key in result[season].Keys){
var s = result[season][key];
if (!string.IsNullOrEmpty(seasonId) && s.Id != seasonId) continue;
var seasonData = await crunInstance.CrSeries.GetSeasonDataById(s);
var sId = s.Id;
if (s.Versions is{ Count: > 0 }){
foreach (var sVersion in s.Versions){
if (sVersion.Original == true){
if (sVersion.Guid != null){
sId = sVersion.Guid;
}
break;
}
}
}
var seasonData = await crunInstance.CrSeries.GetSeasonDataById(sId);
UpdateWithSeasonData(seasonData);
}
}
@ -107,7 +120,7 @@ public class History(Crunchyroll crunInstance){
historySeries.Seasons.Add(newSeason);
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum).ToList();
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum != null ? int.Parse(s.SeasonNum) : 0).ToList();
}
historySeries.UpdateNewEpisodes();
} else{
@ -148,15 +161,24 @@ public class History(Crunchyroll crunInstance){
if (historySeason != null){
foreach (var crunchyEpisode in seasonData.Data){
if (historySeason.EpisodesList.All(e => e.EpisodeId != crunchyEpisode.Id)){
var historyEpisode = historySeason.EpisodesList.Find(e => e.EpisodeId == crunchyEpisode.Id);
if (historyEpisode == null){
var newHistoryEpisode = new HistoryEpisode{
EpisodeTitle = crunchyEpisode.Title,
EpisodeId = crunchyEpisode.Id,
Episode = crunchyEpisode.Episode,
SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _),
};
historySeason.EpisodesList.Add(newHistoryEpisode);
} else{
//Update existing episode
historyEpisode.EpisodeTitle = crunchyEpisode.Title;
historyEpisode.SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _);
}
}
historySeason.EpisodesList.Sort(new NumericStringPropertyComparer());
@ -167,7 +189,7 @@ public class History(Crunchyroll crunInstance){
historySeries.Seasons.Add(newSeason);
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum).ToList();
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum != null ? int.Parse(s.SeasonNum) : 0).ToList();
}
historySeries.UpdateNewEpisodes();
} else{
@ -190,6 +212,7 @@ public class History(Crunchyroll crunInstance){
newHistorySeries.Seasons.Add(newSeason);
newHistorySeries.UpdateNewEpisodes();
}
}
@ -235,6 +258,7 @@ public class History(Crunchyroll crunInstance){
EpisodeTitle = crunchyEpisode.Title,
EpisodeId = crunchyEpisode.Id,
Episode = crunchyEpisode.Episode,
SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _),
};
newSeason.EpisodesList.Add(newHistoryEpisode);
@ -255,6 +279,7 @@ public class History(Crunchyroll crunInstance){
EpisodeTitle = episode.Title,
EpisodeId = episode.Id,
Episode = episode.Episode,
SpecialEpisode = !int.TryParse(episode.Episode, out _),
};
newSeason.EpisodesList.Add(newHistoryEpisode);
@ -328,7 +353,7 @@ public class HistorySeries : INotifyPropertyChanged{
// Iterate over the Episodes from the end to the beginning
for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){
if (!Seasons[i].EpisodesList[j].WasDownloaded){
if (!Seasons[i].EpisodesList[j].WasDownloaded && !Seasons[i].EpisodesList[j].SpecialEpisode){
count++;
} else{
foundWatched = true;
@ -351,7 +376,7 @@ public class HistorySeries : INotifyPropertyChanged{
// Iterate over the Episodes from the end to the beginning
for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){
if (!Seasons[i].EpisodesList[j].WasDownloaded){
if (!Seasons[i].EpisodesList[j].WasDownloaded && !Seasons[i].EpisodesList[j].SpecialEpisode){
//ADD to download queue
await Seasons[i].EpisodesList[j].DownloadEpisode();
} else{
@ -419,6 +444,9 @@ public partial class HistoryEpisode : INotifyPropertyChanged{
[JsonProperty("episode_was_downloaded")]
public bool WasDownloaded{ get; set; }
[JsonProperty("episode_special_episode")]
public bool SpecialEpisode{ get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
public void ToggleWasDownloaded(){

View File

@ -32,7 +32,7 @@ public struct SeriesSearchItem{
[JsonProperty("season_number")] public int SeasonNumber{ get; set; }
public Dictionary<object, object> Images{ get; set; }
[JsonProperty("mature_blocked")] public bool MatureBlocked{ get; set; }
public List<Version> Versions{ get; set; }
public List<Version>? Versions{ get; set; }
public string Title{ get; set; }
[JsonProperty("is_subbed")] public bool IsSubbed{ get; set; }
public string Id{ get; set; }

View File

@ -4,18 +4,24 @@ using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CRD.Downloader;
using CRD.Utils;
using CRD.Views;
using ReactiveUI;
namespace CRD.ViewModels;
public partial class HistoryPageViewModel : ViewModelBase{
public ObservableCollection<HistorySeries> Items{ get; }
[ObservableProperty] private bool? _showLoading = false;
[ObservableProperty]
private bool? _showLoading = false;
[ObservableProperty]
public HistorySeries _selectedSeries;
[ObservableProperty]
public static bool _editMode;
public HistoryPageViewModel(){
Items = Crunchyroll.Instance.HistoryList;
@ -23,9 +29,9 @@ public partial class HistoryPageViewModel : ViewModelBase{
if (historySeries.ThumbnailImage == null){
historySeries.LoadImage();
}
historySeries.UpdateNewEpisodes();
}
}
@ -35,6 +41,18 @@ public partial class HistoryPageViewModel : ViewModelBase{
_selectedSeries = null;
}
[RelayCommand]
public void RemoveSeries(string? seriesId){
HistorySeries? objectToRemove = Crunchyroll.Instance.HistoryList.ToList().Find(se => se.SeriesId == seriesId) ?? null;
if (objectToRemove != null) {
Crunchyroll.Instance.HistoryList.Remove(objectToRemove);
Items.Remove(objectToRemove);
}
CfgManager.WriteJsonToFile(CfgManager.PathCrHistory, Crunchyroll.Instance.HistoryList);
}
[RelayCommand]
public void NavToSeries(){
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel), false, false));
@ -47,6 +65,7 @@ public partial class HistoryPageViewModel : ViewModelBase{
await Items[i].FetchData("");
Items[i].UpdateNewEpisodes();
}
ShowLoading = false;
}
@ -55,8 +74,7 @@ public partial class HistoryPageViewModel : ViewModelBase{
for (int i = 0; i < Items.Count; i++){
await Items[i].AddNewMissingToDownloads();
}
ShowLoading = false;
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
@ -23,9 +24,25 @@ public partial class MainWindowViewModel : ViewModelBase{
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
Init();
CleanUpOldUpdater();
}
private void CleanUpOldUpdater() {
string backupFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Updater.exe.bak");
if (File.Exists(backupFilePath)) {
try {
File.Delete(backupFilePath);
Console.WriteLine($"Deleted old updater file: {backupFilePath}");
} catch (Exception ex) {
Console.WriteLine($"Failed to delete old updater file: {ex.Message}");
}
} else {
Console.WriteLine("No old updater file found to delete.");
}
}
public async void Init(){

View File

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CRD.Downloader;
using CRD.Utils;
using CRD.Views;
using ReactiveUI;
@ -14,6 +15,9 @@ public partial class SeriesPageViewModel : ViewModelBase{
[ObservableProperty]
public HistorySeries _selectedSeries;
[ObservableProperty]
public static bool _editMode;
public SeriesPageViewModel(){
_selectedSeries = Crunchyroll.Instance.SelectedSeries;
@ -29,6 +33,19 @@ public partial class SeriesPageViewModel : ViewModelBase{
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,true));
}
[RelayCommand]
public void RemoveSeason(string? season){
HistorySeason? objectToRemove = SelectedSeries.Seasons.Find(se => se.SeasonId == season) ?? null;
if (objectToRemove != null) {
SelectedSeries.Seasons.Remove(objectToRemove);
}
CfgManager.WriteJsonToFile(CfgManager.PathCrHistory, Crunchyroll.Instance.HistoryList);
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,true));
}
[RelayCommand]
public void NavBack(){
SelectedSeries.UpdateNewEpisodes();

View File

@ -5,6 +5,7 @@
xmlns:vm="clr-namespace:CRD.ViewModels"
xmlns:ui="clr-namespace:CRD.Utils.UI"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
x:DataType="vm:HistoryPageViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="CRD.Views.HistoryPageView">
@ -23,6 +24,7 @@
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" Margin="20 0 0 0 ">
<Button Command="{Binding RefreshAll}" Margin="10">Refresh All</Button>
<Button Command="{Binding AddMissingToQueue}" Margin="10">Add To Queue</Button>
<ToggleButton IsChecked="{Binding EditMode}" Margin="10">Edit</ToggleButton>
</StackPanel>
<Grid Grid.Row="1" Grid.Column="0">
@ -44,6 +46,9 @@
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="250" Width="250"
MaxHeight="400" Height="400" Margin="5">
<Grid>
@ -58,6 +63,26 @@
Margin="4,0,0,0">
</TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="250" Width="250"
MaxHeight="400" Height="400" Background="#90000000" IsVisible="{Binding $parent[UserControl].((vm:HistoryPageViewModel)DataContext).EditMode}">
<Button MaxWidth="250" Width="250" MaxHeight="400" Height="400" FontStyle="Italic"
VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:HistoryPageViewModel)DataContext).RemoveSeries}"
CommandParameter="{Binding SeriesId}"
>
<ToolTip.Tip>
<TextBlock Text="Remove Series" FontSize="15" />
</ToolTip.Tip>
<StackPanel Orientation="Horizontal">
<controls:SymbolIcon Symbol="Delete" FontSize="32" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

View File

@ -29,7 +29,6 @@
</Image>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
@ -41,15 +40,14 @@
<TextBlock Grid.Row="0" FontSize="50" Text="{Binding SelectedSeries.SeriesTitle}"></TextBlock>
<TextBlock Grid.Row="1" FontSize="20" TextWrapping="Wrap" Text="{Binding SelectedSeries.SeriesDescription}"></TextBlock>
<Button Grid.Row="3" Command="{Binding UpdateData}" Margin="0 0 0 10">Fetch Series</Button>
<StackPanel Grid.Row="3" Orientation="Horizontal">
<Button Command="{Binding UpdateData}" Margin="0 0 5 10">Fetch Series</Button>
<ToggleButton IsChecked="{Binding EditMode}" Margin="0 0 0 10">Edit</ToggleButton>
</StackPanel>
</Grid>
<ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
<ItemsControl ItemsSource="{Binding SelectedSeries.Seasons}">
<ItemsControl.ItemTemplate>
@ -63,7 +61,6 @@
IsExpanded="False">
<controls:SettingsExpander.ItemTemplate>
<DataTemplate>
@ -83,14 +80,22 @@
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent" BorderThickness="0" CornerRadius="50" IsVisible="{Binding !WasDownloaded}" Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}" CommandParameter="{Binding EpisodeId}">
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent"
BorderThickness="0" CornerRadius="50"
IsVisible="{Binding !WasDownloaded}"
Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}"
CommandParameter="{Binding EpisodeId}">
<Grid>
<Ellipse Width="25" Height="25" Fill="Gray" />
<controls:SymbolIcon Symbol="Checkmark" FontSize="18" />
</Grid>
</Button>
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent" BorderThickness="0" CornerRadius="50" IsVisible="{Binding WasDownloaded}" Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}" CommandParameter="{Binding EpisodeId}">
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent"
BorderThickness="0" CornerRadius="50"
IsVisible="{Binding WasDownloaded}"
Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}"
CommandParameter="{Binding EpisodeId}">
<Grid>
<Ellipse Width="25" Height="25" Fill="#21a556" />
<controls:SymbolIcon Symbol="Checkmark" FontSize="18" />
@ -115,7 +120,9 @@
<TextBlock Text="/" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="{Binding EpisodesList.Count}" VerticalAlignment="Center"></TextBlock>
<Button Margin="10 0 0 0" FontStyle="Italic"
VerticalAlignment="Center" Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).UpdateData}" CommandParameter="{Binding SeasonId}" >
VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).UpdateData}"
CommandParameter="{Binding SeasonId}">
<ToolTip.Tip>
<TextBlock Text="Fetch Season" FontSize="15" />
</ToolTip.Tip>
@ -123,6 +130,18 @@
<controls:SymbolIcon Symbol="Refresh" FontSize="18" />
</StackPanel>
</Button>
<Button Margin="10 0 0 0" FontStyle="Italic"
VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).RemoveSeason}"
CommandParameter="{Binding SeasonId}"
IsVisible="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).EditMode}">
<ToolTip.Tip>
<TextBlock Text="Remove Season" FontSize="15" />
</ToolTip.Tip>
<StackPanel Orientation="Horizontal">
<controls:SymbolIcon Symbol="Delete" FontSize="18" />
</StackPanel>
</Button>
</StackPanel>
</controls:SettingsExpander.Footer>