diff --git a/Geekbot.net/Commands/Admin/Mod.cs b/Geekbot.net/Commands/Admin/Mod.cs index 2dacee3..6f79157 100644 --- a/Geekbot.net/Commands/Admin/Mod.cs +++ b/Geekbot.net/Commands/Admin/Mod.cs @@ -47,7 +47,7 @@ namespace Geekbot.net.Commands.Admin catch (Exception e) { _errorHandler.HandleCommandException(e, Context, - $"I don't have enough permissions to give {user.Username} that role"); + $"I don't have enough permissions do that"); } } diff --git a/Geekbot.net/Commands/Audio/Voice.cs b/Geekbot.net/Commands/Audio/Voice.cs new file mode 100644 index 0000000..410d8e2 --- /dev/null +++ b/Geekbot.net/Commands/Audio/Voice.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib.Audio; +using Geekbot.net.Lib.ErrorHandling; + +namespace Geekbot.net.Commands.Audio +{ + public class Voice : ModuleBase + { + private readonly IAudioUtils _audioUtils; + private readonly IErrorHandler _errorHandler; + + public Voice(IErrorHandler errorHandler, IAudioUtils audioUtils) + { + _errorHandler = errorHandler; + _audioUtils = audioUtils; + } + +// [Command("join")] + public async Task JoinChannel() + { + try + { + // Get the audio channel + var channel = (Context.User as IGuildUser)?.VoiceChannel; + if (channel == null) + { + await Context.Channel.SendMessageAsync("You must be in a voice channel."); + return; + } + + var audioClient = await channel.ConnectAsync(); + _audioUtils.StoreAudioClient(Context.Guild.Id, audioClient); + await ReplyAsync($"Connected to {channel.Name}"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + +// [Command("disconnect")] + public async Task DisconnectChannel() + { + 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; + } + + await audioClient.StopAsync(); + await ReplyAsync("Disconnected from channel!"); + _audioUtils.Cleanup(Context.Guild.Id); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + _audioUtils.Cleanup(Context.Guild.Id); + } + } + +// [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 message = await Context.Channel.SendMessageAsync("Just a second, i'm still a bit slow at this"); + var ffmpeg = _audioUtils.CreateStreamFromYoutube(url, Context.Guild.Id); + var output = ffmpeg.StandardOutput.BaseStream; + await message.ModifyAsync(msg => msg.Content = "**Playing!** Please note that this feature is experimental"); + var discord = audioClient.CreatePCMStream(Discord.Audio.AudioApplication.Mixed); + await output.CopyToAsync(discord); + await discord.FlushAsync(); + _audioUtils.Cleanup(Context.Guild.Id); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + _audioUtils.Cleanup(Context.Guild.Id); + } + } + } + +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/Google.cs b/Geekbot.net/Commands/Integrations/Google/Google.cs index 8e880c4..7bd3a56 100644 --- a/Geekbot.net/Commands/Integrations/Google/Google.cs +++ b/Geekbot.net/Commands/Integrations/Google/Google.cs @@ -6,8 +6,8 @@ using Discord; using Discord.Commands; using Geekbot.net.Lib; using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; using StackExchange.Redis; -using Utf8Json; namespace Geekbot.net.Commands.Integrations.Google { @@ -40,7 +40,7 @@ namespace Geekbot.net.Commands.Integrations.Google var url = new Uri($"https://kgsearch.googleapis.com/v1/entities:search?languages=en&limit=1&query={searchText}&key={apiKey}"); var responseString = client.DownloadString(url); - var response = JsonSerializer.Deserialize(responseString); + var response = JsonConvert.DeserializeObject(responseString); if (!response.ItemListElement.Any()) { @@ -48,13 +48,13 @@ namespace Geekbot.net.Commands.Integrations.Google return; } - var data = response.ItemListElement.First().ResultDto; + var data = response.ItemListElement.First().Result; var eb = new EmbedBuilder(); eb.Title = data.Name; if(!string.IsNullOrEmpty(data.Description)) eb.WithDescription(data.Description); if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.Url)) eb.WithUrl(data.DetailedDtoDescription.Url); if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.ArticleBody)) eb.AddField("Details", data.DetailedDtoDescription.ArticleBody); - if(!string.IsNullOrEmpty(data.ImageDto?.ContentUrl)) eb.WithThumbnailUrl(data.ImageDto.ContentUrl); + if(!string.IsNullOrEmpty(data.Image?.ContentUrl)) eb.WithThumbnailUrl(data.Image.ContentUrl); await ReplyAsync("", false, eb.Build()); } diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs index 3c4a130..a48b184 100644 --- a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs @@ -2,7 +2,7 @@ { public class GoogleKgApiElementDto { - public GoogleKgApiResultDto ResultDto { get; set; } + public GoogleKgApiResultDto Result { get; set; } public double ResultScore { get; set; } } } \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs index 2c348c9..465f1d7 100644 --- a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs @@ -4,7 +4,7 @@ { public string Name { get; set; } public string Description { get; set; } - public GoogleKgApiImageDto ImageDto { get; set; } + public GoogleKgApiImageDto Image { get; set; } public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; } } } \ No newline at end of file diff --git a/Geekbot.net/Commands/User/Rank/Rank.cs b/Geekbot.net/Commands/User/Ranking/Rank.cs similarity index 95% rename from Geekbot.net/Commands/User/Rank/Rank.cs rename to Geekbot.net/Commands/User/Ranking/Rank.cs index 774ac5a..590921e 100644 --- a/Geekbot.net/Commands/User/Rank/Rank.cs +++ b/Geekbot.net/Commands/User/Ranking/Rank.cs @@ -12,7 +12,7 @@ using Geekbot.net.Lib.Logger; using Geekbot.net.Lib.UserRepository; using StackExchange.Redis; -namespace Geekbot.net.Commands.User.Rank +namespace Geekbot.net.Commands.User.Ranking { public class Rank : ModuleBase { @@ -37,8 +37,7 @@ namespace Geekbot.net.Commands.User.Rank [Command("rank", RunMode = RunMode.Async)] [Remarks(CommandCategories.Statistics)] [Summary("get user top 10 in messages or karma")] - public async Task RankCmd([Summary("type")] string typeUnformated = "messages", - [Summary("amount")] int amount = 10) + public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10) { try { diff --git a/Geekbot.net/Commands/User/Rank/RankUserPolyfillDto.cs b/Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs similarity index 77% rename from Geekbot.net/Commands/User/Rank/RankUserPolyfillDto.cs rename to Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs index f666ffc..625c326 100644 --- a/Geekbot.net/Commands/User/Rank/RankUserPolyfillDto.cs +++ b/Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs @@ -1,4 +1,4 @@ -namespace Geekbot.net.Commands.User.Rank +namespace Geekbot.net.Commands.User.Ranking { internal class RankUserPolyfillDto { diff --git a/Geekbot.net/Commands/Utils/Changelog/Changelog.cs b/Geekbot.net/Commands/Utils/Changelog/Changelog.cs index f956d7c..f1752f7 100644 --- a/Geekbot.net/Commands/Utils/Changelog/Changelog.cs +++ b/Geekbot.net/Commands/Utils/Changelog/Changelog.cs @@ -52,7 +52,7 @@ namespace Geekbot.net.Commands.Utils.Changelog }); var sb = new StringBuilder(); foreach (var commit in commits.Take(10)) - sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.AuthorDto.Date:yyyy-MM-dd})"); + sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.Author.Date:yyyy-MM-dd})"); eb.Description = sb.ToString(); eb.WithFooter(new EmbedFooterBuilder { diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs index ad37311..8debd77 100644 --- a/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs +++ b/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs @@ -2,8 +2,10 @@ namespace Geekbot.net.Commands.Utils.Changelog { - internal class CommitAuthorDto + public class CommitAuthorDto { + public string Name { get; set; } + public string Email { get; set; } public DateTimeOffset Date { get; set; } } } \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs index d5c5bab..3379697 100644 --- a/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs +++ b/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs @@ -1,6 +1,6 @@ namespace Geekbot.net.Commands.Utils.Changelog { - internal class CommitDto + public class CommitDto { public CommitInfoDto Commit { get; set; } } diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs index 102d2cd..9008343 100644 --- a/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs +++ b/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs @@ -1,8 +1,8 @@ namespace Geekbot.net.Commands.Utils.Changelog { - internal class CommitInfoDto + public class CommitInfoDto { - public CommitAuthorDto AuthorDto { get; set; } + public CommitAuthorDto Author { get; set; } public string Message { get; set; } } } \ No newline at end of file diff --git a/Geekbot.net/Geekbot.net.csproj b/Geekbot.net/Geekbot.net.csproj index 5cba28a..861085b 100755 --- a/Geekbot.net/Geekbot.net.csproj +++ b/Geekbot.net/Geekbot.net.csproj @@ -3,7 +3,7 @@ Exe netcoreapp2.0 derp.ico - 3.6.0 + 3.7.0 Pizza and Coffee Studios Pizza and Coffee Studios A Discord bot diff --git a/Geekbot.net/Lib/Audio/AudioUtils.cs b/Geekbot.net/Lib/Audio/AudioUtils.cs new file mode 100644 index 0000000..024019d --- /dev/null +++ b/Geekbot.net/Lib/Audio/AudioUtils.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using Discord.Audio; + +namespace Geekbot.net.Lib.Audio +{ + public class AudioUtils : IAudioUtils + { + private string _tempFolderPath; + private Dictionary _audioClients; + + public AudioUtils() + { + _audioClients = new Dictionary(); + _tempFolderPath = Path.GetFullPath("./tmp/"); + if (Directory.Exists(_tempFolderPath)) + { + Directory.Delete(_tempFolderPath, true); + } + Directory.CreateDirectory(_tempFolderPath); + } + + public IAudioClient GetAudioClient(ulong guildId) + { + return _audioClients[guildId]; + } + + public void StoreAudioClient(ulong guildId, IAudioClient client) + { + _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}"); + } + + public void Cleanup(ulong guildId) + { + File.Delete($"{_tempFolderPath}{guildId}"); + } + + 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 Exception("Could not get Youtube Media URL"); + } + return output; + } + + private void DownloadMediaUrl(string url, ulong guildId) + { + using (var web = new WebClient()) + { + web.DownloadFile(url, $"{_tempFolderPath}{guildId}"); + } +// var ffmpeg = new ProcessStartInfo +// { +// FileName = "ffmpeg", +// Arguments = $"-i \"{_tempFolderPath}{guildId}\" -c:a mp3 -b:a 256k {_tempFolderPath}{guildId}.mp3", +// UseShellExecute = false, +// RedirectStandardOutput = true, +// }; +// Process.Start(ffmpeg).WaitForExit(); +// File.Delete($"{_tempFolderPath}{guildId}"); + return; + } + + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Audio/IAudioUtils.cs b/Geekbot.net/Lib/Audio/IAudioUtils.cs new file mode 100644 index 0000000..4af1293 --- /dev/null +++ b/Geekbot.net/Lib/Audio/IAudioUtils.cs @@ -0,0 +1,15 @@ +using System.Diagnostics; +using Discord.Audio; + +namespace Geekbot.net.Lib.Audio +{ + public interface IAudioUtils + { + IAudioClient GetAudioClient(ulong guildId); + void StoreAudioClient(ulong guildId, IAudioClient client); + Process CreateStreamFromFile(string path); + Process CreateStreamFromYoutube(string url, ulong guildId); + void Cleanup(ulong guildId); + + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Constants.cs b/Geekbot.net/Lib/Constants.cs index d754b5c..dbba570 100644 --- a/Geekbot.net/Lib/Constants.cs +++ b/Geekbot.net/Lib/Constants.cs @@ -3,7 +3,7 @@ public class Constants { public const string Name = "Geekbot"; - public const double BotVersion = 3.6; + public const double BotVersion = 3.7; public const double ApiVersion = 1; } } \ No newline at end of file diff --git a/Geekbot.net/Lib/Logger/GeekbotLogger.cs b/Geekbot.net/Lib/Logger/GeekbotLogger.cs index 8cefdb4..45d65f5 100644 --- a/Geekbot.net/Lib/Logger/GeekbotLogger.cs +++ b/Geekbot.net/Lib/Logger/GeekbotLogger.cs @@ -23,7 +23,7 @@ namespace Geekbot.net.Lib.Logger public void Trace(string source, string message, object extra = null) { - _logger.Trace(CreateLogString("Debug", source, message, null, extra)); + _logger.Trace(CreateLogString("Trace", source, message, null, extra)); } public void Debug(string source, string message, object extra = null) @@ -43,7 +43,7 @@ namespace Geekbot.net.Lib.Logger public void Error(string source, string message, Exception stackTrace, object extra = null) { - _logger.Error(stackTrace, CreateLogString("Error", source, message, stackTrace, extra)); + _logger.Error(CreateLogString("Error", source, message, stackTrace, extra)); } private string CreateLogString(string type, string source, string message, Exception stackTrace = null, object extra = null) @@ -65,7 +65,7 @@ namespace Geekbot.net.Lib.Logger if (source != "Message") return $"[{source}] - {message}"; var m = (MessageDto) extra; - return $"[{source}] - [{m.Guild.Name} - {m.Channel.Name}] {m.User.Name}: {m.Message.Content}"; + return $"[{source}] - [{m?.Guild.Name} - {m?.Channel.Name}] {m?.User.Name}: {m?.Message.Content}"; } } } \ No newline at end of file diff --git a/Geekbot.net/Lib/Logger/LoggerFactory.cs b/Geekbot.net/Lib/Logger/LoggerFactory.cs index 53325a6..d32d80b 100644 --- a/Geekbot.net/Lib/Logger/LoggerFactory.cs +++ b/Geekbot.net/Lib/Logger/LoggerFactory.cs @@ -17,13 +17,13 @@ namespace Geekbot.net.Lib.Logger { Console.WriteLine("Logging Geekbot Logs to Sumologic"); config.LoggingRules.Add( - new LoggingRule("*", LogLevel.Info, LogLevel.Fatal, + new LoggingRule("*", LogLevel.Debug, LogLevel.Fatal, new BufferedSumoLogicTarget() { Url = Environment.GetEnvironmentVariable("GEEKBOT_SUMO"), SourceName = "GeekbotLogger", Layout = "${message}", - UseConsoleLog = false, + UseConsoleLog = true, MaxQueueSizeBytes = 500000, FlushingAccuracy = 250, MaxFlushInterval = 10000, @@ -38,11 +38,11 @@ namespace Geekbot.net.Lib.Logger { var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, + new LoggingRule("*", LogLevel.Info, LogLevel.Fatal, new ColoredConsoleTarget { Name = "Console", - Encoding = Encoding.Unicode, + Encoding = Encoding.UTF8, Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}" }) ); @@ -53,7 +53,7 @@ namespace Geekbot.net.Lib.Logger { Name = "File", Layout = "[${longdate} ${level}] ${message}", - Encoding = Encoding.Unicode, + Encoding = Encoding.UTF8, LineEnding = LineEndingMode.Default, MaxArchiveFiles = 30, ArchiveNumbering = ArchiveNumberingMode.Date, diff --git a/Geekbot.net/Program.cs b/Geekbot.net/Program.cs index f5f878a..82016fa 100755 --- a/Geekbot.net/Program.cs +++ b/Geekbot.net/Program.cs @@ -8,6 +8,7 @@ using Discord; using Discord.Commands; using Discord.WebSocket; using Geekbot.net.Lib; +using Geekbot.net.Lib.Audio; using Geekbot.net.Lib.Clients; using Geekbot.net.Lib.Converters; using Geekbot.net.Lib.ErrorHandling; @@ -113,10 +114,11 @@ namespace Geekbot.net var emojiConverter = new EmojiConverter(); var mtgManaConverter = new MtgManaConverter(); var wikipediaClient = new WikipediaClient(); + var audioUtils = new AudioUtils(); - _services.AddSingleton(_redis); - _services.AddSingleton(logger); - _services.AddSingleton(_userRepository); + _services.AddSingleton(_redis); + _services.AddSingleton(_userRepository); + _services.AddSingleton(logger); _services.AddSingleton(levelCalc); _services.AddSingleton(emojiConverter); _services.AddSingleton(fortunes); @@ -124,6 +126,7 @@ namespace Geekbot.net _services.AddSingleton(malClient); _services.AddSingleton(mtgManaConverter); _services.AddSingleton(wikipediaClient); + _services.AddSingleton(audioUtils); logger.Information("Geekbot", "Connecting to Discord");