new api, new music code
This commit is contained in:
parent
9e870cfc87
commit
f0277b1ba8
@ -26,9 +26,9 @@ namespace NadekoBot.Modules {
|
|||||||
public static IAudioClient Voice;
|
public static IAudioClient Voice;
|
||||||
public static Channel VoiceChannel;
|
public static Channel VoiceChannel;
|
||||||
public static bool Pause = false;
|
public static bool Pause = false;
|
||||||
public static List<YouTubeVideo> SongQueue = new List<YouTubeVideo>();
|
public static List<StreamRequest> SongQueue = new List<StreamRequest>();
|
||||||
|
|
||||||
public static YouTubeVideo CurrentSong;
|
public static StreamRequest CurrentSong;
|
||||||
|
|
||||||
public static bool Exit {
|
public static bool Exit {
|
||||||
get { return exit; }
|
get { return exit; }
|
||||||
@ -49,6 +49,16 @@ namespace NadekoBot.Modules {
|
|||||||
|
|
||||||
public override void Install(ModuleManager manager) {
|
public override void Install(ModuleManager manager) {
|
||||||
var client = NadekoBot.client;
|
var client = NadekoBot.client;
|
||||||
|
|
||||||
|
Task.Run(async () => {
|
||||||
|
while (true) {
|
||||||
|
if (CurrentSong == null || CurrentSong.State == StreamTaskState.Completed) {
|
||||||
|
await LoadNextSong();
|
||||||
|
} else
|
||||||
|
await Task.Delay(200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
manager.CreateCommands("!m", cgb => {
|
manager.CreateCommands("!m", cgb => {
|
||||||
//queue all more complex commands
|
//queue all more complex commands
|
||||||
commands.ForEach(cmd => cmd.Init(cgb));
|
commands.ForEach(cmd => cmd.Init(cgb));
|
||||||
@ -57,8 +67,11 @@ namespace NadekoBot.Modules {
|
|||||||
.Alias("next")
|
.Alias("next")
|
||||||
.Description("Goes to the next song in the queue.")
|
.Description("Goes to the next song in the queue.")
|
||||||
.Do(e => {
|
.Do(e => {
|
||||||
if (Voice != null && Exit == false) {
|
if (CurrentSong == null) return;
|
||||||
NextSong = true;
|
CurrentSong.Cancel();
|
||||||
|
CurrentSong = SongQueue.Take(1).FirstOrDefault();
|
||||||
|
if (CurrentSong != null) {
|
||||||
|
CurrentSong.Start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,50 +79,35 @@ namespace NadekoBot.Modules {
|
|||||||
.Alias("stop")
|
.Alias("stop")
|
||||||
.Description("Completely stops the music and unbinds the bot from the channel.")
|
.Description("Completely stops the music and unbinds the bot from the channel.")
|
||||||
.Do(e => {
|
.Do(e => {
|
||||||
if (Voice != null && Exit == false) {
|
SongQueue.Clear();
|
||||||
Exit = true;
|
if (CurrentSong != null) {
|
||||||
SongQueue = new List<YouTubeVideo>();
|
CurrentSong.Cancel();
|
||||||
|
CurrentSong = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cgb.CreateCommand("p")
|
cgb.CreateCommand("p")
|
||||||
.Alias("pause")
|
.Alias("pause")
|
||||||
.Description("Pauses the song")
|
.Description("Pauses the song")
|
||||||
.Do(async e => {
|
.Do(async e => {
|
||||||
if (Voice != null && Exit == false && CurrentSong != null) {
|
/*if (CurrentSong != null) {
|
||||||
Pause = !Pause;
|
CurrentSong.
|
||||||
if (Pause) {
|
}*/
|
||||||
await e.Send("Pausing. Run the command again to resume.");
|
await e.Send("Not yet implemented.");
|
||||||
} else {
|
|
||||||
await e.Send("Resuming...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cgb.CreateCommand("q")
|
cgb.CreateCommand("q")
|
||||||
.Alias("yq")
|
.Alias("yq")
|
||||||
.Description("Queue a song using a multi/single word name.\n**Usage**: `!m q Dream Of Venice`")
|
.Description("Queue a song using a multi/single word name.\n**Usage**: `!m q Dream Of Venice`")
|
||||||
.Parameter("Query", ParameterType.Unparsed)
|
.Parameter("Query", ParameterType.Unparsed)
|
||||||
.Do(async e => {
|
.Do(e => {
|
||||||
var youtube = YouTube.Default;
|
SongQueue.Add(new StreamRequest(NadekoBot.client, e, e.GetArg("Query")));
|
||||||
var video = youtube.GetAllVideos(Searches.FindYoutubeUrlByKeywords(e.Args[0]))
|
|
||||||
.Where(v => v.AdaptiveKind == AdaptiveKind.Audio)
|
|
||||||
.OrderByDescending(v => v.AudioBitrate).FirstOrDefault();
|
|
||||||
|
|
||||||
if (video?.Uri != "" && video.Uri != null) {
|
|
||||||
SongQueue.Add(video);
|
|
||||||
await e.Send("**Queued** " + video.FullName);
|
|
||||||
} else {
|
|
||||||
await e.Send("Failed to load that song.");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cgb.CreateCommand("lq")
|
cgb.CreateCommand("lq")
|
||||||
.Alias("ls").Alias("lp")
|
.Alias("ls").Alias("lp")
|
||||||
.Description("Lists up to 10 currently queued songs.")
|
.Description("Lists up to 10 currently queued songs.")
|
||||||
.Do(async e => {
|
.Do(async e => {
|
||||||
await e.Send(SongQueue.Count + " videos currently queued.");
|
await e.Send(":musical_note: " + SongQueue.Count + " videos currently queued.");
|
||||||
await e.Send(string.Join("\n", SongQueue.Select(v => v.FullName).Take(10)));
|
await e.Send(string.Join("\n", SongQueue.Select(v => v.Title).Take(10)));
|
||||||
});
|
});
|
||||||
|
|
||||||
cgb.CreateCommand("sh")
|
cgb.CreateCommand("sh")
|
||||||
@ -121,88 +119,21 @@ namespace NadekoBot.Modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SongQueue.Shuffle();
|
SongQueue.Shuffle();
|
||||||
await e.Send("Songs shuffled!");
|
await e.Send(":musical_note: Songs shuffled!");
|
||||||
});
|
|
||||||
|
|
||||||
cgb.CreateCommand("radio")
|
|
||||||
.Alias("music")
|
|
||||||
.Description("Binds to a voice and text channel in order to play music.")
|
|
||||||
.Parameter("ChannelName", ParameterType.Unparsed)
|
|
||||||
.Do(async e => {
|
|
||||||
if (Voice != null) return;
|
|
||||||
VoiceChannel = e.Server.FindChannels(e.GetArg("ChannelName").Trim(), ChannelType.Voice).FirstOrDefault();
|
|
||||||
Voice = await client.Audio().Join(VoiceChannel);
|
|
||||||
Exit = false;
|
|
||||||
NextSong = false;
|
|
||||||
Pause = false;
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
if (Exit) break;
|
|
||||||
if (SongQueue.Count == 0 || Pause) { Thread.Sleep(100); continue; }
|
|
||||||
if (!LoadNextSong()) break;
|
|
||||||
|
|
||||||
await Task.Run(async () => {
|
|
||||||
if (Exit) {
|
|
||||||
Voice = null;
|
|
||||||
Exit = false;
|
|
||||||
await e.Send("Exiting...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var streamer = new AudioStreamer(Music.CurrentSong.Uri);
|
|
||||||
streamer.Start();
|
|
||||||
while (streamer.BytesSentToTranscoder < 100 * 0x1000 || streamer.NetworkDone)
|
|
||||||
await Task.Delay(500);
|
|
||||||
|
|
||||||
int blockSize = 1920 * client.Audio().Config.Channels;
|
|
||||||
byte[] buffer = new byte[blockSize];
|
|
||||||
|
|
||||||
var msg = await e.Send("Playing " + Music.CurrentSong.FullName + " [00:00]");
|
|
||||||
int counter = 0;
|
|
||||||
int byteCount;
|
|
||||||
|
|
||||||
while ((byteCount = streamer.PCMOutput.Read(buffer, 0, blockSize)) > 0) {
|
|
||||||
Voice.Send(buffer, byteCount);
|
|
||||||
counter += blockSize;
|
|
||||||
if (NextSong) {
|
|
||||||
NextSong = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (Exit) {
|
|
||||||
Exit = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (Pause) Thread.Sleep(100);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Voice.Wait();
|
|
||||||
} catch (Exception ex) { Console.WriteLine(ex.ToString()); }
|
|
||||||
await Voice.Disconnect();
|
|
||||||
Voice = null;
|
|
||||||
VoiceChannel = null;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream GetAudioFileStream(string file) {
|
private async Task LoadNextSong() {
|
||||||
Process p = Process.Start(new ProcessStartInfo() {
|
|
||||||
FileName = "ffmpeg",
|
|
||||||
Arguments = "-i \"" + Uri.EscapeUriString(file) + "\" -f s16le -ar 48000 -af volume=1 -ac 2 pipe:1 ",
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = true
|
|
||||||
});
|
|
||||||
return p.StandardOutput.BaseStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool LoadNextSong() {
|
|
||||||
if (SongQueue.Count == 0) {
|
if (SongQueue.Count == 0) {
|
||||||
CurrentSong = null;
|
CurrentSong = null;
|
||||||
return false;
|
await Task.Delay(200);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
CurrentSong = SongQueue[0];
|
CurrentSong = SongQueue[0];
|
||||||
SongQueue.RemoveAt(0);
|
SongQueue.RemoveAt(0);
|
||||||
return true;
|
CurrentSong.Start();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +169,7 @@ namespace NadekoBot.Modules {
|
|||||||
public StreamTaskState State => streamTask?.State ?? StreamTaskState.Queued;
|
public StreamTaskState State => streamTask?.State ?? StreamTaskState.Queued;
|
||||||
|
|
||||||
|
|
||||||
public StreamRequest(DiscordClient client, MessageEventArgs e, string text) {
|
public StreamRequest(DiscordClient client, CommandEventArgs e, string text) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
Server = e.Server;
|
Server = e.Server;
|
||||||
Channel = e.Channel;
|
Channel = e.Channel;
|
||||||
@ -257,59 +188,29 @@ namespace NadekoBot.Modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ResolveLink() {
|
void ResolveLink() {
|
||||||
var url = RequestText;
|
var query = RequestText;
|
||||||
|
try {
|
||||||
|
var video = YouTube.Default.GetAllVideos(Searches.FindYoutubeUrlByKeywords(query))
|
||||||
|
.Where(v => v.AdaptiveKind == AdaptiveKind.Audio)
|
||||||
|
.OrderByDescending(v => v.AudioBitrate).FirstOrDefault();
|
||||||
|
|
||||||
if (url.IndexOf("soundcloud", StringComparison.OrdinalIgnoreCase) != -1) {
|
if (video == null)
|
||||||
var track = Services.SoundcloudService.GetTrackStreamUrl(url, out Title, out StreamUrl);
|
throw new Exception("Could not load any video elements"); // First one
|
||||||
Length = TimeSpan.FromMilliseconds(track.Duration);
|
|
||||||
Title = track.Title;
|
StreamUrl = video.Uri;
|
||||||
FileName = Uri.EscapeUriString(Title) + ".mp3";
|
Title = video.Title;
|
||||||
|
var fileName = Title.Replace("\\","_").Replace("/","_");
|
||||||
StartBuffering();
|
Path.GetInvalidPathChars().ForEach(c => { fileName = fileName.Replace(c, '_'); });
|
||||||
linkResolved = true;
|
FileName = fileName;
|
||||||
} else if (url.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) != -1 || url.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) != -1) {
|
|
||||||
try {
|
|
||||||
var infos = DownloadUrlResolver
|
|
||||||
.GetDownloadUrls(url.Trim())
|
|
||||||
.Where(i => i.AudioType != AudioType.Unknown)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (infos.Length == 0)
|
|
||||||
throw new Exception("Could not load any video elements");
|
|
||||||
|
|
||||||
var info = infos
|
|
||||||
.GroupBy(x => x.AudioBitrate) // Create groups for audio bitrates
|
|
||||||
.OrderByDescending(x => x.Key) // Group with max bitrate first
|
|
||||||
.Take(1) // Only take one group
|
|
||||||
.SelectMany(x => x) // Unpack group container again
|
|
||||||
.OrderBy(x => x.Resolution) // take vid with smallest resolution
|
|
||||||
.First(); // First one
|
|
||||||
|
|
||||||
StreamUrl = info.DownloadUrl;
|
|
||||||
Title = info.Title;
|
|
||||||
FileName = Uri.EscapeUriString(Title) + ".mp4";
|
|
||||||
|
|
||||||
StartBuffering();
|
|
||||||
linkResolved = true;
|
|
||||||
} catch (Exception) {
|
|
||||||
// Send a message to the guy that queued that
|
|
||||||
Channel.SendMessage(":warning: " + User.Mention + " Cannot load youtube url: `This video is not available in your country` or the url is corrupted somehow...");
|
|
||||||
Console.WriteLine("Cannot parse youtube url: " + url);
|
|
||||||
Cancel();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Is it a direct link oO ??
|
|
||||||
var format = validFormats.FirstOrDefault(f => url.EndsWith(f));
|
|
||||||
if (format == null) {
|
|
||||||
Console.WriteLine("Direct link: \"" + url + "\" does not end with a valid extension");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamUrl = url;
|
|
||||||
Title = url;
|
|
||||||
|
|
||||||
StartBuffering();
|
StartBuffering();
|
||||||
linkResolved = true;
|
linkResolved = true;
|
||||||
|
Channel.Send(":musical_note: **Queued** " + video.FullName);
|
||||||
|
} catch (Exception) {
|
||||||
|
// Send a message to the guy that queued that
|
||||||
|
Channel.SendMessage(":warning: " + User.Mention + " Cannot load youtube url: `This video is not available in your country` or the url is corrupted somehow...");
|
||||||
|
Console.WriteLine("Cannot parse youtube url: " + query);
|
||||||
|
Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +220,6 @@ namespace NadekoBot.Modules {
|
|||||||
var fullPath = Path.Combine(folder, FileName);
|
var fullPath = Path.Combine(folder, FileName);
|
||||||
|
|
||||||
FileStream fileStream;
|
FileStream fileStream;
|
||||||
FileStream readStream;
|
|
||||||
try {
|
try {
|
||||||
if (File.Exists(fullPath) && new FileInfo(fullPath).Length > 1024 * 2) {
|
if (File.Exists(fullPath) && new FileInfo(fullPath).Length > 1024 * 2) {
|
||||||
NetworkDone = true;
|
NetworkDone = true;
|
||||||
@ -338,13 +238,9 @@ namespace NadekoBot.Modules {
|
|||||||
Console.WriteLine("Exception while creating or opening stream buffers: " + ex);
|
Console.WriteLine("Exception while creating or opening stream buffers: " + ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Task.Run(() => {
|
Task.Run(() => {
|
||||||
AutoResetDelay fileLengthCheckDelay = new AutoResetDelay(500);
|
|
||||||
int byteCounter = 0;
|
int byteCounter = 0;
|
||||||
bool fileLengthDetermined = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var webClient = new WebClient();
|
var webClient = new WebClient();
|
||||||
@ -362,7 +258,7 @@ namespace NadekoBot.Modules {
|
|||||||
TotalSourceBytes += read;
|
TotalSourceBytes += read;
|
||||||
fileStream.Write(buffer, 0, read);
|
fileStream.Write(buffer, 0, read);
|
||||||
|
|
||||||
if (TotalSourceBytes > 1024 * 2 && Length.TotalSeconds < 0.1 && fileLengthCheckDelay.IsReady) {
|
if (TotalSourceBytes > 1024 * 2 && Length.TotalSeconds < 0.1) {
|
||||||
Length = GetFileLength(fullPath);
|
Length = GetFileLength(fullPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,9 +278,6 @@ namespace NadekoBot.Modules {
|
|||||||
|
|
||||||
Stopwatch resolveTimer = Stopwatch.StartNew();
|
Stopwatch resolveTimer = Stopwatch.StartNew();
|
||||||
|
|
||||||
if (!linkResolved || bufferingStream == null)
|
|
||||||
Channel.SendMessage($":musical_note: Resolving link...\r\n:warning: `Keep in mind that other people can 'steal' the bot by just starting a stream command in their own server...`\r\n");
|
|
||||||
|
|
||||||
while (resolveTimer.ElapsedMilliseconds < 8000) {
|
while (resolveTimer.ElapsedMilliseconds < 8000) {
|
||||||
if (bufferingStream != null)
|
if (bufferingStream != null)
|
||||||
break;
|
break;
|
||||||
@ -425,21 +318,6 @@ namespace NadekoBot.Modules {
|
|||||||
return client.Servers.SelectMany(s => s.VoiceChannels).FirstOrDefault(c => c.Users.Any(u => u.Id == user.Id));
|
return client.Servers.SelectMany(s => s.VoiceChannels).FirstOrDefault(c => c.Users.Any(u => u.Id == user.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetFormattedTitle() {
|
|
||||||
if (Length.TotalSeconds < double.Epsilon)
|
|
||||||
Length = GetFileLength(FileName);
|
|
||||||
|
|
||||||
if (Title != DefaultTitle)
|
|
||||||
return $"**{Title.Replace('*', '°')}** *({Length.ToString()})*";
|
|
||||||
|
|
||||||
// put into <> when it contains a domain
|
|
||||||
if (StreamUrl == null)
|
|
||||||
return "<" + RequestText + ">";
|
|
||||||
if (StreamUrl.Contains("http:") || StreamUrl.Contains("https:"))
|
|
||||||
return "<" + StreamUrl.Trim() + ">";
|
|
||||||
return StreamUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TimeSpan GetFileLength(string fileName) {
|
public static TimeSpan GetFileLength(string fileName) {
|
||||||
try {
|
try {
|
||||||
var startInfo = new ProcessStartInfo("ffprobe", $"-i \"{fileName}\" -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1");
|
var startInfo = new ProcessStartInfo("ffprobe", $"-i \"{fileName}\" -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1");
|
||||||
@ -540,7 +418,7 @@ namespace NadekoBot.Modules {
|
|||||||
|
|
||||||
// How much data is in the final output buffer?
|
// How much data is in the final output buffer?
|
||||||
// We dont want to transcode too much in advance
|
// We dont want to transcode too much in advance
|
||||||
if (available > 0 && availableRingSpace < 1) {
|
if (available > 0) {
|
||||||
int read = await sourceStream.ReadAsync(buffer, 0, (int)Math.Min(available, buffer.LongLength), cancellationToken);
|
int read = await sourceStream.ReadAsync(buffer, 0, (int)Math.Min(available, buffer.LongLength), cancellationToken);
|
||||||
if (read > 0) {
|
if (read > 0) {
|
||||||
// Write to transcoder
|
// Write to transcoder
|
||||||
@ -630,4 +508,115 @@ namespace NadekoBot.Modules {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class StreamTask {
|
||||||
|
readonly DiscordClient client;
|
||||||
|
readonly StreamRequest streamRequest;
|
||||||
|
readonly Stream bufferingStream;
|
||||||
|
|
||||||
|
CancellationTokenSource tokenSource;
|
||||||
|
Task audioTask;
|
||||||
|
|
||||||
|
public StreamTaskState State { get; private set; }
|
||||||
|
|
||||||
|
public StreamTask(DiscordClient client, StreamRequest streamRequest, Stream bufferingStream) {
|
||||||
|
this.streamRequest = streamRequest;
|
||||||
|
this.bufferingStream = bufferingStream;
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
State = StreamTaskState.Queued;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartStreaming() {
|
||||||
|
if (State != StreamTaskState.Queued)
|
||||||
|
return;
|
||||||
|
|
||||||
|
State = StreamTaskState.Playing;
|
||||||
|
tokenSource = new CancellationTokenSource();
|
||||||
|
audioTask = Task.Run(StreamFunc, tokenSource.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelStreaming() {
|
||||||
|
if (State != StreamTaskState.Queued && State != StreamTaskState.Playing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tokenSource?.Cancel(false);
|
||||||
|
audioTask?.Wait();
|
||||||
|
State = StreamTaskState.Completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task StreamFunc() {
|
||||||
|
CancellationToken cancellationToken = tokenSource.Token;
|
||||||
|
IAudioClient voiceClient = null;
|
||||||
|
TranscodingTask streamer = null;
|
||||||
|
try {
|
||||||
|
uint byteCounter = 0;
|
||||||
|
|
||||||
|
// Download and read audio from the url
|
||||||
|
streamer = new TranscodingTask(streamRequest, bufferingStream);
|
||||||
|
streamer.Start();
|
||||||
|
|
||||||
|
// Wait until we have at least a few kb transcoded or network stream done
|
||||||
|
while (true) {
|
||||||
|
if (streamRequest.NetworkDone) {
|
||||||
|
await Task.Delay(600);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (streamer.ReadyBytesLeft > 5 * 1024)
|
||||||
|
break;
|
||||||
|
await Task.Delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start streaming to voice
|
||||||
|
await streamRequest.Channel.SendMessage($":musical_note: Playing {streamRequest.Title}");
|
||||||
|
|
||||||
|
var audioService = client.Audio();
|
||||||
|
voiceClient = await audioService.Join(streamRequest.VoiceChannel);
|
||||||
|
|
||||||
|
int blockSize = 1920 * audioService.Config.Channels;
|
||||||
|
byte[] voiceBuffer = new byte[blockSize];
|
||||||
|
var ringBuffer = streamer.PCMOutput;
|
||||||
|
|
||||||
|
Stopwatch timeout = Stopwatch.StartNew();
|
||||||
|
while (true) {
|
||||||
|
var readCount = ringBuffer.Read(voiceBuffer, 0, voiceBuffer.Length);
|
||||||
|
|
||||||
|
if (readCount == 0) {
|
||||||
|
if (timeout.ElapsedMilliseconds > 1500) {
|
||||||
|
Console.WriteLine("Audio stream timed out. Disconnecting.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(200);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
timeout.Restart();
|
||||||
|
|
||||||
|
byteCounter += (uint)voiceBuffer.Length;
|
||||||
|
voiceClient.Send(voiceBuffer, 0, voiceBuffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamer.Cancel();
|
||||||
|
|
||||||
|
voiceClient.Wait();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
await streamRequest.Channel.SendMessage($":musical_note: {streamRequest.User.Mention} Something went wrong, please report this. :angry: :anger:");
|
||||||
|
Console.WriteLine("Exception while playing music: " + ex);
|
||||||
|
} finally {
|
||||||
|
if (voiceClient != null) {
|
||||||
|
State = StreamTaskState.Completed;
|
||||||
|
streamer?.Cancel();
|
||||||
|
await voiceClient.Disconnect();
|
||||||
|
await Task.Delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -88,17 +88,17 @@ namespace NadekoBot
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
//install modules
|
//install modules
|
||||||
modules.Install(new Administration(), "Administration", FilterType.Unrestricted);
|
modules.Add(new Administration(), "Administration", ModuleFilter.None);
|
||||||
modules.Install(new Conversations(), "Conversations", FilterType.Unrestricted);
|
modules.Add(new Conversations(), "Conversations", ModuleFilter.None);
|
||||||
modules.Install(new Gambling(), "Gambling", FilterType.Unrestricted);
|
modules.Add(new Gambling(), "Gambling", ModuleFilter.None);
|
||||||
modules.Install(new Games(), "Games", FilterType.Unrestricted);
|
modules.Add(new Games(), "Games", ModuleFilter.None);
|
||||||
modules.Install(new Music(), "Music", FilterType.Unrestricted);
|
modules.Add(new Music(), "Music", ModuleFilter.None);
|
||||||
modules.Install(new Searches(), "Searches", FilterType.Unrestricted);
|
modules.Add(new Searches(), "Searches", ModuleFilter.None);
|
||||||
if(trelloLoaded)
|
if(trelloLoaded)
|
||||||
modules.Install(new Trello(), "Trello", FilterType.Unrestricted);
|
modules.Add(new Trello(), "Trello", ModuleFilter.None);
|
||||||
|
|
||||||
//run the bot
|
//run the bot
|
||||||
client.Run(async () =>
|
client.ExecuteAndWait(async () =>
|
||||||
{
|
{
|
||||||
await client.Connect(c.Username, c.Password);
|
await client.Connect(c.Username, c.Password);
|
||||||
Console.WriteLine("Connected!");
|
Console.WriteLine("Connected!");
|
||||||
|
@ -68,6 +68,26 @@
|
|||||||
<HintPath>..\packages\VideoLibrary.1.3.1\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\libvideo.dll</HintPath>
|
<HintPath>..\packages\VideoLibrary.1.3.1\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\libvideo.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Manatee.Json, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c267f67a39449c62, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Manatee.Json.3.2.1\lib\net45\Manatee.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Manatee.StateMachine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=15909d91027a225e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Manatee.StateMachine.1.1.2\lib\net45\Manatee.StateMachine.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Manatee.Trello, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Manatee.Trello.1.8.2\lib\net45\Manatee.Trello.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Manatee.Trello.ManateeJson, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Manatee.Trello.ManateeJson.1.4.0\lib\net45\Manatee.Trello.ManateeJson.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Manatee.Trello.WebApi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Manatee.Trello.WebApi.1.0.1\lib\net45\Manatee.Trello.WebApi.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
@ -91,6 +111,14 @@
|
|||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
@ -122,6 +150,7 @@
|
|||||||
<Compile Include="Modules\Games.cs" />
|
<Compile Include="Modules\Games.cs" />
|
||||||
<Compile Include="Modules\Music.cs" />
|
<Compile Include="Modules\Music.cs" />
|
||||||
<Compile Include="Modules\Searches.cs" />
|
<Compile Include="Modules\Searches.cs" />
|
||||||
|
<Compile Include="Modules\Trello.cs" />
|
||||||
<Compile Include="NadekoBot.cs" />
|
<Compile Include="NadekoBot.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="StatsCollector.cs" />
|
<Compile Include="StatsCollector.cs" />
|
||||||
|
@ -26,7 +26,7 @@ namespace NadekoBot
|
|||||||
{
|
{
|
||||||
this._service = service;
|
this._service = service;
|
||||||
|
|
||||||
_service.RanCommand += StatsCollector_RanCommand;
|
_service.CommandExecuted += StatsCollector_RanCommand;
|
||||||
//NadekoBot.client.MessageReceived += Client_MessageReceived;
|
//NadekoBot.client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
StartCollecting();
|
StartCollecting();
|
||||||
|
Loading…
Reference in New Issue
Block a user