From d0e9c914e416f8a42dd6709c10ab2dc84f77b86e Mon Sep 17 00:00:00 2001 From: Wessel T Date: Sat, 16 Feb 2019 22:24:03 +0100 Subject: [PATCH] Add TODO, splatoon cmd and and update avatar + user cmd --- TODO.md | 36 ++++ src/_application.yml | 2 + src/assets/i18n/en_us/strings.yml | 86 +++++---- src/assets/i18n/nl/strings.yml | 24 ++- src/commands/Discord/Games/splatoon.js | 61 ++++++ src/commands/Discord/Information/avatar.js | 10 +- src/commands/Discord/Information/user.js | 18 ++ src/main.js | 2 +- src/util/smartSearch.js | 212 +++++++++++++++++++++ 9 files changed, 399 insertions(+), 52 deletions(-) create mode 100644 TODO.md create mode 100644 src/commands/Discord/Games/splatoon.js create mode 100644 src/util/smartSearch.js diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..2c3919f --- /dev/null +++ b/TODO.md @@ -0,0 +1,36 @@ +# Things that are either planned or being worked on +[ ] = Planned +[x] = In progress + +- [ ] Tags + - [ ] Commands + - [ ] Use + - [ ] Edit + - [ ] Info + - [ ] Create + - [ ] Delete + - [ ] Source + - [ ] Transfer +- [ ] Moderation + - [ ] Logging + - [ ] Mod logs + - [ ] Action taken + - [ ] User updated + - [ ] Guild updated + - [ ] User join/leave + - [ ] Roles added/updated + - [ ] Message delete/edit + - [ ] Commands + - [ ] Kick + - [ ] Warn + - [ ] Purge + - [ ] Softban + - [ ] Hack(ban) + - [ ] Un(mute) + - [ ] Infractions + +_***Finished (for now)***_: +- [x] Global + - [x] Commands + - [x] user lookup + - [x] guild lookup \ No newline at end of file diff --git a/src/_application.yml b/src/_application.yml index 74ba252..c59fbb9 100644 --- a/src/_application.yml +++ b/src/_application.yml @@ -72,6 +72,8 @@ discord : birb : true lizard : true penguin : true + # Category : GAMES + splatoon : true # Category : DEVELOPER eval : true echo : true diff --git a/src/assets/i18n/en_us/strings.yml b/src/assets/i18n/en_us/strings.yml index b02a2d6..b242a35 100644 --- a/src/assets/i18n/en_us/strings.yml +++ b/src/assets/i18n/en_us/strings.yml @@ -24,13 +24,13 @@ votelock: - '' - '$[emoji#1] If you still have issues after that, you can either create an [**`issue`**](https://github.com/PassTheWessel/wump/issues) on [**`GitHub`**](https://github.com/PassTheWessel/wump) or join my [**`Discord`**](https://discord.gg/SV7DAE9) and posting it there' -core : - prefix : +core: + prefix: + dupe: '$[emoji#0] Your prefix is already set to `$[user:prefix]`' + gdupe: '$[emoji#1] The guild''s prefix is already set to `$[guild:prefix]`' + gperms: '$[emoji#7] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)' + changed: '$[emoji#6] Successfully updated your prefix to `$[user:prefix]`' gchanged: '$[emoji#5] Successfully updated the guild''s prefix to `$[guild:prefix]`' - changed : '$[emoji#6] Successfully updated your prefix to `$[user:prefix]`' - gperms : '$[emoji#7] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)' - gdupe : '$[emoji#1] The guild''s prefix is already set to `$[guild:prefix]`' - dupe : '$[emoji#0] Your prefix is already set to `$[user:prefix]`' info : - '$[emoji#2] **>** Your current prefix is `$[user:prefix]`' - '$[emoji#3] **>** The guild''s prefix is `$[guild:prefix]`' @@ -41,14 +41,14 @@ core : - '' - 'Type `$[prefix:changeCmd]` to update your/the guild''s prefix' - locale : + locale: + dupe: '$[emoji#0] Your locale is already set to `$[uLocale:code]`' + gdupe: '$[emoji#1] The guild''s locale is already set to `$[gLocale:code]`' + gperms: '$[emoji#8] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)' + invalid: '$[emoji#7] The locale you provided isn''t a valid locale' + changed: '$[emoji#6] Successfully updated your locale to `$[uLocale:code]`' gchanged: '$[emoji#5] Successfully updated the guild''s locale to `$[gLocale:code]`' - changed : '$[emoji#6] Successfully updated your locale to `$[uLocale:code]`' - invalid : '$[emoji#7] The locale you provided isn''t a valid locale' - gperms : '$[emoji#8] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)' - gdupe : '$[emoji#1] The guild''s locale is already set to `$[gLocale:code]`' - dupe : '$[emoji#0] Your locale is already set to `$[uLocale:code]`' - list : + list: - '$[emoji#2] **>** Your current locale is `$[uLocale:code]`' - '$[emoji#3] **>** The guild''s locale is `$[gLocale:code]`' - '' @@ -58,48 +58,48 @@ core : - 'Type `$[locale:changeCmd]` to update your/the guild''s locale' - 'If you want to help translate wump, you can join my [Discord](https://discord.gg/SV7DAE9) and create a pull request on my [GitHub](https://github.com/PassTheWessel/wump/compare)' -util : - ping : - busy : '$[emoji#0] Pinging...' - health : +util: + ping: + busy: '$[emoji#0] Pinging...' + health: - 'Unknown' - 'Good' - 'Okay' - 'Bad' - result : + result: - '$[emoji#2] **Round-Trip**: $[roundtrip]ms' - '$[emoji#1] **Heartbeat**: $[latency]ms' - '$[emoji#3] **Health**: $[health]' - math : - busy : '$[emoji#0] Calculating, this may take some time...' + math: + busy: '$[emoji#0] Calculating, this may take some time...' blocked: ' Method "$[math:function]" has been disabled for security reasons ' - snipe : - fail : '$[emoji#0] No snipeable messages found' - footer : 'Sniped by $[author:tag] ($[author:id])' + snipe: + fail: '$[emoji#0] No snipeable messages found' + footer: 'Sniped by $[author:tag] ($[author:id])' -info : - stats : +info: + stats: fetching: '$[emoji#0] Fetching statistics, this may take some time...' - avatar : '$[emoji#0] Here''s **$[user:full]** avatar' + avatar: '$[emoji#0] Here''s **$[user:full]** avatar' - commits : + commits: - '$[emoji#1] **Total commits**: [`$[commits:total]`](https://github.com/PassTheWessel/wump/commits "Click here for a list of all commits")' - '$[emoji#0] **10 most recent commits done on [`PassTheWessel/wump`](https://github.com/PassTheWessel/wump/)**: $[commits:list]' commands: - multi : - - '$[emoji#0] The prefix for **$[guild:name]** is `$[guild:prefix]`' - - '$[emoji#1] Type `$[guild:prefix]command ` for more information' - - '$[emoji#2] **Links**: [`Invite`]($[bot:invite]) **|** [`Support`](https://discord.gg/SV7DAE9) **|** [`GitHub`](https://github.com/PassTheWessel/wump) **|** [`Patreon`](https://patreon.com/wessel)' single: - '$[emoji#3] **Name**: $[command:name]' - '$[emoji#4] **Syntax**: $[command:syntax]' - '$[emoji#5] **Aliases**: $[command:aliases]' - '$[emoji#6] **Cooldown**: $[command:cooldown#formatted]' - '$[emoji#7] **Arguments**: $[command:arguments]' + multi: + - '$[emoji#0] The prefix for **$[guild:name]** is `$[guild:prefix]`' + - '$[emoji#1] Type `$[guild:prefix]command ` for more information' + - '$[emoji#2] **Links**: [`Invite`]($[bot:invite]) **|** [`Support`](https://discord.gg/SV7DAE9) **|** [`GitHub`](https://github.com/PassTheWessel/wump) **|** [`Patreon`](https://patreon.com/wessel)' fields: - 'Core' - 'Information' @@ -136,26 +136,34 @@ info : - '$[emoji#14] Offline **⤏** `$[guild:users#offline]`' invalid: '$[emoji#15] No guild found with your query' - user : - invalid : '$[emoji#11] No user found with your query' - fields : - self : - name : '❯ User Information' + user: + invalid: '$[emoji#11] No user found with your query' + fields: + self: + name: '❯ User Information' value: - '$[emoji#0] **Tag**: $[user:tag] (`$[user:id]`)' - '$[emoji#1] **Creation**: $[user:created@precise] ago (`$[user:created@exact]`)' - '$[emoji#2] **Status**: $[user:status@full]' + mutual: '❯ Mutual Guilds' member: - name : '❯ Member Information' + name: '❯ Member Information' value: - '$[emoji#3] **Nickname**: $[member:nickname]' - '$[emoji#4] **Joined**: $[member:created@precise] ago (`$[member:created@exact]`)' - '$[emoji#5] **Roles**: $[member:roles]' image: - fetching : '$[emoji#0] Fetching a random image, this may take some time...' + fetching: '$[emoji#0] Fetching a random image, this may take some time...' failed_cache: 'Click here if the image didn''t load properly' - + +games: + splatoon: + - 'The current maps are:' + - '<:turf_wars:393051690393272320> **Turf War maps ⟿** $[maps:turf@first] **and** $[maps:turf@second]' + - '<:league:393051694096842762> **League Battle maps ⟿** $[maps:league@first] **and** $[maps:league@second]' + - '<:ranked:393051690108190721> **Ranked Battle maps ⟿** $[maps:ranked@first] **and** $[maps:ranked@second]' + developer: echo : '$[emoji#0] Invalid content to echo' diff --git a/src/assets/i18n/nl/strings.yml b/src/assets/i18n/nl/strings.yml index 312e4e8..af17670 100644 --- a/src/assets/i18n/nl/strings.yml +++ b/src/assets/i18n/nl/strings.yml @@ -135,17 +135,18 @@ info : - '$[emoji#14] Offline **⤏** `$[guild:users#offline]`' invalid: '$[emoji#15] Geen gilde gevonden met uw zoekopdracht' - user : - invalid : '$[emoji#11] Geen gebruiker gevonden met uw zoekopdracht' - fields : - self : - name : '❯ Gebruikers Informatie' + user: + invalid: '$[emoji#11] Geen gebruiker gevonden met uw zoekopdracht' + fields: + self: + name: '❯ Gebruikers Informatie' value: - '$[emoji#0] **Label**: $[user:tag] (`$[user:id]`)' - '$[emoji#1] **Creatie**: $[user:created@precise] ago (`$[user:created@exact]`)' - '$[emoji#2] **Staat**: $[user:status@full]' + mutual: '❯ Wederzijdse Gilden' member: - name : '❯ Ledeninformatie' + name: '❯ Ledeninformatie' value: - '$[emoji#3] **Bijnaam**: $[member:nickname]' - '$[emoji#4] **Aangesloten**: $[member:created@precise] ago (`$[member:created@exact]`)' @@ -153,9 +154,16 @@ info : image: - fetching : '$[emoji#0] Een willekeurig plaatje aan het ophalen, dit kan enige tijd duren...' + fetching: '$[emoji#0] Een willekeurig plaatje aan het ophalen, dit kan enige tijd duren...' failed_cache: 'Klik hier als het plaatje niet is geladen' - + +games: + splatoon: + - 'The current maps are:' + - '<:turf_wars:393051690393272320> **Turf War maps ⟿** $[maps:turf@first] **and** $[maps:turf@second]' + - '<:league:393051694096842762> **League Battle maps ⟿** $[maps:league@first] **and** $[maps:league@second]' + - '<:ranked:393051690108190721> **Ranked Battle maps ⟿** $[maps:ranked@first] **and** $[maps:ranked@second]' + developer: echo : '$[emoji#0] Ongeldig bericht om te echoën' diff --git a/src/commands/Discord/Games/splatoon.js b/src/commands/Discord/Games/splatoon.js new file mode 100644 index 0000000..f2e4290 --- /dev/null +++ b/src/commands/Discord/Games/splatoon.js @@ -0,0 +1,61 @@ +/* + m = Maps + r = Request + w = Wumpfetch +*/ + +const { DiscordCommand } = require('../../../core'); + +const w = require('wumpfetch'); +const l = require('larg'); +const s = require('../../../util/smartSearch'); + +module.exports = class Splatoon extends DiscordCommand { + constructor(bot) { + super(bot, { + name : 'splatoon', + syntax : 'splatoon', + aliases : [], + argument : [], + description: 'Get splatoon\'s current maps', + + hidden : false, + enabled : true, + cooldown : 1000, + category : 'Games', + ownerOnly : false, + guildOnly : false, + permissions: [ 'embedLinks' ] + }); + + this.mutable.BASE_URL = 'https://splatoon.ink'; + this.mutable.REQ_DATA = { + headers: { + 'User-Agent': this.bot.ua + } + }; + } + + async execute(msg, args) { + let r = await w(`${this.mutable.BASE_URL}/schedule2.json`, this.mutable.REQ_DATA).send(); + r = r.json(); + + msg.channel.createMessage(this._localize(msg.author.locale.games.splatoon.join('\n'), { maps: r })); + } + + _localize(msg, extData) { + if (extData && extData.maps) { + const m = extData.maps; + return msg + .replace(/\$\[maps:turf@first]/g, m.modes.regular[0].maps[0]) + .replace(/\$\[maps:ranked@first]/g, m.modes.gachi[0].maps[0]) + .replace(/\$\[maps:league@first]/g, m.modes.league[0].maps[0]) + .replace(/\$\[maps:turf@second]/g, m.modes.regular[0].maps[1]) + .replace(/\$\[maps:ranked@second]/g, m.modes.gachi[0].maps[1]) + .replace(/\$\[maps:league@second]/g, m.modes.league[0].maps[1]); + } + + return msg; + } +}; + diff --git a/src/commands/Discord/Information/avatar.js b/src/commands/Discord/Information/avatar.js index cba0cce..7842cad 100644 --- a/src/commands/Discord/Information/avatar.js +++ b/src/commands/Discord/Information/avatar.js @@ -75,10 +75,12 @@ module.exports = class Avatar extends DiscordCommand { tmp = await w(avatarURL).send(); tmp = tmp.body; // Resizing - dim = sizeOf(tmp); - tmp = await s(tmp) - .resize(dim.width * 2, dim.height * 2, { kernel: resize === 'LINEAR_B' ? s.kernel.linearB : resize === 'LINEAR_A' ? s.kernel.linearA : resize === 'NEAREST' ? s.kernel.nearest : s.kernel.linearA }) // { fit: 'inside' } - .toBuffer(); + if (this.mutable.reg[0].test(oArgs)) { + dim = sizeOf(tmp); + tmp = await s(tmp) + .resize(dim.width * 2, dim.height * 2, { kernel: resize === 'LINEAR_B' ? s.kernel.linearB : resize === 'LINEAR_A' ? s.kernel.linearA : resize === 'NEAREST' ? s.kernel.nearest : s.kernel.linearA }) // { fit: 'inside' } + .toBuffer(); + } // Utility customization if (this.mutable.reg[2].test(oArgs)) tmp = await s(tmp).greyscale().toBuffer(); if (this.mutable.reg[3].test(oArgs)) tmp = await s(tmp).jpeg({ quality: 5 }).toBuffer(); diff --git a/src/commands/Discord/Information/user.js b/src/commands/Discord/Information/user.js index a2aab31..b10b5d6 100644 --- a/src/commands/Discord/Information/user.js +++ b/src/commands/Discord/Information/user.js @@ -59,9 +59,27 @@ module.exports = class Guild extends DiscordCommand { }); } + const mutual = this.bot.guilds.filter((v) => v.members.has(u.id)).map((v) => v.name); + structure.embed.fields.push({ + name: msg.author.locale['info']['user']['fields']['mutual'], + value: mutual.length >= 1 ? this._limit(mutual, 25).join(' **/** ') : 'none', + inline: true + }); + msg.channel.createMessage(structure); } + _limit(array, max) { + if (array.length <= max) return array; + else { + const length = array.length - max; + array.splice(max, array.length - max); + array.push(`And ${length} more...`); + + return array; + } + } + _localize(msg, extData) { if (!msg) return ''; if (extData) { diff --git a/src/main.js b/src/main.js index 9051ec0..fa35170 100644 --- a/src/main.js +++ b/src/main.js @@ -25,7 +25,7 @@ process.argv = require('larg')(process.argv.slice(2)); process.hash = String.string(8); process.handleError = (err, name, type, exit = false, custom = false) => { - if (!custom) print(0, `${type ? type : green('Master')} !! ${name ? name : err.name ? err.name : 'Error'} -\n${red(`${err.message && err.stack ? `${err.message}\n${err.stack}` : err}`)}`); + if (!custom) print(0, `${type ? type : green('Master')} !! ${name ? name : err.name ? err.name : 'Error'} -\n${red(`${err && err.message && err.stack ? `${err.message}\n${err.stack}` : err}`)}`); else print(0, custom); if (exit) process.exit(process.type(exit) === 8 ? exit : 1); diff --git a/src/util/smartSearch.js b/src/util/smartSearch.js new file mode 100644 index 0000000..8e5eef4 --- /dev/null +++ b/src/util/smartSearch.js @@ -0,0 +1,212 @@ +'use strict'; +(function() { + var _match = function(pattern, text, offset, options) { + var insertions = 0; + var matchIndexes = []; + var iPattern = 0; + for (var iText = offset; iText < text.length; iText++) { + if (text[iText] === pattern[iPattern]) { + matchIndexes.push(iText); + if (++iPattern === pattern.length) { + return ({ + insertions: insertions, + matchIndexes: matchIndexes, + }); + } + } else if (matchIndexes.length) { + insertions++; + if (options.maxInsertions > -1 && insertions > options.maxInsertions) { + return null; + } + } + } + return null; + }; + var _find = function(pattern, text, options) { + var match = false; + var insertions = null; + var matchIndexes = null; + var iPattern = 0; + if (options.caseSensitive === false) { + pattern = pattern.toLowerCase(); + text = text.toLowerCase(); + } + for (var iText = 0; iText < text.length; iText++) { + if (text[iText] === pattern[iPattern]) { + var res = _match(pattern, text, iText, options); + if (res && (match === false || res.insertions <= insertions)) { + if (match === false || res.insertions < insertions) { + match = true; + insertions = res.insertions; + matchIndexes = res.matchIndexes; + } else { + matchIndexes = matchIndexes.concat(res.matchIndexes); + } + } + } + } + if (match) { + return ({ + value: pattern, + insertions: insertions, + matchIndexes: matchIndexes, + }); + } + return null; + }; + var _score = function(entryResults) { + var patternsMinInsertions = {}; + var patternsMinMatchIndex = {}; + entryResults.forEach(function(fieldResults) { + fieldResults.patterns.forEach(function(pattern) { + if (patternsMinInsertions[pattern.value] === undefined || pattern.insertions < patternsMinInsertions[pattern.value]) { + patternsMinInsertions[pattern.value] = pattern.insertions; + patternsMinMatchIndex[pattern.value] = pattern.matchIndexes; + } + }); + }); + var minInsertions = 0; + var minMatchIndex = []; + for (var pattern in patternsMinInsertions) { + if (patternsMinInsertions.hasOwnProperty(pattern)) { + minInsertions += patternsMinInsertions[pattern]; + minMatchIndex = minMatchIndex.concat(patternsMinMatchIndex[pattern]); + } + } + return minInsertions + minMatchIndex.sort()[0] / 1000; + }; + var _getFieldString = function(entry, field) { + var path = field; + var current = entry; + for (var i = 0; i < path.length; i++) { + if (current[path[i]] === undefined) { + return null; + } else { + current = current[path[i]]; + } + } + if (typeof current !== 'string') { + return null; + } + return current; + }; + var _forEachObject = function(object, fn) { + var _locals = []; + (function _private(object) { + for (var key in object) { + _locals.push(key); + if (typeof object[key] === 'object') { + _private(object[key]); + } else { + fn([].concat(_locals)); + } + _locals.pop(); + } + })(object); + }; + var _search = function(entries, patterns, fields, options) { + var results = []; + entries.forEach(function(entry) { + var match = false; + var entryMatch = []; + var entryResults = []; + _forEachObject(fields, function(field) { + var fieldString = _getFieldString(entry, field); + if (fieldString === null) { + return; + } + var fieldMatch = []; + var fieldResults = { + field: field.join('.'), + patterns: [] + }; + patterns.forEach(function(pattern) { + var res = _find(pattern, fieldString, options); + if (res) { + fieldResults.patterns.push(res); + fieldMatch.push(pattern); + if (entryMatch.indexOf(pattern) === -1) { + entryMatch.push(pattern); + } + } + }); + if (fieldMatch.length === patterns.length) { + entryResults.push(fieldResults); + match = true; + } else if (options.fieldMatching === false && fieldResults.patterns.length > 0) { + entryResults.push(fieldResults); + } + }); + if ((options.fieldMatching === true && match === true) || (options.fieldMatching === false && entryMatch.length === patterns.length)) { + results.push({ + entry: entry, + info: entryResults, + score: _score(entryResults) + }); + } + }); + return results; + }; + var _buildOptions = function(options) { + var defaultOptions = { + caseSensitive: false, + fieldMatching: false, + maxInsertions: -1, + }; + if (options === undefined) { + return defaultOptions; + } + for (var option in defaultOptions) { + if (options[option] !== undefined) { + defaultOptions[option] = options[option]; + } + } + return defaultOptions; + }; + var sanitizeArray = function(array, caseSensitive) { + if (array === undefined || array.length === undefined || array.length === 0) { + return []; + } + var values = {}; + var newArray = []; + array.forEach(function(elem) { + if (typeof elem !== 'string') { + return; + } + var element = !caseSensitive ? elem.toLowerCase() : elem; + if (element && (element in values) === false) { + values[element] = true; + newArray.push(element); + } + }); + return newArray; + }; + + function smartSearch(entries, patterns, fields, options) { + options = _buildOptions(options); + patterns = sanitizeArray([].concat(patterns), options.caseSensitive); + fields = typeof fields === 'string' ? { + [fields]: true + } : fields; + if (entries.length === 0 || patterns.length === 0) { + return; + } + var results = _search(entries, patterns, fields, options); + results.sort(function(a, b) { + return (a.score - b.score); + }); + return results; + } + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = smartSearch; + } + exports.smartSearch = smartSearch; + } else if (angular) { + angular.module('ngSmartSearch', []).filter('smartSearch', function() { + return smartSearch; + }); + } else { + window.smartSearch = smartSearch; + } +})(); \ No newline at end of file