using System.Globalization; using System.Text; using ErsatzTV.Core.Interfaces.FFmpeg; namespace ErsatzTV.Core.FFmpeg; public class SubtitleBuilder { private readonly ITempFilePool _tempFilePool; private Option _alignment; private Option _borderStyle; private string _content; private Option _end; private bool _fade; private Option _fontName; private Option _fontSize; private int _marginLeft; private int _marginRight; private int _marginV; private Option _outlineColor; private Option _primaryColor; private Option _resolution = None; private Option _shadow; private Option _start; public SubtitleBuilder(ITempFilePool tempFilePool) => _tempFilePool = tempFilePool; public SubtitleBuilder WithResolution(IDisplaySize resolution) { _resolution = Some(resolution); return this; } public SubtitleBuilder WithFontName(string fontName) { _fontName = fontName; return this; } public SubtitleBuilder WithFontSize(int fontSize) { _fontSize = fontSize; return this; } public SubtitleBuilder WithPrimaryColor(string primaryColor) { _primaryColor = primaryColor; return this; } public SubtitleBuilder WithOutlineColor(string outlineColor) { _outlineColor = outlineColor; return this; } public SubtitleBuilder WithAlignment(int alignment) { _alignment = alignment; return this; } public SubtitleBuilder WithMarginRight(int marginRight) { _marginRight = marginRight; return this; } public SubtitleBuilder WithMarginLeft(int marginLeft) { _marginLeft = marginLeft; return this; } public SubtitleBuilder WithMarginV(int marginV) { _marginV = marginV; return this; } public SubtitleBuilder WithBorderStyle(int borderStyle) { _borderStyle = borderStyle; return this; } public SubtitleBuilder WithShadow(int shadow) { _shadow = shadow; return this; } public SubtitleBuilder WithFormattedContent(string content) { _content = content; return this; } public SubtitleBuilder WithStartEnd(TimeSpan start, TimeSpan end) { _start = start; _end = end; return this; } public SubtitleBuilder WithFade(bool fade) { _fade = fade; return this; } public async Task BuildFile() { string fileName = _tempFilePool.GetNextTempFile(TempFileCategory.Subtitle); var sb = new StringBuilder(); sb.AppendLine("[Script Info]"); sb.AppendLine("ScriptType: v4.00+"); sb.AppendLine("WrapStyle: 0"); sb.AppendLine("ScaledBorderAndShadow: yes"); sb.AppendLine("YCbCr Matrix: None"); foreach (IDisplaySize resolution in _resolution) { sb.AppendLine(CultureInfo.InvariantCulture, $"PlayResX: {resolution.Width}"); sb.AppendLine(CultureInfo.InvariantCulture, $"PlayResY: {resolution.Height}"); } sb.AppendLine("[V4+ Styles]"); sb.AppendLine( "Format: Name, Fontname, Fontsize, PrimaryColour, OutlineColour, BorderStyle, Outline, Shadow, Alignment, Encoding"); sb.AppendLine( CultureInfo.InvariantCulture, $"Style: Default,{await _fontName.IfNoneAsync("")},{await _fontSize.IfNoneAsync(32)},{await _primaryColor.IfNoneAsync("")},{await _outlineColor.IfNoneAsync("")},{await _borderStyle.IfNoneAsync(0)},1,{await _shadow.IfNoneAsync(0)},{await _alignment.IfNoneAsync(0)},1"); var start = "0:00:00.00"; foreach (TimeSpan startTime in _start) { start = $"{(int)startTime.TotalHours:00}:{startTime.ToString(@"mm\:ss\.ff", CultureInfo.InvariantCulture)}"; } var end = "99:99:99.99"; foreach (TimeSpan endTime in _end) { end = $"{(int)endTime.TotalHours:00}:{endTime.ToString(@"mm\:ss\.ff", CultureInfo.InvariantCulture)}"; } string fade = _fade ? @"{\fad(1200, 1200)}" : string.Empty; sb.AppendLine("[Events]"); sb.AppendLine("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"); sb.AppendLine( CultureInfo.InvariantCulture, @$"Dialogue: 0,{start},{end},Default,,{_marginLeft},{_marginRight},{_marginV},,{fade}{_content}"); await File.WriteAllTextAsync(fileName, sb.ToString()); return fileName; } }