mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-16 11:42:22 +08:00
Toolbox: Improve danmaku merge
This commit is contained in:
parent
2151393a77
commit
7ec8b1d405
|
@ -27,6 +27,18 @@ namespace BililiveRecorder.ToolBox.Tool.DanmakuMerger
|
|||
ErrorMessage = "At least 2 input files required"
|
||||
};
|
||||
|
||||
if (request.Offsets is not null)
|
||||
{
|
||||
if (request.Offsets.Length != inputLength)
|
||||
{
|
||||
return new CommandResponse<DanmakuMergerResponse>
|
||||
{
|
||||
Status = ResponseStatus.Error,
|
||||
ErrorMessage = "The number of offsets should match the number of input files."
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var files = new FileStream[inputLength];
|
||||
var readers = new XmlReader?[inputLength];
|
||||
|
||||
|
@ -34,14 +46,16 @@ namespace BililiveRecorder.ToolBox.Tool.DanmakuMerger
|
|||
XmlWriter? writer = null;
|
||||
XElement recordInfo;
|
||||
|
||||
DateTimeOffset baseTime;
|
||||
TimeSpan[] timeDiff;
|
||||
|
||||
try // finally
|
||||
{
|
||||
|
||||
{
|
||||
// 读取文件开头并计算时间差
|
||||
try
|
||||
{
|
||||
DateTimeOffset baseTime;
|
||||
|
||||
// 打开输入文件
|
||||
for (var i = 0; i < inputLength; i++)
|
||||
{
|
||||
|
@ -50,7 +64,7 @@ namespace BililiveRecorder.ToolBox.Tool.DanmakuMerger
|
|||
readers[i] = XmlReader.Create(file, null);
|
||||
}
|
||||
|
||||
// 计算时间差
|
||||
// 读取XML文件开头
|
||||
var startTimes = new (DateTimeOffset time, XElement element)[inputLength];
|
||||
for (var i = 0; i < inputLength; i++)
|
||||
{
|
||||
|
@ -72,10 +86,22 @@ namespace BililiveRecorder.ToolBox.Tool.DanmakuMerger
|
|||
}
|
||||
}
|
||||
|
||||
var b = startTimes.OrderBy(x => x.time).First();
|
||||
recordInfo = b.element;
|
||||
baseTime = b.time;
|
||||
timeDiff = startTimes.Select(x => x.time - baseTime).ToArray();
|
||||
if (request.Offsets is not null)
|
||||
{
|
||||
// 使用传递进来的参数作为时间差
|
||||
timeDiff = request.Offsets.Select(x => TimeSpan.FromSeconds(x)).ToArray();
|
||||
var b = startTimes[Array.IndexOf(timeDiff, timeDiff.Min())];
|
||||
recordInfo = b.element;
|
||||
baseTime = b.time;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 使用文件内的开始时间作为时间差
|
||||
var b = startTimes.OrderBy(x => x.time).First();
|
||||
recordInfo = b.element;
|
||||
baseTime = b.time;
|
||||
timeDiff = startTimes.Select(x => x.time - baseTime).ToArray();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -6,6 +6,8 @@ namespace BililiveRecorder.ToolBox.Tool.DanmakuMerger
|
|||
{
|
||||
public string[] Inputs { get; set; } = Array.Empty<string>();
|
||||
|
||||
public int[]? Offsets { get; set; } = null;
|
||||
|
||||
public string Output { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace BililiveRecorder.ToolBox.Tool.DanmakuStartTime
|
||||
{
|
||||
public class DanmakuStartTimeHandler : ICommandHandler<DanmakuStartTimeRequest, DanmakuStartTimeResponse>
|
||||
{
|
||||
public string Name => "Read Danmaku start_time";
|
||||
|
||||
public async Task<CommandResponse<DanmakuStartTimeResponse>> Handle(DanmakuStartTimeRequest request, CancellationToken cancellationToken, ProgressCallback? progress)
|
||||
{
|
||||
List<DanmakuStartTimeResponse.DanmakuStartTime> result = new();
|
||||
|
||||
try
|
||||
{
|
||||
progress?.Invoke(0);
|
||||
var finished = 0;
|
||||
double total = request.Inputs.Length;
|
||||
|
||||
Parallel.ForEach(request.Inputs, input =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var file = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var r = XmlReader.Create(file, null);
|
||||
r.ReadStartElement("i");
|
||||
while (r.Name != "i")
|
||||
{
|
||||
if (r.Name == "BililiveRecorderRecordInfo")
|
||||
{
|
||||
var el = (XNode.ReadFrom(r) as XElement)!;
|
||||
var time = (DateTimeOffset)el.Attribute("start_time");
|
||||
result.Add(new DanmakuStartTimeResponse.DanmakuStartTime { Path = input, StartTime = time });
|
||||
|
||||
Interlocked.Increment(ref finished);
|
||||
progress?.Invoke(finished / total);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new CommandResponse<DanmakuStartTimeResponse>
|
||||
{
|
||||
Status = ResponseStatus.Error,
|
||||
Exception = ex,
|
||||
ErrorMessage = ex.Message
|
||||
};
|
||||
}
|
||||
|
||||
return new CommandResponse<DanmakuStartTimeResponse> { Status = ResponseStatus.OK, Data = new DanmakuStartTimeResponse { StartTimes = result.ToArray() } };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace BililiveRecorder.ToolBox.Tool.DanmakuStartTime
|
||||
{
|
||||
public class DanmakuStartTimeRequest : ICommandRequest<DanmakuStartTimeResponse>
|
||||
{
|
||||
public string[] Inputs { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace BililiveRecorder.ToolBox.Tool.DanmakuStartTime
|
||||
{
|
||||
public class DanmakuStartTimeResponse : IResponseData
|
||||
{
|
||||
public DanmakuStartTime[] StartTimes { get; set; } = Array.Empty<DanmakuStartTime>();
|
||||
|
||||
public void PrintToConsole()
|
||||
{
|
||||
var t = new Table()
|
||||
.AddColumns("Start Time", "File Path")
|
||||
.Border(TableBorder.Rounded);
|
||||
|
||||
foreach (var item in this.StartTimes)
|
||||
{
|
||||
t.AddRow(item.StartTime.ToString().EscapeMarkup(), item.Path.EscapeMarkup());
|
||||
}
|
||||
|
||||
AnsiConsole.Render(t);
|
||||
}
|
||||
|
||||
public class DanmakuStartTime
|
||||
{
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public DateTimeOffset StartTime { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.CommandLine.Invocation;
|
|||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.ToolBox.Tool.Analyze;
|
||||
using BililiveRecorder.ToolBox.Tool.DanmakuMerger;
|
||||
using BililiveRecorder.ToolBox.Tool.DanmakuStartTime;
|
||||
using BililiveRecorder.ToolBox.Tool.Export;
|
||||
using BililiveRecorder.ToolBox.Tool.Fix;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -32,10 +33,16 @@ namespace BililiveRecorder.ToolBox
|
|||
c.Add(new Argument<string>("output", "example: output.brec.xml.gz"));
|
||||
});
|
||||
|
||||
this.RegisterCommand<DanmakuStartTimeHandler, DanmakuStartTimeRequest, DanmakuStartTimeResponse>("danmaku-start-time", null, c =>
|
||||
{
|
||||
c.Add(new Argument<string[]>("inputs", "example: 1.xml 2.xml ..."));
|
||||
});
|
||||
|
||||
this.RegisterCommand<DanmakuMergerHandler, DanmakuMergerRequest, DanmakuMergerResponse>("danmaku-merge", null, c =>
|
||||
{
|
||||
c.Add(new Argument<string>("output", "example: output.xml"));
|
||||
c.Add(new Argument<string[]>("inputs", "example: 1.xml 2.xml ..."));
|
||||
c.Add(new Option<int[]?>("--offsets", "Use offsets provided instead of calculating from starttime attribute."));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Compile Include="Converters\ValueConverterGroup.cs" />
|
||||
<Compile Include="Models\AboutModel.cs" />
|
||||
<Compile Include="Models\Commands.cs" />
|
||||
<Compile Include="Models\DanmakuFileWithOffset.cs" />
|
||||
<Compile Include="Models\LogModel.cs" />
|
||||
<Compile Include="Models\PollyPolicyModel.cs" />
|
||||
<Compile Include="Models\RootModel.cs" />
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
</Grid.RowDefinitions>
|
||||
<StackPanel>
|
||||
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource RoomDialogHeader}"/>
|
||||
<TextBlock TextAlignment="Center" Text="Tip: 这里是房间独立设置,是对↙全局设置↙的覆盖"/>
|
||||
<Separator/>
|
||||
</StackPanel>
|
||||
<ScrollViewer Grid.Row="1">
|
||||
|
|
37
BililiveRecorder.WPF/Models/DanmakuFileWithOffset.cs
Normal file
37
BililiveRecorder.WPF/Models/DanmakuFileWithOffset.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#nullable enable
|
||||
namespace BililiveRecorder.WPF.Models
|
||||
{
|
||||
internal class DanmakuFileWithOffset : INotifyPropertyChanged
|
||||
{
|
||||
private string path;
|
||||
private DateTimeOffset startTime;
|
||||
private int offset;
|
||||
|
||||
public string Path { get => this.path; set => this.SetField(ref this.path, value); }
|
||||
public DateTimeOffset StartTime { get => this.startTime; set => this.SetField(ref this.startTime, value); }
|
||||
public int Offset { get => this.offset; set => this.SetField(ref this.offset, value); }
|
||||
|
||||
public DanmakuFileWithOffset(string path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
protected bool SetField<T>(ref T location, T value, [CallerMemberName] string propertyName = "")
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(location, value))
|
||||
return false;
|
||||
location = value;
|
||||
this.OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(this.path, this.startTime, this.offset);
|
||||
}
|
||||
}
|
|
@ -91,6 +91,11 @@
|
|||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{l:Loc RoomListPage_Menu_Links_Sponsor}" Command="{x:Static m:Commands.OpenLink}" CommandParameter="https://rec.danmuji.org/link/sponsor/">
|
||||
<MenuItem.Icon>
|
||||
<ui:PathIcon Style="{StaticResource PathIconDataOpenInNew}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator/>
|
||||
</StackPanel>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
l:ResxLocalizationProvider.DefaultAssembly="BililiveRecorder.WPF"
|
||||
l:ResxLocalizationProvider.DefaultDictionary="Strings"
|
||||
xmlns:c="clr-namespace:BililiveRecorder.WPF.Controls"
|
||||
xmlns:m="clr-namespace:BililiveRecorder.WPF.Models"
|
||||
xmlns:local="clr-namespace:BililiveRecorder.WPF.Pages"
|
||||
xmlns:config="clr-namespace:BililiveRecorder.Core.Config.V2;assembly=BililiveRecorder.Core"
|
||||
xmlns:confiv2="clr-namespace:BililiveRecorder.Core.Config.V2;assembly=BililiveRecorder.Core"
|
||||
|
@ -80,14 +81,32 @@
|
|||
<TextBlock FontSize="13" Text="{l:Loc Settings_FileName_Description_ToolTip}"
|
||||
l:ResxLocalizationProvider.DefaultDictionary="Strings"/>
|
||||
</StackPanel.ToolTip>
|
||||
<TextBlock Text="{l:Loc Settings_FileName_Description_Text}"/>
|
||||
<ui:PathIcon Margin="2,0" VerticalAlignment="Center" Height="15" Style="{StaticResource PathIconDataInformationOutline}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{l:Loc Settings_FileName_Description_Text}"/>
|
||||
<Button Margin="5,0,0,0" Command="{x:Static m:Commands.OpenLink}" CommandParameter="https://rec.danmuji.org/docs/basic/settings/#%E5%BD%95%E5%88%B6%E6%96%87%E4%BB%B6%E5%90%8D%E6%A0%BC%E5%BC%8F">
|
||||
<ui:PathIcon Margin="2,0" VerticalAlignment="Center" Height="15" Style="{StaticResource PathIconDataOpenInNew}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<c:SettingWithDefault IsSettingNotUsingDefault="{Binding HasRecordFilenameFormat}" Header="{l:Loc Settings_FileName_Record}">
|
||||
<TextBox Text="{Binding RecordFilenameFormat,Delay=500}" ui:TextBoxHelper.IsDeleteButtonVisible="False"/>
|
||||
</c:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="录制画质">
|
||||
<StackPanel MaxWidth="400" HorizontalAlignment="Left">
|
||||
<Button Margin="5,0,0,0" Command="{x:Static m:Commands.OpenLink}" CommandParameter="https://rec.danmuji.org/docs/basic/settings/#%E7%9B%B4%E6%92%AD%E7%94%BB%E8%B4%A8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ui:PathIcon Width="15" Height="15" Style="{StaticResource PathIconDataInformationOutline}"/>
|
||||
<ui:PathIcon Margin="5,0,0,0" Width="15" Height="15" Style="{StaticResource PathIconDataOpenInNew}"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<TextBlock Text="逗号分割的录制画质ID"/>
|
||||
<c:SettingWithDefault IsSettingNotUsingDefault="{Binding HasRecordingQuality}">
|
||||
<TextBox Text="{Binding RecordingQuality,UpdateSourceTrigger=PropertyChanged,Delay=1000}"
|
||||
ui:TextBoxHelper.IsDeleteButtonVisible="False" Width="220" HorizontalAlignment="Left"/>
|
||||
</c:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{l:Loc Settings_Webhook_Title}">
|
||||
<StackPanel MaxWidth="400" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{l:Loc Settings_Webhook_Address}" Margin="0,0,0,10"/>
|
||||
|
@ -99,15 +118,6 @@
|
|||
Text="{Binding WebHookUrls,UpdateSourceTrigger=PropertyChanged,Delay=1000}" ui:TextBoxHelper.IsDeleteButtonVisible="False"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="录制画质">
|
||||
<StackPanel MaxWidth="400" HorizontalAlignment="Left">
|
||||
<TextBlock Text="逗号分割的录制画质ID"/>
|
||||
<c:SettingWithDefault IsSettingNotUsingDefault="{Binding HasRecordingQuality}">
|
||||
<TextBox Text="{Binding RecordingQuality,UpdateSourceTrigger=PropertyChanged,Delay=1000}"
|
||||
ui:TextBoxHelper.IsDeleteButtonVisible="False" Width="220" HorizontalAlignment="Left"/>
|
||||
</c:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</ui:SimpleStackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
|
|
|
@ -28,19 +28,31 @@
|
|||
<Button Margin="0,0,5,0" Content="{l:Loc Toolbox_Merge_Button_AddFile}" Click="AddFile_Click"/>
|
||||
<Button Content="{l:Loc Toolbox_Merge_Button_Merge}" Click="Merge_Click"/>
|
||||
</StackPanel>
|
||||
<ListBox Grid.Row="3" Margin="5" x:Name="listBox" AllowDrop="True" Drop="listBox_Drop">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Margin="0,0,5,0" Padding="2" Content="{l:Loc Toolbox_Merge_Button_Remove}" Click="RemoveFile_Click"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding}" ToolTip="{Binding}" TextWrapping="Wrap" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<ListView Grid.Row="3" Margin="5" x:Name="listView" AllowDrop="True" Drop="DragDrop">
|
||||
<ListView.View>
|
||||
<GridView AllowsColumnReorder="False">
|
||||
<GridViewColumn>
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Padding="2" VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Content="{l:Loc Toolbox_Merge_Button_Remove}" Click="RemoveFile_Click"/>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="偏移量(秒)" Width="120">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate><!--
|
||||
<ui:NumberBox Minimum="0" SmallChange="1" LargeChange="10" Text="{Binding Offset,UpdateSourceTrigger=PropertyChanged}"
|
||||
SpinButtonPlacementMode="Inline" ValidationMode="InvalidInputOverwritten"/>
|
||||
-->
|
||||
<TextBox Width="100" Text="{Binding Offset,UpdateSourceTrigger=PropertyChanged,Delay=300}"
|
||||
ui:TextBoxHelper.IsDeleteButtonVisible="False"/>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="文件路径" DisplayMemberBinding="{Binding Path}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</ui:Page>
|
||||
|
|
|
@ -6,9 +6,12 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using BililiveRecorder.ToolBox;
|
||||
using BililiveRecorder.ToolBox.Tool.DanmakuMerger;
|
||||
using BililiveRecorder.ToolBox.Tool.DanmakuStartTime;
|
||||
using BililiveRecorder.WPF.Controls;
|
||||
using BililiveRecorder.WPF.Models;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Serilog;
|
||||
using WPFLocalizeExtension.Extensions;
|
||||
|
@ -24,43 +27,38 @@ namespace BililiveRecorder.WPF.Pages
|
|||
private static readonly ILogger logger = Log.ForContext<ToolboxDanmakuMergerPage>();
|
||||
private static readonly string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
private readonly ObservableCollection<string> Files = new ObservableCollection<string>();
|
||||
private readonly ObservableCollection<DanmakuFileWithOffset> Files = new();
|
||||
|
||||
public ToolboxDanmakuMergerPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.listBox.ItemsSource = this.Files;
|
||||
this.listView.ItemsSource = this.Files;
|
||||
}
|
||||
|
||||
private void RemoveFile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var b = (Button)sender;
|
||||
var f = (string)b.DataContext;
|
||||
var f = (DanmakuFileWithOffset)b.DataContext;
|
||||
this.Files.Remove(f);
|
||||
|
||||
this.CalculateOffsets();
|
||||
}
|
||||
|
||||
private void listBox_Drop(object sender, DragEventArgs e)
|
||||
private async void DragDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
{
|
||||
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
for (var i = 0; i < files.Length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
if (file.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
this.Files.Add(file);
|
||||
}
|
||||
}
|
||||
await this.AddFilesAsync(files.Where(x => x.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase)).ToArray());
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
}
|
||||
|
||||
private void AddFile_Click(object sender, RoutedEventArgs e)
|
||||
private async void AddFile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var d = new CommonOpenFileDialog
|
||||
{
|
||||
|
@ -79,10 +77,39 @@ namespace BililiveRecorder.WPF.Pages
|
|||
if (d.ShowDialog() != CommonFileDialogResult.Ok)
|
||||
return;
|
||||
|
||||
foreach (var file in d.FileNames)
|
||||
{
|
||||
await this.AddFilesAsync(d.FileNames.ToArray());
|
||||
}
|
||||
|
||||
private async Task AddFilesAsync(string[] paths)
|
||||
{
|
||||
var req = new DanmakuStartTimeRequest { Inputs = paths };
|
||||
var handler = new DanmakuStartTimeHandler();
|
||||
var resp = await handler.Handle(req, default, default).ConfigureAwait(true);
|
||||
|
||||
if (resp.Status != ResponseStatus.OK || resp.Data is null)
|
||||
return;
|
||||
|
||||
var toBeAdded = resp.Data.StartTimes.Select(x => new DanmakuFileWithOffset(x.Path) { StartTime = x.StartTime });
|
||||
foreach (var file in toBeAdded)
|
||||
this.Files.Add(file);
|
||||
|
||||
_ = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)this.CalculateOffsets);
|
||||
}
|
||||
|
||||
private void CalculateOffsets()
|
||||
{
|
||||
if (this.Files.Count == 0)
|
||||
return;
|
||||
|
||||
var minTime = this.Files.Min(x => x.StartTime);
|
||||
|
||||
foreach (var item in this.Files)
|
||||
{
|
||||
item.Offset = (int)(item.StartTime - minTime).TotalSeconds;
|
||||
}
|
||||
|
||||
this.listView.DataContext = null;
|
||||
this.listView.DataContext = this.Files;
|
||||
}
|
||||
|
||||
private async void Merge_Click(object sender, RoutedEventArgs e)
|
||||
|
@ -124,7 +151,7 @@ namespace BililiveRecorder.WPF.Pages
|
|||
EnsureValidNames = true,
|
||||
NavigateToShortcut = true,
|
||||
OverwritePrompt = false,
|
||||
InitialDirectory = Path.GetDirectoryName(inputPaths[0]),
|
||||
InitialDirectory = Path.GetDirectoryName(inputPaths[0].Path),
|
||||
};
|
||||
|
||||
fileDialog.Filters.Add(new CommonFileDialogFilter(LocExtension.GetLocalizedValue<string>("BililiveRecorder.WPF:Strings:Toolbox_Merge_XmlDanmakuFiles"), "*.xml"));
|
||||
|
@ -137,7 +164,8 @@ namespace BililiveRecorder.WPF.Pages
|
|||
|
||||
var req = new DanmakuMergerRequest
|
||||
{
|
||||
Inputs = inputPaths,
|
||||
Inputs = inputPaths.Select(x => x.Path).ToArray(),
|
||||
Offsets = inputPaths.Select(x => x.Offset).ToArray(),
|
||||
Output = outputPath,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user