|
@@ -2,6 +2,7 @@ using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq;
|
|
|
|
+using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Text.RegularExpressions;
|
|
using Jellyfin.Extensions;
|
|
using Jellyfin.Extensions;
|
|
using LrcParser.Model;
|
|
using LrcParser.Model;
|
|
@@ -66,47 +67,56 @@ public partial class LrcLyricParser : ILyricParser
|
|
}
|
|
}
|
|
|
|
|
|
List<LyricLine> lyricList = [];
|
|
List<LyricLine> lyricList = [];
|
|
- for (var l = 0; l < sortedLyricData.Count; l++)
|
|
|
|
|
|
+ for (var lineIndex = 0; lineIndex < sortedLyricData.Count; lineIndex++)
|
|
{
|
|
{
|
|
- var cues = new List<LyricLineCue>();
|
|
|
|
- var lyric = sortedLyricData[l];
|
|
|
|
|
|
+ var lyric = sortedLyricData[lineIndex];
|
|
|
|
|
|
- if (lyric.TimeTags.Count != 0)
|
|
|
|
|
|
+ // Extract cues from time tags
|
|
|
|
+ var cues = new List<LyricLineCue>();
|
|
|
|
+ if (lyric.TimeTags.Count > 0)
|
|
{
|
|
{
|
|
var keys = lyric.TimeTags.Keys.ToList();
|
|
var keys = lyric.TimeTags.Keys.ToList();
|
|
- int current = 0, next = 1;
|
|
|
|
- while (next < keys.Count)
|
|
|
|
|
|
+ for (var tagIndex = 0; tagIndex < keys.Count - 1; tagIndex++)
|
|
{
|
|
{
|
|
- var currentKey = keys[current];
|
|
|
|
- var currentMs = lyric.TimeTags[currentKey] ?? 0;
|
|
|
|
- var nextMs = lyric.TimeTags[keys[next]] ?? 0;
|
|
|
|
-
|
|
|
|
- cues.Add(new LyricLineCue(
|
|
|
|
- position: Math.Max(currentKey.Index, 0),
|
|
|
|
- start: TimeSpan.FromMilliseconds(currentMs).Ticks,
|
|
|
|
- end: TimeSpan.FromMilliseconds(nextMs).Ticks));
|
|
|
|
|
|
+ var currentKey = keys[tagIndex];
|
|
|
|
+ var nextKey = keys[tagIndex + 1];
|
|
|
|
|
|
- current++;
|
|
|
|
- next++;
|
|
|
|
|
|
+ var currentPos = currentKey.State == IndexState.End ? currentKey.Index + 1 : currentKey.Index;
|
|
|
|
+ var nextPos = nextKey.State == IndexState.End ? nextKey.Index + 1 : nextKey.Index;
|
|
|
|
+ var currentMs = lyric.TimeTags[currentKey] ?? 0;
|
|
|
|
+ var nextMs = lyric.TimeTags[keys[tagIndex + 1]] ?? 0;
|
|
|
|
+ var currentSlice = lyric.Text[currentPos..nextPos];
|
|
|
|
+ var currentSliceTrimmed = currentSlice.Trim();
|
|
|
|
+ if (currentSliceTrimmed.Length > 0)
|
|
|
|
+ {
|
|
|
|
+ cues.Add(new LyricLineCue(
|
|
|
|
+ position: currentPos,
|
|
|
|
+ endPosition: nextPos,
|
|
|
|
+ start: TimeSpan.FromMilliseconds(currentMs).Ticks,
|
|
|
|
+ end: TimeSpan.FromMilliseconds(nextMs).Ticks));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- var lastKey = keys[current];
|
|
|
|
|
|
+ var lastKey = keys[^1];
|
|
|
|
+ var lastPos = lastKey.State == IndexState.End ? lastKey.Index + 1 : lastKey.Index;
|
|
var lastMs = lyric.TimeTags[lastKey] ?? 0;
|
|
var lastMs = lyric.TimeTags[lastKey] ?? 0;
|
|
|
|
+ var lastSlice = lyric.Text[lastPos..];
|
|
|
|
+ var lastSliceTrimmed = lastSlice.Trim();
|
|
|
|
|
|
- cues.Add(new LyricLineCue(
|
|
|
|
- position: Math.Max(lastKey.Index, 0),
|
|
|
|
- start: TimeSpan.FromMilliseconds(lastMs).Ticks,
|
|
|
|
- end: l + 1 < sortedLyricData.Count ? TimeSpan.FromMilliseconds(sortedLyricData[l + 1].StartTime).Ticks : null));
|
|
|
|
|
|
+ if (lastSliceTrimmed.Length > 0)
|
|
|
|
+ {
|
|
|
|
+ cues.Add(new LyricLineCue(
|
|
|
|
+ position: lastPos,
|
|
|
|
+ endPosition: lyric.Text.Length,
|
|
|
|
+ start: TimeSpan.FromMilliseconds(lastMs).Ticks,
|
|
|
|
+ end: lineIndex + 1 < sortedLyricData.Count ? TimeSpan.FromMilliseconds(sortedLyricData[lineIndex + 1].StartTime).Ticks : null));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
long lyricStartTicks = TimeSpan.FromMilliseconds(lyric.StartTime).Ticks;
|
|
long lyricStartTicks = TimeSpan.FromMilliseconds(lyric.StartTime).Ticks;
|
|
- lyricList.Add(new LyricLine(WhitespaceRegex().Replace(lyric.Text.Trim(), " "), lyricStartTicks, cues));
|
|
|
|
|
|
+ lyricList.Add(new LyricLine(lyric.Text, lyricStartTicks, cues));
|
|
}
|
|
}
|
|
|
|
|
|
return new LyricDto { Lyrics = lyricList };
|
|
return new LyricDto { Lyrics = lyricList };
|
|
}
|
|
}
|
|
-
|
|
|
|
- // Replacement is required until https://github.com/karaoke-dev/LrcParser/issues/83 is resolved.
|
|
|
|
- [GeneratedRegex(@"\s+")]
|
|
|
|
- private static partial Regex WhitespaceRegex();
|
|
|
|
}
|
|
}
|