added rcs and rpl (repeat current song, playlist), improved !m lq, closes #108
This commit is contained in:
parent
488b897690
commit
b74aaec173
@ -5,15 +5,18 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
namespace NadekoBot.Classes.Music {
|
namespace NadekoBot.Classes.Music
|
||||||
|
{
|
||||||
|
|
||||||
public enum MusicType {
|
public enum MusicType
|
||||||
|
{
|
||||||
Radio,
|
Radio,
|
||||||
Normal,
|
Normal,
|
||||||
Local
|
Local
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum StreamState {
|
public enum StreamState
|
||||||
|
{
|
||||||
Resolving,
|
Resolving,
|
||||||
Queued,
|
Queued,
|
||||||
Buffering, //not using it atm
|
Buffering, //not using it atm
|
||||||
@ -21,7 +24,8 @@ namespace NadekoBot.Classes.Music {
|
|||||||
Completed
|
Completed
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MusicPlayer {
|
public class MusicPlayer
|
||||||
|
{
|
||||||
public static int MaximumPlaylistSize => 50;
|
public static int MaximumPlaylistSize => 50;
|
||||||
|
|
||||||
private IAudioClient audioClient { get; set; }
|
private IAudioClient audioClient { get; set; }
|
||||||
@ -44,8 +48,11 @@ namespace NadekoBot.Classes.Music {
|
|||||||
public Channel PlaybackVoiceChannel { get; private set; }
|
public Channel PlaybackVoiceChannel { get; private set; }
|
||||||
|
|
||||||
private bool Destroyed { get; set; } = false;
|
private bool Destroyed { get; set; } = false;
|
||||||
|
public bool RepeatSong { get; private set; } = false;
|
||||||
|
public bool RepeatPlaylist { get; private set; } = false;
|
||||||
|
|
||||||
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume) {
|
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
|
||||||
|
{
|
||||||
if (startingVoiceChannel == null)
|
if (startingVoiceChannel == null)
|
||||||
throw new ArgumentNullException(nameof(startingVoiceChannel));
|
throw new ArgumentNullException(nameof(startingVoiceChannel));
|
||||||
if (startingVoiceChannel.Type != ChannelType.Voice)
|
if (startingVoiceChannel.Type != ChannelType.Voice)
|
||||||
@ -56,27 +63,42 @@ namespace NadekoBot.Classes.Music {
|
|||||||
SongCancelSource = new CancellationTokenSource();
|
SongCancelSource = new CancellationTokenSource();
|
||||||
cancelToken = SongCancelSource.Token;
|
cancelToken = SongCancelSource.Token;
|
||||||
|
|
||||||
Task.Run(async () => {
|
Task.Run(async () =>
|
||||||
while (!Destroyed) {
|
{
|
||||||
try {
|
while (!Destroyed)
|
||||||
if(audioClient?.State != ConnectionState.Connected)
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (audioClient?.State != ConnectionState.Connected)
|
||||||
audioClient = await PlaybackVoiceChannel.JoinAudio();
|
audioClient = await PlaybackVoiceChannel.JoinAudio();
|
||||||
} catch {
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CurrentSong = GetNextSong();
|
CurrentSong = GetNextSong();
|
||||||
var curSong = CurrentSong;
|
var curSong = CurrentSong;
|
||||||
if (curSong != null) {
|
if (curSong != null)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
OnStarted(this, curSong);
|
OnStarted(this, curSong);
|
||||||
await curSong.Play(audioClient, cancelToken);
|
await curSong.Play(audioClient, cancelToken);
|
||||||
} catch (OperationCanceledException) {
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
Console.WriteLine("Song canceled");
|
Console.WriteLine("Song canceled");
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Console.WriteLine($"Exception in PlaySong: {ex}");
|
Console.WriteLine($"Exception in PlaySong: {ex}");
|
||||||
}
|
}
|
||||||
OnCompleted(this, curSong);
|
OnCompleted(this, curSong);
|
||||||
|
if (RepeatSong)
|
||||||
|
playlist.Insert(0, curSong);
|
||||||
|
else if (RepeatPlaylist)
|
||||||
|
playlist.Insert(playlist.Count, curSong);
|
||||||
SongCancelSource = new CancellationTokenSource();
|
SongCancelSource = new CancellationTokenSource();
|
||||||
cancelToken = SongCancelSource.Token;
|
cancelToken = SongCancelSource.Token;
|
||||||
}
|
}
|
||||||
@ -85,17 +107,22 @@ namespace NadekoBot.Classes.Music {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Next() {
|
public void Next()
|
||||||
lock (playlistLock) {
|
{
|
||||||
if (!SongCancelSource.IsCancellationRequested) {
|
lock (playlistLock)
|
||||||
|
{
|
||||||
|
if (!SongCancelSource.IsCancellationRequested)
|
||||||
|
{
|
||||||
Paused = false;
|
Paused = false;
|
||||||
SongCancelSource.Cancel();
|
SongCancelSource.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop() {
|
public void Stop()
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Clear();
|
playlist.Clear();
|
||||||
CurrentSong = null;
|
CurrentSong = null;
|
||||||
if (!SongCancelSource.IsCancellationRequested)
|
if (!SongCancelSource.IsCancellationRequested)
|
||||||
@ -105,13 +132,16 @@ namespace NadekoBot.Classes.Music {
|
|||||||
|
|
||||||
public void TogglePause() => Paused = !Paused;
|
public void TogglePause() => Paused = !Paused;
|
||||||
|
|
||||||
public void Shuffle() {
|
public void Shuffle()
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Shuffle();
|
playlist.Shuffle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SetVolume(int volume) {
|
public int SetVolume(int volume)
|
||||||
|
{
|
||||||
if (volume < 0)
|
if (volume < 0)
|
||||||
volume = 0;
|
volume = 0;
|
||||||
if (volume > 150)
|
if (volume > 150)
|
||||||
@ -121,8 +151,10 @@ namespace NadekoBot.Classes.Music {
|
|||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Song GetNextSong() {
|
private Song GetNextSong()
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
if (playlist.Count == 0)
|
if (playlist.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
var toReturn = playlist[0];
|
var toReturn = playlist[0];
|
||||||
@ -131,45 +163,56 @@ namespace NadekoBot.Classes.Music {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSong(Song s) {
|
public void AddSong(Song s)
|
||||||
|
{
|
||||||
if (s == null)
|
if (s == null)
|
||||||
throw new ArgumentNullException(nameof(s));
|
throw new ArgumentNullException(nameof(s));
|
||||||
lock (playlistLock) {
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Add(s);
|
playlist.Add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSong(Song s) {
|
public void RemoveSong(Song s)
|
||||||
|
{
|
||||||
if (s == null)
|
if (s == null)
|
||||||
throw new ArgumentNullException(nameof(s));
|
throw new ArgumentNullException(nameof(s));
|
||||||
lock (playlistLock) {
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Remove(s);
|
playlist.Remove(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSongAt(int index) {
|
public void RemoveSongAt(int index)
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
if (index < 0 || index >= playlist.Count)
|
if (index < 0 || index >= playlist.Count)
|
||||||
throw new ArgumentException("Invalid index");
|
throw new ArgumentException("Invalid index");
|
||||||
playlist.RemoveAt(index);
|
playlist.RemoveAt(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Task MoveToVoiceChannel(Channel voiceChannel) {
|
internal Task MoveToVoiceChannel(Channel voiceChannel)
|
||||||
|
{
|
||||||
if (audioClient?.State != ConnectionState.Connected)
|
if (audioClient?.State != ConnectionState.Connected)
|
||||||
throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
|
throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
|
||||||
PlaybackVoiceChannel = voiceChannel;
|
PlaybackVoiceChannel = voiceChannel;
|
||||||
return PlaybackVoiceChannel.JoinAudio();
|
return PlaybackVoiceChannel.JoinAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearQueue() {
|
internal void ClearQueue()
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Clear();
|
playlist.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Destroy() {
|
public void Destroy()
|
||||||
lock (playlistLock) {
|
{
|
||||||
|
lock (playlistLock)
|
||||||
|
{
|
||||||
playlist.Clear();
|
playlist.Clear();
|
||||||
Destroyed = true;
|
Destroyed = true;
|
||||||
CurrentSong = null;
|
CurrentSong = null;
|
||||||
@ -178,5 +221,9 @@ namespace NadekoBot.Classes.Music {
|
|||||||
audioClient.Disconnect();
|
audioClient.Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong;
|
||||||
|
|
||||||
|
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,15 @@ namespace NadekoBot.Modules
|
|||||||
await e.Channel.SendMessage("🎵 No active music player.");
|
await e.Channel.SendMessage("🎵 No active music player.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var toSend = "🎵 **" + musicPlayer.Playlist.Count + "** `tracks currently queued.` ";
|
var currentSong = musicPlayer.CurrentSong;
|
||||||
|
if (currentSong == null)
|
||||||
|
return;
|
||||||
|
var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n";
|
||||||
|
if (musicPlayer.RepeatSong)
|
||||||
|
toSend += "🔁 `Repeating current song.`\n";
|
||||||
|
else if (musicPlayer.RepeatPlaylist)
|
||||||
|
toSend += "🔁 `Repeating playlist.`\n";
|
||||||
|
toSend += $"🎵 **{musicPlayer.Playlist.Count}** `tracks currently queued.` ";
|
||||||
if (musicPlayer.Playlist.Count >= MusicPlayer.MaximumPlaylistSize)
|
if (musicPlayer.Playlist.Count >= MusicPlayer.MaximumPlaylistSize)
|
||||||
toSend += "**Song queue is full!**\n";
|
toSend += "**Song queue is full!**\n";
|
||||||
else
|
else
|
||||||
@ -157,9 +165,10 @@ namespace NadekoBot.Modules
|
|||||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||||
return;
|
return;
|
||||||
var currentSong = musicPlayer.CurrentSong;
|
var currentSong = musicPlayer.CurrentSong;
|
||||||
if (currentSong != null)
|
if (currentSong == null)
|
||||||
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
|
return;
|
||||||
$"{currentSong.PrettyCurrentTime()}");
|
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
|
||||||
|
$"{currentSong.PrettyCurrentTime()}");
|
||||||
});
|
});
|
||||||
|
|
||||||
cgb.CreateCommand("vol")
|
cgb.CreateCommand("vol")
|
||||||
@ -386,6 +395,34 @@ namespace NadekoBot.Modules
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cgb.CreateCommand("rcs")
|
||||||
|
.Alias("repeatcurrentsong")
|
||||||
|
.Description("Toggles repeat of current song.")
|
||||||
|
.Do(async e =>
|
||||||
|
{
|
||||||
|
MusicPlayer musicPlayer;
|
||||||
|
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||||
|
return;
|
||||||
|
var currentSong = musicPlayer.CurrentSong;
|
||||||
|
if (currentSong == null)
|
||||||
|
return;
|
||||||
|
var currentValue = musicPlayer.ToggleRepeatSong();
|
||||||
|
await e.Channel.SendMessage(currentValue ?
|
||||||
|
$"🎵 `Repeating track:`{currentSong.PrettyName}" :
|
||||||
|
$"🎵 `Current track repeat stopped.`");
|
||||||
|
});
|
||||||
|
|
||||||
|
cgb.CreateCommand("rpl")
|
||||||
|
.Alias("repeatplaylist")
|
||||||
|
.Description("Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue).")
|
||||||
|
.Do(async e =>
|
||||||
|
{
|
||||||
|
MusicPlayer musicPlayer;
|
||||||
|
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||||
|
return;
|
||||||
|
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
||||||
|
await e.Channel.SendMessage($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`");
|
||||||
|
});
|
||||||
//cgb.CreateCommand("debug")
|
//cgb.CreateCommand("debug")
|
||||||
// .Description("Does something magical. **BOT OWNER ONLY**")
|
// .Description("Does something magical. **BOT OWNER ONLY**")
|
||||||
// .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
|
// .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
|
||||||
|
Loading…
Reference in New Issue
Block a user