/// <summary> /// Reads WebVTT media captions from a given <see cref="TextReader"/>. /// </summary> /// <param name="reader">Text reader to read the captions.</param> /// <returns>A task that represents the asynchronous read operation.</returns> public static async Task <MediaCaptions> ReadMediaCaptionsAsync( TextReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } // Process stream header line var line = await reader.ReadLineAsync() .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(line) || line.Length < 6 || false == line.StartsWith(Constants.WebVttHeaderToken) || line.Length >= 7 && line[6] != '\t' && line[6] != ' ') { throw new InvalidDataException("The stream does not start with the correct WebVTT file signature."); } var result = new MediaCaptions(); // Process (skip over) optional headers from the stream while (false == string.IsNullOrEmpty(line)) { line = await reader.ReadLineAsync() .ConfigureAwait(false); } // Process media caption blocks. List <RegionDefinition> regions = new List <RegionDefinition>(); List <Style> styles = new List <Style>(); List <Cue> cues = new List <Cue>(); BaseBlock block; do { block = await WebVttParser.ReadBlockAsync(reader) .ConfigureAwait(false); RegionDefinition region = block as RegionDefinition; Style style = block as Style; Cue cue = block as Cue; if (cues.Count == 0) { if (region != null) { regions.Add(region); } else if (style != null) { styles.Add(style); } } else if (region != null || style != null) { throw new InvalidDataException("Region or style blocks cannot be mixed with cue blocks."); } if (cue != null) { cues.Add(cue); } }while (block != null); if (regions.Count > 0) { result.Regions = regions.ToArray(); } if (styles.Count > 0) { result.Styles = styles.ToArray(); } if (cues.Count > 0) { result.Cues = cues.ToArray(); } return(result); }
/// <summary> /// Reads WebVTT Region definition block from the stream. /// </summary> /// <param name="firstLine">First line of the block read from the reader.</param> /// <param name="reader">Text reader to read the region block.</param> /// <returns>A task that represents the asynchronous read operation.</returns> private static async Task <RegionDefinition> ReadRegionAsync( string firstLine, TextReader reader) { string line = firstLine; if (line.Length > Constants.RegionToken.Length && false == string.IsNullOrWhiteSpace(line.Substring(Constants.RegionToken.Length))) { throw new InvalidDataException(string.Format("Invalid characters found after region definition header: {0}", line)); } var content = new StringBuilder(100); while (false == string.IsNullOrEmpty(line)) { line = await reader.ReadLineAsync() .ConfigureAwait(false); if (false == string.IsNullOrEmpty(line)) { if (line.Contains(Constants.ArrowToken)) { throw new InvalidDataException(string.Format("Region definition must not contain '{0}'.", Constants.ArrowToken)); } content.SafeAppendLine(line); } } var result = new RegionDefinition() { RawContent = content.Length > 0 ? content.ToString() : null }; if (result.RawContent != null) { var settings = WebVttParser.ParseSettings(result.RawContent); if (settings != null) { string value; if (WebVttParser.TryGetStringSetting(Constants.RegionIdName, settings, out value)) { result.Id = value; } double percent; if (WebVttParser.TryGetPercentSetting(Constants.WidthName, settings, out percent)) { result.WidthPercent = percent; } Anchor anchor; if (WebVttParser.TryGetAnchorSetting(Constants.RegionAnchorName, settings, out anchor)) { result.RegionAnchor = anchor; } if (WebVttParser.TryGetAnchorSetting(Constants.ViewPortAnchorName, settings, out anchor)) { result.ViewPortAnchor = anchor; } if (WebVttParser.TryGetStringSetting(Constants.ScrollName, settings, out value)) { result.Scroll = string.Equals(value, Constants.ScrollUpValue, StringComparison.OrdinalIgnoreCase); } int lines; if (WebVttParser.TryGetIntSetting(Constants.LinesName, settings, out lines)) { result.Lines = lines; } } } return(result); }