200 lines
6.3 KiB
C#
200 lines
6.3 KiB
C#
using System.Collections;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Windows;
|
|
using EmbyToolbox.Models;
|
|
using EmbyToolbox.Services;
|
|
|
|
namespace EmbyToolbox.ViewModels;
|
|
|
|
public sealed class BulkFileConversionSettingsViewModel : INotifyPropertyChanged, ITrackPlanPreviewHost
|
|
{
|
|
private readonly ConversionQueueItem _representative;
|
|
private readonly ConversionTaskOverride _draft;
|
|
private readonly Action<IReadOnlyList<TrackOverrideEntry>> _onApply;
|
|
private readonly Action _onClose;
|
|
|
|
public BulkFileConversionSettingsViewModel(
|
|
ConversionQueueItem representative,
|
|
IReadOnlyList<ConversionQueueItem> targets,
|
|
ConversionFormOptions formOptions,
|
|
Action<IReadOnlyList<TrackOverrideEntry>> onApply,
|
|
Action onClose)
|
|
{
|
|
_representative = representative;
|
|
_draft = representative.TaskOverride.Clone();
|
|
_onApply = onApply;
|
|
_onClose = onClose;
|
|
FormOptions = formOptions;
|
|
|
|
TargetRowNumbersText = string.Join(", ", targets.OrderBy(i => i.OrderNumber).Select(i => i.OrderNumber));
|
|
FilesCount = targets.Count;
|
|
|
|
BuildRows();
|
|
ValidateDefaultConflicts();
|
|
|
|
SaveCommand = new RelayCommand(ExecuteSave);
|
|
CancelCommand = new RelayCommand(() => _onClose());
|
|
OnSelectionChangedCommand = new RelayCommand(OnSelectionChanged);
|
|
SetSelectedTracksRemoveCommand = new RelayCommand(SetSelectedTracksRemove, CanSetSelectedTracksRemove);
|
|
}
|
|
|
|
public ConversionFormOptions FormOptions { get; }
|
|
public ObservableCollection<TrackSettingsRowViewModel> TrackRows { get; } = new();
|
|
public ObservableCollection<TrackSettingsRowViewModel> SelectedTracks { get; } = new();
|
|
public RelayCommand SaveCommand { get; }
|
|
public RelayCommand CancelCommand { get; }
|
|
public RelayCommand OnSelectionChangedCommand { get; }
|
|
public RelayCommand SetSelectedTracksRemoveCommand { get; }
|
|
public int FilesCount { get; }
|
|
public string TargetRowNumbersText { get; }
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
public void RecalculatePlanPreview()
|
|
{
|
|
// No per-file plan preview in bulk dialog.
|
|
}
|
|
|
|
public void OnTrackDefaultEnabled(TrackSettingsRowViewModel row)
|
|
{
|
|
if (row.DataModel.StreamKind is not (MediaStreamKind.Audio or MediaStreamKind.Subtitle))
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var r in TrackRows)
|
|
{
|
|
if (ReferenceEquals(r, row))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (r.DataModel.StreamKind == row.DataModel.StreamKind)
|
|
{
|
|
r.Default = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ValidateDefaultConflicts()
|
|
{
|
|
var audioDefaults = TrackRows
|
|
.Where(r => r.DataModel.StreamKind == MediaStreamKind.Audio && r.Action != TrackActionKind.Remove && r.Default is true)
|
|
.ToList();
|
|
var subDefaults = TrackRows
|
|
.Where(r => r.DataModel.StreamKind == MediaStreamKind.Subtitle && r.Action != TrackActionKind.Remove && r.Default is true)
|
|
.ToList();
|
|
|
|
foreach (var r in TrackRows)
|
|
{
|
|
r.HasDefaultConflict = false;
|
|
}
|
|
|
|
if (audioDefaults.Count > 1)
|
|
{
|
|
foreach (var r in audioDefaults)
|
|
{
|
|
r.HasDefaultConflict = true;
|
|
}
|
|
}
|
|
|
|
if (subDefaults.Count > 1)
|
|
{
|
|
foreach (var r in subDefaults)
|
|
{
|
|
r.HasDefaultConflict = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnSelectionChanged(object? parameter)
|
|
{
|
|
SelectedTracks.Clear();
|
|
if (parameter is IList list)
|
|
{
|
|
foreach (var r in list.OfType<TrackSettingsRowViewModel>())
|
|
{
|
|
SelectedTracks.Add(r);
|
|
}
|
|
}
|
|
|
|
SetSelectedTracksRemoveCommand.RaiseCanExecuteChanged();
|
|
}
|
|
|
|
private bool CanSetSelectedTracksRemove(object? parameter)
|
|
{
|
|
if (parameter is not IList list || list.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return list.OfType<TrackSettingsRowViewModel>().Any(r => r.ValidActions.Contains(TrackActionKind.Remove));
|
|
}
|
|
|
|
private void SetSelectedTracksRemove(object? parameter)
|
|
{
|
|
if (parameter is not IList list || list.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var rows = list.OfType<TrackSettingsRowViewModel>().ToList();
|
|
var changed = false;
|
|
foreach (var row in rows)
|
|
{
|
|
if (!row.ValidActions.Contains(TrackActionKind.Remove))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
row.Action = TrackActionKind.Remove;
|
|
changed = true;
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
ValidateDefaultConflicts();
|
|
SetSelectedTracksRemoveCommand.RaiseCanExecuteChanged();
|
|
}
|
|
}
|
|
|
|
private void ExecuteSave()
|
|
{
|
|
ValidateDefaultConflicts();
|
|
var hasAudioConflict = TrackRows.Any(r => r.HasDefaultConflict && r.DataModel.StreamKind == MediaStreamKind.Audio);
|
|
var hasSubConflict = TrackRows.Any(r => r.HasDefaultConflict && r.DataModel.StreamKind == MediaStreamKind.Subtitle);
|
|
if (hasAudioConflict || hasSubConflict)
|
|
{
|
|
MessageBox.Show(
|
|
"Ошибка: для Audio и Subtitle может быть только одна дорожка Default (исключая Remove).",
|
|
"Валидация",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
_onApply(_draft.TrackOverrides.Select(t => t.Clone()).ToList());
|
|
_onClose();
|
|
}
|
|
|
|
private void BuildRows()
|
|
{
|
|
TrackRows.Clear();
|
|
var media = _representative.MediaAnalysis;
|
|
var idx = 1;
|
|
foreach (var t in _draft.TrackOverrides)
|
|
{
|
|
MediaStreamInfo? em = t.Source == SourceKind.Embedded && media is not null
|
|
? media.AllStreams.FirstOrDefault(s => s.Index == t.StreamIndex)
|
|
: null;
|
|
TrackRows.Add(new TrackSettingsRowViewModel(this, t, idx, em, _draft.TargetContainer));
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|