LrcLyricProvider.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Globalization;
  5. using System.Linq;
  6. using LrcParser.Model;
  7. using LrcParser.Parser;
  8. using MediaBrowser.Controller.Entities;
  9. using MediaBrowser.Controller.Lyrics;
  10. namespace MediaBrowser.Providers.Lyric;
  11. /// <summary>
  12. /// LRC Lyric Provider.
  13. /// </summary>
  14. public class LrcLyricProvider : ILyricProvider
  15. {
  16. /// <inheritdoc />
  17. public string Name { get; } = "LrcLyricProvider";
  18. /// <inheritdoc />
  19. public IEnumerable<string> SupportedMediaTypes
  20. {
  21. get => new Collection<string>
  22. {
  23. "lrc"
  24. };
  25. }
  26. /// <summary>
  27. /// Opens lyric file for the requested item, and processes it for API return.
  28. /// </summary>
  29. /// <param name="item">The item to to process.</param>
  30. /// <returns>If provider can determine lyrics, returns a <see cref="LyricResponse"/> with or without metadata; otherwise, null.</returns>
  31. public LyricResponse? GetLyrics(BaseItem item)
  32. {
  33. string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
  34. if (string.IsNullOrEmpty(lyricFilePath))
  35. {
  36. return null;
  37. }
  38. List<Controller.Lyrics.Lyric> lyricList = new List<Controller.Lyrics.Lyric>();
  39. List<LrcParser.Model.Lyric> sortedLyricData = new List<LrcParser.Model.Lyric>();
  40. IDictionary<string, string> metaData = new Dictionary<string, string>();
  41. string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath);
  42. try
  43. {
  44. // Parse and sort lyric rows
  45. LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser();
  46. Song lyricData = lrcLyricParser.Decode(lrcFileContent);
  47. sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.First().Value).ToList();
  48. // Parse metadata rows
  49. var metaDataRows = lyricData.Lyrics
  50. .Where(x => x.TimeTags.Count == 0)
  51. .Where(x => x.Text.StartsWith('[') && x.Text.EndsWith(']'))
  52. .Select(x => x.Text)
  53. .ToList();
  54. foreach (string metaDataRow in metaDataRows)
  55. {
  56. var metaDataField = metaDataRow.Split(':');
  57. if (metaDataField.Length != 2)
  58. {
  59. continue;
  60. }
  61. string metaDataFieldName = metaDataField[0][1..].Trim();
  62. string metaDataFieldValue = metaDataField[1][..^1].Trim();
  63. metaData.Add(metaDataFieldName, metaDataFieldValue);
  64. }
  65. }
  66. catch
  67. {
  68. return null;
  69. }
  70. if (sortedLyricData.Count == 0)
  71. {
  72. return null;
  73. }
  74. for (int i = 0; i < sortedLyricData.Count; i++)
  75. {
  76. var timeData = sortedLyricData[i].TimeTags.First().Value;
  77. if (timeData is null)
  78. {
  79. continue;
  80. }
  81. long ticks = TimeSpan.FromMilliseconds((double)timeData).Ticks;
  82. lyricList.Add(new Controller.Lyrics.Lyric(sortedLyricData[i].Text, ticks));
  83. }
  84. if (metaData.Any())
  85. {
  86. return new LyricResponse { Metadata = metaData, Lyrics = lyricList };
  87. }
  88. return new LyricResponse { Lyrics = lyricList };
  89. }
  90. }