Ver Fonte

Add support for Miraheze pseudo-interwiki

Markus-Rost há 4 anos atrás
pai
commit
7b22502e86

+ 8 - 8
cmds/get.js

@@ -15,13 +15,13 @@ async function cmd_get(lang, msg, args, line, wiki) {
 	var id = args.join().replace( /^\\?<(?:@!?|#)(\d+)>$/, '$1' );
 	if ( /^\d+$/.test(id) ) {
 		var guild = await msg.client.shard.broadcastEval( `if ( this.guilds.cache.has('${id}') ) {
-			var {name, id, memberCount, ownerID, owner, me: {permissions}} = this.guilds.cache.get('${id}');
+			var guild = this.guilds.cache.get('${id}');
 			( {
-				name, id, memberCount, ownerID,
-				owner: owner?.user?.tag,
-				permissions: permissions.missing(${defaultPermissions}),
-				pause: id in global.pause,
-				voice: id in global.voice,
+				name: guild.name, id: guild.id,
+				memberCount: guild.memberCount, ownerID: guild.ownerID,
+				owner: guild.owner?.user?.tag, icon: guild.iconURL({dynamic:true}),
+				permissions: guild.me.permissions.missing(${defaultPermissions}),
+				pause: guild.id in global.pause, voice: guild.id in global.voice,
 				shardId: global.shardId
 			} )
 		}` ).then( results => results.find( result => result !== null ) );
@@ -46,7 +46,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 				else guildsettings[1] = '*default*';
 				
 				if ( msg.showEmbed() ) {
-					var embed = new MessageEmbed().addField( guildname[0], guildname[1] ).addField( guildowner[0], guildowner[1] ).addField( guildsize[0], guildsize[1], true ).addField( guildshard[0], guildshard[1], true ).addField( guildpermissions[0], guildpermissions[1] );
+					var embed = new MessageEmbed().setThumbnail( guild.icon ).addField( guildname[0], guildname[1] ).addField( guildowner[0], guildowner[1] ).addField( guildsize[0], guildsize[1], true ).addField( guildshard[0], guildshard[1], true ).addField( guildpermissions[0], guildpermissions[1] );
 					var split = Util.splitMessage( guildsettings[1], {char:',\n',maxLength:1000,prepend:'```json\n',append:',\n```'} );
 					if ( split.length > 5 ) {
 						msg.sendChannel( '', {embed}, true );
@@ -127,7 +127,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 			if ( guildlist[1].length > 1000 ) guildlist[1] = guilds.length;
 			if ( msg.showEmbed() ) {
 				var text = '';
-				var embed = new MessageEmbed().addField( username[0], username[1] ).addField( guildlist[0], guildlist[1] );
+				var embed = new MessageEmbed().setThumbnail( user.displayAvatarURL({dynamic:true}) ).addField( username[0], username[1] ).addField( guildlist[0], guildlist[1] );
 			}
 			else {
 				var embed = {};

+ 2 - 2
cmds/test.js

@@ -34,7 +34,7 @@ function cmd_test(lang, msg, args, line, wiki) {
 		msg.replyMsg( text ).then( message => {
 			if ( !message ) return;
 			var then = Date.now();
-			var embed = new MessageEmbed().setTitle( lang.get('test.time') ).addField( 'Discord', ( then - now ) + 'ms' );
+			var embed = new MessageEmbed().setTitle( lang.get('test.time') ).setFooter( 'Shard: ' + global.shardId ).addField( 'Discord', ( then - now ) + 'ms' );
 			now = Date.now();
 			got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general|extensions&format=json' ).then( response => {
 				then = Date.now();
@@ -44,7 +44,7 @@ function cmd_test(lang, msg, args, line, wiki) {
 				var ping = ( then - now ) + 'ms';
 				var notice = [];
 				if ( response.statusCode !== 200 || !body?.query?.general || !body?.query?.extensions ) {
-					if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+					if ( wiki.noWiki(response.url, response.statusCode) ) {
 						console.log( '- This wiki doesn\'t exist!' );
 						ping += ' <:unknown_wiki:505887262077353984>';
 					}

+ 1 - 1
cmds/verification.js

@@ -179,7 +179,7 @@ function cmd_verification(lang, msg, args, line, wiki) {
 					var body = response.body;
 					if ( body && body.warnings ) log_warn(body.warnings);
 					if ( response.statusCode !== 200 || !body || !body.query || !body.query.allmessages ) {
-						if ( wiki.noWiki(response.url) || response.statusCode === 410 ) console.log( '- This wiki doesn\'t exist!' );
+						if ( wiki.noWiki(response.url, response.statusCode) ) console.log( '- This wiki doesn\'t exist!' );
 						else console.log( '- ' + response.statusCode + ': Error while getting the usergroups: ' + ( body && body.error && body.error.info ) );
 					}
 					var groups = body.query.allmessages.filter( group => !['group-all','group-membership-link-with-expiry'].includes( group.name ) && !/\.(?:css|js)$/.test(group.name) ).map( group => {

+ 1 - 1
cmds/verify.js

@@ -47,7 +47,7 @@ function cmd_verify(lang, msg, args, line, wiki, old_username = '') {
 			var body = response.body;
 			if ( body && body.warnings ) log_warn(body.warnings);
 			if ( response.statusCode !== 200 || !body || !body.query || !body.query.users ) {
-				if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+				if ( wiki.noWiki(response.url, response.statusCode) ) {
 					console.log( '- This wiki doesn\'t exist!' );
 					msg.reactEmoji('nowiki');
 				}

+ 2 - 2
cmds/wiki/diff.js

@@ -75,7 +75,7 @@ function gamepedia_diff(lang, msg, args, wiki, reaction, spoiler, embed) {
 								noerror = false;
 						}
 					}
-					if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+					if ( wiki.noWiki(response.url, response.statusCode) ) {
 						console.log( '- This wiki doesn\'t exist!' );
 						msg.reactEmoji('nowiki');
 					}
@@ -150,7 +150,7 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, compare)
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 2 - 2
cmds/wiki/fandom/diff.js

@@ -56,7 +56,7 @@ function fandom_diff(lang, msg, args, wiki, reaction, spoiler, embed) {
 				var body = response.body;
 				if ( body && body.warnings ) log_warn(body.warnings);
 				if ( response.statusCode !== 200 || !body || !body.query ) {
-					if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+					if ( wiki.noWiki(response.url, response.statusCode) ) {
 						console.log( '- This wiki doesn\'t exist!' );
 						msg.reactEmoji('nowiki');
 					}
@@ -137,7 +137,7 @@ function fandom_diff_send(lang, msg, args, wiki, reaction, spoiler, compare) {
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || !body.query ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 1 - 1
cmds/wiki/fandom/general.js

@@ -74,7 +74,7 @@ function fandom_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '',
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || !body.query ) {
 			if ( interwiki ) msg.sendChannel( spoiler + ' ' + interwiki + ' ' + spoiler );
-			else if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			else if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 1 - 1
cmds/wiki/fandom/overview.js

@@ -19,7 +19,7 @@ function fandom_overview(lang, msg, wiki, reaction, spoiler) {
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || !body.query || !body.query.pages ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 1 - 1
cmds/wiki/fandom/random.js

@@ -14,7 +14,7 @@ function fandom_random(lang, msg, wiki, reaction, spoiler) {
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || !body.query || !body.query.pages ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 15 - 1
cmds/wiki/general.js

@@ -93,7 +93,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				return this.fandom(lang, msg, title, wiki, cmd, reaction, spoiler, querystring, fragment, selfcall);
 			}
 			else if ( interwiki ) msg.sendChannel( spoiler + ' ' + interwiki + ' ' + spoiler );
-			else if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			else if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}
@@ -166,6 +166,20 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 					if ( reaction ) reaction.removeEmoji();
 				} );
 			}
+			else if ( wiki.isMiraheze() && querypage.ns === 0 && /^Mh:[a-z\d]+:/.test(querypage.title) ) {
+				var iw_parts = querypage.title.split(':');
+				var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
+				var iw_link = iw.toLink(iw_parts.slice(2).join(':'), querystring, fragment);
+				var maxselfcall = interwikiLimit[( msg?.guild?.id in patreons ? 'patreon' : 'default' )];
+				if ( selfcall < maxselfcall ) {
+					selfcall++;
+					return this.general(lang, msg, iw_parts.slice(2).join(':'), iw, '!!' + iw.hostname + ' ', reaction, spoiler, querystring, fragment, iw_link, selfcall);
+				}
+				msg.sendChannel( spoiler + ' ' + iw_link + ' ' + spoiler ).then( message => {
+					if ( message && selfcall === maxselfcall ) message.reactEmoji('⚠️');
+				} );
+				if ( reaction ) reaction.removeEmoji();
+			}
 			else if ( ( querypage.missing !== undefined && querypage.known === undefined && !( noRedirect || querypage.categoryinfo ) ) || querypage.invalid !== undefined ) {
 				got.get( wiki + 'api.php?action=query&prop=pageimages|categoryinfo|pageprops|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free&explaintext=true&exsectionformat=raw&exlimit=1&generator=search&gsrnamespace=4|12|14|' + Object.values(body.query.namespaces).filter( ns => ns.content !== undefined ).map( ns => ns.id ).join('|') + '&gsrlimit=1&gsrsearch=' + encodeURIComponent( title ) + '&format=json' ).then( srresponse => {
 					var srbody = srresponse.body;

+ 15 - 12
cmds/wiki/overview.js

@@ -16,11 +16,11 @@ getAllSites.then( sites => allSites = sites );
  */
 function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 	if ( !allSites.length ) getAllSites.update();
-	got.get( wiki + 'api.php?action=query&meta=allmessages|siteinfo&ammessages=custom-Wiki_Manager|custom-GamepediaNotice|custom-FandomMergeNotice&amenableparser=true&siprop=general|statistics&titles=Special:Statistics&format=json' ).then( response => {
+	got.get( wiki + 'api.php?action=query&meta=allmessages|siteinfo&ammessages=custom-Wiki_Manager|custom-GamepediaNotice|custom-FandomMergeNotice&amenableparser=true&siprop=general|statistics|languages&siinlanguagecode=' + lang.lang + ( wiki.isMiraheze() ? '' : '' ) + '&titles=Special:Statistics&format=json' ).then( response => {
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query || !body.query.pages ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}
@@ -54,6 +54,9 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				}
 				if ( image[1] && image[1].startsWith( '/' ) ) image[1] = new URL(image[1], wiki).href;
 			}
+			var language = [lang.get('overview.lang'), body.query.languages.find( language => {
+				return language.code === body.query.general.lang;
+			} )['*']];
 			var articles = [lang.get('overview.articles'), body.query.statistics.articles];
 			var pages = [lang.get('overview.pages'), body.query.statistics.pages];
 			var edits = [lang.get('overview.edits'), body.query.statistics.edits];
@@ -85,8 +88,8 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				if ( ovresponse.statusCode !== 200 || !ovbody || ovbody.exception || !ovbody.items || !ovbody.items.length ) {
 					console.log( '- ' + ovresponse.statusCode + ': Error while getting the wiki details: ' + ( ovbody && ovbody.exception && ovbody.exception.details ) );
 
-					if ( msg.showEmbed() ) embed.addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setTimestamp( msg.client.readyTimestamp ).setFooter( lang.get('overview.inaccurate') );
-					else text = articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
+					if ( msg.showEmbed() ) embed.addField( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setFooter( lang.get('overview.inaccurate') );
+					else text = language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
 	
 					msg.sendChannelError( spoiler + text + spoiler, {embed} );
 					
@@ -156,7 +159,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 						if ( msg.showEmbed() ) {
 							embed.addField( founder[0], founder[1], true );
 							if ( manager[1] ) embed.addField( manager[0], '[' + manager[1] + '](' + wiki.toLink('User:' + manager[1], '', '', true) + ') ([' + lang.get('overview.talk') + '](' + wiki.toLink('User talk:' + manager[1], '', '', true) + '))', true );
-							embed.addField( created[0], created[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true );
+							embed.addField( created[0], created[1], true ).addField( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true );
 							if ( posts[1] ) embed.addField( posts[0], posts[1], true );
 							if ( walls[1] ) embed.addField( walls[0], walls[1], true );
 							if ( comments[1] ) embed.addField( comments[0], comments[1], true );
@@ -170,7 +173,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 							if ( image[1] ) embed.addField( image[0], image[1] ).setImage( image[1] );
 						}
 						else {
-							text += '\n' + founder.join(' ') + ( manager[1] ? '\n' + manager.join(' ') : '' ) + '\n' + created.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ');
+							text += '\n' + founder.join(' ') + ( manager[1] ? '\n' + manager.join(' ') : '' ) + '\n' + created.join(' ') + '\n' + language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ');
 							if ( posts[1] ) text += '\n' + posts.join(' ');
 							if ( walls[1] ) text += '\n' + walls.join(' ');
 							if ( comments[1] ) text += '\n' + comments.join(' ');
@@ -192,7 +195,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				else {
 					if ( msg.showEmbed() ) {
 						if ( manager[1] ) embed.addField( manager[0], '[' + manager[1] + '](' + wiki.toLink('User:' + manager[1], '', '', true) + ') ([' + lang.get('overview.talk') + '](' + wiki.toLink('User talk:' + manager[1], '', '', true) + '))', true );
-						embed.addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setTimestamp( msg.client.readyTimestamp ).setFooter( lang.get('overview.inaccurate') );
+						embed.addField( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setFooter( lang.get('overview.inaccurate') );
 						if ( crossover[1] ) {
 							var crossoverSite = allSites.find( site => '<https://' + site.wiki_domain + '/>' === crossover[1] );
 							if ( crossoverSite ) embed.addField( crossover[0], '[' + crossoverSite.wiki_display_name + '](' + crossover[1] + ')', true );
@@ -200,7 +203,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 						}
 					}
 					else {
-						text = ( manager[1] ? manager.join(' ') + '\n' : '' ) + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
+						text = ( manager[1] ? manager.join(' ') + '\n' : '' ) + language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
 						if ( crossover[1] ) text += '\n' + crossover.join(' ');
 					}
 					
@@ -211,8 +214,8 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 			}, error => {
 				console.log( '- Error while getting the wiki details: ' + error );
 
-				if ( msg.showEmbed() ) embed.addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setTimestamp( msg.client.readyTimestamp ).setFooter( lang.get('overview.inaccurate') );
-				else text = articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
+				if ( msg.showEmbed() ) embed.addField( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setFooter( lang.get('overview.inaccurate') );
+				else text = language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ') + '\n\n*' + lang.get('overview.inaccurate') + '*';
 
 				msg.sendChannelError( spoiler + text + spoiler, {embed} );
 				
@@ -224,7 +227,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 						var managerlist = manager[1].map( wm => '[' + wm + '](' + wiki.toLink('User:' + wm, '', '', true) + ') ([' + lang.get('overview.talk') + '](' + wiki.toLink('User talk:' + wm, '', '', true) + '))' ).join('\n');
 						embed.addField( name[0], name[1], true ).addField( created[0], created[1], true ).addField( manager[0], ( managerlist || lang.get('overview.none') ), true ).addField( official[0], official[1], true );
 					}
-					embed.addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setTimestamp( msg.client.readyTimestamp ).setFooter( lang.get('overview.inaccurate') );
+					embed.addField( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true ).addField( users[0], users[1], true ).setTimestamp( msg.client.readyTimestamp ).setFooter( lang.get('overview.inaccurate') );
 					if ( site ) {
 						if ( crossover[1] ) embed.addField( crossover[0], crossover[1], true );
 						if ( description[1] ) embed.addField( description[0], description[1] );
@@ -233,7 +236,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				}
 				else {
 					if ( site ) text += name.join(' ') + '\n' + created.join(' ') + '\n' + manager[0] + ' ' + ( manager[1].join(', ') || lang.get('overview.none') ) + '\n' + official.join(' ') + '\n';
-					text += articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ');
+					text += language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ');
 					if ( site ) {
 						if ( crossover[1] ) text += '\n' + crossover.join(' ');
 						if ( description[1] ) text += '\n' + description.join(' ');

+ 1 - 1
cmds/wiki/random.js

@@ -17,7 +17,7 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler) {
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query || !body.query.pages ) {
-			if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}

+ 1 - 0
i18n/en.json

@@ -405,6 +405,7 @@
         "founder": "Founder:",
         "image": "Image:",
         "inaccurate": "Statistics may be inaccurate",
+        "lang": "Language:",
         "manager": "Wiki manager:",
         "name": "Full name:",
         "no": "No",

+ 14 - 0
main.js

@@ -146,6 +146,20 @@ if ( process.env.dashboard ) {
 						return dashboard.send( {id: message.id, data} );
 					} );
 					break;
+				case 'notifyGuild':
+					return manager.broadcastEval(`if ( this.guilds.cache.has('${message.data.guild}') ) {
+						let channel = this.guilds.cache.get('${message.data.guild}').publicUpdatesChannel;
+						if ( channel ) channel.send('${message.data.text}').catch( error => {
+							console.log( '- ' + error.name + ': ' + error.message );
+						} );
+					}`).then( results => {
+						data.response = results.find( result => result );
+					}, error => {
+						data.error = error;
+					} ).finally( () => {
+						return dashboard.send( {id: message.id, data} );
+					} );
+					break;
 				default:
 					console.log( '- [Dashboard]: Unknown message received!', message.data );
 					data.error = 'Unknown message type: ' + message.data.type;

+ 9 - 2
util/newMessage.js

@@ -153,7 +153,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 		if ( links.length ) got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&iwurl=true&titles=' + encodeURIComponent( links.map( link => link.title ).join('|') ) + '&format=json' ).then( response => {
 			var body = response.body;
 			if ( response.statusCode !== 200 || !body || !body.query ) {
-				if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+				if ( wiki.noWiki(response.url, response.statusCode) ) {
 					console.log( '- This wiki doesn\'t exist!' );
 					msg.reactEmoji('nowiki');
 					return;
@@ -177,6 +177,12 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 				} ) );
 				querypages.filter( page => page.missing !== undefined && page.known === undefined ).forEach( page => links.filter( link => link.title === page.title ).forEach( link => {
 					if ( ( page.ns === 2 || page.ns === 202 ) && !page.title.includes( '/' ) ) return;
+					if ( wiki.isMiraheze() && page.ns === 0 && /^Mh:[a-z\d]+:/.test(page.title) ) {
+						var iw_parts = page.title.split(':');
+						var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
+						link.url = iw.toLink(iw_parts.slice(2).join(':'), '', link.section);
+						return;
+					}
 					link.url = wiki.toLink(link.title, 'action=edit&redlink=1');
 				} ) );
 			}
@@ -194,7 +200,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 		if ( embeds.length ) got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general' + ( wiki.isFandom() ? '' : '|variables' ) + '&titles=' + encodeURIComponent( embeds.map( embed => embed.title + '|Template:' + embed.title ).join('|') ) + '&format=json' ).then( response => {
 			var body = response.body;
 			if ( response.statusCode !== 200 || !body || !body.query ) {
-				if ( wiki.noWiki(response.url) || response.statusCode === 410 ) {
+				if ( wiki.noWiki(response.url, response.statusCode) ) {
 					console.log( '- This wiki doesn\'t exist!' );
 					msg.reactEmoji('nowiki');
 					return;
@@ -214,6 +220,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 				var missing = [];
 				querypages.filter( page => page.missing !== undefined && page.known === undefined ).forEach( page => embeds.filter( embed => embed.title === page.title ).forEach( embed => {
 					if ( ( page.ns === 2 || page.ns === 202 ) && !page.title.includes( '/' ) ) return;
+					if ( wiki.isMiraheze() && page.ns === 0 && /^Mh:[a-z\d]+:/.test(page.title) ) return;
 					embeds.splice(embeds.indexOf(embed), 1);
 					if ( page.ns === 0 && !embed.section ) {
 						var template = querypages.find( template => template.ns === 10 && template.title.split(':').slice(1).join(':') === embed.title );

+ 15 - 2
util/wiki.js

@@ -26,6 +26,7 @@ class Wiki extends URL {
 		this.articlepath = articlepath;
 		this.mainpage = '';
 		this.centralauth = 'local';
+		this.miraheze = this.hostname.endsWith( '.miraheze.org' );
 	}
 
 	/**
@@ -57,15 +58,17 @@ class Wiki extends URL {
 	 * @param {String} siteinfo.articlepath - Articlepath of the wiki.
 	 * @param {String} siteinfo.mainpage - Main page of the wiki.
 	 * @param {String} siteinfo.centralidlookupprovider - Central auth of the wiki.
+	 * @param {String} siteinfo.logo - Logo of the wiki.
 	 * @returns {Wiki}
 	 */
-	updateWiki({server, servername, scriptpath, articlepath, mainpage, centralidlookupprovider}) {
+	updateWiki({server, servername, scriptpath, articlepath, mainpage, centralidlookupprovider, logo}) {
 		if ( servername ) this.hostname = servername;
 		else this.hostname = server.replace( /^(?:https?:)?\/\//, '' );
 		this.pathname = scriptpath + '/';
 		this.articlepath = articlepath;
 		this.mainpage = mainpage;
 		this.centralauth = centralidlookupprovider;
+		this.miraheze = /^(?:https?:)?\/\/static\.miraheze\.org\//.test(logo);
 		return this;
 	}
 
@@ -87,6 +90,14 @@ class Wiki extends URL {
 		return this.hostname.endsWith( '.gamepedia.com' );
 	}
 
+	/**
+	 * Check for a Miraheze wiki.
+	 * @returns {Boolean}
+	 */
+	isMiraheze() {
+		return this.miraheze;
+	}
+
 	/**
 	 * Check for CentralAuth.
 	 * @returns {Boolean}
@@ -98,9 +109,11 @@ class Wiki extends URL {
 	/**
 	 * Check if a wiki is missing.
 	 * @param {String} [message] - Error message or response url.
+	 * @param {Number} [statusCode] - Status code of the response.
 	 * @returns {Boolean}
 	 */
-	noWiki(message = '') {
+	noWiki(message = '', statusCode = 0) {
+		if ( statusCode === 410 || statusCode === 404 ) return true;
 		if ( !this.isFandom() ) return false;
 		if ( this.hostname.startsWith( 'www.' ) || message.startsWith( 'https://www.' ) ) return true;
 		return [