From 10323daaa1dbdefbcebb4ab33f6eadca1fc38d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique=20Ivanchechen?= Date: Tue, 31 Jan 2023 21:05:31 -0300 Subject: [PATCH] Removing NAudio dependency so it will work on Linux --- .github/workflows/ci.yml | 4 +- .gitignore | 2 + Kasbot.csproj | 1 - Modules/PublicModule.cs | 3 - Services/CommandHandlingService.cs | 2 +- Services/PlayerService.cs | 99 +++++++++++++++++++++--------- 6 files changed, 75 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d1e976..e617116 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ name: CI on: - push: - branches: [ "master" ] + # push: + # branches: [ "master" ] pull_request: branches: [ "master" ] diff --git a/.gitignore b/.gitignore index 6dd4c0e..0967eed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ appsettings.*.json .env* +Properties/launchSettings.json + .vs .vscode bin diff --git a/Kasbot.csproj b/Kasbot.csproj index 18b178e..f793392 100644 --- a/Kasbot.csproj +++ b/Kasbot.csproj @@ -10,7 +10,6 @@ - diff --git a/Modules/PublicModule.cs b/Modules/PublicModule.cs index 086e554..252e46c 100644 --- a/Modules/PublicModule.cs +++ b/Modules/PublicModule.cs @@ -1,10 +1,7 @@ using Discord; -using Discord.Audio; using Discord.Commands; using Kasbot.Services; -using NAudio.Wave; using TextCommandFramework.Services; -using YoutubeExplode; namespace TextCommandFramework.Modules { diff --git a/Services/CommandHandlingService.cs b/Services/CommandHandlingService.cs index 5709c27..65fe94c 100644 --- a/Services/CommandHandlingService.cs +++ b/Services/CommandHandlingService.cs @@ -37,7 +37,7 @@ namespace TextCommandFramework.Services return; var argPos = 0; - var prefix = "!"; + var prefix = "-"; //Check if the message sent has the specified prefix if (!message.HasStringPrefix(prefix, ref argPos)) return; diff --git a/Services/PlayerService.cs b/Services/PlayerService.cs index 5852e6a..842a444 100644 --- a/Services/PlayerService.cs +++ b/Services/PlayerService.cs @@ -1,9 +1,15 @@ -using Discord; +using AngleSharp; +using Discord; using Discord.Audio; +using Discord.Audio.Streams; using Discord.Commands; using Discord.WebSocket; -using NAudio.Wave; +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Pipes; using YoutubeExplode; +using YoutubeExplode.Videos.Streams; namespace Kasbot.Services { @@ -16,50 +22,83 @@ namespace Kasbot.Services Clients = new Dictionary(); } - private async Task DownloadAudioFromYoutube(string youtubeUrl) + private async Task DownloadAudioFromYoutube(string youtubeUrl) { var youtube = new YoutubeClient(); var videoId = await youtube.Search.GetVideosAsync(youtubeUrl).FirstOrDefaultAsync(); var streamInfoSet = await youtube.Videos.Streams.GetManifestAsync(videoId.Id); - var highestAudioStreamInfo = streamInfoSet.GetAudioStreams().OrderByDescending(s => s.Bitrate).FirstOrDefault(); - var streamVideo = await youtube.Videos.Streams.GetAsync(highestAudioStreamInfo); - var memoryStream = new MemoryStream(); - await streamVideo.CopyToAsync(memoryStream); - memoryStream.Position = 0; - return memoryStream; + var streamInfo = streamInfoSet.GetAudioOnlyStreams().GetWithHighestBitrate(); + var streamVideo = await youtube.Videos.Streams.GetAsync(streamInfo); + var fileName = $"{videoId.Id}.mp3"; + + using (var fileStream = new FileStream(fileName, FileMode.Create)) + { + await streamVideo.CopyToAsync(fileStream); + } + return fileName; } public async Task Play(SocketCommandContext Context, string arguments) { IVoiceChannel channel = (Context.User as IVoiceState).VoiceChannel; - var audioStream = await DownloadAudioFromYoutube(arguments); - if (audioStream is null) - { - await Context.Channel.SendMessageAsync("Failed to download audio from YouTube."); - return; - } + string filename = string.Empty; + try + { + filename = await DownloadAudioFromYoutube(arguments); + } + catch (Exception ex) + { + throw new Exception("Error while downloading video from YouTube!"); + } + var audioClient = await channel.ConnectAsync(); - using (var mp3Reader = new StreamMediaFoundationReader(audioStream)) + + using (var ffmpeg = CreateStream(filename)) + using (var output = ffmpeg.StandardOutput.BaseStream) + using (var discord = audioClient.CreatePCMStream(AudioApplication.Mixed)) { - var audioOut = audioClient.CreatePCMStream(AudioApplication.Music); - await audioClient.SetSpeakingAsync(true); - - var media = new Media + try { - AudioClient = audioClient, - Message = Context.Message, - Name = "", - AudioOutStream = audioOut, - }; - Clients.Add(Context.Guild, media); - - await mp3Reader.CopyToAsync(audioOut); - await audioClient.SetSpeakingAsync(false); + var media = new Media() + { + AudioClient = audioClient, + AudioOutStream = discord, + FileName = filename, + Message = Context.Message, + Name = "" + }; + Clients.Add(Context.Guild, media); + await output.CopyToAsync(discord); + } + finally + { + await discord.FlushAsync(); + File.Delete(filename); + } } } + private Process CreateStream(string filename) + { + var process = Process.Start(new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = $"-hide_banner -loglevel panic -i {filename} -ac 2 -f s16le -ar 48000 pipe:1", + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true + }); + + if (process == null || process.HasExited) + { + throw new Exception("Sorry, ffmpeg killed himself! Bah."); + } + + return process; + } + public async Task Stop(SocketCommandContext Context) { if (!Clients.ContainsKey(Context.Guild)) @@ -68,6 +107,7 @@ namespace Kasbot.Services var media = Clients[Context.Guild]; Clients.Remove(Context.Guild); + File.Delete(media.FileName); await Context.Message.DeleteAsync(); await media.Message.DeleteAsync(); await media.AudioOutStream.DisposeAsync(); @@ -80,6 +120,7 @@ namespace Kasbot.Services public class Media { public string Name { get; set; } + public string FileName { get; set; } public IAudioClient AudioClient { get; set; } public AudioOutStream AudioOutStream { get; set; } public SocketUserMessage Message { get; set; }