2
0
Эх сурвалжийг харах

Auto stash before merge of "lyric-lrc-file-support" and "origin/lyric-lrc-file-support"

1hitsong 2 жил өмнө
parent
commit
d9be3874ba

+ 2 - 0
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;

+ 7 - 2
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<ILiveTvManager> _livetvManagerFactory;
 
+        private readonly IEnumerable<ILyricsProvider> _lyricProviders;
+
         public DtoService(
             ILogger<DtoService> logger,
             ILibraryManager libraryManager,
@@ -60,7 +63,8 @@ namespace Emby.Server.Implementations.Dto
             IProviderManager providerManager,
             IApplicationHost appHost,
             IMediaSourceManager mediaSourceManager,
-            Lazy<ILiveTvManager> livetvManagerFactory)
+            Lazy<ILiveTvManager> livetvManagerFactory,
+            IEnumerable<ILyricsProvider> 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

+ 3 - 2
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)

+ 0 - 106
Jellyfin.Api/Helpers/ItemHelper.cs

@@ -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
-{
-    /// <summary>
-    /// Item helper.
-    /// </summary>
-    public static class ItemHelper
-    {
-        /// <summary>
-        /// Opens lyrics file, converts to a List of Lyrics, and returns it.
-        /// </summary>
-        /// <param name="item">Requested Item.</param>
-        /// <returns>Collection of Lyrics.</returns>
-        internal static 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;
-        }
-
-        /// <summary>
-        /// Checks if requested item has a matching lyric file.
-        /// </summary>
-        /// <param name="itemPath">Path of requested item.</param>
-        /// <returns>True if item has a matching lyrics file.</returns>
-        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;
-        }
-
-
-        /// <summary>
-        /// Checks if requested item has a matching local lyric file.
-        /// </summary>
-        /// <param name="itemPath">Path of requested item.</param>
-        /// <returns>True if item has a matching lyrics file; otherwise false.</returns>
-        public static bool HasLyricFile(string itemPath)
-        {
-            string? lyricFilePath = GetLyricFilePath(itemPath);
-            return !string.IsNullOrEmpty(lyricFilePath);
-        }
-    }
-}

+ 0 - 1
Jellyfin.Api/Jellyfin.Api.csproj

@@ -17,7 +17,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="LrcParser" Version="2022.529.1" />
     <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.8" />
     <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />

+ 0 - 34
Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs

@@ -1,34 +0,0 @@
-using System.Collections.ObjectModel;
-using MediaBrowser.Controller.Entities;
-
-namespace Jellyfin.Api.Models.UserDtos
-{
-    /// <summary>
-    /// Interface ILyricsProvider.
-    /// </summary>
-    public interface ILyricsProvider
-    {
-        /// <summary>
-        /// Gets a value indicating the File Extenstions this provider works with.
-        /// </summary>
-        public Collection<string>? FileExtensions { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether Process() generated data.
-        /// </summary>
-        /// <returns><c>true</c> if data generated; otherwise, <c>false</c>.</returns>
-        bool HasData { get; }
-
-        /// <summary>
-        /// Gets Data object generated by Process() method.
-        /// </summary>
-        /// <returns><c>Object</c> with data if no error occured; otherwise, <c>null</c>.</returns>
-        object? Data { get; }
-
-        /// <summary>
-        /// Opens lyric file for [the specified item], and processes it for API return.
-        /// </summary>
-        /// <param name="item">The item to to process.</param>
-        void Process(BaseItem item);
-    }
-}

+ 24 - 0
MediaBrowser.Controller/Lyrics/ILyricsProvider.cs

@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Lyrics
+{
+    /// <summary>
+    /// Interface ILyricsProvider.
+    /// </summary>
+    public interface ILyricsProvider
+    {
+        /// <summary>
+        /// Gets the supported media types for this provider.
+        /// </summary>
+        /// <value>The supported media types.</value>
+        IEnumerable<string> SupportedMediaTypes { get; }
+
+        /// <summary>
+        /// Gets the lyrics.
+        /// </summary>
+        /// <param name="item">The item to to process.</param>
+        /// <returns>Task{LyricResponse}.</returns>
+        LyricResponse? GetLyrics(BaseItem item);
+    }
+}

+ 1 - 1
Jellyfin.Api/Models/UserDtos/Lyric.cs → MediaBrowser.Controller/Lyrics/Lyric.cs

@@ -1,4 +1,4 @@
-namespace Jellyfin.Api.Models.UserDtos
+namespace MediaBrowser.Controller.Lyrics
 {
     /// <summary>
     /// Lyric dto.

+ 87 - 0
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
+{
+    /// <summary>
+    /// Item helper.
+    /// </summary>
+    public class LyricInfo
+    {
+        /// <summary>
+        /// Opens lyrics file, converts to a List of Lyrics, and returns it.
+        /// </summary>
+        /// <param name="lyricProviders">Collection of all registered <see cref="ILyricsProvider"/> interfaces.</param>
+        /// <param name="item">Requested Item.</param>
+        /// <returns>Collection of Lyrics.</returns>
+        public static LyricResponse? GetLyricData(IEnumerable<ILyricsProvider> 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<Lyric>
+                {
+                    new Lyric { Start = 0, Text = "Test" }
+                }
+            };
+        }
+
+        /// <summary>
+        /// Checks if requested item has a matching lyric file.
+        /// </summary>
+        /// <param name="lyricProvider">The current lyricProvider interface.</param>
+        /// <param name="itemPath">Path of requested item.</param>
+        /// <returns>True if item has a matching lyrics file.</returns>
+        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;
+        }
+
+        /// <summary>
+        /// Checks if requested item has a matching local lyric file.
+        /// </summary>
+        /// <param name="lyricProviders">Collection of all registered <see cref="ILyricsProvider"/> interfaces.</param>
+        /// <param name="itemPath">Path of requested item.</param>
+        /// <returns>True if item has a matching lyrics file; otherwise false.</returns>
+        public static bool HasLyricFile(IEnumerable<ILyricsProvider> lyricProviders, string itemPath)
+        {
+            foreach (var provider in lyricProviders)
+            {
+                if (GetLyricFilePath(provider, itemPath) is not null)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}

+ 15 - 0
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<string, object> MetaData { get; set; }
+
+        public IEnumerable<Lyric> Lyrics { get; set; }
+    }
+}

+ 1 - 1
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; }
 

+ 17 - 22
Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs → MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs

@@ -4,11 +4,14 @@ 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 Jellyfin.Api.Models.UserDtos
+namespace MediaBrowser.Providers.Lyric
 {
     /// <summary>
     /// LRC File Lyric Provider.
@@ -20,7 +23,7 @@ namespace Jellyfin.Api.Models.UserDtos
         /// </summary>
         public LrcLyricsProvider()
         {
-            FileExtensions = new Collection<string>
+            SupportedMediaTypes = new Collection<string>
             {
                 "lrc"
             };
@@ -29,13 +32,7 @@ namespace Jellyfin.Api.Models.UserDtos
         /// <summary>
         /// Gets a value indicating the File Extenstions this provider works with.
         /// </summary>
-        public Collection<string>? FileExtensions { get; }
-
-        /// <summary>
-        /// Gets or Sets a value indicating whether Process() generated data.
-        /// </summary>
-        /// <returns><c>true</c> if data generated; otherwise, <c>false</c>.</returns>
-        public bool HasData { get; set; }
+        public IEnumerable<string> SupportedMediaTypes { get; }
 
         /// <summary>
         /// Gets or Sets Data object generated by Process() method.
@@ -47,16 +44,17 @@ namespace Jellyfin.Api.Models.UserDtos
         /// Opens lyric file for [the specified item], and processes it for API return.
         /// </summary>
         /// <param name="item">The item to to process.</param>
-        public void Process(BaseItem item)
+        /// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
+        public LyricResponse? GetLyrics(BaseItem item)
         {
-            string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
+            string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
 
             if (string.IsNullOrEmpty(lyricFilePath))
             {
-                return;
+                return null;
             }
 
-            List<Lyric> lyricsList = new List<Lyric>();
+            List<MediaBrowser.Controller.Lyrics.Lyric> lyricsList = new List<MediaBrowser.Controller.Lyrics.Lyric>();
 
             List<LrcParser.Model.Lyric> sortedLyricData = new List<LrcParser.Model.Lyric>();
             var metaData = new ExpandoObject() as IDictionary<string, object>;
@@ -88,30 +86,27 @@ namespace Jellyfin.Api.Models.UserDtos
             }
             catch
             {
-                return;
+                return null;
             }
 
             if (!sortedLyricData.Any())
             {
-                return;
+                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 Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text });
+                lyricsList.Add(new MediaBrowser.Controller.Lyrics.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 };
+               return new LyricResponse { MetaData = metaData, Lyrics = lyricsList };
             }
+
+            return new LyricResponse { Lyrics = lyricsList };
         }
     }
 }

+ 14 - 21
Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs → MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs

@@ -1,14 +1,13 @@
 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 System.Threading.Tasks;
+using Jellyfin.Api.Helpers;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Lyrics;
 
-namespace Jellyfin.Api.Models.UserDtos
+namespace MediaBrowser.Providers.Lyric
 {
     /// <summary>
     /// TXT File Lyric Provider.
@@ -20,7 +19,7 @@ namespace Jellyfin.Api.Models.UserDtos
         /// </summary>
         public TxtLyricsProvider()
         {
-            FileExtensions = new Collection<string>
+            SupportedMediaTypes = new Collection<string>
             {
                 "lrc", "txt"
             };
@@ -29,13 +28,7 @@ namespace Jellyfin.Api.Models.UserDtos
         /// <summary>
         /// Gets a value indicating the File Extenstions this provider works with.
         /// </summary>
-        public Collection<string>? FileExtensions { get; }
-
-        /// <summary>
-        /// Gets or Sets a value indicating whether Process() generated data.
-        /// </summary>
-        /// <returns><c>true</c> if data generated; otherwise, <c>false</c>.</returns>
-        public bool HasData { get; set; }
+        public IEnumerable<string> SupportedMediaTypes { get; }
 
         /// <summary>
         /// Gets or Sets Data object generated by Process() method.
@@ -47,16 +40,17 @@ namespace Jellyfin.Api.Models.UserDtos
         /// Opens lyric file for [the specified item], and processes it for API return.
         /// </summary>
         /// <param name="item">The item to to process.</param>
-        public void Process(BaseItem item)
+        /// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
+        public LyricResponse? GetLyrics(BaseItem item)
         {
-            string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path);
+            string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path);
 
             if (string.IsNullOrEmpty(lyricFilePath))
             {
-                return;
+                return null;
             }
 
-            List<Lyric> lyricsList = new List<Lyric>();
+            List<MediaBrowser.Controller.Lyrics.Lyric> lyricsList = new List<MediaBrowser.Controller.Lyrics.Lyric>();
 
             string lyricData = System.IO.File.ReadAllText(lyricFilePath);
 
@@ -66,16 +60,15 @@ namespace Jellyfin.Api.Models.UserDtos
 
             if (!lyricTextLines.Any())
             {
-                return;
+                return null;
             }
 
             foreach (string lyricLine in lyricTextLines)
             {
-                lyricsList.Add(new Lyric { Text = lyricLine });
+                lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine });
             }
 
-            this.HasData = true;
-            this.Data = new { lyrics = lyricsList };
+            return new LyricResponse { Lyrics = lyricsList };
         }
     }
 }

+ 2 - 0
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -6,6 +6,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <ProjectReference Include="..\Jellyfin.Api\Jellyfin.Api.csproj" />
     <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
     <ProjectReference Include="..\DvdLib\DvdLib.csproj" />
@@ -16,6 +17,7 @@
   </ItemGroup>
 
   <ItemGroup>
+    <PackageReference Include="LrcParser" Version="2022.529.1" />
     <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
     <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
     <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />