Quellcode durchsuchen

Add Bengali and small improvements

Markus-Rost vor 4 Jahren
Ursprung
Commit
f7879df476
13 geänderte Dateien mit 169 neuen und 123 gelöschten Zeilen
  1. 3 3
      README.md
  2. 1 1
      RcGcDb
  3. 41 14
      cmds/wiki/overview.js
  4. 1 1
      dashboard/index.html
  5. 10 4
      dashboard/index.js
  6. 5 5
      dashboard/login.html
  7. 2 4
      dashboard/rcscript.js
  8. 24 23
      dashboard/settings.js
  9. 2 4
      dashboard/verification.js
  10. 4 0
      i18n/allLangs.json
  11. 5 9
      main.js
  12. 30 24
      util/default.json
  13. 41 31
      util/edit_diff.js

+ 3 - 3
README.md

@@ -1,11 +1,11 @@
 # Wiki-Bot[<img src="https://translate.wikibot.de/widgets/wiki-bot/-/svg-badge.svg" alt="Translation status" align="right" />](#translations)[<img src="https://github.com/Markus-Rost/discord-wiki-bot/workflows/Node.js CI/badge.svg" alt="Node.js CI" align="right" />](https://github.com/Markus-Rost/discord-wiki-bot/actions)
-[<img src="https://commons.gamepedia.com/media/9/93/Cursebot.png" alt="Wiki-Bot" align="right" />](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot)
+[<img src="https://commons.gamepedia.com/media/9/93/Cursebot.png" alt="Wiki-Bot" align="right" />](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot)
 
 **Wiki-Bot** is a bot for [Discord](https://discord.com/) with the purpose to easily link and search [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki) sites like [Gamepedia](https://www.gamepedia.com/) and [Fandom](https://www.fandom.com/) wikis. **Wiki-Bot** shows short descriptions and additional info about pages and is able to resolve redirects and follow interwiki links.
 
 **Wiki-Bot** has translations for English, German, French, Hindi, Dutch, Polish, Portuguese, Russian, Turkish and Chinese.
 
-[Use this link to invite **Wiki-Bot** to your Discord server.](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot)
+[Use this link to invite **Wiki-Bot** to your Discord server.](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot)
 
 Support server: [https://discord.gg/v77RTk5](https://discord.gg/v77RTk5)
 
@@ -18,7 +18,7 @@ Support server: [https://discord.gg/v77RTk5](https://discord.gg/v77RTk5)
 * [Voice Channel](#voice-channel)
 
 ## Setup
-After [inviting](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot) **Wiki-Bot** to your server you need to set the wiki you want to search by default. You do this with the `!wiki settings` command.
+After [inviting](https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot) **Wiki-Bot** to your server you need to set the wiki you want to search by default. You do this with the `!wiki settings` command.
 * Change the wiki with `!wiki settings wiki <url>`
   * Example: `!wiki settings wiki https://minecraft.gamepedia.com/Minecraft_Wiki`
 * Change the language with `!wiki settings lang <language>`

+ 1 - 1
RcGcDb

@@ -1 +1 @@
-Subproject commit 5cdd84e4f98e119b2760aa6c71a996b910562670
+Subproject commit ab67bc64cd773170a8a73dbfa269550a88132ec4

+ 41 - 14
cmds/wiki/overview.js

@@ -16,7 +16,7 @@ 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|languages&siinlanguagecode=' + lang.lang + ( wiki.isMiraheze() ? '' : '' ) + '&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 + '&list=allrevisions&arvdir=newer&arvlimit=1&arvprop=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 ) {
@@ -41,7 +41,6 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				site = allSites.find( site => site.wiki_domain === wiki.hostname );
 				
 				var name = [lang.get('overview.name'), site.wiki_display_name];
-				var created = [lang.get('overview.created'), new Date(parseInt(site.created + '000', 10)).toLocaleString(lang.get('dateformat'), timeoptions)];
 				var manager = [lang.get('overview.manager'), site.wiki_managers];
 				var official = [lang.get('overview.official'), lang.get('overview.' + ( site.official_wiki ? 'yes' : 'no' ))];
 				var crossover = [lang.get('overview.crossover'), ( site.wiki_crossover ? '<https://' + site.wiki_crossover + '/>' : '' )];
@@ -54,6 +53,12 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				}
 				if ( image[1] && image[1].startsWith( '/' ) ) image[1] = new URL(image[1], wiki).href;
 			}
+			var created = [lang.get('overview.created')];
+			var creation_date = null;
+			if ( body.query.allrevisions?.[0]?.revisions?.[0]?.timestamp ) {
+				creation_date = new Date(body.query.allrevisions[0].revisions[0].timestamp);
+				created.push(creation_date.toLocaleString(lang.get('dateformat'), timeoptions));
+			}
 			var language = [lang.get('overview.lang'), body.query.languages.find( language => {
 				return language.code === body.query.general.lang;
 			} )['*']];
@@ -88,8 +93,14 @@ 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( 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') + '*';
+					if ( msg.showEmbed() ) {
+						if ( created[1] ) embed.addField( created[0], created[1], true );
+						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 {
+						if ( created[1] ) text += created.join(' ') + '\n';
+						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} );
 					
@@ -101,7 +112,10 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 					var vertical = [lang.get('overview.vertical'), site.hub];
 					var topic = [lang.get('overview.topic'), site.topic];
 					var founder = [lang.get('overview.founder'), site.founding_user_id];
-					var created = [lang.get('overview.created'), new Date(site.creation_date).toLocaleString(lang.get('dateformat'), timeoptions)];
+					if ( created[1] && creation_date > new Date(site.creation_date) ) {
+						creation_date = new Date(site.creation_date);
+						created[1] = creation_date.toLocaleString(lang.get('dateformat'), timeoptions);
+					}
 					var posts = [lang.get('overview.posts')];
 					var walls = [lang.get('overview.walls')];
 					var comments = [lang.get('overview.comments')];
@@ -148,9 +162,12 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 							}
 							else {
 								let counts = dsbody?._embedded?.count?.[0];
-								if ( counts?.FORUM ) posts.push(counts.FORUM);
-								if ( counts?.WALL ) walls.push(counts.WALL);
-								if ( counts?.ARTICLE_COMMENT ) comments.push(counts.ARTICLE_COMMENT);
+								if ( counts?.FORUM || counts?.WALL || counts?.ARTICLE_COMMENT ) {
+									if ( counts?.FORUM ) posts.push(counts.FORUM);
+									if ( counts?.WALL ) walls.push(counts.WALL);
+									if ( counts?.ARTICLE_COMMENT ) comments.push(counts.ARTICLE_COMMENT);
+								}
+								else if ( counts?.total ) posts.push(counts.total);
 							}
 						}, error => {
 							console.log( '- Error while getting discussions stats: ' + error );
@@ -159,7 +176,8 @@ 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( language[0], language[1], true ).addField( articles[0], articles[1], true ).addField( pages[0], pages[1], true ).addField( edits[0], edits[1], true );
+							if ( created[1] ) embed.addField( created[0], created[1], true );
+							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 );
 							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 );
@@ -173,7 +191,10 @@ 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' + language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ');
+							text += '\n' + founder.join(' ');
+							if ( manager[1] ) text += '\n' + manager.join(' ');
+							if ( created[1] ) text += '\n' + created.join(' ');
+							text += '\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(' ');
@@ -195,6 +216,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 );
+						if ( created[1] ) embed.addField( created[0], created[1], true );
 						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] );
@@ -203,8 +225,11 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 						}
 					}
 					else {
-						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 ( manager[1] ) text += manager.join(' ') + '\n';
+						if ( created[1] ) text += created.join(' ') + '\n';
+						text += language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ');
 						if ( crossover[1] ) text += '\n' + crossover.join(' ');
+						text += '\n\n*' + lang.get('overview.inaccurate') + '*';
 					}
 					
 					msg.sendChannel( spoiler + text + spoiler, {embed} );
@@ -215,7 +240,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				console.log( '- Error while getting the wiki details: ' + error );
 
 				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') + '*';
+				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} );
 				
@@ -225,8 +250,9 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 				if ( msg.showEmbed() ) {
 					if ( site ) {
 						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( name[0], name[1], true ).addField( manager[0], ( managerlist || lang.get('overview.none') ), true ).addField( official[0], official[1], true );
 					}
+					if ( created[1] ) embed.addField( created[0], created[1], true );
 					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 );
@@ -235,7 +261,8 @@ 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';
+					if ( site ) text += name.join(' ') + '\n' + manager[0] + ' ' + ( manager[1].join(', ') || lang.get('overview.none') ) + '\n' + official.join(' ') + '\n';
+					if ( created[1] ) text += created.join(' ') + '\n';
 					text += language.join(' ') + '\n' + articles.join(' ') + '\n' + pages.join(' ') + '\n' + edits.join(' ') + '\n' + users.join(' ');
 					if ( site ) {
 						if ( crossover[1] ) text += '\n' + crossover.join(' ');

+ 1 - 1
dashboard/index.html

@@ -49,7 +49,7 @@
 		<div id="guildlist">
 			<div class="guild" id="invite">
 				<div class="bar"></div>
-				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot" alt="Invite Wiki-Bot">
+				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot" alt="Invite Wiki-Bot">
 					<div class="avatar svg-avatar">
 						<svg width="24" height="24" viewBox="0 0 24 24">
 							<path fill="currentColor" d="M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"></path>

+ 10 - 4
dashboard/index.js

@@ -51,9 +51,7 @@ const server = http.createServer((req, res) => {
 		if ( args.length === 5 && ['settings', 'verification', 'rcscript'].includes( args[3] )
 		&& /^(?:default|new|\d+)$/.test(args[4]) && settingsData.has(state)
 		&& settingsData.get(state).guilds.isMember.has(args[2]) ) {
-			if ( process.env.READONLY ) {
-				return dashboard(res, state, new URL(`${req.url}?save=failed`, process.env.dashboard));
-			}
+			if ( process.env.READONLY ) return save_response(`${req.url}?save=failed`);
 			let body = '';
 			req.on( 'data', chunk => {
 				body += chunk.toString();
@@ -75,8 +73,16 @@ const server = http.createServer((req, res) => {
 						}
 					}
 				} );
-				return posts[args[3]](res, settingsData.get(state), args[2], args[4], settings);
+				console.log( settings );
+				return posts[args[3]](save_response, settingsData.get(state), args[2], args[4], settings);
 			} );
+
+			/**
+			 * @param {String} [resURL]
+			 */
+			function save_response(resURL = '/') {
+				return dashboard(res, state, new URL(resURL, process.env.dashboard));
+			}
 		}
 	}
 

+ 5 - 5
dashboard/login.html

@@ -10,7 +10,7 @@
 	<meta property="og:title" content="Login – Wiki-Bot Settings">
 	<meta property="og:site_name" content="Wiki-Bot Settings">
 	<meta itemprop="author" content="MarkusRost">
-	<link rel="stylesheet" type="text/css" href="src/index.css">
+	<link rel="stylesheet" type="text/css" href="/src/index.css">
 </head>
 <body>
 	<div id="text">
@@ -32,11 +32,11 @@
 	<div class="scrollbar" id="sidebar">
 		<div class="scrollbar" id="channellist">
 			<a class="channel channel-header" id="login">
-				<img src="src/settings.svg" alt="Settings">
+				<img src="/src/settings.svg" alt="Settings">
 				<div>Login</div>
 			</a>
-			<a class="channel" id="invite-wikibot" href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot">
-				<img src="src/channel.svg" alt="Channel">
+			<a class="channel" id="invite-wikibot" href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot">
+				<img src="/src/channel.svg" alt="Channel">
 				<div>Invite Wiki-Bot</div>
 			</a>
 		</div>
@@ -51,7 +51,7 @@
 		<div id="guildlist">
 			<div class="guild" id="invite">
 				<div class="bar"></div>
-				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot" alt="Invite Wiki-Bot">
+				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939904064&scope=bot" alt="Invite Wiki-Bot">
 					<div class="avatar svg-avatar">
 						<svg width="24" height="24" viewBox="0 0 24 24">
 							<path fill="currentColor" d="M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"></path>

+ 2 - 4
dashboard/rcscript.js

@@ -1,7 +1,6 @@
 const {defaultSettings, limit: {rcgcdw: rcgcdwLimit}} = require('../util/default.json');
 const {RcGcDw: allLangs} = require('../i18n/allLangs.json');
 const {got, db, sendMsg, hasPerm} = require('./util.js');
-const dashboard = require('./guilds.js');
 
 const fieldset = {
 	channel: '<label for="wb-settings-channel">Channel:</label>'
@@ -193,7 +192,7 @@ function dashboard_rcscript(res, $, guild, args) {
 
 /**
  * Change recent changes scripts
- * @param {import('http').ServerResponse} res - The server response
+ * @param {Function} res - The server response
  * @param {import('./util.js').Settings} userSettings - The settings of the user
  * @param {String} guild - The id of the guild
  * @param {String} type - The setting to change
@@ -210,8 +209,7 @@ function dashboard_rcscript(res, $, guild, args) {
 function update_rcscript(res, userSettings, guild, type, settings) {
 	
 	console.log( settings );
-	return dashboard(res, userSettings.state,
-		new URL(`/guild/${guild}/rcscript/${type}?save=failed`, process.env.dashboard));
+	return res(`/guild/${guild}/rcscript/${type}?save=failed`);
 }
 
 module.exports = {

+ 24 - 23
dashboard/settings.js

@@ -1,7 +1,6 @@
 const {defaultSettings} = require('../util/default.json');
 const {allLangs} = require('../i18n/allLangs.json');
 const {got, db, sendMsg, hasPerm} = require('./util.js');
-const dashboard = require('./guilds.js');
 
 const fieldset = {
 	channel: '<label for="wb-settings-channel">Channel:</label>'
@@ -191,7 +190,7 @@ function dashboard_settings(res, $, guild, args) {
 
 /**
  * Change settings
- * @param {import('http').ServerResponse} res - The server response
+ * @param {Function} res - The server response
  * @param {import('./util.js').Settings} userSettings - The settings of the user
  * @param {String} guild - The id of the guild
  * @param {String} type - The setting to change
@@ -207,7 +206,6 @@ function dashboard_settings(res, $, guild, args) {
  * @param {String} [settings.delete_settings]
  */
 function update_settings(res, userSettings, guild, type, settings) {
-	console.log( settings );
 	sendMsg( {
 		type: 'getMember',
 		member: userSettings.user.id,
@@ -216,47 +214,50 @@ function update_settings(res, userSettings, guild, type, settings) {
 		if ( !response ) {
 			userSettings.guilds.notMember.set(guild, userSettings.guilds.isMember.get(guild));
 			userSettings.guilds.isMember.delete(guild);
-			return dashboard(res, userSettings.state,
-				new URL(`/guild/${guild}?save=failed`, process.env.dashboard));
+			return res(`/guild/${guild}?save=failed`);
 		}
 		if ( response === 'noMember' || !hasPerm(response.permissions, 'MANAGE_SERVER') ) {
 			userSettings.guilds.isMember.delete(guild);
-			return dashboard(res, userSettings.state,
-				new URL('/?save=failed', process.env.dashboard));
+			return res('/?save=failed');
 		}
 		if ( type === 'default' ) {
 			if ( !settings.save_settings || settings.channel
 			|| ( !response.patreon && settings.prefix ) ) {
-				return dashboard(res, userSettings.state,
-					new URL(`/guild/${guild}/settings?save=failed`, process.env.dashboard));
+				return res(`/guild/${guild}/settings?save=failed`);
 			}
-			return dashboard(res, userSettings.state,
-				new URL(`/guild/${guild}/settings?save=success`, process.env.dashboard));
+			return res(`/guild/${guild}/settings?save=success`);
 		}
 		if ( ( !settings.save_settings && !settings.delete_settings )
 		|| !settings.channel || settings.voice || ( !response.patreon
 		&& ( settings.prefix || settings.lang || settings.inline ) ) ) {
-			return dashboard(res, userSettings.state,
-				new URL(`/guild/${guild}/settings/${type}?save=failed`, process.env.dashboard));
+			return res(`/guild/${guild}/settings/${type}?save=failed`);
 		}
 		if ( type === 'new' ) {
 			if ( !settings.save_settings ) {
-				return dashboard(res, userSettings.state,
-					new URL(`/guild/${guild}/settings/new?save=failed`, process.env.dashboard));
+				return res(`/guild/${guild}/settings/new?save=failed`);
 			}
-			return dashboard(res, userSettings.state,
-				new URL(`/guild/${guild}/settings/new?save=success`, process.env.dashboard));
+			return res(`/guild/${guild}/settings/new?save=success`);
 		}
 		if ( !settings.save_settings && settings.delete_settings ) {
-			return dashboard(res, userSettings.state,
-				new URL(`/guild/${guild}/settings?save=success`, process.env.dashboard));
+			return db.run( 'DELETE FROM discord WHERE guild = ? AND channel = ?', [guild, type], function (delerror) {
+				if ( delerror ) {
+					console.log( '- Dashboard: Error while removing the settings: ' + delerror );
+					return res(`/guild/${guild}/settings/${type}?save=failed`);
+				}
+				console.log( '- Dashboard: Settings successfully removed: ' + guild );
+				sendMsg( {
+					type: 'notifyGuild', guild,
+					text: `<@${userSettings.user.id}> removed the settings for <#${type}>.\n${new URL(`/guild/${guild}/settings`, process.env.dashboard)}`
+				} ).catch( error => {
+					console.log( '- Dashboard: Error while notifying the guild: ' + error );
+				} );
+				return res(`/guild/${guild}/settings?save=success`);
+			} );
 		}
-		return dashboard(res, userSettings.state,
-			new URL(`/guild/${guild}/settings/${type}?save=success`, process.env.dashboard));
+		return res(`/guild/${guild}/settings/${type}?save=success`);
 	}, error => {
 		console.log( '- Dashboard: Error while getting the member: ' + error );
-		return dashboard(res, userSettings.state,
-			new URL(`/guild/${guild}/settings/${type}?save=failed`, process.env.dashboard));
+		return res(`/guild/${guild}/settings/${type}?save=failed`);
 	} );
 }
 

+ 2 - 4
dashboard/verification.js

@@ -1,6 +1,5 @@
 const {limit: {verification: verificationLimit}} = require('../util/default.json');
 const {db, sendMsg, hasPerm} = require('./util.js');
-const dashboard = require('./guilds.js');
 
 const fieldset = {
 	channel: '<label for="wb-settings-channel">Channel:</label>'
@@ -207,7 +206,7 @@ function dashboard_verification(res, $, guild, args) {
 
 /**
  * Change verifications
- * @param {import('http').ServerResponse} res - The server response
+ * @param {Function} res - The server response
  * @param {import('./util.js').Settings} userSettings - The settings of the user
  * @param {String} guild - The id of the guild
  * @param {String} type - The setting to change
@@ -224,8 +223,7 @@ function dashboard_verification(res, $, guild, args) {
 function update_verification(res, userSettings, guild, type, settings) {
 	
 	console.log( settings );
-	return dashboard(res, userSettings.state,
-		new URL(`/guild/${guild}/verification/${type}?save=failed`, process.env.dashboard));
+	return res(`/guild/${guild}/verification/${type}?save=failed`);
 }
 
 module.exports = {

+ 4 - 0
i18n/allLangs.json

@@ -2,6 +2,7 @@
 	"allLangs": {
 		"names": {
 			"en": "English",
+			"bn": "বাংলা",
 			"de": "Deutsch",
 			"fr": "Français",
 			"hi": "हिन्दी",
@@ -17,6 +18,9 @@
 			"en": "en",
 			"eng": "en",
 			"english": "en",
+			"bn": "bn",
+			"bengali": "bn",
+			"বাংলা": "bn",
 			"de": "de",
 			"german": "de",
 			"deutsch": "de",

+ 5 - 9
main.js

@@ -122,7 +122,7 @@ if ( process.env.dashboard ) {
 							return results.find( result => result[i] )?.[i];
 						} );
 					}, error => {
-						data.error = error;
+						data.error = error.toString();
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );
 					} );
@@ -141,7 +141,7 @@ if ( process.env.dashboard ) {
 					}`).then( results => {
 						data.response = results.find( result => result );
 					}, error => {
-						data.error = error;
+						data.error = error.toString();
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );
 					} );
@@ -149,13 +149,9 @@ if ( process.env.dashboard ) {
 				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;
+						if ( channel ) channel.send(\`${message.data.text.replace( /`/g, '\\`' )}\`).catch( error => console.log( '- Dashboard: ' + error.name + ': ' + error.message ) );
+					}`).catch( error => {
+						data.error = error.toString();
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );
 					} );

+ 30 - 24
util/default.json

@@ -22,7 +22,7 @@
 			"display": 2
 		}
 	},
-	"defaultPermissions": 939912256,
+	"defaultPermissions": 939904064,
 	"defaultSettings": {
 		"lang": "en",
 		"wiki": "https://en.wikipedia.org/w/"
@@ -106,67 +106,67 @@
 	"wikiProjects": [
 		{
 			"name": "wikipedia.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikipedia\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikipedia\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "mediawiki.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?mediawiki\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?mediawiki\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikimedia.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikimedia\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikimedia\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wiktionary.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wiktionary\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wiktionary\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikibooks.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikibooks\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikibooks\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikisource.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikisource\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikisource\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikidata.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikidata\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikidata\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikiversity.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikiversity\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikiversity\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikiquote.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikiquote\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikiquote\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikinews.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikinews\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikinews\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
 		{
 			"name": "wikivoyage.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)?wikivoyage\\.org)",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)?(?:m\\.)?wikivoyage\\.org)",
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
@@ -176,29 +176,35 @@
 			"articlePath": "/wiki/",
 			"scriptPath": "/w/"
 		},
-		{
-			"name": "metapedia.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)metapedia\\.org)",
-			"articlePath": "/wiki/",
-			"scriptPath": "/m/"
-		},
 		{
 			"name": "paradoxwikis.com",
 			"regex": "((?:[a-z\\d-]{1,50}\\.)paradoxwikis\\.com)",
 			"articlePath": "/",
 			"scriptPath": "/"
 		},
-		{
-			"name": "brickimedia.org",
-			"regex": "((?:[a-z\\d-]{1,50}\\.)brickimedia\\.org)",
-			"articlePath": "/wiki/",
-			"scriptPath": "/w/"
-		},
 		{
 			"name": "runescape.wiki",
 			"regex": "((?:(?:classic|oldschool|pt|www)\\.)?runescape\\.wiki)",
 			"articlePath": "/w/",
 			"scriptPath": "/"
+		},
+		{
+			"name": "wiki.biligame.com",
+			"regex": "(wiki\\.biligame\\.com/(?:[a-z\\d]{1,50}))",
+			"articlePath": "/",
+			"scriptPath": "/"
+		},
+		{
+			"name": "metapedia.org",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)metapedia\\.org)",
+			"articlePath": "/wiki/",
+			"scriptPath": "/m/"
+		},
+		{
+			"name": "brickimedia.org",
+			"regex": "((?:[a-z\\d-]{1,50}\\.)brickimedia\\.org)",
+			"articlePath": "/wiki/",
+			"scriptPath": "/w/"
 		}
 	]
 }

+ 41 - 31
util/edit_diff.js

@@ -10,60 +10,70 @@ const {escapeFormatting} = require('./functions.js');
  */
 function diffParser(html, more, whitespace) {
 	var current_tag = '';
+	var last_ins = null;
+	var last_del = null;
+	var empty = false;
 	var small_prev_ins = '';
 	var small_prev_del = '';
 	var ins_length = more.length;
 	var del_length = more.length;
-	var added = false;
 	var parser = new htmlparser.Parser( {
 		onopentag: (tagname, attribs) => {
 			if ( tagname === 'ins' || tagname == 'del' ) current_tag = tagname;
-			if ( tagname === 'td' && attribs.class === 'diff-addedline' ) current_tag = tagname+'a';
-			if ( tagname === 'td' && attribs.class === 'diff-deletedline' ) current_tag = tagname+"d";
-			if ( tagname === 'td' && attribs.class === 'diff-marker' ) added = true;
+			if ( tagname === 'td' && attribs.class === 'diff-addedline' && ins_length <= 1000 ) {
+				current_tag = 'tda';
+				last_ins = '';
+			}
+			if ( tagname === 'td' && attribs.class === 'diff-deletedline' && del_length <= 1000 ) {
+				current_tag = 'tdd';
+				last_del = '';
+			}
+			if ( tagname === 'td' && attribs.class === 'diff-empty' ) empty = true;
 		},
 		ontext: (htmltext) => {
 			if ( current_tag === 'ins' && ins_length <= 1000 ) {
 				ins_length += ( '**' + escapeFormatting(htmltext) + '**' ).length;
-				if ( ins_length <= 1000 ) small_prev_ins += '**' + escapeFormatting(htmltext) + '**';
-				else small_prev_ins += more;
+				if ( ins_length <= 1000 ) last_ins += '**' + escapeFormatting(htmltext) + '**';
 			}
 			if ( current_tag === 'del' && del_length <= 1000 ) {
 				del_length += ( '~~' + escapeFormatting(htmltext) + '~~' ).length;
-				if ( del_length <= 1000 ) small_prev_del += '~~' + escapeFormatting(htmltext) + '~~';
-				else small_prev_del += more;
+				if ( del_length <= 1000 ) last_del += '~~' + escapeFormatting(htmltext) + '~~';
 			}
-			if ( ( current_tag === 'afterins' || current_tag === 'tda') && ins_length <= 1000 ) {
+			if ( current_tag === 'tda' && ins_length <= 1000 ) {
 				ins_length += escapeFormatting(htmltext).length;
-				if ( ins_length <= 1000 ) small_prev_ins += escapeFormatting(htmltext);
-				else small_prev_ins += more;
+				if ( ins_length <= 1000 ) last_ins += escapeFormatting(htmltext);
 			}
-			if ( ( current_tag === 'afterdel' || current_tag === 'tdd') && del_length <= 1000 ) {
+			if ( current_tag === 'tdd' && del_length <= 1000 ) {
 				del_length += escapeFormatting(htmltext).length;
-				if ( del_length <= 1000 ) small_prev_del += escapeFormatting(htmltext);
-				else small_prev_del += more;
+				if ( del_length <= 1000 ) last_del += escapeFormatting(htmltext);
 			}
-			if ( added ) {
-				if ( htmltext === '+' && ins_length <= 1000 ) {
+		},
+		onclosetag: (tagname) => {
+			current_tag = '';
+			if ( tagname === 'ins' ) current_tag = 'tda';
+			if ( tagname === 'del' ) current_tag = 'tdd';
+			if ( tagname === 'tr' ) {
+				if ( last_ins !== null ) {
 					ins_length++;
-					if ( ins_length <= 1000 ) small_prev_ins += '\n';
-					else small_prev_ins += more;
+					if ( empty && last_ins.trim().length && !last_ins.includes( '**' ) ) {
+						ins_length += 4;
+						last_ins = '**' + last_ins + '**';
+					}
+					small_prev_ins += '\n' + last_ins;
+					if ( ins_length > 1000 ) small_prev_ins += more;
+					last_ins = null;
 				}
-				if ( htmltext === '−' && del_length <= 1000 ) {
+				if ( last_del !== null ) {
 					del_length++;
-					if ( del_length <= 1000 ) small_prev_del += '\n';
-					else small_prev_del += more;
+					if ( empty && last_del.trim().length && !last_ins.includes( '~~' ) ) {
+						del_length += 4;
+						last_del = '~~' + last_del + '~~';
+					}
+					small_prev_del += '\n' + last_del;
+					if ( del_length > 1000 ) small_prev_del += more;
+					last_del = null;
 				}
-				added = false;
-			}
-		},
-		onclosetag: (tagname) => {
-			if ( tagname === 'ins' ) {
-				current_tag = 'afterins';
-			} else if ( tagname === 'del' ) {
-				current_tag = 'afterdel';
-			} else {
-				current_tag = '';
+				empty = false;
 			}
 		}
 	} );