aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs49
-rw-r--r--Jellyfin.Api/Helpers/ItemHelper.cs87
-rw-r--r--Jellyfin.Api/Jellyfin.Api.csproj12
-rw-r--r--Jellyfin.Api/Libraries/LrcParser.dllbin0 -> 12288 bytes
-rw-r--r--Jellyfin.Api/Models/UserDtos/Lyrics.cs23
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
new file mode 100644
index 000000000..46e4fb703
--- /dev/null
+++ b/Jellyfin.Api/Libraries/LrcParser.dll
Binary files differ
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; }
+ }
+}