mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
- Re-added .qap / .queueautoplay
- Several strings and commands related to music have been changed - Changed .ms / .movesong to .tm / .trackmove but kept old aliases - Changed ~~song~~ -> rack throughout music module strings - Updated CHANGELOG.md
This commit is contained in:
@@ -103,7 +103,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
var (trackInfo, index) = await mp.TryEnqueueTrackAsync(query, ctx.User.ToString(), asNext, forcePlatform);
|
||||
if (trackInfo is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.song_not_found);
|
||||
await ReplyErrorLocalizedAsync(strs.track_not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithAuthor(GetText(strs.queued_song) + " #" + (index + 1), MUSIC_ICON_URL)
|
||||
.WithAuthor(GetText(strs.queued_track) + " #" + (index + 1), MUSIC_ICON_URL)
|
||||
.WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ")
|
||||
.WithFooter(trackInfo.Platform.ToString());
|
||||
|
||||
@@ -248,7 +248,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async partial Task ListQueue()
|
||||
{
|
||||
// show page with the current song
|
||||
// show page with the current track
|
||||
if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_player);
|
||||
@@ -291,8 +291,8 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
add += "🔂 " + GetText(strs.repeating_track) + "\n";
|
||||
else
|
||||
{
|
||||
// if (mp.Autoplay)
|
||||
// add += "↪ " + GetText(strs.autoplaying) + "\n";
|
||||
if (mp.AutoPlay)
|
||||
add += "↪ " + GetText(strs.autoplaying) + "\n";
|
||||
// if (mp.FairPlay && !mp.Autoplay)
|
||||
// add += " " + GetText(strs.fairplay) + "\n";
|
||||
if (repeatType == PlayerRepeatType.Queue)
|
||||
@@ -339,7 +339,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
|
||||
if (videos.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.song_not_found);
|
||||
await ReplyErrorLocalizedAsync(strs.track_not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
{
|
||||
if (index < 1)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.removed_song_error);
|
||||
await ReplyErrorLocalizedAsync(strs.removed_track_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -402,16 +402,16 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mp.TryRemoveTrackAt(index - 1, out var song))
|
||||
if (!mp.TryRemoveTrackAt(index - 1, out var track))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.removed_song_error);
|
||||
await ReplyErrorLocalizedAsync(strs.removed_track_error);
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithAuthor(GetText(strs.removed_song) + " #" + index, MUSIC_ICON_URL)
|
||||
.WithDescription(song.PrettyName())
|
||||
.WithFooter(song.PrettyInfo())
|
||||
.WithAuthor(GetText(strs.removed_track) + " #" + index, MUSIC_ICON_URL)
|
||||
.WithDescription(track.PrettyName())
|
||||
.WithFooter(track.PrettyInfo())
|
||||
.WithErrorColor();
|
||||
|
||||
await _service.SendToOutputAsync(ctx.Guild.Id, embed);
|
||||
@@ -550,7 +550,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async partial Task MoveSong(int from, int to)
|
||||
public async partial Task TrackMove(int from, int to)
|
||||
{
|
||||
if (--from < 0 || --to < 0 || from == to)
|
||||
{
|
||||
@@ -578,7 +578,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithTitle(track.Title.TrimTo(65))
|
||||
.WithAuthor(GetText(strs.song_moved), MUSIC_ICON_URL)
|
||||
.WithAuthor(GetText(strs.track_moved), MUSIC_ICON_URL)
|
||||
.AddField(GetText(strs.from_position), $"#{from + 1}", true)
|
||||
.AddField(GetText(strs.to_position), $"#{to + 1}", true)
|
||||
.WithOkColor();
|
||||
@@ -744,4 +744,15 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
await _service.SetMusicQualityAsync(ctx.Guild.Id, preset);
|
||||
await ReplyConfirmLocalizedAsync(strs.music_quality_set(Format.Bold(preset.ToString())));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async partial Task QueueAutoPlay()
|
||||
{
|
||||
var newValue = await _service.ToggleQueueAutoPlayAsync(ctx.Guild.Id);
|
||||
if (newValue)
|
||||
await ReplyConfirmLocalizedAsync(strs.music_autoplay_on);
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.music_autoplay_off);
|
||||
}
|
||||
}
|
@@ -32,4 +32,5 @@ public interface IMusicService : IPlaceholderProvider
|
||||
Task<bool> ToggleAutoDisconnectAsync(ulong guildId);
|
||||
Task<QualityPreset> GetMusicQualityAsync(ulong guildId);
|
||||
Task SetMusicQualityAsync(ulong guildId, QualityPreset preset);
|
||||
Task<bool> ToggleQueueAutoPlayAsync(ulong guildId);
|
||||
}
|
@@ -156,7 +156,12 @@ public sealed class MusicService : IMusicService
|
||||
|
||||
_outputChannels[guildId] = (defaultChannel, overrideChannel);
|
||||
|
||||
var mp = new MusicPlayer(queue, resolver, proxy, settings.QualityPreset);
|
||||
var mp = new MusicPlayer(queue,
|
||||
resolver,
|
||||
proxy,
|
||||
_googleApiService,
|
||||
settings.QualityPreset,
|
||||
settings.AutoPlay);
|
||||
|
||||
mp.SetRepeat(settings.PlayerRepeat);
|
||||
|
||||
@@ -191,7 +196,7 @@ public sealed class MusicService : IMusicService
|
||||
_ = lastFinishedMessage?.DeleteAsync();
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithAuthor(GetText(guildId, strs.finished_song), Music.MUSIC_ICON_URL)
|
||||
.WithAuthor(GetText(guildId, strs.finished_track), Music.MUSIC_ICON_URL)
|
||||
.WithDescription(trackInfo.PrettyName())
|
||||
.WithFooter(trackInfo.PrettyTotalTime());
|
||||
|
||||
@@ -207,7 +212,7 @@ public sealed class MusicService : IMusicService
|
||||
_ = lastPlayingMessage?.DeleteAsync();
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithAuthor(GetText(guildId, strs.playing_song(index + 1)), Music.MUSIC_ICON_URL)
|
||||
.WithAuthor(GetText(guildId, strs.playing_track(index + 1)), Music.MUSIC_ICON_URL)
|
||||
.WithDescription(trackInfo.PrettyName())
|
||||
.WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}");
|
||||
|
||||
@@ -288,7 +293,7 @@ public sealed class MusicService : IMusicService
|
||||
|
||||
public IEnumerable<(string Name, Func<string> Func)> GetPlaceholders()
|
||||
{
|
||||
// random song that's playing
|
||||
// random track that's playing
|
||||
yield return ("%music.playing%", () =>
|
||||
{
|
||||
var randomPlayingTrack = _players.Select(x => x.Value.GetCurrentTrack(out _))
|
||||
@@ -438,5 +443,17 @@ public sealed class MusicService : IMusicService
|
||||
},
|
||||
preset);
|
||||
|
||||
public async Task<bool> ToggleQueueAutoPlayAsync(ulong guildId)
|
||||
{
|
||||
var newValue = false;
|
||||
await ModifySettingsInternalAsync(guildId,
|
||||
(settings, _) => newValue = settings.AutoPlay = !settings.AutoPlay,
|
||||
false);
|
||||
|
||||
if (TryGetMusicPlayer(guildId, out var mp))
|
||||
mp.AutoPlay = newValue;
|
||||
return newValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@@ -10,6 +10,7 @@ public interface IMusicPlayer : IDisposable
|
||||
bool IsKilled { get; }
|
||||
int CurrentIndex { get; }
|
||||
public PlayerRepeatType Repeat { get; }
|
||||
bool AutoPlay { get; set; }
|
||||
|
||||
void Stop();
|
||||
void Clear();
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
public interface ITrackInfo
|
||||
{
|
||||
public string Id => string.Empty;
|
||||
public string Title { get; }
|
||||
public string Url { get; }
|
||||
public string Thumbnail { get; }
|
||||
|
@@ -28,6 +28,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
||||
private readonly IMusicQueue _queue;
|
||||
private readonly ITrackResolveProvider _trackResolveProvider;
|
||||
private readonly IVoiceProxy _proxy;
|
||||
private readonly IGoogleApiService _googleApiService;
|
||||
private readonly ISongBuffer _songBuffer;
|
||||
|
||||
private bool skipped;
|
||||
@@ -35,15 +36,21 @@ public sealed class MusicPlayer : IMusicPlayer
|
||||
private readonly Thread _thread;
|
||||
private readonly Random _rng;
|
||||
|
||||
public bool AutoPlay { get; set; }
|
||||
|
||||
public MusicPlayer(
|
||||
IMusicQueue queue,
|
||||
ITrackResolveProvider trackResolveProvider,
|
||||
IVoiceProxy proxy,
|
||||
QualityPreset qualityPreset)
|
||||
IGoogleApiService googleApiService,
|
||||
QualityPreset qualityPreset,
|
||||
bool autoPlay)
|
||||
{
|
||||
_queue = queue;
|
||||
_trackResolveProvider = trackResolveProvider;
|
||||
_proxy = proxy;
|
||||
_googleApiService = googleApiService;
|
||||
AutoPlay = autoPlay;
|
||||
_rng = new NadekoRandom();
|
||||
|
||||
_vc = GetVoiceClient(qualityPreset);
|
||||
@@ -265,7 +272,29 @@ public sealed class MusicPlayer : IMusicPlayer
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
// turn off green in vc
|
||||
|
||||
_ = OnCompleted?.Invoke(this, track);
|
||||
|
||||
// todo update when settings are changed
|
||||
if (AutoPlay && track.Platform == MusicPlatform.Youtube)
|
||||
{
|
||||
try
|
||||
{
|
||||
var relatedSongs = await _googleApiService.GetRelatedVideosAsync(track.TrackInfo.Id, 5);
|
||||
var related = relatedSongs.Shuffle().FirstOrDefault();
|
||||
if (related is not null)
|
||||
{
|
||||
var relatedTrack = await _trackResolveProvider.QuerySongAsync(related, MusicPlatform.Youtube);
|
||||
if (relatedTrack is not null)
|
||||
EnqueueTrack(relatedTrack, "Autoplay");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Failed queueing a related song via autoplay");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HandleQueuePostTrack();
|
||||
skipped = false;
|
||||
|
@@ -1,30 +1,15 @@
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
public sealed class RemoteTrackInfo : ITrackInfo
|
||||
public sealed record RemoteTrackInfo(
|
||||
string Id,
|
||||
string Title,
|
||||
string Url,
|
||||
string Thumbnail,
|
||||
TimeSpan Duration,
|
||||
MusicPlatform Platform,
|
||||
Func<Task<string?>> _streamFactory) : ITrackInfo
|
||||
{
|
||||
public string Title { get; }
|
||||
public string Url { get; }
|
||||
public string Thumbnail { get; }
|
||||
public TimeSpan Duration { get; }
|
||||
public MusicPlatform Platform { get; }
|
||||
|
||||
private readonly Func<Task<string?>> _streamFactory;
|
||||
|
||||
public RemoteTrackInfo(
|
||||
string title,
|
||||
string url,
|
||||
string thumbnail,
|
||||
TimeSpan duration,
|
||||
MusicPlatform platform,
|
||||
Func<Task<string?>> streamFactory)
|
||||
{
|
||||
_streamFactory = streamFactory;
|
||||
Title = title;
|
||||
Url = url;
|
||||
Thumbnail = thumbnail;
|
||||
Duration = duration;
|
||||
Platform = platform;
|
||||
}
|
||||
private readonly Func<Task<string?>> _streamFactory = _streamFactory;
|
||||
|
||||
public async ValueTask<string?> GetStreamUrl()
|
||||
=> await _streamFactory();
|
||||
|
@@ -94,7 +94,9 @@ public sealed class YtdlYoutubeResolver : IYoutubeResolver
|
||||
}
|
||||
|
||||
private ITrackInfo DataToInfo(in YtTrackData trackData)
|
||||
=> new RemoteTrackInfo(trackData.Title,
|
||||
=> new RemoteTrackInfo(
|
||||
trackData.Id,
|
||||
trackData.Title,
|
||||
$"https://youtube.com/watch?v={trackData.Id}",
|
||||
trackData.Thumbnail,
|
||||
trackData.Duration,
|
||||
|
@@ -4,8 +4,6 @@ using System.Globalization;
|
||||
|
||||
namespace NadekoBot.Modules.Searches;
|
||||
|
||||
// todo weighted warnings fix
|
||||
// todo autoplay/fairplay
|
||||
public partial class Searches
|
||||
{
|
||||
public partial class FinanceCommands : NadekoSubmodule<CryptoService>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#nullable disable
|
||||
// #nullable disable
|
||||
// using NadekoBot.Db.Models;
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
@@ -10,6 +11,7 @@
|
||||
// using NadekoBot.Services.Database.Models;
|
||||
// using NadekoBot.Extensions;
|
||||
// using Serilog;
|
||||
// using TwitchLib.Api;
|
||||
// using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
//
|
||||
// namespace NadekoBot.Modules.Searches.Common.StreamNotifications.Providers
|
||||
@@ -25,33 +27,17 @@
|
||||
// public override FollowedStream.FType Platform => FollowedStream.FType.Twitch;
|
||||
//
|
||||
// private (string Token, DateTime Expiry) _token = default;
|
||||
//
|
||||
// private readonly TwitchAPI _api;
|
||||
//
|
||||
// public TwitchHelixProvider(IHttpClientFactory httpClientFactory)
|
||||
// {
|
||||
// _httpClientFactory = httpClientFactory;
|
||||
// _api = new TwitchAPI();
|
||||
// }
|
||||
//
|
||||
// private async Task EnsureTokenValidAsync()
|
||||
// {
|
||||
// if (_token != default && (DateTime.UtcNow - _token.Expiry) > TimeSpan.FromHours(1))
|
||||
// return;
|
||||
// => await _api.Auth.GetAccessTokenAsync();
|
||||
//
|
||||
// const string clientId = string.Empty;
|
||||
// const string clientSecret = string.Empty;
|
||||
//
|
||||
// var client = _httpClientFactory.CreateClient();
|
||||
// var res = await client.PostAsync("https://id.twitch.tv/oauth2/token" +
|
||||
// $"?client_id={clientId}" +
|
||||
// $"&client_secret={clientSecret}" +
|
||||
// "&grant_type=client_credentials", new StringContent(""));
|
||||
//
|
||||
// var data = JsonDocument.Parse(await res.Content.ReadAsStringAsync()).RootElement;
|
||||
//
|
||||
// _token = (data.GetProperty("access_token").GetString(),
|
||||
// DateTime.UtcNow + TimeSpan.FromSeconds(data.GetProperty("expires_in").GetInt32()));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public override Task<bool> IsValidUrl(string url)
|
||||
// {
|
||||
// var match = Regex.Match(url);
|
||||
|
Reference in New Issue
Block a user