private SubtitleItem ParseLine(string line, float frameRate)
        {
            var match = Regex.Match(line, LineRegex);

            if (match.Success && match.Groups.Count > 2)
            {
                var startFrame = match.Groups[1].Value;
                var start      = (int)(1000 * double.Parse(startFrame) / frameRate);
                var endTime    = match.Groups[2].Value;
                var end        = (int)(1000 * double.Parse(endTime) / frameRate);
                var text       = match.Groups[match.Groups.Count - 1].Value;
                var lines      = text.Split(_lineSeparators);
                //... آنچه گذشت|{y:i}RamtinJokar|{y:i}SalAM
                var nonEmptyLines = lines.Where(l => !string.IsNullOrEmpty(l)).ToList();
                if (nonEmptyLines.Count > 0)
                {
                    for (int i = 0; i < nonEmptyLines.Count; i++)
                    {
                        nonEmptyLines[i] = nonEmptyLines[i].Replace("|", Environment.NewLine);
                        if (nonEmptyLines[i].Contains("{y:i}"))
                        {
                            nonEmptyLines[i] = nonEmptyLines[i].Replace("{y:i}", "");
                            nonEmptyLines[i] = "<i>" + nonEmptyLines[i] + "</i>";
                        }
                        if (nonEmptyLines[i].Contains("{Y:b}"))
                        {
                            nonEmptyLines[i] = nonEmptyLines[i].Replace("{Y:b}", "");
                            nonEmptyLines[i] = "<b>" + nonEmptyLines[i] + "</b>";
                        }
                    }
                }
                var item = new SubtitleItem
                {
                    Lines     = nonEmptyLines,
                    StartTime = start,
                    EndTime   = end
                };

                return(item);
            }
            else
            {
                var message = string.Format("The subtitle file line {0} is " +
                                            "not in the micro dvd format. We stop the process.", line);
                throw new InvalidDataException(message);
            }
        }
Пример #2
0
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;


            Regex        regexTimeCodes = new Regex(@"^\{T\ \d+:\d+:\d+:\d+$");
            StreamReader st             = new StreamReader(stream, encoding, true);
            string       reshte         = st.ReadToEnd();

            List <string> lines = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            //{T 00:00:14:01
            //تقديم به تمام پارسي زبانان جهان
            //}
            //{T 00:00:20:97

            //}
            items.Clear();
            int    _errorCount = 0;
            bool   textOn      = false;
            string text        = string.Empty;
            double start       = 0;
            double end         = 0;

            foreach (string line in lines)
            {
                if (textOn)
                {
                    if (line.Trim() == "}")
                    {
                        SubtitleItem s = new SubtitleItem();
                        s.StartTime = int.Parse(start.ToString());
                        s.EndTime   = int.Parse(end.ToString());
                        s.Lines     = new List <string>()
                        {
                            text
                        };
                        items.Add(s);

                        text   = string.Empty;
                        start  = 0;
                        end    = 0;
                        textOn = false;
                    }
                    else
                    {
                        if (text.Length == 0)
                        {
                            text = line;
                        }
                        else
                        {
                            text += Environment.NewLine + line;
                        }
                    }
                }
                else
                {
                    if (regexTimeCodes.Match(line).Success)
                    {
                        try
                        {
                            textOn = true;
                            string[] arr = line.Substring(3).Trim().Split(':');
                            if (arr.Length == 4)
                            {
                                int hours        = int.Parse(arr[0]);
                                int minutes      = int.Parse(arr[1]);
                                int seconds      = int.Parse(arr[2]);
                                int milliseconds = int.Parse(arr[3]);
                                if (arr[3].Length == 2)
                                {
                                    milliseconds *= 10;
                                }
                                TimeSpan t = new TimeSpan(0, hours, minutes, seconds, milliseconds);
                                start = t.TotalMilliseconds;
                            }
                        }
                        catch
                        {
                            textOn = false;
                            _errorCount++;
                        }
                    }
                }
            }

            int index = 1;

            foreach (SubtitleItem s in items)
            {
                foreach (string line in s.Lines)
                {
                    SubtitleItem next = GetParagraphOrDefault(index);
                    if (next != null)
                    {
                        s.EndTime = next.StartTime;
                    }
                }
                index++;
            }

            int counter = 0;
            List <SubtitleItem> customList = new List <SubtitleItem>();

            foreach (var item in items)
            {
                if (counter % 2 == 0)
                {
                    customList.Add(item);
                }
                counter++;
            }
            items.Clear();
            items.AddRange(customList);

            if (items.Any())
            {
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'DVD Subtitle' format");
            }
        }
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;
            List <SubtitleItem> items    = new List <SubtitleItem>();
            Regex         regexTimeCodes = new Regex(@"^\d\d:\d\d:\d\d:\d\d[ ]+-[ ]+\d\d:\d\d:\d\d:\d\d");
            StreamReader  st             = new StreamReader(stream, encoding, true);
            string        reshte         = st.ReadToEnd();
            List <string> lines          = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            var          sb            = new StringBuilder();
            SubtitleItem lastParagraph = null;
            int          _errorCount   = 0;

            foreach (string line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                bool success = false;

                Match match = null;
                if (line.Length > 26 && line[2] == ':')
                {
                    match = regexTimeCodes.Match(line);
                }

                if (match != null && match.Success)
                {
                    string s = line.Substring(0, match.Length);
                    s = s.Replace(" - ", ":");
                    s = s.Replace(" ", string.Empty);
                    string[] parts = s.Split(':');
                    if (parts.Length == 8)
                    {
                        int hours        = int.Parse(parts[0]);
                        int minutes      = int.Parse(parts[1]);
                        int seconds      = int.Parse(parts[2]);
                        int milliseconds = int.Parse(parts[3]) * 10;
                        int start        = int.Parse(new TimeSpan(0, hours, minutes, seconds, milliseconds).TotalMilliseconds.ToString());

                        hours        = int.Parse(parts[4]);
                        minutes      = int.Parse(parts[5]);
                        seconds      = int.Parse(parts[6]);
                        milliseconds = int.Parse(parts[7]) * 10;
                        int end = int.Parse(new TimeSpan(0, hours, minutes, seconds, milliseconds).TotalMilliseconds.ToString());

                        string text = line.Substring(match.Length).TrimStart();
                        text = text.Replace("|", Environment.NewLine);

                        lastParagraph           = new SubtitleItem();
                        lastParagraph.StartTime = start;
                        lastParagraph.EndTime   = end;
                        lastParagraph.Lines     = new List <string>()
                        {
                            text
                        };
                        items.Add(lastParagraph);
                        success = true;
                    }
                }
                if (!success)
                {
                    _errorCount++;
                }
            }
            if (items.Any())
            {
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'Sony DVDArchitect' Subtitle format");
            }
        }
Пример #4
0
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;
            List <SubtitleItem> items    = new List <SubtitleItem>();
            Regex         regexTimeCodes = new Regex(@"^\d\d:\d\d:\d\d.\d+,\d\d:\d\d:\d\d.\d+$");
            StreamReader  st             = new StreamReader(stream, encoding, true);
            string        reshte         = st.ReadToEnd();
            List <string> lines          = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            var           sb        = new StringBuilder();
            SubtitleItem  paragraph = new SubtitleItem();
            ExpectingLine expecting = ExpectingLine.TimeCodes;


            foreach (string line in lines)
            {
                if (regexTimeCodes.IsMatch(line))
                {
                    string[] parts = line.Split(new[] { ':', ',', '.' }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length == 8)
                    {
                        try
                        {
                            int startHours        = int.Parse(parts[0]);
                            int startMinutes      = int.Parse(parts[1]);
                            int startSeconds      = int.Parse(parts[2]);
                            int startMilliseconds = int.Parse(parts[3]);
                            int endHours          = int.Parse(parts[4]);
                            int endMinutes        = int.Parse(parts[5]);
                            int endSeconds        = int.Parse(parts[6]);
                            int endMilliseconds   = int.Parse(parts[7]);
                            paragraph.StartTime = int.Parse(new TimeSpan(0, startHours, startMinutes, startSeconds, startMilliseconds).TotalMilliseconds.ToString());
                            paragraph.EndTime   = int.Parse(new TimeSpan(0, endHours, endMinutes, endSeconds, endMilliseconds).TotalMilliseconds.ToString());
                            expecting           = ExpectingLine.Text;
                        }
                        catch
                        {
                            expecting = ExpectingLine.TimeCodes;
                        }
                    }
                }
                else
                {
                    if (expecting == ExpectingLine.Text)
                    {
                        if (line.Length > 0)
                        {
                            string text = line.Replace("[br]", Environment.NewLine);
                            text = text.Replace("{\\i1}", "<i>");
                            text = text.Replace("{\\i0}", "</i>");
                            text = text.Replace("{\\i}", "</i>");
                            text = text.Replace("{\\b1}", "<b>'");
                            text = text.Replace("{\\b0}", "</b>");
                            text = text.Replace("{\\b}", "</b>");
                            text = text.Replace("{\\u1}", "<u>");
                            text = text.Replace("{\\u0}", "</u>");
                            text = text.Replace("{\\u}", "</u>");
                            //<font color="">... آنچه گذشت</font>[br]{\i1}Ramtin{\b1}'Jokar{\b0}{\i0}[br]{\i1}SalAM{\i0}
                            text = text.Replace("[br]", Environment.NewLine);


                            paragraph.Lines = new List <string>()
                            {
                                text
                            };
                            items.Add(paragraph);
                            paragraph = new SubtitleItem();
                            expecting = ExpectingLine.TimeCodes;
                        }
                    }
                }
            }

            if (items.Any())
            {
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'SubViewer 2.0' Subtitle format");
            }
        }
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;
            List <SubtitleItem> items    = new List <SubtitleItem>();
            Regex         regexTimeCodes = new Regex(@"^\d\d:\d\d:\d\d:\d\d\\\d\d:\d\d:\d\d:\d\d$");
            StreamReader  st             = new StreamReader(stream, encoding, true);
            string        reshte         = st.ReadToEnd();
            List <string> lines          = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            var          sb          = new StringBuilder();
            SubtitleItem p           = null;
            int          _errorCount = 0;

            foreach (string line in lines)
            {
                string s = line.Trim();
                if (regexTimeCodes.IsMatch(s))
                {
                    var temp = s.Split('\\');
                    if (temp.Length > 1)
                    {
                        string start = temp[0];
                        string end   = temp[1];

                        string[] startParts = start.Split(new[] { ':', '.' }, StringSplitOptions.RemoveEmptyEntries);
                        string[] endParts   = end.Split(new[] { ':', '.' }, StringSplitOptions.RemoveEmptyEntries);
                        if (startParts.Length == 4 && endParts.Length == 4)
                        {
                            try
                            {
                                p           = new SubtitleItem();
                                p.StartTime = DecodeTimeCode(startParts);
                                p.EndTime   = DecodeTimeCode(endParts);
                                string text = sb.ToString().Trim();

                                Boolean positionTop = false;

                                if (text.StartsWith("}"))
                                {
                                    positionTop = true;

                                    text = text.Remove(0, 1);
                                }

                                text = text.Replace("[", @"<i>");
                                text = text.Replace("]", @"</i>");



                                text = text.Replace("</i>" + Environment.NewLine + "<i>", Environment.NewLine);


                                if (positionTop)
                                {
                                    text = "{\\an8}" + text;
                                }

                                p.Lines = new List <string>()
                                {
                                    text
                                };
                                if (text.Length > 0)
                                {
                                    items.Add(p);
                                }
                                sb = new StringBuilder();
                            }
                            catch (Exception exception)
                            {
                                _errorCount++;
                                System.Diagnostics.Debug.WriteLine(exception.Message);
                            }
                        }
                    }
                }
                else if (string.IsNullOrWhiteSpace(line) || line.StartsWith("*"))
                {
                }
                else if (p != null)
                {
                    sb.AppendLine(line);
                }
            }


            if (items.Any())
            {
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'SoftNi colon sub' Subtitle format");
            }
        }
Пример #6
0
        public List <SubtitleItem> ParseStream(Stream ssaStream, Encoding encoding)
        {
            if (!ssaStream.CanRead || !ssaStream.CanSeek)
            {
                var message = string.Format("Stream must be seekable and readable in a subtitles parser. " +
                                            "Operation interrupted; isSeekable: {0} - isReadable: {1}",
                                            ssaStream.CanSeek, ssaStream.CanSeek);
                throw new ArgumentException(message);
            }


            ssaStream.Position = 0;

            var reader = new StreamReader(ssaStream, encoding, true);

            var line       = reader.ReadLine();
            var lineNumber = 1;

            while (line != null && line != EventLine)
            {
                line = reader.ReadLine();
                lineNumber++;
            }

            if (line != null)
            {
                var headerLine = reader.ReadLine();
                if (!string.IsNullOrEmpty(headerLine))
                {
                    var columnHeaders = headerLine.Split(Separator).Select(head => head.Trim()).ToList();

                    var startIndexColumn = columnHeaders.IndexOf(StartColumn);
                    var endIndexColumn   = columnHeaders.IndexOf(EndColumn);
                    var textIndexColumn  = columnHeaders.IndexOf(TextColumn);

                    if (startIndexColumn > 0 && endIndexColumn > 0 && textIndexColumn > 0)
                    {
                        var items = new List <SubtitleItem>();

                        line = reader.ReadLine();
                        while (line != null)
                        {
                            if (!string.IsNullOrEmpty(line))
                            {
                                var columns   = line.Split(Separator);
                                var startText = columns[startIndexColumn];
                                var endText   = columns[endIndexColumn];


                                var textLine = string.Join(",", columns.Skip(textIndexColumn));

                                var start = ParseSsaTimecode(startText);
                                var end   = ParseSsaTimecode(endText);


                                if (start > 0 && end > 0 && !string.IsNullOrEmpty(textLine))
                                {
                                    textLine = textLine.Replace(@"{\c&H&}", "");
                                    textLine = textLine.Replace(@"{\c}", "");
                                    textLine = textLine.Replace(@"\\N", Environment.NewLine);
                                    textLine = textLine.Replace("{\\i1}", "<i>");
                                    textLine = textLine.Replace("{\\i0}", "</i>");
                                    textLine = textLine.Replace("{\\i}", "</i>");
                                    textLine = textLine.Replace("{\\b1}", "<b>'");
                                    textLine = textLine.Replace("{\\b0}", "</b>");
                                    textLine = textLine.Replace("{\\b}", "</b>");
                                    textLine = textLine.Replace("{\\u1}", "<u>");
                                    textLine = textLine.Replace("{\\u0}", "</u>");
                                    textLine = textLine.Replace("{\\u}", "</u>");
                                    textLine = textLine.Replace(@"{\b0\i0}", "");
                                    textLine = textLine.Replace(@"{\b1\i1}", "");
                                    textLine = textLine.Replace(@"{\i0\b0}", "");
                                    textLine = textLine.Replace(@"{\i1\b1}", "");

                                    var item = new SubtitleItem()
                                    {
                                        StartTime = start,
                                        EndTime   = end,
                                        Lines     = new List <string>()
                                        {
                                            textLine
                                        }
                                    };
                                    items.Add(item);
                                }
                            }
                            line = reader.ReadLine();
                        }

                        if (items.Any())
                        {
                            return(items);
                        }
                        else
                        {
                            throw new ArgumentException("Stream is not in a valid Ssa format");
                        }
                    }
                    else
                    {
                        var message = string.Format("Couldn't find all the necessary columns " +
                                                    "headers ({0}, {1}, {2}) in header line {3}",
                                                    StartColumn, EndColumn, TextColumn, headerLine);
                        throw new ArgumentException(message);
                    }
                }
                else
                {
                    var message = string.Format("The header line after the line '{0}' was null -> " +
                                                "no need to continue parsing", line);
                    throw new ArgumentException(message);
                }
            }
            else
            {
                var message = string.Format("We reached line '{0}' with line number #{1} without finding to " +
                                            "Event section ({2})", line, lineNumber, EventLine);
                throw new ArgumentException(message);
            }
        }
Пример #7
0
        public List <SubtitleItem> ParseStream(Stream vttStream, Encoding encoding)
        {
            if (!vttStream.CanRead || !vttStream.CanSeek)
            {
                var message = string.Format("Stream must be seekable and readable in a subtitles parser. " +
                                            "Operation interrupted; isSeekable: {0} - isReadable: {1}",
                                            vttStream.CanSeek, vttStream.CanSeek);
                throw new ArgumentException(message);
            }

            vttStream.Position = 0;

            var reader = new StreamReader(vttStream, encoding, true);

            var items       = new List <SubtitleItem>();
            var vttSubParts = GetVttSubTitleParts(reader).ToList();

            if (vttSubParts.Any())
            {
                foreach (var vttSubPart in vttSubParts)
                {
                    var lines =
                        vttSubPart.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
                        .Select(s => s.Trim())
                        .Where(l => !string.IsNullOrEmpty(l))
                        .ToList();

                    var item = new SubtitleItem();
                    foreach (var line in lines)
                    {
                        if (item.StartTime == 0 && item.EndTime == 0)
                        {
                            int startTc;
                            int endTc;
                            var success = TryParseTimecodeLine(line, out startTc, out endTc);
                            if (success)
                            {
                                item.StartTime = startTc;
                                item.EndTime   = endTc;
                            }
                        }
                        else
                        {
                            item.Lines.Add(line);
                        }
                    }

                    if ((item.StartTime != 0 || item.EndTime != 0) && item.Lines.Any())
                    {
                        items.Add(item);
                    }
                }

                if (items.Any())
                {
                    return(items);
                }
                else
                {
                    throw new ArgumentException("Stream is not in a valid VTT format");
                }
            }
            else
            {
                throw new FormatException("Parsing as VTT returned no VTT part.");
            }
        }
Пример #8
0
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;
            List <SubtitleItem> items    = new List <SubtitleItem>();
            Regex         regexTimeCodes = new Regex(@"^\[\d\d:\d\d:\d\d\]$");
            StreamReader  st             = new StreamReader(stream, encoding, true);
            string        reshte         = st.ReadToEnd();
            List <string> lines          = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            var          sb        = new StringBuilder();
            SubtitleItem paragraph = new SubtitleItem();

            ExpectingLine expecting = ExpectingLine.TimeStart;

            int _errorCount = 0;

            foreach (string line in lines)
            {
                if (line.StartsWith("[") && regexTimeCodes.IsMatch(line))
                {
                    string[] parts = line.Split(new[] { ':', ']', '[', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length == 3)
                    {
                        try
                        {
                            int startHours   = int.Parse(parts[0]);
                            int startMinutes = int.Parse(parts[1]);
                            int startSeconds = int.Parse(parts[2]);
                            var tc           = int.Parse(new TimeSpan(0, startHours, startMinutes, startSeconds, 0).TotalMilliseconds.ToString());
                            if (expecting == ExpectingLine.TimeStart)
                            {
                                paragraph           = new SubtitleItem();
                                paragraph.StartTime = tc;
                                expecting           = ExpectingLine.Text;
                            }
                            else if (expecting == ExpectingLine.TimeEnd)
                            {
                                paragraph.EndTime = tc;
                                expecting         = ExpectingLine.TimeStart;
                                items.Add(paragraph);
                                paragraph = new SubtitleItem();
                            }
                        }
                        catch
                        {
                            _errorCount++;
                            expecting = ExpectingLine.TimeStart;
                        }
                    }
                }
                else
                {
                    if (expecting == ExpectingLine.Text)
                    {
                        if (line.Length > 0)
                        {
                            string text = line.Replace("|", Environment.NewLine);
                            paragraph.Lines = new List <string>()
                            {
                                text
                            };
                            expecting = ExpectingLine.TimeEnd;
                        }
                    }
                }
            }

            if (items.Any())
            {
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'SubViewer 1.0' Subtitle format");
            }
        }
Пример #9
0
        public void LoadSubtitle(List <SubtitleItem> subtitle, string contents, List <string> liness = null)
        {
            string allInput      = contents;
            string allInputLower = allInput.ToLower();

            if (!allInputLower.Contains("<sync "))
            {
                return;
            }

            int styleStart = allInputLower.IndexOf("<style", StringComparison.Ordinal);

            const string syncTag      = "<sync start=";
            const string syncTagEnc   = "<sync encrypted=\"true\" start=";
            int          syncStartPos = allInputLower.IndexOf(syncTag, StringComparison.Ordinal);
            int          index        = syncStartPos + syncTag.Length;

            int syncStartPosEnc = allInputLower.IndexOf(syncTagEnc, StringComparison.Ordinal);

            if ((syncStartPosEnc >= 0 && syncStartPosEnc < syncStartPos) || syncStartPos == -1)
            {
                syncStartPos = syncStartPosEnc;
                index        = syncStartPosEnc + syncTagEnc.Length;
            }

            var p = new SubtitleItem();

            while (syncStartPos >= 0)
            {
                string millisecAsString = string.Empty;
                while (index < allInput.Length && @"""'0123456789".Contains(allInput[index]))
                {
                    if (allInput[index] != '"' && allInput[index] != '\'')
                    {
                        millisecAsString += allInput[index];
                    }
                    index++;
                }

                while (index < allInput.Length && allInput[index] != '>')
                {
                    index++;
                }
                if (index < allInput.Length && allInput[index] == '>')
                {
                    index++;
                }

                int syncEndPos    = allInputLower.IndexOf(syncTag, index, StringComparison.Ordinal);
                int syncEndPosEnc = allInputLower.IndexOf(syncTagEnc, index, StringComparison.Ordinal);
                if ((syncStartPosEnc >= 0 && syncStartPosEnc < syncStartPos) || syncEndPos == -1)
                {
                    syncEndPos = syncEndPosEnc;
                }

                string text;
                if (syncEndPos >= 0)
                {
                    text = allInput.Substring(index, syncEndPos - index);
                }
                else
                {
                    text = allInput.Substring(index);
                }

                string textToLower = text.ToLower();
                if (textToLower.Contains(" class="))
                {
                    var className  = new StringBuilder();
                    int startClass = textToLower.IndexOf(" class=", StringComparison.Ordinal);
                    int indexClass = startClass + 7;
                    while (indexClass < textToLower.Length)
                    {
                        className.Append(text[indexClass]);
                        indexClass++;
                    }
                }

                if (text.Contains("ID=\"Source\"") || text.Contains("ID=Source"))
                {
                    int sourceIndex = text.IndexOf("ID=\"Source\"", StringComparison.Ordinal);
                    if (sourceIndex < 0)
                    {
                        sourceIndex = text.IndexOf("ID=Source", StringComparison.Ordinal);
                    }
                    int st = sourceIndex - 1;
                    while (st > 0 && text.Substring(st, 2).ToUpper() != "<P")
                    {
                        st--;
                    }
                    if (st > 0)
                    {
                        text = text.Substring(0, st) + text.Substring(sourceIndex);
                    }
                    int et = st;
                    while (et < text.Length - 5 && text.Substring(et, 3).ToUpper() != "<P>" && text.Substring(et, 4).ToUpper() != "</P>")
                    {
                        et++;
                    }
                    text = text.Substring(0, st) + text.Substring(et);
                }
                text = text.Replace(Environment.NewLine, " ");
                text = text.Replace("  ", " ");

                text = text.TrimEnd();
                text = Regex.Replace(text, @"<br {0,2}/?>", Environment.NewLine, RegexOptions.IgnoreCase);

                while (text.Contains("  "))
                {
                    text = text.Replace("  ", " ");
                }
                text = text.Replace("</BODY>", string.Empty).Replace("</SAMI>", string.Empty).TrimEnd();

                int endSyncPos = text.ToUpper().IndexOf("</SYNC>", StringComparison.Ordinal);
                if (text.IndexOf('>') > 0 && (text.IndexOf('>') < endSyncPos || endSyncPos == -1))
                {
                    text = text.Remove(0, text.IndexOf('>') + 1);
                }
                text = text.TrimEnd();

                if (text.EndsWith("</sync>", StringComparison.OrdinalIgnoreCase))
                {
                    text = text.Substring(0, text.Length - 7).TrimEnd();
                }

                if (text.EndsWith("</p>", StringComparison.Ordinal) || text.EndsWith("</P>", StringComparison.Ordinal))
                {
                    text = text.Substring(0, text.Length - 4).TrimEnd();
                }

                text = text.Replace("&nbsp;", " ").Replace("&NBSP;", " ");

                if (text.Contains("<font color=") && !text.Contains("</font>"))
                {
                    text += "</font>";
                }
                if (text.StartsWith("<FONT COLOR=") && !text.Contains("</font>") && !text.Contains("</FONT>"))
                {
                    text += "</FONT>";
                }

                if (text.Contains('<') && text.Contains('>'))
                {
                    var  total   = new StringBuilder();
                    var  partial = new StringBuilder();
                    bool tagOn   = false;
                    for (int i = 0; i < text.Length; i++)
                    {
                        string tmp = text.Substring(i);
                        if (tmp.StartsWith("<") &&
                            (tmp.StartsWith("<font", StringComparison.Ordinal) ||
                             tmp.StartsWith("<div", StringComparison.Ordinal) ||
                             tmp.StartsWith("<i", StringComparison.Ordinal) ||
                             tmp.StartsWith("<b", StringComparison.Ordinal) ||
                             tmp.StartsWith("<s", StringComparison.Ordinal) ||
                             tmp.StartsWith("</", StringComparison.Ordinal)))
                        {
                            total.Append(WebUtility.HtmlDecode(partial.ToString()));
                            partial = new StringBuilder();
                            tagOn   = true;
                            total.Append('<');
                        }
                        else if (text.Substring(i).StartsWith(">") && tagOn)
                        {
                            tagOn = false;
                            total.Append('>');
                        }
                        else if (!tagOn)
                        {
                            partial.Append(text[i]);
                        }
                        else
                        {
                            total.Append(text[i]);
                        }
                    }
                    total.Append(WebUtility.HtmlDecode(partial.ToString()));
                    text = total.ToString();
                }
                else
                {
                    text = WebUtility.HtmlDecode(text);
                }

                string cleanText = text;
                while (cleanText.Contains("  "))
                {
                    cleanText = cleanText.Replace("  ", " ");
                }
                while (cleanText.Contains(Environment.NewLine + " "))
                {
                    cleanText = cleanText.Replace(Environment.NewLine + " ", Environment.NewLine);
                }
                while (cleanText.Contains(" " + Environment.NewLine))
                {
                    cleanText = cleanText.Replace(" " + Environment.NewLine, Environment.NewLine);
                }
                cleanText = cleanText.Trim();

                if (p.Lines.Count > 0 && !string.IsNullOrEmpty(millisecAsString) &&
                    p.Lines[0] != null && p.Lines[0].Length > 0)
                {
                    p.EndTime = int.Parse(millisecAsString);
                    subtitle.Add(p);
                    p = new SubtitleItem();
                }

                p.Lines = new List <string> {
                    cleanText
                };
                int l;
                if (int.TryParse(millisecAsString, out l))
                {
                    p.StartTime = l;
                }

                if (syncEndPos <= 0)
                {
                    syncStartPos = -1;
                }
                else
                {
                    syncStartPos = allInputLower.IndexOf(syncTag, syncEndPos, StringComparison.Ordinal);
                    index        = syncStartPos + syncTag.Length;

                    syncStartPosEnc = allInputLower.IndexOf(syncTagEnc, syncEndPos, StringComparison.Ordinal);
                    if ((syncStartPosEnc >= 0 && syncStartPosEnc < syncStartPos) || syncStartPos == -1)
                    {
                        syncStartPos = syncStartPosEnc;
                        index        = syncStartPosEnc + syncTagEnc.Length;
                    }
                }
            }
            if (!string.IsNullOrEmpty(p.Lines[0]) && !subtitle.Contains(p) &&
                p.Lines[0] != null && p.Lines[0].Length > 0)
            {
                p.EndTime = p.StartTime;
                subtitle.Add(p);
            }

            if (subtitle.Count > 0 &&
                (subtitle[subtitle.Count - 1].Lines[0].ToUpper().Trim() == "</BODY>" ||
                 subtitle[subtitle.Count - 1].Lines[0].ToUpper().Trim() == "<BODY>"))
            {
                subtitle.RemoveAt(subtitle.Count - 1);
            }

            System.Diagnostics.Debug.WriteLine(subtitle.Count);
        }
        public List <SubtitleItem> ParseStream(Stream stream, Encoding encoding)
        {
            stream.Position = 0;
            List <SubtitleItem> items    = new List <SubtitleItem>();
            Regex         regexTimeCodes = new Regex(@"^\d\d:\d\d:\d\d\.\d\d\d[ \t]+\d\d:\d\d:\d\d\.\d\d\d[ \t]+\d\d:\d\d:\d\d\.\d\d\d[ \t]+");
            StreamReader  st             = new StreamReader(stream, encoding, true);
            string        reshte         = st.ReadToEnd();
            List <string> lines          = new List <string>(reshte.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));

            SubtitleItem lastParagraph = null;
            int          _errorCount   = 0;

            foreach (string line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                string s       = line;
                bool   success = false;

                if (s.Length > 26 && s.IndexOf(':') == 2)
                {
                    var match = regexTimeCodes.Match(s);
                    if (match.Success)
                    {
                        s = s.Substring(0, match.Length);
                        s = s.Replace("\t", ":");
                        s = s.Replace(".", ":");
                        s = s.Replace(" ", string.Empty);
                        s = s.Trim().TrimEnd(':').TrimEnd();
                        string[] parts = s.Split(':');
                        if (parts.Length == 12)
                        {
                            int hours        = int.Parse(parts[0]);
                            int minutes      = int.Parse(parts[1]);
                            int seconds      = int.Parse(parts[2]);
                            int milliseconds = int.Parse(parts[3]);
                            int start        = int.Parse(new TimeSpan(0, hours, minutes, seconds, milliseconds).TotalMilliseconds.ToString());

                            hours        = int.Parse(parts[4]);
                            minutes      = int.Parse(parts[5]);
                            seconds      = int.Parse(parts[6]);
                            milliseconds = int.Parse(parts[7]);
                            int end = int.Parse(new TimeSpan(0, hours, minutes, seconds, milliseconds).TotalMilliseconds.ToString());

                            string text = line.Substring(match.Length).TrimStart();
                            text = text.Replace("|", Environment.NewLine);

                            lastParagraph           = new SubtitleItem();
                            lastParagraph.StartTime = start;
                            lastParagraph.EndTime   = end;
                            lastParagraph.Lines     = new List <string>()
                            {
                                text
                            };
                            items.Add(lastParagraph);
                            success = true;
                        }
                    }
                }
                if (!success)
                {
                    _errorCount++;
                }
            }

            if (items.Any())
            {
                System.Diagnostics.Debug.WriteLine("items count: " + items.Count);
                return(items);
            }
            else
            {
                throw new ArgumentException("Stream is not in a valid 'Sony DVDArchitect Explicit duration' Subtitle format");
            }
        }