diff options
| author | Luis Miguel Almánzar <ruisu15@gmail.com> | 2014-05-11 00:23:16 -0400 |
|---|---|---|
| committer | Luis Miguel Almánzar <ruisu15@gmail.com> | 2014-05-11 00:23:16 -0400 |
| commit | 8a8e272cb70f572079687d0a19bc4a27884c5b95 (patch) | |
| tree | 25212dd1539c9ebc7574d06bda123812843455ff | |
| parent | f2237b858ad4defe47d7671cffdf3febeff3ad00 (diff) | |
implemented SSA Parser
4 files changed, 141 insertions, 3 deletions
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index ca7e58371..093bf34c1 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -1,17 +1,69 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; namespace MediaBrowser.MediaEncoding.Subtitles { public class SsaParser : ISubtitleParser { + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + public SubtitleTrackInfo Parse(Stream stream) { - throw new NotImplementedException(); + var trackInfo = new SubtitleTrackInfo(); + var eventIndex = 1; + using (var reader = new StreamReader(stream)) + { + string line; + while (reader.ReadLine() != "[Events]") + {} + var headers = ParseFieldHeaders(reader.ReadLine()); + + while ((line = reader.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + if(line.StartsWith("[")) + break; + if(string.IsNullOrEmpty(line)) + continue; + var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) }; + eventIndex++; + var sections = line.Substring(10).Split(','); + + subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]); + subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]); + subEvent.Text = string.Join(",", sections.Skip(headers["Text"])); + subEvent.Text = Regex.Replace(subEvent.Text, "\\{(\\\\[\\w]+\\(?([\\w\\d]+,?)+\\)?)+\\}", string.Empty, RegexOptions.IgnoreCase); + subEvent.Text = Regex.Replace(subEvent.Text, @"\\N", "<br />", RegexOptions.IgnoreCase); + + trackInfo.TrackEvents.Add(subEvent); + } + } + return trackInfo; + } + + long GetTicks(string time) + { + TimeSpan span; + return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out span) + ? span.Ticks: 0; + } + + private Dictionary<string,int> ParseFieldHeaders(string line) { + var fields = line.Substring(8).Split(',').Select(x=>x.Trim()).ToList(); + + var result = new Dictionary<string, int> { + {"Start", fields.IndexOf("Start")}, + {"End", fields.IndexOf("End")}, + {"Text", fields.IndexOf("Text")} + }; + return result; } } } diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj index 46f748130..dad3677f2 100644 --- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj +++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj @@ -50,6 +50,7 @@ </Otherwise> </Choose> <ItemGroup> + <Compile Include="MediaEncoding\Subtitles\SsaParserTests.cs" /> <Compile Include="MediaEncoding\Subtitles\SrtParserTests.cs" /> <Compile Include="Providers\MovieDbProviderTests.cs" /> <Compile Include="Resolvers\MovieResolverTests.cs" /> @@ -83,6 +84,9 @@ <None Include="app.config" /> </ItemGroup> <ItemGroup> + <None Include="MediaEncoding\Subtitles\TestSubtitles\data.ssa"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> <None Include="MediaEncoding\Subtitles\TestSubtitles\unit.srt"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs new file mode 100644 index 000000000..51dc7f959 --- /dev/null +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; +using MediaBrowser.MediaEncoding.Subtitles; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MediaBrowser.Tests.MediaEncoding.Subtitles { + + [TestClass] + public class SsaParserTests { + + [TestMethod] + public void TestParse() { + + var expectedSubs = + new SubtitleTrackInfo { + TrackEvents = new List<SubtitleTrackEvent> { + new SubtitleTrackEvent { + Id = "1", + StartPositionTicks = 24000000, + EndPositionTicks = 72000000, + Text = + "Senator, we're <br />making our final <br />approach into Coruscant." + }, + new SubtitleTrackEvent { + Id = "2", + StartPositionTicks = 97100000, + EndPositionTicks = 133900000, + Text = + "Very good, Lieutenant." + }, + new SubtitleTrackEvent { + Id = "3", + StartPositionTicks = 150400000, + EndPositionTicks = 180400000, + Text = "It's <br />a <br />trap!" + } + } + }; + + var sut = new SsaParser(); + + var stream = File.OpenRead(@"MediaEncoding\Subtitles\TestSubtitles\data.ssa"); + + var result = sut.Parse(stream); + + Assert.IsNotNull(result); + Assert.AreEqual(expectedSubs.TrackEvents.Count,result.TrackEvents.Count); + for (int i = 0; i < expectedSubs.TrackEvents.Count; i++) + { + Assert.AreEqual(expectedSubs.TrackEvents[i].Id, result.TrackEvents[i].Id); + Assert.AreEqual(expectedSubs.TrackEvents[i].StartPositionTicks, result.TrackEvents[i].StartPositionTicks); + Assert.AreEqual(expectedSubs.TrackEvents[i].EndPositionTicks, result.TrackEvents[i].EndPositionTicks); + Assert.AreEqual(expectedSubs.TrackEvents[i].Text, result.TrackEvents[i].Text); + } + + } + } +}
\ No newline at end of file diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa new file mode 100644 index 000000000..3114a844a --- /dev/null +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa @@ -0,0 +1,23 @@ +[Script Info] +Title: Testing subtitles for the SSA Format + +[V4 Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding +Style: Default,Arial,20,65535,65535,65535,-2147483640,-1,0,1,3,0,2,30,30,30,0,0 +Style: Titre_episode,Akbar,140,15724527,65535,65535,986895,-1,0,1,1,0,3,30,30,30,0,0 +Style: Wolf main,Wolf_Rain,56,15724527,15724527,15724527,4144959,0,0,1,1,2,2,5,5,30,0,0 + + + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: 0,0:00:02.40,0:00:07.20,Default,,0000,0000,0000,,Senator, {\kf89}we're \Nmaking our final \napproach into Coruscant. +Dialogue: 0,0:00:09.71,0:00:13.39,Default,,0000,0000,0000,,{\pos(400,570)}Very good, Lieutenant. +Dialogue: 0,0:00:15.04,0:00:18.04,Default,,0000,0000,0000,,It's \Na \ntrap! + + +[Pictures] +This section will be ignored + +[Fonts] +This section will be ignored
\ No newline at end of file |
