using System.Text; namespace EmbyToolbox.Services; public sealed class ChapterBuilderService { public string BuildFfmetadata(IReadOnlyList chapterTitles, IReadOnlyList durationsSeconds) { if (chapterTitles.Count != durationsSeconds.Count) { throw new ArgumentException("Количество глав не совпадает с количеством длительностей."); } var sb = new StringBuilder(); sb.AppendLine(";FFMETADATA1"); long currentStartMs = 0; for (var i = 0; i < chapterTitles.Count; i++) { var durationMs = Math.Max(1L, (long)Math.Round(Math.Max(0.001, durationsSeconds[i]) * 1000.0, MidpointRounding.AwayFromZero)); var endMs = currentStartMs + durationMs - 1; var title = string.IsNullOrWhiteSpace(chapterTitles[i]) ? $"Часть {i + 1}" : chapterTitles[i].Trim(); sb.AppendLine("[CHAPTER]"); sb.AppendLine("TIMEBASE=1/1000"); sb.AppendLine($"START={currentStartMs}"); sb.AppendLine($"END={endMs}"); sb.AppendLine($"title={EscapeMetadataValue(title)}"); currentStartMs += durationMs; } return sb.ToString(); } private static string EscapeMetadataValue(string value) => value .Replace("\\", "\\\\", StringComparison.Ordinal) .Replace("=", "\\=", StringComparison.Ordinal) .Replace(";", "\\;", StringComparison.Ordinal) .Replace("#", "\\#", StringComparison.Ordinal) .Replace(Environment.NewLine, " ", StringComparison.Ordinal) .Replace("\n", " ", StringComparison.Ordinal) .Replace("\r", " ", StringComparison.Ordinal); }