diff --git a/MainWindow.xaml b/MainWindow.xaml
index 50bbb9f..fb2983c 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -233,6 +233,12 @@
+
+
+
+
+
+
@@ -259,13 +265,14 @@
+ Binding="{Binding IdDisplay}" Width="45" IsReadOnly="True"/>
private void FileQueueList_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
+ if (e.Key == System.Windows.Input.Key.Space)
+ {
+ OpenSelectedFileInDefaultPlayer();
+ e.Handled = true;
+ return;
+ }
+
if (e.Key != System.Windows.Input.Key.Delete) return;
var selected = FileQueueList.SelectedItems.Cast().ToList();
@@ -371,6 +379,25 @@ public partial class MainWindow : FluentWindow
e.Handled = true;
}
+ ///
+ /// Opens the currently-selected queue item with whatever application
+ /// Windows has associated with .mkv files (typically the default video
+ /// player), so the user can quickly preview a file without leaving the app.
+ ///
+ private void OpenSelectedFileInDefaultPlayer()
+ {
+ if (FileQueueList.SelectedItem is not QueuedFileItem item) return;
+
+ try
+ {
+ Process.Start(new ProcessStartInfo(item.FilePath) { UseShellExecute = true });
+ }
+ catch (Exception ex)
+ {
+ StatusText.Text = $"Couldn't open {item.FileName}: {ex.Message}";
+ }
+ }
+
private void ClearQueueButton_Click(object sender, RoutedEventArgs e)
{
foreach (var item in _fileQueue)
diff --git a/Models/MkvModels.cs b/Models/MkvModels.cs
index bbe2158..45bfbf1 100644
--- a/Models/MkvModels.cs
+++ b/Models/MkvModels.cs
@@ -13,6 +13,15 @@ public class MkvIdentifyResult
[JsonPropertyName("tracks")]
public List Tracks { get; set; } = new();
+
+ [JsonPropertyName("chapters")]
+ public List Chapters { get; set; } = new();
+}
+
+public class MkvChapters
+{
+ [JsonPropertyName("num_entries")]
+ public int NumEntries { get; set; }
}
public class MkvTrack
diff --git a/Models/TrackItem.cs b/Models/TrackItem.cs
index d6c66f8..e317acc 100644
--- a/Models/TrackItem.cs
+++ b/Models/TrackItem.cs
@@ -44,6 +44,20 @@ public class TrackItem : INotifyPropertyChanged
///
public string DisplayName => Type == "subtitles" ? $"{Codec}/{Name}" : Name;
+ ///
+ /// Video is always kept, and chapters (a synthetic pseudo-track, not a
+ /// real mkvmerge track) are always kept too — neither is user-selectable,
+ /// so their Copy checkbox is shown checked but disabled.
+ ///
+ public bool IsEditable => Type is "audio" or "subtitles";
+
+ ///
+ /// Chapters aren't a real track and have no track ID; show a dash
+ /// instead of a meaningless number.
+ ///
+ public string IdDisplay => Type == "chapters" ? "—" : Id.ToString();
+
+
public bool Copy
{
get => _copy;
diff --git a/Services/MkvService.cs b/Services/MkvService.cs
index 6dc1238..52a0a1e 100644
--- a/Services/MkvService.cs
+++ b/Services/MkvService.cs
@@ -110,7 +110,7 @@ public class MkvService
MkvTrack? preferredAudio = eligibleAudio.FirstOrDefault(t => t.Properties?.AudioChannels == 2)
?? eligibleAudio.FirstOrDefault();
- return info.Tracks.Select(t =>
+ var items = info.Tracks.Select(t =>
{
bool copy = t.Type switch
{
@@ -136,6 +136,22 @@ public class MkvService
Copy = copy,
};
}).ToList();
+
+ int chapterCount = info.Chapters.Sum(c => c.NumEntries);
+ if (chapterCount > 0)
+ {
+ items.Add(new TrackItem
+ {
+ Id = -1,
+ Type = "chapters",
+ Codec = string.Empty,
+ Language = string.Empty,
+ Name = $"Chapters ({chapterCount})",
+ Copy = true,
+ });
+ }
+
+ return items;
}
///