浏览代码

add random and stats query args, add random/ns

Markus-Rost 3 年之前
父节点
当前提交
d60f520908
共有 6 个文件被更改,包括 132 次插入32 次删除
  1. 3 4
      cmds/wiki/general.js
  2. 8 5
      cmds/wiki/overview.js
  3. 62 12
      cmds/wiki/random.js
  4. 35 11
      functions/special_page.js
  5. 1 0
      util/functions.js
  6. 23 0
      util/i18n.js

+ 3 - 4
cmds/wiki/general.js

@@ -84,7 +84,8 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 	}
 	var noRedirect = ( querystring.getAll('redirect').pop() === 'no' || ( querystring.has('action') && querystring.getAll('action').pop() !== 'view' ) );
 	var uselang = ( querystring.get('variant') || querystring.get('uselang') || lang.lang );
-	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=siteinfo&siprop=general|namespaces|specialpagealiases&iwurl=true' + ( noRedirect ? '' : '&redirects=true' ) + '&prop=categoryinfo|info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&converttitles=true&titles=%1F' + encodeURIComponent( ( aliasInvoke === 'search' ? full_title.split(' ').slice(1).join(' ') : title ).replace( /\x1F/g, '\ufffd' ) ) + '&format=json' ).then( response => {
+	if ( querystring.get('variant') || querystring.get('uselang') ) lang = lang.uselang(querystring.get('variant'), querystring.get('uselang'));
+	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|specialpagealiases&iwurl=true' + ( noRedirect ? '' : '&redirects=true' ) + '&prop=categoryinfo|info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&converttitles=true&titles=%1F' + encodeURIComponent( ( aliasInvoke === 'search' ? full_title.split(' ').slice(1).join(' ') : title ).replace( /\x1F/g, '\ufffd' ) ) + '&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 ) {
@@ -312,9 +313,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				var specialpage = body.query.specialpagealiases.find( sp => body.query.namespaces['-1']['*'] + ':' + sp.aliases[0].replace( /\_/g, ' ' ) === querypage.title.split('/')[0] );
 				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( 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);
+					return fn.special_page(lang, msg, querypage, specialpage, body.query, wiki, querystring, fragment, reaction, spoiler);
 				}
 			}
 			if ( querypage.ns === -2 ) {

+ 8 - 5
cmds/wiki/overview.js

@@ -10,9 +10,12 @@ const {toFormatting, toPlaintext, escapeFormatting} = require('../../util/functi
  * @param {import('../../util/wiki.js')} wiki - The wiki for the overview.
  * @param {import('discord.js').MessageReaction} reaction - The reaction on the message.
  * @param {String} spoiler - If the response is in a spoiler.
+ * @param {URLSearchParams} [querystring] - The querystring for the link.
+ * @param {String} [fragment] - The section for the link.
  */
-function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
-	got.get( wiki + 'api.php?uselang=' + lang.lang + '&action=query&meta=allmessages|siteinfo&amenableparser=true&amtitle=Special:Statistics&ammessages=statistics' + ( wiki.isFandom() ? '|custom-GamepediaNotice|custom-FandomMergeNotice' : '' ) + '&siprop=general|statistics|languages|rightsinfo' + ( wiki.isFandom() ? '|variables' : '' ) + '&siinlanguagecode=' + lang.lang + '&list=logevents&ledir=newer&lelimit=1&leprop=timestamp&titles=Special:Statistics&format=json' ).then( response => {
+function gamepedia_overview(lang, msg, wiki, reaction, spoiler, querystring = new URLSearchParams(), fragment = '') {
+	var uselang = ( querystring.get('variant') || querystring.get('uselang') || lang.lang );
+	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=allmessages|siteinfo&amenableparser=true&amtitle=Special:Statistics&ammessages=statistics' + ( wiki.isFandom() ? '|custom-GamepediaNotice|custom-FandomMergeNotice' : '' ) + '&siprop=general|statistics|languages|rightsinfo' + ( wiki.isFandom() ? '|variables' : '' ) + '&siinlanguagecode=' + uselang + '&list=logevents&ledir=newer&lelimit=1&leprop=timestamp&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 ) {
@@ -22,7 +25,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 			}
 			else {
 				console.log( '- ' + response.statusCode + ': Error while getting the statistics: ' + ( body && body.error && body.error.info ) );
-				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Statistics') + '>' + spoiler );
+				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Statistics', querystring, fragment) + '>' + spoiler );
 			}
 			
 			if ( reaction ) reaction.removeEmoji();
@@ -86,7 +89,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 		}
 		
 		var title = body.query.pages['-1'].title;
-		var pagelink = wiki.toLink(title);
+		var pagelink = wiki.toLink(title, querystring, fragment);
 		var text = '<' + pagelink + '>';
 		var embed = null;
 		if ( msg.showEmbed() ) {
@@ -262,7 +265,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 		}
 		else {
 			console.log( '- Error while getting the statistics: ' + error );
-			msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Statistics') + '>' + spoiler );
+			msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Statistics', querystring, fragment) + '>' + spoiler );
 		}
 		
 		if ( reaction ) reaction.removeEmoji();

+ 62 - 12
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, escapeFormatting} = require('../../util/functions.js');
+const {toMarkdown, htmlToDiscord, escapeFormatting} = require('../../util/functions.js');
 const extract_desc = require('../../util/extract_desc.js');
 
 /**
@@ -11,43 +11,76 @@ const extract_desc = require('../../util/extract_desc.js');
  * @param {import('../../util/wiki.js')} wiki - The wiki for the page.
  * @param {import('discord.js').MessageReaction} reaction - The reaction on the message.
  * @param {String} spoiler - If the response is in a spoiler.
+ * @param {String[]} [namespace] - The namespace to get a random page of.
+ * @param {URLSearchParams} [querystring] - The querystring for the link.
+ * @param {String} [fragment] - The section for the link.
  */
-function gamepedia_random(lang, msg, wiki, reaction, spoiler) {
-	got.get( wiki + 'api.php?uselang=' + lang.lang + '&action=query&meta=siteinfo&siprop=general&prop=info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&generator=random&grnnamespace=0&format=json' ).then( response => {
+function gamepedia_random(lang, msg, wiki, reaction, spoiler, namespace = ['0', '*'], querystring = new URLSearchParams(), fragment = '') {
+	var uselang = ( querystring.get('variant') || querystring.get('uselang') || lang.lang );
+	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=allmessages|siteinfo&amenableparser=true&amtitle=Special:Random&ammessages=randompage|randompage-nopages&amargs=%1F' + namespace[1] + '%1F' + namespace[0].split('|').length + '&siprop=general&prop=categoryinfo|info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&converttitles=true&generator=random&grnfilterredir=nonredirects&grnlimit=1&grnnamespace=' + namespace[0] + '&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 ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query || !body.query.general ) {
 			if ( wiki.noWiki(response.url, response.statusCode) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				msg.reactEmoji('nowiki');
 			}
 			else {
 				console.log( '- ' + response.statusCode + ': Error while getting the search results: ' + ( body && body.error && body.error.info ) );
-				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Random') + '>' + spoiler );
+				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Random', querystring, fragment) + '>' + spoiler );
 			}
 			if ( reaction ) reaction.removeEmoji();
 			return;
 		}
 		wiki.updateWiki(body.query.general);
 		logging(wiki, msg.guild?.id, 'random');
+		if ( !body.query.pages ) {
+			var title = 'Special:Random';
+			if ( namespace[0] !== '0' && namespace[0].split('|').length === 1 ) title += '/' + namespace[1];
+			var pagelink = wiki.toLink(title, querystring, fragment);
+			var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(title) ).setURL( pagelink ).setThumbnail( new URL(body.query.general.logo, wiki).href );
+			if ( body.query.allmessages?.[0]?.['*']?.trim?.() ) {
+				let displaytitle = escapeFormatting(body.query.allmessages[0]['*'].trim());
+				if ( displaytitle.length > 250 ) displaytitle = displaytitle.substring(0, 250) + '\u2026';
+				embed.setTitle( displaytitle );
+			}
+			if ( body.query.allmessages?.[1]?.['*']?.trim?.() ) {
+				var description = toMarkdown(body.query.allmessages[1]['*'], wiki, title, true);
+				if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
+				embed.setDescription( description );
+			}
+			msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+			
+			if ( reaction ) reaction.removeEmoji();
+			return;
+		}
 		var querypage = Object.values(body.query.pages)[0];
-		var pagelink = wiki.toLink(querypage.title);
+		var pagelink = wiki.toLink(querypage.title, querystring, fragment);
+		var text = '';
 		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';
 			embed.setTitle( displaytitle );
 		}
+		if ( querypage.extract ) {
+			var extract = extract_desc(querypage.extract, fragment);
+			embed.backupDescription = extract[0];
+			if ( extract[1].length && extract[2].length ) {
+				embed.backupField = {name: extract[1], value: extract[2]};
+			}
+		}
 		if ( querypage.pageprops && querypage.pageprops.description ) {
 			var description = htmlToDiscord( querypage.pageprops.description );
 			if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
 			embed.backupDescription = description;
 		}
-		else if ( querypage.extract ) {
-			var extract = extract_desc(querypage.extract);
-			embed.backupDescription = extract[0];
+		if ( querypage.ns === 6 ) {
+			var pageimage = ( querypage?.original?.source || wiki.toLink('Special:FilePath/' + querypage.title, {version:Date.now()}) );
+			if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
+			else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pageimage,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 		}
-		if ( querypage.title === body.query.general.mainpage ) {
+		else if ( querypage.title === body.query.general.mainpage ) {
 			embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 		}
 		else if ( querypage.pageimage && querypage.original ) {
@@ -57,8 +90,25 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler) {
 			embed.setThumbnail( wiki.toLink('Special:FilePath/' + querypage.pageprops.page_image_free, {version:Date.now()}) );
 		}
 		else embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
+		if ( querypage.categoryinfo ) {
+			var category = [lang.get('search.category.content')];
+			if ( querypage.categoryinfo.size === 0 ) {
+				category.push(lang.get('search.category.empty'));
+			}
+			if ( querypage.categoryinfo.pages > 0 ) {
+				category.push(lang.get('search.category.pages', querypage.categoryinfo.pages.toLocaleString(lang.get('dateformat')), querypage.categoryinfo.pages));
+			}
+			if ( querypage.categoryinfo.files > 0 ) {
+				category.push(lang.get('search.category.files', querypage.categoryinfo.files.toLocaleString(lang.get('dateformat')), querypage.categoryinfo.files));
+			}
+			if ( querypage.categoryinfo.subcats > 0 ) {
+				category.push(lang.get('search.category.subcats', querypage.categoryinfo.subcats.toLocaleString(lang.get('dateformat')), querypage.categoryinfo.subcats));
+			}
+			if ( msg.showEmbed() ) embed.addField( category[0], category.slice(1).join('\n') );
+			else text += '\n\n' + category.join('\n');
+		}
 		
-		parse_page(lang, msg, '🎲 ' + spoiler + '<' + pagelink + '>' + spoiler, embed, wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ));
+		return parse_page(lang, msg, '🎲 ' + spoiler + '<' + pagelink + '>' + text + spoiler, embed, wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), fragment, pagelink);
 	}, error => {
 		if ( wiki.noWiki(error.message) ) {
 			console.log( '- This wiki doesn\'t exist!' );
@@ -66,7 +116,7 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler) {
 		}
 		else {
 			console.log( '- Error while getting the search results: ' + error );
-			msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Random') + '>' + spoiler );
+			msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Random', querystring, fragment) + '>' + spoiler );
 		}
 		if ( reaction ) reaction.removeEmoji();
 	} );

+ 35 - 11
functions/special_page.js

@@ -1,16 +1,36 @@
-const {Util} = require('discord.js');
+const {MessageEmbed, Util} = require('discord.js');
 const logging = require('../util/logging.js');
 const {timeoptions} = require('../util/default.json');
 const {toMarkdown, escapeFormatting} = require('../util/functions.js');
 
 const overwrites = {
-	randompage: (fn, lang, msg, wiki, reaction, spoiler) => {
-		fn.random(lang, msg, wiki, reaction, spoiler);
+	randompage: (fn, lang, msg, wiki, querystring, fragment, reaction, spoiler, args, embed, query) => {
+		let namespaces = Object.values(query.namespaces);
+		let contentNamespaces = namespaces.filter( ns => ns.content !== undefined );
+		let namespaceData = [contentNamespaces.map( ns => ns.id ).join('|'), contentNamespaces.map( ns => ( ns['*'] || '*' )  ).join(', ')];
+		if ( args[0] ) {
+			args[0] = args[0].replace( /_/g, ' ' ).toLowerCase().trim();
+			let namespaceMap = {};
+			namespaces.forEach( namespace => {
+				if ( namespace.id < 0 ) return;
+				if ( namespace.canonical ) namespaceMap[namespace.canonical.toLowerCase()] = namespace.id;
+				namespaceMap[namespace['*'].toLowerCase()] = namespace.id;
+			} );
+			query.namespacealiases.forEach( namespace => {
+				if ( namespace.id < 0 ) return;
+				namespaceMap[namespace['*'].toLowerCase()] = namespace.id;
+			} );
+			if ( namespaceMap.hasOwnProperty(args[0]) ) {
+				namespaceData = [namespaceMap[args[0]].toString(), ( namespaces.find( namespace => namespace.id === namespaceMap[args[0]] )?.['*'] || '*' )];
+			}
+			else if ( args[0] === '*' ) namespaceData = ['*', '*'];
+		}
+		fn.random(lang, msg, wiki, reaction, spoiler, namespaceData, querystring, fragment, embed);
 	},
-	statistics: (fn, lang, msg, wiki, reaction, spoiler) => {
-		fn.overview(lang, msg, wiki, reaction, spoiler);
+	statistics: (fn, lang, msg, wiki, querystring, fragment, reaction, spoiler) => {
+		fn.overview(lang, msg, wiki, reaction, spoiler, querystring, fragment);
 	},
-	diff: (fn, lang, msg, wiki, reaction, spoiler, args, embed) => {
+	diff: (fn, lang, msg, wiki, querystring, fragment, reaction, spoiler, args, embed) => {
 		fn.diff(lang, msg, args, wiki, reaction, spoiler, embed);
 	}
 }
@@ -34,7 +54,7 @@ const queryfunctions = {
 	timestamp: (query, wiki, lang) => query.querypage.results.map( result => {
 		try {
 			var dateformat = new Intl.DateTimeFormat(lang.get('dateformat'), Object.assign({
-				timeZone: body.query.general.timezone
+				timeZone: query.general.timezone
 			}, timeoptions));
 		}
 		catch ( error ) {
@@ -131,15 +151,19 @@ const descriptions = {
  * @param {String} querypage.title - The title of the special page.
  * @param {String} querypage.uselang - The language of the special page.
  * @param {String} specialpage - The canonical name of the special page.
- * @param {import('discord.js').MessageEmbed} embed - The embed for the page.
+ * @param {Object} query - The siteinfo from the wiki.
  * @param {import('../util/wiki.js')} wiki - The wiki for the page.
+ * @param {URLSearchParams} querystring - The querystring for the link.
+ * @param {String} fragment - The section for the link.
  * @param {import('discord.js').MessageReaction} reaction - The reaction on the message.
  * @param {String} spoiler - If the response is in a spoiler.
  */
-function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, embed, wiki, reaction, spoiler) {
+function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, query, wiki, querystring, fragment, reaction, spoiler) {
+	var pagelink = wiki.toLink(title, querystring, fragment);
+	var embed = new MessageEmbed().setAuthor( query.general.sitename ).setTitle( escapeFormatting(title) ).setURL( pagelink ).setThumbnail( new URL(query.general.logo, wiki).href );
 	if ( overwrites.hasOwnProperty(specialpage) ) {
 		var args = title.split('/').slice(1,3);
-		overwrites[specialpage](this, lang, msg, wiki, reaction, spoiler, args, embed);
+		overwrites[specialpage](this, lang, msg, wiki, querystring, fragment, reaction, spoiler, args, embed, query);
 		return;
 	}
 	logging(wiki, msg.guild?.id, 'general', 'special');
@@ -173,7 +197,7 @@ function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, embe
 	}, error => {
 		console.log( '- Error while getting the special page: ' + error );
 	} ).finally( () => {
-		msg.sendChannel( spoiler + '<' + embed.url + '>' + spoiler, {embed} );
+		msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
 		
 		if ( reaction ) reaction.removeEmoji();
 	} );

+ 1 - 0
util/functions.js

@@ -168,6 +168,7 @@ function htmlToPlain(html) {
 		onopentag: (tagname, attribs) => {
 			if ( tagname === 'sup' && attribs.class === 'reference' ) ignoredTag = 'sup';
 			if ( tagname === 'span' && attribs.class === 'smwttcontent' ) ignoredTag = 'span';
+			if ( tagname === 'br' ) text += ' ';
 		},
 		ontext: (htmltext) => {
 			if ( !ignoredTag ) {

+ 23 - 0
util/i18n.js

@@ -48,6 +48,29 @@ class Lang {
 		} );
 	}
 
+	/**
+	 * Change the message language.
+	 * @param {String[]} languageOverwrites - Arguments for the message.
+	 * @returns {Lang}
+	 */
+	uselang(...languageOverwrites) {
+		languageOverwrites = languageOverwrites.map( lang => {
+			if ( typeof lang !== 'string' ) return;
+			if ( lang === 'allLangs' || !i18n.hasOwnProperty(lang) ) {
+				if ( /^[a-z]{2}(?:-[a-z]{2,4})?$/.test(lang) && i18n.allLangs.map.hasOwnProperty(lang) ) {
+					return i18n.allLangs.map[lang];
+				}
+				return;
+			}
+			return lang;
+		} ).filter( lang => lang );
+		if ( !languageOverwrites.length || ( languageOverwrites.length === 1 && languageOverwrites[0] === this.lang ) ) return this;
+		var newLang = new Lang(this.lang, this.namespace);
+		newLang.fallback.unshift(...languageOverwrites.slice(1), newLang.lang);
+		newLang.lang = languageOverwrites[0];
+		return newLang;
+	}
+
 	/**
 	 * Get a localized message.
 	 * @param {String} message - Name of the message.