Skip to content

Commit

Permalink
Merge pull request #122 from andy840119/throw-exception-if-lec-format…
Browse files Browse the repository at this point in the history
…-is-illegal

Add try-catch to deal with illegal format.
  • Loading branch information
andy840119 authored Jun 26, 2020
2 parents 9c30aa0 + 284ae1a commit c53acc9
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 41 deletions.
59 changes: 40 additions & 19 deletions osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) andy840119 <[email protected]>. 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;
Expand All @@ -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<LyricLine>().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<FormatException>(() => 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<FormatException>(() => 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<LyricLine>().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);
}
}
}
Expand Down
58 changes: 36 additions & 22 deletions osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,50 @@ 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;
// 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;

return new TimeTagIndex(index, state);
}, v => (double)v.Time),
RubyTags = result.QueryRubies(lyric).Select(ruby => new RubyTag
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);
}
}
}
}
Expand Down

0 comments on commit c53acc9

Please sign in to comment.