diff --git a/EmbyToolbox/MainWindow.xaml b/EmbyToolbox/MainWindow.xaml index 0a31bf6..59a650b 100644 --- a/EmbyToolbox/MainWindow.xaml +++ b/EmbyToolbox/MainWindow.xaml @@ -368,7 +368,6 @@ - @@ -412,37 +411,6 @@ - - - - - - - - - @@ -463,43 +431,6 @@ - - - @@ -541,9 +472,21 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/EmbyToolbox/MainWindow.xaml.cs b/EmbyToolbox/MainWindow.xaml.cs index 8acdfce..811ee44 100644 --- a/EmbyToolbox/MainWindow.xaml.cs +++ b/EmbyToolbox/MainWindow.xaml.cs @@ -1,7 +1,4 @@ using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; using EmbyToolbox.ViewModels; namespace EmbyToolbox; @@ -13,19 +10,4 @@ public partial class MainWindow InitializeComponent(); DataContext = new MainWindowViewModel(); } - - private void OnJsonTreeItemPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) - { - var dependencyObject = e.OriginalSource as DependencyObject; - while (dependencyObject is not null && dependencyObject is not TreeViewItem) - { - dependencyObject = VisualTreeHelper.GetParent(dependencyObject); - } - - if (dependencyObject is TreeViewItem item) - { - item.IsSelected = true; - item.Focus(); - } - } } diff --git a/EmbyToolbox/ViewModels/VideoInfoViewModel.cs b/EmbyToolbox/ViewModels/VideoInfoViewModel.cs index 92d747c..66c0811 100644 --- a/EmbyToolbox/ViewModels/VideoInfoViewModel.cs +++ b/EmbyToolbox/ViewModels/VideoInfoViewModel.cs @@ -1,4 +1,3 @@ -using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Text.Json; @@ -23,7 +22,8 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged private string _selectedFilePath = string.Empty; private string _analysisStateText = string.Empty; private string _errorMessage = string.Empty; - private string _rawJson = string.Empty; + private string _formattedJson = string.Empty; + private IReadOnlyList _formattedJsonLines = Array.Empty(); private string _summaryText = string.Empty; private bool _isBusy; private bool _isVideoInfoDropHighlight; @@ -44,41 +44,16 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged SelectFileCommand = new RelayCommand(ExecuteSelectFile); SelectSummaryFilesCommand = new RelayCommand(ExecuteSelectSummaryFiles); - ExpandAllCommand = new RelayCommand(ExecuteExpandAll); - CollapseAllCommand = new RelayCommand(ExecuteCollapseAll); - CopyJsonCommand = new RelayCommand(ExecuteCopyJson, () => !string.IsNullOrWhiteSpace(_rawJson)); - SaveJsonCommand = new RelayCommand(ExecuteSaveJson, () => !string.IsNullOrWhiteSpace(_rawJson)); CopySummaryCommand = new RelayCommand(ExecuteCopySummary, () => !string.IsNullOrWhiteSpace(SummaryText) && SummaryText != "Файл не проанализирован"); SaveSummaryCommand = new RelayCommand(ExecuteSaveSummary, () => !string.IsNullOrWhiteSpace(SummaryText) && SummaryText != "Файл не проанализирован"); - CopyNodeValueCommand = new RelayCommand(ExecuteCopyNodeValue, CanCopyNodeValue); - CopyNodeLineCommand = new RelayCommand(ExecuteCopyNodeLine, CanCopyNodeLine); - CopyNodeWithChildrenCommand = new RelayCommand(ExecuteCopyNodeWithChildren, CanCopyNodeWithChildren); - CopyNodePathCommand = new RelayCommand(ExecuteCopyNodePath, CanCopyNodePath); } - public ObservableCollection JsonNodes { get; } = new(); - public ICommand SelectFileCommand { get; } public ICommand SelectSummaryFilesCommand { get; } - public ICommand ExpandAllCommand { get; } - - public ICommand CollapseAllCommand { get; } - - public ICommand CopyJsonCommand { get; } - - public ICommand SaveJsonCommand { get; } public ICommand CopySummaryCommand { get; } public ICommand SaveSummaryCommand { get; } - public ICommand CopyNodeValueCommand { get; } - - public ICommand CopyNodeLineCommand { get; } - - public ICommand CopyNodeWithChildrenCommand { get; } - - public ICommand CopyNodePathCommand { get; } - public string SelectedFilePath { get => _selectedFilePath; @@ -124,6 +99,37 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged } } + public string FormattedJson + { + get => _formattedJson; + private set + { + if (_formattedJson == value) + { + return; + } + + _formattedJson = value; + FormattedJsonLines = SplitTextLines(value); + OnPropertyChanged(); + } + } + + public IReadOnlyList FormattedJsonLines + { + get => _formattedJsonLines; + private set + { + if (ReferenceEquals(_formattedJsonLines, value)) + { + return; + } + + _formattedJsonLines = value; + OnPropertyChanged(); + } + } + public bool IsBusy { get => _isBusy; @@ -307,9 +313,8 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged private async Task AnalyzeAsync() { - JsonNodes.Clear(); ErrorMessage = string.Empty; - _rawJson = string.Empty; + FormattedJson = string.Empty; RaiseCommandStates(); if (string.IsNullOrWhiteSpace(SelectedFilePath)) @@ -335,8 +340,7 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged try { - _rawJson = result.Json; - BuildTree(_rawJson); + FormattedJson = FormatJsonOrFallback(result.Json); AnalysisStateText = "Готово"; RaiseCommandStates(); _logging.Info($"ffprobe завершен: {Path.GetFileName(SelectedFilePath)}", "video-info.ffprobe", command: result.Command, stdout: result.StdOut, stderr: result.StdErr); @@ -427,125 +431,6 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged RaiseCommandStates(); } - private void BuildTree(string json) - { - using var doc = JsonDocument.Parse(json); - JsonNodes.Clear(); - - if (doc.RootElement.ValueKind == JsonValueKind.Object) - { - foreach (var property in doc.RootElement.EnumerateObject()) - { - JsonNodes.Add(CreateNode(property.Name, property.Value, null)); - } - } - else - { - JsonNodes.Add(CreateNode("root", doc.RootElement, null)); - } - } - - private static JsonTreeNodeViewModel CreateNode(string name, JsonElement element, JsonTreeNodeViewModel? parent) - { - var node = new JsonTreeNodeViewModel(name, GetPreviewValue(element), element.GetRawText(), parent); - - switch (element.ValueKind) - { - case JsonValueKind.Object: - foreach (var prop in element.EnumerateObject()) - { - node.Children.Add(CreateNode(prop.Name, prop.Value, node)); - } - break; - case JsonValueKind.Array: - var index = 0; - foreach (var item in element.EnumerateArray()) - { - node.Children.Add(CreateNode($"[{index}]", item, node)); - index++; - } - break; - } - - return node; - } - - private static string GetPreviewValue(JsonElement element) - { - return element.ValueKind switch - { - JsonValueKind.Object => "{...}", - JsonValueKind.Array => "[...]", - JsonValueKind.String => element.GetString() ?? string.Empty, - JsonValueKind.Number => element.GetRawText(), - JsonValueKind.True => "true", - JsonValueKind.False => "false", - JsonValueKind.Null => "null", - _ => element.GetRawText() - }; - } - - private void ExecuteExpandAll() - { - SetExpandedState(JsonNodes, true); - } - - private void ExecuteCollapseAll() - { - SetExpandedState(JsonNodes, false); - } - - private static void SetExpandedState(IEnumerable nodes, bool isExpanded) - { - foreach (var node in nodes) - { - node.IsExpanded = isExpanded; - SetExpandedState(node.Children, isExpanded); - } - } - - private void ExecuteCopyJson() - { - if (string.IsNullOrWhiteSpace(_rawJson)) - { - return; - } - - Clipboard.SetText(_rawJson); - _logging.Info("JSON скопирован в буфер обмена", "video-info.copy"); - } - - private void ExecuteSaveJson() - { - if (string.IsNullOrWhiteSpace(_rawJson)) - { - return; - } - - var defaultName = string.IsNullOrWhiteSpace(SelectedFilePath) - ? "ffprobe.json" - : $"{Path.GetFileNameWithoutExtension(SelectedFilePath)}.ffprobe.json"; - - var dialog = new SaveFileDialog - { - Title = "Сохранить JSON ffprobe", - Filter = "JSON (*.json)|*.json|Все файлы|*.*", - FileName = defaultName, - InitialDirectory = _recentPaths.GetInitialDirectory(RecentPathScenario.SettingsOutputFolder), - }; - - if (dialog.ShowDialog() != true) - { - return; - } - - File.WriteAllText(dialog.FileName, _rawJson); - _recentPaths.RememberChosenFolder( - RecentPathScenario.SettingsOutputFolder, - Path.GetDirectoryName(dialog.FileName) ?? dialog.FileName); - _logging.Info($"JSON сохранен: {dialog.FileName}", "video-info.save"); - } - private void ExecuteCopySummary() { if (string.IsNullOrWhiteSpace(SummaryText) || SummaryText == "Файл не проанализирован") @@ -594,105 +479,8 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged private void RaiseCommandStates() { - (CopyJsonCommand as RelayCommand)?.RaiseCanExecuteChanged(); - (SaveJsonCommand as RelayCommand)?.RaiseCanExecuteChanged(); (CopySummaryCommand as RelayCommand)?.RaiseCanExecuteChanged(); (SaveSummaryCommand as RelayCommand)?.RaiseCanExecuteChanged(); - (CopyNodeValueCommand as RelayCommand)?.RaiseCanExecuteChanged(); - (CopyNodeLineCommand as RelayCommand)?.RaiseCanExecuteChanged(); - (CopyNodeWithChildrenCommand as RelayCommand)?.RaiseCanExecuteChanged(); - (CopyNodePathCommand as RelayCommand)?.RaiseCanExecuteChanged(); - } - - private static JsonTreeNodeViewModel? AsNode(object? parameter) - { - return parameter as JsonTreeNodeViewModel; - } - - private bool CanCopyNodeValue(object? parameter) - { - var node = AsNode(parameter); - return node is not null && node.Children.Count == 0; - } - - private bool CanCopyNodeLine(object? parameter) - { - return AsNode(parameter) is not null; - } - - private bool CanCopyNodeWithChildren(object? parameter) - { - return AsNode(parameter) is not null; - } - - private bool CanCopyNodePath(object? parameter) - { - return AsNode(parameter) is not null; - } - - private void ExecuteCopyNodeValue(object? parameter) - { - var node = AsNode(parameter); - if (node is null || node.Children.Count > 0) - { - return; - } - - Clipboard.SetText(node.Value); - _logging.Info("узел JSON скопирован", "video-info.copy"); - } - - private void ExecuteCopyNodeLine(object? parameter) - { - var node = AsNode(parameter); - if (node is null) - { - return; - } - - Clipboard.SetText($"{node.Name}: {node.Value}"); - _logging.Info("узел JSON скопирован", "video-info.copy"); - } - - private void ExecuteCopyNodeWithChildren(object? parameter) - { - var node = AsNode(parameter); - if (node is null) - { - return; - } - - var formatted = FormatJsonOrFallback(node.SubtreeJson); - Clipboard.SetText(formatted); - _logging.Info("узел JSON скопирован", "video-info.copy"); - } - - private void ExecuteCopyNodePath(object? parameter) - { - var node = AsNode(parameter); - if (node is null) - { - return; - } - - Clipboard.SetText(BuildNodePath(node)); - _logging.Info("узел JSON скопирован", "video-info.copy"); - } - - private static string BuildNodePath(JsonTreeNodeViewModel node) - { - if (node.Parent is null) - { - return node.Name; - } - - var parentPath = BuildNodePath(node.Parent); - if (node.Name.StartsWith("[", StringComparison.Ordinal)) - { - return $"{parentPath}{node.Name}"; - } - - return string.IsNullOrWhiteSpace(parentPath) ? node.Name : $"{parentPath}.{node.Name}"; } private static string FormatJsonOrFallback(string json) @@ -707,5 +495,15 @@ public sealed class VideoInfoViewModel : INotifyPropertyChanged return json; } } + + private static IReadOnlyList SplitTextLines(string text) + { + if (string.IsNullOrEmpty(text)) + { + return Array.Empty(); + } + + return text.ReplaceLineEndings("\n").Split('\n'); + } }