From 5f5347aee3209383248a6055318ec8883291d406 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 9 Sep 2022 20:14:23 -0400
Subject: Add Lyrics API Endpoint
---
.gitignore | 2 +
Jellyfin.Api/Controllers/UserLibraryController.cs | 49 ++++++++++++
Jellyfin.Api/Helpers/ItemHelper.cs | 87 ++++++++++++++++++++++
Jellyfin.Api/Jellyfin.Api.csproj | 12 +++
Jellyfin.Api/Libraries/LrcParser.dll | Bin 0 -> 12288 bytes
Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 ++++++
6 files changed, 173 insertions(+)
create mode 100644 Jellyfin.Api/Helpers/ItemHelper.cs
create mode 100644 Jellyfin.Api/Libraries/LrcParser.dll
create mode 100644 Jellyfin.Api/Models/UserDtos/Lyrics.cs
diff --git a/.gitignore b/.gitignore
index c2ae76c1e3..3f80ffcf7d 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 e45f9b58cd..89fb56744c 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);
}
+
+ ///
+ /// Gets an item's lyrics.
+ ///
+ /// User id.
+ /// Item id.
+ /// Lyrics returned.
+ /// Something went wrong. No Lyrics will be returned.
+ /// An containing the intros to play.
+ [HttpGet("Users/{userId}/Items/{itemId}/Lyrics")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
+ {
+ var user = _userManager.GetUserById(userId);
+
+ if (user == null)
+ {
+ List lyricsList = new List
+ {
+ 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 lyricsList = new List
+ {
+ new Lyrics { Error = "Requested Item Not Found" }
+ };
+ return NotFound(new { Results = lyricsList.ToArray() });
+ }
+
+ List 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 0000000000..43ef7aa093
--- /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
+{
+ ///
+ /// Item helper.
+ ///
+ public static class ItemHelper
+ {
+ ///
+ /// Opens lyrics file, converts to a List of Lyrics, and returns it.
+ ///
+ /// Requested Item.
+ /// Collection of Lyrics.
+ internal static List GetLyricData(BaseItem item)
+ {
+ List lyricsList = new List();
+
+ 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 894d871383..1b78bb1074 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -46,4 +46,16 @@
+
+
+ Libraries\LrcParser.dll
+
+
+
+
+
+ Always
+
+
+
diff --git a/Jellyfin.Api/Libraries/LrcParser.dll b/Jellyfin.Api/Libraries/LrcParser.dll
new file mode 100644
index 0000000000..46e4fb7033
Binary files /dev/null and b/Jellyfin.Api/Libraries/LrcParser.dll differ
diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs
new file mode 100644
index 0000000000..df1b5d08a2
--- /dev/null
+++ b/Jellyfin.Api/Models/UserDtos/Lyrics.cs
@@ -0,0 +1,23 @@
+namespace Jellyfin.Api.Models.UserDtos
+{
+ ///
+ /// Lyric dto.
+ ///
+ public class Lyrics
+ {
+ ///
+ /// Gets or sets the start.
+ ///
+ public double? Start { get; set; }
+
+ ///
+ /// Gets or sets the test.
+ ///
+ public string? Text { get; set; }
+
+ ///
+ /// Gets or sets the error.
+ ///
+ public string? Error { get; set; }
+ }
+}
--
cgit v1.2.3
From 8b78802c0b42d9d55f5bd8c3f34a542d78903f75 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 9 Sep 2022 21:08:38 -0400
Subject: Update Jellyfin.Api/Controllers/UserLibraryController.cs
Co-authored-by: Cody Robibero
---
Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 89fb56744c..42367940d3 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -402,11 +402,7 @@ namespace Jellyfin.Api.Controllers
if (user == null)
{
- List lyricsList = new List
- {
- new Lyrics { Error = "User Not Found" }
- };
- return NotFound(new { Results = lyricsList.ToArray() });
+ return NotFound();
}
var item = itemId.Equals(default)
--
cgit v1.2.3
From 92715a74262fbf52f7071b45f5b61b7f057bb28e Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 9 Sep 2022 21:09:39 -0400
Subject: Update Jellyfin.Api/Controllers/UserLibraryController.cs
Co-authored-by: Cody Robibero
---
Jellyfin.Api/Controllers/UserLibraryController.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 42367940d3..a1b911a450 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -424,7 +424,7 @@ namespace Jellyfin.Api.Controllers
return Ok(new { Results = result });
}
- return NotFound(new { Results = result.ToArray() });
+ return NotFound();
}
}
}
--
cgit v1.2.3
From 0aa2780ea7b23aed31765550f707f7ea9fc0daf1 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 9 Sep 2022 21:15:57 -0400
Subject: Update Jellyfin.Api/Controllers/UserLibraryController.cs
Co-authored-by: Cody Robibero
---
Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index a1b911a450..7830df9bc9 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -411,11 +411,7 @@ namespace Jellyfin.Api.Controllers
if (item == null)
{
- List lyricsList = new List
- {
- new Lyrics { Error = "Requested Item Not Found" }
- };
- return NotFound(new { Results = lyricsList.ToArray() });
+ return NotFound();
}
List result = ItemHelper.GetLyricData(item);
--
cgit v1.2.3
From d24444b6d3a2e973d50edc2a8a1d01a433db645e Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 10 Sep 2022 10:51:05 -0400
Subject: Update Jellyfin.Api/Models/UserDtos/Lyrics.cs
Co-authored-by: Neil Burrows
---
Jellyfin.Api/Models/UserDtos/Lyrics.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs
index df1b5d08a2..cd548eb037 100644
--- a/Jellyfin.Api/Models/UserDtos/Lyrics.cs
+++ b/Jellyfin.Api/Models/UserDtos/Lyrics.cs
@@ -11,7 +11,7 @@ namespace Jellyfin.Api.Models.UserDtos
public double? Start { get; set; }
///
- /// Gets or sets the test.
+ /// Gets or sets the text.
///
public string? Text { get; set; }
--
cgit v1.2.3
From 2e260e5319b0b58290a1e30a28886c69d5a65325 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 10 Sep 2022 14:29:30 -0400
Subject: Updates based on review
---
Jellyfin.Api/Controllers/UserLibraryController.cs | 9 ++-
Jellyfin.Api/Helpers/ItemHelper.cs | 68 +++++++++++++---------
Jellyfin.Api/Jellyfin.Api.csproj | 13 +----
Jellyfin.Api/Libraries/LrcParser.dll | Bin 12288 -> 0 bytes
4 files changed, 46 insertions(+), 44 deletions(-)
delete mode 100644 Jellyfin.Api/Libraries/LrcParser.dll
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 89fb56744c..afd4013ed3 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -12,7 +12,6 @@ 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;
@@ -422,13 +421,13 @@ namespace Jellyfin.Api.Controllers
return NotFound(new { Results = lyricsList.ToArray() });
}
- List result = ItemHelper.GetLyricData(item);
- if (string.IsNullOrEmpty(result.ElementAt(0).Error))
+ var result = ItemHelper.GetLyricData(item);
+ if (result is not null)
{
- return Ok(new { Results = result });
+ return Ok(result);
}
- return NotFound(new { Results = result.ToArray() });
+ return NotFound();
}
}
}
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
index 43ef7aa093..c1b5ea6ccc 100644
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ b/Jellyfin.Api/Helpers/ItemHelper.cs
@@ -1,19 +1,13 @@
using System;
using System.Collections.Generic;
+using System.Dynamic;
+using System.Globalization;
using System.IO;
-using System.Net.Http;
-using System.Threading.Tasks;
+using System.Linq;
using Jellyfin.Api.Models.UserDtos;
-using Kfstorm.LrcParser;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
+using LrcParser.Model;
+using LrcParser.Parser;
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
{
@@ -27,7 +21,7 @@ namespace Jellyfin.Api.Helpers
///
/// Requested Item.
/// Collection of Lyrics.
- internal static List GetLyricData(BaseItem item)
+ internal static object? GetLyricData(BaseItem item)
{
List lyricsList = new List();
@@ -39,8 +33,7 @@ namespace Jellyfin.Api.Helpers
string txtFilePath = @Path.ChangeExtension(item.Path, "txt");
if (!System.IO.File.Exists(txtFilePath))
{
- lyricsList.Add(new Lyrics { Error = "Lyric File Not Found" });
- return lyricsList;
+ return null;
}
var lyricTextData = System.IO.File.ReadAllText(txtFilePath);
@@ -51,37 +44,58 @@ namespace Jellyfin.Api.Helpers
lyricsList.Add(new Lyrics { Text = lyricLine });
}
- return lyricsList;
+ return new { lyrics = lyricsList };
}
// Process LRC File
- ILrcFile lyricData;
+ Song lyricData;
+ List sortedLyricData = new List();
+ var metaData = new ExpandoObject() as IDictionary;
string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath);
+
try
{
- lrcFileContent = lrcFileContent.Replace('<', '[');
- lrcFileContent = lrcFileContent.Replace('>', ']');
- lyricData = Kfstorm.LrcParser.LrcFile.FromText(lrcFileContent);
+ LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser();
+ lyricData = lrcLyricParser.Decode(lrcFileContent);
+ var _metaData = 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 dataRow in _metaData)
+ {
+ var data = dataRow.Split(":");
+
+ string newPropertyName = data[0].Replace("[", string.Empty, StringComparison.Ordinal);
+ string newPropertyValue = data[1].Replace("]", string.Empty, StringComparison.Ordinal);
+
+ metaData.Add(newPropertyName, newPropertyValue);
+ }
+
+ sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList();
}
catch
{
- lyricsList.Add(new Lyrics { Error = "No Lyrics Data" });
- return lyricsList;
+ return null;
}
if (lyricData == null)
{
- lyricsList.Add(new Lyrics { Error = "No Lyrics Data" });
- return lyricsList;
+ return null;
}
- foreach (var lyricLine in lyricData.Lyrics)
+ for (int i = 0; i < sortedLyricData.Count; i++)
{
- double ticks = lyricLine.Timestamp.TotalSeconds * 10000000;
- lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = lyricLine.Content });
+ if (sortedLyricData[i].TimeTags.Count > 0)
+ {
+ var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
+ double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000;
+ lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ }
}
- return lyricsList;
+ return new { MetaData = metaData, lyrics = lyricsList };
}
}
}
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index 1b78bb1074..972387e02a 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -17,6 +17,7 @@
+
@@ -46,16 +47,4 @@
-
-
- Libraries\LrcParser.dll
-
-
-
-
-
- Always
-
-
-
diff --git a/Jellyfin.Api/Libraries/LrcParser.dll b/Jellyfin.Api/Libraries/LrcParser.dll
deleted file mode 100644
index 46e4fb7033..0000000000
Binary files a/Jellyfin.Api/Libraries/LrcParser.dll and /dev/null differ
--
cgit v1.2.3
From 9d5cf67dfe2d5871d42a55a5e114c5ead1036ff0 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 10 Sep 2022 14:58:03 -0400
Subject: Create ILyricsProvider
---
Emby.Server.Implementations/Dto/DtoService.cs | 5 +
Jellyfin.Api/Helpers/ItemHelper.cs | 117 +++++++++++++---------
Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs | 34 +++++++
Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs | 117 ++++++++++++++++++++++
Jellyfin.Api/Models/UserDtos/Lyric.cs | 18 ++++
Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 -----
Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs | 81 +++++++++++++++
MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +
8 files changed, 325 insertions(+), 72 deletions(-)
create mode 100644 Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
create mode 100644 Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs
create mode 100644 Jellyfin.Api/Models/UserDtos/Lyric.cs
delete mode 100644 Jellyfin.Api/Models/UserDtos/Lyrics.cs
create mode 100644 Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 09ba368514..96717cff53 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using Jellyfin.Api.Helpers;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
@@ -139,6 +140,10 @@ namespace Emby.Server.Implementations.Dto
{
LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult();
}
+ else if (item is Audio)
+ {
+ dto.HasLocalLyricsFile = ItemHelper.HasLyricFile(item.Path);
+ }
if (item is IItemByName itemByName
&& options.ContainsField(ItemFields.ItemCounts))
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
index c1b5ea6ccc..622eb0b9fe 100644
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ b/Jellyfin.Api/Helpers/ItemHelper.cs
@@ -23,79 +23,98 @@ namespace Jellyfin.Api.Helpers
/// Collection of Lyrics.
internal static object? GetLyricData(BaseItem item)
{
- List lyricsList = new List();
+ List providerList = new List();
- string lrcFilePath = @Path.ChangeExtension(item.Path, "lrc");
+ // Find all classes that implement ILyricsProvider Interface
+ var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
+ .GetTypes()
+ .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface);
- // LRC File not found, fallback to TXT file
- if (!System.IO.File.Exists(lrcFilePath))
+ if (!foundLyricProviders.Any())
{
- string txtFilePath = @Path.ChangeExtension(item.Path, "txt");
- if (!System.IO.File.Exists(txtFilePath))
- {
- return null;
- }
+ return null;
+ }
- var lyricTextData = System.IO.File.ReadAllText(txtFilePath);
- string[] lyricTextLines = lyricTextData.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var provider in foundLyricProviders)
+ {
+ providerList.Add((ILyricsProvider)Activator.CreateInstance(provider));
+ }
- foreach (var lyricLine in lyricTextLines)
+ foreach (ILyricsProvider provider in providerList)
+ {
+ provider.Process(item);
+ if (provider.HasData)
{
- lyricsList.Add(new Lyrics { Text = lyricLine });
+ return provider.Data;
}
-
- return new { lyrics = lyricsList };
}
- // Process LRC File
- Song lyricData;
- List sortedLyricData = new List();
- var metaData = new ExpandoObject() as IDictionary;
- string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath);
-
- try
- {
- LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser();
- lyricData = lrcLyricParser.Decode(lrcFileContent);
- var _metaData = 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 dataRow in _metaData)
- {
- var data = dataRow.Split(":");
+ return null;
+ }
- string newPropertyName = data[0].Replace("[", string.Empty, StringComparison.Ordinal);
- string newPropertyValue = data[1].Replace("]", string.Empty, StringComparison.Ordinal);
+ ///
+ /// Checks if requested item has a matching lyric file.
+ ///
+ /// Path of requested item.
+ /// True if item has a matching lyrics file.
+ public static string? GetLyricFilePath(string itemPath)
+ {
+ List supportedLyricFileExtensions = new List();
- metaData.Add(newPropertyName, newPropertyValue);
- }
+ // Find all classes that implement ILyricsProvider Interface
+ var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
+ .GetTypes()
+ .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface);
- sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList();
- }
- catch
+ if (!foundLyricProviders.Any())
{
return null;
}
- if (lyricData == null)
+ // Iterate over all found lyric providers
+ foreach (var provider in foundLyricProviders)
{
- return null;
+ var foundProvider = (ILyricsProvider)Activator.CreateInstance(provider);
+ if (foundProvider?.FileExtensions is null)
+ {
+ continue;
+ }
+
+ if (foundProvider.FileExtensions.Any())
+ {
+ // Gather distinct list of handled file extentions
+ foreach (string lyricFileExtension in foundProvider.FileExtensions)
+ {
+ if (!supportedLyricFileExtensions.Contains(lyricFileExtension))
+ {
+ supportedLyricFileExtensions.Add(lyricFileExtension);
+ }
+ }
+ }
}
- for (int i = 0; i < sortedLyricData.Count; i++)
+ foreach (string lyricFileExtension in supportedLyricFileExtensions)
{
- if (sortedLyricData[i].TimeTags.Count > 0)
+ string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
+ if (System.IO.File.Exists(lyricFilePath))
{
- var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
- double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000;
- lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ return lyricFilePath;
}
}
- return new { MetaData = metaData, lyrics = lyricsList };
+ return null;
+ }
+
+
+ ///
+ /// Checks if requested item has a matching local lyric file.
+ ///
+ /// Path of requested item.
+ /// True if item has a matching lyrics file; otherwise false.
+ public static bool HasLyricFile(string itemPath)
+ {
+ string? lyricFilePath = GetLyricFilePath(itemPath);
+ return !string.IsNullOrEmpty(lyricFilePath);
}
}
}
diff --git a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
new file mode 100644
index 0000000000..37f1f5bbe4
--- /dev/null
+++ b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
@@ -0,0 +1,34 @@
+using System.Collections.ObjectModel;
+using MediaBrowser.Controller.Entities;
+
+namespace Jellyfin.Api.Models.UserDtos
+{
+ ///
+ /// Interface ILyricsProvider.
+ ///
+ public interface ILyricsProvider
+ {
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public Collection? FileExtensions { get; }
+
+ ///
+ /// Gets a value indicating whether Process() generated data.
+ ///
+ /// true if data generated; otherwise, false.
+ bool HasData { get; }
+
+ ///
+ /// Gets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ object? Data { get; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ void Process(BaseItem item);
+ }
+}
diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs
new file mode 100644
index 0000000000..029acd6ca5
--- /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
+{
+ ///
+ /// LRC File Lyric Provider.
+ ///
+ public class LrcLyricsProvider : ILyricsProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LrcLyricsProvider()
+ {
+ FileExtensions = new Collection
+ {
+ "lrc"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public Collection? FileExtensions { get; }
+
+ ///
+ /// Gets or Sets a value indicating whether Process() generated data.
+ ///
+ /// true if data generated; otherwise, false.
+ public bool HasData { get; set; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ public void Process(BaseItem item)
+ {
+ string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return;
+ }
+
+ List lyricsList = new List();
+
+ List sortedLyricData = new List();
+ var metaData = new ExpandoObject() as IDictionary;
+ 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 };
+ }
+ }
+ }
+}
diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs
new file mode 100644
index 0000000000..2794cd78a0
--- /dev/null
+++ b/Jellyfin.Api/Models/UserDtos/Lyric.cs
@@ -0,0 +1,18 @@
+namespace Jellyfin.Api.Models.UserDtos
+{
+ ///
+ /// Lyric dto.
+ ///
+ public class Lyric
+ {
+ ///
+ /// Gets or sets the start time (ticks).
+ ///
+ public double Start { get; set; }
+
+ ///
+ /// Gets or sets the text.
+ ///
+ public string Text { get; set; } = string.Empty;
+ }
+}
diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs
deleted file mode 100644
index cd548eb037..0000000000
--- a/Jellyfin.Api/Models/UserDtos/Lyrics.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Jellyfin.Api.Models.UserDtos
-{
- ///
- /// Lyric dto.
- ///
- public class Lyrics
- {
- ///
- /// Gets or sets the start.
- ///
- public double? Start { get; set; }
-
- ///
- /// Gets or sets the text.
- ///
- public string? Text { get; set; }
-
- ///
- /// Gets or sets the error.
- ///
- public string? Error { get; set; }
- }
-}
diff --git a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
new file mode 100644
index 0000000000..03cce1ffbb
--- /dev/null
+++ b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
@@ -0,0 +1,81 @@
+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
+{
+ ///
+ /// TXT File Lyric Provider.
+ ///
+ public class TxtLyricsProvider : ILyricsProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TxtLyricsProvider()
+ {
+ FileExtensions = new Collection
+ {
+ "lrc", "txt"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public Collection? FileExtensions { get; }
+
+ ///
+ /// Gets or Sets a value indicating whether Process() generated data.
+ ///
+ /// true if data generated; otherwise, false.
+ public bool HasData { get; set; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ public void Process(BaseItem item)
+ {
+ string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return;
+ }
+
+ List lyricsList = new List();
+
+ string lyricData = System.IO.File.ReadAllText(lyricFilePath);
+
+ // Splitting on Environment.NewLine caused some new lines to be missed in Windows.
+ char[] newLinedelims = new[] { '\r', '\n' };
+ string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
+
+ if (!lyricTextLines.Any())
+ {
+ return;
+ }
+
+ foreach (string lyricLine in lyricTextLines)
+ {
+ lyricsList.Add(new Lyric { Text = lyricLine });
+ }
+
+ this.HasData = true;
+ this.Data = new { lyrics = lyricsList };
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index fdb84fa320..b40a0210ad 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -76,6 +76,8 @@ namespace MediaBrowser.Model.Dto
public bool? CanDownload { get; set; }
+ public bool? HasLocalLyricsFile { get; set; }
+
public bool? HasSubtitles { get; set; }
public string PreferredMetadataLanguage { get; set; }
--
cgit v1.2.3
From 97f8a63b8934ead26cfc7d41550188d86cada93a Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sun, 11 Sep 2022 15:56:34 -0400
Subject: Allow LRC start value to be null
---
Jellyfin.Api/Models/UserDtos/Lyric.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs
index 2794cd78a0..f83fc9839b 100644
--- a/Jellyfin.Api/Models/UserDtos/Lyric.cs
+++ b/Jellyfin.Api/Models/UserDtos/Lyric.cs
@@ -8,7 +8,7 @@ namespace Jellyfin.Api.Models.UserDtos
///
/// Gets or sets the start time (ticks).
///
- public double Start { get; set; }
+ public double? Start { get; set; }
///
/// Gets or sets the text.
--
cgit v1.2.3
From 3928d02e175f732d5e13fa0c66dbccb704c4324d Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sun, 11 Sep 2022 16:13:17 -0400
Subject: Resolve Possible null reference
---
Jellyfin.Api/Helpers/ItemHelper.cs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
index 622eb0b9fe..cd29361bd7 100644
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ b/Jellyfin.Api/Helpers/ItemHelper.cs
@@ -37,7 +37,11 @@ namespace Jellyfin.Api.Helpers
foreach (var provider in foundLyricProviders)
{
- providerList.Add((ILyricsProvider)Activator.CreateInstance(provider));
+ ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider;
+ if (newProvider is not null)
+ {
+ providerList.Add(newProvider);
+ }
}
foreach (ILyricsProvider provider in providerList)
@@ -74,7 +78,7 @@ namespace Jellyfin.Api.Helpers
// Iterate over all found lyric providers
foreach (var provider in foundLyricProviders)
{
- var foundProvider = (ILyricsProvider)Activator.CreateInstance(provider);
+ ILyricsProvider? foundProvider = Activator.CreateInstance(provider) as ILyricsProvider;
if (foundProvider?.FileExtensions is null)
{
continue;
--
cgit v1.2.3
From cecca5f715f70b263f81b5c44dfcee5c38d53bf8 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sun, 11 Sep 2022 19:13:02 -0400
Subject: Remove unneeded 2nd loops
---
.gitignore | 2 --
Jellyfin.Api/Helpers/ItemHelper.cs | 30 ++++++++----------------------
2 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3f80ffcf7d..c2ae76c1e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -281,5 +281,3 @@ apiclient/generated
# Omnisharp crash logs
mono_crash.*.json
-
-!LrcParser.dll
\ No newline at end of file
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
index cd29361bd7..0afe5a155d 100644
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ b/Jellyfin.Api/Helpers/ItemHelper.cs
@@ -40,16 +40,11 @@ namespace Jellyfin.Api.Helpers
ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider;
if (newProvider is not null)
{
- providerList.Add(newProvider);
- }
- }
-
- foreach (ILyricsProvider provider in providerList)
- {
- provider.Process(item);
- if (provider.HasData)
- {
- return provider.Data;
+ newProvider.Process(item);
+ if (newProvider.HasData)
+ {
+ return newProvider.Data;
+ }
}
}
@@ -86,26 +81,17 @@ namespace Jellyfin.Api.Helpers
if (foundProvider.FileExtensions.Any())
{
- // Gather distinct list of handled file extentions
foreach (string lyricFileExtension in foundProvider.FileExtensions)
{
- if (!supportedLyricFileExtensions.Contains(lyricFileExtension))
+ string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
+ if (System.IO.File.Exists(lyricFilePath))
{
- supportedLyricFileExtensions.Add(lyricFileExtension);
+ return lyricFilePath;
}
}
}
}
- foreach (string lyricFileExtension in supportedLyricFileExtensions)
- {
- string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
- if (System.IO.File.Exists(lyricFilePath))
- {
- return lyricFilePath;
- }
- }
-
return null;
}
--
cgit v1.2.3
From 31ec521f5ebfdffc1c38b4c67e7632933041a988 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sun, 11 Sep 2022 19:15:33 -0400
Subject: Remove now unused variables
---
Jellyfin.Api/Helpers/ItemHelper.cs | 4 ----
1 file changed, 4 deletions(-)
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
index 0afe5a155d..49bb8af8e3 100644
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ b/Jellyfin.Api/Helpers/ItemHelper.cs
@@ -23,8 +23,6 @@ namespace Jellyfin.Api.Helpers
/// Collection of Lyrics.
internal static object? GetLyricData(BaseItem item)
{
- List providerList = new List();
-
// Find all classes that implement ILyricsProvider Interface
var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
@@ -58,8 +56,6 @@ namespace Jellyfin.Api.Helpers
/// True if item has a matching lyrics file.
public static string? GetLyricFilePath(string itemPath)
{
- List supportedLyricFileExtensions = new List();
-
// Find all classes that implement ILyricsProvider Interface
var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
--
cgit v1.2.3
From c0dae0fef5255f27071b8dd84e8468a3e1ad29bf Mon Sep 17 00:00:00 2001
From: Jamie Introcaso
Date: Wed, 14 Sep 2022 20:39:26 -0400
Subject: Adds lyric providers to DI pipeline
This is adding those lyric providers to the DI pipeline along with a super simple implementation of how to use them in the controller method. Probably should be refactored into a lyric service of some sort that would have the providers injected into it.
---
Emby.Server.Implementations/ApplicationHost.cs | 3 +++
Jellyfin.Api/Controllers/UserLibraryController.cs | 19 ++++++++++++-------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 91a16c199d..3e9c540e7b 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -46,6 +46,7 @@ using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using Jellyfin.Api.Helpers;
+using Jellyfin.Api.Models.UserDtos;
using Jellyfin.MediaEncoding.Hls.Playlist;
using Jellyfin.Networking.Configuration;
using Jellyfin.Networking.Manager;
@@ -580,6 +581,8 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index ed8a98d23f..123c5e0795 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -1,17 +1,14 @@
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 MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -40,6 +37,7 @@ namespace Jellyfin.Api.Controllers
private readonly IDtoService _dtoService;
private readonly IUserViewManager _userViewManager;
private readonly IFileSystem _fileSystem;
+ private readonly IEnumerable _lyricProviders;
///
/// Initializes a new instance of the class.
@@ -50,13 +48,15 @@ namespace Jellyfin.Api.Controllers
/// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
+ /// Collection of all registered interfaces.
public UserLibraryController(
IUserManager userManager,
IUserDataManager userDataRepository,
ILibraryManager libraryManager,
IDtoService dtoService,
IUserViewManager userViewManager,
- IFileSystem fileSystem)
+ IFileSystem fileSystem,
+ IEnumerable lyricProviders)
{
_userManager = userManager;
_userDataRepository = userDataRepository;
@@ -64,6 +64,7 @@ namespace Jellyfin.Api.Controllers
_dtoService = dtoService;
_userViewManager = userViewManager;
_fileSystem = fileSystem;
+ _lyricProviders = lyricProviders;
}
///
@@ -413,10 +414,14 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- var result = ItemHelper.GetLyricData(item);
- if (result is not null)
+ // Super nieve implementation. I would suggest building a lyric service of some sort and doing this there.
+ foreach (var provider in _lyricProviders)
{
- return Ok(result);
+ provider.Process(item);
+ if (provider.HasData)
+ {
+ return Ok(provider.Data);
+ }
}
return NotFound();
--
cgit v1.2.3
From d9be3874ba3842d5888c5cbbe583614ed990849e Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Thu, 15 Sep 2022 19:45:26 -0400
Subject: Auto stash before merge of "lyric-lrc-file-support" and
"origin/lyric-lrc-file-support"
---
Emby.Server.Implementations/ApplicationHost.cs | 2 +
Emby.Server.Implementations/Dto/DtoService.cs | 9 +-
Jellyfin.Api/Controllers/UserLibraryController.cs | 5 +-
Jellyfin.Api/Helpers/ItemHelper.cs | 106 -------------------
Jellyfin.Api/Jellyfin.Api.csproj | 1 -
Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs | 34 ------
Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs | 117 ---------------------
Jellyfin.Api/Models/UserDtos/Lyric.cs | 18 ----
Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs | 81 --------------
MediaBrowser.Controller/Lyrics/ILyricsProvider.cs | 24 +++++
MediaBrowser.Controller/Lyrics/Lyric.cs | 18 ++++
MediaBrowser.Controller/Lyrics/LyricInfo.cs | 87 +++++++++++++++
MediaBrowser.Controller/Lyrics/LyricResponse.cs | 15 +++
MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +-
MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs | 112 ++++++++++++++++++++
MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs | 74 +++++++++++++
.../MediaBrowser.Providers.csproj | 2 +
17 files changed, 345 insertions(+), 362 deletions(-)
delete mode 100644 Jellyfin.Api/Helpers/ItemHelper.cs
delete mode 100644 Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
delete mode 100644 Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs
delete mode 100644 Jellyfin.Api/Models/UserDtos/Lyric.cs
delete mode 100644 Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
create mode 100644 MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
create mode 100644 MediaBrowser.Controller/Lyrics/Lyric.cs
create mode 100644 MediaBrowser.Controller/Lyrics/LyricInfo.cs
create mode 100644 MediaBrowser.Controller/Lyrics/LyricResponse.cs
create mode 100644 MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
create mode 100644 MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 3e9c540e7b..5487e5e023 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -68,6 +68,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications;
@@ -95,6 +96,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.Chapters;
+using MediaBrowser.Providers.Lyric;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Plugins.Tmdb;
using MediaBrowser.Providers.Subtitles;
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 96717cff53..bed82a4bbb 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -19,6 +19,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
@@ -51,6 +52,8 @@ namespace Emby.Server.Implementations.Dto
private readonly IMediaSourceManager _mediaSourceManager;
private readonly Lazy _livetvManagerFactory;
+ private readonly IEnumerable _lyricProviders;
+
public DtoService(
ILogger logger,
ILibraryManager libraryManager,
@@ -60,7 +63,8 @@ namespace Emby.Server.Implementations.Dto
IProviderManager providerManager,
IApplicationHost appHost,
IMediaSourceManager mediaSourceManager,
- Lazy livetvManagerFactory)
+ Lazy livetvManagerFactory,
+ IEnumerable lyricProviders)
{
_logger = logger;
_libraryManager = libraryManager;
@@ -71,6 +75,7 @@ namespace Emby.Server.Implementations.Dto
_appHost = appHost;
_mediaSourceManager = mediaSourceManager;
_livetvManagerFactory = livetvManagerFactory;
+ _lyricProviders = lyricProviders;
}
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
@@ -142,7 +147,7 @@ namespace Emby.Server.Implementations.Dto
}
else if (item is Audio)
{
- dto.HasLocalLyricsFile = ItemHelper.HasLyricFile(item.Path);
+ dto.HasLyrics = MediaBrowser.Controller.Lyrics.LyricInfo.HasLyricFile(_lyricProviders, item.Path);
}
if (item is IItemByName itemByName
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 123c5e0795..3da78c1169 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -414,8 +415,8 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- // Super nieve implementation. I would suggest building a lyric service of some sort and doing this there.
- foreach (var provider in _lyricProviders)
+ var result = MediaBrowser.Controller.Lyrics.LyricInfo.GetLyricData(_lyricProviders, item);
+ if (result is not null)
{
provider.Process(item);
if (provider.HasData)
diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs
deleted file mode 100644
index 49bb8af8e3..0000000000
--- a/Jellyfin.Api/Helpers/ItemHelper.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using Jellyfin.Api.Models.UserDtos;
-using LrcParser.Model;
-using LrcParser.Parser;
-using MediaBrowser.Controller.Entities;
-
-namespace Jellyfin.Api.Helpers
-{
- ///
- /// Item helper.
- ///
- public static class ItemHelper
- {
- ///
- /// Opens lyrics file, converts to a List of Lyrics, and returns it.
- ///
- /// Requested Item.
- /// Collection of Lyrics.
- internal static object? GetLyricData(BaseItem item)
- {
- // Find all classes that implement ILyricsProvider Interface
- var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
- .GetTypes()
- .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface);
-
- if (!foundLyricProviders.Any())
- {
- return null;
- }
-
- foreach (var provider in foundLyricProviders)
- {
- ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider;
- if (newProvider is not null)
- {
- newProvider.Process(item);
- if (newProvider.HasData)
- {
- return newProvider.Data;
- }
- }
- }
-
- return null;
- }
-
- ///
- /// Checks if requested item has a matching lyric file.
- ///
- /// Path of requested item.
- /// True if item has a matching lyrics file.
- public static string? GetLyricFilePath(string itemPath)
- {
- // Find all classes that implement ILyricsProvider Interface
- var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly()
- .GetTypes()
- .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface);
-
- if (!foundLyricProviders.Any())
- {
- return null;
- }
-
- // Iterate over all found lyric providers
- foreach (var provider in foundLyricProviders)
- {
- ILyricsProvider? foundProvider = Activator.CreateInstance(provider) as ILyricsProvider;
- if (foundProvider?.FileExtensions is null)
- {
- continue;
- }
-
- if (foundProvider.FileExtensions.Any())
- {
- foreach (string lyricFileExtension in foundProvider.FileExtensions)
- {
- string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
- if (System.IO.File.Exists(lyricFilePath))
- {
- return lyricFilePath;
- }
- }
- }
- }
-
- return null;
- }
-
-
- ///
- /// Checks if requested item has a matching local lyric file.
- ///
- /// Path of requested item.
- /// True if item has a matching lyrics file; otherwise false.
- public static bool HasLyricFile(string itemPath)
- {
- string? lyricFilePath = GetLyricFilePath(itemPath);
- return !string.IsNullOrEmpty(lyricFilePath);
- }
- }
-}
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index 972387e02a..894d871383 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -17,7 +17,6 @@
-
diff --git a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
deleted file mode 100644
index 37f1f5bbe4..0000000000
--- a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Collections.ObjectModel;
-using MediaBrowser.Controller.Entities;
-
-namespace Jellyfin.Api.Models.UserDtos
-{
- ///
- /// Interface ILyricsProvider.
- ///
- public interface ILyricsProvider
- {
- ///
- /// Gets a value indicating the File Extenstions this provider works with.
- ///
- public Collection? FileExtensions { get; }
-
- ///
- /// Gets a value indicating whether Process() generated data.
- ///
- /// true if data generated; otherwise, false.
- bool HasData { get; }
-
- ///
- /// Gets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- object? Data { get; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
- ///
- /// The item to to process.
- void Process(BaseItem item);
- }
-}
diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs
deleted file mode 100644
index 029acd6ca5..0000000000
--- a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-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
-{
- ///
- /// LRC File Lyric Provider.
- ///
- public class LrcLyricsProvider : ILyricsProvider
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public LrcLyricsProvider()
- {
- FileExtensions = new Collection
- {
- "lrc"
- };
- }
-
- ///
- /// Gets a value indicating the File Extenstions this provider works with.
- ///
- public Collection? FileExtensions { get; }
-
- ///
- /// Gets or Sets a value indicating whether Process() generated data.
- ///
- /// true if data generated; otherwise, false.
- public bool HasData { get; set; }
-
- ///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
- ///
- /// The item to to process.
- public void Process(BaseItem item)
- {
- string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
-
- if (string.IsNullOrEmpty(lyricFilePath))
- {
- return;
- }
-
- List lyricsList = new List();
-
- List sortedLyricData = new List();
- var metaData = new ExpandoObject() as IDictionary;
- 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 };
- }
- }
- }
-}
diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs
deleted file mode 100644
index f83fc9839b..0000000000
--- a/Jellyfin.Api/Models/UserDtos/Lyric.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Jellyfin.Api.Models.UserDtos
-{
- ///
- /// Lyric dto.
- ///
- public class Lyric
- {
- ///
- /// Gets or sets the start time (ticks).
- ///
- public double? Start { get; set; }
-
- ///
- /// Gets or sets the text.
- ///
- public string Text { get; set; } = string.Empty;
- }
-}
diff --git a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
deleted file mode 100644
index 03cce1ffbb..0000000000
--- a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-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
-{
- ///
- /// TXT File Lyric Provider.
- ///
- public class TxtLyricsProvider : ILyricsProvider
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public TxtLyricsProvider()
- {
- FileExtensions = new Collection
- {
- "lrc", "txt"
- };
- }
-
- ///
- /// Gets a value indicating the File Extenstions this provider works with.
- ///
- public Collection? FileExtensions { get; }
-
- ///
- /// Gets or Sets a value indicating whether Process() generated data.
- ///
- /// true if data generated; otherwise, false.
- public bool HasData { get; set; }
-
- ///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
- ///
- /// The item to to process.
- public void Process(BaseItem item)
- {
- string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
-
- if (string.IsNullOrEmpty(lyricFilePath))
- {
- return;
- }
-
- List lyricsList = new List();
-
- string lyricData = System.IO.File.ReadAllText(lyricFilePath);
-
- // Splitting on Environment.NewLine caused some new lines to be missed in Windows.
- char[] newLinedelims = new[] { '\r', '\n' };
- string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
-
- if (!lyricTextLines.Any())
- {
- return;
- }
-
- foreach (string lyricLine in lyricTextLines)
- {
- lyricsList.Add(new Lyric { Text = lyricLine });
- }
-
- this.HasData = true;
- this.Data = new { lyrics = lyricsList };
- }
- }
-}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
new file mode 100644
index 0000000000..bac32a398a
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+ ///
+ /// Interface ILyricsProvider.
+ ///
+ public interface ILyricsProvider
+ {
+ ///
+ /// Gets the supported media types for this provider.
+ ///
+ /// The supported media types.
+ IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets the lyrics.
+ ///
+ /// The item to to process.
+ /// Task{LyricResponse}.
+ LyricResponse? GetLyrics(BaseItem item);
+ }
+}
diff --git a/MediaBrowser.Controller/Lyrics/Lyric.cs b/MediaBrowser.Controller/Lyrics/Lyric.cs
new file mode 100644
index 0000000000..d44546dd39
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/Lyric.cs
@@ -0,0 +1,18 @@
+namespace MediaBrowser.Controller.Lyrics
+{
+ ///
+ /// Lyric dto.
+ ///
+ public class Lyric
+ {
+ ///
+ /// Gets or sets the start time (ticks).
+ ///
+ public double? Start { get; set; }
+
+ ///
+ /// Gets or sets the text.
+ ///
+ public string Text { get; set; } = string.Empty;
+ }
+}
diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
new file mode 100644
index 0000000000..83a10701a2
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
+using MediaBrowser.Controller.Net;
+using Microsoft.AspNetCore.Mvc;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+ ///
+ /// Item helper.
+ ///
+ public class LyricInfo
+ {
+ ///
+ /// Opens lyrics file, converts to a List of Lyrics, and returns it.
+ ///
+ /// Collection of all registered interfaces.
+ /// Requested Item.
+ /// Collection of Lyrics.
+ public static LyricResponse? GetLyricData(IEnumerable lyricProviders, BaseItem item)
+ {
+
+ foreach (var provider in lyricProviders)
+ {
+ var result = provider.GetLyrics(item);
+ if (result is not null)
+ {
+ return result;
+ }
+ }
+
+ return new LyricResponse
+ {
+ Lyrics = new List
+ {
+ new Lyric { Start = 0, Text = "Test" }
+ }
+ };
+ }
+
+ ///
+ /// Checks if requested item has a matching lyric file.
+ ///
+ /// The current lyricProvider interface.
+ /// Path of requested item.
+ /// True if item has a matching lyrics file.
+ public static string? GetLyricFilePath(ILyricsProvider lyricProvider, string itemPath)
+ {
+ if (lyricProvider.SupportedMediaTypes.Any())
+ {
+ foreach (string lyricFileExtension in lyricProvider.SupportedMediaTypes)
+ {
+ string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
+ if (System.IO.File.Exists(lyricFilePath))
+ {
+ return lyricFilePath;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Checks if requested item has a matching local lyric file.
+ ///
+ /// Collection of all registered interfaces.
+ /// Path of requested item.
+ /// True if item has a matching lyrics file; otherwise false.
+ public static bool HasLyricFile(IEnumerable lyricProviders, string itemPath)
+ {
+ foreach (var provider in lyricProviders)
+ {
+ if (GetLyricFilePath(provider, itemPath) is not null)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
new file mode 100644
index 0000000000..e312638ecc
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
@@ -0,0 +1,15 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+ public class LyricResponse
+ {
+ public IDictionary MetaData { get; set; }
+
+ public IEnumerable Lyrics { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index b40a0210ad..2a86fded22 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -76,7 +76,7 @@ namespace MediaBrowser.Model.Dto
public bool? CanDownload { get; set; }
- public bool? HasLocalLyricsFile { get; set; }
+ public bool? HasLyrics { get; set; }
public bool? HasSubtitles { get; set; }
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
new file mode 100644
index 0000000000..e30d563087
--- /dev/null
+++ b/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using Jellyfin.Api.Helpers;
+using LrcParser.Model;
+using LrcParser.Parser;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
+
+namespace MediaBrowser.Providers.Lyric
+{
+ ///
+ /// LRC File Lyric Provider.
+ ///
+ public class LrcLyricsProvider : ILyricsProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LrcLyricsProvider()
+ {
+ SupportedMediaTypes = new Collection
+ {
+ "lrc"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ /// A representing the asynchronous operation.
+ public LyricResponse? GetLyrics(BaseItem item)
+ {
+ string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return null;
+ }
+
+ List lyricsList = new List();
+
+ List sortedLyricData = new List();
+ var metaData = new ExpandoObject() as IDictionary;
+ 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 null;
+ }
+
+ if (!sortedLyricData.Any())
+ {
+ return null;
+ }
+
+ 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 MediaBrowser.Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ }
+
+ if (metaData.Any())
+ {
+ return new LyricResponse { MetaData = metaData, Lyrics = lyricsList };
+ }
+
+ return new LyricResponse { Lyrics = lyricsList };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
new file mode 100644
index 0000000000..2a5da4e4d8
--- /dev/null
+++ b/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Threading.Tasks;
+using Jellyfin.Api.Helpers;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
+
+namespace MediaBrowser.Providers.Lyric
+{
+ ///
+ /// TXT File Lyric Provider.
+ ///
+ public class TxtLyricsProvider : ILyricsProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TxtLyricsProvider()
+ {
+ SupportedMediaTypes = new Collection
+ {
+ "lrc", "txt"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ /// A representing the asynchronous operation.
+ public LyricResponse? GetLyrics(BaseItem item)
+ {
+ string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return null;
+ }
+
+ List lyricsList = new List();
+
+ string lyricData = System.IO.File.ReadAllText(lyricFilePath);
+
+ // Splitting on Environment.NewLine caused some new lines to be missed in Windows.
+ char[] newLinedelims = new[] { '\r', '\n' };
+ string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
+
+ if (!lyricTextLines.Any())
+ {
+ return null;
+ }
+
+ foreach (string lyricLine in lyricTextLines)
+ {
+ lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine });
+ }
+
+ return new LyricResponse { Lyrics = lyricsList };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 9864db9ac2..8514489f8a 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -6,6 +6,7 @@
+
@@ -16,6 +17,7 @@
+
--
cgit v1.2.3
From f4fd908f8d7ffcdea6acaf75928f6c2960ed6338 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Thu, 15 Sep 2022 20:49:25 -0400
Subject: Create ILyricManager
---
Emby.Server.Implementations/ApplicationHost.cs | 4 +-
Emby.Server.Implementations/Dto/DtoService.cs | 8 +-
Jellyfin.Api/Controllers/UserLibraryController.cs | 16 ++-
MediaBrowser.Controller/Lyrics/ILyricManager.cs | 37 +++++++
MediaBrowser.Controller/Lyrics/ILyricProvider.cs | 29 ++++++
MediaBrowser.Controller/Lyrics/ILyricsProvider.cs | 24 -----
MediaBrowser.Controller/Lyrics/LyricInfo.cs | 50 +--------
MediaBrowser.Providers/Lyric/LrcLyricProvider.cs | 119 ++++++++++++++++++++++
MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs | 112 --------------------
MediaBrowser.Providers/Lyric/LyricManager.cs | 97 ++++++++++++++++++
MediaBrowser.Providers/Lyric/TxtLyricProvider.cs | 82 +++++++++++++++
MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs | 74 --------------
12 files changed, 378 insertions(+), 274 deletions(-)
create mode 100644 MediaBrowser.Controller/Lyrics/ILyricManager.cs
create mode 100644 MediaBrowser.Controller/Lyrics/ILyricProvider.cs
delete mode 100644 MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
create mode 100644 MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
delete mode 100644 MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
create mode 100644 MediaBrowser.Providers/Lyric/LyricManager.cs
create mode 100644 MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
delete mode 100644 MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 5487e5e023..409fc04b16 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -583,8 +583,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService));
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
@@ -603,6 +601,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
@@ -790,6 +789,7 @@ namespace Emby.Server.Implementations
Resolve().AddParts(GetExports(), GetExports(), GetExports());
Resolve().AddParts(GetExports());
+ Resolve().AddParts(GetExports());
Resolve().AddParts(GetExports());
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index bed82a4bbb..6ab574c5c5 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -52,7 +52,7 @@ namespace Emby.Server.Implementations.Dto
private readonly IMediaSourceManager _mediaSourceManager;
private readonly Lazy _livetvManagerFactory;
- private readonly IEnumerable _lyricProviders;
+ private readonly ILyricManager _lyricManager;
public DtoService(
ILogger logger,
@@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.Dto
IApplicationHost appHost,
IMediaSourceManager mediaSourceManager,
Lazy livetvManagerFactory,
- IEnumerable lyricProviders)
+ ILyricManager lyricManager)
{
_logger = logger;
_libraryManager = libraryManager;
@@ -75,7 +75,7 @@ namespace Emby.Server.Implementations.Dto
_appHost = appHost;
_mediaSourceManager = mediaSourceManager;
_livetvManagerFactory = livetvManagerFactory;
- _lyricProviders = lyricProviders;
+ _lyricManager = lyricManager;
}
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
@@ -147,7 +147,7 @@ namespace Emby.Server.Implementations.Dto
}
else if (item is Audio)
{
- dto.HasLyrics = MediaBrowser.Controller.Lyrics.LyricInfo.HasLyricFile(_lyricProviders, item.Path);
+ dto.HasLyrics = _lyricManager.HasLyricFile(item);
}
if (item is IItemByName itemByName
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 3da78c1169..1421ab444a 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -38,7 +38,7 @@ namespace Jellyfin.Api.Controllers
private readonly IDtoService _dtoService;
private readonly IUserViewManager _userViewManager;
private readonly IFileSystem _fileSystem;
- private readonly IEnumerable _lyricProviders;
+ private readonly ILyricManager _lyricManager;
///
/// Initializes a new instance of the class.
@@ -49,7 +49,7 @@ namespace Jellyfin.Api.Controllers
/// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
- /// Collection of all registered interfaces.
+ /// Instance of the interface.
public UserLibraryController(
IUserManager userManager,
IUserDataManager userDataRepository,
@@ -57,7 +57,7 @@ namespace Jellyfin.Api.Controllers
IDtoService dtoService,
IUserViewManager userViewManager,
IFileSystem fileSystem,
- IEnumerable lyricProviders)
+ ILyricManager lyricManager)
{
_userManager = userManager;
_userDataRepository = userDataRepository;
@@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers
_dtoService = dtoService;
_userViewManager = userViewManager;
_fileSystem = fileSystem;
- _lyricProviders = lyricProviders;
+ _lyricManager = lyricManager;
}
///
@@ -415,14 +415,10 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- var result = MediaBrowser.Controller.Lyrics.LyricInfo.GetLyricData(_lyricProviders, item);
+ var result = _lyricManager.GetLyric(item);
if (result is not null)
{
- provider.Process(item);
- if (provider.HasData)
- {
- return Ok(provider.Data);
- }
+ return Ok(result);
}
return NotFound();
diff --git a/MediaBrowser.Controller/Lyrics/ILyricManager.cs b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
new file mode 100644
index 0000000000..4fd11b9e02
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
@@ -0,0 +1,37 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Providers;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+ public interface ILyricManager
+ {
+ ///
+ /// Adds the parts.
+ ///
+ /// The lyric providers.
+ void AddParts(IEnumerable lyricProviders);
+
+ ///
+ /// Gets the lyrics.
+ ///
+ /// The media item.
+ /// Lyrics for passed item.
+ LyricResponse GetLyric(BaseItem item);
+
+ ///
+ /// Checks if requested item has a matching local lyric file.
+ ///
+ /// The media item.
+ /// True if item has a matching lyrics file; otherwise false.
+ bool HasLyricFile(BaseItem item);
+ }
+}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
new file mode 100644
index 0000000000..691fed1fd2
--- /dev/null
+++ b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+ ///
+ /// Interface ILyricsProvider.
+ ///
+ public interface ILyricProvider
+ {
+ ///
+ /// Gets a value indicating the provider name.
+ ///
+ string Name { get; }
+
+ ///
+ /// Gets the supported media types for this provider.
+ ///
+ /// The supported media types.
+ IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets the lyrics.
+ ///
+ /// The item to to process.
+ /// Task{LyricResponse}.
+ LyricResponse? GetLyrics(BaseItem item);
+ }
+}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
deleted file mode 100644
index bac32a398a..0000000000
--- a/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System.Collections.Generic;
-using MediaBrowser.Controller.Entities;
-
-namespace MediaBrowser.Controller.Lyrics
-{
- ///
- /// Interface ILyricsProvider.
- ///
- public interface ILyricsProvider
- {
- ///
- /// Gets the supported media types for this provider.
- ///
- /// The supported media types.
- IEnumerable SupportedMediaTypes { get; }
-
- ///
- /// Gets the lyrics.
- ///
- /// The item to to process.
- /// Task{LyricResponse}.
- LyricResponse? GetLyrics(BaseItem item);
- }
-}
diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
index 83a10701a2..d44e14237a 100644
--- a/MediaBrowser.Controller/Lyrics/LyricInfo.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
@@ -13,42 +13,15 @@ namespace MediaBrowser.Controller.Lyrics
///
/// Item helper.
///
- public class LyricInfo
+ public static class LyricInfo
{
- ///
- /// Opens lyrics file, converts to a List of Lyrics, and returns it.
- ///
- /// Collection of all registered interfaces.
- /// Requested Item.
- /// Collection of Lyrics.
- public static LyricResponse? GetLyricData(IEnumerable lyricProviders, BaseItem item)
- {
-
- foreach (var provider in lyricProviders)
- {
- var result = provider.GetLyrics(item);
- if (result is not null)
- {
- return result;
- }
- }
-
- return new LyricResponse
- {
- Lyrics = new List
- {
- new Lyric { Start = 0, Text = "Test" }
- }
- };
- }
-
///
/// Checks if requested item has a matching lyric file.
///
/// The current lyricProvider interface.
/// Path of requested item.
/// True if item has a matching lyrics file.
- public static string? GetLyricFilePath(ILyricsProvider lyricProvider, string itemPath)
+ public static string? GetLyricFilePath(ILyricProvider lyricProvider, string itemPath)
{
if (lyricProvider.SupportedMediaTypes.Any())
{
@@ -64,24 +37,5 @@ namespace MediaBrowser.Controller.Lyrics
return null;
}
-
- ///
- /// Checks if requested item has a matching local lyric file.
- ///
- /// Collection of all registered interfaces.
- /// Path of requested item.
- /// True if item has a matching lyrics file; otherwise false.
- public static bool HasLyricFile(IEnumerable lyricProviders, string itemPath)
- {
- foreach (var provider in lyricProviders)
- {
- if (GetLyricFilePath(provider, itemPath) is not null)
- {
- return true;
- }
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
new file mode 100644
index 0000000000..18a85c93ac
--- /dev/null
+++ b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using Jellyfin.Api.Helpers;
+using LrcParser.Model;
+using LrcParser.Parser;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
+
+namespace MediaBrowser.Providers.Lyric
+{
+ ///
+ /// LRC File Lyric Provider.
+ ///
+ public class LrcLyricProvider : ILyricProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LrcLyricProvider()
+ {
+ Name = "LrcLyricProvider";
+
+ SupportedMediaTypes = new Collection
+ {
+ "lrc"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the provider name.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ /// A representing the asynchronous operation.
+ public LyricResponse? GetLyrics(BaseItem item)
+ {
+ string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return null;
+ }
+
+ List lyricsList = new List();
+
+ List sortedLyricData = new List();
+ var metaData = new ExpandoObject() as IDictionary;
+ 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 null;
+ }
+
+ if (!sortedLyricData.Any())
+ {
+ return null;
+ }
+
+ 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 MediaBrowser.Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ }
+
+ if (metaData.Any())
+ {
+ return new LyricResponse { MetaData = metaData, Lyrics = lyricsList };
+ }
+
+ return new LyricResponse { Lyrics = lyricsList };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
deleted file mode 100644
index e30d563087..0000000000
--- a/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Dynamic;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-using Jellyfin.Api.Helpers;
-using LrcParser.Model;
-using LrcParser.Parser;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Lyrics;
-
-namespace MediaBrowser.Providers.Lyric
-{
- ///
- /// LRC File Lyric Provider.
- ///
- public class LrcLyricsProvider : ILyricsProvider
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public LrcLyricsProvider()
- {
- SupportedMediaTypes = new Collection
- {
- "lrc"
- };
- }
-
- ///
- /// Gets a value indicating the File Extenstions this provider works with.
- ///
- public IEnumerable SupportedMediaTypes { get; }
-
- ///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
- ///
- /// The item to to process.
- /// A representing the asynchronous operation.
- public LyricResponse? GetLyrics(BaseItem item)
- {
- string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
-
- if (string.IsNullOrEmpty(lyricFilePath))
- {
- return null;
- }
-
- List lyricsList = new List();
-
- List sortedLyricData = new List();
- var metaData = new ExpandoObject() as IDictionary;
- 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 null;
- }
-
- if (!sortedLyricData.Any())
- {
- return null;
- }
-
- 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 MediaBrowser.Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
- }
-
- if (metaData.Any())
- {
- return new LyricResponse { MetaData = metaData, Lyrics = lyricsList };
- }
-
- return new LyricResponse { Lyrics = lyricsList };
- }
- }
-}
diff --git a/MediaBrowser.Providers/Lyric/LyricManager.cs b/MediaBrowser.Providers/Lyric/LyricManager.cs
new file mode 100644
index 0000000000..48572c63e4
--- /dev/null
+++ b/MediaBrowser.Providers/Lyric/LyricManager.cs
@@ -0,0 +1,97 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Extensions;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Lyrics;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Subtitles;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Providers;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Lyric
+{
+ public class LyricManager : ILyricManager
+ {
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+ private readonly ILibraryMonitor _monitor;
+ private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly ILocalizationManager _localization;
+
+ private ILyricProvider[] _lyricProviders;
+
+ public LyricManager(
+ ILogger logger,
+ IFileSystem fileSystem,
+ ILibraryMonitor monitor,
+ IMediaSourceManager mediaSourceManager,
+ ILocalizationManager localizationManager)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+ _monitor = monitor;
+ _mediaSourceManager = mediaSourceManager;
+ _localization = localizationManager;
+ }
+
+ ///
+ public void AddParts(IEnumerable lyricProviders)
+ {
+ _lyricProviders = lyricProviders
+ .OrderBy(i => i is IHasOrder hasOrder ? hasOrder.Order : 0)
+ .ToArray();
+ }
+
+ ///
+ public LyricResponse GetLyric(BaseItem item)
+ {
+ foreach (ILyricProvider provider in _lyricProviders)
+ {
+ var results = provider.GetLyrics(item);
+ if (results is not null)
+ {
+ return results;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ public bool HasLyricFile(BaseItem item)
+ {
+ foreach (ILyricProvider provider in _lyricProviders)
+ {
+ if (item is null)
+ {
+ continue;
+ }
+
+ if (LyricInfo.GetLyricFilePath(provider, item.Path) is not null)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
new file mode 100644
index 0000000000..939d8708b2
--- /dev/null
+++ b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Jellyfin.Api.Helpers;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
+
+namespace MediaBrowser.Providers.Lyric
+{
+ ///
+ /// TXT File Lyric Provider.
+ ///
+ public class TxtLyricProvider : ILyricProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TxtLyricProvider()
+ {
+ Name = "TxtLyricProvider";
+
+ SupportedMediaTypes = new Collection
+ {
+ "lrc", "txt"
+ };
+ }
+
+ ///
+ /// Gets a value indicating the provider name.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets a value indicating the File Extenstions this provider works with.
+ ///
+ public IEnumerable SupportedMediaTypes { get; }
+
+ ///
+ /// Gets or Sets Data object generated by Process() method.
+ ///
+ /// Object with data if no error occured; otherwise, null.
+ public object? Data { get; set; }
+
+ ///
+ /// Opens lyric file for [the specified item], and processes it for API return.
+ ///
+ /// The item to to process.
+ /// A representing the asynchronous operation.
+ public LyricResponse? GetLyrics(BaseItem item)
+ {
+ string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
+
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return null;
+ }
+
+ List lyricsList = new List();
+
+ string lyricData = System.IO.File.ReadAllText(lyricFilePath);
+
+ // Splitting on Environment.NewLine caused some new lines to be missed in Windows.
+ char[] newLinedelims = new[] { '\r', '\n' };
+ string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
+
+ if (!lyricTextLines.Any())
+ {
+ return null;
+ }
+
+ foreach (string lyricLine in lyricTextLines)
+ {
+ lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine });
+ }
+
+ return new LyricResponse { Lyrics = lyricsList };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
deleted file mode 100644
index 2a5da4e4d8..0000000000
--- a/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Threading.Tasks;
-using Jellyfin.Api.Helpers;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Lyrics;
-
-namespace MediaBrowser.Providers.Lyric
-{
- ///
- /// TXT File Lyric Provider.
- ///
- public class TxtLyricsProvider : ILyricsProvider
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public TxtLyricsProvider()
- {
- SupportedMediaTypes = new Collection
- {
- "lrc", "txt"
- };
- }
-
- ///
- /// Gets a value indicating the File Extenstions this provider works with.
- ///
- public IEnumerable SupportedMediaTypes { get; }
-
- ///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
- ///
- /// The item to to process.
- /// A representing the asynchronous operation.
- public LyricResponse? GetLyrics(BaseItem item)
- {
- string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
-
- if (string.IsNullOrEmpty(lyricFilePath))
- {
- return null;
- }
-
- List lyricsList = new List();
-
- string lyricData = System.IO.File.ReadAllText(lyricFilePath);
-
- // Splitting on Environment.NewLine caused some new lines to be missed in Windows.
- char[] newLinedelims = new[] { '\r', '\n' };
- string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
-
- if (!lyricTextLines.Any())
- {
- return null;
- }
-
- foreach (string lyricLine in lyricTextLines)
- {
- lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine });
- }
-
- return new LyricResponse { Lyrics = lyricsList };
- }
- }
-}
--
cgit v1.2.3
From f740d1b9f00d91bfad970f56abed67d8c8c16c9c Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 16 Sep 2022 20:52:40 -0400
Subject: Remove use of AddParts. Cleanup use of Lyric vs Lyrics.
---
Emby.Server.Implementations/ApplicationHost.cs | 2 +-
Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +++---
Jellyfin.Server/CoreAppHost.cs | 6 ++++++
MediaBrowser.Controller/Lyrics/ILyricManager.cs | 18 ++--------------
MediaBrowser.Controller/Lyrics/ILyricProvider.cs | 4 ++--
MediaBrowser.Controller/Lyrics/Lyric.cs | 4 ++--
MediaBrowser.Controller/Lyrics/LyricInfo.cs | 8 +++----
MediaBrowser.Controller/Lyrics/LyricResponse.cs | 9 ++++++++
MediaBrowser.Providers/Lyric/LrcLyricProvider.cs | 24 ++++++++-------------
MediaBrowser.Providers/Lyric/LyricManager.cs | 16 +++++---------
MediaBrowser.Providers/Lyric/TxtLyricProvider.cs | 26 +++++++++--------------
11 files changed, 53 insertions(+), 70 deletions(-)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 409fc04b16..5edc25952d 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -789,7 +789,7 @@ namespace Emby.Server.Implementations
Resolve().AddParts(GetExports(), GetExports(), GetExports());
Resolve().AddParts(GetExports());
- Resolve().AddParts(GetExports());
+ //Resolve().AddParts(GetExports());
Resolve().AddParts(GetExports());
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 1421ab444a..2cb2e93284 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -394,10 +394,10 @@ namespace Jellyfin.Api.Controllers
/// Item id.
/// Lyrics returned.
/// Something went wrong. No Lyrics will be returned.
- /// An containing the intros to play.
+ /// An containing the item's lyrics.
[HttpGet("Users/{userId}/Items/{itemId}/Lyrics")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
+ public ActionResult> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
@@ -415,7 +415,7 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- var result = _lyricManager.GetLyric(item);
+ var result = _lyricManager.GetLyrics(item);
if (result is not null)
{
return Ok(result);
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 67e50b92d9..984711dc2d 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -19,6 +19,7 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Model.Activity;
@@ -95,6 +96,11 @@ namespace Jellyfin.Server
serviceCollection.AddScoped();
+ foreach (var type in GetExportTypes())
+ {
+ serviceCollection.AddSingleton(typeof(ILyricProvider), type);
+ }
+
base.RegisterServices(serviceCollection);
}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricManager.cs b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
index 4fd11b9e02..c0f78d177d 100644
--- a/MediaBrowser.Controller/Lyrics/ILyricManager.cs
+++ b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
@@ -1,37 +1,23 @@
-#nullable disable
-
#pragma warning disable CS1591
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Lyrics
{
public interface ILyricManager
{
- ///
- /// Adds the parts.
- ///
- /// The lyric providers.
- void AddParts(IEnumerable lyricProviders);
-
///
/// Gets the lyrics.
///
/// The media item.
/// Lyrics for passed item.
- LyricResponse GetLyric(BaseItem item);
+ LyricResponse GetLyrics(BaseItem item);
///
/// Checks if requested item has a matching local lyric file.
///
/// The media item.
- /// True if item has a matching lyrics file; otherwise false.
+ /// True if item has a matching lyric file; otherwise false.
bool HasLyricFile(BaseItem item);
}
}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
index 691fed1fd2..5e677ab26f 100644
--- a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
+++ b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
@@ -22,8 +22,8 @@ namespace MediaBrowser.Controller.Lyrics
///
/// Gets the lyrics.
///
- /// The item to to process.
- /// Task{LyricResponse}.
+ /// The media item.
+ /// If found, returns lyrics for passed item; otherwise, null.
LyricResponse? GetLyrics(BaseItem item);
}
}
diff --git a/MediaBrowser.Controller/Lyrics/Lyric.cs b/MediaBrowser.Controller/Lyrics/Lyric.cs
index d44546dd39..56a0a8a72d 100644
--- a/MediaBrowser.Controller/Lyrics/Lyric.cs
+++ b/MediaBrowser.Controller/Lyrics/Lyric.cs
@@ -1,12 +1,12 @@
namespace MediaBrowser.Controller.Lyrics
{
///
- /// Lyric dto.
+ /// Lyric model.
///
public class Lyric
{
///
- /// Gets or sets the start time (ticks).
+ /// Gets or sets the start time in ticks.
///
public double? Start { get; set; }
diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
index d44e14237a..018f296b1a 100644
--- a/MediaBrowser.Controller/Lyrics/LyricInfo.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
@@ -11,16 +11,16 @@ using Microsoft.AspNetCore.Mvc;
namespace MediaBrowser.Controller.Lyrics
{
///
- /// Item helper.
+ /// Lyric helper methods.
///
public static class LyricInfo
{
///
- /// Checks if requested item has a matching lyric file.
+ /// Gets matching lyric file for a requested item.
///
- /// The current lyricProvider interface.
+ /// The lyricProvider interface to use.
/// Path of requested item.
- /// True if item has a matching lyrics file.
+ /// Lyric file path if passed lyric provider's supported media type is found; otherwise, null.
public static string? GetLyricFilePath(ILyricProvider lyricProvider, string itemPath)
{
if (lyricProvider.SupportedMediaTypes.Any())
diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
index e312638ecc..498eb873c7 100644
--- a/MediaBrowser.Controller/Lyrics/LyricResponse.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
@@ -6,10 +6,19 @@ using System.Collections.Generic;
namespace MediaBrowser.Controller.Lyrics
{
+ ///
+ /// LyricResponse model.
+ ///
public class LyricResponse
{
+ ///
+ /// Gets or sets MetaData.
+ ///
public IDictionary MetaData { get; set; }
+ ///
+ /// Gets or sets Lyrics.
+ ///
public IEnumerable Lyrics { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
index 18a85c93ac..10db10ac6f 100644
--- a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
@@ -14,7 +14,7 @@ using MediaBrowser.Controller.Lyrics;
namespace MediaBrowser.Providers.Lyric
{
///
- /// LRC File Lyric Provider.
+ /// LRC Lyric Provider.
///
public class LrcLyricProvider : ILyricProvider
{
@@ -37,21 +37,15 @@ namespace MediaBrowser.Providers.Lyric
public string Name { get; }
///
- /// Gets a value indicating the File Extenstions this provider works with.
+ /// Gets a value indicating the File Extenstions this provider supports.
///
public IEnumerable SupportedMediaTypes { get; }
///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
+ /// Opens lyric file for the requested item, and processes it for API return.
///
/// The item to to process.
- /// A representing the asynchronous operation.
+ /// If provider can determine lyrics, returns a with or without metadata; otherwise, null.
public LyricResponse? GetLyrics(BaseItem item)
{
string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
@@ -61,9 +55,9 @@ namespace MediaBrowser.Providers.Lyric
return null;
}
- List lyricsList = new List();
-
+ List lyricList = new List();
List sortedLyricData = new List();
+
var metaData = new ExpandoObject() as IDictionary;
string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath);
@@ -105,15 +99,15 @@ namespace MediaBrowser.Providers.Lyric
{
var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000;
- lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ lyricList.Add(new Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
}
if (metaData.Any())
{
- return new LyricResponse { MetaData = metaData, Lyrics = lyricsList };
+ return new LyricResponse { MetaData = metaData, Lyrics = lyricList };
}
- return new LyricResponse { Lyrics = lyricsList };
+ return new LyricResponse { Lyrics = lyricList };
}
}
}
diff --git a/MediaBrowser.Providers/Lyric/LyricManager.cs b/MediaBrowser.Providers/Lyric/LyricManager.cs
index 48572c63e4..698da46867 100644
--- a/MediaBrowser.Providers/Lyric/LyricManager.cs
+++ b/MediaBrowser.Providers/Lyric/LyricManager.cs
@@ -36,32 +36,26 @@ namespace MediaBrowser.Providers.Lyric
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILocalizationManager _localization;
- private ILyricProvider[] _lyricProviders;
+ private IEnumerable _lyricProviders;
public LyricManager(
ILogger logger,
IFileSystem fileSystem,
ILibraryMonitor monitor,
IMediaSourceManager mediaSourceManager,
- ILocalizationManager localizationManager)
+ ILocalizationManager localizationManager,
+ IEnumerable lyricProviders)
{
_logger = logger;
_fileSystem = fileSystem;
_monitor = monitor;
_mediaSourceManager = mediaSourceManager;
_localization = localizationManager;
+ _lyricProviders = lyricProviders;
}
///
- public void AddParts(IEnumerable lyricProviders)
- {
- _lyricProviders = lyricProviders
- .OrderBy(i => i is IHasOrder hasOrder ? hasOrder.Order : 0)
- .ToArray();
- }
-
- ///
- public LyricResponse GetLyric(BaseItem item)
+ public LyricResponse GetLyrics(BaseItem item)
{
foreach (ILyricProvider provider in _lyricProviders)
{
diff --git a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
index 939d8708b2..aa222ed97b 100644
--- a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
@@ -11,7 +11,7 @@ using MediaBrowser.Controller.Lyrics;
namespace MediaBrowser.Providers.Lyric
{
///
- /// TXT File Lyric Provider.
+ /// TXT Lyric Provider.
///
public class TxtLyricProvider : ILyricProvider
{
@@ -34,21 +34,15 @@ namespace MediaBrowser.Providers.Lyric
public string Name { get; }
///
- /// Gets a value indicating the File Extenstions this provider works with.
+ /// Gets a value indicating the File Extenstions this provider supports.
///
public IEnumerable SupportedMediaTypes { get; }
///
- /// Gets or Sets Data object generated by Process() method.
- ///
- /// Object with data if no error occured; otherwise, null.
- public object? Data { get; set; }
-
- ///
- /// Opens lyric file for [the specified item], and processes it for API return.
+ /// Opens lyric file for the requested item, and processes it for API return.
///
/// The item to to process.
- /// A representing the asynchronous operation.
+ /// If provider can determine lyrics, returns a ; otherwise, null.
public LyricResponse? GetLyrics(BaseItem item)
{
string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
@@ -58,25 +52,25 @@ namespace MediaBrowser.Providers.Lyric
return null;
}
- List lyricsList = new List();
+ List lyricList = new List();
string lyricData = System.IO.File.ReadAllText(lyricFilePath);
// Splitting on Environment.NewLine caused some new lines to be missed in Windows.
- char[] newLinedelims = new[] { '\r', '\n' };
- string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries);
+ char[] newLineDelims = new[] { '\r', '\n' };
+ string[] lyricTextLines = lyricData.Split(newLineDelims, StringSplitOptions.RemoveEmptyEntries);
if (!lyricTextLines.Any())
{
return null;
}
- foreach (string lyricLine in lyricTextLines)
+ foreach (string lyricTextLine in lyricTextLines)
{
- lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine });
+ lyricList.Add(new Controller.Lyrics.Lyric { Text = lyricTextLine });
}
- return new LyricResponse { Lyrics = lyricsList };
+ return new LyricResponse { Lyrics = lyricList };
}
}
}
--
cgit v1.2.3
From 8912f618f59c1e798e406b8ed7fed4504e2c2de3 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Fri, 16 Sep 2022 21:11:28 -0400
Subject: Change API GetLyrics return type
---
Jellyfin.Api/Controllers/UserLibraryController.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 2cb2e93284..df91a8efc7 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -397,7 +397,7 @@ namespace Jellyfin.Api.Controllers
/// An containing the item's lyrics.
[HttpGet("Users/{userId}/Items/{itemId}/Lyrics")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
+ public ActionResult GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
--
cgit v1.2.3
From 9350fa40bda4464a1a5f01fee7f2f72415b7f5d4 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 17 Sep 2022 08:46:09 -0400
Subject: Convert _lyricProviders to an array.
---
MediaBrowser.Providers/Lyric/LyricManager.cs | 42 ++--------------------------
1 file changed, 3 insertions(+), 39 deletions(-)
diff --git a/MediaBrowser.Providers/Lyric/LyricManager.cs b/MediaBrowser.Providers/Lyric/LyricManager.cs
index 698da46867..f5560b0542 100644
--- a/MediaBrowser.Providers/Lyric/LyricManager.cs
+++ b/MediaBrowser.Providers/Lyric/LyricManager.cs
@@ -2,56 +2,20 @@
#pragma warning disable CS1591
-using System;
using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Jellyfin.Extensions;
-using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Lyrics;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Providers;
-using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.Lyric
{
public class LyricManager : ILyricManager
{
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryMonitor _monitor;
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly ILocalizationManager _localization;
+ private readonly ILyricProvider[] _lyricProviders;
- private IEnumerable _lyricProviders;
-
- public LyricManager(
- ILogger logger,
- IFileSystem fileSystem,
- ILibraryMonitor monitor,
- IMediaSourceManager mediaSourceManager,
- ILocalizationManager localizationManager,
- IEnumerable lyricProviders)
+ public LyricManager(IEnumerable lyricProviders)
{
- _logger = logger;
- _fileSystem = fileSystem;
- _monitor = monitor;
- _mediaSourceManager = mediaSourceManager;
- _localization = localizationManager;
- _lyricProviders = lyricProviders;
+ _lyricProviders = lyricProviders.ToArray();
}
///
--
cgit v1.2.3
From 823e2ec029d8708b71452afc7442524823d82acb Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 17 Sep 2022 09:22:07 -0400
Subject: Removing unused lines
---
MediaBrowser.Controller/Lyrics/LyricInfo.cs | 7 -------
MediaBrowser.Controller/Lyrics/LyricResponse.cs | 2 --
MediaBrowser.Providers/Lyric/LrcLyricProvider.cs | 2 --
MediaBrowser.Providers/Lyric/TxtLyricProvider.cs | 3 ---
4 files changed, 14 deletions(-)
diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
index 018f296b1a..ae831b4d23 100644
--- a/MediaBrowser.Controller/Lyrics/LyricInfo.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
@@ -1,12 +1,5 @@
-using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Lyrics;
-using MediaBrowser.Controller.Net;
-using Microsoft.AspNetCore.Mvc;
namespace MediaBrowser.Controller.Lyrics
{
diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
index 498eb873c7..59ee5c7f2c 100644
--- a/MediaBrowser.Controller/Lyrics/LyricResponse.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
@@ -1,7 +1,5 @@
#nullable disable
-#pragma warning disable CS1591
-
using System.Collections.Generic;
namespace MediaBrowser.Controller.Lyrics
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
index 10db10ac6f..ea42d75255 100644
--- a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
@@ -4,8 +4,6 @@ using System.Collections.ObjectModel;
using System.Dynamic;
using System.Globalization;
using System.Linq;
-using System.Threading.Tasks;
-using Jellyfin.Api.Helpers;
using LrcParser.Model;
using LrcParser.Parser;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
index aa222ed97b..8a51d7277c 100644
--- a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs
@@ -2,9 +2,6 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using Jellyfin.Api.Helpers;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Lyrics;
--
cgit v1.2.3
From 7d886116fd3b617cae6884a33b8b545358fa6289 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 17 Sep 2022 10:42:48 -0400
Subject: Var type refinements
---
MediaBrowser.Controller/Lyrics/Lyric.cs | 2 +-
MediaBrowser.Controller/Lyrics/LyricResponse.cs | 4 ++--
MediaBrowser.Providers/Lyric/LrcLyricProvider.cs | 13 +++++++------
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/MediaBrowser.Controller/Lyrics/Lyric.cs b/MediaBrowser.Controller/Lyrics/Lyric.cs
index 56a0a8a72d..35cdabbb9b 100644
--- a/MediaBrowser.Controller/Lyrics/Lyric.cs
+++ b/MediaBrowser.Controller/Lyrics/Lyric.cs
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Lyrics
///
/// Gets or sets the start time in ticks.
///
- public double? Start { get; set; }
+ public long? Start { get; set; }
///
/// Gets or sets the text.
diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
index 59ee5c7f2c..796ca3bc36 100644
--- a/MediaBrowser.Controller/Lyrics/LyricResponse.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
@@ -10,9 +10,9 @@ namespace MediaBrowser.Controller.Lyrics
public class LyricResponse
{
///
- /// Gets or sets MetaData.
+ /// Gets or sets Metadata.
///
- public IDictionary MetaData { get; set; }
+ public IDictionary Metadata { get; set; }
///
/// Gets or sets Lyrics.
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
index ea42d75255..59a172cee2 100644
--- a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
@@ -8,6 +8,7 @@ using LrcParser.Model;
using LrcParser.Parser;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Lyrics;
+using Swashbuckle.AspNetCore.SwaggerGen;
namespace MediaBrowser.Providers.Lyric
{
@@ -56,7 +57,7 @@ namespace MediaBrowser.Providers.Lyric
List lyricList = new List();
List sortedLyricData = new List();
- var metaData = new ExpandoObject() as IDictionary;
+ IDictionary metaData = new Dictionary();
string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath);
try
@@ -77,8 +78,8 @@ namespace MediaBrowser.Providers.Lyric
{
var metaDataField = metaDataRow.Split(":");
- string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal);
- string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal);
+ string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal).Trim();
+ string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal).Trim();
metaData.Add(metaDataFieldName, metaDataFieldValue);
}
@@ -96,13 +97,13 @@ namespace MediaBrowser.Providers.Lyric
for (int i = 0; i < sortedLyricData.Count; i++)
{
var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
- double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000;
- lyricList.Add(new Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+ long ticks = Convert.ToInt64(timeData, new NumberFormatInfo()) * 10000;
+ lyricList.Add(new Controller.Lyrics.Lyric { Start = ticks, Text = sortedLyricData[i].Text });
}
if (metaData.Any())
{
- return new LyricResponse { MetaData = metaData, Lyrics = lyricList };
+ return new LyricResponse { Metadata = metaData, Lyrics = lyricList };
}
return new LyricResponse { Lyrics = lyricList };
--
cgit v1.2.3
From 29932466a9e75f9cf54332be9bb9d39dce238d07 Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 17 Sep 2022 10:55:04 -0400
Subject: Remove commented out code
---
Emby.Server.Implementations/ApplicationHost.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 5edc25952d..3c3c90e61e 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -789,7 +789,6 @@ namespace Emby.Server.Implementations
Resolve().AddParts(GetExports(), GetExports(), GetExports());
Resolve().AddParts(GetExports());
- //Resolve().AddParts(GetExports());
Resolve().AddParts(GetExports());
--
cgit v1.2.3
From c65819221d9a84ec0ae69a243fdcb17bce7aa65f Mon Sep 17 00:00:00 2001
From: 1hitsong <3330318+1hitsong@users.noreply.github.com>
Date: Sat, 17 Sep 2022 17:37:38 -0400
Subject: Code cleanups. Remove pragma commands
---
MediaBrowser.Controller/Lyrics/ILyricManager.cs | 36 ++---
MediaBrowser.Controller/Lyrics/ILyricProvider.cs | 39 +++---
MediaBrowser.Controller/Lyrics/Lyric.cs | 34 +++--
MediaBrowser.Controller/Lyrics/LyricInfo.cs | 39 +++---
MediaBrowser.Controller/Lyrics/LyricResponse.cs | 27 ++--
MediaBrowser.Providers/Lyric/LrcLyricProvider.cs | 152 ++++++++++-----------
MediaBrowser.Providers/Lyric/LyricManager.cs | 72 +++++-----
MediaBrowser.Providers/Lyric/TxtLyricProvider.cs | 86 +++++-------
.../MediaBrowser.Providers.csproj | 1 -
9 files changed, 231 insertions(+), 255 deletions(-)
diff --git a/MediaBrowser.Controller/Lyrics/ILyricManager.cs b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
index c0f78d177d..dad0250f6b 100644
--- a/MediaBrowser.Controller/Lyrics/ILyricManager.cs
+++ b/MediaBrowser.Controller/Lyrics/ILyricManager.cs
@@ -1,23 +1,23 @@
-#pragma warning disable CS1591
-
using MediaBrowser.Controller.Entities;
-namespace MediaBrowser.Controller.Lyrics
+namespace MediaBrowser.Controller.Lyrics;
+
+///
+/// Interface ILyricManager.
+///
+public interface ILyricManager
{
- public interface ILyricManager
- {
- ///
- /// Gets the lyrics.
- ///
- /// The media item.
- /// Lyrics for passed item.
- LyricResponse GetLyrics(BaseItem item);
+ ///
+ /// Gets the lyrics.
+ ///
+ /// The media item.
+ /// Lyrics for passed item.
+ LyricResponse GetLyrics(BaseItem item);
- ///
- /// Checks if requested item has a matching local lyric file.
- ///
- /// The media item.
- /// True if item has a matching lyric file; otherwise false.
- bool HasLyricFile(BaseItem item);
- }
+ ///
+ /// Checks if requested item has a matching local lyric file.
+ ///
+ /// The media item.
+ /// True if item has a matching lyric file; otherwise false.
+ bool HasLyricFile(BaseItem item);
}
diff --git a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
index 5e677ab26f..1b52de255f 100644
--- a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
+++ b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs
@@ -1,29 +1,28 @@
using System.Collections.Generic;
using MediaBrowser.Controller.Entities;
-namespace MediaBrowser.Controller.Lyrics
+namespace MediaBrowser.Controller.Lyrics;
+
+///
+/// Interface ILyricsProvider.
+///
+public interface ILyricProvider
{
///
- /// Interface ILyricsProvider.
+ /// Gets a value indicating the provider name.
///
- public interface ILyricProvider
- {
- ///
- /// Gets a value indicating the provider name.
- ///
- string Name { get; }
+ string Name { get; }
- ///
- /// Gets the supported media types for this provider.
- ///
- /// The supported media types.
- IEnumerable SupportedMediaTypes { get; }
+ ///
+ /// Gets the supported media types for this provider.
+ ///
+ /// The supported media types.
+ IEnumerable SupportedMediaTypes { get; }
- ///
- /// Gets the lyrics.
- ///
- /// The media item.
- /// If found, returns lyrics for passed item; otherwise, null.
- LyricResponse? GetLyrics(BaseItem item);
- }
+ ///
+ /// Gets the lyrics.
+ ///
+ /// The media item.
+ /// If found, returns lyrics for passed item; otherwise, null.
+ LyricResponse? GetLyrics(BaseItem item);
}
diff --git a/MediaBrowser.Controller/Lyrics/Lyric.cs b/MediaBrowser.Controller/Lyrics/Lyric.cs
index 35cdabbb9b..f39fbb0221 100644
--- a/MediaBrowser.Controller/Lyrics/Lyric.cs
+++ b/MediaBrowser.Controller/Lyrics/Lyric.cs
@@ -1,18 +1,28 @@
-namespace MediaBrowser.Controller.Lyrics
+namespace MediaBrowser.Controller.Lyrics;
+
+///
+/// Lyric model.
+///
+public class Lyric
{
///
- /// Lyric model.
+ /// Initializes a new instance of the class.
///
- public class Lyric
+ /// The lyric start time in ticks.
+ /// The lyric text.
+ public Lyric(string text, long? start = null)
{
- ///
- /// Gets or sets the start time in ticks.
- ///
- public long? Start { get; set; }
-
- ///
- /// Gets or sets the text.
- ///
- public string Text { get; set; } = string.Empty;
+ Start = start;
+ Text = text;
}
+
+ ///
+ /// Gets the start time in ticks.
+ ///
+ public long? Start { get; }
+
+ ///
+ /// Gets the text.
+ ///
+ public string Text { get; }
}
diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
index ae831b4d23..61e205b6cc 100644
--- a/MediaBrowser.Controller/Lyrics/LyricInfo.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs
@@ -1,34 +1,29 @@
using System.IO;
-using System.Linq;
-namespace MediaBrowser.Controller.Lyrics
+namespace MediaBrowser.Controller.Lyrics;
+
+///
+/// Lyric helper methods.
+///
+public static class LyricInfo
{
///
- /// Lyric helper methods.
+ /// Gets matching lyric file for a requested item.
///
- public static class LyricInfo
+ /// The lyricProvider interface to use.
+ /// Path of requested item.
+ /// Lyric file path if passed lyric provider's supported media type is found; otherwise, null.
+ public static string? GetLyricFilePath(ILyricProvider lyricProvider, string itemPath)
{
- ///
- /// Gets matching lyric file for a requested item.
- ///
- /// The lyricProvider interface to use.
- /// Path of requested item.
- /// Lyric file path if passed lyric provider's supported media type is found; otherwise, null.
- public static string? GetLyricFilePath(ILyricProvider lyricProvider, string itemPath)
+ foreach (string lyricFileExtension in lyricProvider.SupportedMediaTypes)
{
- if (lyricProvider.SupportedMediaTypes.Any())
+ var lyricFilePath = Path.ChangeExtension(itemPath, lyricFileExtension);
+ if (File.Exists(lyricFilePath))
{
- foreach (string lyricFileExtension in lyricProvider.SupportedMediaTypes)
- {
- string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension);
- if (System.IO.File.Exists(lyricFilePath))
- {
- return lyricFilePath;
- }
- }
+ return lyricFilePath;
}
-
- return null;
}
+
+ return null;
}
}
diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
index 796ca3bc36..e18cb1101e 100644
--- a/MediaBrowser.Controller/Lyrics/LyricResponse.cs
+++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs
@@ -1,22 +1,19 @@
-#nullable disable
-
using System.Collections.Generic;
-namespace MediaBrowser.Controller.Lyrics
+namespace MediaBrowser.Controller.Lyrics;
+
+///
+/// LyricResponse model.
+///
+public class LyricResponse
{
///
- /// LyricResponse model.
+ /// Gets or sets Metadata.
///
- public class LyricResponse
- {
- ///
- /// Gets or sets Metadata.
- ///
- public IDictionary Metadata { get; set; }
+ public IDictionary? Metadata { get; set; }
- ///
- /// Gets or sets Lyrics.
- ///
- public IEnumerable Lyrics { get; set; }
- }
+ ///
+ /// Gets or sets Lyrics.
+ ///
+ public IEnumerable? Lyrics { get; set; }
}
diff --git a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
index 59a172cee2..9bacfc2964 100644
--- a/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
+++ b/MediaBrowser.Providers/Lyric/LrcLyricProvider.cs
@@ -1,112 +1,102 @@
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;
using MediaBrowser.Controller.Lyrics;
-using Swashbuckle.AspNetCore.SwaggerGen;
-namespace MediaBrowser.Providers.Lyric
+namespace MediaBrowser.Providers.Lyric;
+
+///
+/// LRC Lyric Provider.
+///
+public class LrcLyricProvider : ILyricProvider
{
- ///
- /// LRC Lyric Provider.
- ///
- public class LrcLyricProvider : ILyricProvider
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public LrcLyricProvider()
- {
- Name = "LrcLyricProvider";
+ ///
+ public string Name { get; } = "LrcLyricProvider";
- SupportedMediaTypes = new Collection
+ ///
+ public IEnumerable SupportedMediaTypes
+ {
+ get => new Collection
{
"lrc"
};
- }
+ }
- ///
- /// Gets a value indicating the provider name.
- ///
- public string Name { get; }
-
- ///
- /// Gets a value indicating the File Extenstions this provider supports.
- ///
- public IEnumerable SupportedMediaTypes { get; }
-
- ///
- /// Opens lyric file for the requested item, and processes it for API return.
- ///
- /// The item to to process.
- /// If provider can determine lyrics, returns a with or without metadata; otherwise, null.
- public LyricResponse? GetLyrics(BaseItem item)
- {
- string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
+ ///
+ /// Opens lyric file for the requested item, and processes it for API return.
+ ///
+ /// The item to to process.
+ /// If provider can determine lyrics, returns a with or without metadata; otherwise, null.
+ public LyricResponse? GetLyrics(BaseItem item)
+ {
+ string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
- if (string.IsNullOrEmpty(lyricFilePath))
- {
- return null;
- }
+ if (string.IsNullOrEmpty(lyricFilePath))
+ {
+ return null;
+ }
- List lyricList = new List();
- List sortedLyricData = new List();
+ List lyricList = new List();
+ List sortedLyricData = new List();
- IDictionary metaData = new Dictionary();
- string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath);
+ IDictionary metaData = new Dictionary();
+ string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath);
- try
+ 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.First().Value).ToList();
+
+ // Parse metadata rows
+ var metaDataRows = lyricData.Lyrics
+ .Where(x => x.TimeTags.Count == 0)
+ .Where(x => x.Text.StartsWith('[') && x.Text.EndsWith(']'))
+ .Select(x => x.Text)
+ .ToList();
+
+ foreach (string metaDataRow in metaDataRows)
{
- // 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(':');
+ if (metaDataField.Length != 2)
{
- var metaDataField = metaDataRow.Split(":");
-
- string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal).Trim();
- string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal).Trim();
-
- metaData.Add(metaDataFieldName, metaDataFieldValue);
+ continue;
}
- }
- catch
- {
- return null;
- }
- if (!sortedLyricData.Any())
- {
- return null;
- }
+ string metaDataFieldName = metaDataField[0][1..].Trim();
+ string metaDataFieldValue = metaDataField[1][..^1].Trim();
- for (int i = 0; i < sortedLyricData.Count; i++)
- {
- var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
- long ticks = Convert.ToInt64(timeData, new NumberFormatInfo()) * 10000;
- lyricList.Add(new Controller.Lyrics.Lyric { Start = ticks, Text = sortedLyricData[i].Text });
+ metaData.Add(metaDataFieldName, metaDataFieldValue);
}
+ }
+ catch
+ {
+ return null;
+ }
- if (metaData.Any())
- {
- return new LyricResponse { Metadata = metaData, Lyrics = lyricList };
- }
+ if (sortedLyricData.Count == 0)
+ {
+ return null;
+ }
- return new LyricResponse { Lyrics = lyricList };
+ for (int i = 0; i < sortedLyricData.Count; i++)
+ {
+ var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value;
+ long ticks = TimeSpan.FromMilliseconds((double)timeData).Ticks;
+ lyricList.Add(new Controller.Lyrics.Lyric(sortedLyricData[i].Text, ticks));
}
+
+ if (metaData.Any())
+ {
+ return new LyricResponse { Metadata = metaData, Lyrics = lyricList };
+ }
+
+ return new LyricResponse { Lyrics = lyricList };
}
}
diff --git a/MediaBrowser.Providers/Lyric/LyricManager.cs b/MediaBrowser.Providers/Lyric/LyricManager.cs
index f5560b0542..06f913d079 100644
--- a/MediaBrowser.Providers/Lyric/LyricManager.cs
+++ b/MediaBrowser.Providers/Lyric/LyricManager.cs
@@ -1,55 +1,57 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Lyrics;
-namespace MediaBrowser.Providers.Lyric
+namespace MediaBrowser.Providers.Lyric;
+
+///
+/// Lyric Manager.
+///
+public class LyricManager : ILyricManager
{
- public class LyricManager : ILyricManager
- {
- private readonly ILyricProvider[] _lyricProviders;
+ private readonly ILyricProvider[] _lyricProviders;
- public LyricManager(IEnumerable lyricProviders)
- {
- _lyricProviders = lyricProviders.ToArray();
- }
+ ///