diff --git a/Discord.Net b/Discord.Net index 4506fc5a..80384323 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 4506fc5a54fe31d826649dc413467c52a3cd7896 +Subproject commit 80384323790471d254c7db5c237a49dc62624378 diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 598a19b0..ad6e7023 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -9,6 +9,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Discord.WebSocket; +using NadekoBot.Services.Database; namespace NadekoBot.Modules.Gambling { @@ -19,15 +21,27 @@ namespace NadekoBot.Modules.Gambling { public enum CurrencyEvent { - FlowerReaction + FlowerReaction, + SneakyGameStatus } //flower reaction event public static readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + + private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10) + .Concat(Enumerable.Range(65, 26)) + .Concat(Enumerable.Range(97, 26)) + .Select(x => (char)x) + .ToArray(); + + public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); + + private static string _secretCode = String.Empty; + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [OwnerOnly] - public async Task StartEvent(CurrencyEvent e) + public async Task StartEvent(CurrencyEvent e, int arg = -1) { var channel = (ITextChannel)Context.Channel; try @@ -38,6 +52,9 @@ namespace NadekoBot.Modules.Gambling case CurrencyEvent.FlowerReaction: await FlowerReactionEvent(Context).ConfigureAwait(false); break; + case CurrencyEvent.SneakyGameStatus: + await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false); + break; default: break; } @@ -45,6 +62,63 @@ namespace NadekoBot.Modules.Gambling catch { } } + public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg) + { + int num; + if (arg == null || arg < 5) + num = 60; + else + num = arg.Value; + + if (_secretCode != String.Empty) + return; + var rng = new NadekoRandom(); + + for (int i = 0; i < 5; i++) + { + _secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)]; + } + + await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName) + .ConfigureAwait(false); + try + { + await Context.Channel.SendConfirmAsync($"SneakyGameStatus event started", + $"Users must type a secret code to get 100 currency.\n" + + $"Lasts {num} seconds. Don't tell anyone. Shhh.") + .ConfigureAwait(false); + } + catch { } + + + NadekoBot.Client.MessageReceived += SneakyGameMessageReceivedEventHandler; + await Task.Delay(num * 1000); + NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler; + + _sneakyGameAwardedUsers.Clear(); + _secretCode = String.Empty; + + await NadekoBot.Client.SetGameAsync($"SneakyGame event ended.") + .ConfigureAwait(false); + } + + private static Task SneakyGameMessageReceivedEventHandler(SocketMessage arg) + { + if (arg.Content == _secretCode && + _sneakyGameAwardedUsers.Add(arg.Author.Id)) + { + var _ = Task.Run(async () => + { + await CurrencyHandler.AddCurrencyAsync(arg.Author, "Sneaky Game Event", 100, false) + .ConfigureAwait(false); + + try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); } + catch { } + }); + } + + return Task.Delay(0); + } public static async Task FlowerReactionEvent(CommandContext Context) { diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 3a365bf0..f5a2a454 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -506,7 +506,7 @@ namespace NadekoBot.Modules.Gambling title = AffinityTitles.Sloot; else if (count < 17) title = AffinityTitles.Depraved; - else if (count < 20) + else title = AffinityTitles.Harlot; return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 8db03d30..ceaa4300 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Gambling return; } await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver}!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} gifted {amount}{CurrencySign} to {Format.Bold(receiver.ToString())}!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Gambling await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount}{CurrencySign} to <@{usrId}>!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 8dfd7d5a..6faf288c 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games [NadekoModule("Games", ">")] public partial class Games : DiscordModule { - private static IEnumerable _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text); + private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray(); [NadekoCommand, Usage, Description, Aliases] @@ -37,7 +37,7 @@ namespace NadekoBot.Modules.Games await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false)) - .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false))); + .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false))); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 6d101975..e11b680e 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -71,6 +71,7 @@ namespace NadekoBot.Modules.Music.Classes public event Action OnPauseChanged = delegate { }; public IVoiceChannel PlaybackVoiceChannel { get; private set; } + public ITextChannel OutputTextChannel { get; set; } private bool Destroyed { get; set; } = false; public bool RepeatSong { get; private set; } = false; @@ -84,10 +85,12 @@ namespace NadekoBot.Modules.Music.Classes public event Action SongRemoved = delegate { }; - public MusicPlayer(IVoiceChannel startingVoiceChannel, float? defaultVolume) + public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume) { if (startingVoiceChannel == null) throw new ArgumentNullException(nameof(startingVoiceChannel)); + + OutputTextChannel = outputChannel; Volume = defaultVolume ?? 1.0f; PlaybackVoiceChannel = startingVoiceChannel; diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index b7c41b55..5ad9918c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -797,6 +797,23 @@ namespace NadekoBot.Modules.Music await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task SetMusicChannel() + { + MusicPlayer musicPlayer; + if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) + { + await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false); + return; + } + + musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel; + + await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false); + } + public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) { if (voiceCh == null || voiceCh.Guild != textCh.Guild) @@ -815,7 +832,7 @@ namespace NadekoBot.Modules.Music { vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume; } - var mp = new MusicPlayer(voiceCh, vol); + var mp = new MusicPlayer(voiceCh, textCh, vol); IUserMessage playingMessage = null; IUserMessage lastFinishedMessage = null; mp.OnCompleted += async (s, song) => @@ -825,7 +842,7 @@ namespace NadekoBot.Modules.Music if (lastFinishedMessage != null) lastFinishedMessage.DeleteAfter(0); - lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) @@ -833,7 +850,14 @@ namespace NadekoBot.Modules.Music if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal) { - await QueueSong(await queuer.Guild.GetCurrentUserAsync(), textCh, voiceCh, (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false); + var relatedVideos = (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList(); + if(relatedVideos.Count > 0) + await QueueSong(await queuer.Guild.GetCurrentUserAsync(), + textCh, + voiceCh, + relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)], + silent, + musicType).ConfigureAwait(false); } } catch { } @@ -850,7 +874,7 @@ namespace NadekoBot.Modules.Music if (playingMessage != null) playingMessage.DeleteAfter(0); - playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) @@ -859,22 +883,21 @@ namespace NadekoBot.Modules.Music catch { } }; mp.OnPauseChanged += async (paused) => - { - try - { - IUserMessage msg; - if (paused) - msg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); - else - msg = await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); - - if (msg != null) - msg.DeleteAfter(10); - } - catch { } - }; - + { + try + { + IUserMessage msg; + if (paused) + msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); + else + msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); + if (msg != null) + msg.DeleteAfter(10); + } + catch { } + }; + mp.SongRemoved += async (song, index) => { try @@ -885,7 +908,7 @@ namespace NadekoBot.Modules.Music .WithFooter(ef => ef.WithText(song.PrettyInfo)) .WithErrorColor(); - await textCh.EmbedAsync(embed).ConfigureAwait(false); + await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false); } catch { } diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 27840678..8abcfee8 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -320,10 +320,10 @@ namespace NadekoBot.Modules.Searches .ConfigureAwait(false); try { - var items = JArray.Parse(response).Shuffle().ToList(); - if (items == null) + var items = JArray.Parse(response).ToArray(); + if (items == null || items.Length == 0) throw new KeyNotFoundException("Cannot find a card by that name"); - var item = items[0]; + var item = items[new NadekoRandom().Next(0, items.Length)]; var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString()); var cost = item["cost"].ToString(); var desc = item["text"].ToString(); @@ -379,13 +379,16 @@ namespace NadekoBot.Modules.Searches throw new KeyNotFoundException("Cannot find a card by that name"); foreach (var item in items.Where(item => item.HasValues && item["img"] != null).Take(4)) { - using (var sr = await http.GetStreamAsync(item["img"].ToString())) + await Task.Run(async () => { - var imgStream = new MemoryStream(); - await sr.CopyToAsync(imgStream); - imgStream.Position = 0; - images.Add(new ImageSharp.Image(imgStream)); - } + using (var sr = await http.GetStreamAsync(item["img"].ToString())) + { + var imgStream = new MemoryStream(); + await sr.CopyToAsync(imgStream); + imgStream.Position = 0; + images.Add(new ImageSharp.Image(imgStream)); + } + }).ConfigureAwait(false); } string msg = null; if (items.Count > 4) @@ -393,7 +396,7 @@ namespace NadekoBot.Modules.Searches msg = "⚠ Found over 4 images. Showing random 4."; } var ms = new MemoryStream(); - images.AsEnumerable().Merge().SaveAsPng(ms); + await Task.Run(() => images.AsEnumerable().Merge().SaveAsPng(ms)); ms.Position = 0; await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 66ffa3c2..b2594d3a 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -97,8 +97,10 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) - .WithThumbnailUrl(user.RealAvatarUrl()) .WithColor(NadekoBot.OkColor); + + if (user.AvatarId != null) + embed.WithThumbnailUrl(user.RealAvatarUrl()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index fd60a591..8add0707 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -93,24 +93,31 @@ namespace NadekoBot.Modules.Utility var isAdmin = ((IGuildUser)Context.Message.Author).GuildPermissions.Administrator; keyword = keyword.ToUpperInvariant(); + var sucess = false; string response; using (var uow = DbHandler.UnitOfWork()) { - var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword); + var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword)?.Where(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id).ToArray(); if (qs == null || !qs.Any()) { - await Context.Channel.SendErrorAsync("No quotes found.").ConfigureAwait(false); - return; + sucess = false; + response = "No quotes found which you can remove."; } + else + { + var q = qs[new NadekoRandom().Next(0, qs.Length)]; - var q = qs.Shuffle().FirstOrDefault(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id); - - uow.Quotes.Remove(q); - await uow.CompleteAsync().ConfigureAwait(false); - response = "🗑 **Deleted a random quote.**"; + uow.Quotes.Remove(q); + await uow.CompleteAsync().ConfigureAwait(false); + sucess = true; + response = "🗑 **Deleted a random quote.**"; + } } - await Context.Channel.SendConfirmAsync(response); + if(sucess) + await Context.Channel.SendConfirmAsync(response); + else + await Context.Channel.SendErrorAsync(response); } [NadekoCommand, Usage, Description, Aliases] @@ -126,7 +133,7 @@ namespace NadekoBot.Modules.Utility using (var uow = DbHandler.UnitOfWork()) { var quotes = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword); - + //todo kwoth please don't be complete retard uow.Quotes.RemoveRange(quotes.ToArray());//wtf?! await uow.CompleteAsync(); diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 304b2782..1c1af1e0 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -15,6 +15,8 @@ using System.Threading; using ImageSharp; using System.Collections.Generic; using Newtonsoft.Json; +using Discord.WebSocket; +using NadekoBot.Services; namespace NadekoBot.Modules.Utility { @@ -113,21 +115,29 @@ namespace NadekoBot.Modules.Utility game = game.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(game)) return; - var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync()) + + var socketGuild = Context.Guild as SocketGuild; + if (socketGuild == null) { + _log.Warn("Can't cast guild to socket guild."); + return; + } + var rng = new NadekoRandom(); + var arr = await Task.Run(() => socketGuild.Users .Where(u => u.Game?.Name?.ToUpperInvariant() == game) .Select(u => u.Username) - .Shuffle() + .OrderBy(x => rng.Next()) .Take(60) - .ToList(); + .ToArray()).ConfigureAwait(false); int i = 0; - if (!arr.Any()) + if (arr.Length == 0) await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); - else { + else + { await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) .Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```") .ConfigureAwait(false); - } + } } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index ae2ff2c6..e89ba368 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6782,6 +6782,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to setmusicchannel smch. + /// + public static string setmusicchannel_cmd { + get { + return ResourceManager.GetString("setmusicchannel_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in.. + /// + public static string setmusicchannel_desc { + get { + return ResourceManager.GetString("setmusicchannel_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}smch`. + /// + public static string setmusicchannel_usage { + get { + return ResourceManager.GetString("setmusicchannel_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to setmuterole. /// @@ -8340,7 +8367,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}voice+text`. + /// Looks up a localized string similar to `{0}v+t`. /// public static string voiceplustext_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a31288b1..7ee5714b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -340,7 +340,7 @@ Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. - `{0}voice+text` + `{0}v+t` scsc @@ -3033,4 +3033,13 @@ `{0}mal straysocks` + + setmusicchannel smch + + + Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. + + + `{0}smch` + \ No newline at end of file diff --git a/src/NadekoBot/_libs/32/libsodium.dll b/src/NadekoBot/_libs/32/libsodium.dll new file mode 100644 index 00000000..a9ab5078 Binary files /dev/null and b/src/NadekoBot/_libs/32/libsodium.dll differ diff --git a/src/NadekoBot/_libs/32/opus.dll b/src/NadekoBot/_libs/32/opus.dll new file mode 100644 index 00000000..f867793e Binary files /dev/null and b/src/NadekoBot/_libs/32/opus.dll differ diff --git a/src/NadekoBot/_libs/64/libsodium.dll b/src/NadekoBot/_libs/64/libsodium.dll new file mode 100644 index 00000000..f5de830e Binary files /dev/null and b/src/NadekoBot/_libs/64/libsodium.dll differ diff --git a/src/NadekoBot/_libs/64/opus.dll b/src/NadekoBot/_libs/64/opus.dll new file mode 100644 index 00000000..a962869f Binary files /dev/null and b/src/NadekoBot/_libs/64/opus.dll differ