NadekoBot/NadekoBot.Modules.Utility/Utility.cs

368 lines
16 KiB
C#
Raw Normal View History

2016-08-13 18:45:08 +00:00
using Discord;
using Discord.Commands;
using System;
using System.Linq;
using System.Threading.Tasks;
2016-08-15 14:57:40 +00:00
using System.Text;
using NadekoBot.Extensions;
using System.Reflection;
using NadekoBot.Services.Impl;
2016-12-24 07:05:43 +00:00
using System.Net.Http;
2017-01-05 12:49:50 +00:00
using System.Collections.Concurrent;
using System.Threading;
using ImageSharp;
2017-01-11 13:05:57 +00:00
using System.Collections.Generic;
using Newtonsoft.Json;
2017-01-29 21:54:27 +00:00
using Discord.WebSocket;
2017-04-03 10:43:59 +00:00
using System.Diagnostics;
2017-07-17 19:42:36 +00:00
using NadekoBot.Common;
using NadekoBot.Common.Attributes;
using Color = Discord.Color;
2017-05-29 23:53:16 +00:00
using NadekoBot.Services;
2016-08-13 18:45:08 +00:00
2017-05-29 23:53:16 +00:00
namespace NadekoBot.Modules.Utility
2016-08-13 18:45:08 +00:00
{
public partial class Utility : NadekoTopLevelModule
2016-08-13 18:45:08 +00:00
{
private readonly DiscordSocketClient _client;
2017-05-22 23:59:31 +00:00
private readonly IStatsService _stats;
private readonly IBotCredentials _creds;
2017-07-15 03:23:46 +00:00
private readonly ShardsCoordinator _shardCoord;
2017-01-05 12:49:50 +00:00
2017-07-19 07:31:00 +00:00
public Utility(NadekoBot nadeko, DiscordSocketClient client, IStatsService stats, IBotCredentials creds)
{
2017-05-22 23:59:31 +00:00
_client = client;
_stats = stats;
_creds = creds;
2017-07-19 07:31:00 +00:00
_shardCoord = nadeko.ShardCoord;
2017-01-05 12:49:50 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2017-01-01 11:52:52 +00:00
public async Task TogetherTube()
2016-12-24 07:05:43 +00:00
{
Uri target;
using (var http = new HttpClient())
{
var res = await http.GetAsync("https://togethertube.com/room/create").ConfigureAwait(false);
target = res.RequestMessage.RequestUri;
}
2016-12-31 10:55:12 +00:00
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
2016-12-24 07:05:43 +00:00
.WithAuthor(eab => eab.WithIconUrl("https://togethertube.com/assets/img/favicons/favicon-32x32.png")
.WithName("Together Tube")
.WithUrl("https://togethertube.com/"))
.WithDescription(Context.User.Mention + " " + GetText("togtub_room_link") + "\n" + target));
2016-12-24 07:05:43 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-13 18:45:08 +00:00
[RequireContext(ContextType.Guild)]
public async Task WhosPlaying([Remainder] string game)
2016-08-13 18:45:08 +00:00
{
game = game?.Trim().ToUpperInvariant();
2016-08-13 18:45:08 +00:00
if (string.IsNullOrWhiteSpace(game))
return;
2017-01-29 21:54:27 +00:00
var socketGuild = Context.Guild as SocketGuild;
if (socketGuild == null)
{
2017-01-29 21:54:27 +00:00
_log.Warn("Can't cast guild to socket guild.");
return;
}
var rng = new NadekoRandom();
var arr = await Task.Run(() => socketGuild.Users
2016-08-15 14:57:40 +00:00
.Where(u => u.Game?.Name?.ToUpperInvariant() == game)
2016-08-13 18:45:08 +00:00
.Select(u => u.Username)
2017-01-29 21:54:27 +00:00
.OrderBy(x => rng.Next())
2017-01-26 07:02:57 +00:00
.Take(60)
2017-01-29 21:54:27 +00:00
.ToArray()).ConfigureAwait(false);
2016-08-13 18:45:08 +00:00
int i = 0;
2017-01-29 21:54:27 +00:00
if (arr.Length == 0)
await ReplyErrorLocalized("nobody_playing_game").ConfigureAwait(false);
2017-01-29 21:54:27 +00:00
else
{
2016-12-16 18:43:57 +00:00
await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2)
2016-12-08 15:40:59 +00:00
.Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```")
.ConfigureAwait(false);
2017-01-29 21:54:27 +00:00
}
2016-08-13 18:45:08 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-13 18:45:08 +00:00
[RequireContext(ContextType.Guild)]
public async Task InRole([Remainder] IRole role)
2016-08-15 14:57:40 +00:00
{
2017-03-09 16:34:35 +00:00
var rng = new NadekoRandom();
var usrs = (await Context.Guild.GetUsersAsync()).ToArray();
2017-03-09 16:34:35 +00:00
var roleUsers = usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString())
.ToArray();
var inroleusers = string.Join(", ", roleUsers
.OrderBy(x => rng.Next())
.Take(50));
var embed = new EmbedBuilder().WithOkColor()
2017-03-09 16:34:35 +00:00
.WithTitle(" " + Format.Bold(GetText("inrole_list", Format.Bold(role.Name))) + $" - {roleUsers.Length}")
.WithDescription($"```css\n[{role.Name}]\n{inroleusers}```");
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
2016-08-15 14:57:40 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-15 14:57:40 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public async Task CheckMyPerms()
2016-08-15 14:57:40 +00:00
{
StringBuilder builder = new StringBuilder();
var user = (IGuildUser) Context.User;
2016-12-16 18:43:57 +00:00
var perms = user.GetPermissions((ITextChannel)Context.Channel);
2016-08-15 14:57:40 +00:00
foreach (var p in perms.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
{
builder.AppendLine($"{p.Name} : {p.GetValue(perms, null)}");
2016-08-15 14:57:40 +00:00
}
2016-12-16 18:43:57 +00:00
await Context.Channel.SendConfirmAsync(builder.ToString());
2016-08-15 14:57:40 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-15 14:57:40 +00:00
[RequireContext(ContextType.Guild)]
public async Task UserId([Remainder] IGuildUser target = null)
2016-08-15 14:57:40 +00:00
{
2016-12-16 18:43:57 +00:00
var usr = target ?? Context.User;
await ReplyConfirmLocalized("userid", "🆔", Format.Bold(usr.ToString()),
Format.Code(usr.Id.ToString())).ConfigureAwait(false);
2016-08-15 14:57:40 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-12-16 18:43:57 +00:00
public async Task ChannelId()
2016-08-15 14:57:40 +00:00
{
await ReplyConfirmLocalized("channelid", "🆔", Format.Code(Context.Channel.Id.ToString()))
.ConfigureAwait(false);
2016-08-15 14:57:40 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-15 14:57:40 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public async Task ServerId()
2016-08-15 14:57:40 +00:00
{
await ReplyConfirmLocalized("serverid", "🆔", Format.Code(Context.Guild.Id.ToString()))
.ConfigureAwait(false);
2016-08-15 14:57:40 +00:00
}
2016-08-13 18:45:08 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-15 14:57:40 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public async Task Roles(IGuildUser target, int page = 1)
2016-08-15 14:57:40 +00:00
{
2016-12-16 18:43:57 +00:00
var channel = (ITextChannel)Context.Channel;
var guild = channel.Guild;
const int rolesPerPage = 20;
if (page < 1 || page > 100)
return;
2016-08-15 14:57:40 +00:00
if (target != null)
{
var roles = target.GetRoles().Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray();
2016-12-21 11:52:01 +00:00
if (!roles.Any())
{
await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false);
2016-12-21 11:52:01 +00:00
}
else
{
await channel.SendConfirmAsync(GetText("roles_page", page, Format.Bold(target.ToString())),
"\n• " + string.Join("\n• ", (IEnumerable<IRole>)roles).SanitizeMentions()).ConfigureAwait(false);
2016-12-21 11:52:01 +00:00
}
2016-08-15 14:57:40 +00:00
}
else
{
var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray();
2016-12-21 11:52:01 +00:00
if (!roles.Any())
{
await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false);
2016-12-21 11:52:01 +00:00
}
else
{
await channel.SendConfirmAsync(GetText("roles_all_page", page),
"\n• " + string.Join("\n• ", (IEnumerable<IRole>)roles).SanitizeMentions()).ConfigureAwait(false);
2016-12-21 11:52:01 +00:00
}
2016-08-15 14:57:40 +00:00
}
2016-08-13 18:45:08 +00:00
}
2016-08-18 21:00:54 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public Task Roles(int page = 1) =>
Roles(null, page);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2017-01-08 17:14:10 +00:00
public async Task ChannelTopic([Remainder]ITextChannel channel = null)
{
2017-01-08 17:14:10 +00:00
if (channel == null)
channel = (ITextChannel)Context.Channel;
var topic = channel.Topic;
if (string.IsNullOrWhiteSpace(topic))
await ReplyErrorLocalized("no_topic_set").ConfigureAwait(false);
else
await Context.Channel.SendConfirmAsync(GetText("channel_topic"), topic).ConfigureAwait(false);
}
2017-01-07 15:33:37 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireBotPermission(ChannelPermission.CreateInstantInvite)]
[RequireUserPermission(ChannelPermission.CreateInstantInvite)]
public async Task CreateInvite()
{
var invite = await ((ITextChannel)Context.Channel).CreateInviteAsync(0, null, isUnique: true);
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}");
}
[NadekoCommand, Usage, Description, Aliases]
[Shard0Precondition]
public async Task ShardStats(int page = 1)
{
if (--page < 0)
return;
2017-07-15 03:23:46 +00:00
var statuses = _shardCoord.Statuses.ToArray()
2017-06-21 22:12:29 +00:00
.Where(x => x != null);
2017-06-21 21:49:13 +00:00
var status = string.Join(", ", statuses
.GroupBy(x => x.ConnectionState)
.Select(x => $"{x.Count()} {x.Key}")
.ToArray());
2017-02-04 17:19:03 +00:00
2017-06-21 21:49:13 +00:00
var allShardStrings = statuses
.Select(x =>
{
var timeDiff = DateTime.UtcNow - x.Time;
if (timeDiff > TimeSpan.FromSeconds(20))
return $"Shard #{Format.Bold(x.ShardId.ToString())} **UNRESPONSIVE** for {timeDiff.ToString(@"hh\:mm\:ss")}";
return GetText("shard_stats_txt", x.ShardId.ToString(),
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()), timeDiff.ToString(@"hh\:mm\:ss"));
})
.ToArray();
2017-02-06 07:35:45 +00:00
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
{
2017-02-06 07:35:45 +00:00
var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25));
2017-02-04 17:19:03 +00:00
if (string.IsNullOrWhiteSpace(str))
str = GetText("no_shards_on_page");
2017-02-05 05:36:07 +00:00
return new EmbedBuilder()
.WithAuthor(a => a.WithName(GetText("shard_stats")))
.WithTitle(status)
.WithOkColor()
.WithDescription(str);
}, allShardStrings.Length / 25);
}
2017-02-05 05:36:07 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-12-16 18:43:57 +00:00
public async Task Stats()
{
await Context.Channel.EmbedAsync(
new EmbedBuilder().WithOkColor()
2016-12-16 18:43:57 +00:00
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
2017-05-22 23:59:31 +00:00
.AddField(efb => efb.WithName(GetText("author")).WithValue(_stats.Author).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).WithIsInline(true))
2017-07-15 03:23:46 +00:00
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{_client.ShardId} / {_creds.TotalShards}").WithIsInline(true))
2017-05-22 23:59:31 +00:00
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(_stats.CommandsRan.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("owner_ids")).WithValue(string.Join("\n", _creds.OwnerIds)).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
GetText("presence_txt",
_stats.GuildCount, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true)));
2016-08-18 21:00:54 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-12-16 18:43:57 +00:00
public async Task Showemojis([Remainder] string emojis)
{
2017-05-22 23:59:31 +00:00
var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emote)t.Value);
var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url)));
2016-12-08 17:35:34 +00:00
if (string.IsNullOrWhiteSpace(result))
await ReplyErrorLocalized("showemojis_none").ConfigureAwait(false);
2016-12-08 17:35:34 +00:00
else
2016-12-16 18:43:57 +00:00
await Context.Channel.SendMessageAsync(result).ConfigureAwait(false);
}
2016-10-28 11:31:21 +00:00
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task ListServers(int page = 1)
2016-10-28 11:31:21 +00:00
{
page -= 1;
if (page < 0)
return;
var guilds = await Task.Run(() => _client.Guilds.OrderBy(g => g.Name).Skip((page) * 15).Take(15)).ConfigureAwait(false);
2016-10-28 11:31:21 +00:00
if (!guilds.Any())
{
await ReplyErrorLocalized("listservers_none").ConfigureAwait(false);
2016-10-28 11:31:21 +00:00
return;
}
await Context.Channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithOkColor(),
2016-12-08 15:40:59 +00:00
(embed, g) => embed.AddField(efb => efb.WithName(g.Name)
.WithValue(
GetText("listservers", g.Id, g.Users.Count,
g.OwnerId))
2016-12-16 18:43:57 +00:00
.WithIsInline(false))))
2016-12-08 15:40:59 +00:00
.ConfigureAwait(false);
2016-10-28 11:31:21 +00:00
}
2017-01-11 13:05:57 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task SaveChat(int cnt)
{
var msgs = new List<IMessage>(cnt);
await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false);
var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt";
var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}")
2017-03-19 14:48:12 +00:00
.Select(g => new
{
date = g.Key,
messages = g.OrderBy(x => x.CreatedAt).Select(s =>
{
var msg = $"【{s.Timestamp:HH:mm:ss}】{s.Author}:";
if (string.IsNullOrWhiteSpace(s.ToString()))
{
if (s.Attachments.Any())
{
msg += "FILES_UPLOADED: " + string.Join("\n", s.Attachments.Select(x => x.Url));
}
else if (s.Embeds.Any())
{
msg += "EMBEDS: " + string.Join("\n--------\n", s.Embeds.Select(x => $"Description: {x.Description}"));
}
}
else
{
msg += s.ToString();
}
return msg;
})
});
2017-01-11 13:05:57 +00:00
await Context.User.SendFileAsync(
await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title, false).ConfigureAwait(false);
2017-01-11 13:05:57 +00:00
}
2017-04-03 10:43:59 +00:00
[NadekoCommand, Usage, Description, Aliases]
public async Task Ping()
{
var sw = Stopwatch.StartNew();
var msg = await Context.Channel.SendMessageAsync("🏓").ConfigureAwait(false);
sw.Stop();
msg.DeleteAfter(0);
await Context.Channel.SendConfirmAsync($"{Format.Bold(Context.User.ToString())} 🏓 {(int)sw.Elapsed.TotalMilliseconds}ms").ConfigureAwait(false);
}
2016-08-13 18:45:08 +00:00
}
2017-08-25 20:48:39 +00:00
}