public async Task LoadNextSong() { CurrentSong?.Stop(); CurrentSong = null; if (SongQueue.Count != 0) { CurrentSong = SongQueue[0]; SongQueue.RemoveAt(0); } else { VoiceClient?.Disconnect(); VoiceClient = null; return; } try { if (VoiceClient == null) { Console.WriteLine($"Joining voice channel [{DateTime.Now.Second}]"); //VoiceClient = //todo add a new event, to tell people nadeko is trying to join VoiceClient = await Discord.Audio.AudioExtensions.JoinAudio(VoiceChannel); Console.WriteLine($"Joined voicechannel [{DateTime.Now.Second}]"); } await Task.Factory.StartNew(async() => await CurrentSong?.Start(), TaskCreationOptions.LongRunning).Unwrap(); } catch (Exception ex) { Console.WriteLine($"Starting failed: {ex}"); CurrentSong?.Stop(); CurrentSong = null; } }
public async Task StartPlaylist() { if (IsPlaying) { return; } if (await IsPlaylistEmpty()) { return; } if (PlaybackChannel == null) { await ChatChannel.SafeSendMessage("Audio playback channel has not been set."); return; } if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel)) { return; } _voiceClient = await _client.Audio().Join(PlaybackChannel); while (true) { if (_stopPlaylistFlag) { _stopPlaylistFlag = false; break; } if (await IsPlaylistEmpty()) { return; } await StartCurrentTrackPlayback(); if (_prevFlag) { _prevFlag = false; TrackIndex--; } else if (!_skipToFlag) { TrackIndex++; } } _voiceClient.Wait(); await _voiceClient.Disconnect(); }
private void leave() { commands.CreateCommand("leave") .Description("Leaves the voice channel") .Do(async => { _vClient.Disconnect(); playlist.Clear(); inVoiceChannel = false; }); }
public void SendAudio(string filePath) // Audio sending control { var channelCount = bot.GetService <AudioService>().Config.Channels; // Get the number of AudioChannels our AudioService has been configured to use. var OutFormat = new WaveFormat(48000, 16, channelCount); // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. using (var MP3Reader = new Mp3FileReader(filePath)) // Create a new Disposable MP3FileReader, to read audio from the filePath parameter using (var resampler = new MediaFoundationResampler(MP3Reader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format { resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality int blockSize = OutFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer byte[] buffer = new byte[blockSize]; int byteCount; while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present { if (byteCount < blockSize) { // Incomplete Frame for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } _vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord if (_isPaused) { do { } while (_isPaused); } if (_isStopped) { break; } } _vClient.Disconnect(); _isStopped = true; _isPaused = false; Connected = false; } }
public static async Task SendAudio(string filepath, Channel voiceChannel) { vClient = await discord.GetService <AudioService>().Join(voiceChannel); try { var channelCount = discord.GetService <AudioService>().Config.Channels; // Get the number of AudioChannels our AudioService has been configured to use. var OutFormat = new WaveFormat(48000, 16, channelCount); // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. using (var WaveReader = new WaveFileReader(filepath)) // Create a new Disposable MP3FileReader, to read audio from the filePath parameter using (var resampler = new MediaFoundationResampler(WaveReader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format { resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality int blockSize = OutFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer byte[] buffer = new byte[blockSize]; int byteCount; while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0 && playingSong) // Read audio into our buffer, and keep a loop open while data is present { if (byteCount < blockSize) { // Incomplete Frame for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord } await vClient.Disconnect(); } } catch { //if something goes wrong. System.Console.WriteLine("lol oops"); } await vClient.Disconnect(); }
private async Task Play(Discord.Commands.CommandEventArgs e) { if (playing) { return; } if (discordAudio == null || discordAudio.Channel != e.User.VoiceChannel) { await Summon(e); } playing = true; Console.WriteLine(queue.Count); while (queue.Count > 0) { await SendAudio(e.Channel, queue[0]); queue.RemoveAt(0); } await discordAudio.Disconnect(); queue = new List <Song>(); playing = false; await e.Channel.SendMessage("Queue empty!"); }
private void PlayYouTube(IAudioClient audioClient, string youtubeURL) { IEnumerable <VideoInfo> downloadUrls = DownloadUrlResolver.GetDownloadUrls(youtubeURL); VideoInfo targetVideoInfo = downloadUrls.First(info => info.VideoType == VideoType.Mp4 && info.Resolution == 720); if (targetVideoInfo.RequiresDecryption) { DownloadUrlResolver.DecryptDownloadUrl(targetVideoInfo); } Console.WriteLine("Found download url {0}", targetVideoInfo.DownloadUrl); Process process = Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-i {targetVideoInfo.DownloadUrl} -f s16le -ar 48000 -ac 2 pipe:1", UseShellExecute = false, RedirectStandardOutput = true }); Console.WriteLine("Started ffmpeg"); Thread.Sleep(5000); int blockSize = 3840; byte[] buffer = new byte[blockSize]; int byteCount; while (!shouldStop) { byteCount = process.StandardOutput.BaseStream.Read(buffer, 0, blockSize); if (byteCount == 0) { break; } audioClient.Send(buffer, 0, byteCount); } audioClient.Wait(); if (shouldStop) { process.Kill(); shouldStop = false; audioClient.Disconnect(); } }
private Task <string> GetNextSong() { _skipThis = false; return(Task.Run(async() => { if (queue.Count == 0) { _playing = false; await _vclient.Disconnect(); return null; } else { string nsong = queue[0]; queue.RemoveAt(0); return Play(nsong); } })); }
public async Task Stream(string Chat, byte[] Sound) { IAudioClient AudioClient = null; try { var ChatId = ulong.Parse(Chat); if (!AudioClients.TryGetValue(ChatId, out AudioClient) || AudioClient.CancelToken.IsCancellationRequested) { var Channel = Client.Servers.SelectMany(x => x.VoiceChannels).Where(x => x.Id == ChatId).FirstOrDefault(); if (Channel == null) { return; } AudioClients.TryRemove(ChatId, out AudioClient); AudioClient = await Channel.JoinAudio(); if (AudioClients.TryAdd(ChatId, AudioClient)) { SendAudio = false; Task.Delay(750).ContinueWith(delegate { SendAudio = true; }); } } else if (AudioClient.State != ConnectionState.Connected) { Bot.Log("Connecting to audio in voice chat #" + ChatId); AudioClient = await AudioClient.Channel.JoinAudio(); } else if (Sound != null && SendAudio) { await AudioClient.OutputStream.WriteAsync(Sound, 0, Sound.Length); } } catch (Exception Ex) { Bot.Log(Ex); await AudioClient?.Disconnect(); } }
public async Task DisconnectClient() { try { if (AudioClient != null) { try { await AudioClient.Disconnect(); } catch (Exception Ex) { Ex.Log(); } Sending = null; AudioClient = null; } } catch { } }
// Private call private void SpeakCommand() { commands.CreateCommand(callCommand) .Do(async(e) => { // Pick a random quote int randomFileIndex = rand.Next(reaperLines.Length); string fileToPost = reaperLines[randomFileIndex]; // Add file path to queue audioQueue.Enqueue(fileToPost); // If queue is not already undergoing the process of emptying its contents if (!isBeingEmptied) { // Raise flag isBeingEmptied = true; // Connect to the voice channel voiceClient = await discord.GetService <AudioService>() .Join(e.User.VoiceChannel); // Dequeuing until the queue is empty string queueItem; while (audioQueue.TryDequeue(out queueItem)) { VoiceFunctions.playAudio(queueItem, voiceClient, discord); } // Disconnecting from voice channel await voiceClient.Disconnect(); // Lower flag isBeingEmptied = false; } }); }
private async void sendAudioQueue(Queue <Command> audioQueue) { IAudioClient _vClient = null; while (audioQueue.Count > 0) { Command current = audioQueue.Dequeue(); try { _vClient = await current.VoiceChannel.JoinAudio(); } catch (Exception e) { log.Error("Error joining channel: " + e.Message); break; } audioPlaying = true; send(current.Path, current, _vClient); } try { await _vClient.Disconnect(); } catch (Exception e) { log.Error("Error disconnecting: " + e.Message); return; } audioPlaying = false; }
// Streaming service for the radio stream public async Task RadioStream(string pathOrUrl, CommandEventArgs e) { // Fires when no IAudioClient has been found if (_audio == null) { throw new MissingMemberException(); } // Runs ffmpeg in another thread so it does not block non async methods like Createcommands effectively blocking everything new Thread(() => { Process process = Process.Start(new ProcessStartInfo { // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process FileName = "ffmpeg", Arguments = $"-i {pathOrUrl} -y " + // Here we provide a list of arguments to feed into FFmpeg. -i means the location of the file/URL it will read from "-f s16le -ar 48000 -ac 2 pipe:1", // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout. UseShellExecute = false, RedirectStandardOutput = true // Capture the stdout of the process }); Thread.Sleep(2000); // Sleep for a few seconds so FFmpeg can start processing data. int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono byte[] buffer = new byte[blockSize]; int byteCount; while (true) // Loop forever, so data will always be read { byteCount = process.StandardOutput.BaseStream // Access the underlying MemoryStream from the stdout of FFmpeg .Read(buffer, 0, blockSize); // Read stdout into the buffer while (byteCount == 0) { Thread.Sleep(2500); } // Call from leave command consider making boolean a method and making it return if (_stopAudio) { Process[] Processes = Process.GetProcessesByName("ffmpeg"); // gets all processes called ffmpeg if more than one instance of ffmpeg is present unstable effects WILL occur if (Processes.Length != 0) { foreach (Process Proc in Processes) { Proc.Kill(); // gets the first process called ffmpeg } _audio.Disconnect(); // leaves the audio channel } else { throw new ArgumentNullException(); } _stopAudio = false; // resets the soundstopcall } // call to change station, kills ffmpeg process to free up pipes otherwise the pipe will break or overflow if (_changeStation) { // gets all processes named ffmpeg. Process[] Processes = Process.GetProcessesByName("ffmpeg"); // gets all processes called ffmpeg if (Processes.Length != 0) { // there is a possibility that there are multiple ffmpeg processes running kills them all foreach (Process Proc in Processes) { Proc.Kill(); // kills the process } } _changeStation = false; // resets the changestation call } _audio.Send(buffer, 0, byteCount); // Send our data to Discord } //Program._audio.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now. }).Start(); }
//TODO: This isn't threadsafe internal async Task RemoveClient(Server server, IAudioClient client) { if (Config.EnableMultiserver && server != null) { if (_voiceClients.TryRemove(server.Id, out client)) { await client.Disconnect(); await (client as AudioClient).GatewaySocket.Disconnect(); } } }
//m r,radio - init //m n,next - next in que //m p,pause - pauses, call again to unpause //m yq [key_words] - queue from yt by keywords //m s,stop - stop //m sh - shuffle songs //m pl - current playlist public override void Install(ModuleManager manager) { var client = NadekoBot.client; manager.CreateCommands("!m", cgb => { //queue all more complex commands commands.ForEach(cmd => cmd.Init(cgb)); cgb.CreateCommand("n") .Alias("next") .Description("Goes to the next song in the queue.") .Do(e => { if (Voice != null && Exit == false) { NextSong = true; } }); cgb.CreateCommand("s") .Alias("stop") .Description("Completely stops the music and unbinds the bot from the channel.") .Do(e => { if (Voice != null && Exit == false) { Exit = true; SongQueue = new List <YouTubeVideo>(); } }); cgb.CreateCommand("p") .Alias("pause") .Description("Pauses the song") .Do(async e => { if (Voice != null && Exit == false && CurrentSong != null) { Pause = !Pause; if (Pause) { await e.Send("Pausing. Run the command again to resume."); } else { await e.Send("Resuming..."); } } }); cgb.CreateCommand("q") .Alias("yq") .Description("Queue a song using a multi/single word name.\n**Usage**: `!m q Dream Of Venice`") .Parameter("Query", ParameterType.Unparsed) .Do(async e => { var youtube = YouTube.Default; 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); if (SongQueue.Count > 1) { await e.Send("**Queued** " + video.FullName); } } }); cgb.CreateCommand("lq") .Alias("ls").Alias("lp") .Description("Lists up to 10 currently queued songs.") .Do(async e => { await e.Send(SongQueue.Count + " videos currently queued."); await e.Send(string.Join("\n", SongQueue.Select(v => v.FullName).Take(10))); }); cgb.CreateCommand("sh") .Description("Shuffles the current playlist.") .Do(async e => { if (SongQueue.Count < 2) { await e.Send("Not enough songs in order to perform the shuffle."); return; } SongQueue.Shuffle(); await e.Send("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; }); }); }
public void ForceStop() { _voiceClient?.Disconnect(); IsPlaying = false; }
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($"Playing **{streamRequest.Title}** [{streamRequest.Length}]"); 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) { await streamRequest.Channel.SendMessage($"Finished playing **{streamRequest.Title}**"); State = StreamTaskState.Completed; streamer?.Cancel(); await voiceClient.Disconnect(); await Task.Delay(500); } } }
public async Task StartPlaylist() { if (IsPlaying) return; if (await IsPlaylistEmpty()) return; if (PlaybackChannel == null) { await ChatChannel.SafeSendMessage("Audio playback channel has not been set."); return; } if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel)) return; _voiceClient = await _client.Audio().Join(PlaybackChannel); while (true) { if (_stopPlaylistFlag) { _stopPlaylistFlag = false; break; } if (await IsPlaylistEmpty()) return; await StartCurrentTrackPlayback(); if (_prevFlag) { _prevFlag = false; TrackIndex--; } else if (!_skipToFlag) TrackIndex++; } _voiceClient.Wait(); await _voiceClient.Disconnect(); }
// Start the bot, pulling the calendar service from the main thread. public DiscordBot(CalendarService calendarService, DriveService driveService) { // Properly initialise the client. client = new DiscordClient(xyz => { // Set log severity. xyz.LogLevel = LogSeverity.Info; }); // Display the log message to the terminal. client.Log.Message += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source} { e.Message}"); // Grab the provided prefix prefix = Program.config[1].ToCharArray()[0]; // Configure the command structure. client.UsingCommands(xyz => { // Set prefix character so that the bot knows what to look for. xyz.PrefixChar = prefix; xyz.AllowMentionPrefix = true; }); client.UsingAudio(xyz => { // We're only sending audio, not receiving. xyz.Mode = AudioMode.Outgoing; }); // Properly initialise the command service for issuing the commands to the bot. commands = client.GetService <CommandService>(); /* * ██████╗ █████╗ ███████╗██╗ ██████╗ * ██╔══██╗██╔══██╗██╔════╝██║██╔════╝ * ██████╔╝███████║███████╗██║██║ * ██╔══██╗██╔══██║╚════██║██║██║ * ██████╔╝██║ ██║███████║██║╚██████╗ * ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═════╝ */ commands.CreateCommand("help").Parameter("args", ParameterType.Multiple).Do(async(e) => { // Command displays specified help text. // Delete the command message. await e.Message.Delete(); // Initialise the arguments string string args = null; // If no arguments are passed, or 'all' is passed, we want to display all commands. if (e.Args.Length == 0 || e.Args.Contains("all")) { args = "general beer events shitpost sound"; } // Else we only want to display the ones that are specified. else { args = string.Join(" ", e.Args).ToLower(); } // Initialise the helptext list. List <string> helptext = new List <string>(); // Add the basic usage to the helptext. helptext.Add($"Command usage : `{prefix}command <argument>`"); // All text is pre-formatted when it's added to the list. // If general commands are specified, add them to the help text. if (args.Contains("general")) { helptext.Add("**General**"); helptext.Add("``` info : display basic info about the bot.\n" + " whois <user> : display <user>'s role on the server.\n" + "help <command group> : display help for specified command group.\n" + " list groups : list the command groups.\n" + " synchronise : sync the images & soundbytes with the Google Drive (Admin/OG FKTS only).\n" + " changelog : show changelog.```"); } // If beer commands are specified, add them to the help text. if (args.Contains("beer")) { helptext.Add("**Beer**"); helptext.Add($"``` find <beername> : Search for <beername> and present to text channel.\n" + $" suggest : get a random beer suggestion.\n" + $"giveme <beername> : grab the url of the store page of <beername> if possible.```"); } // If event commands are specified, add them to the help text. if (args.Contains("event")) { helptext.Add("**Event**"); helptext.Add("``` events : display upcoming events.\n" + "view <event> : display more information about <event>.```"); } // If shitposting commands are specified, add them to the help text. if (args.Contains("image")) { helptext.Add("**Random Image**"); helptext.Add("``` image : send a random shitpost.\n" + " blacklist : display the current blacklist\n" + "clearblacklist : clear the shitpost blacklist.```"); } // If sound commands are specified, add them to the help text. if (args.Contains("sound")) { helptext.Add("**Sound**"); helptext.Add("```play <soundbyte> : play the specified soundbyte.\n" + " list sounds : list available soundbytes.\n" + " queue : display the current queue\n" + " clear queue : clears the queue\n" + " disconnect : force the bot to disconnect from the voice channel.```"); } // Join the list into a continuous string, seperated by carriage returns string helpmessage = string.Join("\n", helptext.ToArray()); // Inform the user help is on the way, and send the help. await e.Channel.SendMessage($"Sending requested help for {e.User.Mention}"); await e.Channel.SendMessage($"{helpmessage}"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] Displaying help for {e.User.Name}"); }); commands.CreateCommand("whois").Parameter("otheruser", ParameterType.Multiple).Do(async(e) => { // Command displas the primary role of the specified user. // Notes the command being issued and who issued it into the terminal. Console.WriteLine($"[{e.Server}] Command 'whois' called by {e.User.Name}"); // Stores the provided name as a string. String name = string.Join(" ", e.Args); // Creates a DiscordUser object and finds the user in the server. Discord.User singleuser = e.Server.FindUsers(name).FirstOrDefault(t => t.Name == name);; // If the user exists... if (singleuser != null) { // If the users role is not 'everyone' if (singleuser.Roles.First().ToString() != "everyone") { // Converts role to a string, sends it to the FLIV function and tests if it begins with a vowel, this is for grammar. if (functions.FLIV(singleuser.Roles.First().ToString().ToUpper())) { // Send the message back to the channel with correct grammar (eg. an Admin). await e.Channel.SendMessage($"{singleuser.Name} is an {singleuser.Roles.First()}"); } else { // Send the message back to the channel with correct grammar (eg. a Moderator). await e.Channel.SendMessage($"{singleuser.Name} is a {singleuser.Roles.First()}"); } } else { // If the user has no special role, they're just a normal person. await e.Channel.SendMessage($"{singleuser.Name} is just some random person."); } } else { // In the case of not finding the user, reports this to the terminal. Console.WriteLine($"[{e.Server}] Command failed. No User '{e.GetArg("otheruser")}'"); // Also informs the command issuer by sending a message to the channel. await e.Channel.SendMessage($"Could not find user: {e.GetArg("otheruser")}"); } }); // Command to display the author and status of this bot. commands.CreateCommand("info").Do(async(e) => { // Command displays the bot info. // Delete the command message. await e.Message.Delete(); // Notes the command being issued and who issued it into the terminal. Console.WriteLine($"[{e.Server}] Full bot info shown for {e.User.Name}"); // Sends the information back to the channel await e.Channel.SendMessage($"CataBot v4, a Discord Bot made by Catalan.\n" + $"v4 adds Google Drive interaction."); }); commands.CreateCommand("list").Parameter("args", ParameterType.Required).Do(async(e) => { // Command lists the sounbytes or command groups // Delete the command message. await e.Message.Delete(); // Inform the user that their list will be shown. await e.Channel.SendMessage($"List shown for {e.User.Mention}"); // Display the correct list. if (e.GetArg("args").ToLower() == "sounds") { // List the available soundbytes to the text channel. await e.Channel.SendMessage($"*Available soundbytes:*"); string[] sounds = Directory.GetFiles(location + "sounds/"); for (int i = 0; i < sounds.Length; i++) { sounds[i] = sounds[i].Substring(sounds[i].LastIndexOf('/') + 1); sounds[i] = sounds[i].Substring(0, sounds[i].IndexOf(".mp3")); } await e.Channel.SendMessage($"```{string.Join("\n", sounds)}```"); Console.WriteLine($"[{e.Server}] Soundbyte list shown for {e.User.Name}"); } else if (e.GetArg("args").ToLower() == "groups") { // Display what the command groups are to the text channel. await e.Channel.SendMessage($"*Command Groups:*"); await e.Channel.SendMessage($"```null" + $"\nGeneral" + $"\nBeer" + $"\nEvents" + $"\nImages" + $"\nSound```"); Console.WriteLine($"[{e.Server}] Command groups shown for {e.User.Name}"); } else { // Inform the user if the specified list does not exist. await e.Channel.SendMessage($"{e.User.Mention} that list doesn't exist!"); } }); commands.CreateCommand("synchronise").Alias(new string[] { "sync" }).Do(async(e) => { // Command send a random shitpost to the text channel. // Delete the command message. await e.Message.Delete(); // Specificy the roles need to issue this command, string[] reqRoles = { "Admin", "OG FKTS" }; // If the user has the required permissions, execute the command as normal. if (reqRoles.Any(s => e.User.Roles.Any(r => r.Name.Contains(s)))) { // Inform the user that the shitpost is being sent await e.Channel.SendMessage($"Synchronising files for {e.User.Mention}"); // Set the file extensions. string[] imageExtensions = { ".jpg", ".png" }; string[] soundExtensions = { ".mp3", ".wav" }; try { // Pull the metadata for all image/sound files. List <Google.Apis.Drive.v3.Data.File> iFiles = drive.GetFiles(driveService, imageExtensions); List <Google.Apis.Drive.v3.Data.File> sFiles = drive.GetFiles(driveService, soundExtensions); // Synchronise the folders. drive.syncFiles(driveService, iFiles, "images/", e.Channel); drive.syncFiles(driveService, sFiles, "sounds/", e.Channel); await e.Channel.SendMessage("GDrive synchronisation complete."); Console.WriteLine($"[{e.Server}] Synchronised with GDrive ({e.User.Name})"); } catch { // If it fails, throw an error message to the user & console. Console.WriteLine($"[{e.Server}] Failed to sync"); await e.Channel.SendMessage("GDrive synchronisation failed."); } } else { // If the user doesn't have the correct permissions, inform them. await e.Channel.SendMessage($"{e.User.Mention} Insufficient permissions to sync files."); } }); commands.CreateCommand("exit").Do(async(e) => { // Command shuts down the bot. // Delete the command message. await e.Message.Delete(); await e.Channel.SendMessage($"***Shutting down CataBot***"); // If user is an admin. if (e.User.Roles.Any(s => s.Name.Contains("Admin"))) { Environment.Exit(0); } else { await e.Channel.SendMessage($"**YOU DO NOT HAVE ENOUGH BADGES TO TRAIN ME** {e.User.Mention}"); } }); /* * ██████╗ █████╗ ██╗ ███████╗███╗ ██╗██████╗ █████╗ ██████╗ * ██╔════╝██╔══██╗██║ ██╔════╝████╗ ██║██╔══██╗██╔══██╗██╔══██╗ * ██║ ███████║██║ █████╗ ██╔██╗ ██║██║ ██║███████║██████╔╝ * ██║ ██╔══██║██║ ██╔══╝ ██║╚██╗██║██║ ██║██╔══██║██╔══██╗ * ╚██████╗██║ ██║███████╗███████╗██║ ╚████║██████╔╝██║ ██║██║ ██║ * ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ */ commands.CreateCommand("events").Do(async(e) => { // Command displays all upcoming events. // Message handling for the command & log. Console.WriteLine($"[{e.Server}] Upcoming events shown for {e.User.Name}"); await e.Message.Delete(); // Set parameters and initial order for calendar events. calendarService = calendar.prepEvents(calendarService); // Begin the event feed. await e.Channel.SendMessage($"**Upcoming events:**"); if (calendarService.Events.List("primary").Execute().Items != null && calendarService.Events.List("primary").Execute().Items.Count > 0) { // Initialise event list List <calendar.EventListItem> eventList = calendar.eshortDetails(calendarService); // Create two new lists for events this month and next, Splitting the events list into the two new lists based on month. List <calendar.EventListItem> ThisMonth = eventList.Where(x => x.ToString().Contains(functions.SanitiseMonth(DateTime.Now.Month.ToString()))).ToList(); List <calendar.EventListItem> NextMonth = eventList.Where(x => x.ToString().Contains(functions.SanitiseMonth((DateTime.Now.Month + 1).ToString()))).ToList(); // Builds the list into a multi-line string that can be printed. string events = string.Join("\n", eventList.ToArray()); string eventsthismonth = string.Join("\n", ThisMonth.ToArray()); string eventsnextmonth = string.Join("\n", NextMonth.ToArray()); // Print out the upcoming events, handling if there are none in the appropriate month. await e.Channel.SendMessage($"*This Month:*"); if (ThisMonth.Count != 0) { await e.Channel.SendMessage($"```{eventsthismonth}```"); } else { await e.Channel.SendMessage($"```*No events this month*```"); } // Only display next month if there are any events. if (ThisMonth.Count < 1) { await e.Channel.SendMessage($"*Later:*"); await e.Channel.SendMessage($"```{eventsnextmonth}```"); } } else { // If there are no upcoming events at all, return this. await e.Channel.SendMessage($"No upcoming events found."); } }); commands.CreateCommand("view").Parameter("eventSearch", ParameterType.Multiple).Do(async(e) => { // Command displays a specific event to the text channel. // Delete the command message. await e.Message.Delete(); List <Event> events = new List <Event>(calendarService.Events.List("primary").Execute().Items); calendarService = calendar.prepEvents(calendarService); if (events != null && events.Count > 0) { string summaryMatch = calendar.matchEvent(calendarService, e.Args); string[] details = calendar.eventDetails(calendarService, summaryMatch); await e.Channel.SendMessage($"**Event:** *{details[0]}*\n" + $"`Starts: {details[3]} | {details[2]}`\n" + $"`Ends: {details[5]} | {details[4]}`\n" + $"Description:\n" + $"```{details[1]}```\n"); } else { await e.Channel.SendMessage($"No upcoming events to view"); } }); /* * ██████╗ ███████╗███████╗██████╗ * ██╔══██╗██╔════╝██╔════╝██╔══██╗ * ██████╔╝█████╗ █████╗ ██████╔╝ * ██╔══██╗██╔══╝ ██╔══╝ ██╔══██╗ * ██████╔╝███████╗███████╗██║ ██║ * ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝ */ List <string> beers = new List <string>(); beers.Add("brewery"); beers.Add("country"); beers.Add("styles"); commands.CreateCommand("find").Parameter("beer", ParameterType.Multiple).Do(async(e) => { // Command finds the specified beer and displays it. // Delete the command message. await e.Message.Delete(); // Grab the name of the beer to look for. string BeerToSearch = string.Join(" ", e.Args); // Inform the user that a beer will be searched. await e.Channel.SendMessage($"Searching '*{BeerToSearch}*' for {e.User.Mention}"); // Search for the beer and pull the URL. string url = beer.Search(BeerToSearch, beers); // Initialise lists to store beer info. List <string> MessageItem = new List <string>(); List <string> Message = new List <string>(); if (url != "Not found!") { // If beer was found, retrieve the details inc. image link MessageItem = beer.Retrieve(url, e.Channel, "RandomBeer"); // Send beer name. await e.Channel.SendMessage($"**{MessageItem[1]}**"); // Initialise a WebClient to grab the image. WebClient webClient = new WebClient(); // Download the image and save it. webClient.DownloadFile(MessageItem[0], "temp/beer-image.png"); // Dispose of the WebClient now that it is no longer needed. webClient.Dispose(); // Send the image that was downloaded. await e.Channel.SendFile("temp/beer-image.png"); // Send the remaining beer details. string message = string.Join("\n", MessageItem.GetRange(2, MessageItem.Count - 2).ToArray()); await e.Channel.SendMessage($"{message}"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] beer found for {e.User.Name} ({MessageItem[1]})"); } else { await e.Channel.SendMessage($"Couldn't find '*{BeerToSearch}*'"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] beer not found for {e.User.Name} ({BeerToSearch})"); } }); commands.CreateCommand("suggest").Do(async(e) => { // Command suggests a beer for the user and displays it. // Delete the command message. await e.Message.Delete(); // Inform the user that a beer will be suggested. await e.Channel.SendMessage($"Suggesting a beer for {e.User.Mention}"); // Search for a random beer and pull the URL. string url = beer.Search("RandomBeer", beers); // Initialise lists to store beer info. List <string> MessageItem = new List <string>(); List <string> Message = new List <string>(); // Error handling if no URL could be pulled for whatever reason. if (url != "Not found!") { // If beer was found, retrieve the details inc. image link MessageItem = beer.Retrieve(url, e.Channel, "RandomBeer"); // Send beer name. await e.Channel.SendMessage($"**{MessageItem[1]}**"); // Initialise a WebClient to grab the image. WebClient webClient = new WebClient(); // Download the image and save it. webClient.DownloadFile(MessageItem[0], "temp/beer-image.png"); // Dispose of the WebClient now that it is no longer needed. webClient.Dispose(); // Send the image that was downloaded. await e.Channel.SendFile("temp/beer-image.png"); // Send the remaining beer details. string message = string.Join("\n", MessageItem.GetRange(2, MessageItem.Count - 2).ToArray()); await e.Channel.SendMessage($"{message}"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] beer suggested for {e.User.Name} ({MessageItem[1]})"); } else { await e.Channel.SendMessage($"Couldn't suggest a beer"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] beer could not be suggested for {e.User.Name}"); } }); commands.CreateCommand("giveme").Parameter("BeerToSearch", ParameterType.Multiple).Do(async(e) => { // Command provides URL to the specified beer. // Delete the command message. await e.Message.Delete(); // Grab the name of the beer to look for. string BeerToSearch = string.Join(" ", e.Args); // Inform the user that the link is being grabbed. await e.Channel.SendMessage($"Grabbing store page for {BeerToSearch} for {e.User.Mention}"); // Find and pull the URL for the beer. string url = beer.Search(BeerToSearch, beers); // Send the URL to the channel. await e.Channel.SendMessage($"**URL:** {url}"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] beer URL pulled for {e.User.Name} ({BeerToSearch})"); }); /* * ███████╗ ██████╗ ██╗ ██╗███╗ ██╗██████╗ * ██╔════╝██╔═══██╗██║ ██║████╗ ██║██╔══██╗ * ███████╗██║ ██║██║ ██║██╔██╗ ██║██║ ██║ * ╚════██║██║ ██║██║ ██║██║╚██╗██║██║ ██║ * ███████║╚██████╔╝╚██████╔╝██║ ╚████║██████╔╝ * ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ */ commands.CreateCommand("play").Parameter("audiofile", ParameterType.Required).Do(async(e) => { // Command plays a specified soundbyte. // Delete the command message. await e.Message.Delete(); // Get audio file selection. string audiofile = e.GetArg("audiofile"); // Check if the requested file exists. if (functions.fileExists(audiofile)) { // Inform the user that the soundbyte is being played. await e.Channel.SendMessage($"Playing '*{audiofile}*' for {e.User.Mention}"); // Add the soundbyte to the queue. queue.Add(audiofile); // If we're not sending audio, we will need to start sending audio. if (!sendingAudio) { sendingAudio = true; // Check if the user is in a voice channel. if (e.User.VoiceChannel != null) { try { // If file exists, and user is in a voice channel, play it using the SendAudio function (further down). SendAudio(e.User.VoiceChannel, e.Channel, e.Server); // Inform the console. Console.WriteLine($"[{e.Server}] {audiofile} soundbyte played for {e.User.Name}"); } catch { // Inform the console. Console.WriteLine($"[{e.Server}] {audiofile} soundbyte could not be played for {e.User.Name}"); } } else { // If user not in a voice channel, inform the terminal and tell the user to join a voice channel. Console.WriteLine($"[{e.Server}] user {e.User.Name} not in voice channel"); await e.Channel.SendMessage($"{e.User.Mention} join a voice channel to use the soundboard!"); } } } else { // If the file does not exist, inform the user and the terminal. await e.Channel.SendMessage($"{e.User.Mention} Couldn't find sound '{audiofile}'"); // Inform the console of the command. Console.WriteLine($"[{e.Server}] file {audiofile} could not be found, or does not exist."); } }); commands.CreateCommand("queue").Do(async(e) => { // Command displays the queue. // Delete the command message. await e.Message.Delete(); // Inform the user the queue will be shown. await e.Channel.SendMessage($"Showing queue for {e.User.Name}"); // Grab the queue and turn it into a carriage return deliminated string. string Queue = string.Join("\n", queue.ToArray()); // Send the list to the text channel and inform the console. await e.Channel.SendMessage("*Soundbyte queue:*"); await e.Channel.SendMessage($"```{Queue}```"); Console.WriteLine($"[{e.Server}] Showing soundbyte queue for {e.User.Name}"); }); commands.CreateCommand("clearqueue").Alias(new string[] { "cq" }).Do(async(e) => { // Command clears the soundbyte queue. // Delete the command message. await e.Message.Delete(); // Inform the user the queue is being cleared. await e.Channel.SendMessage($"Clearing queue for {e.User.Mention}"); // Clear the blacklist. queue.Clear(); // Inform the console of the command. Console.WriteLine($"[{e.Server}] Queue cleared by {e.User.Name}"); }); commands.CreateCommand("disconnect").Do(async(s) => { // Command forces the bot to disconnect from the voice channel. // Delete the command message. await s.Message.Delete(); // Disconnect the client from the voice channel. await vClient.Disconnect(); // Clear the queue to avoid confusion upon restart of audio sending. queue.Clear(); }); /* * ██╗███╗ ███╗ █████╗ ██████╗ ███████╗███████╗ * ██║████╗ ████║██╔══██╗██╔════╝ ██╔════╝██╔════╝ * ██║██╔████╔██║███████║██║ ███╗█████╗ ███████╗ * ██║██║╚██╔╝██║██╔══██║██║ ██║██╔══╝ ╚════██║ * ██║██║ ╚═╝ ██║██║ ██║╚██████╔╝███████╗███████║ * ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ */ commands.CreateCommand("image").Do(async(e) => { // Command send a random shitpost to the text channel. // Delete the command message. await e.Message.Delete(); // Inform the user that the shitpost is being sent await e.Channel.SendMessage($"Sending random image for {e.User.Mention}"); // Get all the filenames of the correct filetype from the google drive. string[] files = Directory.GetFiles(location + "images/"); // Initialise a string to hold the file. string chosenfile = null; do { // Pick a random file. chosenfile = files[functions.GenIndex(files.Length)]; // Check if the file is on the blacklist if (!blacklist.ToArray().Contains(chosenfile.Substring(chosenfile.LastIndexOf('/') + 1))) { // Add the sent file to the blacklist. blacklist.Add(chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)); // If it isn't, try to send the file. try { // Send the file. await e.Channel.SendFile(chosenfile); // Inform the console. Console.WriteLine($"[{e.Server}] Sending random image ('{chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)}') for {e.User.Name}"); } catch { // Inform the console. Console.WriteLine($"[{e.Server}] Sending random image failure. Failed to send '{chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)}' for {e.User.Name}"); } break; } // If it is, repeat until it a non-blacklisted file is found and sent. } while (true); // If the blacklist is full, forget the first item. if (blacklist.Count > 100) { blacklist.RemoveAt(0); } // Inform the console of the command. Console.WriteLine($"[{e.Server}] Blacklist updated [{blacklist.Count}]"); }); commands.CreateCommand("blacklist").Do(async(e) => { // Delete the command message. await e.Message.Delete(); // Inform the user the queue will be cleared. await e.Channel.SendMessage($"Showing blacklist for {e.User.Name}"); string[] blcklst = blacklist.ToArray(); for (int i = 0; i < blcklst.Length; i++) { blcklst[i] = blcklst[i].Substring(blcklst[i].LastIndexOf('/')); } // Grab the queue and turn it into a carriage return deliminated string. string Blacklist = string.Join("\n", blcklst); // Send the list to the text channel and inform the console. await e.Channel.SendMessage("*Blacklist:*"); await e.Channel.SendMessage($"```{string.Join("\n",blacklist.ToArray())}```"); Console.WriteLine($"[{e.Server}] Showing blacklist for {e.User.Name}"); }); commands.CreateCommand("clearblacklist").Do(async(e) => { // Command clears the shitpost blacklist. // Delete the command message. await e.Message.Delete(); // Inform the user the blacklist is being cleared. await e.Channel.SendMessage($"Clearing random image blacklist for {e.User.Mention}"); // Clear the blacklist. blacklist.Clear(); // Inform the console of the command. Console.WriteLine($"[{e.Server}] Blacklist cleared by {e.User.Name}"); }); client.ExecuteAndWait(async() => { // Connects the client using it's unique token. await client.Connect("BOT TOKEN HERE", TokenType.Bot); // Sets the game to be the help prompt, so users can easily issue the help command. client.SetGame($"v4 - {prefix}help for help."); }); }
public static void disconnect(IAudioClient voiceClient) { voiceClient.Disconnect(); }