diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/UserLibraryController.cs | 49 | ||||
| -rw-r--r-- | Jellyfin.Api/Helpers/ItemHelper.cs | 87 | ||||
| -rw-r--r-- | Jellyfin.Api/Jellyfin.Api.csproj | 12 | ||||
| -rw-r--r-- | Jellyfin.Api/Libraries/LrcParser.dll | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 |
6 files changed, 173 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore index c2ae76c1e..3f80ffcf7 100644 --- a/.gitignore +++ b/.gitignore @@ -281,3 +281,5 @@ apiclient/generated # Omnisharp crash logs mono_crash.*.json + +!LrcParser.dll
\ No newline at end of file diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index e45f9b58c..89fb56744 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -1,14 +1,18 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data.Enums; using Jellyfin.Extensions; +using Kfstorm.LrcParser; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -381,5 +385,50 @@ namespace Jellyfin.Api.Controllers return _userDataRepository.GetUserDataDto(item, user); } + + /// <summary> + /// Gets an item's lyrics. + /// </summary> + /// <param name="userId">User id.</param> + /// <param name="itemId">Item id.</param> + /// <response code="200">Lyrics returned.</response> + /// <response code="404">Something went wrong. No Lyrics will be returned.</response> + /// <returns>An <see cref="OkResult"/> containing the intros to play.</returns> + [HttpGet("Users/{userId}/Items/{itemId}/Lyrics")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<QueryResult<BaseItemDto>> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) + { + var user = _userManager.GetUserById(userId); + + if (user == null) + { + List<Lyrics> lyricsList = new List<Lyrics> + { + new Lyrics { Error = "User Not Found" } + }; + return NotFound(new { Results = lyricsList.ToArray() }); + } + + var item = itemId.Equals(default) + ? _libraryManager.GetUserRootFolder() + : _libraryManager.GetItemById(itemId); + + if (item == null) + { + List<Lyrics> lyricsList = new List<Lyrics> + { + new Lyrics { Error = "Requested Item Not Found" } + }; + return NotFound(new { Results = lyricsList.ToArray() }); + } + + List<Lyrics> result = ItemHelper.GetLyricData(item); + if (string.IsNullOrEmpty(result.ElementAt(0).Error)) + { + return Ok(new { Results = result }); + } + + return NotFound(new { Results = result.ToArray() }); + } } } diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs new file mode 100644 index 000000000..43ef7aa09 --- /dev/null +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Jellyfin.Api.Models.UserDtos; +using Kfstorm.LrcParser; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Devices; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Helpers +{ + /// <summary> + /// Item helper. + /// </summary> + public static class ItemHelper + { + /// <summary> + /// Opens lyrics file, converts to a List of Lyrics, and returns it. + /// </summary> + /// <param name="item">Requested Item.</param> + /// <returns>Collection of Lyrics.</returns> + internal static List<Lyrics> GetLyricData(BaseItem item) + { + List<Lyrics> lyricsList = new List<Lyrics>(); + + string lrcFilePath = @Path.ChangeExtension(item.Path, "lrc"); + + // LRC File not found, fallback to TXT file + if (!System.IO.File.Exists(lrcFilePath)) + { + string txtFilePath = @Path.ChangeExtension(item.Path, "txt"); + if (!System.IO.File.Exists(txtFilePath)) + { + lyricsList.Add(new Lyrics { Error = "Lyric File Not Found" }); + return lyricsList; + } + + var lyricTextData = System.IO.File.ReadAllText(txtFilePath); + string[] lyricTextLines = lyricTextData.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + foreach (var lyricLine in lyricTextLines) + { + lyricsList.Add(new Lyrics { Text = lyricLine }); + } + + return lyricsList; + } + + // Process LRC File + ILrcFile lyricData; + string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath); + try + { + lrcFileContent = lrcFileContent.Replace('<', '['); + lrcFileContent = lrcFileContent.Replace('>', ']'); + lyricData = Kfstorm.LrcParser.LrcFile.FromText(lrcFileContent); + } + catch + { + lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); + return lyricsList; + } + + if (lyricData == null) + { + lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); + return lyricsList; + } + + foreach (var lyricLine in lyricData.Lyrics) + { + double ticks = lyricLine.Timestamp.TotalSeconds * 10000000; + lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = lyricLine.Content }); + } + + return lyricsList; + } + } +} diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 894d87138..1b78bb107 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -46,4 +46,16 @@ </AssemblyAttribute> </ItemGroup> + <ItemGroup> + <Reference Include="LrcParser"> + <HintPath>Libraries\LrcParser.dll</HintPath> + </Reference> + </ItemGroup> + + <ItemGroup> + <None Update="Libraries\LrcParser.dll"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + </ItemGroup> + </Project> diff --git a/Jellyfin.Api/Libraries/LrcParser.dll b/Jellyfin.Api/Libraries/LrcParser.dll Binary files differnew file mode 100644 index 000000000..46e4fb703 --- /dev/null +++ b/Jellyfin.Api/Libraries/LrcParser.dll diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs new file mode 100644 index 000000000..df1b5d08a --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/Lyrics.cs @@ -0,0 +1,23 @@ +namespace Jellyfin.Api.Models.UserDtos +{ + /// <summary> + /// Lyric dto. + /// </summary> + public class Lyrics + { + /// <summary> + /// Gets or sets the start. + /// </summary> + public double? Start { get; set; } + + /// <summary> + /// Gets or sets the test. + /// </summary> + public string? Text { get; set; } + + /// <summary> + /// Gets or sets the error. + /// </summary> + public string? Error { get; set; } + } +} |
