added rcs and rpl (repeat current song, playlist), improved !m lq, closes #108

This commit is contained in:
Master Kwoth 2016-04-01 18:40:45 +02:00
parent 488b897690
commit b74aaec173
2 changed files with 123 additions and 39 deletions

View File

@ -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)
{
try
{
if (audioClient?.State != ConnectionState.Connected) 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;
} }
} }

View File

@ -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,7 +165,8 @@ 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)
return;
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " + await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
$"{currentSong.PrettyCurrentTime()}"); $"{currentSong.PrettyCurrentTime()}");
}); });
@ -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())