2016-08-13 18:45:08 +00:00
using Discord ;
using Discord.Commands ;
using NadekoBot.Attributes ;
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.Text.RegularExpressions ;
using System.Reflection ;
2016-11-30 19:15:22 +00:00
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 ;
2016-08-13 18:45:08 +00:00
namespace NadekoBot.Modules.Utility
{
2016-09-10 19:45:12 +00:00
[NadekoModule("Utility", ".")]
2016-08-18 21:00:54 +00:00
public partial class Utility : DiscordModule
2016-08-13 18:45:08 +00:00
{
2017-01-05 12:49:50 +00:00
private static ConcurrentDictionary < ulong , Timer > rotatingRoleColors = new ConcurrentDictionary < ulong , Timer > ( ) ;
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task RotateRoleColor ( int timeout , IRole role , params string [ ] hexes )
{
var channel = ( ITextChannel ) Context . Channel ;
2017-01-05 18:13:53 +00:00
if ( ( timeout < 60 & & timeout ! = 0 ) | | timeout > 3600 )
2017-01-05 12:49:50 +00:00
return ;
Timer t ;
if ( timeout = = 0 | | hexes . Length = = 0 )
{
if ( rotatingRoleColors . TryRemove ( role . Id , out t ) )
{
t . Change ( Timeout . Infinite , Timeout . Infinite ) ;
await channel . SendConfirmAsync ( $"Stopped rotating colors for the **{role.Name}** role" ) . ConfigureAwait ( false ) ;
}
return ;
}
var hexColors = hexes . Select ( hex = >
{
try { return ( ImageSharp . Color ? ) new ImageSharp . Color ( hex . Replace ( "#" , "" ) ) ; } catch { return null ; }
} )
. Where ( c = > c ! = null )
. Select ( c = > c . Value )
. ToArray ( ) ;
if ( ! hexColors . Any ( ) )
{
await channel . SendMessageAsync ( "No colors are in the correct format. Use `#00ff00` for example." ) . ConfigureAwait ( false ) ;
return ;
}
var images = hexColors . Select ( color = >
{
var img = new ImageSharp . Image ( 50 , 50 ) ;
img . BackgroundColor ( color ) ;
return img ;
} ) . Merge ( ) . ToStream ( ) ;
var i = 0 ;
t = new Timer ( async ( _ ) = >
{
try
{
var color = hexColors [ i ] ;
await role . ModifyAsync ( r = > r . Color = new Discord . Color ( color . R , color . G , color . B ) ) . ConfigureAwait ( false ) ;
+ + i ;
if ( i > = hexColors . Length )
i = 0 ;
}
catch { }
} , null , 0 , timeout * 1000 ) ;
rotatingRoleColors . AddOrUpdate ( role . Id , t , ( key , old ) = >
{
old . Change ( Timeout . Infinite , Timeout . Infinite ) ;
return t ;
} ) ;
2017-01-11 13:05:57 +00:00
2017-01-05 12:49:50 +00:00
await channel . SendFileAsync ( images , "magicalgirl.jpg" , $"Rotating **{role.Name}** role's color." ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +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/" ) )
2017-01-01 12:28:35 +00:00
. WithDescription ( $"{Context.User.Mention} Here is your room link:\n{target}" ) ) ;
2016-12-24 07:05:43 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-13 18:45:08 +00:00
[RequireContext(ContextType.Guild)]
2017-01-01 11:52:52 +00:00
public async Task WhosPlaying ( [ Remainder ] string game = null )
2016-08-13 18:45:08 +00:00
{
game = game . Trim ( ) . ToUpperInvariant ( ) ;
if ( string . IsNullOrWhiteSpace ( game ) )
return ;
2016-12-16 18:43:57 +00:00
var arr = ( await ( Context . Channel as IGuildChannel ) . Guild . GetUsersAsync ( ) )
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 )
. ToList ( ) ;
int i = 0 ;
if ( ! arr . Any ( ) )
2016-12-16 18:43:57 +00:00
await Context . Channel . SendErrorAsync ( "Nobody is playing that game." ) . ConfigureAwait ( false ) ;
2016-08-13 18:45:08 +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 ) ;
2016-08-13 18:45:08 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-13 18:45:08 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public async Task InRole ( [ Remainder ] string roles )
2016-08-15 14:57:40 +00:00
{
2016-08-13 18:45:08 +00:00
if ( string . IsNullOrWhiteSpace ( roles ) )
return ;
var arg = roles . Split ( ',' ) . Select ( r = > r . Trim ( ) . ToUpperInvariant ( ) ) ;
2016-12-08 15:40:59 +00:00
string send = "ℹ ️ **Here is a list of users in those roles:**" ;
2016-08-13 18:45:08 +00:00
foreach ( var roleStr in arg . Where ( str = > ! string . IsNullOrWhiteSpace ( str ) & & str ! = "@EVERYONE" & & str ! = "EVERYONE" ) )
{
2016-12-16 18:43:57 +00:00
var role = Context . Guild . Roles . Where ( r = > r . Name . ToUpperInvariant ( ) = = roleStr ) . FirstOrDefault ( ) ;
2016-08-13 18:45:08 +00:00
if ( role = = null ) continue ;
2016-11-21 00:56:12 +00:00
send + = $"```css\n[{role.Name}]\n" ;
2016-12-17 04:09:04 +00:00
send + = string . Join ( ", " , ( await Context . Guild . GetUsersAsync ( ) ) . Where ( u = > u . RoleIds . Contains ( role . Id ) ) . Select ( u = > u . ToString ( ) ) ) ;
2016-11-21 00:56:12 +00:00
send + = $"\n```" ;
2016-08-15 14:57:40 +00:00
}
2016-12-16 18:43:57 +00:00
var usr = Context . User as IGuildUser ;
2016-08-15 14:57:40 +00:00
while ( send . Length > 2000 )
{
2016-12-16 18:43:57 +00:00
if ( ! usr . GetPermissions ( ( ITextChannel ) Context . Channel ) . ManageMessages )
2016-08-15 14:57:40 +00:00
{
2016-12-16 18:43:57 +00:00
await Context . Channel . SendErrorAsync ( $"⚠️ {usr.Mention} **you are not allowed to use this command on roles with a lot of users in them to prevent abuse.**" ) . ConfigureAwait ( false ) ;
2016-08-15 14:57:40 +00:00
return ;
}
var curstr = send . Substring ( 0 , 2000 ) ;
2016-12-16 18:43:57 +00:00
await Context . Channel . SendConfirmAsync ( curstr . Substring ( 0 ,
2016-08-15 14:57:40 +00:00
curstr . LastIndexOf ( ", " , StringComparison . Ordinal ) + 1 ) ) . ConfigureAwait ( false ) ;
send = curstr . Substring ( curstr . LastIndexOf ( ", " , StringComparison . Ordinal ) + 1 ) +
send . Substring ( 2000 ) ;
2016-08-13 18:45:08 +00:00
}
2016-12-16 18:43:57 +00:00
await Context . Channel . SendConfirmAsync ( send ) . ConfigureAwait ( false ) ;
2016-08-15 14:57:40 +00:00
}
2016-10-05 03:09:44 +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
{
2016-11-21 00:24:15 +00:00
StringBuilder builder = new StringBuilder ( "```http\n" ) ;
2016-12-16 18:43:57 +00:00
var user = Context . User as IGuildUser ;
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).ToString()}" ) ;
}
builder . Append ( "```" ) ;
2016-12-16 18:43:57 +00:00
await Context . Channel . SendConfirmAsync ( builder . ToString ( ) ) ;
2016-08-15 14:57:40 +00:00
}
2016-10-05 03:09:44 +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 UserId ( 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 Context . Channel . SendConfirmAsync ( $"🆔 of the user **{ usr.Username }** is `{ usr.Id }`" ) . ConfigureAwait ( false ) ;
2016-08-15 14:57:40 +00:00
}
2016-10-05 03:09:44 +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
{
2016-12-16 18:43:57 +00:00
await Context . Channel . SendConfirmAsync ( $"🆔 of this channel is `{Context.Channel.Id}`" ) . ConfigureAwait ( false ) ;
2016-08-15 14:57:40 +00:00
}
2016-10-05 03:09:44 +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
{
2017-01-01 15:39:24 +00:00
await Context . Channel . SendConfirmAsync ( $"🆔 of this server is `{Context.Guild.Id}`" ) . ConfigureAwait ( false ) ;
2016-08-15 14:57:40 +00:00
}
2016-08-13 18:45:08 +00:00
2016-10-05 03:09:44 +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 ;
2016-09-13 16:12:27 +00:00
var guild = channel . Guild ;
2016-10-10 00:27:33 +00:00
const int RolesPerPage = 20 ;
if ( page < 1 | | page > 100 )
return ;
2016-12-22 05:12:04 +00:00
2016-08-15 14:57:40 +00:00
if ( target ! = null )
{
2016-12-21 11:52:01 +00:00
var roles = target . GetRoles ( ) . Except ( new [ ] { guild . EveryoneRole } ) . OrderBy ( r = > - r . Position ) . Skip ( ( page - 1 ) * RolesPerPage ) . Take ( RolesPerPage ) ;
if ( ! roles . Any ( ) )
{
2016-12-22 05:12:04 +00:00
await channel . SendErrorAsync ( "No roles on this page." ) . ConfigureAwait ( false ) ;
2016-12-21 11:52:01 +00:00
}
else
{
2016-12-22 05:12:04 +00:00
await channel . SendConfirmAsync ( $"⚔ **Page #{page} of roles for {target.Username}**" , $"```css\n• " + string . Join ( "\n• " , roles ) . SanitizeMentions ( ) + "\n```" ) . ConfigureAwait ( false ) ;
2016-12-21 11:52:01 +00:00
}
2016-08-15 14:57:40 +00:00
}
else
{
2016-12-21 11:52:01 +00:00
var roles = guild . Roles . Except ( new [ ] { guild . EveryoneRole } ) . OrderBy ( r = > - r . Position ) . Skip ( ( page - 1 ) * RolesPerPage ) . Take ( RolesPerPage ) ;
if ( ! roles . Any ( ) )
{
2016-12-22 05:12:04 +00:00
await channel . SendErrorAsync ( "No roles on this page." ) . ConfigureAwait ( false ) ;
2016-12-21 11:52:01 +00:00
}
else
{
2016-12-22 05:12:04 +00:00
await channel . SendConfirmAsync ( $"⚔ **Page #{page} of all roles on this server:**" , $"```css\n• " + string . Join ( "\n• " , roles ) . SanitizeMentions ( ) + "\n```" ) . 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
2016-10-10 00:27:33 +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 ) ;
2016-10-10 00:27:33 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-28 00:46:36 +00:00
[RequireContext(ContextType.Guild)]
2017-01-08 17:14:10 +00:00
public async Task ChannelTopic ( [ Remainder ] ITextChannel channel = null )
2016-08-28 00:46:36 +00:00
{
2017-01-08 17:14:10 +00:00
if ( channel = = null )
channel = ( ITextChannel ) Context . Channel ;
2016-08-28 00:46:36 +00:00
var topic = channel . Topic ;
if ( string . IsNullOrWhiteSpace ( topic ) )
2017-01-09 18:58:52 +00:00
await Context . Channel . SendErrorAsync ( "No topic set." ) . ConfigureAwait ( false ) ;
2016-08-28 00:46:36 +00:00
else
2017-01-09 18:58:52 +00:00
await Context . Channel . SendConfirmAsync ( "Channel topic" , topic ) . ConfigureAwait ( false ) ;
2016-08-28 00:46:36 +00:00
}
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}" ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-12-16 18:43:57 +00:00
public async Task Stats ( )
2016-08-18 21:00:54 +00:00
{
2016-11-30 19:15:22 +00:00
var stats = NadekoBot . Stats ;
2016-12-31 12:21:18 +00:00
await Context . Channel . EmbedAsync (
2016-12-24 07:30:20 +00:00
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" ) )
. AddField ( efb = > efb . WithName ( Format . Bold ( "Author" ) ) . WithValue ( stats . Author ) . WithIsInline ( true ) )
. AddField ( efb = > efb . WithName ( Format . Bold ( "Library" ) ) . WithValue ( stats . Library ) . WithIsInline ( true ) )
2016-12-31 12:21:18 +00:00
. AddField ( efb = > efb . WithName ( Format . Bold ( "Bot ID" ) ) . WithValue ( NadekoBot . Client . CurrentUser ( ) . Id . ToString ( ) ) . WithIsInline ( true ) )
2016-12-16 18:43:57 +00:00
. AddField ( efb = > efb . WithName ( Format . Bold ( "Commands Ran" ) ) . WithValue ( stats . CommandsRan . ToString ( ) ) . WithIsInline ( true ) )
. AddField ( efb = > efb . WithName ( Format . Bold ( "Messages" ) ) . WithValue ( $"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)" ) . WithIsInline ( true ) )
. AddField ( efb = > efb . WithName ( Format . Bold ( "Memory" ) ) . WithValue ( $"{stats.Heap} MB" ) . WithIsInline ( true ) )
2017-01-12 00:32:02 +00:00
. AddField ( efb = > efb . WithName ( Format . Bold ( "Owner ID(s)" ) ) . WithValue ( string . Join ( "\n" , NadekoBot . Credentials . OwnerIds ) ) . WithIsInline ( true ) )
2016-12-16 18:43:57 +00:00
. AddField ( efb = > efb . WithName ( Format . Bold ( "Uptime" ) ) . WithValue ( stats . GetUptimeString ( "\n" ) ) . WithIsInline ( true ) )
2017-01-06 23:46:07 +00:00
. AddField ( efb = > efb . WithName ( Format . Bold ( "Presence" ) ) . WithValue ( $"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels" ) . WithIsInline ( true ) )
#if ! GLOBAL_NADEKO
2016-12-24 07:30:20 +00:00
. WithFooter ( efb = > efb . WithText ( $"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued." ) )
2017-01-06 23:46:07 +00:00
#endif
2016-12-31 10:55:12 +00:00
) ;
2016-08-18 21:00:54 +00:00
}
2016-10-06 17:19:42 +00:00
private Regex emojiFinder { get ; } = new Regex ( @"<:(?<name>.+?):(?<id>\d*)>" , RegexOptions . Compiled ) ;
[NadekoCommand, Usage, Description, Aliases]
2016-12-16 18:43:57 +00:00
public async Task Showemojis ( [ Remainder ] string emojis )
2016-10-06 17:19:42 +00:00
{
var matches = emojiFinder . Matches ( emojis ) ;
var result = string . Join ( "\n" , matches . Cast < Match > ( )
2016-11-21 00:24:15 +00:00
. Select ( m = > $"**Name:** {m.Groups[" name "]} **Link:** http://discordapp.com/api/emojis/{m.Groups[" id "]}.png" ) ) ;
2016-12-08 17:35:34 +00:00
if ( string . IsNullOrWhiteSpace ( result ) )
2016-12-16 18:43:57 +00:00
await Context . Channel . SendErrorAsync ( "No special emojis found." ) ;
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-06 17:19:42 +00:00
}
2016-10-26 20:26:25 +00:00
2016-10-28 11:31:21 +00:00
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
2016-12-21 08:33:47 +00:00
public async Task ListServers ( int page = 1 )
2016-10-28 11:31:21 +00:00
{
page - = 1 ;
if ( page < 0 )
return ;
2017-01-07 18:56:44 +00:00
var guilds = await Task . Run ( ( ) = > NadekoBot . Client . GetGuilds ( ) . OrderBy ( g = > g . Name ) . Skip ( ( page - 1 ) * 15 ) . Take ( 15 ) ) . ConfigureAwait ( false ) ;
2016-10-28 11:31:21 +00:00
if ( ! guilds . Any ( ) )
{
2017-01-01 15:39:24 +00:00
await Context . Channel . SendErrorAsync ( "No servers found on that page." ) . ConfigureAwait ( false ) ;
2016-10-28 11:31:21 +00:00
return ;
}
2017-01-01 15:39:24 +00:00
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 )
2016-12-17 00:21:05 +00:00
. WithValue ( $"```css\nID: {g.Id}\nMembers: {g.Users.Count}\nOwnerID: {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 sb = new StringBuilder ( ) ;
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}" )
. Select ( g = > new { date = g . Key , messages = g . OrderBy ( x = > x . CreatedAt ) . Select ( s = > $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s . ToString ( ) ) } ) ;
await Context . User . SendFileAsync (
await JsonConvert . SerializeObject ( grouping , Formatting . Indented ) . ToStream ( ) . ConfigureAwait ( false ) , title , title ) . ConfigureAwait ( false ) ;
}
2016-08-13 18:45:08 +00:00
}
2016-12-22 05:12:04 +00:00
}