From 9ff5fca7ba4cb415d133fc9cf04af2ca802a1887 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Fri, 26 Jun 2020 18:24:07 +0900 Subject: [PATCH 1/2] 1. Add try-catch to deal with illegal format. 2. Add some test. --- .../Beatmaps/Formats/LrcDecoderTest.cs | 59 +++++++++++++------ .../Beatmaps/Formats/LrcDecoder.cs | 59 ++++++++++++------- 2 files changed, 77 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs index 4dd313113..276971d39 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs @@ -1,9 +1,11 @@ // Copyright (c) andy840119 . Licensed under the GPL Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.IO; using System.Linq; using NUnit.Framework; +using osu.Game.Beatmaps; using osu.Game.IO; using osu.Game.Rulesets.Karaoke.Beatmaps.Formats; using osu.Game.Rulesets.Karaoke.Objects; @@ -14,38 +16,57 @@ namespace osu.Game.Rulesets.Karaoke.Tests.Beatmaps.Formats public class LrcDecoderTest { [Test] - public void TestDecodeNote() + public void TestDecodeLyric() { const string lyric_text = "[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]"; + var beatmap = decodeLrcLine(lyric_text); + // Get first beatmap + var lyric = beatmap.HitObjects.OfType().FirstOrDefault(); + + // Check lyric + Assert.AreEqual(lyric?.Text, "からおけ"); + Assert.AreEqual(lyric?.StartTime, 1000); + Assert.AreEqual(lyric?.EndTime, 5000); + + // Check time tag + var tags = lyric?.TimeTags; + var checkedTags = tags.ToArray(); + Assert.AreEqual(tags.Count, 5); + Assert.AreEqual(checkedTags.Length, 5); + Assert.AreEqual(string.Join(',', tags.Select(x => x.Key.Index)), "0,1,2,3,4"); + Assert.AreEqual(string.Join(',', tags.Select(x => x.Value)), "1000,2000,3000,4000,5000"); + } + + [Test] + public void TestDecodeLyricWithDulicatedTimeTag() + { + const string wrong_lyric_text = "[00:04.00]か[00:04.00]ら[00:05.00]お[00:06.00]け[00:07.00]"; + Assert.Throws(() => decodeLrcLine(wrong_lyric_text)); + } + + [Test] + [Ignore("Waiting for lyric parser update.")] + public void TestDecodeLyricWithTimeTagNotOrder() + { + const string wrong_lyric_text = "[00:04.00]か[00:03.00]ら[00:02.00]お[00:01.00]け[00:00.00]"; + Assert.Throws(() => decodeLrcLine(wrong_lyric_text)); + } + + private Beatmap decodeLrcLine(string line) + { using (var stream = new MemoryStream()) using (var writer = new StreamWriter(stream)) using (var reader = new LineBufferedReader(stream)) { // Create stream - writer.Write(lyric_text); + writer.Write(line); writer.Flush(); stream.Position = 0; // Create karaoke note decoder var decoder = new LrcDecoder(); - var beatmap = decoder.Decode(reader); - - // Get first beatmap - var lyric = beatmap.HitObjects.OfType().FirstOrDefault(); - - // Check lyric - Assert.AreEqual(lyric?.Text, "からおけ"); - Assert.AreEqual(lyric?.StartTime, 1000); - Assert.AreEqual(lyric?.EndTime, 5000); - - // Check time tag - var tags = lyric?.TimeTags; - var checkedTags = tags.ToArray(); - Assert.AreEqual(tags.Count, 5); - Assert.AreEqual(checkedTags.Length, 5); - Assert.AreEqual(string.Join(',', tags.Select(x => x.Key.Index)), "0,1,2,3,4"); - Assert.AreEqual(string.Join(',', tags.Select(x => x.Value)), "1000,2000,3000,4000,5000"); + return decoder.Decode(reader); } } } diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs index 70ca12bfa..e037c9b98 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs @@ -30,36 +30,51 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu var result = new LrcParser().Decode(lyricText); // Convert line - foreach (var line in result.Lines) + for(int i=0;i < result.Lines.Length; i++) { // Empty line should not be imported + var line = result.Lines[i]; if (string.IsNullOrEmpty(line.Text)) continue; - var startTime = line.TimeTags.FirstOrDefault(x => x.Time > 0).Time; - var duration = line.TimeTags.LastOrDefault(x => x.Time > 0).Time - startTime; - - var lyric = line.Text; - output.HitObjects.Add(new LyricLine + try { - Text = lyric, - // Start time and end time should be re-assigned - StartTime = startTime, - Duration = duration, - TimeTags = line.TimeTags.Where(x => x.Check).ToDictionary(k => - { - var index = (int)Math.Ceiling((double)(Array.IndexOf(line.TimeTags, k) - 1) / 2); - var state = (Array.IndexOf(line.TimeTags, k) - 1) % 2 == 0 ? TimeTagIndex.IndexState.Start : TimeTagIndex.IndexState.End; - return new TimeTagIndex(index, state); - }, v => (double)v.Time), - RubyTags = result.QueryRubies(lyric).Select(ruby => new RubyTag + // todo : check list ls sorted by time. + var timetags = line.TimeTags; + + var startTime = timetags.FirstOrDefault(x => x.Time > 0).Time; + var duration = timetags.LastOrDefault(x => x.Time > 0).Time - startTime; + + var lyric = line.Text; + output.HitObjects.Add(new LyricLine { - Text = ruby.Ruby.Ruby, - StartIndex = ruby.StartIndex, - EndIndex = ruby.EndIndex - }).ToArray() - }); + Text = lyric, + // Start time and end time should be re-assigned + StartTime = startTime, + Duration = duration, + TimeTags = timetags.Where(x => x.Check).ToDictionary(k => + { + var index = (int)Math.Ceiling((double)(Array.IndexOf(timetags, k) - 1) / 2); + var state = (Array.IndexOf(timetags, k) - 1) % 2 == 0 ? TimeTagIndex.IndexState.Start : TimeTagIndex.IndexState.End; + + return new TimeTagIndex(index, state); + }, v => (double)v.Time), + RubyTags = result.QueryRubies(lyric).Select(ruby => new RubyTag + { + Text = ruby.Ruby.Ruby, + StartIndex = ruby.StartIndex, + EndIndex = ruby.EndIndex + }).ToArray() + }); + } + catch (Exception ex) + { + var message = $"Parsing lyric '{line.Text}' got error in line:{i}" + + $"Please check time tag should be ordered and not duplicated." + + $"Then re-import again."; + throw new FormatException(message, ex); + } } } } From 284ae1a21d34036a34221d836695718b463fa934 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Fri, 26 Jun 2020 18:27:59 +0900 Subject: [PATCH 2/2] Clean-up code. --- .../Beatmaps/Formats/LrcDecoder.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs index e037c9b98..2f269d9f5 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs @@ -30,7 +30,7 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu var result = new LrcParser().Decode(lyricText); // Convert line - for(int i=0;i < result.Lines.Length; i++) + for (int i = 0; i < result.Lines.Length; i++) { // Empty line should not be imported var line = result.Lines[i]; @@ -39,12 +39,11 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu try { - // todo : check list ls sorted by time. - var timetags = line.TimeTags; + var timeTags = line.TimeTags; - var startTime = timetags.FirstOrDefault(x => x.Time > 0).Time; - var duration = timetags.LastOrDefault(x => x.Time > 0).Time - startTime; + var startTime = timeTags.FirstOrDefault(x => x.Time > 0).Time; + var duration = timeTags.LastOrDefault(x => x.Time > 0).Time - startTime; var lyric = line.Text; output.HitObjects.Add(new LyricLine @@ -53,10 +52,10 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu // Start time and end time should be re-assigned StartTime = startTime, Duration = duration, - TimeTags = timetags.Where(x => x.Check).ToDictionary(k => + TimeTags = timeTags.Where(x => x.Check).ToDictionary(k => { - var index = (int)Math.Ceiling((double)(Array.IndexOf(timetags, k) - 1) / 2); - var state = (Array.IndexOf(timetags, k) - 1) % 2 == 0 ? TimeTagIndex.IndexState.Start : TimeTagIndex.IndexState.End; + var index = (int)Math.Ceiling((double)(Array.IndexOf(timeTags, k) - 1) / 2); + var state = (Array.IndexOf(timeTags, k) - 1) % 2 == 0 ? TimeTagIndex.IndexState.Start : TimeTagIndex.IndexState.End; return new TimeTagIndex(index, state); }, v => (double)v.Time), @@ -71,8 +70,8 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu catch (Exception ex) { var message = $"Parsing lyric '{line.Text}' got error in line:{i}" + - $"Please check time tag should be ordered and not duplicated." + - $"Then re-import again."; + "Please check time tag should be ordered and not duplicated." + + "Then re-import again."; throw new FormatException(message, ex); } }