BililiveRecorder/BililiveRecorder.WPF/Pages/ToolboxAutoFixPage.xaml.cs

379 lines
14 KiB
C#
Raw Permalink Normal View History

2021-02-23 18:03:37 +08:00
using System;
using System.Collections.Generic;
using System.ComponentModel;
2021-02-27 18:14:44 +08:00
using System.IO;
using System.Runtime.CompilerServices;
2021-05-02 21:34:27 +08:00
using System.Threading;
2021-02-23 18:03:37 +08:00
using System.Threading.Tasks;
using System.Windows;
2021-04-19 18:20:14 +08:00
using BililiveRecorder.ToolBox;
2021-07-15 20:20:13 +08:00
using BililiveRecorder.ToolBox.Tool.Analyze;
using BililiveRecorder.ToolBox.Tool.Export;
using BililiveRecorder.ToolBox.Tool.Fix;
2021-02-27 18:14:44 +08:00
using BililiveRecorder.WPF.Controls;
using Microsoft.WindowsAPICodePack.Dialogs;
using Serilog;
2021-05-01 23:18:22 +08:00
using WPFLocalizeExtension.Extensions;
2021-02-23 18:03:37 +08:00
2021-02-27 18:14:44 +08:00
#nullable enable
2021-02-23 18:03:37 +08:00
namespace BililiveRecorder.WPF.Pages
{
/// <summary>
/// Interaction logic for ToolboxAutoFixPage.xaml
/// </summary>
public partial class ToolboxAutoFixPage
{
2021-02-27 18:14:44 +08:00
private static readonly ILogger logger = Log.ForContext<ToolboxAutoFixPage>();
private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
2021-02-27 18:14:44 +08:00
private readonly AutoFixSettings settings = new AutoFixSettings();
2021-02-23 18:03:37 +08:00
public ToolboxAutoFixPage()
{
2021-02-27 18:14:44 +08:00
this.InitializeComponent();
this.SettingsArea.DataContext = this.settings;
2021-02-27 18:14:44 +08:00
}
private void SelectFile_Button_Click(object sender, RoutedEventArgs e)
{
2021-05-01 23:18:22 +08:00
var title = LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_AutoFix_SelectInputDialog_Title");
2021-02-27 18:14:44 +08:00
var fileDialog = new CommonOpenFileDialog()
{
Title = title,
IsFolderPicker = false,
Multiselect = false,
AllowNonFileSystemItems = false,
AddToMostRecentlyUsedList = false,
EnsurePathExists = true,
EnsureFileExists = true,
NavigateToShortcut = true,
Filters =
{
2021-05-01 23:18:22 +08:00
new CommonFileDialogFilter("FLV",".flv"),
new CommonFileDialogFilter("dev's toy",".xml,.gz,.zip")
2021-02-27 18:14:44 +08:00
}
};
if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok)
{
this.FileNameTextBox.Text = fileDialog.FileName;
}
}
2021-05-01 17:57:43 +08:00
#pragma warning disable VSTHRD100 // Avoid async void methods
2021-02-27 18:14:44 +08:00
private async void Fix_Button_Click(object sender, RoutedEventArgs e)
2021-05-01 17:57:43 +08:00
#pragma warning restore VSTHRD100 // Avoid async void methods
2021-02-27 18:14:44 +08:00
{
AutoFixProgressDialog? progressDialog = null;
if (!this.semaphoreSlim.Wait(0))
return;
2021-02-27 18:14:44 +08:00
try
{
var inputPath = this.FileNameTextBox.Text;
if (string.IsNullOrWhiteSpace(inputPath) || !File.Exists(inputPath))
return;
logger.Debug("修复文件 {Path}", inputPath);
2021-05-02 21:34:27 +08:00
progressDialog = new AutoFixProgressDialog()
{
CancelButtonVisibility = Visibility.Visible,
CancellationTokenSource = new CancellationTokenSource(),
Owner = Application.Current.MainWindow
2021-05-02 21:34:27 +08:00
};
var token = progressDialog.CancellationTokenSource.Token;
var showTask = progressDialog.ShowAndDisableMinimizeToTrayAsync();
2021-02-27 18:14:44 +08:00
2021-04-14 23:46:24 +08:00
string? output_path;
2021-02-27 18:14:44 +08:00
{
2021-05-01 23:18:22 +08:00
var title = LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_AutoFix_SelectOutputDialog_Title");
2021-02-27 18:14:44 +08:00
var fileDialog = new CommonSaveFileDialog()
{
Title = title,
AddToMostRecentlyUsedList = false,
EnsurePathExists = true,
EnsureValidNames = true,
NavigateToShortcut = true,
OverwritePrompt = false,
2021-05-01 17:57:43 +08:00
InitialDirectory = Path.GetDirectoryName(inputPath),
2021-02-27 18:14:44 +08:00
DefaultDirectory = Path.GetDirectoryName(inputPath),
DefaultFileName = Path.GetFileName(inputPath)
};
if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok)
2021-04-14 23:46:24 +08:00
output_path = fileDialog.FileName;
2021-02-27 18:14:44 +08:00
else
return;
}
2021-04-14 23:46:24 +08:00
var req = new FixRequest
2021-02-27 18:14:44 +08:00
{
2021-04-14 23:46:24 +08:00
Input = inputPath,
OutputBase = output_path,
PipelineSettings = new Flv.Pipeline.ProcessingPipelineSettings
{
SplitOnScriptTag = this.settings.SplitOnScriptTag,
DisableSplitOnH264AnnexB = this.settings.DisableSplitOnH264AnnexB,
}
2021-04-14 23:46:24 +08:00
};
2021-02-27 18:14:44 +08:00
2021-04-14 23:46:24 +08:00
var handler = new FixHandler();
2021-02-27 18:14:44 +08:00
2021-05-02 21:34:27 +08:00
var resp = await handler.Handle(req, token, async p =>
2021-04-14 23:46:24 +08:00
{
await this.Dispatcher.InvokeAsync(() =>
{
progressDialog.Progress = (int)(p * 98d);
});
2021-02-27 18:14:44 +08:00
}).ConfigureAwait(true);
2021-05-05 22:11:51 +08:00
logger.Debug("修复结果 {@Response}", resp);
2021-05-02 21:34:27 +08:00
if (resp.Status != ResponseStatus.Cancelled && resp.Status != ResponseStatus.OK)
2021-04-19 18:20:14 +08:00
{
logger.Warning(resp.Exception, "修复时发生错误 (@Status)", resp.Status);
2021-05-01 23:18:22 +08:00
await Task.Run(() => ShowErrorMessageBox(resp)).ConfigureAwait(true);
2021-04-19 18:20:14 +08:00
}
2021-02-27 18:14:44 +08:00
progressDialog.Hide();
await showTask.ConfigureAwait(true);
}
catch (Exception ex)
{
2021-04-19 18:20:14 +08:00
logger.Error(ex, "修复时发生未处理的错误");
2021-02-27 18:14:44 +08:00
}
finally
{
try
{
_ = this.Dispatcher.BeginInvoke((Action)(() => progressDialog?.Hide()));
progressDialog?.CancellationTokenSource?.Cancel();
2021-02-27 18:14:44 +08:00
}
catch (Exception) { }
this.semaphoreSlim.Release();
2021-02-27 18:14:44 +08:00
}
}
2021-07-15 20:20:13 +08:00
private static void ShowErrorMessageBox<T>(CommandResponse<T> resp) where T : IResponseData
2021-05-01 23:18:22 +08:00
{
var title = LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_AutoFix_Error_Title");
var type = LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_AutoFix_Error_Type_" + resp.Status.ToString());
MessageBox.Show($"{type}\n{resp.ErrorMessage}", title, MessageBoxButton.OK, MessageBoxImage.Warning);
}
2021-05-01 17:57:43 +08:00
#pragma warning disable VSTHRD100 // Avoid async void methods
2021-02-27 20:44:04 +08:00
private async void Analyze_Button_Click(object sender, RoutedEventArgs e)
2021-05-01 17:57:43 +08:00
#pragma warning restore VSTHRD100 // Avoid async void methods
2021-02-27 18:14:44 +08:00
{
AutoFixProgressDialog? progressDialog = null;
if (!this.semaphoreSlim.Wait(0))
return;
2021-02-27 18:14:44 +08:00
try
{
var inputPath = this.FileNameTextBox.Text;
if (string.IsNullOrWhiteSpace(inputPath) || !File.Exists(inputPath))
return;
logger.Debug("分析文件 {Path}", inputPath);
2021-05-02 21:34:27 +08:00
progressDialog = new AutoFixProgressDialog()
{
CancelButtonVisibility = Visibility.Visible,
CancellationTokenSource = new CancellationTokenSource(),
Owner = Application.Current.MainWindow
2021-05-02 21:34:27 +08:00
};
var token = progressDialog.CancellationTokenSource.Token;
var showTask = progressDialog.ShowAndDisableMinimizeToTrayAsync();
2021-02-27 18:14:44 +08:00
2021-04-14 23:46:24 +08:00
var req = new AnalyzeRequest
2021-02-27 20:44:04 +08:00
{
Input = inputPath,
PipelineSettings = new Flv.Pipeline.ProcessingPipelineSettings
{
SplitOnScriptTag = this.settings.SplitOnScriptTag,
DisableSplitOnH264AnnexB = this.settings.DisableSplitOnH264AnnexB,
}
2021-04-14 23:46:24 +08:00
};
2021-02-27 18:14:44 +08:00
2021-04-14 23:46:24 +08:00
var handler = new AnalyzeHandler();
2021-02-27 20:44:04 +08:00
2021-05-02 21:34:27 +08:00
var resp = await handler.Handle(req, token, async p =>
2021-02-27 20:44:04 +08:00
{
2021-04-14 23:46:24 +08:00
await this.Dispatcher.InvokeAsync(() =>
{
progressDialog.Progress = (int)(p * 98d);
});
}).ConfigureAwait(true);
2021-02-27 20:44:04 +08:00
2021-05-05 22:11:51 +08:00
logger.Debug("分析结果 {@Response}", resp);
2021-05-02 21:34:27 +08:00
if (resp.Status != ResponseStatus.Cancelled)
2021-04-19 18:20:14 +08:00
{
2021-05-02 21:34:27 +08:00
if (resp.Status != ResponseStatus.OK)
{
logger.Warning(resp.Exception, "分析时发生错误 (@Status)", resp.Status);
await Task.Run(() => ShowErrorMessageBox(resp)).ConfigureAwait(true);
}
else
{
2021-07-15 20:20:13 +08:00
this.analyzeResultDisplayArea.DataContext = resp.Data;
2021-05-02 21:34:27 +08:00
}
2021-04-19 18:20:14 +08:00
}
2021-02-27 20:44:04 +08:00
progressDialog.Hide();
await showTask.ConfigureAwait(true);
2021-02-27 18:14:44 +08:00
}
catch (Exception ex)
{
2021-04-19 18:20:14 +08:00
logger.Error(ex, "分析时发生未处理的错误");
2021-02-27 18:14:44 +08:00
}
finally
{
try
{
_ = this.Dispatcher.BeginInvoke((Action)(() => progressDialog?.Hide()));
progressDialog?.CancellationTokenSource?.Cancel();
2021-02-27 18:14:44 +08:00
}
catch (Exception) { }
this.semaphoreSlim.Release();
2021-02-27 18:14:44 +08:00
}
}
2021-05-01 17:57:43 +08:00
#pragma warning disable VSTHRD100 // Avoid async void methods
2021-02-27 18:14:44 +08:00
private async void Export_Button_Click(object sender, RoutedEventArgs e)
2021-05-01 17:57:43 +08:00
#pragma warning restore VSTHRD100 // Avoid async void methods
2021-02-27 18:14:44 +08:00
{
AutoFixProgressDialog? progressDialog = null;
if (!this.semaphoreSlim.Wait(0))
return;
2021-02-27 18:14:44 +08:00
try
{
var inputPath = this.FileNameTextBox.Text;
if (string.IsNullOrWhiteSpace(inputPath) || !File.Exists(inputPath))
return;
logger.Debug("导出文件 {Path}", inputPath);
2021-05-02 21:34:27 +08:00
progressDialog = new AutoFixProgressDialog()
{
CancelButtonVisibility = Visibility.Visible,
CancellationTokenSource = new CancellationTokenSource(),
Owner = Application.Current.MainWindow
2021-05-02 21:34:27 +08:00
};
var token = progressDialog.CancellationTokenSource.Token;
var showTask = progressDialog.ShowAndDisableMinimizeToTrayAsync();
2021-02-27 18:14:44 +08:00
var outputPath = string.Empty;
{
2021-05-01 23:18:22 +08:00
var title = LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_AutoFix_SelectOutputDialog_Title");
2021-02-27 18:14:44 +08:00
var fileDialog = new CommonSaveFileDialog()
{
Title = title,
AddToMostRecentlyUsedList = false,
EnsurePathExists = true,
EnsureValidNames = true,
NavigateToShortcut = true,
2021-05-01 23:18:22 +08:00
OverwritePrompt = true,
2021-05-01 17:57:43 +08:00
InitialDirectory = Path.GetDirectoryName(inputPath),
2021-02-27 18:14:44 +08:00
DefaultDirectory = Path.GetDirectoryName(inputPath),
DefaultFileName = Path.GetFileNameWithoutExtension(inputPath) + ".brec.xml.zip"
2021-02-27 18:14:44 +08:00
};
if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok)
outputPath = fileDialog.FileName;
else
return;
}
2021-04-14 23:46:24 +08:00
var req = new ExportRequest
2021-02-27 18:14:44 +08:00
{
2021-04-14 23:46:24 +08:00
Input = inputPath,
Output = outputPath
};
2021-02-27 18:14:44 +08:00
2021-04-14 23:46:24 +08:00
var handler = new ExportHandler();
2021-05-02 21:34:27 +08:00
var resp = await handler.Handle(req, token, async p =>
2021-03-02 23:39:54 +08:00
{
2021-04-14 23:46:24 +08:00
await this.Dispatcher.InvokeAsync(() =>
2021-02-27 18:14:44 +08:00
{
2021-04-14 23:46:24 +08:00
progressDialog.Progress = (int)(p * 95d);
2021-02-27 18:14:44 +08:00
});
2021-03-02 23:39:54 +08:00
}).ConfigureAwait(true);
2021-02-27 18:14:44 +08:00
2021-05-05 22:11:51 +08:00
logger.Debug("导出分析数据结果 {@Response}", resp);
2021-05-02 21:34:27 +08:00
if (resp.Status != ResponseStatus.Cancelled && resp.Status != ResponseStatus.OK)
2021-04-19 18:20:14 +08:00
{
logger.Warning(resp.Exception, "导出分析数据时发生错误 (@Status)", resp.Status);
2021-05-01 23:18:22 +08:00
await Task.Run(() => ShowErrorMessageBox(resp)).ConfigureAwait(true);
2021-04-19 18:20:14 +08:00
}
2021-02-27 18:14:44 +08:00
progressDialog.Hide();
await showTask.ConfigureAwait(true);
}
catch (Exception ex)
{
2021-04-19 18:20:14 +08:00
logger.Error(ex, "导出时发生未处理的错误");
2021-02-27 18:14:44 +08:00
}
finally
{
try
{
_ = this.Dispatcher.BeginInvoke((Action)(() => progressDialog?.Hide()));
progressDialog?.CancellationTokenSource?.Cancel();
2021-02-27 18:14:44 +08:00
}
catch (Exception) { }
this.semaphoreSlim.Release();
2021-02-27 18:14:44 +08:00
}
}
private void FileNameTextBox_Drop(object sender, DragEventArgs e)
{
try
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
this.FileNameTextBox.Text = files[0];
}
}
catch (Exception)
{ }
}
public sealed class AutoFixSettings : INotifyPropertyChanged
{
private bool splitOnScriptTag;
private bool disableSplitOnH264AnnexB;
public event PropertyChangedEventHandler? PropertyChanged;
private bool SetField<T>(ref T location, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(location, value))
return false;
location = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
/// <summary>
/// FLV修复-检测到可能缺少数据时分段
/// </summary>
public bool SplitOnScriptTag { get => this.splitOnScriptTag; set => this.SetField(ref this.splitOnScriptTag, value); }
/// <summary>
/// FLV修复-检测到 H264 Annex-B 时禁用修复分段
/// </summary>
public bool DisableSplitOnH264AnnexB { get => this.disableSplitOnH264AnnexB; set => this.SetField(ref this.disableSplitOnH264AnnexB, value); }
}
2021-02-23 18:03:37 +08:00
}
}