- Unify audio/subtitle selection: single-select, auto-default, cross-file propagation by exact name - Show file size in queue, group divider and reordered columns in track table, drop accent highlight on row selection - Add cumulative progress bar (files finished, MB copied) to the stripping window - Add Windows toast notifications on stripping completion/cancel/error - Restart the app after settings are changed; Cancel no longer clears the queue, only closes the window - Add ConfigureAwait(false) throughout MkvService so concurrent strips don't starve the UI thread - Hardcode scan/strip concurrency (10/5) instead of exposing it in Settings
92 lines
2.9 KiB
C#
92 lines
2.9 KiB
C#
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Futonizer.Models;
|
|
|
|
/// <summary>
|
|
/// Represents one track of a queued MKV file, as shown in the track table.
|
|
/// The <see cref="Copy"/> property is user-editable and drives which tracks
|
|
/// are passed to mkvmerge when stripping.
|
|
/// </summary>
|
|
public class TrackItem : INotifyPropertyChanged
|
|
{
|
|
private bool _copy;
|
|
|
|
public int Id { get; init; }
|
|
public string Type { get; init; } = string.Empty;
|
|
public string Codec { get; init; } = string.Empty;
|
|
public string Language { get; init; } = string.Empty;
|
|
public string Name { get; init; } = string.Empty;
|
|
public bool ForcedDisplay { get; init; }
|
|
|
|
/// <summary>
|
|
/// True for the first track of each type group (video/audio/subtitles/
|
|
/// chapters) in the track table, computed once when the list is built.
|
|
/// Used to draw a divider line above the row in the UI.
|
|
/// </summary>
|
|
public bool IsGroupStart { get; set; }
|
|
|
|
|
|
private bool _defaultTrack;
|
|
|
|
/// <summary>
|
|
/// Whether this track should be flagged as the default track of its type
|
|
/// when stripped. For audio and subtitles this is kept in sync with
|
|
/// <see cref="Copy"/> (selecting a track also makes it the default one
|
|
/// of its type).
|
|
/// </summary>
|
|
public bool DefaultTrack
|
|
{
|
|
get => _defaultTrack;
|
|
set
|
|
{
|
|
if (_defaultTrack == value) return;
|
|
_defaultTrack = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Text shown in the track table's Name column.
|
|
/// </summary>
|
|
public string DisplayName => Name;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public bool IsEditable => Type is "audio" or "subtitles";
|
|
|
|
/// <summary>
|
|
/// Chapters aren't a real track and have no track ID; show a dash
|
|
/// instead of a meaningless number.
|
|
/// </summary>
|
|
public string IdDisplay => Type == "chapters" ? "—" : Id.ToString();
|
|
|
|
|
|
public bool Copy
|
|
{
|
|
get => _copy;
|
|
set
|
|
{
|
|
if (_copy == value) return;
|
|
_copy = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Key used to match a track's identity across different queued files
|
|
/// when propagating an audio/subtitle selection. Matched on "Codec/Name"
|
|
/// so tracks with the same name but a different codec are treated as
|
|
/// distinct, even though only the name is shown in the table.
|
|
/// </summary>
|
|
public string PropagationKey => $"{Codec}/{Name}";
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
private void OnPropertyChanged([CallerMemberName] string? name = null)
|
|
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
|
}
|