Store lyrics in the database as media streams (#9951)

This commit is contained in:
Cody Robibero
2024-02-26 05:09:40 -07:00
committed by GitHub
parent 59f50ae8b2
commit 0bc41c015f
49 changed files with 1481 additions and 262 deletions

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
@@ -27,6 +28,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
Artists = Array.Empty<string>();
AlbumArtists = Array.Empty<string>();
LyricFiles = Array.Empty<string>();
}
/// <inheritdoc />
@@ -65,6 +67,16 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override MediaType MediaType => MediaType.Audio;
/// <summary>
/// Gets or sets a value indicating whether this audio has lyrics.
/// </summary>
public bool? HasLyrics { get; set; }
/// <summary>
/// Gets or sets the list of lyric paths.
/// </summary>
public IReadOnlyList<string> LyricFiles { get; set; }
public override double GetDefaultPrimaryImageAspectRatio()
{
return 1;

View File

@@ -168,6 +168,15 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns>
BaseItem GetItemById(Guid id);
/// <summary>
/// Gets the item by id, as T.
/// </summary>
/// <param name="id">The item id.</param>
/// <typeparam name="T">The type of item.</typeparam>
/// <returns>The item.</returns>
T GetItemById<T>(Guid id)
where T : BaseItem;
/// <summary>
/// Gets the intros.
/// </summary>

View File

@@ -1,5 +1,12 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Lyrics;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Lyrics;
@@ -9,16 +16,93 @@ namespace MediaBrowser.Controller.Lyrics;
public interface ILyricManager
{
/// <summary>
/// Gets the lyrics.
/// Occurs when a lyric download fails.
/// </summary>
/// <param name="item">The media item.</param>
/// <returns>A task representing found lyrics the passed item.</returns>
Task<LyricResponse?> GetLyrics(BaseItem item);
event EventHandler<LyricDownloadFailureEventArgs> LyricDownloadFailure;
/// <summary>
/// Checks if requested item has a matching local lyric file.
/// Search for lyrics for the specified song.
/// </summary>
/// <param name="item">The media item.</param>
/// <returns>True if item has a matching lyric file; otherwise false.</returns>
bool HasLyricFile(BaseItem item);
/// <param name="audio">The song.</param>
/// <param name="isAutomated">Whether the request is automated.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>The list of lyrics.</returns>
Task<IReadOnlyList<RemoteLyricInfoDto>> SearchLyricsAsync(
Audio audio,
bool isAutomated,
CancellationToken cancellationToken);
/// <summary>
/// Search for lyrics.
/// </summary>
/// <param name="request">The search request.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>The list of lyrics.</returns>
Task<IReadOnlyList<RemoteLyricInfoDto>> SearchLyricsAsync(
LyricSearchRequest request,
CancellationToken cancellationToken);
/// <summary>
/// Download the lyrics.
/// </summary>
/// <param name="audio">The audio.</param>
/// <param name="lyricId">The remote lyric id.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>The downloaded lyrics.</returns>
Task<LyricDto?> DownloadLyricsAsync(
Audio audio,
string lyricId,
CancellationToken cancellationToken);
/// <summary>
/// Download the lyrics.
/// </summary>
/// <param name="audio">The audio.</param>
/// <param name="libraryOptions">The library options to use.</param>
/// <param name="lyricId">The remote lyric id.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>The downloaded lyrics.</returns>
Task<LyricDto?> DownloadLyricsAsync(
Audio audio,
LibraryOptions libraryOptions,
string lyricId,
CancellationToken cancellationToken);
/// <summary>
/// Upload new lyrics.
/// </summary>
/// <param name="audio">The audio file the lyrics belong to.</param>
/// <param name="lyricResponse">The lyric response.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task<LyricDto?> UploadLyricAsync(Audio audio, LyricResponse lyricResponse);
/// <summary>
/// Get the remote lyrics.
/// </summary>
/// <param name="id">The remote lyrics id.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>The lyric response.</returns>
Task<LyricDto?> GetRemoteLyricsAsync(string id, CancellationToken cancellationToken);
/// <summary>
/// Deletes the lyrics.
/// </summary>
/// <param name="audio">The audio file to remove lyrics from.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task DeleteLyricsAsync(Audio audio);
/// <summary>
/// Get the list of lyric providers.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>Lyric providers.</returns>
IReadOnlyList<LyricProviderInfo> GetSupportedProviders(BaseItem item);
/// <summary>
/// Get the existing lyric for the audio.
/// </summary>
/// <param name="audio">The audio item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The parsed lyric model.</returns>
Task<LyricDto?> GetLyricsAsync(Audio audio, CancellationToken cancellationToken);
}

View File

@@ -1,5 +1,5 @@
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Providers.Lyric;
using MediaBrowser.Model.Lyrics;
namespace MediaBrowser.Controller.Lyrics;
@@ -24,5 +24,5 @@ public interface ILyricParser
/// </summary>
/// <param name="lyrics">The raw lyrics content.</param>
/// <returns>The parsed lyrics or null if invalid.</returns>
LyricResponse? ParseLyrics(LyricFile lyrics);
LyricDto? ParseLyrics(LyricFile lyrics);
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Lyrics;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Lyrics;
/// <summary>
/// Interface ILyricsProvider.
/// </summary>
public interface ILyricProvider
{
/// <summary>
/// Gets the provider name.
/// </summary>
string Name { get; }
/// <summary>
/// Search for lyrics.
/// </summary>
/// <param name="request">The search request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The list of remote lyrics.</returns>
Task<IEnumerable<RemoteLyricInfo>> SearchAsync(LyricSearchRequest request, CancellationToken cancellationToken);
/// <summary>
/// Get the lyrics.
/// </summary>
/// <param name="id">The remote lyric id.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The lyric response.</returns>
Task<LyricResponse?> GetLyricsAsync(string id, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,26 @@
using System;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Lyrics
{
/// <summary>
/// An event that occurs when subtitle downloading fails.
/// </summary>
public class LyricDownloadFailureEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the item.
/// </summary>
public required BaseItem Item { get; set; }
/// <summary>
/// Gets or sets the provider.
/// </summary>
public required string Provider { get; set; }
/// <summary>
/// Gets or sets the exception.
/// </summary>
public required Exception Exception { get; set; }
}
}

View File

@@ -1,28 +0,0 @@
namespace MediaBrowser.Providers.Lyric;
/// <summary>
/// The information for a raw lyrics file before parsing.
/// </summary>
public class LyricFile
{
/// <summary>
/// Initializes a new instance of the <see cref="LyricFile"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="content">The content, must not be empty.</param>
public LyricFile(string name, string content)
{
Name = name;
Content = content;
}
/// <summary>
/// Gets or sets the name of the lyrics file. This must include the file extension.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the contents of the file.
/// </summary>
public string Content { get; set; }
}

View File

@@ -1,28 +0,0 @@
namespace MediaBrowser.Controller.Lyrics;
/// <summary>
/// Lyric model.
/// </summary>
public class LyricLine
{
/// <summary>
/// Initializes a new instance of the <see cref="LyricLine"/> class.
/// </summary>
/// <param name="text">The lyric text.</param>
/// <param name="start">The lyric start time in ticks.</param>
public LyricLine(string text, long? start = null)
{
Text = text;
Start = start;
}
/// <summary>
/// Gets the text of this lyric line.
/// </summary>
public string Text { get; }
/// <summary>
/// Gets the start time in ticks.
/// </summary>
public long? Start { get; }
}

View File

@@ -1,52 +0,0 @@
namespace MediaBrowser.Controller.Lyrics;
/// <summary>
/// LyricMetadata model.
/// </summary>
public class LyricMetadata
{
/// <summary>
/// Gets or sets the song artist.
/// </summary>
public string? Artist { get; set; }
/// <summary>
/// Gets or sets the album this song is on.
/// </summary>
public string? Album { get; set; }
/// <summary>
/// Gets or sets the title of the song.
/// </summary>
public string? Title { get; set; }
/// <summary>
/// Gets or sets the author of the lyric data.
/// </summary>
public string? Author { get; set; }
/// <summary>
/// Gets or sets the length of the song in ticks.
/// </summary>
public long? Length { get; set; }
/// <summary>
/// Gets or sets who the LRC file was created by.
/// </summary>
public string? By { get; set; }
/// <summary>
/// Gets or sets the lyric offset compared to audio in ticks.
/// </summary>
public long? Offset { get; set; }
/// <summary>
/// Gets or sets the software used to create the LRC file.
/// </summary>
public string? Creator { get; set; }
/// <summary>
/// Gets or sets the version of the creator used.
/// </summary>
public string? Version { get; set; }
}

View File

@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Lyrics;
/// <summary>
/// LyricResponse model.
/// </summary>
public class LyricResponse
{
/// <summary>
/// Gets or sets Metadata for the lyrics.
/// </summary>
public LyricMetadata Metadata { get; set; } = new();
/// <summary>
/// Gets or sets a collection of individual lyric lines.
/// </summary>
public IReadOnlyList<LyricLine> Lyrics { get; set; } = Array.Empty<LyricLine>();
}