using MkvPropEditWrapper.Shared; namespace MkvPropEditWrapper.MkvInfo.Reader; public static class NodeUtils { public static IEnumerable Descendants(this MkvNode root) { var nodes = new Stack(new[] {root}); while (nodes.Any()) { var node = nodes.Pop(); yield return node; foreach (var newNode in node.Children) { nodes.Push(newNode); } } } /// /// Generate track info from parsed output, only works on the first root node as it uses absolute depth /// /// Node root /// All parseable public static IEnumerable GetTrackInfos(this MkvNodeRoot root) { TrackInfo? ParseTrackInfo(MkvNode track) { ReadOnlySpan audioType = "audio"; ReadOnlySpan subtitleType = "subtitles"; int number = -1; var trackType = TrackType.Unknown; string language = "Unknown"; bool defaultFlag = default; bool forcedFlag = default; foreach (var child in track.Children) { if (child is MkvProperty property) { ReadOnlySpan span; switch (property.PropertyType) { case PropertyType.TrackType: span = property.Value.Span; if (span.SequenceEqual(audioType)) { trackType = TrackType.Audio; } else if (span.SequenceEqual(subtitleType)) { trackType = TrackType.Subtitles; } else { return null; } break; case PropertyType.TrackNumber: span = property.Value.Span; number = int.Parse(span[..span.IndexOf(' ')]); break; case PropertyType.Language: language = property.Value.ToString(); break; case PropertyType.FlagDefault: defaultFlag = property.Value.Span[0] == '1'; break; case PropertyType.FlagForced: forcedFlag = property.Value.Span[0] == '1'; break; } } } return number == -1 ? null : new TrackInfo(number, trackType, language, defaultFlag, forcedFlag); } var tracks = root.Descendants().Where(n => n is { Depth: 2, NodeType: NodeType.Track }); foreach (var track in tracks) { var trackInfo = ParseTrackInfo(track); if (trackInfo is not null) { yield return trackInfo; } } } public static (IEnumerable audio, IEnumerable subtitles) SplitByType(this IEnumerable trackInfos) { var lookup = trackInfos.OrderBy(t => t.Number).ToLookup(t => t.TrackType); return (lookup[TrackType.Audio], lookup[TrackType.Subtitles]); } }