소스 검색

some cleanup

Markus-Rost 3 년 전
부모
커밋
6c1a534b06
21개의 변경된 파일154개의 추가작업 그리고 131개의 파일을 삭제
  1. 48 56
      bot.js
  2. 3 3
      cmds/eval.js
  3. 2 2
      cmds/get.js
  4. 6 6
      cmds/help.js
  5. 4 4
      cmds/patreon.js
  6. 2 2
      cmds/pause.js
  7. 6 2
      cmds/stop.js
  8. 4 4
      cmds/test.js
  9. 5 5
      cmds/verification.js
  10. 4 4
      cmds/verify.js
  11. 1 1
      cmds/voice.js
  12. 3 4
      cmds/wiki/general.js
  13. 1 1
      cmds/wiki/special_page.js
  14. 5 5
      cmds/wiki/user.js
  15. 1 0
      dashboard/src/index.css
  16. 1 1
      functions/global_block.js
  17. 2 2
      functions/parse_page.js
  18. 8 8
      functions/verify.js
  19. 12 8
      main.js
  20. 27 2
      util/functions.js
  21. 9 11
      util/newMessage.js

+ 48 - 56
bot.js

@@ -6,7 +6,7 @@ import db from './util/database.js';
 import Lang from './util/i18n.js';
 import Wiki from './util/wiki.js';
 import newMessage from './util/newMessage.js';
-import {allowDelete} from './util/functions.js';
+import {breakOnTimeoutPause, allowDelete} from './util/functions.js';
 
 inspect.defaultOptions = {compact: false, breakLength: Infinity};
 
@@ -71,12 +71,8 @@ String.prototype.isMention = function(guild) {
 	return text === '@' + client.user.username || text.replace( /^<@!?(\d+)>$/, '$1' ) === client.user.id || ( guild && text === '@' + guild.me.displayName );
 };
 
-Discord.Channel.prototype.isGuild = function(includeThreads = true) {
-	return this.isText() && this.type.startsWith( 'GUILD_' ) && ( includeThreads || !this.isThread() );
-}
-
 Discord.Message.prototype.isAdmin = function() {
-	return this.channel.isGuild() && this.member && ( this.member.permissions.has(Discord.Permissions.FLAGS.MANAGE_GUILD) || ( this.isOwner() && this.evalUsed ) );
+	return this.inGuild() && this.member && ( this.member.permissions.has(Discord.Permissions.FLAGS.MANAGE_GUILD) || ( this.isOwner() && this.evalUsed ) );
 };
 
 Discord.Message.prototype.isOwner = function() {
@@ -84,11 +80,11 @@ Discord.Message.prototype.isOwner = function() {
 };
 
 Discord.Message.prototype.showEmbed = function() {
-	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.EMBED_LINKS);
+	return !this.inGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.EMBED_LINKS);
 };
 
 Discord.Message.prototype.uploadFiles = function() {
-	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.ATTACH_FILES);
+	return !this.inGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.ATTACH_FILES);
 };
 
 String.prototype.replaceSave = function(pattern, replacement) {
@@ -96,23 +92,19 @@ String.prototype.replaceSave = function(pattern, replacement) {
 };
 
 Discord.Message.prototype.reactEmoji = function(name, ignorePause = false) {
-	if ( !this.channel.isGuild() || !pausedGuilds.has(this.guildId) || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		var emoji = '<:error:440871715938238494>';
-		switch ( name ) {
-			case 'nowiki':
-				emoji = '<:unknown_wiki:505884572001763348>';
-				break;
-			case 'error':
-				emoji = '<:error:440871715938238494>';
-				break;
-			default:
-				emoji = name;
-		}
-		return this.react(emoji).catch(log_error);
-	} else {
-		console.log( '- Aborted, paused.' );
-		return Promise.resolve();
+	if ( breakOnTimeoutPause(this, ignorePause) ) return Promise.resolve();
+	var emoji = '<:error:440871715938238494>';
+	switch ( name ) {
+		case 'nowiki':
+			emoji = '<:unknown_wiki:505884572001763348>';
+			break;
+		case 'error':
+			emoji = '<:error:440871715938238494>';
+			break;
+		default:
+			emoji = name;
 	}
+	return this.react(emoji).catch(log_error);
 };
 
 Discord.MessageReaction.prototype.removeEmoji = function() {
@@ -120,22 +112,19 @@ Discord.MessageReaction.prototype.removeEmoji = function() {
 };
 
 Discord.Message.prototype.sendChannel = function(message, ignorePause = false) {
-	if ( !this.channel.isGuild() || !pausedGuilds.has(this.guildId) || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
-		return this.channel.send( message ).then( msg => {
-			allowDelete(msg, this.author.id);
-			return msg;
-		}, error => {
-			log_error(error);
-			this.reactEmoji('error');
-		} );
-	} else {
-		console.log( '- Aborted, paused.' );
-		return Promise.resolve();
-	}
+	if ( breakOnTimeoutPause(this, ignorePause) ) return Promise.resolve();
+	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+	return this.channel.send( message ).then( msg => {
+		allowDelete(msg, this.author.id);
+		return msg;
+	}, error => {
+		log_error(error);
+		this.reactEmoji('error');
+	} );
 };
 
 Discord.Message.prototype.sendChannelError = function(message) {
+	if ( breakOnTimeoutPause(this) ) return Promise.resolve();
 	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
 	return this.channel.send( message ).then( msg => {
 		msg.reactEmoji('error');
@@ -148,19 +137,15 @@ Discord.Message.prototype.sendChannelError = function(message) {
 };
 
 Discord.Message.prototype.replyMsg = function(message, ignorePause = false, letDelete = true) {
-	if ( !this.channel.isGuild() || !pausedGuilds.has(this.guildId) || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
-		return this.reply( message ).then( msg => {
-			if ( letDelete ) allowDelete(msg, this.author.id);
-			return msg;
-		}, error => {
-			log_error(error);
-			this.reactEmoji('error');
-		} );
-	} else {
-		console.log( '- Aborted, paused.' );
-		return Promise.resolve();
-	}
+	if ( breakOnTimeoutPause(this, ignorePause) ) return Promise.resolve();
+	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+	return this.reply( message ).then( msg => {
+		if ( letDelete ) allowDelete(msg, this.author.id);
+		return msg;
+	}, error => {
+		log_error(error);
+		this.reactEmoji('error');
+	} );
 };
 
 String.prototype.hasPrefix = function(prefix, flags = '') {
@@ -210,6 +195,7 @@ client.on( 'interactionCreate', interaction => {
  * @param {Discord.CommandInteraction} interaction - The interaction.
  */
 function slash_command(interaction) {
+	if ( breakOnTimeoutPause(interaction) ) return;
 	if ( interaction.commandName === 'inline' ) console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: /' + interaction.commandName );
 	else console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: /' + interaction.commandName + ' ' + interaction.options.data.map( option => {
 		return option.name + ':' + option.value;
@@ -234,6 +220,7 @@ function slash_command(interaction) {
  * @param {Discord.ButtonInteraction} interaction - The interaction.
  */
 function message_button(interaction) {
+	if ( breakOnTimeoutPause(interaction) ) return;
 	var cmd = ( buttonsMap.hasOwnProperty(interaction.customId) ? buttonsMap[interaction.customId] : interaction.customId );
 	if ( !buttons.hasOwnProperty(cmd) ) return;
 	if ( !interaction.inGuild() ) {
@@ -263,7 +250,8 @@ client.on( 'messageCreate', msg => {
  */
 function messageCreate(msg) {
 	if ( isStop || !msg.channel.isText() || msg.system || msg.webhookId || msg.author.bot || msg.author.id === msg.client.user.id ) return;
-	if ( !msg.content.hasPrefix(( msg.channel.isGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix ), 'm') ) {
+	if ( msg.member?.communicationDisabledUntilTimestamp > Date.now() || msg.guild?.me.communicationDisabledUntilTimestamp > Date.now() ) return;
+	if ( !msg.content.hasPrefix(( msg.inGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix ), 'm') ) {
 		if ( msg.content === process.env.prefix + 'help' && ( msg.isAdmin() || msg.isOwner() ) ) {
 			if ( msg.channel.permissionsFor(msg.client.user).has(( msg.channel.isThread() ? Discord.Permissions.FLAGS.SEND_MESSAGES_IN_THREADS : Discord.Permissions.FLAGS.SEND_MESSAGES )) ) {
 				console.log( msg.guildId + ': ' + msg.content );
@@ -281,7 +269,7 @@ function messageCreate(msg) {
 		}
 		if ( !( msg.content.includes( '[[' ) && msg.content.includes( ']]' ) ) && !( msg.content.includes( '{{' ) && msg.content.includes( '}}' ) ) ) return;
 	}
-	if ( msg.channel.isGuild() ) {
+	if ( msg.inGuild() ) {
 		let sqlargs = [msg.guildId];
 		if ( msg.channel.isThread() ) sqlargs.push(msg.channel.parentId, '#' + msg.channel.parent?.parentId);
 		else sqlargs.push(msg.channelId, '#' + msg.channel.parentId);
@@ -297,10 +285,14 @@ function messageCreate(msg) {
 				console.log( msg.guildId + ': Missing permissions - ' + missing.join(', ') );
 				if ( !missing.includes( 'SEND_MESSAGES' ) && !missing.includes( 'SEND_MESSAGES_IN_THREADS' ) ) {
 					db.query( 'SELECT lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
-						msg.replyMsg( new Lang(( row?.lang || msg.guild.preferredLocale ), 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', true );
+						return row.lang;
 					}, dberror => {
 						console.log( '- Error while getting the lang: ' + dberror );
-						msg.replyMsg( new Lang(msg.guild.preferredLocale, 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', true );
+					} ).then( lang => {
+						msg.sendChannel( {
+							content: new Lang(( lang || msg.guild.preferredLocale ), 'general').get('missingperm') + ' `' + missing.join('`, `') + '`',
+							reply: ( missing.includes( 'READ_MESSAGE_HISTORY' ) ? null : {messageReference: msg.id} )
+						}, true );
 					} );
 				}
 			}
@@ -362,7 +354,7 @@ client.on( 'guildDelete', guild => {
 		return;
 	}
 	console.log( '- ' + guild.id + ': I\'ve been removed from a server.' );
-	leftGuilds.set(guild.id, setTimeout(removeSettings, 300000, guild.id).unref());
+	leftGuilds.set(guild.id, setTimeout(removeSettings, 300_000, guild.id).unref());
 } );
 
 function removeSettings(guild) {
@@ -415,7 +407,7 @@ function graceful(signal) {
 		}, dberror => {
 			console.log( '- ' + process.env.SHARDS + ': ' + signal + ': Error while closing the database connection: ' + dberror );
 		} );
-	}, 1000 ).unref();
+	}, 1_000 ).unref();
 }
 
 process.once( 'SIGINT', graceful );

+ 3 - 3
cmds/eval.js

@@ -84,7 +84,7 @@ function checkWiki(wiki) {
 		if ( rc.length ) {
 			result.rcid = rc[0].rcid;
 			let text = '';
-			let len = ( Date.parse(rc[0].timestamp) - Date.parse(rc[rc.length - 1].timestamp) ) / 60000;
+			let len = ( Date.parse(rc[0].timestamp) - Date.parse(rc[rc.length - 1].timestamp) ) / 60_000;
 			len = Math.round(len);
 			let rdays = ( len / 1440 );
 			let days = Math.floor(rdays);
@@ -200,7 +200,7 @@ function removePatreons(guild, msg) {
 							if ( discordClient.guilds.cache.has(evalData.guild) ) {
 								let rows = evalData.rows;
 								return discordClient.guilds.cache.get(evalData.guild).channels.cache.filter( channel => {
-									return ( channel.isGuild(false) && rows.some( row => {
+									return ( ( channel.isText() && !channel.isThread() ) && rows.some( row => {
 										return ( row.channel === '#' + channel.parentId );
 									} ) );
 								} ).map( channel => {
@@ -310,7 +310,7 @@ function removeSettings(msg) {
 			return [
 				[...discordClient.guilds.cache.keys()],
 				discordClient.channels.cache.filter( channel => {
-					return ( channel.isGuild() || ( channel.type === 'GUILD_CATEGORY' && patreonGuildsPrefix.has(channel.guildId) ) );
+					return ( ( channel.isText() && channel.guildId ) || ( channel.type === 'GUILD_CATEGORY' && patreonGuildsPrefix.has(channel.guildId) ) );
 				} ).map( channel => ( channel.type === 'GUILD_CATEGORY' ? '#' : '' ) + channel.id )
 			];
 		} ).then( results => {

+ 2 - 2
cmds/get.js

@@ -18,7 +18,7 @@ const {shardIdForGuildId} = ShardClientUtil;
 async function cmd_get(lang, msg, args, line, wiki) {
 	var id = args.join().replace( /^\\?<(?:@!?|#)(\d+)>$/, '$1' );
 	if ( !/^\d+$/.test(id) ) {
-		if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
+		if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
 		return;
 	}
 	try {
@@ -89,7 +89,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 		}
 		
 		var channel = await msg.client.shard.broadcastEval( (discordClient, evalData) => {
-			if ( discordClient.channels.cache.filter( channel => channel.isGuild() || channel.type === 'GUILD_CATEGORY' ).has(evalData.id) ) {
+			if ( discordClient.channels.cache.filter( channel => ( channel.isText() && channel.guildId ) || channel.type === 'GUILD_CATEGORY' ).has(evalData.id) ) {
 				var channel = discordClient.channels.cache.get(evalData.id);
 				return {
 					name: channel.name, id: channel.id, type: channel.type, parentId: channel.parentId,

+ 6 - 6
cmds/help.js

@@ -82,7 +82,7 @@ const restrictions = {
  * @param {import('../util/wiki.js').default} wiki - The wiki for the message.
  */
 function cmd_help(lang, msg, args, line, wiki) {
-	if ( msg.channel.isGuild() && pausedGuilds.has(msg.guildId) && ( args.join('') || !msg.isAdmin() ) ) return;
+	if ( msg.inGuild() && pausedGuilds.has(msg.guildId) && ( args.join('') || !msg.isAdmin() ) ) return;
 	if ( msg.isAdmin() && msg.defaultSettings ) help_server(lang, msg);
 	var isMinecraft = mcw.hasOwnProperty(wiki.href);
 	var maxLength = ( ['hi', 'bn'].includes( lang.lang ) ? 480 : 2000 );
@@ -94,12 +94,12 @@ function cmd_help(lang, msg, args, line, wiki) {
 		var invoke = args[0].toLowerCase();
 		var cmd = ( lang.aliases[invoke] || invoke );
 		if ( cmd === 'admin' ) {
-			if ( !msg.channel.isGuild() || msg.isAdmin() ) {
+			if ( !msg.inGuild() || msg.isAdmin() ) {
 				var cmdlist = lang.get('help.admin') + '\n';
 				if ( process.env.READONLY ) cmdlist = msg.author.toString() + ', ' + lang.get('general.readonly') + '\n' + process.env.invite + '\n\n' + cmdlist;
 				cmdlist += formathelp(helplist.admin, msg, lang);
 				cmdlist += '\n\n🔸 ' + lang.get('help.adminfooter');
-				if ( process.env.dashboard ) cmdlist += '\n\t\t' + new URL(( msg.channel.isGuild() ? `/guild/${msg.guildId}/settings` : '/' ), process.env.dashboard).href;
+				if ( process.env.dashboard ) cmdlist += '\n\t\t' + new URL(( msg.inGuild() ? `/guild/${msg.guildId}/settings` : '/' ), process.env.dashboard).href;
 				Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 			}
 			else {
@@ -146,12 +146,12 @@ function cmd_help(lang, msg, args, line, wiki) {
  * @param {import('../util/i18n.js').default} lang - The user language.
  */
 function formathelp(messages, msg, lang) {
-	var prefix = ( msg.channel.isGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix );
-	var mention = '@' + ( msg.channel.isGuild() ? msg.guild.me.displayName : msg.client.user.username );
+	var prefix = ( msg.inGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix );
+	var mention = '@' + ( msg.inGuild() ? msg.guild.me.displayName : msg.client.user.username );
 	return messages.filter( message => {
 		if ( restrictions.inline.includes( message ) && msg.noInline ) return false;
 		if ( !restrictions.patreon.includes( message ) ) return true;
-		return ( msg.channel.isGuild() && patreonGuildsPrefix.has(msg.guildId) );
+		return ( msg.inGuild() && patreonGuildsPrefix.has(msg.guildId) );
 	} ).map( message => {
 		var cmd = message.split('.')[0];
 		var intro = ( restrictions.inline.includes( message ) ? '' : prefix );

+ 4 - 4
cmds/patreon.js

@@ -15,7 +15,7 @@ const {shardIdForGuildId} = ShardClientUtil;
  */
 function cmd_patreon(lang, msg, args, line, wiki) {
 	if ( !( process.env.channel.split('|').includes( msg.channelId ) && args.join('') ) ) {
-		if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
+		if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
 		return;
 	}
 	
@@ -100,7 +100,7 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 							return msg.client.shard.broadcastEval( (discordClient, evalData) => {
 								if ( discordClient.guilds.cache.has(evalData.guild) ) {
 									return discordClient.guilds.cache.get(evalData.guild).channels.cache.filter( channel => {
-										return ( channel.isGuild(false) && evalData.rows.some( row => {
+										return ( ( channel.isText() && !channel.isThread() ) && evalData.rows.some( row => {
 											return ( row.channel === '#' + channel.parentId );
 										} ) );
 									} ).map( channel => {
@@ -268,7 +268,7 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 								return discordClient.guilds.cache.has(guild);
 							} ).map( guild => {
 								return discordClient.guilds.cache.get(guild).channels.cache.filter( channel => {
-									return ( channel.isGuild(false) && evalData.rows.some( row => {
+									return ( ( channel.isText() && !channel.isThread() ) && evalData.rows.some( row => {
 										return ( row.channel === '#' + channel.parentId );
 									} ) );
 								} ).map( channel => {
@@ -364,7 +364,7 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 		msg.replyMsg( 'I got an error while searching for <@' + args[1] + '>, please try again later.', true );
 	} );
 	
-	if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
+	if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
 }
 
 export default {

+ 2 - 2
cmds/pause.js

@@ -7,7 +7,7 @@
  * @param {import('../util/wiki.js').default} wiki - The wiki for the message.
  */
 function cmd_pause(lang, msg, args, line, wiki) {
-	if ( msg.channel.isGuild() && args.join(' ').split('\n')[0].isMention(msg.guild) && ( msg.isAdmin() || msg.isOwner() ) ) {
+	if ( msg.inGuild() && args.join(' ').split('\n')[0].isMention(msg.guild) && ( msg.isAdmin() || msg.isOwner() ) ) {
 		if ( pausedGuilds.has(msg.guildId) ) {
 			pausedGuilds.delete(msg.guildId);
 			console.log( '- Pause ended.' );
@@ -17,7 +17,7 @@ function cmd_pause(lang, msg, args, line, wiki) {
 			console.log( '- Pause started.' );
 			pausedGuilds.add(msg.guildId);
 		}
-	} else if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) {
+	} else if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) {
 		this.LINK(lang, msg, line, wiki);
 	}
 }

+ 6 - 2
cmds/stop.js

@@ -14,8 +14,12 @@ async function cmd_stop(lang, msg, args, line, wiki) {
 	} else if ( args.join(' ').split('\n')[0].isMention(msg.guild) ) {
 		await msg.replyMsg( 'I\'ll restart myself now!', true );
 		console.log( '\n- Restarting all shards!\n\n' );
-		await msg.client.shard.respawnAll({timeout: -1});
-	} else if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) {
+		await msg.client.shard.respawnAll( {
+			shardDelay: 5_000,
+			respawnDelay: 500,
+			timeout: 60_000
+		} );
+	} else if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) {
 		this.LINK(lang, msg, line, wiki);
 	}
 }

+ 4 - 4
cmds/test.js

@@ -25,9 +25,9 @@ const wsStatus = [
  */
 function cmd_test(lang, msg, args, line, wiki) {
 	if ( args.join('') ) {
-		if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
+		if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
 	}
-	else if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) {
+	else if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) {
 		if ( msg.isAdmin() && msg.defaultSettings ) help_setup(lang, msg);
 		let textList = lang.get('test.text').filter( text => text.trim() );
 		var text = ( textList[Math.floor(Math.random() * ( textList.length * 5 ))] || lang.get('test.text.0') );
@@ -36,12 +36,12 @@ function cmd_test(lang, msg, args, line, wiki) {
 		msg.replyMsg( text ).then( message => {
 			if ( !message ) return;
 			var discordPing = message.createdTimestamp - msg.createdTimestamp;
-			if ( discordPing > 1000 ) text = lang.get('test.slow') + ' 🐌\n' + process.env.invite;
+			if ( discordPing > 1_000 ) text = lang.get('test.slow') + ' 🐌\n' + process.env.invite;
 			var embed = new MessageEmbed().setTitle( lang.get('test.time') ).setFooter( 'Shard: ' + process.env.SHARDS ).addField( 'Discord', discordPing.toLocaleString(lang.get('dateformat')) + 'ms' );
 			var now = Date.now();
 			got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&format=json', {
 				timeout: {
-					request: 10000
+					request: 10_000
 				}
 			} ).then( response => {
 				var then = Date.now();

+ 5 - 5
cmds/verification.js

@@ -16,7 +16,7 @@ const {limit: {verification: verificationLimit}} = require('../util/default.json
  */
 function cmd_verification(lang, msg, args, line, wiki) {
 	if ( !msg.isAdmin() ) {
-		if ( msg.channel.isGuild() && !pausedGuilds.has(msg.guildId) ) this.verify(lang, msg, args, line, wiki);
+		if ( msg.inGuild() && !pausedGuilds.has(msg.guildId) ) this.verify(lang, msg, args, line, wiki);
 		else msg.reactEmoji('❌');
 		return;
 	}
@@ -144,9 +144,9 @@ function cmd_verification(lang, msg, args, line, wiki) {
 				if ( channels.length > 10 ) return msg.replyMsg( {content: lang.get('verification.channel_max'), components}, true );
 				channels = channels.map( channel => {
 					var new_channel = '';
-					if ( /^\d+$/.test(channel) ) new_channel = msg.guild.channels.cache.filter( tc => tc.isGuild(false) ).get(channel);
-					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild(false) ).find( gc => gc.name === channel.replace( /^#/, '' ) );
-					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild(false) ).find( gc => gc.name.toLowerCase() === channel.toLowerCase().replace( /^#/, '' ) );
+					if ( /^\d+$/.test(channel) ) new_channel = msg.guild.channels.cache.filter( gc => gc.isText() && !gc.isThread() ).get(channel);
+					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isText() && !gc.isThread() ).find( gc => gc.name === channel.replace( /^#/, '' ) );
+					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isText() && !gc.isThread() ).find( gc => gc.name.toLowerCase() === channel.toLowerCase().replace( /^#/, '' ) );
 					return new_channel;
 				} );
 				if ( channels.some( channel => !channel ) ) return msg.replyMsg( {content: lang.get('verification.channel_missing'), components}, true );
@@ -189,7 +189,7 @@ function cmd_verification(lang, msg, args, line, wiki) {
 			if ( ( ( args[1] === 'editcount' || args[1] === 'accountage' ) && /^\d+$/.test(args[2]) ) || ( args[1] === 'postcount' && /^(?:-?\d+|null)$/.test(args[2]) ) ) {
 				args[2] = parseInt(args[2], 10);
 				if ( isNaN(args[2]) ) args[2] = null;
-				if ( args[2] > 1000000 || args[2] < -1000000 ) {
+				if ( args[2] > 1_000_000 || args[2] < -1_000_000 ) {
 					return msg.replyMsg( {content: lang.get('verification.value_too_high'), components}, true );
 				}
 				return db.query( 'UPDATE verification SET ' + args[1] + ' = $1 WHERE guild = $2 AND configid = $3', [args[2], msg.guildId, row.configid] ).then( () => {

+ 4 - 4
cmds/verify.js

@@ -13,7 +13,7 @@ import {got, oauthVerify, allowDelete, escapeFormatting} from '../util/functions
  * @param {import('../util/wiki.js').default} wiki - The wiki for the message.
  */
 function cmd_verify(lang, msg, args, line, wiki) {
-	if ( !msg.channel.isGuild() || msg.defaultSettings ) return this.LINK(lang, msg, line, wiki);
+	if ( !msg.inGuild() || msg.defaultSettings ) return this.LINK(lang, msg, line, wiki);
 	if ( !msg.guild.me.permissions.has(Permissions.FLAGS.MANAGE_ROLES) ) {
 		if ( msg.isAdmin() ) {
 			console.log( msg.guildId + ': Missing permissions - MANAGE_ROLES' );
@@ -99,7 +99,7 @@ function cmd_verify(lang, msg, args, line, wiki) {
 					} ).then( message => {
 						msg.reactEmoji('📩');
 						allowDelete(message, msg.author.id);
-						setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
+						setTimeout( () => msg.delete().catch(log_error), 60_000 ).unref();
 					}, error => {
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 							return msg.replyMsg( lang.get('verify.oauth_private') );
@@ -190,7 +190,7 @@ function cmd_verify(lang, msg, args, line, wiki) {
 						} ).then( message => {
 							msg.reactEmoji('📩');
 							allowDelete(message, msg.author.id);
-							setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
+							setTimeout( () => msg.delete().catch(log_error), 60_000 ).unref();
 						}, error => {
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 								return msg.replyMsg( lang.get('verify.oauth_private') );
@@ -228,7 +228,7 @@ function cmd_verify(lang, msg, args, line, wiki) {
 						msg.member.send( {content: msg.channel.toString() + '; ' + result.content, embeds: dmEmbeds, components: []} ).then( message => {
 							msg.reactEmoji('📩');
 							allowDelete(message, msg.author.id);
-							setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
+							setTimeout( () => msg.delete().catch(log_error), 60_000 ).unref();
 						}, error => {
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 								return msg.replyMsg( options, false, false );

+ 1 - 1
cmds/voice.js

@@ -43,7 +43,7 @@ function cmd_voice(lang, msg, args, line, wiki) {
 			} );
 		}
 	}
-	if ( !msg.channel.isGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
+	if ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) this.LINK(lang, msg, line, wiki);
 }
 
 export default {

+ 3 - 4
cmds/wiki/general.js

@@ -3,7 +3,7 @@ import {MessageEmbed} from 'discord.js';
 import parse_page from '../../functions/parse_page.js';
 import phabricator from '../../functions/phabricator.js';
 import logging from '../../util/logging.js';
-import {got, htmlToDiscord, escapeFormatting, partialURIdecode} from '../../util/functions.js';
+import {got, htmlToDiscord, escapeFormatting, partialURIdecode, breakOnTimeoutPause} from '../../util/functions.js';
 import extract_desc from '../../util/extract_desc.js';
 import Wiki from '../../util/wiki.js';
 import * as fn from './functions.js'
@@ -298,7 +298,7 @@ export default function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reacti
 				}
 				else embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 				
-				var prefix = ( msg.channel.isGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix );
+				var prefix = ( msg.inGuild() && patreonGuildsPrefix.get(msg.guildId) || process.env.prefix );
 				var linksuffix = ( querystring.toString() ? '?' + querystring : '' ) + ( fragment ? '#' + fragment : '' );
 				if ( title.replace( /[_-]/g, ' ' ).toLowerCase() === querypage.title.replace( /-/g, ' ' ).toLowerCase() ) {
 					text = '';
@@ -414,9 +414,8 @@ export default function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reacti
 			return parse_page(lang, msg, spoiler + '<' + pagelink + '>' + text + spoiler, ( noEmbed ? null : embed ), wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ), pagelink);
 		}
 		if ( body.query.interwiki ) {
-			if ( msg.channel.isGuild() && pausedGuilds.has(msg.guildId) ) {
+			if ( breakOnTimeoutPause(msg) ) {
 				if ( reaction ) reaction.removeEmoji();
-				console.log( '- Aborted, paused.' );
 				return;
 			}
 			var iw = new URL(body.query.interwiki[0].url.replace( /\\/g, '%5C' ).replace( /@(here|everyone)/g, '%40$1' ), wiki);

+ 1 - 1
cmds/wiki/special_page.js

@@ -201,7 +201,7 @@ export default function special_page(lang, msg, {title, uselang = lang.lang}, sp
 			if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
 			embed.setDescription( description );
 		}
-		if ( msg.channel.isGuild() && patreonGuildsPrefix.has(msg.guildId) && querypages.hasOwnProperty(specialpage) ) {
+		if ( msg.inGuild() && patreonGuildsPrefix.has(msg.guildId) && querypages.hasOwnProperty(specialpage) ) {
 			var text = Util.splitMessage( querypages[specialpage][1](body.query, wiki, lang), {maxLength:1000} )[0];
 			embed.addField( lang.get('search.special'), ( text || lang.get('search.empty') ) );
 			if ( body.query.querypage?.cached !== undefined ) {

+ 5 - 5
cmds/wiki/user.js

@@ -217,7 +217,7 @@ export default function gamepedia_user(lang, msg, namespace, username, wiki, que
 				} );
 			}
 			
-			if ( msg.channel.isGuild() && patreonGuildsPrefix.has(msg.guildId) && wiki.isFandom() ) {
+			if ( msg.inGuild() && patreonGuildsPrefix.has(msg.guildId) && wiki.isFandom() ) {
 				if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 				else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 
@@ -519,7 +519,7 @@ export default function gamepedia_user(lang, msg, namespace, username, wiki, que
 						if ( discord.length > 100 ) discord = discord.substring(0, 100) + '\u2026';
 					}
 					if ( discord ) {
-						if ( msg.channel.isGuild() ) {
+						if ( msg.inGuild() ) {
 							var discordmember = msg.guild.members.cache.find( member => {
 								return escapeFormatting(member.user.tag) === discord;
 							} );
@@ -547,7 +547,7 @@ export default function gamepedia_user(lang, msg, namespace, username, wiki, que
 					console.log( '- Error while getting the curse profile: ' + error );
 				} );
 				if ( discord ) {
-					if ( msg.channel.isGuild() ) {
+					if ( msg.inGuild() ) {
 						var discordmember = msg.guild.members.cache.find( member => {
 							return escapeFormatting(member.user.tag) === discord;
 						} );
@@ -566,7 +566,7 @@ export default function gamepedia_user(lang, msg, namespace, username, wiki, que
 					else text += '\n\n**' + block.header + '**\n' + block.text;
 				}
 				
-				if ( msg.channel.isGuild() && patreonGuildsPrefix.has(msg.guildId) ) {
+				if ( msg.inGuild() && patreonGuildsPrefix.has(msg.guildId) ) {
 					if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 					else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 					
@@ -579,7 +579,7 @@ export default function gamepedia_user(lang, msg, namespace, username, wiki, que
 				if ( revision?.user === username ) {
 					let discord = ( revision?.slots?.main || revision )['*'].replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 					if ( discord.length > 100 ) discord = discord.substring(0, 100) + '\u2026';
-					if ( msg.channel.isGuild() ) var discordmember = msg.guild.members.cache.find( member => {
+					if ( msg.inGuild() ) var discordmember = msg.guild.members.cache.find( member => {
 						return member.user.tag === discord;
 					} );
 					let discordname = [lang.get('user.info.discord'),escapeFormatting(discord)];

+ 1 - 0
dashboard/src/index.css

@@ -591,6 +591,7 @@ fieldset textarea {
 #wb-settings-avatar-preview-img {
 	width: 128px;
 	height: 128px;
+	image-rendering: pixelated;
 	background: #32353b;
 }
 .theme-light #wb-settings-avatar-preview-img {

+ 1 - 1
functions/global_block.js

@@ -13,7 +13,7 @@ import {got, escapeFormatting} from '../util/functions.js';
  * @param {String} [gender] - The gender of the user.
  */
 export default function global_block(lang, msg, username, text, embed, wiki, spoiler, gender) {
-	if ( !msg || !msg.channel.isGuild() || !patreonGuildsPrefix.has(msg.guildId) || !wiki.isFandom() ) return;
+	if ( !msg || !msg.inGuild() || !patreonGuildsPrefix.has(msg.guildId) || !wiki.isFandom() ) return;
 	
 	var isUser = true;
 	if ( !gender ) {

+ 2 - 2
functions/parse_page.js

@@ -114,7 +114,7 @@ export default function parse_page(lang, msg, content, embed, wiki, reaction, {t
 		if ( !message ) return;
 		if ( !parsedContentModels.includes( contentmodel ) ) return got.get( wiki + 'api.php?action=query&prop=revisions&rvprop=content&rvslots=main&converttitles=true&titles=%1F' + encodeURIComponent( title ) + '&format=json', {
 			timeout: {
-				request: 10000
+				request: 10_000
 			}
 		} ).then( response => {
 			var body = response.body;
@@ -178,7 +178,7 @@ export default function parse_page(lang, msg, content, embed, wiki, reaction, {t
 		let extraImages = [];
 		return got.get( wiki + 'api.php?uselang=' + uselang + '&action=parse' + ( noRedirect ? '' : '&redirects=true' ) + '&prop=text|images|displaytitle' + ( contentmodel !== 'wikitext' || fragment || disambiguation !== undefined ? '' : '&section=0' ) + '&disablelimitreport=true&disableeditsection=true&disabletoc=true&sectionpreview=true&page=' + encodeURIComponent( title ) + '&format=json', {
 			timeout: {
-				request: 10000
+				request: 10_000
 			}
 		} ).then( response => {
 			if ( response.statusCode !== 200 || !response?.body?.parse?.text ) {

+ 8 - 8
functions/verify.js

@@ -26,7 +26,7 @@ export default function verify(lang, channel, member, username, wiki, rows, old_
 		onmatch: rows[0].onmatch
 	};
 	verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
-		return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has([Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES]) );
+		return ( logchannel.isText() && logchannel.permissionsFor(channel.guild.me).has([Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES]) );
 	} ).get(verifynotice.logchannel) : null );
 	var embed = new MessageEmbed().setFooter( lang.get('verify.footer') ).setTimestamp();
 	var result = {
@@ -205,7 +205,7 @@ export default function verify(lang, channel, member, username, wiki, rows, old_
 				var removeRoles = [new Set(), new Set()];
 				var verified = false;
 				var rename = false;
-				var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86400000;
+				var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86_400_000;
 				rows.forEach( row => {
 					let and_or = 'some';
 					if ( row.usergroup.startsWith( 'AND|' ) ) {
@@ -440,7 +440,7 @@ export default function verify(lang, channel, member, username, wiki, rows, old_
 			var removeRoles = [new Set(), new Set()];
 			var verified = false;
 			var rename = false;
-			var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86400000;
+			var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86_400_000;
 			rows.forEach( row => {
 				var and_or = 'some';
 				if ( row.usergroup.startsWith( 'AND|' ) ) {
@@ -640,7 +640,7 @@ globalThis.verifyOauthUser = function(state, access_token, settings) {
 		/** @type {{logchannel:import('discord.js').TextChannel,flags:Number,onsuccess:String,onmatch:String}} */
 		var verifynotice = ( rows[0] || {} );
 		verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
-			return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has([Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES]) );
+			return ( logchannel.isText() && logchannel.permissionsFor(channel.guild.me).has([Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES]) );
 		} ).get(verifynotice.logchannel) : null );
 		got.get( wiki + 'api.php?action=query&meta=siteinfo|globaluserinfo&siprop=general&guiprop=groups&guiuser=' + encodeURIComponent( username ) + '&list=users&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 			var body = response.body;
@@ -713,7 +713,7 @@ globalThis.verifyOauthUser = function(state, access_token, settings) {
 			var removeRoles = [new Set(), new Set()];
 			var verified = false;
 			var rename = false;
-			var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86400000;
+			var accountage = ( Date.now() - new Date(queryuser.registration) ) / 86_400_000;
 			rows.forEach( row => {
 				var and_or = 'some';
 				if ( row.usergroup.startsWith( 'AND|' ) ) {
@@ -925,7 +925,7 @@ globalThis.verifyOauthUser = function(state, access_token, settings) {
 							allowDelete(msg, member.id);
 							if ( settings.sourceMessage ) {
 								settings.sourceMessage.reactEmoji('📩');
-								setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60000 ).unref();
+								setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60_000 ).unref();
 							}
 						}, error => {
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
@@ -951,7 +951,7 @@ globalThis.verifyOauthUser = function(state, access_token, settings) {
 						allowDelete(msg, member.id);
 						if ( settings.sourceMessage ) {
 							settings.sourceMessage.reactEmoji('📩');
-							setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60000 ).unref();
+							setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60_000 ).unref();
 						}
 					}, error => {
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
@@ -987,7 +987,7 @@ function parseNotice(text = '', variables = {editcount: 0, postcount: 0, account
 	text = text.replace( /\$(editcount|postcount|accountage)/g, (variable, key, offset, fulltext) => {
 		var value = ( variables[key] ?? 0 );
 		if ( typeof value === 'string' ) return value;
-		if ( /#(?:if)?expr:[^{|}]*$/.test(fulltext.substring(0, offset)) ) return ( value > 1000000000 ? 1000000000 : value );
+		if ( /#(?:if)?expr:[^{|}]*$/.test(fulltext.substring(0, offset)) ) return ( value > 1_000_000_000 ? 1_000_000_000 : value );
 		return value.toLocaleString(variables.dateformat);
 	} );
 	if ( text.includes( '#expr:' ) ) text = text.replace( /{{\s*#expr:\s*(-?\d{1,10})\s*([+-])\s*(-?\d{1,10})(?:\s*([+-])\s*(-?\d{1,10}))?(?:\s*([+-])\s*(-?\d{1,10}))?(?:\s*([+-])\s*(-?\d{1,10}))?\s*}}/g, (expr, n0, o1, n1, o2, n2, o3, n3, o4, n4, offset, fulltext) => {

+ 12 - 8
main.js

@@ -11,7 +11,7 @@ if ( process.argv[2] === 'readonly' ) process.env.READONLY = true;
 const got = gotDefault.extend( {
 	throwHttpErrors: false,
 	timeout: {
-		request: 30000
+		request: 30_000
 	},
 	headers: {
 		'User-Agent': 'Wiki-Bot/' + ( isDebug ? 'testing' : process.env.npm_package_version ) + ' (Discord; ' + process.env.npm_package_name + ( process.env.invite ? '; ' + process.env.invite : '' ) + ')'
@@ -71,7 +71,7 @@ manager.on( 'shardCreate', shard => {
 
 manager.spawn( {
 	delay: 0,
-	timeout: 60000
+	timeout: -1
 } ).then( shards => {
 	if ( !isDebug && process.env.botlist ) {
 		var botList = JSON.parse(process.env.botlist);
@@ -79,7 +79,7 @@ manager.spawn( {
 			if ( !value ) delete botList[key];
 		}
 		if ( Object.keys(botList).length ) {
-			setInterval( postStats, 10800000, botList, shards.size ).unref();
+			setInterval( postStats, 10_800_000, botList, shards.size ).unref();
 		}
 	}
 }, error => {
@@ -90,7 +90,10 @@ manager.spawn( {
 		if ( typeof server !== 'undefined' && !server.killed ) server.kill();
 		process.exit(1);
 	}
-	else manager.spawn({timeout: -1}).catch( error2 => {
+	else manager.spawn( {
+		delay: 5_000,
+		timeout: 90_000
+	} ).catch( error2 => {
 		console.error( '- Error while spawning the shards: ' + error2 );
 		manager.respawn = false;
 		manager.shards.filter( shard => shard.process && !shard.process.killed ).forEach( shard => shard.kill() );
@@ -104,6 +107,7 @@ if ( process.env.dashboard ) {
 	const dashboard = forkChildProcess('./dashboard/index.js', ( isDebug ? ['debug'] : [] ));
 	server = dashboard;
 
+	/** @type {Object.<string, function(import('discord.js').Client, Object)>} */
 	const evalFunctions = {
 		getGuilds: (discordClient, evalData) => {
 			return Promise.all(
@@ -116,7 +120,7 @@ if ( process.env.dashboard ) {
 								memberCount: guild.memberCount,
 								botPermissions: guild.me.permissions.bitfield.toString(),
 								channels: guild.channels.cache.filter( channel => {
-									return ( channel.isGuild(false) || channel.type === 'GUILD_CATEGORY' );
+									return ( ( channel.isText() && !channel.isThread() ) || channel.type === 'GUILD_CATEGORY' );
 								} ).sort( (a, b) => {
 									let aVal = a.rawPosition + 1;
 									if ( a.type === 'GUILD_CATEGORY' ) aVal *= 1000;
@@ -167,7 +171,7 @@ if ( process.env.dashboard ) {
 					};
 					if ( evalData.channel ) {
 						let channel = guild.channels.cache.get(evalData.channel);
-						if ( channel?.isGuild(false) || ( response.patreon && evalData.allowCategory && channel?.type === 'GUILD_CATEGORY' ) ) {
+						if ( ( channel?.isText() && !channel.isThread() ) || ( response.patreon && evalData.allowCategory && channel?.type === 'GUILD_CATEGORY' ) ) {
 							response.userPermissions = channel.permissionsFor(member).bitfield.toString();
 							response.botPermissions = channel.permissionsFor(guild.me).bitfield.toString();
 							response.isCategory = ( channel.type === 'GUILD_CATEGORY' );
@@ -177,7 +181,7 @@ if ( process.env.dashboard ) {
 					}
 					if ( evalData.newchannel ) {
 						let newchannel = guild.channels.cache.get(evalData.newchannel);
-						if ( newchannel?.isGuild(false) ) {
+						if ( newchannel?.isText() && !newchannel.isThread() ) {
 							response.userPermissionsNew = newchannel.permissionsFor(member).bitfield.toString();
 							response.botPermissionsNew = newchannel.permissionsFor(guild.me).bitfield.toString();
 						}
@@ -375,5 +379,5 @@ if ( isDebug && process.argv[3]?.startsWith( '--timeout:' ) ) {
 		isDebug = false;
 		manager.shards.filter( shard => shard.process && !shard.process.killed ).forEach( shard => shard.kill() );
 		if ( typeof server !== 'undefined' && !server.killed ) server.kill();
-	}, timeout * 1000 ).unref();
+	}, timeout * 1_000 ).unref();
 }

+ 27 - 2
util/functions.js

@@ -3,7 +3,7 @@ import gotDefault from 'got';
 const got = gotDefault.extend( {
 	throwHttpErrors: false,
 	timeout: {
-		request: 5000
+		request: 5_000
 	},
 	headers: {
 		'User-Agent': 'Wiki-Bot/' + ( isDebug ? 'testing' : process.env.npm_package_version ) + ' (Discord; ' + process.env.npm_package_name + ( process.env.invite ? '; ' + process.env.invite : '' ) + ')'
@@ -432,6 +432,29 @@ function partialURIdecode(m) {
 	return text;
 };
 
+/**
+ * Check for timeout or pause.
+ * @param {import('discord.js').Message|import('discord.js').Interaction} msg - The message.
+ * @param {Boolean} [ignorePause] - Ignore pause for admins.
+ * @returns {Boolean}
+ */
+function breakOnTimeoutPause(msg, ignorePause = false) {
+	if ( !msg.inGuild() ) return false;
+	if ( msg.member?.communicationDisabledUntilTimestamp > Date.now() ) {
+		console.log( '- Aborted, communication disabled for User.' );
+		return true;
+	}
+	if ( msg.guild?.me.communicationDisabledUntilTimestamp > Date.now() ) {
+		console.log( '- Aborted, communication disabled for Wiki-Bot.' );
+		return true;
+	}
+	if ( pausedGuilds.has(msg.guildId) && !( ignorePause && ( msg.isAdmin() || msg.isOwner() ) ) ) {
+		console.log( '- Aborted, guild paused.' );
+		return true;
+	};
+	return false;
+};
+
 /**
  * Allow users to delete their command responses.
  * @param {import('discord.js').Message} msg - The response.
@@ -440,7 +463,7 @@ function partialURIdecode(m) {
 function allowDelete(msg, author) {
 	msg?.awaitReactions?.( {
 		filter: (reaction, user) => ( reaction.emoji.name === '🗑️' && user.id === author ),
-		max: 1, time: 300000
+		max: 1, time: 300_000
 	} ).then( reaction => {
 		if ( reaction.size ) msg.delete().catch(log_error);
 	} );
@@ -454,6 +477,7 @@ function allowDelete(msg, author) {
  * @returns {Promise<import('discord.js').Message?>}
  */
 function sendMessage(interaction, message, letDelete = true) {
+	if ( !interaction.ephemeral && letDelete && breakOnTimeoutPause(interaction) ) return Promise.resolve();
 	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
 	return interaction.editReply( message ).then( msg => {
 		if ( letDelete && (msg.flags & 64) !== 64 ) allowDelete(msg, interaction.user.id);
@@ -473,6 +497,7 @@ export {
 	escapeFormatting,
 	limitLength,
 	partialURIdecode,
+	breakOnTimeoutPause,
 	allowDelete,
 	sendMessage
 };

+ 9 - 11
util/newMessage.js

@@ -41,9 +41,7 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 	wiki = new Wiki(wiki);
 	msg.noInline = noInline;
 	var cont = ( content || msg.content );
-	var cleanCont = ( content && Util.cleanContent(content, msg) || msg.cleanContent );
-	var author = msg.author;
-	var channel = msg.channel;
+	var cleanCont = ( content ? Util.cleanContent(content, msg) : msg.cleanContent );
 	if ( msg.isOwner() && cont.hasPrefix(prefix) ) {
 		let invoke = cont.substring(prefix.length).split(' ')[0].split('\n')[0].toLowerCase();
 		let aliasInvoke = ( lang.aliases[invoke] || invoke );
@@ -51,7 +49,7 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 			cont = cont.substring(prefix.length);
 			let args = cont.split(' ').slice(1);
 			if ( cont.split(' ')[0].split('\n')[1] ) args.unshift( '', cont.split(' ')[0].split('\n')[1] );
-			console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + prefix + cont );
+			console.log( ( msg.guildId || '@' + msg.author.id ) + ': ' + prefix + cont );
 			return ownercmdmap[aliasInvoke](lang, msg, args, cont, wiki);
 		}
 	}
@@ -66,10 +64,10 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 			console.log( '- Message contains too many commands!' );
 			msg.reactEmoji('⚠️');
 			msg.sendChannelError( {
-				content: lang.get('general.limit', author.toString()),
+				content: lang.get('general.limit', msg.author.toString()),
 				reply: {messageReference: msg.id},
 				allowedMentions: {
-					users: [author.id],
+					users: [msg.author.id],
 					repliedUser: true
 				}
 			} );
@@ -83,10 +81,10 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 		var ownercmd = ( msg.isOwner() && ownercmdmap.hasOwnProperty(aliasInvoke) );
 		var pausecmd = ( msg.isAdmin() && pausedGuilds.has(msg.guildId) && pausecmdmap.hasOwnProperty(aliasInvoke) );
 		if ( msg.onlyVerifyCommand && !( aliasInvoke === 'verify' || pausecmd || ownercmd ) ) return;
-		if ( channel.isGuild() && pausedGuilds.has(msg.guildId) && !( pausecmd || ownercmd ) ) {
+		if ( msg.inGuild() && pausedGuilds.has(msg.guildId) && !( pausecmd || ownercmd ) ) {
 			return console.log( msg.guildId + ': Paused' );
 		}
-		console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + prefix + line );
+		console.log( ( msg.guildId || '@' + msg.author.id ) + ': ' + prefix + line );
 		if ( ownercmd ) return ownercmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( pausecmd ) return pausecmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( cmdmap.hasOwnProperty(aliasInvoke) ) return cmdmap[aliasInvoke](lang, msg, args, line, wiki);
@@ -116,7 +114,7 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 	} );
 	if ( msg.onlyVerifyCommand ) return;
 	
-	if ( ( !channel.isGuild() || !pausedGuilds.has(msg.guildId) ) && !noInline && ( cont.includes( '[[' ) || cont.includes( '{{' ) ) ) {
+	if ( ( !msg.inGuild() || !pausedGuilds.has(msg.guildId) ) && !noInline && ( cont.includes( '[[' ) || cont.includes( '{{' ) ) ) {
 		var links = [];
 		var embeds = [];
 		var linkcount = 0;
@@ -133,7 +131,7 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 				while ( ( entry = regex.exec(line) ) !== null ) {
 					if ( linkcount < linkmaxcount ) {
 						linkcount++;
-						console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + entry[0] );
+						console.log( ( msg.guildId || '@' + msg.author.id ) + ': ' + entry[0] );
 						let title = entry[2].split('#')[0];
 						let section = entry[2].split('#').slice(1).join('#');
 						links.push({title,section,spoiler:entry[1]});
@@ -153,7 +151,7 @@ export default function newMessage(msg, lang, wiki = defaultSettings.wiki, prefi
 				while ( ( entry = regex.exec(line) ) !== null ) {
 					if ( count < maxcount ) {
 						count++;
-						console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + entry[0] );
+						console.log( ( msg.guildId || '@' + msg.author.id ) + ': ' + entry[0] );
 						let title = entry[2].split('#')[0];
 						let section = entry[2].split('#').slice(1).join('#');
 						embeds.push({title,section,spoiler:entry[1]});