added rcs and rpl (repeat current song, playlist), improved !m lq, closes #108
This commit is contained in:
		| @@ -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,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()) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user