Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lyrics.Java support #148

Merged
merged 19 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
[![Lavalink4NET Support Server Banner](https://discordapp.com/api/guilds/894533462428635146/embed.png?style=banner3)](https://discord.gg/cD4qTmnqRg)

### Features

- ⚖️ **Node Clustering / Load Balancing**<br>Distribute load across nodes for efficient and reliable audio playback (for large scale bots).

- ✳️ **Extensible**<br>Customize and enhance features using plugins to match your bot's needs.
Expand Down Expand Up @@ -42,7 +43,7 @@
- 📊 **Statistics tracking support**<br>Lavalink4NET supports tracking and evaluation of node statistics. In clustering, node statistics can be used to evaluate the best node for efficient resource usage.

- ➕ **Compatible with [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus), [Discord.Net](https://github.com/discord-net/Discord.Net), [Remora](https://github.com/Remora/Remora.Discord), and [NetCord](https://github.com/KubaZ2/NetCord).**<br>Lavalink4NET has an adaptive client API, meaning it can support any discord client. Currently, DSharpPlus, Discord.Net, Remora and NetCord are supported out-of-the-box.

### Documentation

> [!IMPORTANT]
Expand Down Expand Up @@ -74,6 +75,8 @@ Lavalink4NET offers high flexibility and extensibility by providing an isolated

- [**Lavalink4NET.Integrations.TextToSpeech**](https://www.nuget.org/packages/Lavalink4NET.Integrations.TextToSpeech/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.Integrations.TextToSpeech.svg?style=flat-square)<br>Enable text-to-speech functionality in Lavalink4NET. Convert written text into spoken words, allowing your application to generate and play audio from text inputs. Requires the installation of the corresponding plugin on the Lavalink node.

- [**Lavalink4NET.Integrations.LyricsJava**](https://www.nuget.org/packages/Lavalink4NET.Integrations.LyricsJava/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.Integrations.LyricsJava.svg?style=flat-square)<br>Fetch timed lyrics from youtube or non-timed lyrics from genius. Automatically fetches lyrics for the current track. Requires the installation of the corresponding plugin on the Lavalink node.

#### _Services_

- [**Lavalink4NET.Lyrics**](https://www.nuget.org/packages/Lavalink4NET.Lyrics/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.Lyrics.svg?style=flat-square)<br>Fetch and display song lyrics from lyrics.ovh with this lyrics service integrated with Lavalink4NET. Enhance the music experience for your users.
Expand All @@ -84,7 +87,7 @@ Lavalink4NET offers high flexibility and extensibility by providing an isolated

#### _Core Components_

- [**Lavalink4NET**](https://www.nuget.org/packages/Lavalink4NET/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.svg?style=flat-square)<br>This core library is used to implement client wrappers. It is not intended for end users. Please use Lavalink4NET.Discord.Net, Lavalink4NET.DSharpPlus, Lavalink4NET.Remora.Discord or Lavalink4NET.NetCord instead.
- [**Lavalink4NET**](https://www.nuget.org/packages/Lavalink4NET/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.svg?style=flat-square)<br>This core library is used to implement client wrappers. It is not intended for end users. Please use Lavalink4NET.Discord.Net, Lavalink4NET.DSharpPlus, Lavalink4NET.Remora.Discord or Lavalink4NET.NetCord instead.

- [**Lavalink4NET.Abstractions**](https://www.nuget.org/packages/Lavalink4NET.Abstractions/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.Abstractions.svg?style=flat-square)<br>General abstractions and common primitives for the Lavalink4NET client library.

Expand All @@ -93,6 +96,7 @@ Lavalink4NET offers high flexibility and extensibility by providing an isolated
- [**Lavalink4NET.Rest**](https://www.nuget.org/packages/Lavalink4NET.Rest/)&nbsp;&nbsp;&nbsp;![NuGet](https://img.shields.io/nuget/vpre/Lavalink4NET.Rest.svg?style=flat-square)<br>Easily interact with the Lavalink REST API using this REST API client primitives library. Build custom functionalities or integrate Lavalink4NET with other services.

### Prerequisites

- At least one lavalink node
- At least .NET 6

Expand Down Expand Up @@ -124,7 +128,7 @@ var playerOptions = new LavalinkPlayerOptions
};

await audioService.Players
.JoinAsync(<guild id>, <voice channel id>, playerOptions, stoppingToken)
.JoinAsync(<guild id>, <voice channel id>, playerOptions, stoppingToken)
.ConfigureAwait(false);
```

Expand Down
78 changes: 78 additions & 0 deletions docs/docs/integrations/lyricsjava.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Lyrics.Java

The Lyrics.Java plugin for Lavalink allows you to fetch lyrics from YouTube or genius. The plugin will automatically fetch lyrics for the current track.

Lavalink4NET provides an integration for the Lyrics.Java plugin with the [`Lavalink4NET.Integrations.LyricsJava`](https://www.nuget.org/packages/Lavalink4NET.Integrations.LyricsJava) package.

## Installation

For using Lyrics.Java, you need to install the [`Lavalink4NET.Integrations.LyricsJava`](https://www.nuget.org/packages/Lavalink4NET.Integrations.LyricsJava) package.

:::caution
You need to have the [LyricsJava](https://github.com/DuncteBot/java-timed-lyrics) plugin installed on your Lavalink server.
:::

## Usage

First, you need to integrate the LyricsJava plugin with Lavalink4NET. You can do this by calling `UseLyricsJava` on either the host or the audio service:

```csharp
var app = builder.Build();

app.UseLyricsJava();

app.Run();
```

That's it! The LyricsJava plugin is now integrated with Lavalink4NET.

### Getting lyrics for the current track

For getting the lyrics of the current track, you can use the `GetCurrentTrackLyricsAsync` method. This method will return the lyrics of the current track. The method requires the session id and the guild id both of which you can get from player properties.

```csharp
var player = await audioService.Players
.GetPlayerAsync(guildId)
.ConfigureAwait(false);

var lyrics = await audioService.Tracks
.GetCurrentTrackLyricsAsync(player)
.ConfigureAwait(false);
```

### Getting lyrics from youtube

For getting the lyrics of a youtube video, you can use the `GetYoutubeLyricsAsync` method. This method will return the lyrics of the youtube video. The method requires a youtube video id, which can be acquired by using the `SearchAsync` method if using a different provider (e.g. Spotify).

```csharp
var results = await AudioService.Tracks
.SearchLyricsAsync("Queen - Bohemian Rhapsody")
.ConfigureAwait(false);

var videoId = results.First().VideoId;

var lyrics = await AudioService.Tracks
.GetYouTubeLyricsAsync(videoId) // Youtube Video Id (e.g. dQw4w9WgXcQ)
.ConfigureAwait(false);
```

### Getting lyrics from genius

For getting the lyrics of a song from genius, you can use the `GetGeniusLyricsAsync` method. This method will return the lyrics of the song. The method requires the song name and the artist name.

```csharp
var lyrics = await AudioService.Tracks
.GetGeniusLyricsAsync("Queen - Bohemian Rhapsody")
.ConfigureAwait(false);
```

## Player listener

Similar to the inactivity tracking service, the LyricsJava integration also implements a player listener for receiving event notifications. The player listener can be used to receive notifications for when the lyrics of the current track has been loaded.

```csharp
public interface ILavaLyricsPlayerListener : ILavalinkPlayerListener
{
ValueTask NotifyLyricsLoadedAsync(Lyrics lyrics, CancellationToken cancellationToken = default);
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
namespace Lavalink4NET.Rest.Tests;

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebSockets;

[ExcludeFromCodeCoverage]
internal sealed class HttpClientFactory : IHttpClientFactory, IAsyncDisposable
{
private int _state; // 0 = build, 1 = run, 2 = disposed
private readonly WebApplication _application;

public HttpClientFactory()
{
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
builder.Services.AddWebSockets(x => { });

_application = builder.Build();
}

public void Start()
{
var state = Interlocked.CompareExchange(ref _state, 1, 0);
ObjectDisposedException.ThrowIf(state is 2, this);

if (state is 1)
{
throw new InvalidOperationException("The application is already running.");
}

Debug.Assert(state is 0);
_ = _application.RunAsync();
}

public WebApplication Application
{
get
{
ObjectDisposedException.ThrowIf(_state is 2, this);

if (_state is not 0)
{
throw new InvalidOperationException("The application can not be accessed after starting it.");
}

return _application;
}
}

public HttpClient CreateClient(string name)
{
ObjectDisposedException.ThrowIf(_state is 2, this);

if (_state is not 1)
{
throw new InvalidOperationException("The application must be started before creating a client.");
}

return _application.GetTestServer().CreateClient();
}

public ValueTask DisposeAsync()
{
var state = Interlocked.CompareExchange(ref _state, 2, 1);

if (state is not 1)
{
return default;
}

return _application.DisposeAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Lavalink4NET.Integrations.LyricsJava\Lavalink4NET.Integrations.LyricsJava.csproj" />
</ItemGroup>

</Project>
Loading
Loading