diff options
Diffstat (limited to 'Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs')
| -rw-r--r-- | Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs new file mode 100644 index 000000000..029acd6ca --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// <summary> + /// LRC File Lyric Provider. + /// </summary> + public class LrcLyricsProvider : ILyricsProvider + { + /// <summary> + /// Initializes a new instance of the <see cref="LrcLyricsProvider"/> class. + /// </summary> + public LrcLyricsProvider() + { + FileExtensions = new Collection<string> + { + "lrc" + }; + } + + /// <summary> + /// Gets a value indicating the File Extenstions this provider works with. + /// </summary> + public Collection<string>? FileExtensions { get; } + + /// <summary> + /// Gets or Sets a value indicating whether Process() generated data. + /// </summary> + /// <returns><c>true</c> if data generated; otherwise, <c>false</c>.</returns> + public bool HasData { get; set; } + + /// <summary> + /// Gets or Sets Data object generated by Process() method. + /// </summary> + /// <returns><c>Object</c> with data if no error occured; otherwise, <c>null</c>.</returns> + public object? Data { get; set; } + + /// <summary> + /// Opens lyric file for [the specified item], and processes it for API return. + /// </summary> + /// <param name="item">The item to to process.</param> + public void Process(BaseItem item) + { + string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return; + } + + List<Lyric> lyricsList = new List<Lyric>(); + + List<LrcParser.Model.Lyric> sortedLyricData = new List<LrcParser.Model.Lyric>(); + var metaData = new ExpandoObject() as IDictionary<string, object>; + string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath); + + try + { + // Parse and sort lyric rows + LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); + Song lyricData = lrcLyricParser.Decode(lrcFileContent); + sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); + + // Parse metadata rows + var metaDataRows = lyricData.Lyrics + .Where(x => x.TimeTags.Count == 0) + .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) + .Select(x => x.Text) + .ToList(); + + foreach (string metaDataRow in metaDataRows) + { + var metaDataField = metaDataRow.Split(":"); + + string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal); + string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal); + + metaData.Add(metaDataFieldName, metaDataFieldValue); + } + } + catch + { + return; + } + + if (!sortedLyricData.Any()) + { + return; + } + + for (int i = 0; i < sortedLyricData.Count; i++) + { + var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; + double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; + lyricsList.Add(new Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + } + + this.HasData = true; + if (metaData.Any()) + { + this.Data = new { MetaData = metaData, lyrics = lyricsList }; + } + else + { + this.Data = new { lyrics = lyricsList }; + } + } + } +} |
