-
-
Notifications
You must be signed in to change notification settings - Fork 39
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
Enhance queue management and interaction response #617
Conversation
A few minor things I fixed:
|
To
I have no problem with adding it, but I don't think it'll be in use for long since discord is changing some stuff cough #601 cough |
got it |
no its fine, we'll leave it in |
We just have to test it out Solid work, many thanks |
Anyone? |
Hi sorry, Been a rough month. Looking at it right now |
- Introduced a new `EditResponseAsync` method for string content. - Created `DefaultQueueEntry` class for track playback handling. - Updated `LavalinkConfiguration` with a customizable `QueueEntryFactory`. - Refactored `LavalinkGuildPlayer` to utilize a static `QueueInternal` for guild-specific queues. - Deprecated the `QueueEntries` property in favor of the new `Queue` property. - Implemented a new thread-safe `LavalinkQueue<T>` class for queue operations.
We don't use Obsolete anymore, instead we use Deprecated. We distribute our own code analyzers.
Signed-off-by: Lala Sabathil <[email protected]>
Could you possibly add a function Would appreciate it <3 |
Tested with the following code, working so far: LavalinkConfiguration config = new()
{
// ..
QueueEntryFactory = () => new QueueEntryFactory()
} public record QueueEntryFactory : IQueueEntry
{
public LavalinkTrack Track { get; set; } = default!;
public async Task AfterPlayingAsync(LavalinkGuildPlayer player)
{
await player.Channel.SendMessageAsync($"Track ended: {this.Track.Info.Title}-{player.Guild.Name}");
}
public async Task<bool> BeforePlayingAsync(LavalinkGuildPlayer player)
{
await player.Channel.SendMessageAsync($"Track Started: {this.Track.Info.Title}-{player.Guild.Name}");
return await Task.FromResult(true);
}
} [SlashCommand("queue_test", "Lavalink queue test")]
public async Task TestQueueAsync(InteractionContext ctx, [Option("channel", "Voice channel"), ChannelTypes(ChannelType.Voice)] DiscordChannel voiceChannel)
{
await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent("Trying PR"));
try
{
ArgumentNullException.ThrowIfNull(ctx.Guild);
var ll = ctx.Client.GetLavalink();
var sess = ll.ConnectedSessions.First().Value!;
var gp = await sess.ConnectAsync(voiceChannel);
List<string> urls = ["https://open.spotify.com/track/5GMzkOyhJHgMx1V7K00AzP?si=919a2d7b0db54367", "https://open.spotify.com/track/1gH07IJaAPtPlXBQDefLl6?si=d19d294f29784d09"];
foreach (var url in urls)
{
var s = await gp.LoadTracksAsync(url);
LavalinkTrack? track;
switch (s.LoadType)
{
case LavalinkLoadResultType.Error:
{
var ex = s.GetResultAs<LavalinkException>();
await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AsEphemeral().AddEmbed(new DiscordEmbedBuilder().WithTitle("Failed to load")
.WithDescription("Loading this song/playlist failed, please try again, reasons could be:\n" + "> Playlist is set to private or unlisted\n" + "> The song is unavailable/deleted").Build()));
ctx.Client.Logger.LogError($"Message: {ex.Message}\nCause: {ex.Cause}");
continue;
}
case LavalinkLoadResultType.Empty:
{
await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AsEphemeral()
.AddEmbed(new DiscordEmbedBuilder().WithTitle("Failed to load").WithDescription("No song/playlist was found with this URL, please try again/a different one").Build()));
continue;
}
case LavalinkLoadResultType.Playlist:
{
var pl = s.GetResultAs<LavalinkPlaylist>();
track = pl.Tracks.First();
break;
}
case LavalinkLoadResultType.Track:
{
track = s.GetResultAs<LavalinkTrack>();
break;
}
case LavalinkLoadResultType.Search:
default:
continue;
}
if (track is not null)
gp.AddToQueue(track);
}
gp.PlayQueue();
}
catch (Exception ex)
{
await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent("Error"));
ctx.Client.Logger.LogError(ex.Message);
ctx.Client.Logger.LogError(ex.StackTrace);
if (ex is BadRequestException ex2)
ctx.Client.Logger.LogError(ex2.WebResponse.Response);
}
} server:
port: 2333
address: 0.0.0.0
http2:
enabled: false
plugins:
youtube:
enabled: true
allowSearch: true
allowDirectVideoIds: true
allowDirectPlaylistIds: true
clients:
- M_WEB
- WEB
- MUSIC
- WEBEMBEDDED
- ANDROID_VR
- TV
- TVHTML5EMBEDDED
oauth:
enabled: true
skipInitialization: false
refreshToken: "<redacted>"
pot:
token: "<redacted>"
visitorData: "<redacted>"
lavasrc:
providers:
- "ytsearch:\"%ISRC%\""
- "ytsearch:%QUERY%"
- "scsearch:%QUERY%"
- "spsearch:%QUERY%"
- "sprec:%QUERY%"
- "ymsearch:%QUERY%"
#- "amsearch:%QUERY%"
#- "dzisrc:%ISRC%"
#- "dzsearch:%QUERY%"
- "ymsearch:%QUERY%"
sources:
spotify: true
applemusic: false
deezer: false
yandexmusic: true
flowerytts: true
vkmusic: false
youtube: true
lyrics-sources:
spotify: true
deezer: false
youtube: true
yandexmusic: true
vkmusic: false
spotify:
clientId: "<redacted>"
clientSecret: "<redacted>"
spDc: "<redacted>"
playlistLoadLimit: 6
albumLoadLimit: 6
resolveArtistsInSearch: false
localFiles: true
yandexmusic:
accessToken: "<redacted>"
playlistLoadLimit: 1
albumLoadLimit: 1
artistLoadLimit: 1
flowerytts:
voice: "default voice"
translate: false
silence: 0
speed: 1.0
audioFormat: "mp3"
lavalink:
plugins:
- dependency: "dev.lavalink.youtube:youtube-plugin:1.11.3"
snapshot: false
- dependency: "com.github.topi314.lavasearch:lavasearch-plugin:1.0.0"
repository: "https://maven.lavalink.dev/releases"
snapshot: false
- dependency: "com.github.topi314.lavasrc:lavasrc-plugin:4.3.0"
repository: "https://maven.lavalink.dev/releases"
snapshot: false
- dependency: "com.github.topi314.sponsorblock:sponsorblock-plugin:3.0.0"
repository: "https://maven.lavalink.dev/releases"
snapshot: false
server:
password: "<redacted>"
sources:
youtube: false
bandcamp: true
soundcloud: true
twitch: true
vimeo: true
http: true
local: true
nico: true
filters:
volume: true
equalizer: true
karaoke: true
timescale: true
tremolo: true
vibrato: true
distortion: true
rotation: true
channelMix: true
lowPass: true
bufferDurationMs: 400
frameBufferDurationMs: 5000
opusEncodingQuality: 10
resamplingQuality: MEDIUM
trackStuckThresholdMs: 10000
useSeekGhosting: true
youtubePlaylistLoadLimit: 6
playerUpdateInterval: 5
youtubeSearchEnabled: true
soundcloudSearchEnabled: true
gc-warnings: true
metrics:
prometheus:
enabled: false
endpoint: /metrics
sentry:
dsn: ""
environment: "dev"
logging:
file:
path: ./logs/
level:
root: INFO
lavalink: INFO
dev.lavalink.youtube.http.YoutubeOauth2Handler: INFO
request:
enabled: true
includeClientInfo: true
includeHeaders: false
includeQueryString: true
includePayload: true
maxPayloadLength: 10000
logback:
rollingpolicy:
max-file-size: 1GB
max-history: 30 services:
lavalink:
image: ghcr.io/lavalink-devs/lavalink:4
container_name: lavalink
restart: unless-stopped
environment:
- _JAVA_OPTIONS=-Xmx6G
- SERVER_PORT=2333
volumes:
- ./application.yml:/opt/Lavalink/application.yml
- ./plugins/:/opt/Lavalink/plugins/
- ./music/:/opt/Lavalink/music/
networks:
- lavalink
expose:
- 2333
ports:
- "2333:2333"
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
lavalink:
name: lavalink |
|
I've got another idea, if it's not too much, otherwise I'll do it later. Something like
As example, loading https://youtube.com/playlist?list=PLTfsFojBr0EA73rCVGlphc4z_hcC8PCEc&si=Oz-v7xCpTO2rTZlN through {
"loadType": "playlist",
"data": {
"info": {
"name": "Nice Songs UwU",
"selectedTrack": -1
},
"pluginInfo": {},
"tracks": [
{
"encoded": "QAAAowMADkknbSBHb2luZyBMaWtlAAdIYWxsbWFuAAAAAAAC1pAAC3hUMlo0MElYU0NvAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9eFQyWjQwSVhTQ28BADBodHRwczovL2kueXRpbWcuY29tL3ZpL3hUMlo0MElYU0NvL21xZGVmYXVsdC5qcGcAAAd5b3V0dWJlAAAAAAAAAAA=",
"info": {
"identifier": "xT2Z40IXSCo",
"isSeekable": true,
"author": "Hallman",
"length": 186000,
"isStream": false,
"position": 0,
"title": "I'm Going Like",
"uri": "https://www.youtube.com/watch?v=xT2Z40IXSCo",
"sourceName": "youtube",
"artworkUrl": "https://i.ytimg.com/vi/xT2Z40IXSCo/mqdefault.jpg",
"isrc": null
},
"pluginInfo": {},
"userData": {}
},
{
"encoded": "QAAAsAMADFRlY2hubyBUYXViZQAWVGhlIEhvbHkgU2FudGEgQmFyYmFyYQAAAAAAAjpQAAs1aGozZG1tNlh3MAABACtodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PTVoajNkbW02WHcwAQAwaHR0cHM6Ly9pLnl0aW1nLmNvbS92aS81aGozZG1tNlh3MC9tcWRlZmF1bHQuanBnAAAHeW91dHViZQAAAAAAAAAA",
"info": {
"identifier": "5hj3dmm6Xw0",
"isSeekable": true,
"author": "The Holy Santa Barbara",
"length": 146000,
"isStream": false,
"position": 0,
"title": "Techno Taube",
"uri": "https://www.youtube.com/watch?v=5hj3dmm6Xw0",
"sourceName": "youtube",
"artworkUrl": "https://i.ytimg.com/vi/5hj3dmm6Xw0/mqdefault.jpg",
"isrc": null
},
"pluginInfo": {},
"userData": {}
}
]
}
} Which can be loaded through GetResultAs<LavalinkPlaylist>() |
- Introduced `AddToQueue(LavalinkPlaylist playlist)` method in `LavalinkGuildPlayer` to add all tracks from a playlist to the queue. - Updated documentation to cover the queue system, including enabling it, basic operations, and custom queue entry implementation for advanced playback control.
yea, also i have updated the docs for queue system section, please check it out. |
Will do, I'm building a new extension right now, to give users a plug-able music system |
It's pretty simple It registers slash commands for it automatically and handles lavalink. // DiscordClient client
// we have to init the application commands module beforehand
client.UseSimpleMusicCommands(new LavalinkConfiguration());
var extension = await Client.GetSimpleMusicCommandsExtension();
extension.RegisterMusicCommands();
// it's important to connect the discord client first
await client.ConnectAsync();
await extension.ConnectAsync(); It's using the built-in queue internal SimpleMusicCommandsExtension(LavalinkConfiguration? configuration = null)
{
configuration ??= new();
configuration.EnableBuiltInQueueSystem = true;
configuration.QueueEntryFactory = () => new DefaultQueueEntry();
this.Configuration = configuration;
} |
amazing, the docs are great |
hehe, thank you ^^ |
I believe that should be all.. |
Signed-off-by: Lala Sabathil <[email protected]>
Signed-off-by: Lala Sabathil <[email protected]>
Signed-off-by: Lala Sabathil <[email protected]>
Signed-off-by: Lala Sabathil <[email protected]>
Target nightly release: 10.6.6-nightly-024 |
Description
EditResponseAsync
method for string content.DefaultQueueEntry
class for track playback handling.LavalinkConfiguration
with a customizableQueueEntryFactory
.LavalinkGuildPlayer
to utilize a staticQueueInternal
for guild-specific queues.QueueEntries
property in favor of the newQueue
property.LavalinkQueue<T>
class for queue operations.Type of change
Please delete options that are not relevant.
How Has This Been Tested?
I really like the short, not too long way of writing.
The
EditResponseAsync
method is used a lot and I think the input is mainly a content, so I added a method input which is string content, hope you agree.tested the queue part with 3 servers and they work fine (only manual test, no automation test and code test).
In case the user only wants to use Queue(
EnableBuiltInQueueSystem = true
) and does not want to use pipeline queue entrya transient pipeline
DefaultQueueEntry
will be used.If they want to use it, just sets a
QueueEntryFactory
function that creates queue entry objects.We can use
QueueEntryFactory
with DIOtherwise we can create it with delegate instance
When playing the tracks it will also create a
transient
ofQueueEntryFactory
Test Configuration:
Checklist:
@Aiko-IT-Systems/discatsharp