Merge branch 'refactoring' into 'master'

Refactoring

See merge request open/Geekbot.net!12
This commit is contained in:
Daan 2018-05-04 21:37:57 +00:00
commit 26a0c89cf7
18 changed files with 245 additions and 29 deletions

View file

@ -47,7 +47,7 @@ namespace Geekbot.net.Commands.Admin
catch (Exception e) catch (Exception e)
{ {
_errorHandler.HandleCommandException(e, Context, _errorHandler.HandleCommandException(e, Context,
$"I don't have enough permissions to give {user.Username} that role"); $"I don't have enough permissions do that");
} }
} }

View file

@ -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);
}
}
}
}

View file

@ -6,8 +6,8 @@ using Discord;
using Discord.Commands; using Discord.Commands;
using Geekbot.net.Lib; using Geekbot.net.Lib;
using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.ErrorHandling;
using Newtonsoft.Json;
using StackExchange.Redis; using StackExchange.Redis;
using Utf8Json;
namespace Geekbot.net.Commands.Integrations.Google 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 url = new Uri($"https://kgsearch.googleapis.com/v1/entities:search?languages=en&limit=1&query={searchText}&key={apiKey}");
var responseString = client.DownloadString(url); var responseString = client.DownloadString(url);
var response = JsonSerializer.Deserialize<GoogleKgApiResponseDto>(responseString); var response = JsonConvert.DeserializeObject<GoogleKgApiResponseDto>(responseString);
if (!response.ItemListElement.Any()) if (!response.ItemListElement.Any())
{ {
@ -48,13 +48,13 @@ namespace Geekbot.net.Commands.Integrations.Google
return; return;
} }
var data = response.ItemListElement.First().ResultDto; var data = response.ItemListElement.First().Result;
var eb = new EmbedBuilder(); var eb = new EmbedBuilder();
eb.Title = data.Name; eb.Title = data.Name;
if(!string.IsNullOrEmpty(data.Description)) eb.WithDescription(data.Description); 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?.Url)) eb.WithUrl(data.DetailedDtoDescription.Url);
if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.ArticleBody)) eb.AddField("Details", data.DetailedDtoDescription.ArticleBody); 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()); await ReplyAsync("", false, eb.Build());
} }

View file

@ -2,7 +2,7 @@
{ {
public class GoogleKgApiElementDto public class GoogleKgApiElementDto
{ {
public GoogleKgApiResultDto ResultDto { get; set; } public GoogleKgApiResultDto Result { get; set; }
public double ResultScore { get; set; } public double ResultScore { get; set; }
} }
} }

View file

@ -4,7 +4,7 @@
{ {
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; } public string Description { get; set; }
public GoogleKgApiImageDto ImageDto { get; set; } public GoogleKgApiImageDto Image { get; set; }
public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; } public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; }
} }
} }

View file

@ -12,7 +12,7 @@ using Geekbot.net.Lib.Logger;
using Geekbot.net.Lib.UserRepository; using Geekbot.net.Lib.UserRepository;
using StackExchange.Redis; using StackExchange.Redis;
namespace Geekbot.net.Commands.User.Rank namespace Geekbot.net.Commands.User.Ranking
{ {
public class Rank : ModuleBase public class Rank : ModuleBase
{ {
@ -37,8 +37,7 @@ namespace Geekbot.net.Commands.User.Rank
[Command("rank", RunMode = RunMode.Async)] [Command("rank", RunMode = RunMode.Async)]
[Remarks(CommandCategories.Statistics)] [Remarks(CommandCategories.Statistics)]
[Summary("get user top 10 in messages or karma")] [Summary("get user top 10 in messages or karma")]
public async Task RankCmd([Summary("type")] string typeUnformated = "messages", public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10)
[Summary("amount")] int amount = 10)
{ {
try try
{ {

View file

@ -1,4 +1,4 @@
namespace Geekbot.net.Commands.User.Rank namespace Geekbot.net.Commands.User.Ranking
{ {
internal class RankUserPolyfillDto internal class RankUserPolyfillDto
{ {

View file

@ -52,7 +52,7 @@ namespace Geekbot.net.Commands.Utils.Changelog
}); });
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var commit in commits.Take(10)) 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.Description = sb.ToString();
eb.WithFooter(new EmbedFooterBuilder eb.WithFooter(new EmbedFooterBuilder
{ {

View file

@ -2,8 +2,10 @@
namespace Geekbot.net.Commands.Utils.Changelog 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; } public DateTimeOffset Date { get; set; }
} }
} }

View file

@ -1,6 +1,6 @@
namespace Geekbot.net.Commands.Utils.Changelog namespace Geekbot.net.Commands.Utils.Changelog
{ {
internal class CommitDto public class CommitDto
{ {
public CommitInfoDto Commit { get; set; } public CommitInfoDto Commit { get; set; }
} }

View file

@ -1,8 +1,8 @@
namespace Geekbot.net.Commands.Utils.Changelog 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; } public string Message { get; set; }
} }
} }

View file

@ -3,7 +3,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<ApplicationIcon>derp.ico</ApplicationIcon> <ApplicationIcon>derp.ico</ApplicationIcon>
<Version>3.6.0</Version> <Version>3.7.0</Version>
<Company>Pizza and Coffee Studios</Company> <Company>Pizza and Coffee Studios</Company>
<Authors>Pizza and Coffee Studios</Authors> <Authors>Pizza and Coffee Studios</Authors>
<Description>A Discord bot</Description> <Description>A Discord bot</Description>

View file

@ -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<ulong, IAudioClient> _audioClients;
public AudioUtils()
{
_audioClients = new Dictionary<ulong, IAudioClient>();
_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;
}
}
}

View file

@ -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);
}
}

View file

@ -3,7 +3,7 @@
public class Constants public class Constants
{ {
public const string Name = "Geekbot"; public const string Name = "Geekbot";
public const double BotVersion = 3.6; public const double BotVersion = 3.7;
public const double ApiVersion = 1; public const double ApiVersion = 1;
} }
} }

View file

@ -23,7 +23,7 @@ namespace Geekbot.net.Lib.Logger
public void Trace(string source, string message, object extra = null) 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) 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) 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) 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}"; if (source != "Message") return $"[{source}] - {message}";
var m = (MessageDto) extra; 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}";
} }
} }
} }

View file

@ -17,13 +17,13 @@ namespace Geekbot.net.Lib.Logger
{ {
Console.WriteLine("Logging Geekbot Logs to Sumologic"); Console.WriteLine("Logging Geekbot Logs to Sumologic");
config.LoggingRules.Add( config.LoggingRules.Add(
new LoggingRule("*", LogLevel.Info, LogLevel.Fatal, new LoggingRule("*", LogLevel.Debug, LogLevel.Fatal,
new BufferedSumoLogicTarget() new BufferedSumoLogicTarget()
{ {
Url = Environment.GetEnvironmentVariable("GEEKBOT_SUMO"), Url = Environment.GetEnvironmentVariable("GEEKBOT_SUMO"),
SourceName = "GeekbotLogger", SourceName = "GeekbotLogger",
Layout = "${message}", Layout = "${message}",
UseConsoleLog = false, UseConsoleLog = true,
MaxQueueSizeBytes = 500000, MaxQueueSizeBytes = 500000,
FlushingAccuracy = 250, FlushingAccuracy = 250,
MaxFlushInterval = 10000, MaxFlushInterval = 10000,
@ -38,11 +38,11 @@ namespace Geekbot.net.Lib.Logger
{ {
var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info;
config.LoggingRules.Add( config.LoggingRules.Add(
new LoggingRule("*", minLevel, LogLevel.Fatal, new LoggingRule("*", LogLevel.Info, LogLevel.Fatal,
new ColoredConsoleTarget new ColoredConsoleTarget
{ {
Name = "Console", Name = "Console",
Encoding = Encoding.Unicode, Encoding = Encoding.UTF8,
Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}" Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}"
}) })
); );
@ -53,7 +53,7 @@ namespace Geekbot.net.Lib.Logger
{ {
Name = "File", Name = "File",
Layout = "[${longdate} ${level}] ${message}", Layout = "[${longdate} ${level}] ${message}",
Encoding = Encoding.Unicode, Encoding = Encoding.UTF8,
LineEnding = LineEndingMode.Default, LineEnding = LineEndingMode.Default,
MaxArchiveFiles = 30, MaxArchiveFiles = 30,
ArchiveNumbering = ArchiveNumberingMode.Date, ArchiveNumbering = ArchiveNumberingMode.Date,

View file

@ -8,6 +8,7 @@ using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Geekbot.net.Lib; using Geekbot.net.Lib;
using Geekbot.net.Lib.Audio;
using Geekbot.net.Lib.Clients; using Geekbot.net.Lib.Clients;
using Geekbot.net.Lib.Converters; using Geekbot.net.Lib.Converters;
using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.ErrorHandling;
@ -113,10 +114,11 @@ namespace Geekbot.net
var emojiConverter = new EmojiConverter(); var emojiConverter = new EmojiConverter();
var mtgManaConverter = new MtgManaConverter(); var mtgManaConverter = new MtgManaConverter();
var wikipediaClient = new WikipediaClient(); var wikipediaClient = new WikipediaClient();
var audioUtils = new AudioUtils();
_services.AddSingleton(_redis); _services.AddSingleton<IDatabase>(_redis);
_services.AddSingleton(logger); _services.AddSingleton<IUserRepository>(_userRepository);
_services.AddSingleton(_userRepository); _services.AddSingleton<IGeekbotLogger>(logger);
_services.AddSingleton<ILevelCalc>(levelCalc); _services.AddSingleton<ILevelCalc>(levelCalc);
_services.AddSingleton<IEmojiConverter>(emojiConverter); _services.AddSingleton<IEmojiConverter>(emojiConverter);
_services.AddSingleton<IFortunesProvider>(fortunes); _services.AddSingleton<IFortunesProvider>(fortunes);
@ -124,6 +126,7 @@ namespace Geekbot.net
_services.AddSingleton<IMalClient>(malClient); _services.AddSingleton<IMalClient>(malClient);
_services.AddSingleton<IMtgManaConverter>(mtgManaConverter); _services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
_services.AddSingleton<IWikipediaClient>(wikipediaClient); _services.AddSingleton<IWikipediaClient>(wikipediaClient);
_services.AddSingleton<IAudioUtils>(audioUtils);
logger.Information("Geekbot", "Connecting to Discord"); logger.Information("Geekbot", "Connecting to Discord");