فهرست منبع

remove ugly escapeFormatting

Markus-Rost 4 سال پیش
والد
کامیت
d57ef42c63

+ 0 - 6
bot.js

@@ -111,12 +111,6 @@ Discord.Message.prototype.uploadFiles = function() {
 	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has('ATTACH_FILES');
 };
 
-String.prototype.escapeFormatting = function(isMarkdown) {
-	var text = this;
-	if ( !isMarkdown ) text = text.replace( /[\(\)\\]/g, '\\$&' );
-	return text.replace( /[`_\*~:<>{}@\|]|\/\//g, '\\$&' );
-};
-
 String.prototype.replaceSave = function(pattern, replacement) {
 	return this.replace( pattern, ( typeof replacement === 'string' ? replacement.replace( /\$/g, '$$$$' ) : replacement ) );
 };

+ 7 - 6
cmds/get.js

@@ -1,5 +1,6 @@
 const {MessageEmbed, Util, ShardClientUtil: {shardIDForGuildID}} = require('discord.js');
 const {defaultSettings, defaultPermissions} = require('../util/default.json');
+const {escapeFormatting} = require('../util/functions.js');
 var db = require('../util/database.js');
 
 /**
@@ -26,8 +27,8 @@ async function cmd_get(lang, msg, args, line, wiki) {
 			} )
 		}`, shardIDForGuildID(id, msg.client.shard.count) );
 		if ( guild ) {
-			var guildname = ['Guild:', guild.name.escapeFormatting() + ' `' + guild.id + '`' + ( guild.pause ? '\\*' : '' )];
-			var guildowner = ['Owner:', ( guild.owner ? guild.owner.escapeFormatting() + ' ' : '' ) + '`' + guild.ownerID + '` <@' + guild.ownerID + '>'];
+			var guildname = ['Guild:', escapeFormatting(guild.name) + ' `' + guild.id + '`' + ( guild.pause ? '\\*' : '' )];
+			var guildowner = ['Owner:', ( guild.owner ? escapeFormatting(guild.owner) + ' ' : '' ) + '`' + guild.ownerID + '` <@' + guild.ownerID + '>'];
 			var guildsize = ['Size:', guild.memberCount + ' members'];
 			var guildshard = ['Shard:', guild.shardId];
 			var guildpermissions = ['Missing permissions:', ( guild.permissions.length ? '`' + guild.permissions.join('`, `') + '`' : '*none*' )];
@@ -75,8 +76,8 @@ async function cmd_get(lang, msg, args, line, wiki) {
 			} )
 		}` ).then( results => results.find( result => result ) );
 		if ( channel ) {
-			var channelguild = ['Guild:', channel.guild.escapeFormatting() + ' `' + channel.guildID + '`' + ( channel.pause ? '\\*' : '' )];
-			var channelname = ['Channel:', '#' + channel.name.escapeFormatting() + ' `' + channel.id + '` <#' + channel.id + '>'];
+			var channelguild = ['Guild:', escapeFormatting(channel.guild) + ' `' + channel.guildID + '`' + ( channel.pause ? '\\*' : '' )];
+			var channelname = ['Channel:', '#' + escapeFormatting(channel.name) + ' `' + channel.id + '` <#' + channel.id + '>'];
 			var channeldetails = ['Details:', '`' + channel.type + '`' + ( channel.parentID ? ' – `' + channel.parentID + '` <#' + channel.parentID + '>' : '' )];
 			var channelpermissions = ['Missing permissions:', ( channel.permissions.length ? '`' + channel.permissions.join('`, `') + '`' : '*none*' )];
 			var channellang = ['Language:', '*unknown*'];
@@ -114,7 +115,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 		
 		var user = await msg.client.users.fetch(id, false).catch( () => {} );
 		if ( user ) {
-			var username = ['User:', user.tag.escapeFormatting() + ' `' + user.id + '` <@' + user.id + '>'];
+			var username = ['User:', escapeFormatting(user.tag) + ' `' + user.id + '` <@' + user.id + '>'];
 			var guildlist = ['Guilds:', '*none*'];
 			var guilds = await msg.client.shard.broadcastEval( `this.guilds.cache.filter( guild => guild.members.cache.has('${user.id}') ).map( guild => {
 				var member = guild.members.cache.get('${user.id}');
@@ -126,7 +127,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 				}
 			} )` ).then( results => {
 				return results.reduce( (acc, val) => acc.concat(val), [] ).map( user_guild => {
-					return user_guild.name.escapeFormatting() + ' `' + user_guild.id + '`' + ( user_guild.isAdmin ? '\\*' : '' );
+					return escapeFormatting(user_guild.name) + ' `' + user_guild.id + '`' + ( user_guild.isAdmin ? '\\*' : '' );
 				} );
 			} );
 			if ( guilds.length ) guildlist[1] = guilds.join('\n');

+ 5 - 4
cmds/minecraft/bug.js

@@ -1,4 +1,5 @@
 const {MessageEmbed} = require('discord.js');
+const {escapeFormatting} = require('../../util/functions.js');
 
 /**
  * Sends a Minecraft issue.
@@ -44,7 +45,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler) {
 				}
 				else {
 					var statusList = lang.get('minecraft.status');
-					var summary = body.fields.summary.escapeFormatting();
+					var summary = escapeFormatting(body.fields.summary);
 					if ( summary.length > 250 ) summary = summary.substring(0, 250) + '\u2026';
 					var description = ( body.fields.description || '' ).replace( /\{code\}/g, '```' );
 					if ( description.length > 2000 ) description = description.substring(0, 2000) + '\u2026';
@@ -58,7 +59,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler) {
 							var issue = link[ward + 'Issue']; // looks for property (in|out)wardIssue
 							var name = ( linkList?.[link.type.name]?.[ward]?.replaceSave( /\$1/g, issue.key ) || link.type[ward] + ' ' + issue.key );
 							var status = issue.fields.status.name;
-							var value = ( statusList?.[status] || status ) + ': [' + issue.fields.summary.escapeFormatting() + '](' + baseBrowseUrl + issue.key + ')';
+							var value = ( statusList?.[status] || status ) + ': [' + escapeFormatting(issue.fields.summary) + '](' + baseBrowseUrl + issue.key + ')';
 							if ( embed.fields.length < 25 && ( embed.length + name.length + value.length ) < 6000 ) embed.addField( name, value );
 							else extralinks.push({name,value,inline:false});
 						} );
@@ -69,7 +70,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler) {
 					if ( body.fields.resolution && body.fields.fixVersions && body.fields.fixVersions.length ) {
 						fixed = '\n' + lang.get('minecraft.fixed', body.fields.fixVersions.length) + ' ' + body.fields.fixVersions.map( v => v.name ).join(', ');
 					}
-					msg.sendChannel( spoiler + '**' + ( statusList?.[status] || status ) + '**: ' + body.fields.summary.escapeFormatting() + '\n<' + baseBrowseUrl + body.key + '>' + fixed + spoiler, {embed} );
+					msg.sendChannel( spoiler + '**' + ( statusList?.[status] || status ) + '**: ' + escapeFormatting(body.fields.summary) + '\n<' + baseBrowseUrl + body.key + '>' + fixed + spoiler, {embed} );
 				}
 			}
 		}, error => {
@@ -112,7 +113,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler) {
 						var statusList = lang.get('minecraft.status');
 						body.issues.forEach( bug => {
 							var status = ( bug.fields.resolution ? bug.fields.resolution.name : bug.fields.status.name );
-							var value = ( statusList?.[status] || status ) + ': [' + bug.fields.summary.escapeFormatting() + '](https://bugs.mojang.com/browse/' + bug.key + ')';
+							var value = ( statusList?.[status] || status ) + ': [' + escapeFormatting(bug.fields.summary) + '](https://bugs.mojang.com/browse/' + bug.key + ')';
 							embed.addField( bug.key, value );
 						} );
 						if ( body.total > 25 ) {

+ 5 - 10
cmds/wiki/diff.js

@@ -1,7 +1,7 @@
 const {MessageEmbed} = require('discord.js');
 const logging = require('../../util/logging.js');
 const {timeoptions} = require('../../util/default.json');
-const {toFormatting, htmlToDiscord} = require('../../util/functions.js');
+const {htmlToPlain, htmlToDiscord, escapeFormatting} = require('../../util/functions.js');
 const diffParser = require('../../util/edit_diff.js');
 
 /**
@@ -181,7 +181,7 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, compare)
 			var revisions = pages[0].revisions.sort( (first, second) => Date.parse(second.timestamp) - Date.parse(first.timestamp) );
 			var diff = revisions[0].revid;
 			var oldid = ( revisions[1] ? revisions[1].revid : 0 );
-			var editor = [lang.get('diff.info.editor'), ( revisions[0].userhidden !== undefined ? lang.get('diff.hidden') : revisions[0].user )];
+			var editor = [lang.get('diff.info.editor'), ( revisions[0].userhidden !== undefined ? lang.get('diff.hidden') : ( msg.showEmbed() ? '[' + escapeFormatting(revisions[0].user) + '](' + wiki.toLink(( revisions[0].anon !== undefined ? 'Special:Contributions/' : 'User:' ) + revisions[0].user, '', '', true) + ')' : escapeFormatting(revisions[0].user) ) )];
 			try {
 				var dateformat = new Intl.DateTimeFormat(lang.get('dateformat'), Object.assign({
 					timeZone: body.query.general.timezone
@@ -202,13 +202,8 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, compare)
 			var text = '<' + pagelink + '>';
 			var embed = null;
 			if ( msg.showEmbed() ) {
-				var editorlink = '[' + editor[1] + '](' + wiki.toLink('User:' + editor[1], '', '', true) + ')';
-				if ( revisions[0].anon !== undefined ) {
-					editorlink = '[' + editor[1] + '](' + wiki.toLink('Special:Contributions/' + editor[1], '', '', true) + ')';
-				}
-				if ( editor[1] === lang.get('diff.hidden') ) editorlink = editor[1];
-				embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( ( title + '?diff=' + diff + '&oldid=' + oldid ).escapeFormatting() ).setURL( pagelink ).addField( editor[0], editorlink, true ).addField( size[0], size[1], true ).addField( comment[0], comment[1] ).setFooter( timestamp[1] );
-				if ( tags ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink, true) );
+				embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting( title + '?diff=' + diff + '&oldid=' + oldid ) ).setURL( pagelink ).addField( editor[0], editor[1], true ).addField( size[0], size[1], true ).addField( comment[0], comment[1] ).setFooter( timestamp[1] );
+				if ( tags ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink) );
 				
 				var more = '\n__' + lang.get('diff.info.more') + '__';
 				var whitespace = '__' + lang.get('diff.info.whitespace') + '__';
@@ -259,7 +254,7 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, compare)
 						if ( compare[1].length ) embed.addField( lang.get('diff.info.added'), compare[1], true );
 					}
 					else if ( ( revisions[0]?.slots?.main || revisions[0] )['*'] ) {
-						var content = ( revisions[0]?.slots?.main || revisions[0] )['*'].escapeFormatting();
+						var content = escapeFormatting( ( revisions[0]?.slots?.main || revisions[0] )['*'] );
 						if ( content.trim().length ) {
 							if ( content.length <= 1000 ) content = '**' + content + '**';
 							else {

+ 6 - 6
cmds/wiki/general.js

@@ -2,7 +2,7 @@ const {MessageEmbed} = require('discord.js');
 const parse_page = require('../../functions/parse_page.js');
 const phabricator = require('../../functions/phabricator.js');
 const logging = require('../../util/logging.js');
-const {htmlToDiscord, partialURIdecode} = require('../../util/functions.js');
+const {htmlToDiscord, escapeFormatting, partialURIdecode} = require('../../util/functions.js');
 const extract_desc = require('../../util/extract_desc.js');
 const {limit: {interwiki: interwikiLimit}, wikiProjects} = require('../../util/default.json');
 const Wiki = require('../../util/wiki.js');
@@ -217,7 +217,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				querypage.uselang = uselang;
 				var pagelink = wiki.toLink(querypage.title, querystring, fragment);
 				var text = '';
-				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink );
+				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 				if ( querypage.pageprops && querypage.pageprops.displaytitle ) {
 					var displaytitle = htmlToDiscord( querypage.pageprops.displaytitle );
 					if ( displaytitle.length > 250 ) displaytitle = displaytitle.substring(0, 250) + '\u2026';
@@ -298,7 +298,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				specialpage = ( specialpage ? specialpage.realname : querypage.title.replace( body.query.namespaces['-1']['*'] + ':', '' ).split('/')[0] ).toLowerCase();
 				if ( !['mylanguage'].includes( specialpage ) ) {
 					var pagelink = wiki.toLink(querypage.title, querystring, fragment);
-					var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
+					var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
 					return fn.special_page(lang, msg, querypage, specialpage, embed, wiki, reaction, spoiler);
 				}
 			}
@@ -306,7 +306,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				logging(wiki, msg.guild?.id, 'general', 'media');
 				var filepath = body.query.specialpagealiases.find( sp => sp.realname === 'Filepath' );
 				var pagelink = wiki.toLink(body.query.namespaces['-1']['*'] + ':' + ( filepath?.aliases?.[0] || 'FilePath' ) + querypage.title.replace( body.query.namespaces['-2']['*'] + ':', '/' ), querystring, fragment);
-				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink ).setDescription( '[' + lang.get('search.media') + '](' + wiki.toLink(querypage.title, '', '', true) + ')' );
+				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink ).setDescription( '[' + lang.get('search.media') + '](' + wiki.toLink(querypage.title, '', '', true) + ')' );
 				if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pagelink );
 				else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pagelink,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 				
@@ -318,7 +318,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			logging(wiki, msg.guild?.id, 'general');
 			var pagelink = wiki.toLink(querypage.title, querystring, ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ));
 			var text = '';
-			var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink );
+			var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 			if ( querypage.pageprops && querypage.pageprops.displaytitle ) {
 				var displaytitle = htmlToDiscord( querypage.pageprops.displaytitle );
 				if ( displaytitle.length > 250 ) displaytitle = displaytitle.substring(0, 250) + '\u2026';
@@ -427,7 +427,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			uselang, noRedirect
 		};
 		var pagelink = wiki.toLink(querypage.title, querystring, fragment);
-		var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
+		var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
 		got.get( wiki + 'api.php?uselang=' + uselang + '&action=query' + ( noRedirect ? '' : '&redirects=true' ) + '&prop=info|pageprops|extracts&ppprop=description|displaytitle|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&titles=' + encodeURIComponent( querypage.title ) + '&format=json' ).then( mpresponse => {
 			var mpbody = mpresponse.body;
 			if ( mpbody && mpbody.warnings ) log_warn(body.warnings);

+ 3 - 3
cmds/wiki/overview.js

@@ -1,7 +1,7 @@
 const {MessageEmbed} = require('discord.js');
 const logging = require('../../util/logging.js');
 const {timeoptions} = require('../../util/default.json');
-const {toFormatting, toPlaintext} = require('../../util/functions.js');
+const {toFormatting, toPlaintext, escapeFormatting} = require('../../util/functions.js');
 
 /**
  * Sends a Gamepedia wiki overview.
@@ -89,7 +89,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 		var text = '<' + pagelink + '>';
 		var embed = null;
 		if ( msg.showEmbed() ) {
-			embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( title.escapeFormatting() ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
+			embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(title) ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
 		}
 		else {
 			text += '\n';
@@ -127,7 +127,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 					created[1] = dateformat.format(creation_date);
 				}
 				if ( site.desc ) {
-					description[1] = site.desc.escapeFormatting();
+					description[1] = escapeFormatting(site.desc);
 					if ( description[1].length > 1000 ) {
 						description[1] = description[1].substring(0, 1000) + '\u2026';
 					}

+ 2 - 2
cmds/wiki/random.js

@@ -1,7 +1,7 @@
 const {MessageEmbed} = require('discord.js');
 const parse_page = require('../../functions/parse_page.js');
 const logging = require('../../util/logging.js');
-const {htmlToDiscord} = require('../../util/functions.js');
+const {htmlToDiscord, escapeFormatting} = require('../../util/functions.js');
 const extract_desc = require('../../util/extract_desc.js');
 
 /**
@@ -32,7 +32,7 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler) {
 		logging(wiki, msg.guild?.id, 'random');
 		var querypage = Object.values(body.query.pages)[0];
 		var pagelink = wiki.toLink(querypage.title);
-		var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink );
+		var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 		if ( querypage.pageprops && querypage.pageprops.displaytitle ) {
 			var displaytitle = htmlToDiscord( querypage.pageprops.displaytitle );
 			if ( displaytitle.length > 250 ) displaytitle = displaytitle.substring(0, 250) + '\u2026';

+ 18 - 18
cmds/wiki/user.js

@@ -5,7 +5,7 @@ const parse_page = require('../../functions/parse_page.js');
 const logging = require('../../util/logging.js');
 const extract_desc = require('../../util/extract_desc.js');
 const {timeoptions, usergroups} = require('../../util/default.json');
-const {toMarkdown, toPlaintext, htmlToDiscord} = require('../../util/functions.js');
+const {toMarkdown, toPlaintext, htmlToDiscord, escapeFormatting} = require('../../util/functions.js');
 
 /**
  * Processes a Gamepedia user.
@@ -31,7 +31,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 				if ( querypage.missing !== undefined || querypage.ns === -1 ) msg.reactEmoji('error');
 				else {
 					var pagelink = wiki.toLink(querypage.title, querystring, fragment);
-					var embed = new MessageEmbed().setTitle( querypage.title.escapeFormatting() ).setURL( pagelink );
+					var embed = new MessageEmbed().setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 					if ( body?.query?.general ) {
 						wiki.updateWiki(body.query.general);
 						embed.setAuthor( body.query.general.sitename );
@@ -141,13 +141,13 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 			if ( isBlocked ) {
 				var text = 'user.block.' + ( isIndef ? 'indef_' : '' ) + ( block.reason ? 'text' : 'noreason' );
 				if ( msg.showEmbed() ) {
-					text = lang.get(text, dateformat.format(blockedtimestamp), blockduration, blockexpiry, '[' + block.by.escapeFormatting() + '](' + wiki.toLink('User:' + block.by, '', '', true) + ')', toMarkdown(block.reason, wiki));
+					text = lang.get(text, dateformat.format(blockedtimestamp), blockduration, blockexpiry, '[' + escapeFormatting(block.by) + '](' + wiki.toLink('User:' + block.by, '', '', true) + ')', toMarkdown(block.reason, wiki));
 				}
 				else {
-					text = lang.get(text, dateformat.format(blockedtimestamp), blockduration, blockexpiry, block.by.escapeFormatting(), toPlaintext(block.reason));
+					text = lang.get(text, dateformat.format(blockedtimestamp), blockduration, blockexpiry, escapeFormatting(block.by), toPlaintext(block.reason));
 				}
 				return {
-					header: lang.get('user.block.header', block.user, 'unknown').escapeFormatting(), text
+					header: lang.get('user.block.header', escapeFormatting(block.user), 'unknown'), text
 				};
 			}
 		} ).filter( block => block !== undefined );
@@ -251,7 +251,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 			if ( querypage.missing !== undefined || querypage.ns === -1 ) msg.reactEmoji('🤷');
 			else {
 				var pagelink = wiki.toLink(querypage.title, querystring, fragment);
-				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( querypage.title.escapeFormatting() ).setURL( pagelink );
+				var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 				if ( querypage.pageprops && querypage.pageprops.displaytitle ) {
 					var displaytitle = htmlToDiscord( querypage.pageprops.displaytitle );
 					if ( displaytitle.length > 250 ) displaytitle = displaytitle.substring(0, 250) + '\u2026';
@@ -422,13 +422,13 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 			if ( isBlocked ) {
 				var blockedtext = 'user.block.' + ( isIndef ? 'indef_' : '' ) + ( queryuser.blockreason ? 'text' : 'noreason' );
 				if ( msg.showEmbed() ) {
-					blockedtext = lang.get(blockedtext, ( blockedtimestamp ? dateformat.format(blockedtimestamp) : 'Invalid Date' ), blockduration, blockexpiry, '[' + queryuser.blockedby.escapeFormatting() + '](' + wiki.toLink('User:' + queryuser.blockedby, '', '', true) + ')', toMarkdown(queryuser.blockreason, wiki));
+					blockedtext = lang.get(blockedtext, ( blockedtimestamp ? dateformat.format(blockedtimestamp) : 'Invalid Date' ), blockduration, blockexpiry, '[' + escapeFormatting(queryuser.blockedby) + '](' + wiki.toLink('User:' + queryuser.blockedby, '', '', true) + ')', toMarkdown(queryuser.blockreason, wiki));
 				}
 				else {
-					blockedtext = lang.get(blockedtext, ( blockedtimestamp ? dateformat.format(blockedtimestamp) : 'Invalid Date' ), blockduration, blockexpiry, queryuser.blockedby.escapeFormatting(), toPlaintext(queryuser.blockreason));
+					blockedtext = lang.get(blockedtext, ( blockedtimestamp ? dateformat.format(blockedtimestamp) : 'Invalid Date' ), blockduration, blockexpiry, escapeFormatting(queryuser.blockedby), toPlaintext(queryuser.blockreason));
 				}
 				var block = {
-					header: lang.get('user.block.header', username, queryuser.gender).escapeFormatting(), text: blockedtext
+					header: lang.get('user.block.header', escapeFormatting(username), queryuser.gender), text: blockedtext
 				};
 			}
 			
@@ -436,7 +436,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 			var text = '<' + pagelink + '>';
 			var embed = null;
 			if ( msg.showEmbed() ) {
-				embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( username.escapeFormatting() ).setURL( pagelink ).addField( editcount[0], '[' + editcount[1] + '](' + wiki.toLink(contribs + username, '', '', true) + ')', true );
+				embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(username) ).setURL( pagelink ).addField( editcount[0], '[' + editcount[1] + '](' + wiki.toLink(contribs + username, '', '', true) + ')', true );
 				embed.forceTitle = true;
 				if ( wiki.hasCentralAuth() ) {
 					embed.addField( lang.get('user.info.globaleditcount'), '[' + body.query.globaluserinfo.editcount.toLocaleString(lang.get('dateformat')) + '](' + wiki.toLink('Special:CentralAuth/' + username, '', '', true) + ')', true ).addField( lang.get('user.info.wikisedited'), '[' + body.query.globaluserinfo.merged.filter( mergedWiki => mergedWiki.editcount ).length.toLocaleString(lang.get('dateformat')) + '](' + wiki.toLink('Special:CentralAuth/' + username, '', '', true) + ')', true );
@@ -493,7 +493,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 						embed.setThumbnail( pbody.userData.avatar.replace( '/thumbnail/width/400/height/400', '' ) );
 					}
 					if ( pbody.userData.bio && !embed.description ) {
-						let bio = pbody.userData.bio.escapeFormatting();
+						let bio = escapeFormatting(pbody.userData.bio);
 						if ( bio.length > 1000 ) bio = bio.substring(0, 1000) + '\u2026';
 						embed.backupDescription = bio;
 					}
@@ -506,7 +506,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 				}
 				var discord = '';
 				if ( pbody.userData.discordHandle ) {
-					discord = pbody.userData.discordHandle.escapeFormatting().replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
+					discord = escapeFormatting(pbody.userData.discordHandle).replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 					if ( discord.length > 100 ) discord = discord.substring(0, 100) + '\u2026';
 				}
 				if ( wiki.isGamepedia() ) return got.get( wiki + 'api.php?action=profile&do=getPublicProfile&user_name=' + encodeURIComponent( username ) + '&format=json&cache=' + Date.now() ).then( cpresponse => {
@@ -516,13 +516,13 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 						return;
 					}
 					if ( cpbody.profile['link-discord'] ) {
-						discord = cpbody.profile['link-discord'].escapeFormatting().replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
+						discord = escapeFormatting(cpbody.profile['link-discord']).replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 						if ( discord.length > 100 ) discord = discord.substring(0, 100) + '\u2026';
 					}
 					if ( discord ) {
 						if ( msg.channel.isGuild() ) {
 							var discordmember = msg.guild.members.cache.find( member => {
-								return member.user.tag.escapeFormatting() === discord;
+								return escapeFormatting(member.user.tag) === discord;
 							} );
 						}
 						var discordname = [lang.get('user.info.discord'),discord];
@@ -550,7 +550,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 				if ( discord ) {
 					if ( msg.channel.isGuild() ) {
 						var discordmember = msg.guild.members.cache.find( member => {
-							return member.user.tag.escapeFormatting() === discord;
+							return escapeFormatting(member.user.tag) === discord;
 						} );
 					}
 					let discordname = [lang.get('user.info.discord'),discord];
@@ -583,7 +583,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 					if ( msg.channel.isGuild() ) var discordmember = msg.guild.members.cache.find( member => {
 						return member.user.tag === discord;
 					} );
-					let discordname = [lang.get('user.info.discord'),discord.escapeFormatting()];
+					let discordname = [lang.get('user.info.discord'),escapeFormatting(discord)];
 					if ( discordmember ) discordname[1] = discordmember.toString();
 					
 					if ( msg.showEmbed() ) embed.addField( discordname[0], discordname[1], true );
@@ -595,8 +595,8 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 				else text += '\n\n**' + block.header + '**\n' + block.text;
 			}
 			if ( wiki.hasCentralAuth() && body.query.globaluserinfo.locked !== undefined ) {
-				if ( msg.showEmbed() ) embed.addField( '\u200b', '**' + lang.get('user.gblock.header', username, gender).escapeFormatting() + '**' );
-				else text += '\n\n**' + lang.get('user.gblock.header', username, gender).escapeFormatting() + '**';
+				if ( msg.showEmbed() ) embed.addField( '\u200b', '**' + lang.get('user.gblock.header', escapeFormatting(username), gender) + '**' );
+				else text += '\n\n**' + lang.get('user.gblock.header', escapeFormatting(username), gender) + '**';
 			}
 			
 			parse_page(lang, msg, spoiler + text + spoiler, embed, wiki, reaction, querypage);

+ 13 - 32
functions/discussion.js

@@ -1,6 +1,7 @@
 const htmlparser = require('htmlparser2');
 const {MessageEmbed, Util} = require('discord.js');
 const {limit: {discussion: discussionLimit}} = require('../util/default.json');
+const {htmlToDiscord, escapeFormatting} = require('../util/functions.js');
 
 /**
  * Processes discussion commands.
@@ -28,7 +29,7 @@ function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler)
 				var parser = new htmlparser.Parser( {
 					onopentag: (tagname, attribs) => {
 						if ( tagname === 'meta' && attribs.property === 'og:description' ) {
-							var description = attribs.content.escapeFormatting();
+							var description = escapeFormatting(attribs.content);
 							if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
 							embed.setDescription( description );
 						}
@@ -108,7 +109,7 @@ function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler)
 								console.log( '- ' + thresponse.statusCode + ': Error while getting the thread: ' + ( thbody && thbody.title ) );
 								embed.setTitle( '~~' + pbody.threadId + '~~' );
 							}
-							else embed.setTitle( thbody.title.escapeFormatting() );
+							else embed.setTitle( escapeFormatting(thbody.title) );
 						}, error => {
 							console.log( '- Error while getting the thread: ' + error );
 							embed.setTitle( '~~' + pbody.threadId + '~~' );
@@ -252,11 +253,11 @@ function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler)
  */
 function discussion_send(lang, msg, wiki, discussion, embed, spoiler) {
 	if ( discussion.title ) {
-		embed.setTitle( discussion.title.escapeFormatting() );
+		embed.setTitle( escapeFormatting(discussion.title) );
 		var pagelink = wiki + 'f/p/' + ( discussion.threadId || discussion.id );
 	}
 	else {
-		if ( discussion._embedded.thread ) embed.setTitle( discussion._embedded.thread[0].title.escapeFormatting() );
+		if ( discussion._embedded.thread ) embed.setTitle( escapeFormatting(discussion._embedded.thread[0].title) );
 		var pagelink = wiki + 'f/p/' + discussion.threadId + '/r/' + discussion.id;
 	}
 	var text = '<' + pagelink + '>';
@@ -267,10 +268,10 @@ function discussion_send(lang, msg, wiki, discussion, embed, spoiler) {
 			embed.setImage( discussion._embedded.contentImages[0].url );
 			break;
 		case 'POLL':
-			discussion.poll.answers.forEach( answer => embed.addField( answer.text.escapeFormatting(), ( answer.image ? '[__' + lang.get('discussion.image').escapeFormatting() + '__](' + answer.image.url + ')\n' : '' ) + lang.get('discussion.votes', answer.votes.toLocaleString(lang.get('dateformat')), answer.votes, ( ( answer.votes / discussion.poll.totalVotes ) * 100 ).toFixed(1).toLocaleString(lang.get('dateformat'))), true ) );
+			discussion.poll.answers.forEach( answer => embed.addField( escapeFormatting(answer.text), ( answer.image ? '[__' + lang.get('discussion.image') + '__](' + answer.image.url + ')\n' : '' ) + lang.get('discussion.votes', answer.votes.toLocaleString(lang.get('dateformat')), answer.votes, ( ( answer.votes / discussion.poll.totalVotes ) * 100 ).toFixed(1).toLocaleString(lang.get('dateformat'))), true ) );
 			break;
 		case 'QUIZ':
-			description = discussion._embedded.quizzes[0].title.escapeFormatting();
+			description = escapeFormatting(discussion._embedded.quizzes[0].title);
 			embed.setThumbnail( discussion._embedded.quizzes[0].image );
 			break;
 		default:
@@ -285,7 +286,7 @@ function discussion_send(lang, msg, wiki, discussion, embed, spoiler) {
 						else {
 							description = description.replace( /\{\@(\d+)\}/g, (match, n) => {
 								if ( n >= discussion._embedded.contentImages.length ) return '';
-								else return '[__' + lang.get('discussion.image').escapeFormatting() + '__](' + discussion._embedded.contentImages[n].url + ')';
+								else return '[__' + lang.get('discussion.image') + '__](' + discussion._embedded.contentImages[n].url + ')';
 							} );
 							embed.setThumbnail( discussion._embedded.contentImages[0].url );
 						}
@@ -294,43 +295,23 @@ function discussion_send(lang, msg, wiki, discussion, embed, spoiler) {
 				}
 				catch ( jsonerror ) {
 					console.log( '- Error while getting the formatting: ' + jsonerror );
-					description = discussion.rawContent.escapeFormatting();
+					description = escapeFormatting(discussion.rawContent);
 					if ( discussion._embedded.contentImages.length ) embed.setThumbnail( discussion._embedded.contentImages[0].url );
 				}
 			}
 			else if ( discussion.renderedContent ) {
-				var current_tag = '';
-				var parser = new htmlparser.Parser( {
-					onopentag: (tagname, attribs) => {
-						if ( tagname === 'a' ) {
-							current_tag = attribs.href;
-							description += '[';
-						}
-					},
-					ontext: (htmltext) => {
-						description += htmltext.escapeFormatting();
-					},
-					onclosetag: (tagname) => {
-						if ( tagname === 'a' ) {
-							description += '](' + current_tag + ')';
-							current_tag = '';
-						}
-						if ( tagname === 'p' ) description += '\n';
-					}
-				} );
-				parser.write( discussion.renderedContent );
-				parser.end();
+				description = htmlToDiscord(discussion.renderedContent, pagelink);
 				if ( discussion._embedded.contentImages.length ) embed.setThumbnail( discussion._embedded.contentImages[0].url );
 			}
 			else {
-				description = discussion.rawContent.escapeFormatting();
+				description = escapeFormatting(discussion.rawContent);
 				if ( discussion._embedded.contentImages.length ) embed.setThumbnail( discussion._embedded.contentImages[0].url );
 			}
 	}
 	if ( description.length > 2000 ) description = description.substring(0, 2000) + '\u2026';
 	embed.setDescription( description );
 	if ( discussion.tags?.length ) {
-		embed.addField( lang.get('discussion.tags'), Util.splitMessage( discussion.tags.map( tag => '[' + tag.articleTitle.escapeFormatting() + '](' + wiki.toLink(tag.articleTitle, '', '', true) + ')' ).join(', '), {char:', ',maxLength:1000} )[0], false );
+		embed.addField( lang.get('discussion.tags'), Util.splitMessage( discussion.tags.map( tag => '[' + escapeFormatting(tag.articleTitle) + '](' + wiki.toLink(tag.articleTitle, '', '', true) + ')' ).join(', '), {char:', ',maxLength:1000} )[0], false );
 	}
 	
 	msg.sendChannel( spoiler + text + spoiler, {embed} );
@@ -379,7 +360,7 @@ function discussion_formatting(jsonModel) {
 					}
 				} );
 			}
-			description += prepend + jsonModel.text.escapeFormatting() + append;
+			description += prepend + escapeFormatting(jsonModel.text) + append;
 			break;
 		case 'image':
 			if ( jsonModel.attrs.id !== null ) description += '{@' + jsonModel.attrs.id + '}\n';

+ 3 - 2
functions/global_block.js

@@ -1,4 +1,5 @@
 const cheerio = require('cheerio');
+const {escapeFormatting} = require('../util/functions.js');
 
 /**
  * Add global blocks to user messages.
@@ -42,8 +43,8 @@ function global_block(lang, msg, username, text, embed, wiki, spoiler, gender) {
 					else text += '\n\n**' + lang.get('user.gblock.disabled') + '**';
 				}
 				else if ( $('#mw-content-text .userprofile.mw-warning-with-logexcerpt').length ) {
-					if ( msg.showEmbed() ) embed.addField( '\u200b', '**' + lang.get('user.gblock.header', username, gender).escapeFormatting() + '**' );
-					else text += '\n\n**' + lang.get('user.gblock.header', username, gender).escapeFormatting() + '**';
+					if ( msg.showEmbed() ) embed.addField( '\u200b', '**' + lang.get('user.gblock.header', escapeFormatting(username), gender) + '**' );
+					else text += '\n\n**' + lang.get('user.gblock.header', escapeFormatting(username), gender) + '**';
 				}
 			}
 		}, error => {

+ 5 - 5
functions/parse_page.js

@@ -1,7 +1,7 @@
 const cheerio = require('cheerio');
 const {MessageEmbed} = require('discord.js');
 const {toSection} = require('../util/wiki.js');
-const {parse_infobox, htmlToPlain, htmlToDiscord, limitLength} = require('../util/functions.js');
+const {parse_infobox, htmlToPlain, htmlToDiscord, escapeFormatting, limitLength} = require('../util/functions.js');
 
 const parsedContentModels = [
 	'wikitext',
@@ -206,7 +206,7 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 						let value = infobox.find(field.value.replace( /^`(.+)`$/, '[data-source="$1"] .pi-data-value, .pi-data-value[data-source="$1"]' )).html();
 						if ( !value ) value = infobox.find(field.value.replace( /^`(.+)`$/, '[data-item-name="$1"] .pi-data-value, .pi-data-value[data-item-name="$1"]' )).html();
 						if ( value ) {
-							value = htmlToDiscord(value, embed.url, true).trim().replace( /\n{3,}/g, '\n\n' );
+							value = htmlToDiscord(value, embed.url).trim().replace( /\n{3,}/g, '\n\n' );
 							if ( value.length > 500 ) value = limitLength(value, 500, 250);
 							if ( value ) field.value = value;
 						}
@@ -265,7 +265,7 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 						value.find(removeClasses.join(', ')).remove();
 						if ( !label.is('td') && label.html()?.trim() && value.html()?.trim() ) tdLabel = false;
 						label = htmlToPlain(label).trim().split('\n')[0];
-						value = htmlToDiscord(value, embed.url, true).trim().replace( /\n{3,}/g, '\n\n' );
+						value = htmlToDiscord(value, embed.url).trim().replace( /\n{3,}/g, '\n\n' );
 						if ( label.length > 100 ) label = label.substring(0, 100) + '\u2026';
 						if ( value.length > 500 ) value = limitLength(value, 500, 250);
 						if ( label && value ) embed.addField( label, value, true );
@@ -334,9 +334,9 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 					sectionContent.find(infoboxList.join(', ')).remove();
 					sectionContent.find('div, ' + removeClasses.join(', ')).not(removeClassesExceptions.join(', ')).remove();
 					var name = htmlToPlain(section).trim();
-					if ( !name.length ) name = fragment.escapeFormatting();
+					if ( !name.length ) name = escapeFormatting(fragment);
 					if ( name.length > 250 ) name = name.substring(0, 250) + '\u2026';
-					var value = htmlToDiscord(sectionContent, embed.url, true).trim().replace( /\n{3,}/g, '\n\n' );
+					var value = htmlToDiscord(sectionContent, embed.url).trim().replace( /\n{3,}/g, '\n\n' );
 					if ( value.length > 1000 ) value = limitLength(value, 1000, 20);
 					if ( name.length && value.length ) {
 						embed.spliceFields( 0, 0, {name, value} );

+ 5 - 5
functions/phabricator.js

@@ -37,17 +37,17 @@ function phabricator_task(lang, msg, wiki, link, reaction, spoiler = '') {
 			return;
 		}
 		var task = body.result.data[0];
-		var status = '**' + task.fields.status.name + ':** ' + task.fields.name.escapeFormatting() + '\n';
+		var status = '**' + task.fields.status.name + ':** ' + escapeFormatting(task.fields.name) + '\n';
 		if ( !msg.showEmbed() ) {
 			msg.sendChannel( spoiler + status + '<' + link + '>' + spoiler );
 			
 			if ( reaction ) reaction.removeEmoji();
 			return;
 		}
-		var summary = task.fields.name.escapeFormatting();
+		var summary = escapeFormatting(task.fields.name);
 		if ( summary.length > 250 ) summary = summary.substring(0, 250) + '\u2026';
-		var embed = new MessageEmbed().setAuthor( 'Phabricator' ).setTitle( summary ).setURL( link ).addField( 'Status', task.fields.status.name, true ).addField( 'Priority', task.fields.priority.name, true );
-		if ( task.fields.subtype !== 'default' ) embed.addField( 'Subtype', task.fields.subtype, true );;
+		var embed = new MessageEmbed().setAuthor( 'Phabricator' ).setTitle( summary ).setURL( link ).addField( 'Status', escapeFormatting(task.fields.status.name), true ).addField( 'Priority', escapeFormatting(task.fields.priority.name), true );
+		if ( task.fields.subtype !== 'default' ) embed.addField( 'Subtype', escapeFormatting(task.fields.subtype), true );
 		var description = parse_text( task.fields.description.raw, site );
 		if ( description.length > 2000 ) description = limitLength(description, 2000, 40);
 		embed.setDescription( description );
@@ -61,7 +61,7 @@ function phabricator_task(lang, msg, wiki, link, reaction, spoiler = '') {
 				}
 				var projects = Object.values(pbody.result);
 				var tags = projects.map( project => {
-					return '[' + project.fullName + '](' + project.uri + ')';
+					return '[' + escapeFormatting(project.fullName) + '](' + project.uri + ')';
 				} ).join(',\n');
 				if ( tags.length > 1000 ) tags = projects.map( project => project.fullName ).join(',\n');
 				if ( tags.length > 1000 ) tags = tags.substring(0, 1000) + '\u2026';

+ 10 - 10
functions/special_page.js

@@ -1,7 +1,7 @@
 const {Util} = require('discord.js');
 const logging = require('../util/logging.js');
 const {timeoptions} = require('../util/default.json');
-const {toMarkdown} = require('../util/functions.js');
+const {toMarkdown, escapeFormatting} = require('../util/functions.js');
 
 const overwrites = {
 	randompage: (fn, lang, msg, wiki, reaction, spoiler) => {
@@ -17,19 +17,19 @@ const overwrites = {
 
 const queryfunctions = {
 	title: (query, wiki) => query.querypage.results.map( result => {
-		return '[' + result.title.escapeFormatting() + '](' + wiki.toLink(result.title, '', '', true) + ')';
+		return '[' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, '', '', true) + ')';
 	} ).join('\n'),
 	times: (query, wiki, lang) => query.querypage.results.map( result => {
-		return parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + '× [' + result.title.escapeFormatting() + '](' + wiki.toLink(result.title, '', '', true) + ')';
+		return parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + '× [' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, '', '', true) + ')';
 	} ).join('\n'),
 	size: (query, wiki, lang) => query.querypage.results.map( result => {
-		return lang.get('diff.info.bytes', parseInt(result.value, 10).toLocaleString(lang.get('dateformat')), result.value) + ': [' + result.title.escapeFormatting() + '](' + wiki.toLink(result.title, '', '', true) + ')';
+		return lang.get('diff.info.bytes', parseInt(result.value, 10).toLocaleString(lang.get('dateformat')), result.value) + ': [' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, '', '', true) + ')';
 	} ).join('\n'),
 	redirect: (query, wiki) => query.querypage.results.map( result => {
-		return '[' + result.title.replace( / /g, '_' ).escapeFormatting() + '](' + wiki.toLink(result.title, 'redirect=no', '', true) + ')' + ( result.databaseResult && result.databaseResult.rd_title ? ' → ' + result.databaseResult.rd_title.escapeFormatting() : '' );
+		return '[' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, 'redirect=no', '', true) + ')' + ( result.databaseResult && result.databaseResult.rd_title ? ' → ' + escapeFormatting(result.databaseResult.rd_title) : '' );
 	} ).join('\n'),
 	doubleredirect: (query, wiki) => query.querypage.results.map( result => {
-		return '[' + result.title.replace( / /g, '_' ).escapeFormatting() + '](' + wiki.toLink(result.title, 'redirect=no', '', true) + ')' + ( result.databaseResult && result.databaseResult.b_title && result.databaseResult.c_title ? ' → ' + result.databaseResult.b_title.escapeFormatting() + ' → ' + result.databaseResult.c_title.escapeFormatting() : '' );
+		return '[' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, 'redirect=no', '', true) + ')' + ( result.databaseResult && result.databaseResult.b_title && result.databaseResult.c_title ? ' → ' + escapeFormatting(result.databaseResult.b_title) + ' → ' + escapeFormatting(result.databaseResult.c_title) : '' );
 	} ).join('\n'),
 	timestamp: (query, wiki, lang) => query.querypage.results.map( result => {
 		try {
@@ -42,21 +42,21 @@ const queryfunctions = {
 				timeZone: 'UTC'
 			}, timeoptions));
 		}
-		return dateformat.format(new Date(result.timestamp)).escapeFormatting() + ': [' + result.title.escapeFormatting() + '](' + wiki.toLink(result.title, '', '', true) + ')';
+		return dateformat.format(new Date(result.timestamp)) + ': [' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, '', '', true) + ')';
 	} ).join('\n'),
 	media: (query, wiki, lang) => query.querypage.results.map( result => {
 		var ms = result.title.split(';');
 		return '**' + ms[1] + '**: ' + lang.get('search.category.files', parseInt(ms[2], 10).toLocaleString(lang.get('dateformat')), parseInt(ms[2], 10)) + ' (' + lang.get('diff.info.bytes', parseInt(ms[3], 10).toLocaleString(lang.get('dateformat')), parseInt(ms[3], 10)) + ')';
 	} ).join('\n'),
 	category: (query, wiki, lang) => query.querypage.results.map( result => {
-		return parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + '× [' + result.title.escapeFormatting() + '](' + wiki.toLink('Category:' + result.title, '', '', true) + ')';
+		return parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + '× [' + escapeFormatting(result.title) + '](' + wiki.toLink('Category:' + result.title, '', '', true) + ')';
 	} ).join('\n'),
 	gadget: (query, wiki, lang) => query.querypage.results.map( result => {
 		result.title = result.title.replace( /^(?:.*:)?gadget-/, '' );
-		return '**' + result.title.escapeFormatting() + '**: ' + parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + ' users (' + result.ns.toLocaleString(lang.get('dateformat')) + ' active)';
+		return '**' + escapeFormatting(result.title) + '**: ' + parseInt(result.value, 10).toLocaleString(lang.get('dateformat')) + ' users (' + result.ns.toLocaleString(lang.get('dateformat')) + ' active)';
 	} ).join('\n'),
 	recentchanges: (query, wiki) => query.recentchanges.map( result => {
-		return '[' + result.title.escapeFormatting() + '](' + wiki.toLink(result.title, ( result.type === 'edit' ? {diff:result.revid,oldid:result.old_revid} : '' ), '', true) + ')';
+		return '[' + escapeFormatting(result.title) + '](' + wiki.toLink(result.title, ( result.type === 'edit' ? {diff:result.revid,oldid:result.old_revid} : '' ), '', true) + ')';
 	} ).join('\n')
 }
 

+ 33 - 32
functions/verify.js

@@ -1,6 +1,7 @@
 const cheerio = require('cheerio');
 const {MessageEmbed} = require('discord.js');
 const logging = require('../util/logging.js');
+const {escapeFormatting} = require('../util/functions.js');
 const toTitle = require('../util/wiki.js').toTitle;
 
 /**
@@ -30,8 +31,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			}
 			else if ( body?.error?.code === 'us400' ) { // special catch for Fandom
 				if ( !old_username ) logging(wiki, channel.guild.id, 'verification');
-				embed.setTitle( ( old_username || username ).escapeFormatting() ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', ( old_username || username ).escapeFormatting()) );
-				result.content = lang.get('verify.user_missing_reply', ( old_username || username ).escapeFormatting());
+				embed.setTitle( escapeFormatting( old_username || username ) ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', escapeFormatting( old_username || username )) );
+				result.content = lang.get('verify.user_missing_reply', escapeFormatting( old_username || username ));
 			}
 			else {
 				console.log( '- ' + response.statusCode + ': Error while getting the user: ' + ( body && body.error && body.error.info ) );
@@ -46,28 +47,28 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 		embed.setAuthor( body.query.general.sitename );
 		if ( body.query.users.length !== 1 || queryuser.missing !== undefined || queryuser.invalid !== undefined ) {
 			username = ( body.query.users.length === 1 ? queryuser.name : username );
-			embed.setTitle( ( old_username || username ).escapeFormatting() ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', ( old_username || username ).escapeFormatting()) );
+			embed.setTitle( escapeFormatting( old_username || username ) ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', escapeFormatting( old_username || username )) );
 			if ( wiki.isFandom() && !old_username ) return got.get( wiki + 'api/v1/User/UsersByName?limit=1&query=' + encodeURIComponent( username ) + '&format=json' ).then( wsresponse => {
 				var wsbody = wsresponse.body;
 				if ( wsresponse.statusCode !== 200 || wsbody?.exception || wsbody?.users?.[0]?.name?.length !== username.length ) {
 					if ( !wsbody?.users ) console.log( '- ' + wsresponse.statusCode + ': Error while searching the user: ' + wsbody?.exception?.details );
-					result.content = lang.get('verify.user_missing_reply', username.escapeFormatting());
+					result.content = lang.get('verify.user_missing_reply', escapeFormatting(username));
 					return;
 				}
 				return verify(lang, channel, member, wsbody.users[0].name.split(' '), wiki, rows, username);
 			}, error => {
 				console.log( '- Error while searching the user: ' + error );
-				result.content = lang.get('verify.user_missing_reply', username.escapeFormatting());
+				result.content = lang.get('verify.user_missing_reply', escapeFormatting(username));
 			} );
-			result.content = lang.get('verify.user_missing_reply', ( old_username || username ).escapeFormatting());
+			result.content = lang.get('verify.user_missing_reply', escapeFormatting( old_username || username ));
 			return;
 		}
 		username = queryuser.name;
 		var pagelink = wiki.toLink('User:' + username, '', '', true);
-		embed.setTitle( username.escapeFormatting() ).setURL( pagelink );
+		embed.setTitle( escapeFormatting(username) ).setURL( pagelink );
 		if ( queryuser.blockexpiry ) {
-			embed.setColor('#FF0000').setDescription( lang.get('verify.user_blocked', '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
-			result.content = lang.get('verify.user_blocked_reply', username.escapeFormatting(), queryuser.gender);
+			embed.setColor('#FF0000').setDescription( lang.get('verify.user_blocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
+			result.content = lang.get('verify.user_blocked_reply', escapeFormatting(username), queryuser.gender);
 			return;
 		}
 		
@@ -83,14 +84,14 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				let $ = cheerio.load(gbresponse.body);
 				if ( $('#mw-content-text .errorbox').length ) {
 					return Promise.reject({
-						desc: lang.get('verify.user_disabled', '[' + username.escapeFormatting() + '](' + pagelink + ')'),
-						reply: lang.get('verify.user_disabled_reply', username.escapeFormatting())
+						desc: lang.get('verify.user_disabled', '[' + escapeFormatting(username) + '](' + pagelink + ')'),
+						reply: lang.get('verify.user_disabled_reply', escapeFormatting(username))
 					});
 				}
 				else if ( $('#mw-content-text .userprofile.mw-warning-with-logexcerpt').length ) {
 					return Promise.reject({
-						desc: lang.get('verify.user_gblocked', '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender),
-						reply: lang.get('verify.user_gblocked_reply', username.escapeFormatting(), queryuser.gender)
+						desc: lang.get('verify.user_gblocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender),
+						reply: lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender)
 					});
 				}
 			}
@@ -107,7 +108,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				}
 				queryuser.editcount = ucbody.userData.localEdits;
 				queryuser.postcount = ucbody.userData.posts;
-				if ( ucbody.userData.discordHandle ) discordname = ucbody.userData.discordHandle.escapeFormatting().replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
+				if ( ucbody.userData.discordHandle ) discordname = escapeFormatting(ucbody.userData.discordHandle).replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 				
 				if ( wiki.isGamepedia() ) return got.get( wiki + 'api.php?action=profile&do=getPublicProfile&user_name=' + encodeURIComponent( username ) + '&format=json&cache=' + Date.now() ).then( presponse => {
 					var pbody = presponse.body;
@@ -115,7 +116,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 						console.log( '- ' + presponse.statusCode + ': Error while getting the Discord tag: ' + ( pbody?.error?.info || pbody?.errormsg ) );
 						return Promise.reject();
 					}
-					if ( pbody.profile['link-discord'] ) discordname = pbody.profile['link-discord'].escapeFormatting().replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
+					if ( pbody.profile['link-discord'] ) discordname = escapeFormatting(pbody.profile['link-discord']).replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 				}, error => {
 					console.log( '- Error while getting the Discord tag: ' + error );
 					return Promise.reject();
@@ -125,15 +126,15 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				return Promise.reject();
 			} ).then( () => {
 				if ( discordname.length > 100 ) discordname = discordname.substring(0, 100) + '\u2026';
-				var authortag = member.user.tag.escapeFormatting();
+				var authortag = escapeFormatting(member.user.tag);
 				embed.addField( lang.get('verify.discord', ( authortag === discordname ? queryuser.gender : 'unknown' )), authortag, true ).addField( lang.get('verify.wiki', queryuser.gender), ( discordname || lang.get('verify.empty') ), true );
 				if ( authortag !== discordname ) {
-					embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
+					embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 					var help_link = '';
 					if ( wiki.isGamepedia() ) help_link = lang.get('verify.help_gamepedia') + '?c=' + ( patreons[channel.guild.id] && patreons[channel.guild.id] !== process.env.prefix ? encodeURIComponent( patreons[channel.guild.id] + ' verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + toTitle(username) + '&discord=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator;
 					else if ( wiki.isFandom() ) help_link = lang.get('verify.help_fandom') + '/' + toTitle(username) + '?c=' + ( patreons[channel.guild.id] && patreons[channel.guild.id] !== process.env.prefix ? encodeURIComponent( patreons[channel.guild.id] + ' verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator + '&useskin=oasis';
 					if ( help_link.length ) embed.addField( lang.get('verify.notice'), lang.get('verify.help_guide', help_link, queryuser.gender) + '\n' + help_link );
-					result.content = lang.get('verify.user_failed_reply', username.escapeFormatting(), queryuser.gender);
+					result.content = lang.get('verify.user_failed_reply', escapeFormatting(username), queryuser.gender);
 					return;
 				}
 				
@@ -164,8 +165,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					}
 				} );
 				if ( verified ) {
-					embed.setColor('#00FF00').setDescription( lang.get('verify.user_verified', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) + ( rename ? '\n' + lang.get('verify.user_renamed', queryuser.gender) : '' ) );
-					var text = lang.get('verify.user_verified_reply', username.escapeFormatting(), queryuser.gender);
+					embed.setColor('#00FF00').setDescription( lang.get('verify.user_verified', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) + ( rename ? '\n' + lang.get('verify.user_renamed', queryuser.gender) : '' ) );
+					var text = lang.get('verify.user_verified_reply', escapeFormatting(username), queryuser.gender);
 					var verify_promise = [
 						member.roles.add( roles, lang.get('verify.audit_reason', username) ).catch( error => {
 							log_error(error);
@@ -195,8 +196,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					} );
 				}
 				
-				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
-				result.content = lang.get('verify.user_matches_reply', username.escapeFormatting(), queryuser.gender);
+				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
+				result.content = lang.get('verify.user_matches_reply', escapeFormatting(username), queryuser.gender);
 			}, error => {
 				if ( error ) console.log( '- Error while getting the Discord tag: ' + error );
 				embed.setColor('#000000').setDescription( lang.get('verify.error') );
@@ -218,8 +219,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			}
 			if ( wiki.hasCentralAuth() ) {
 				if ( mwbody.query.globaluserinfo.locked !== undefined ) {
-					embed.setColor('#FF0000').setDescription( lang.get('verify.user_gblocked', '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
-					result.content = lang.get('verify.user_gblocked_reply', username.escapeFormatting(), queryuser.gender);
+					embed.setColor('#FF0000').setDescription( lang.get('verify.user_gblocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
+					result.content = lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender);
 					return;
 				}
 				queryuser.groups.push(...mwbody.query.globaluserinfo.groups);
@@ -228,15 +229,15 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			
 			var discordname = '';
 			if ( revision && revision.user === username ) {
-				discordname = ( revision?.slots?.main || revision )['*'].escapeFormatting().replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
+				discordname = escapeFormatting(( revision?.slots?.main || revision )['*']).replace( /^\s*([^@#:]{2,32}?)\s*#(\d{4,6})\s*$/u, '$1#$2' );
 			}
 			if ( discordname.length > 100 ) discordname = discordname.substring(0, 100) + '\u2026';
-			var authortag = member.user.tag.escapeFormatting();
+			var authortag = escapeFormatting(member.user.tag);
 			embed.addField( lang.get('verify.discord', ( authortag === discordname ? queryuser.gender : 'unknown' )), authortag, true ).addField( lang.get('verify.wiki', queryuser.gender), ( discordname || lang.get('verify.empty') ), true );
 			if ( authortag !== discordname ) {
-				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
+				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 				embed.addField( lang.get('verify.notice'), lang.get('verify.help_subpage', '**`' + member.user.tag + '`**', queryuser.gender) + '\n' + wiki.toLink('Special:MyPage/Discord', 'action=edit') );
-				result.content = lang.get('verify.user_failed_reply', username.escapeFormatting(), queryuser.gender);
+				result.content = lang.get('verify.user_failed_reply', escapeFormatting(username), queryuser.gender);
 				return;
 			}
 			
@@ -263,8 +264,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				}
 			} );
 			if ( verified ) {
-				embed.setColor('#00FF00').setDescription( lang.get('verify.user_verified', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) + ( rename ? '\n' + lang.get('verify.user_renamed', queryuser.gender) : '' ) );
-				var text = lang.get('verify.user_verified_reply', username.escapeFormatting(), queryuser.gender);
+				embed.setColor('#00FF00').setDescription( lang.get('verify.user_verified', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) + ( rename ? '\n' + lang.get('verify.user_renamed', queryuser.gender) : '' ) );
+				var text = lang.get('verify.user_verified_reply', escapeFormatting(username), queryuser.gender);
 				var verify_promise = [
 					member.roles.add( roles, lang.get('verify.audit_reason', username) ).catch( error => {
 						log_error(error);
@@ -294,8 +295,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				} );
 			}
 			
-			embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + username.escapeFormatting() + '](' + pagelink + ')', queryuser.gender) );
-			result.content = lang.get('verify.user_matches_reply', username.escapeFormatting(), queryuser.gender);
+			embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
+			result.content = lang.get('verify.user_matches_reply', escapeFormatting(username), queryuser.gender);
 		}, error => {
 			console.log( '- Error while getting the Discord tag: ' + error );
 			embed.setColor('#000000').setDescription( lang.get('verify.error') );

+ 5 - 3
util/extract_desc.js

@@ -1,3 +1,5 @@
+const {escapeFormatting} = require('./functions.js');
+
 /**
  * Get the description for a page.
  * @param {String} [text] - The full page extract.
@@ -6,7 +8,7 @@
  */
 function extract_desc(text = '', fragment = '') {
 	var sectionIndex = text.indexOf('\ufffd\ufffd');
-	var extract = ( sectionIndex !== -1 ? text.substring(0, sectionIndex) : text ).trim().escapeFormatting();
+	var extract = escapeFormatting(( sectionIndex !== -1 ? text.substring(0, sectionIndex) : text ).trim());
 	if ( extract.length > 1000 ) extract = extract.substring(0, 1000) + '\u2026';
 	var section = null;
 	var regex = /\ufffd{2}(\d)\ufffd{2}([^\n]+)/g;
@@ -14,7 +16,7 @@ function extract_desc(text = '', fragment = '') {
 	var sectionText = '';
 	while ( fragment && ( section = regex.exec(text) ) !== null ) {
 		if ( section[2].replace( / /g, '_' ) !== fragment.replace( / /g, '_' ) ) continue;
-		sectionHeader = section[2].escapeFormatting();
+		sectionHeader = escapeFormatting(section[2]);
 		if ( sectionHeader.length > 240 ) sectionHeader = sectionHeader.substring(0, 240) + '\u2026';
 		sectionHeader = section_formatting(sectionHeader, section[1]);
 		sectionText = text.substring(regex.lastIndex);
@@ -38,7 +40,7 @@ function extract_desc(text = '', fragment = '') {
 				sectionIndex = sectionText.indexOf('\ufffd\ufffd1\ufffd\ufffd');
 				if ( sectionIndex !== -1 ) sectionText = sectionText.substring(0, sectionIndex);
 		}
-		sectionText = sectionText.trim().escapeFormatting().replace( /\ufffd{2}(\d)\ufffd{2}([^\n]+)/g, (match, n, sectionTitle) => {
+		sectionText = escapeFormatting(sectionText.trim()).replace( /\ufffd{2}(\d)\ufffd{2}([^\n]+)/g, (match, n, sectionTitle) => {
 			return section_formatting(sectionTitle, n);
 		} );
 		if ( sectionText.length > 1000 ) sectionText = sectionText.substring(0, 1000) + '\u2026';

+ 4 - 4
util/functions.js

@@ -32,7 +32,7 @@ function parse_infobox(infobox, embed, thumbnail, pagelink = '') {
 		case 'data':
 			var {label = '', value = '', source = '', 'item-name': name = ''} = infobox.data;
 			label = htmlToPlain(label).trim();
-			value = htmlToDiscord(value, pagelink, true).trim();
+			value = htmlToDiscord(value, pagelink).trim();
 			if ( label.includes( '*UNKNOWN LINK*' ) ) {
 				if ( !( source || name ) ) break;
 				label = '`' + ( source || name )  + '`';
@@ -130,7 +130,7 @@ function toMarkdown(text = '', wiki, title = '', fullWikitext = false) {
 		while ( ( link = regex.exec(text) ) !== null ) {
 			text = text.replaceSave( link[0], '[' + link[2] + '](https://' + link[1] + ')' );
 		}
-		return htmlToDiscord( text, '', true, true ).replaceSave( /'''/g, '**' ).replaceSave( /''/g, '*' );
+		return htmlToDiscord(text, '', true, true).replaceSave( /'''/g, '**' ).replaceSave( /''/g, '*' );
 	}
 	return escapeFormatting(text, true);
 };
@@ -372,8 +372,8 @@ function htmlToDiscord(html, pagelink = '', ...escapeArgs) {
  * @returns {String}
  */
 function escapeFormatting(text = '', isMarkdown = false, keepLinks = false) {
-	if ( !isMarkdown ) text = text.replace( /[()\\]/g, '\\$&' );
-	if ( !keepLinks ) text = text.replace( /\/\//g, '\\$&' );
+	if ( !isMarkdown ) text = text.replace( /\\/g, '\\\\' ).replace( /\]\(/g, ']\\(' );
+	if ( !keepLinks ) text = text.replace( /\/\//g, '/\\/' );
 	return text.replace( /[`_*~:<>{}@|]/g, '\\$&' );
 };