Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add retry button to failed and canceled tasks #1194

Merged
merged 8 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@

[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}]
[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}]
indent_style = space
indent_size = 4
tab_width = 4

[*.resx]
indent_style = space
indent_size = 2
tab_width = 4

[*.cs]

# Microsoft .NET properties
Expand Down
1 change: 1 addition & 0 deletions TwitchDownloaderWPF/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" />
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" />
<!-- Top dictionaries MUST be HandyControl, other merged dictionaries below -->
<ResourceDictionary Source="pack://application:,,,/WpfExtensions.Xaml;component/converters/importoperators.xaml" />
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="AppBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="AppElementBackground" Color="#FFFFFF" />
Expand Down
19 changes: 13 additions & 6 deletions TwitchDownloaderWPF/PageQueue.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:fa="http://schemas.fontawesome.com/icons/"
xmlns:markup="clr-namespace:WpfExtensions.Xaml.Markup;assembly=WpfExtensions.Xaml"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="800"
Title="PageQueue" Loaded="Page_Loaded">
Expand Down Expand Up @@ -45,14 +46,19 @@
<fa:SvgAwesome Icon="Solid_StopCircle" Foreground="{DynamicResource AppText}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{lex:Loc TaskErrorButton}" Click="MenuItemTaskError_Click" Visibility="{Binding Exception.Visibility}" Foreground="{DynamicResource AppText}">
<MenuItem Header="{lex:Loc ContextMenuRemoveTask}" Click="MenuItemRemoveTask_Click" Foreground="{DynamicResource AppText}">
<MenuItem.Icon>
<fa:SvgAwesome Icon="Solid_ExclamationTriangle" Foreground="{DynamicResource AppText}" />
<fa:SvgAwesome Icon="Solid_Times" Foreground="{DynamicResource AppText}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{lex:Loc ContextMenuRemoveTask}" Click="MenuItemRemoveTask_Click" Foreground="{DynamicResource AppText}">
<MenuItem Header="{lex:Loc TaskRetry}" Click="MenuItemTaskRetry_Click" Visibility="{Binding CanReinitialize, Converter={StaticResource Boolean2VisibilityConverter}}" Foreground="{DynamicResource AppText}">
<MenuItem.Icon>
<fa:SvgAwesome Icon="Solid_Times" Foreground="{DynamicResource AppText}" />
<fa:SvgAwesome Icon="Solid_Redo" Foreground="{DynamicResource AppText}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{lex:Loc TaskErrorButton}" Click="MenuItemTaskError_Click" Visibility="{Binding Exception, Converter={markup:Compose {StaticResource IsNullOperator}, {StaticResource NotOperator}, {StaticResource Boolean2VisibilityConverter}}}" Foreground="{DynamicResource AppText}">
<MenuItem.Icon>
<fa:SvgAwesome Icon="Solid_ExclamationTriangle" Foreground="{DynamicResource AppText}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{lex:Loc ContextMenuOpenTaskFolder}" Click="MenuItemOpenTaskFolder_Click" Foreground="{DynamicResource AppText}">
Expand All @@ -74,8 +80,9 @@
<TextBlock Text="{Binding TaskType, StringFormat=Task Type: {0}}" Foreground="{DynamicResource AppText}"></TextBlock>
<TextBlock Text="{Binding DisplayStatus, StringFormat=Status: {0}, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" Foreground="{DynamicResource AppText}"></TextBlock>
<StackPanel Orientation="Horizontal" Margin="1,1,0,1">
<Button Content="{lex:Loc TaskCancel}" Margin="0,0,4,0" MinWidth="60" Height="28" FontSize="12" Click="BtnCancelTask_Click" IsEnabled="{Binding CanCancel}" Background="{DynamicResource ActionButtonBackground}" Foreground="{DynamicResource ActionButtonText}" BorderBrush="{DynamicResource ActionButtonBorder}" />
<Button Visibility="{Binding Exception.Visibility}" Content="{lex:Loc TaskErrorButton}" Margin="0,0,4,0" MinWidth="60" Height="28" FontSize="12" Click="BtnTaskError_Click" Background="{DynamicResource ActionButtonBackground}" Foreground="{DynamicResource ActionButtonText}" BorderBrush="{DynamicResource ActionButtonBorder}" />
<Button Content="{lex:Loc TaskCancel}" Margin="0,0,4,0" MinWidth="60" Height="28" FontSize="12" Click="BtnCancelTask_Click" Visibility="{Binding CanCancel, Converter={StaticResource Boolean2VisibilityConverter}}" Background="{DynamicResource ActionButtonBackground}" Foreground="{DynamicResource ActionButtonText}" BorderBrush="{DynamicResource ActionButtonBorder}" />
<Button Content="{lex:Loc TaskRetry}" Margin="0,0,4,0" MinWidth="60" Height="28" FontSize="12" Click="BtnRetryTask_Click" Visibility="{Binding CanReinitialize, Converter={StaticResource Boolean2VisibilityConverter}}" Background="{DynamicResource ActionButtonBackground}" Foreground="{DynamicResource ActionButtonText}" BorderBrush="{DynamicResource ActionButtonBorder}" />
<Button Content="{lex:Loc TaskErrorButton}" Margin="0,0,4,0" MinWidth="60" Height="28" FontSize="12" Click="BtnTaskError_Click" Visibility="{Binding Exception, Converter={markup:Compose {StaticResource IsNullOperator}, {StaticResource NotOperator}, {StaticResource Boolean2VisibilityConverter}}}" Background="{DynamicResource ActionButtonBackground}" Foreground="{DynamicResource ActionButtonText}" BorderBrush="{DynamicResource ActionButtonBorder}" />
<ProgressBar Height="16" Width="200" Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Background="{DynamicResource AppElementInnerBackground}" Foreground="{DynamicResource ProgressBarForeground}" />
<Image MaxHeight="20" Margin="5,0" gif:ImageBehavior.AnimatedSource="{Binding StatusImage, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
Expand Down
34 changes: 31 additions & 3 deletions TwitchDownloaderWPF/PageQueue.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,15 @@ private static void ShowTaskException(ITwitchTask task)
{
var taskException = task.Exception;

if (taskException?.Exception == null)
if (taskException is null)
{
return;
}

var errorMessage = taskException.Exception.Message;
var errorMessage = taskException.Message;
if (Settings.Default.VerboseErrors)
{
errorMessage = taskException.Exception.ToString();
errorMessage = taskException.ToString();
}

MessageBox.Show(Application.Current.MainWindow!, errorMessage, Translations.Strings.MessageBoxTitleError, MessageBoxButton.OK, MessageBoxImage.Error);
Expand Down Expand Up @@ -305,5 +305,33 @@ private void MenuItemOpenTaskFolder_Click(object sender, RoutedEventArgs e)

FileService.OpenExplorerForFile(new FileInfo(task.OutputFile));
}

private void BtnRetryTask_Click(object sender, RoutedEventArgs e)
{
if (sender is not Button { DataContext: ITwitchTask task })
{
return;
}

RetryTask(task);
}

private void MenuItemTaskRetry_Click(object sender, RoutedEventArgs e)
{
if (sender is not MenuItem { DataContext: ITwitchTask task })
{
return;
}

RetryTask(task);
}

private static void RetryTask(ITwitchTask task)
{
if (task.CanReinitialize)
{
task.Reinitialize();
}
}
}
}
10 changes: 10 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.es.resx
Original file line number Diff line number Diff line change
Expand Up @@ -934,4 +934,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.fr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.it.resx
Original file line number Diff line number Diff line change
Expand Up @@ -934,4 +934,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.ja.resx
Original file line number Diff line number Diff line change
Expand Up @@ -932,4 +932,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>正確なトリミングでトリミングされた動画は、まれに最初と最後の数秒間映像や音声が途切れることがあります。セーフなトリミングでは、映像や音声が途切れることはありませんが映像が若干長くなる可能性があります。</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.pl.resx
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.pt-br.resx
Original file line number Diff line number Diff line change
Expand Up @@ -932,4 +932,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -932,4 +932,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.ru.resx
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Иногда обрезанное видео может испытывать проблемы с заиканьем в первых/последних нескольких секунд. Безопасная обрезка гарантирует отсутствие заикания, но может немного удлинить видео.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.tr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -934,4 +934,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.uk.resx
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>Videos trimmed with exact trim may rarely experience video/audio stuttering within the first/last few seconds. Safe trimming is guaranteed to not stutter but may result in a slightly longer video.</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
3 changes: 3 additions & 0 deletions TwitchDownloaderWPF/Translations/Strings.zh-cn.resx
Original file line number Diff line number Diff line change
Expand Up @@ -935,4 +935,7 @@
<data name="VideoTrimModeTooltip" xml:space="preserve">
<value>使用精确模式修剪的视频在前几秒或最后几秒可能会出现视频 / 音频卡顿。安全模式保证不会出现卡顿,但可能会导致视频稍长。</value>
</data>
<data name="TaskRetry" xml:space="preserve">
<value>Retry</value>
</data>
</root>
1 change: 1 addition & 0 deletions TwitchDownloaderWPF/TwitchDownloaderWPF.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="WpfExtensions.Xaml" Version="1.2.0" />
<PackageReference Include="WPFLocalizeExtension" Version="3.10.0" />
<PackageReference Include="Xabe.FFmpeg.Downloader" Version="5.2.6" />
<PackageReference Include="Autoupdater.NET.Official" Version="1.9.1" />
Expand Down
37 changes: 27 additions & 10 deletions TwitchDownloaderWPF/TwitchTasks/ChatDownloadTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace TwitchDownloaderWPF.TwitchTasks
{
internal class ChatDownloadTask : ITwitchTask
{
public TaskData Info { get; set; } = new TaskData();
public TaskData Info { get; } = new();

private int _progress;
public int Progress
Expand Down Expand Up @@ -43,26 +43,33 @@ public string StatusImage
}

public ChatDownloadOptions DownloadOptions { get; init; }
public CancellationTokenSource TokenSource { get; set; } = new CancellationTokenSource();
public CancellationTokenSource TokenSource { get; private set; } = new();
public ITwitchTask DependantTask { get; set; }
public string TaskType { get; } = Translations.Strings.ChatDownload;

private TwitchTaskException _exception = new();
public TwitchTaskException Exception
private Exception _exception;
public Exception Exception
{
get => _exception;
private set => SetField(ref _exception, value);
}

public string OutputFile => DownloadOptions.Filename;

private bool _canCancel = true;
private bool _canCancel;
public bool CanCancel
{
get => _canCancel;
private set => SetField(ref _canCancel, value);
}

private bool _canReinitialize;
public bool CanReinitialize
{
get => _canReinitialize;
private set => SetField(ref _canReinitialize, value);
}

public event PropertyChangedEventHandler PropertyChanged;

public void Cancel()
Expand All @@ -83,6 +90,15 @@ public void Cancel()
ChangeStatus(TwitchTaskStatus.Canceled);
}

public void Reinitialize()
{
Progress = 0;
TokenSource = new CancellationTokenSource();
Exception = null;
CanReinitialize = false;
ChangeStatus(TwitchTaskStatus.Ready);
}

public bool CanRun()
{
return Status == TwitchTaskStatus.Ready;
Expand All @@ -93,10 +109,7 @@ public void ChangeStatus(TwitchTaskStatus newStatus)
Status = newStatus;
DisplayStatus = newStatus.ToString();

if (CanCancel && newStatus is TwitchTaskStatus.Canceled or TwitchTaskStatus.Failed or TwitchTaskStatus.Finished or TwitchTaskStatus.Stopping)
{
CanCancel = false;
}
CanCancel = newStatus is not TwitchTaskStatus.Canceled and not TwitchTaskStatus.Failed and not TwitchTaskStatus.Finished and not TwitchTaskStatus.Stopping;

StatusImage = newStatus switch
{
Expand All @@ -113,6 +126,7 @@ public async Task RunAsync()
{
TokenSource.Dispose();
ChangeStatus(TwitchTaskStatus.Canceled);
CanReinitialize = true;
return;
}

Expand All @@ -125,6 +139,7 @@ public async Task RunAsync()
if (TokenSource.IsCancellationRequested)
{
ChangeStatus(TwitchTaskStatus.Canceled);
CanReinitialize = true;
}
else
{
Expand All @@ -135,11 +150,13 @@ public async Task RunAsync()
catch (Exception ex) when (ex is OperationCanceledException or TaskCanceledException && TokenSource.IsCancellationRequested)
{
ChangeStatus(TwitchTaskStatus.Canceled);
CanReinitialize = true;
}
catch (Exception ex)
{
ChangeStatus(TwitchTaskStatus.Failed);
Exception = new TwitchTaskException(ex);
Exception = ex;
CanReinitialize = true;
}
downloader = null;
TokenSource.Dispose();
Expand Down
Loading
Loading