rewrite started

This commit is contained in:
Master Kwoth 2016-02-27 02:23:47 +01:00
parent 0240a62337
commit ba7fb089d2
3 changed files with 159 additions and 29 deletions

View File

@ -5,6 +5,9 @@ using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using MusicModule = NadekoBot.Modules.Music; using MusicModule = NadekoBot.Modules.Music;
using System.Collections;
using NadekoBot.Extensions;
using System.Threading;
namespace NadekoBot.Classes.Music { namespace NadekoBot.Classes.Music {
@ -13,8 +16,130 @@ namespace NadekoBot.Classes.Music {
Normal, Normal,
Local Local
} }
public class Song {
public StreamState State { get; internal set; }
public class MusicControls { private Song() { }
internal Task Play(CancellationToken cancelToken) {
throw new NotImplementedException();
}
}
public class MusicPlayer {
private IAudioClient _client { get; set; }
private List<Song> _playlist = new List<Song>();
public IReadOnlyCollection<Song> Playlist => _playlist;
private object playlistLock = new object();
public Song CurrentSong { get; set; } = default(Song);
private CancellationTokenSource SongCancelSource { get; set; }
private CancellationToken cancelToken { get; set; }
public bool Paused { get; set; }
public float Volume { get; private set; }
public MusicPlayer(IAudioClient client) {
if (client == null)
throw new ArgumentNullException(nameof(client));
_client = client;
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
Task.Run(async () => {
while (_client?.State == ConnectionState.Connected) {
CurrentSong = GetNextSong();
if (CurrentSong != null) {
try {
await CurrentSong.Play(cancelToken);
}
catch (OperationCanceledException) {
Console.WriteLine("Song canceled");
}
catch (Exception ex) {
Console.WriteLine($"Exception in PlaySong: {ex}");
}
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
}
else {
await Task.Delay(1000);
}
}
await Stop();
});
}
public void Next() {
if(!SongCancelSource.IsCancellationRequested)
SongCancelSource.Cancel();
}
public async Task Stop() {
lock (_playlist) {
_playlist.Clear();
}
try {
if (!SongCancelSource.IsCancellationRequested)
SongCancelSource.Cancel();
}
catch {
Console.WriteLine("This shouldn't happen");
}
await _client?.Disconnect();
}
public void Shuffle() {
lock (_playlist) {
_playlist.Shuffle();
}
}
public void SetVolume(float volume) {
if (volume < 0)
volume = 0;
if (volume > 150)
volume = 150;
Volume = volume / 100.0f;
}
private Song GetNextSong() {
lock (playlistLock) {
if (_playlist.Count == 0)
return null;
var toReturn = _playlist[0];
_playlist.RemoveAt(0);
return toReturn;
}
}
public void AddSong(Song s) {
if (s == null)
throw new ArgumentNullException(nameof(s));
lock (playlistLock) {
_playlist.Add(s);
}
}
public void RemoveSong(Song s) {
if (s == null)
throw new ArgumentNullException(nameof(s));
lock (playlistLock) {
_playlist.Remove(s);
}
}
public void RemoveSongAt(int index) {
lock (playlistLock) {
if (index < 0 || index >= _playlist.Count)
throw new ArgumentException("Invalid index");
_playlist.RemoveAt(index);
}
}
/*
private CommandEventArgs _e; private CommandEventArgs _e;
public bool NextSong { get; set; } = false; public bool NextSong { get; set; } = false;
public IAudioClient Voice { get; set; } public IAudioClient Voice { get; set; }
@ -33,7 +158,7 @@ namespace NadekoBot.Classes.Music {
private readonly object _voiceLock = new object(); private readonly object _voiceLock = new object();
public MusicControls() { public MusicPlayer() {
Task.Run(async () => { Task.Run(async () => {
while (true) { while (true) {
if (!Stopped) { if (!Stopped) {
@ -61,7 +186,7 @@ namespace NadekoBot.Classes.Music {
} }
} }
public MusicControls(Channel voiceChannel, CommandEventArgs e, float? vol) : this() { public MusicPlayer(Channel voiceChannel, CommandEventArgs e, float? vol) : this() {
if (voiceChannel == null) if (voiceChannel == null)
throw new ArgumentNullException(nameof(voiceChannel)); throw new ArgumentNullException(nameof(voiceChannel));
if (vol != null) if (vol != null)
@ -96,7 +221,6 @@ namespace NadekoBot.Classes.Music {
catch (Exception ex) { catch (Exception ex) {
Console.WriteLine($"Starting failed: {ex}"); Console.WriteLine($"Starting failed: {ex}");
CurrentSong?.Stop(); CurrentSong?.Stop();
CurrentSong = null;
} }
} }
@ -112,7 +236,7 @@ namespace NadekoBot.Classes.Music {
VoiceClient?.Disconnect(); VoiceClient?.Disconnect();
VoiceClient = null; VoiceClient = null;
MusicControls throwAwayValue; MusicPlayer throwAwayValue;
MusicModule.musicPlayers.TryRemove(_e.Server, out throwAwayValue); MusicModule.musicPlayers.TryRemove(_e.Server, out throwAwayValue);
} }
} }
@ -127,5 +251,6 @@ namespace NadekoBot.Classes.Music {
} }
internal bool TogglePause() => IsPaused = !IsPaused; internal bool TogglePause() => IsPaused = !IsPaused;
*/
} }
} }

View File

@ -38,9 +38,9 @@ namespace NadekoBot.Classes.Music {
public MusicType LinkType { get; } public MusicType LinkType { get; }
public MusicControls MusicControls; public MusicPlayer MusicControls;
public StreamRequest(CommandEventArgs e, string query, MusicControls mc, MusicType musicType = MusicType.Normal) { public StreamRequest(CommandEventArgs e, string query, MusicPlayer mc, MusicType musicType = MusicType.Normal) {
if (e == null) if (e == null)
throw new ArgumentNullException(nameof(e)); throw new ArgumentNullException(nameof(e));
if (query == null) if (query == null)

View File

@ -15,7 +15,7 @@ using Timer = System.Timers.Timer;
namespace NadekoBot.Modules { namespace NadekoBot.Modules {
class Music : DiscordModule { class Music : DiscordModule {
public static ConcurrentDictionary<Server, MusicControls> musicPlayers = new ConcurrentDictionary<Server, MusicControls>(); public static ConcurrentDictionary<Server, MusicPlayer> musicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
public static ConcurrentDictionary<ulong, float> musicVolumes = new ConcurrentDictionary<ulong, float>(); public static ConcurrentDictionary<ulong, float> musicVolumes = new ConcurrentDictionary<ulong, float>();
internal static string GetMusicStats() { internal static string GetMusicStats() {
@ -24,7 +24,21 @@ namespace NadekoBot.Modules {
return $"Playing {cnt = stats.Count()} songs".SnPl(cnt) + $", {stats.Sum(kvp => kvp.Value?.SongQueue?.Count ?? 0)} queued."; return $"Playing {cnt = stats.Count()} songs".SnPl(cnt) + $", {stats.Sum(kvp => kvp.Value?.SongQueue?.Count ?? 0)} queued.";
} }
Timer setgameTimer => new Timer();
bool setgameEnabled = false;
public Music() : base() { public Music() : base() {
setgameTimer.Interval = 20000;
setgameTimer.Elapsed += (s, e) => {
try {
int num = musicPlayers.Where(kvp => kvp.Value.CurrentSong != null).Count();
NadekoBot.client.SetGame($"{num} songs".SnPl(num) + $", {musicPlayers.Sum(kvp => kvp.Value.SongQueue.Count())} queued");
}
catch { }
};
} }
public override void Install(ModuleManager manager) { public override void Install(ModuleManager manager) {
@ -164,17 +178,6 @@ namespace NadekoBot.Modules {
player.SongQueue.Shuffle(); player.SongQueue.Shuffle();
await e.Channel.SendMessage("🎵 `Songs shuffled.`"); await e.Channel.SendMessage("🎵 `Songs shuffled.`");
}); });
bool setgameEnabled = false;
Timer setgameTimer = new Timer();
setgameTimer.Interval = 20000;
setgameTimer.Elapsed += (s, e) => {
try {
int num = musicPlayers.Where(kvp => kvp.Value.CurrentSong != null).Count();
NadekoBot.client.SetGame($"{num} songs".SnPl(num) + $", {musicPlayers.Sum(kvp => kvp.Value.SongQueue.Count())} queued");
}
catch { }
};
cgb.CreateCommand("setgame") cgb.CreateCommand("setgame")
.Description("Sets the game of the bot to the number of songs playing.**Owner only**") .Description("Sets the game of the bot to the number of songs playing.**Owner only**")
.Do(async e => { .Do(async e => {
@ -201,7 +204,7 @@ namespace NadekoBot.Modules {
//todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE
var msg = await e.Channel.SendMessage($"🎵 `Attempting to queue {ids.Count} songs".SnPl(ids.Count) + "...`"); var msg = await e.Channel.SendMessage($"🎵 `Attempting to queue {ids.Count} songs".SnPl(ids.Count) + "...`");
foreach (var id in ids) { foreach (var id in ids) {
Task.Run(async () => await QueueSong(e, id, true)).ConfigureAwait(false); Task.Run(async () => await QueueSong(e, id, true));
await Task.Delay(150); await Task.Delay(150);
} }
msg?.Edit("🎵 `Playlist queue complete.`"); msg?.Edit("🎵 `Playlist queue complete.`");
@ -250,7 +253,7 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("mv") cgb.CreateCommand("mv")
.Description("Moves the bot to your voice channel. (works only if music is already playing)") .Description("Moves the bot to your voice channel. (works only if music is already playing)")
.Do(async e => { .Do(async e => {
MusicControls mc; MusicPlayer mc;
if (e.User.VoiceChannel == null || e.User.VoiceChannel.Server != e.Server || !musicPlayers.TryGetValue(e.Server, out mc)) if (e.User.VoiceChannel == null || e.User.VoiceChannel.Server != e.Server || !musicPlayers.TryGetValue(e.Server, out mc))
return; return;
mc.VoiceChannel = e.User.VoiceChannel; mc.VoiceChannel = e.User.VoiceChannel;
@ -262,7 +265,7 @@ namespace NadekoBot.Modules {
.Parameter("num", ParameterType.Required) .Parameter("num", ParameterType.Required)
.Do(async e => { .Do(async e => {
var arg = e.GetArg("num"); var arg = e.GetArg("num");
MusicControls mc; MusicPlayer mc;
if (!musicPlayers.TryGetValue(e.Server, out mc)) { if (!musicPlayers.TryGetValue(e.Server, out mc)) {
return; return;
} }
@ -316,7 +319,7 @@ namespace NadekoBot.Modules {
if (musicVolumes.TryGetValue(e.Server.Id, out throwAway)) if (musicVolumes.TryGetValue(e.Server.Id, out throwAway))
vol = throwAway; vol = throwAway;
if (!musicPlayers.TryAdd(e.Server, new MusicControls(e.User.VoiceChannel, e, vol))) { if (!musicPlayers.TryAdd(e.Server, new MusicPlayer(e.User.VoiceChannel, e, vol))) {
await e.Channel.SendMessage("Failed to create a music player for this server."); await e.Channel.SendMessage("Failed to create a music player for this server.");
return; return;
} }
@ -339,13 +342,15 @@ namespace NadekoBot.Modules {
qmsg = await e.Channel.SendMessage("🎵 `Searching / Resolving...`"); qmsg = await e.Channel.SendMessage("🎵 `Searching / Resolving...`");
sr.OnResolvingFailed += async (err) => { sr.OnResolvingFailed += async (err) => {
try { try {
await qmsg.Edit($"💢 🎵 `Resolving failed` for **{query}**"); await qmsg.Delete();
await e.Channel.Send($"💢 🎵 `Resolving failed` for **{query}**");
} }
catch { } catch { }
}; };
sr.OnQueued += async () => { sr.OnQueued += async () => {
try { try {
await qmsg.Edit($"🎵`Queued`{sr.FullPrettyName}"); await qmsg.Delete();
await e.Channel.Send($"🎵`Queued`{sr.FullPrettyName}");
} }
catch { } catch { }
}; };
@ -354,7 +359,7 @@ namespace NadekoBot.Modules {
} }
sr.OnCompleted += async () => { sr.OnCompleted += async () => {
try { try {
MusicControls mc; MusicPlayer mc;
if (musicPlayers.TryGetValue(e.Server, out mc)) { if (musicPlayers.TryGetValue(e.Server, out mc)) {
if (mc.SongQueue.Count == 0) if (mc.SongQueue.Count == 0)
mc.Stop(); mc.Stop();
@ -363,13 +368,13 @@ namespace NadekoBot.Modules {
} }
catch { } catch { }
}; };
sr.OnStarted += async () => { sr.OnStarted += async () => {
try { try {
var msgTxt = $"🎵`Playing`{sr.FullPrettyName} `Vol: {(int)(player.Volume * 100)}%`"; var msgTxt = $"🎵`Playing`{sr.FullPrettyName} `Vol: {(int)(player.Volume * 100)}%`";
if (qmsg != null) if (qmsg != null)
await qmsg.Edit(msgTxt); await qmsg.Delete();
else await e.Channel.SendMessage(msgTxt);
await e.Channel.SendMessage(msgTxt);
} }
catch { } catch { }
}; };