summaryrefslogtreecommitdiff
path: root/mkvtool-gui
diff options
context:
space:
mode:
authorb5f0d6c3 <[email protected]>2021-10-22 14:45:22 +0800
committerb5f0d6c3 <[email protected]>2021-10-22 14:45:22 +0800
commitcc993e05efef9fb1a797d686a18161fb906676d4 (patch)
tree6592579d71980d58fdc466fefcb3b9a7699c1783 /mkvtool-gui
parent7fde5d4d448f64c2250ab003e2ecb75a7d268733 (diff)
add mkvtool-gui
Diffstat (limited to 'mkvtool-gui')
-rw-r--r--mkvtool-gui/App.axaml11
-rw-r--r--mkvtool-gui/App.axaml.cs35
-rw-r--r--mkvtool-gui/CustomFontManagerImpl.cs73
-rw-r--r--mkvtool-gui/MainWindow.axaml218
-rw-r--r--mkvtool-gui/MainWindow.axaml.cs428
-rw-r--r--mkvtool-gui/Program.cs23
-rw-r--r--mkvtool-gui/mkvtool.csproj28
-rw-r--r--mkvtool-gui/sdk.cs135
8 files changed, 951 insertions, 0 deletions
diff --git a/mkvtool-gui/App.axaml b/mkvtool-gui/App.axaml
new file mode 100644
index 0000000..9871dd1
--- /dev/null
+++ b/mkvtool-gui/App.axaml
@@ -0,0 +1,11 @@
+<Application xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:Class="mkvtool.App">
+ <Application.Styles>
+ <FluentTheme Mode="Light" />
+ </Application.Styles>
+ <Application.Styles>
+ <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml" />
+ <StyleInclude Source="avares://Avalonia.Controlz/Styles/Generic.axaml" />
+ </Application.Styles>
+</Application> \ No newline at end of file
diff --git a/mkvtool-gui/App.axaml.cs b/mkvtool-gui/App.axaml.cs
new file mode 100644
index 0000000..44e12cf
--- /dev/null
+++ b/mkvtool-gui/App.axaml.cs
@@ -0,0 +1,35 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using Avalonia.Platform;
+
+namespace mkvtool
+{
+ public class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+
+ /// <summary>
+ /// override RegisterServices register custom service
+ /// </summary>
+ public override void RegisterServices()
+ {
+ AvaloniaLocator.CurrentMutable.Bind<IFontManagerImpl>().ToConstant(new CustomFontManagerImpl());
+ base.RegisterServices();
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mkvtool-gui/CustomFontManagerImpl.cs b/mkvtool-gui/CustomFontManagerImpl.cs
new file mode 100644
index 0000000..c47fedb
--- /dev/null
+++ b/mkvtool-gui/CustomFontManagerImpl.cs
@@ -0,0 +1,73 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Avalonia.Media;
+using Avalonia.Platform;
+using Avalonia.Skia;
+using SkiaSharp;
+
+namespace mkvtool
+{
+ public class CustomFontManagerImpl : IFontManagerImpl
+ {
+ private readonly Typeface[] _customTypefaces;
+ private readonly string _defaultFamilyName;
+
+ private readonly Typeface _defaultTypeface =
+ new Typeface("Microsoft Yahei");
+
+ public CustomFontManagerImpl()
+ {
+ _customTypefaces = new[] {_defaultTypeface};
+ _defaultFamilyName = _defaultTypeface.FontFamily.FamilyNames.PrimaryFamilyName;
+ }
+
+ public string GetDefaultFontFamilyName()
+ {
+ return _defaultFamilyName;
+ }
+
+ public IEnumerable<string> GetInstalledFontFamilyNames(bool checkForUpdates = false)
+ {
+ return _customTypefaces.Select(x => x.FontFamily.Name);
+ }
+
+ private readonly string[] _bcp47 =
+ {
+ CultureInfo.CurrentCulture.ThreeLetterISOLanguageName, CultureInfo.CurrentCulture.TwoLetterISOLanguageName
+ };
+
+ public bool TryMatchCharacter(int codepoint, FontStyle fontStyle, FontWeight fontWeight, FontFamily fontFamily,
+ CultureInfo culture, out Typeface typeface)
+ {
+ foreach (var customTypeface in _customTypefaces)
+ {
+ if (customTypeface.GlyphTypeface.GetGlyph((uint) codepoint) == 0)
+ {
+ continue;
+ }
+
+ typeface = new Typeface(customTypeface.FontFamily.Name, fontStyle, fontWeight);
+
+ return true;
+ }
+
+ var fallback = SKFontManager.Default.MatchCharacter(fontFamily?.Name, (SKFontStyleWeight) fontWeight,
+ SKFontStyleWidth.Normal, (SKFontStyleSlant) fontStyle, _bcp47, codepoint);
+
+ typeface = new Typeface(fallback?.FamilyName ?? _defaultFamilyName, fontStyle, fontWeight);
+
+ return true;
+ }
+
+ public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface)
+ {
+ SKTypeface skTypeface;
+ skTypeface = SKTypeface.FromFamilyName(_defaultTypeface.FontFamily.Name,
+ (SKFontStyleWeight) typeface.Weight, SKFontStyleWidth.Normal, (SKFontStyleSlant) typeface.Style);
+
+
+ return new GlyphTypefaceImpl(skTypeface);
+ }
+ }
+} \ No newline at end of file
diff --git a/mkvtool-gui/MainWindow.axaml b/mkvtool-gui/MainWindow.axaml
new file mode 100644
index 0000000..014010e
--- /dev/null
+++ b/mkvtool-gui/MainWindow.axaml
@@ -0,0 +1,218 @@
+<Window xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="600"
+ d:DesignHeight="600"
+ Width="850"
+ Height="650"
+ x:Class="mkvtool.MainWindow"
+ WindowStartupLocation="CenterScreen"
+ xmlns:Controls="clr-namespace:Avalonia.Controlz.Controls;assembly=Avalonia.Controlz"
+ Title="MKV Tool" Opened="TopLevel_OnOpened">
+ <DockPanel>
+ <TabControl DockPanel.Dock="Left">
+ <TabItem Header="Subset">
+ <StackPanel>
+ <Controls:GroupBox Header="Check subsetted" Margin="10">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
+ <Button Content="File..." Click="CheckFileBtn_OnClick" Margin="5" />
+ <Button Content="Folder..." Click="CheckFolderBtn_OnClick" Margin="5" />
+ </StackPanel>
+ </Controls:GroupBox>
+ <Controls:GroupBox Header="Do subset" Margin="10">
+ <StackPanel Margin="5" HorizontalAlignment="Center">
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="ASS subtitles:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="sa1" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="asses" Click="SubsetSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Text="Fonts:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="sa2" />
+ </ScrollViewer>
+ </StackPanel>
+ </StackPanel>
+ <Button Content="Select..." Tag="fonts" Click="SubsetSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Output folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="sa3" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="output" Click="SubsetSelectBtns_OnClick" />
+ </StackPanel>
+ <CheckBox Content="Output in sub folder" IsChecked="True" Name="sa4" />
+ <Button Margin="10" Content="Go" Click="DoSubsetBtn_OnClick" />
+ </StackPanel>
+ </Controls:GroupBox>
+ </StackPanel>
+ </TabItem>
+ <TabItem Header="Dump / Make">
+ <StackPanel>
+ <Controls:GroupBox Header="Dump" Margin="10">
+ <StackPanel Margin="5" HorizontalAlignment="Center">
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="File or folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="da1" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select file..." Tag="file" Click="DumpSelectBtns_OnClick" />
+ <Button Content="Select folder..." Tag="folder" Click="DumpSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Output folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="da2" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="output" Click="DumpSelectBtns_OnClick" />
+ </StackPanel>
+ <CheckBox Content="Subset" IsChecked="True" Name="da3" />
+ <Button Margin="10" Content="Go" Click="DoDumpBtn_OnClick" />
+ </StackPanel>
+ </Controls:GroupBox>
+ <Controls:GroupBox Header="Make" Margin="10">
+ <StackPanel Margin="5" HorizontalAlignment="Center">
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Text="Video folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ma1" />
+ </ScrollViewer>
+ </StackPanel>
+ </StackPanel>
+ <Button Content="Select..." Tag="dir" Click="MakeSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Data folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ma2" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="data" Click="MakeSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Output folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ma3" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="output" Click="MakeSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Default Subtitle language:" VerticalAlignment="Center"
+ TextAlignment="Center" />
+ <TextBox Name="ma4" />
+ </StackPanel>
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Default Subtitle title:" VerticalAlignment="Center"
+ TextAlignment="Center" />
+ <TextBox Name="ma5" />
+ </StackPanel>
+ </StackPanel>
+ <Button Margin="10" Content="Go" Click="DoMakeBtn_OnClick" />
+ </StackPanel>
+ </Controls:GroupBox>
+ </StackPanel>
+ </TabItem>
+ <TabItem Header="Create">
+ <StackPanel>
+ <Controls:GroupBox Header="Do Create" Margin="10">
+ <StackPanel Margin="5" HorizontalAlignment="Center">
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Text="Video folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ca1" />
+ </ScrollViewer>
+ </StackPanel>
+ </StackPanel>
+ <Button Content="Select..." Tag="v" Click="CreateSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Subtitles folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ca2" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="s" Click="CreateSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Fonts folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ca3" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="f" Click="CreateSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Output folder:" />
+ <ScrollViewer HorizontalScrollBarVisibility="Auto"
+ VerticalScrollBarVisibility="Auto">
+ <TextBlock Name="ca4" />
+ </ScrollViewer>
+ </StackPanel>
+ <Button Content="Select..." Tag="o" Click="CreateSelectBtns_OnClick" />
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Default Subtitle language:" VerticalAlignment="Center"
+ TextAlignment="Center" />
+ <TextBox Name="ca5" />
+ </StackPanel>
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" Margin="5">
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock Text="Default Subtitle title:" VerticalAlignment="Center"
+ TextAlignment="Center" />
+ <TextBox Name="ca6" />
+ </StackPanel>
+ </StackPanel>
+ <CheckBox Content="Clean old data" IsChecked="False" Name="ca7" />
+ <Button Margin="10" Content="Go" Click="DoCreatetn_OnClick" />
+ </StackPanel>
+ </Controls:GroupBox>
+ </StackPanel>
+ </TabItem>
+ </TabControl>
+ <Controls:GroupBox Header="Log" Margin="10" DockPanel.Dock="Right">
+ <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
+ <TextBox IsReadOnly="True" Name="logBox" Margin="10" />
+ </ScrollViewer>
+ </Controls:GroupBox>
+ </DockPanel>
+</Window> \ No newline at end of file
diff --git a/mkvtool-gui/MainWindow.axaml.cs b/mkvtool-gui/MainWindow.axaml.cs
new file mode 100644
index 0000000..10b34de
--- /dev/null
+++ b/mkvtool-gui/MainWindow.axaml.cs
@@ -0,0 +1,428 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using MessageBox.Avalonia;
+using MEnums = MessageBox.Avalonia.Enums;
+
+namespace mkvtool
+{
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private async void CheckFileBtn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ string[] files = await ShowSelectFileDialog("MKV file", new string[] {"mkv"}, false);
+ if (files != null)
+ {
+ bool[] result = mkvlib.CheckSubset(files[0], lcb);
+ if (result[1])
+ await MessageBoxManager.GetMessageBoxStandardWindow("Check result",
+ "Has error.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Error, WindowStartupLocation.CenterOwner).Show();
+ else if (result[0])
+ await MessageBoxManager.GetMessageBoxStandardWindow("Check result",
+ "This mkv file are subsetted.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ else
+ await MessageBoxManager.GetMessageBoxStandardWindow("Check result",
+ "This mkv file are not subsetted.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Warning, WindowStartupLocation.CenterOwner).Show();
+ }
+ }
+
+ private async void CheckFolderBtn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ string dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ string[] list = mkvlib.QueryFolder(dir, lcb);
+ if (list != null && list.Length > 0)
+ {
+ lcb("Not subsetted file list:");
+ lcb(" ----- Begin ----- ");
+ lcb(string.Join(Environment.NewLine, list));
+ lcb(" ----- End ----- ");
+ }
+ else
+ lcb("All files are subseted.");
+ }
+ }
+
+ void lcb(string str)
+ {
+ this.FindControl<TextBox>("logBox").Text += str + Environment.NewLine;
+ }
+
+ private async void TopLevel_OnOpened(object? sender, EventArgs e)
+ {
+ if (!mkvlib.InitInstance(lcb))
+ {
+ await MessageBoxManager.GetMessageBoxStandardWindow("Check result",
+ "Failed to init mkvlib.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Error, WindowStartupLocation.CenterOwner).Show();
+ this.IsEnabled = false;
+ }
+ }
+
+ class SubsetArg
+ {
+ public static string[] Asses { get; set; }
+ public static string Fonts { get; set; }
+ public static string Output { get; set; }
+ public static bool DirSafe { get; set; }
+ }
+
+ private async void SubsetSelectBtns_OnClick(object? sender, RoutedEventArgs e)
+ {
+ Button btn = (Button) sender;
+ string dir;
+ switch (btn.Tag.ToString())
+ {
+ case "asses":
+ SubsetArg.Asses = null;
+ this.FindControl<TextBlock>("sa1").Text = string.Empty;
+ string[] files = await ShowSelectFileDialog("ASS file(s)", new[] {"ass"}, true);
+ if (files != null && files.Length > 0)
+ {
+ SubsetArg.Asses = files;
+ this.FindControl<TextBlock>("sa1").Text = string.Join(Environment.NewLine, files);
+ }
+
+ break;
+ case "fonts":
+ SubsetArg.Fonts = string.Empty;
+ this.FindControl<TextBlock>("sa2").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ SubsetArg.Fonts = dir;
+ this.FindControl<TextBlock>("sa2").Text = dir;
+ }
+
+ break;
+ case "output":
+ SubsetArg.Output = string.Empty;
+ this.FindControl<TextBlock>("sa3").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ SubsetArg.Output = dir;
+ this.FindControl<TextBlock>("sa3").Text = dir;
+ }
+
+ break;
+ }
+ }
+
+ async Task<string[]> ShowSelectFileDialog(string name, string[] ext, bool multiple)
+ {
+ OpenFileDialog fileDialog = new OpenFileDialog();
+ fileDialog.AllowMultiple = multiple;
+ FileDialogFilter filter = new FileDialogFilter();
+ filter.Name = name;
+ filter.Extensions.AddRange(ext);
+ fileDialog.Filters.Add(filter);
+ string[] files = await fileDialog.ShowAsync(this);
+ return files;
+ }
+
+ private async void DoSubsetBtn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ if (SubsetArg.Asses != null && SubsetArg.Asses.Length > 0 && !string.IsNullOrEmpty(SubsetArg.Fonts) &&
+ !string.IsNullOrEmpty(SubsetArg.Output))
+ {
+ SubsetArg.DirSafe = this.FindControl<CheckBox>("sa4").IsChecked == true;
+ if (mkvlib.ASSFontSubset(SubsetArg.Asses, SubsetArg.Fonts, SubsetArg.Output, SubsetArg.DirSafe, lcb))
+ {
+ await MessageBoxManager.GetMessageBoxStandardWindow("Subset result",
+ "Subset successfully.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ SubsetArg.Asses = null;
+ SubsetArg.Fonts = string.Empty;
+ SubsetArg.Output = string.Empty;
+ this.FindControl<TextBlock>("sa1").Text = string.Empty;
+ this.FindControl<TextBlock>("sa2").Text = string.Empty;
+ this.FindControl<TextBlock>("sa3").Text = string.Empty;
+ this.FindControl<CheckBox>("sa4").IsCancel = true;
+ }
+ else
+ await MessageBoxManager.GetMessageBoxStandardWindow("Subset result",
+ "Failed to subset.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ }
+ }
+
+ class DumpArg
+ {
+ public static string Path { get; set; }
+ public static string Output { get; set; }
+ public static bool Subset { get; set; }
+ public static bool Dir { get; set; }
+ }
+
+ private async void DumpSelectBtns_OnClick(object? sender, RoutedEventArgs e)
+ {
+ Button btn = (Button) sender;
+ string dir;
+ switch (btn.Tag.ToString())
+ {
+ case "file":
+ DumpArg.Path = string.Empty;
+ DumpArg.Dir = false;
+ this.FindControl<TextBlock>("da1").Text = string.Empty;
+ string[] files = await ShowSelectFileDialog("MKV file",
+ new[] {"mkv"},
+ false);
+ if (files != null && files.Length > 0)
+ {
+ DumpArg.Path = files[0];
+ this.FindControl<TextBlock>("da1").Text = files[0];
+ }
+
+ break;
+ case "folder":
+ DumpArg.Path = string.Empty;
+ this.FindControl<TextBlock>("da1").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ DumpArg.Path = dir;
+ this.FindControl<TextBlock>("da1").Text = dir;
+ DumpArg.Dir = true;
+ }
+
+ break;
+ case "output":
+ DumpArg.Output = string.Empty;
+ this.FindControl<TextBlock>("da2").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ DumpArg.Output = dir;
+ this.FindControl<TextBlock>("da2").Text = dir;
+ }
+
+ break;
+ }
+ }
+
+ private async void DoDumpBtn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(DumpArg.Path) &&
+ !string.IsNullOrEmpty(DumpArg.Output))
+ {
+ DumpArg.Subset = this.FindControl<CheckBox>("da3").IsChecked == true;
+ bool r = !DumpArg.Dir
+ ? mkvlib.DumpMKV(DumpArg.Path, DumpArg.Output, DumpArg.Subset, lcb)
+ : mkvlib.DumpMKVs(DumpArg.Path, DumpArg.Output, DumpArg.Subset, lcb);
+ if (r)
+ {
+ await MessageBoxManager.GetMessageBoxStandardWindow("Dump result",
+ "Dump successfully.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ DumpArg.Path = string.Empty;
+ DumpArg.Output = string.Empty;
+ DumpArg.Dir = false;
+ this.FindControl<TextBlock>("da1").Text = string.Empty;
+ this.FindControl<TextBlock>("da2").Text = string.Empty;
+ this.FindControl<CheckBox>("da3").IsCancel = true;
+ }
+ else
+ await MessageBoxManager.GetMessageBoxStandardWindow("Dump result",
+ "Failed to dump.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ }
+ }
+
+ class MakeArg
+ {
+ public static string Dir { get; set; }
+ public static string Data { get; set; }
+ public static string Output { get; set; }
+ public static string slang { get; set; }
+ public static string stitle { get; set; }
+ }
+
+ private async void MakeSelectBtns_OnClick(object? sender, RoutedEventArgs e)
+ {
+ Button btn = (Button) sender;
+ string dir;
+ switch (btn.Tag.ToString())
+ {
+ case "dir":
+ MakeArg.Dir = string.Empty;
+ this.FindControl<TextBlock>("ma1").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ MakeArg.Dir = dir;
+ this.FindControl<TextBlock>("ma1").Text = dir;
+ }
+
+ break;
+ case "data":
+ MakeArg.Data = string.Empty;
+ this.FindControl<TextBlock>("ma2").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ MakeArg.Data = dir;
+ this.FindControl<TextBlock>("ma2").Text = dir;
+ }
+
+ break;
+ case "output":
+ MakeArg.Output = string.Empty;
+ this.FindControl<TextBlock>("ma3").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ MakeArg.Output = dir;
+ this.FindControl<TextBlock>("ma3").Text = dir;
+ }
+
+ break;
+ }
+ }
+
+ private async void DoMakeBtn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(MakeArg.Dir) && !string.IsNullOrEmpty(MakeArg.Data) &&
+ !string.IsNullOrEmpty(MakeArg.Output))
+ {
+ MakeArg.slang = this.FindControl<TextBox>("ma4").Text;
+ MakeArg.stitle = this.FindControl<TextBox>("ma5").Text;
+ if (mkvlib.MakeMKVs(MakeArg.Dir, MakeArg.Data, MakeArg.Output, MakeArg.slang, MakeArg.stitle, lcb))
+ {
+ await MessageBoxManager.GetMessageBoxStandardWindow("Make result",
+ "Make successfully.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ MakeArg.Dir = string.Empty;
+ MakeArg.Data = string.Empty;
+ MakeArg.Output = string.Empty;
+ MakeArg.slang = string.Empty;
+ MakeArg.stitle = string.Empty;
+ this.FindControl<TextBlock>("ma1").Text = string.Empty;
+ this.FindControl<TextBlock>("ma2").Text = string.Empty;
+ this.FindControl<TextBlock>("ma3").Text = string.Empty;
+ this.FindControl<TextBox>("ma4").Text = string.Empty;
+ this.FindControl<TextBox>("ma5").Text = string.Empty;
+ }
+ else
+ await MessageBoxManager.GetMessageBoxStandardWindow("Make result",
+ "Failed to make.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ }
+ }
+
+ class CreateArg
+ {
+ public static string vDir { get; set; }
+ public static string sDir { get; set; }
+ public static string fDir { get; set; }
+ public static string oDir { get; set; }
+ public static string slang { get; set; }
+ public static string stitle { get; set; }
+ public static bool clean { get; set; }
+ }
+
+ private async void CreateSelectBtns_OnClick(object? sender, RoutedEventArgs e)
+ {
+ Button btn = (Button) sender;
+ string dir;
+ switch (btn.Tag.ToString())
+ {
+ case "v":
+ CreateArg.vDir = string.Empty;
+ this.FindControl<TextBlock>("ca1").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ CreateArg.vDir = dir;
+ this.FindControl<TextBlock>("ca1").Text = dir;
+ }
+
+ break;
+ case "s":
+ CreateArg.sDir = string.Empty;
+ this.FindControl<TextBlock>("ca2").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ CreateArg.sDir = dir;
+ this.FindControl<TextBlock>("ca2").Text = dir;
+ }
+
+ break;
+ case "f":
+ CreateArg.fDir = string.Empty;
+ this.FindControl<TextBlock>("ca3").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ CreateArg.fDir = dir;
+ this.FindControl<TextBlock>("ca3").Text = dir;
+ }
+
+ break;
+ case "o":
+ CreateArg.oDir = string.Empty;
+ this.FindControl<TextBlock>("ca4").Text = string.Empty;
+ dir = await new OpenFolderDialog().ShowAsync(this);
+ if (!string.IsNullOrEmpty(dir))
+ {
+ CreateArg.oDir = dir;
+ this.FindControl<TextBlock>("ca4").Text = dir;
+ }
+
+ break;
+ }
+ }
+
+ private async void DoCreatetn_OnClick(object? sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(CreateArg.vDir) && !string.IsNullOrEmpty(CreateArg.sDir) &&
+ !string.IsNullOrEmpty(CreateArg.fDir) && !string.IsNullOrEmpty(CreateArg.oDir))
+ {
+ CreateArg.slang = this.FindControl<TextBox>("ca5").Text;
+ CreateArg.stitle = this.FindControl<TextBox>("ca6").Text;
+ CreateArg.clean = this.FindControl<CheckBox>("ca7").IsChecked == true;
+ if (mkvlib.CreateMKVs(CreateArg.vDir, CreateArg.sDir, CreateArg.fDir, string.Empty, CreateArg.oDir,
+ CreateArg.slang, CreateArg.stitle, CreateArg.clean, lcb))
+ {
+ await MessageBoxManager.GetMessageBoxStandardWindow("Create result",
+ "Create successfully.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ CreateArg.vDir = string.Empty;
+ CreateArg.sDir = string.Empty;
+ CreateArg.fDir = string.Empty;
+ CreateArg.oDir = string.Empty;
+ CreateArg.clean = false;
+ this.FindControl<TextBlock>("ca1").Text = string.Empty;
+ this.FindControl<TextBlock>("ca2").Text = string.Empty;
+ this.FindControl<TextBlock>("ca3").Text = string.Empty;
+ this.FindControl<TextBlock>("ca4").Text = string.Empty;
+ this.FindControl<TextBox>("ca5").Text = string.Empty;
+ this.FindControl<TextBox>("ca6").Text = string.Empty;
+ this.FindControl<CheckBox>("ca7").IsChecked = false;
+ }
+ else
+ await MessageBoxManager.GetMessageBoxStandardWindow("Create result",
+ "Failed to create.", MEnums.ButtonEnum.Ok,
+ MEnums.Icon.Info, WindowStartupLocation.CenterOwner).Show();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mkvtool-gui/Program.cs b/mkvtool-gui/Program.cs
new file mode 100644
index 0000000..7eb68e0
--- /dev/null
+++ b/mkvtool-gui/Program.cs
@@ -0,0 +1,23 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+
+namespace mkvtool
+{
+ class Program
+ {
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ [STAThread]
+ public static void Main(string[] args) => BuildAvaloniaApp()
+ .StartWithClassicDesktopLifetime(args);
+
+ // Avalonia configuration, don't remove; also used by visual designer.
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure<App>()
+ .UsePlatformDetect()
+ .LogToTrace();
+ }
+} \ No newline at end of file
diff --git a/mkvtool-gui/mkvtool.csproj b/mkvtool-gui/mkvtool.csproj
new file mode 100644
index 0000000..0791134
--- /dev/null
+++ b/mkvtool-gui/mkvtool.csproj
@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>WinExe</OutputType>
+ <TargetFramework>net5.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
+ <IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
+ <IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(IsWindows)'=='true'">
+ <DefineConstants>Windows</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(IsOSX)'=='true'">
+ <DefineConstants>OSX</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(IsLinux)'=='true'">
+ <DefineConstants>Linux</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <None Remove=".gitignore" />
+ </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="Avalonia" Version="0.10.8" />
+ <PackageReference Include="Avalonia.Desktop" Version="0.10.8" />
+ <PackageReference Include="mameolan.Avalonia.Controlz" Version="1.0.0-CI-20211017-144151" />
+ <PackageReference Include="MessageBox.Avalonia" Version="1.5.3" />
+ </ItemGroup>
+</Project>
diff --git a/mkvtool-gui/sdk.cs b/mkvtool-gui/sdk.cs
new file mode 100644
index 0000000..2be1922
--- /dev/null
+++ b/mkvtool-gui/sdk.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text.Json;
+
+public static class mkvlib
+{
+#if OSX
+ const string so = "mkvlib_osx.so";
+#endif
+#if Linux
+ const string so = "mkvlib_linux.so";
+#endif
+#if Windows
+ const string so = "mkvlib_windows.so";
+#endif
+
+ #region imports
+
+ [DllImport(so)]
+ static extern bool InitInstance(logCallback lcb);
+
+ [DllImport(so)]
+ static extern IntPtr GetMKVInfo(IntPtr ptr);
+
+ [DllImport(so)]
+ static extern bool DumpMKV(IntPtr file, IntPtr output, bool subset, logCallback lcb);
+
+ [DllImport(so)]
+ static extern IntPtr CheckSubset(IntPtr file, logCallback lcb);
+
+ [DllImport(so)]
+ static extern bool CreateMKV(IntPtr file, IntPtr tracks, IntPtr attachments, IntPtr output, IntPtr slang,
+ IntPtr stitle, bool clean);
+
+ [DllImport(so)]
+ static extern bool ASSFontSubset(IntPtr files, IntPtr fonts, IntPtr output, bool dirSafe, logCallback lcb);
+
+ [DllImport(so)]
+ static extern IntPtr QueryFolder(IntPtr dir, logCallback lcb);
+
+ [DllImport(so)]
+ static extern bool DumpMKVs(IntPtr dir, IntPtr output, bool subset, logCallback lcb);
+
+ [DllImport(so)]
+ static extern bool CreateMKVs(IntPtr vDir, IntPtr sDir, IntPtr fDir, IntPtr tDir, IntPtr oDir, IntPtr slang,
+ IntPtr stitle, bool clean, logCallback lcb);
+
+ [DllImport(so)]
+ static extern bool MakeMKVs(IntPtr dir, IntPtr data, IntPtr output, IntPtr slang, IntPtr stitle, logCallback lcb);
+
+ #endregion
+
+ public static bool InitInstance(Action<string> lcb)
+ {
+ return InitInstance(_lcb(lcb));
+ }
+
+ public static string GetMKVInfo(string file)
+ {
+ return css(GetMKVInfo(cs(file)));
+ }
+
+ public static bool DumpMKV(string file, string output, bool subset, Action<string> lcb)
+ {
+ return DumpMKV(cs(file), cs(output), subset, _lcb(lcb));
+ }
+
+ public static bool[] CheckSubset(string file, Action<string> lcb)
+ {
+ string json = css(CheckSubset(cs(file), _lcb(lcb)));
+ JsonDocument doc = JsonDocument.Parse(json);
+ bool[] result = new bool[2];
+ result[0] = doc.RootElement.GetProperty("subsetted").GetBoolean();
+ result[1] = doc.RootElement.GetProperty("error").GetBoolean();
+ return result;
+ }
+
+ public static bool CreateMKV(string file, string[] tracks, string[] attachments, string output, string slang,
+ string stitle, bool clean)
+ {
+ string _tracks = JsonSerializer.Serialize<string[]>(tracks);
+ string _attachments = JsonSerializer.Serialize<string[]>(attachments);
+ return CreateMKV(cs(file), cs(_tracks), cs(_attachments), cs(output), cs(slang), cs(stitle), clean);
+ }
+
+ public static bool ASSFontSubset(string[] files, string fonts, string output, bool dirSafe, Action<string> lcb)
+ {
+ string _files = JsonSerializer.Serialize<string[]>(files);
+ return ASSFontSubset(cs(_files), cs(fonts), cs(output), dirSafe, _lcb(lcb));
+ }
+
+ public static string[] QueryFolder(string dir, Action<string> lcb)
+ {
+ string result = css(QueryFolder(cs(dir), _lcb(lcb)));
+ return JsonSerializer.Deserialize<string[]>(result);
+ }
+
+ public static bool DumpMKVs(string dir, string output, bool subset, Action<string> lcb)
+ {
+ return DumpMKVs(cs(dir), cs(output), subset, _lcb(lcb));
+ }
+
+ public static bool CreateMKVs(string vDir, string sDir, string fDir, string tDir, string oDir, string slang,
+ string stitle, bool clean, Action<string> lcb)
+ {
+ return CreateMKVs(cs(vDir), cs(sDir), cs(fDir), cs(tDir), cs(oDir), cs(slang), cs(stitle), clean, _lcb(lcb));
+ }
+
+ public static bool MakeMKVs(string dir, string data, string output, string slang, string stitle, Action<string> lcb)
+ {
+ return MakeMKVs(cs(dir), cs(data), cs(output), cs(slang), cs(stitle), _lcb(lcb));
+ }
+
+
+ delegate void logCallback(IntPtr ptr);
+
+ static logCallback _lcb(Action<string> lcb)
+ {
+ return (ptr) =>
+ {
+ if (lcb != null)
+ lcb(css(ptr));
+ };
+ }
+
+ static IntPtr cs(string str)
+ {
+ return Marshal.StringToCoTaskMemUTF8(str);
+ }
+
+ static string css(IntPtr ptr)
+ {
+ return Marshal.PtrToStringUTF8(ptr);
+ }
+} \ No newline at end of file