From 1ee627a915dd6018c2cd629698d378e6d5a5a555 Mon Sep 17 00:00:00 2001 From: runebaas Date: Thu, 11 Jan 2018 00:16:04 +0100 Subject: [PATCH] Groundwork for playing youtube videos to voice --- Geekbot.net/Commands/Voice.cs | 46 ++++++++++++-------- Geekbot.net/Lib/AudioClientCache.cs | 66 ++++++++++++++++++++++++++++- readme.md | 1 + 3 files changed, 93 insertions(+), 20 deletions(-) diff --git a/Geekbot.net/Commands/Voice.cs b/Geekbot.net/Commands/Voice.cs index 242d642..6fbcaa9 100644 --- a/Geekbot.net/Commands/Voice.cs +++ b/Geekbot.net/Commands/Voice.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Threading.Tasks; using Discord; using Discord.Commands; @@ -63,23 +64,32 @@ namespace Geekbot.net.Commands } } -// [Command("play")] -// public async Task play(IVoiceChannel channel = null) -// { -// try -// { -// var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id); -// if (audioClient == null) -// { -// await Context.Channel.SendMessageAsync("I'm not in a voice channel at the moment"); -// return; -// } -// -// } -// catch (Exception e) -// { -// _errorHandler.HandleCommandException(e, Context); -// } -// } + [Command("ytplay")] + public async Task ytplay(string url) + { + try + { + if (!url.Contains("youtube")) + { + await ReplyAsync("I can only play youtube videos"); + return; + } + var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id); + if (audioClient == null) + { + await ReplyAsync("I'm not in a voice channel at the moment"); + return; + } + var ffmpeg = _audioUtils.CreateStreamFromYoutube(url, Context.Guild.Id); + var output = ffmpeg.StandardOutput.BaseStream; + var discord = audioClient.CreatePCMStream(Discord.Audio.AudioApplication.Mixed); + await output.CopyToAsync(discord); + await discord.FlushAsync(); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } } } \ No newline at end of file diff --git a/Geekbot.net/Lib/AudioClientCache.cs b/Geekbot.net/Lib/AudioClientCache.cs index cf94c38..0869525 100644 --- a/Geekbot.net/Lib/AudioClientCache.cs +++ b/Geekbot.net/Lib/AudioClientCache.cs @@ -1,17 +1,28 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; using Discord.Audio; +using Discord.Net; namespace Geekbot.net.Lib { public class AudioUtils : IAudioUtils { + private string _tempFolderPath; private Dictionary _audioClients; public AudioUtils() { _audioClients = new Dictionary(); + _tempFolderPath = Path.GetFullPath("./temp/"); + if (!Directory.Exists(_tempFolderPath)) + { + Directory.CreateDirectory(_tempFolderPath); + } } - + public IAudioClient GetAudioClient(ulong guildId) { return _audioClients[guildId]; @@ -21,11 +32,62 @@ namespace Geekbot.net.Lib { _audioClients[guildId] = client; } + + public Process CreateStreamFromFile(string path) + { + var ffmpeg = new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = $"-i {path} -ac 2 -f s16le -ar 48000 pipe:1", + UseShellExecute = false, + RedirectStandardOutput = true, + }; + return Process.Start(ffmpeg); + } + + public Process CreateStreamFromYoutube(string url, ulong guildId) + { + var ytdlMediaUrl = GetYoutubeMediaUrl(url); + DownloadMediaUrl(ytdlMediaUrl, guildId); + return CreateStreamFromFile($"{_tempFolderPath}\\{guildId}.mp3"); + } + + private string GetYoutubeMediaUrl(string url) + { + var ytdl = new ProcessStartInfo() + { + FileName = "youtube-dl", + Arguments = $"-f bestaudio -g {url}", + UseShellExecute = false, + RedirectStandardOutput = true + }; + var output = Process.Start(ytdl).StandardOutput.ReadToEnd(); + if (string.IsNullOrWhiteSpace(output)) + { + throw new System.Exception("Could not get Youtube Media URL"); + } + return output; + } + + private void DownloadMediaUrl(string url, ulong guildId) + { + var ffmpeg = new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = $"-re -i \"${url}\" -c:a mp3 -b:a 256k {_tempFolderPath}\\{guildId}.mp3", + UseShellExecute = false, + RedirectStandardOutput = true, + }; + Process.Start(ffmpeg).WaitForExit(); + return; + } } public interface IAudioUtils { IAudioClient GetAudioClient(ulong guildId); void StoreAudioClient(ulong guildId, IAudioClient client); + Process CreateStreamFromFile(string path); + Process CreateStreamFromYoutube(string url, ulong guildId); } } \ No newline at end of file diff --git a/readme.md b/readme.md index 4c828d7..be5ba0a 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ You can invite Geekbot to your server with [this link](https://discordapp.com/oa * DotNet Core 2 * Redis * Discord.net +* ffmpeg ## Running