├── .env.example ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── res └── i18n │ └── en │ └── default.json ├── src ├── bot.js ├── commands │ ├── core │ │ └── ping.js │ └── test │ │ └── trial.js ├── middleware │ ├── logger.js │ └── parseMessage.js └── selfbot.js └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | # Bot options 2 | CLIENT_TOKEN= 3 | CLIENT_PREFIX= 4 | SELFBOT= 5 | 6 | # Sharding options 7 | PROCESS_COUNT= 8 | SHARDS_PER_PROCESS= -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaFeatures": { 4 | "experimentalObjectRestSpread": true, 5 | "jsx": false 6 | }, 7 | "sourceType": "module" 8 | }, 9 | "env": { 10 | "es6": true, 11 | "node": true 12 | }, 13 | "plugins": [ 14 | "standard", 15 | "promise" 16 | ], 17 | "globals": { 18 | "document": false, 19 | "navigator": false, 20 | "window": false 21 | }, 22 | "rules": { 23 | "accessor-pairs": 2, 24 | "arrow-spacing": [2, { "before": true, "after": true }], 25 | "block-spacing": [2, "always"], 26 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 27 | "camelcase": [2, { "properties": "never" }], 28 | "comma-dangle": [2, "never"], 29 | "comma-spacing": [2, { "before": false, "after": true }], 30 | "comma-style": [2, "last"], 31 | "constructor-super": 2, 32 | "curly": [2, "multi-line"], 33 | "dot-location": [2, "property"], 34 | "eol-last": 2, 35 | "eqeqeq": [2, "allow-null"], 36 | "func-call-spacing": [2, "never"], 37 | "handle-callback-err": [2, "^(err|error)$" ], 38 | "indent": [2, 2, { "SwitchCase": 1 }], 39 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 40 | "keyword-spacing": [2, { "before": true, "after": true }], 41 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 42 | "new-parens": 2, 43 | "no-array-constructor": 2, 44 | "no-caller": 2, 45 | "no-class-assign": 2, 46 | "no-cond-assign": 2, 47 | "no-const-assign": 2, 48 | "no-constant-condition": [2, { "checkLoops": false }], 49 | "no-control-regex": 2, 50 | "no-debugger": 2, 51 | "no-delete-var": 2, 52 | "no-dupe-args": 2, 53 | "no-dupe-class-members": 2, 54 | "no-dupe-keys": 2, 55 | "no-duplicate-case": 2, 56 | "no-duplicate-imports": 2, 57 | "no-empty-character-class": 2, 58 | "no-empty-pattern": 2, 59 | "no-eval": 2, 60 | "no-ex-assign": 2, 61 | "no-extend-native": 2, 62 | "no-extra-bind": 2, 63 | "no-extra-boolean-cast": 2, 64 | "no-extra-parens": [2, "functions"], 65 | "no-fallthrough": 2, 66 | "no-floating-decimal": 2, 67 | "no-func-assign": 2, 68 | "no-global-assign": 2, 69 | "no-implied-eval": 2, 70 | "no-inner-declarations": [2, "functions"], 71 | "no-invalid-regexp": 2, 72 | "no-irregular-whitespace": 2, 73 | "no-iterator": 2, 74 | "no-label-var": 2, 75 | "no-labels": [2, { "allowLoop": false, "allowSwitch": false }], 76 | "no-lone-blocks": 2, 77 | "no-mixed-spaces-and-tabs": 2, 78 | "no-multi-spaces": 2, 79 | "no-multi-str": 2, 80 | "no-multiple-empty-lines": [2, { "max": 1 }], 81 | "no-native-reassign": 2, 82 | "no-negated-in-lhs": 2, 83 | "no-new": 2, 84 | "no-new-func": 2, 85 | "no-new-object": 2, 86 | "no-new-require": 2, 87 | "no-new-symbol": 2, 88 | "no-new-wrappers": 2, 89 | "no-obj-calls": 2, 90 | "no-octal": 2, 91 | "no-octal-escape": 2, 92 | "no-path-concat": 2, 93 | "no-proto": 2, 94 | "no-redeclare": 2, 95 | "no-regex-spaces": 2, 96 | "no-return-assign": [2, "except-parens"], 97 | "no-self-assign": 2, 98 | "no-self-compare": 2, 99 | "no-sequences": 2, 100 | "no-shadow-restricted-names": 2, 101 | "no-sparse-arrays": 2, 102 | "no-tabs": 2, 103 | "no-template-curly-in-string": 2, 104 | "no-this-before-super": 2, 105 | "no-throw-literal": 2, 106 | "no-trailing-spaces": 2, 107 | "no-undef": 2, 108 | "no-undef-init": 2, 109 | "no-unexpected-multiline": 2, 110 | "no-unmodified-loop-condition": 2, 111 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 112 | "no-unreachable": 2, 113 | "no-unsafe-finally": 2, 114 | "no-unsafe-negation": 2, 115 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 116 | "no-useless-call": 2, 117 | "no-useless-computed-key": 2, 118 | "no-useless-constructor": 2, 119 | "no-useless-escape": 2, 120 | "no-useless-rename": 2, 121 | "no-whitespace-before-property": 2, 122 | "no-with": 2, 123 | "object-property-newline": [2, { "allowMultiplePropertiesPerLine": true }], 124 | "one-var": [2, { "initialized": "never" }], 125 | "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }], 126 | "padded-blocks": [2, "never"], 127 | "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }], 128 | "rest-spread-spacing": [2, "never"], 129 | "semi-spacing": [2, { "before": false, "after": true }], 130 | "space-before-blocks": [2, "always"], 131 | "space-before-function-paren": [2, "always"], 132 | "space-in-parens": [2, "never"], 133 | "space-infix-ops": 2, 134 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 135 | "spaced-comment": [2, "always", { "line": { "markers": ["*package", "!", ","] }, "block": { "balanced": true, "markers": ["*package", "!", ","], "exceptions": ["*"] } }], 136 | "template-curly-spacing": [2, "never"], 137 | "unicode-bom": [2, "never"], 138 | "use-isnan": 2, 139 | "valid-typeof": 2, 140 | "wrap-iife": [2, "any"], 141 | "yield-star-spacing": [2, "both"], 142 | "yoda": [2, "never"], 143 | "standard/object-curly-even-spacing": [2, "either"], 144 | "standard/array-bracket-even-spacing": [2, "either"], 145 | "standard/computed-property-even-spacing": [2, "even"], 146 | "promise/param-names": 2 147 | } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Runtime 40 | .env 41 | 42 | # Compiled 43 | lib -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | before_install: 5 | - npm explore npm -g -- npm install node-gyp@latest 6 | install: npm install 7 | dist: trusty 8 | sudo: false -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Pyraxo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Yui](https://i.pyraxo.moe/1h1yRfaU8aGzXX9V1PUgwp2G6l7VrePg.gif) 2 | 3 | [![MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kukogei/iris/master/LICENSE) 4 | 5 | **Yui** serves as a base core for both Discord bots and selfbots. Requires **Node.js 6+** 6 | 7 | ## Installation 8 | ```bash 9 | $ git clone https://github.com/pyraxo/yui 10 | $ cd yui 11 | $ npm i 12 | $ npm start 13 | ``` 14 | 15 | ## Configuration 16 | Create a new `.env` file from `.env.example` and edit the values as desired. Follow `.env` instructions [here](https://www.npmjs.com/package/dotenv-safe) 17 | * `CLIENT_TOKEN` - Your bot token goes here 18 | * `CLIENT_PREFIX` - Bot prefix 19 | * `SELFBOT` - Set to `true` if you intend to use it as a selfbot, disables sharding 20 | * `PROCESS_COUNT` - Number of clusters (child processes) 21 | * `SHARDS_PER_PROCESS` - Number of shards per process 22 | 23 | ### Example .env 24 | ``` 25 | # Bot options 26 | CLIENT_TOKEN=your token here 27 | CLIENT_PREFIX=> 28 | SELFBOT=true 29 | 30 | # Sharding options 31 | PROCESS_COUNT=1 32 | SHARDS_PER_PROCESS=1 33 | ``` 34 | 35 | ## Documentation 36 | * [Eris](https://abal.moe/Eris/docs) - Discord library 37 | * [Sylphy](https://github.com/pyraxo/sylphy/wiki) - Bot framework 38 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const path = require('path') 3 | const moment = require('moment') 4 | const { Crystal } = require('sylphy') 5 | 6 | require('longjohn') 7 | require('dotenv-safe').config({ 8 | path: path.join(__dirname, '.env'), 9 | allowEmptyValues: true 10 | }) 11 | 12 | const isSelfbot = process.env.SELFBOT === 'true' 13 | 14 | if (isSelfbot) { 15 | require('./src/selfbot') 16 | } else { 17 | const cluster = new Crystal(path.join('src', 'bot.js'), parseInt(process.env.PROCESS_COUNT, 10)) 18 | const timestamp = () => `[${chalk.grey(moment().format('HH:mm:ss'))}]` 19 | 20 | cluster.on('clusterCreate', id => 21 | console.log(`${timestamp()} [MASTER]: CLUSTER ${chalk.cyan.bold(id)} ONLINE`) 22 | ) 23 | 24 | cluster.createClusters().then( 25 | () => console.log(`${timestamp()} [MASTER]: ` + chalk.magenta('We\'re live, ladies and gentlemen.')), 26 | err => console.error(err) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yui", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-regex": { 8 | "version": "2.1.1", 9 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 10 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 11 | }, 12 | "ansi-styles": { 13 | "version": "2.2.1", 14 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 15 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" 16 | }, 17 | "async": { 18 | "version": "1.0.0", 19 | "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", 20 | "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" 21 | }, 22 | "bluebird": { 23 | "version": "3.5.0", 24 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", 25 | "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" 26 | }, 27 | "chalk": { 28 | "version": "1.1.3", 29 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 30 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 31 | "requires": { 32 | "ansi-styles": "2.2.1", 33 | "escape-string-regexp": "1.0.5", 34 | "has-ansi": "2.0.0", 35 | "strip-ansi": "3.0.1", 36 | "supports-color": "2.0.0" 37 | } 38 | }, 39 | "colors": { 40 | "version": "1.0.3", 41 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", 42 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" 43 | }, 44 | "cycle": { 45 | "version": "1.0.3", 46 | "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", 47 | "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" 48 | }, 49 | "dotenv": { 50 | "version": "4.0.0", 51 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", 52 | "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" 53 | }, 54 | "dotenv-safe": { 55 | "version": "4.0.4", 56 | "resolved": "https://registry.npmjs.org/dotenv-safe/-/dotenv-safe-4.0.4.tgz", 57 | "integrity": "sha1-iw587Y5wsdPF2HTvlCDkBvOUJbM=", 58 | "requires": { 59 | "dotenv": "4.0.0" 60 | } 61 | }, 62 | "eris": { 63 | "version": "github:abalabahaha/eris#39733fc6fadd8bf648bf713e5e5f990809e03849", 64 | "requires": { 65 | "opusscript": "0.0.3", 66 | "tweetnacl": "1.0.0", 67 | "ws": "3.1.0" 68 | } 69 | }, 70 | "escape-string-regexp": { 71 | "version": "1.0.5", 72 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 73 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 74 | }, 75 | "eventemitter3": { 76 | "version": "2.0.3", 77 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", 78 | "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=" 79 | }, 80 | "eyes": { 81 | "version": "0.1.8", 82 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 83 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" 84 | }, 85 | "has-ansi": { 86 | "version": "2.0.0", 87 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 88 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 89 | "requires": { 90 | "ansi-regex": "2.1.1" 91 | } 92 | }, 93 | "isstream": { 94 | "version": "0.1.2", 95 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 96 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 97 | }, 98 | "longjohn": { 99 | "version": "0.2.12", 100 | "resolved": "https://registry.npmjs.org/longjohn/-/longjohn-0.2.12.tgz", 101 | "integrity": "sha1-fKdEawg2VcN351EiE9x1TVKmSn4=", 102 | "requires": { 103 | "source-map-support": "0.4.15" 104 | } 105 | }, 106 | "moment": { 107 | "version": "2.18.1", 108 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", 109 | "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" 110 | }, 111 | "moment-duration-format": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/moment-duration-format/-/moment-duration-format-1.3.0.tgz", 114 | "integrity": "sha1-VBdxtfh6BJzGVUBHXTrZZnN9aQg=" 115 | }, 116 | "opusscript": { 117 | "version": "0.0.3", 118 | "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.3.tgz", 119 | "integrity": "sha1-zkZxf8jW+QHFGR5pSFyImgNqhnQ=", 120 | "optional": true 121 | }, 122 | "safe-buffer": { 123 | "version": "5.1.1", 124 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 125 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 126 | }, 127 | "source-map": { 128 | "version": "0.5.6", 129 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", 130 | "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" 131 | }, 132 | "source-map-support": { 133 | "version": "0.4.15", 134 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", 135 | "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", 136 | "requires": { 137 | "source-map": "0.5.6" 138 | } 139 | }, 140 | "stack-trace": { 141 | "version": "0.0.10", 142 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 143 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" 144 | }, 145 | "strip-ansi": { 146 | "version": "3.0.1", 147 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 148 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 149 | "requires": { 150 | "ansi-regex": "2.1.1" 151 | } 152 | }, 153 | "supports-color": { 154 | "version": "2.0.0", 155 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 156 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" 157 | }, 158 | "sylphy": { 159 | "version": "github:pyraxo/sylphy#75d772d1139d745263644e30d31b48ed0059bce0", 160 | "requires": { 161 | "eris": "github:abalabahaha/eris#39733fc6fadd8bf648bf713e5e5f990809e03849" 162 | } 163 | }, 164 | "tweetnacl": { 165 | "version": "1.0.0", 166 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", 167 | "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=", 168 | "optional": true 169 | }, 170 | "ultron": { 171 | "version": "1.1.0", 172 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", 173 | "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" 174 | }, 175 | "winston": { 176 | "version": "2.3.1", 177 | "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", 178 | "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", 179 | "requires": { 180 | "async": "1.0.0", 181 | "colors": "1.0.3", 182 | "cycle": "1.0.3", 183 | "eyes": "0.1.8", 184 | "isstream": "0.1.2", 185 | "stack-trace": "0.0.10" 186 | } 187 | }, 188 | "winston-daily-rotate-file": { 189 | "version": "1.4.6", 190 | "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-1.4.6.tgz", 191 | "integrity": "sha1-8gS2raGaU4b99S/pl9jhDkP/d4g=" 192 | }, 193 | "ws": { 194 | "version": "3.1.0", 195 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.1.0.tgz", 196 | "integrity": "sha512-TU4/qKFlyQFqNITNWiqPCUY9GqlAhEotlzfcZcve6VT1YEngQl1dDMqwQQS3eMYruJ5r/UD3lcsWib6iVMDGDw==", 197 | "requires": { 198 | "safe-buffer": "5.1.1", 199 | "ultron": "1.1.0" 200 | } 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yui", 3 | "description": "Discord bot core", 4 | "version": "1.0.0", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/pyraxo/yui.git" 12 | }, 13 | "keywords": [ 14 | "discord", 15 | "bot", 16 | "commands", 17 | "core", 18 | "middleware", 19 | "modules", 20 | "selfbot" 21 | ], 22 | "author": "pyraxo (https://pyraxo.moe)", 23 | "license": "AGPL-3.0", 24 | "bugs": { 25 | "url": "https://github.com/pyraxo/yui/issues" 26 | }, 27 | "homepage": "https://github.com/pyraxo/yui#readme", 28 | "dependencies": { 29 | "bluebird": "^3.4.7", 30 | "chalk": "^1.1.3", 31 | "dotenv-safe": "^4.0.3", 32 | "eventemitter3": "^2.0.2", 33 | "longjohn": "^0.2.11", 34 | "moment": "^2.17.1", 35 | "moment-duration-format": "^1.3.0", 36 | "sylphy": "github:pyraxo/sylphy", 37 | "winston": "^2.3.0", 38 | "winston-daily-rotate-file": "^1.4.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /res/i18n/en/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": { 3 | "INSUFFICIENT_ARGS": "insufficient arguments supplied - {{requiredArgs}} expected, but only {{argsCount}} found.", 4 | "NO_END_QUOTE": "you have a missing end quote.", 5 | "ON_COOLDOWN": "please cool down! ({{time}} seconds left)", 6 | "NO_PERMS": "you need the permissions {{perms}} to run this command!", 7 | "NO_PERMS_BOT": "I need the permissions {{perms}} to run this command!", 8 | "NO_PMS": "this command can't be run in PMs.", 9 | "member": { 10 | "NOT_FOUND": "the member could not be found" 11 | }, 12 | "channel": { 13 | "NOT_FOUND": "the channel could not be found" 14 | }, 15 | "command": { 16 | "NOT_FOUND": "the command could not be found" 17 | }, 18 | "group": { 19 | "NOT_FOUND": "the command group could not be found" 20 | }, 21 | "role": { 22 | "NOT_FOUND": "the role could not be found" 23 | }, 24 | "string": { 25 | "NOT_STRING": "{{arg}} must be a string", 26 | "MAX": "{{arg}} length cannot be more than {{max}}", 27 | "MIN": "{{arg}} length cannot be less than {{min}}", 28 | "ONE_OF": "{{arg}} must be one of the following" 29 | }, 30 | "list": { 31 | "MAX": "{{arg}} length cannot contain more than {{max}} items", 32 | "MIN": "{{arg}} length cannot contain less than {{min}} items", 33 | "MAX_LENGTH": "{{arg}} cannot contain items longer than {{maxLength}}", 34 | "MIN_LENGTH": "{{arg}} cannot contain items shorter than {{minLength}}", 35 | "DUPES": "{{arg}} cannot contain duplicate values" 36 | }, 37 | "int": { 38 | "NOT_INT": "{{arg}} is not an integer", 39 | "MAX": "{{arg}} must be less than or equals to {{max}}", 40 | "MIN": "{{arg}} must be more than or equals to {{min}}" 41 | } 42 | }, 43 | "menus": { 44 | "EXIT": "Enter {{cancel}} to exit the menu.", 45 | "ERRORED": "the menu has closed:", 46 | "EXITED": "you have exited the menu.", 47 | "SELECTION": "Selection Menu", 48 | "ERROR": "Unknown Error", 49 | "INPUT": "Type the number of your choice into chat or '{{cancel}}' to cancel.", 50 | "MORE_RESULTS": "And {{num}} more..." 51 | }, 52 | "collector": { 53 | "timeout": "Timeout after {{timeout}}s", 54 | "max": "Exceeded {{max}} tries", 55 | "maxMatches": "Exceeded {{maxMatches}} matches" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/bot.js: -------------------------------------------------------------------------------- 1 | require('winston-daily-rotate-file') 2 | require('moment-duration-format') 3 | 4 | const path = require('path') 5 | const chalk = require('chalk') 6 | const winston = require('winston') 7 | const moment = require('moment') 8 | const util = require('util') 9 | const { Client } = require('sylphy') 10 | 11 | const resolve = (str) => path.join('src', str) 12 | 13 | const processID = parseInt(process.env['PROCESS_ID'], 10) 14 | const processShards = parseInt(process.env['SHARDS_PER_PROCESS'], 10) 15 | const firstShardID = processID * processShards 16 | const lastShardID = firstShardID + processShards - 1 17 | 18 | const logger = new (winston.Logger)({ 19 | transports: [ 20 | new (winston.transports.Console)({ 21 | level: 'silly', 22 | colorize: true, 23 | label: processShards > 1 ? `C ${firstShardID}-${lastShardID}` : `C ${processID}`, 24 | timestamp: () => `[${chalk.grey(moment().format('HH:mm:ss'))}]` 25 | }), 26 | new (winston.transports.DailyRotateFile)({ 27 | colorize: false, 28 | datePattern: '.yyyy-MM-dd', 29 | prepend: true, 30 | json: false, 31 | formatter: function ({ level, message = '', meta = {}, formatter, depth, colorize }) { 32 | const timestamp = moment().format('YYYY-MM-DD hh:mm:ss a') 33 | const obj = Object.keys(meta).length 34 | ? `\n\t${meta.stack ? meta.stack : util.inspect(meta, false, depth || null, colorize)}` 35 | : '' 36 | return `${timestamp} ${level.toUpperCase()} ${chalk.stripColor(message)} ${obj}` 37 | }, 38 | filename: path.join(process.cwd(), `logs/shard-${processID}.log`), 39 | }) 40 | ] 41 | }) 42 | 43 | const bot = new Client({ 44 | token: process.env['CLIENT_TOKEN'], 45 | prefix: process.env['CLIENT_PREFIX'], 46 | modules: resolve('modules'), 47 | locales: path.resolve('res', 'i18n'), 48 | messageLimit: 0, 49 | getAllUsers: true, 50 | disableEveryone: true, 51 | maxShards: processShards * parseInt(process.env['PROCESS_COUNT'], 10), 52 | firstShardID, 53 | lastShardID 54 | }) 55 | 56 | bot.on('commander:registered', ({ trigger, group, aliases } = {}) => 57 | bot.logger.debug(`Command '${trigger}' in group '${group}' registered with ${aliases} aliases`) 58 | ) 59 | 60 | bot 61 | .unregister('logger', 'console') // use custom winston console transport 62 | .register('logger', 'winston', logger) 63 | .unregister('middleware', true) // use custom middleware 64 | .register('middleware', resolve('middleware')) 65 | .register('commands', resolve('commands'), { groupedCommands: true }) 66 | 67 | bot.on('ready', () => { 68 | const guilds = bot.guilds.size 69 | const users = bot.users.size 70 | const channels = Object.keys(bot.channelGuildMap).length 71 | 72 | bot.logger.info(`${chalk.red.bold(bot.user.username)} - ${ 73 | firstShardID === lastShardID 74 | ? `Shard ${firstShardID} is ready!` 75 | : `Shards ${firstShardID} to ${lastShardID} are ready!` 76 | }`) 77 | bot.logger.info( 78 | `G: ${chalk.green.bold(guilds)} | ` + 79 | `C: ${chalk.green.bold(channels)} | ` + 80 | `U: ${chalk.green.bold(users)}` 81 | ) 82 | bot.logger.info(`Prefix: ${chalk.cyan.bold(bot.prefix)}`) 83 | }) 84 | 85 | bot.on('error', err => bot.logger.error(err)) 86 | 87 | bot.run() 88 | -------------------------------------------------------------------------------- /src/commands/core/ping.js: -------------------------------------------------------------------------------- 1 | const { Command } = require('sylphy') 2 | 3 | class Ping extends Command { 4 | constructor (...args) { 5 | super(...args, { 6 | name: 'ping', 7 | description: 'Pong!', 8 | options: { hidden: true } 9 | }) 10 | } 11 | 12 | handle ({ msg }, responder) { 13 | return responder.format('emoji:info').send('Pong!').then(m => 14 | m.edit(`${m.content} - Time taken: **${m.timestamp - msg.timestamp}ms**`) 15 | .catch(this.logger.error) 16 | ) 17 | } 18 | } 19 | 20 | module.exports = Ping 21 | -------------------------------------------------------------------------------- /src/commands/test/trial.js: -------------------------------------------------------------------------------- 1 | const { Command } = require('sylphy') 2 | 3 | class TT extends Command { 4 | constructor (...args) { 5 | super(...args, { 6 | name: 'try', 7 | description: 'What!', 8 | options: { hidden: true } 9 | }) 10 | } 11 | 12 | async handle ({ msg, args }, responder) { 13 | const dialog = await responder.dialog([{ 14 | prompt: 'channel???', 15 | input: { name: 'response', type: 'channel', bot: false } 16 | }]) 17 | console.log(dialog) 18 | } 19 | } 20 | 21 | module.exports = TT 22 | -------------------------------------------------------------------------------- /src/middleware/logger.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | 3 | module.exports = { 4 | priority: 5, 5 | process: container => { 6 | const { client, msg, commands, logger, isPrivate, isCommand } = container 7 | if (!isCommand) return Promise.resolve() 8 | logger.info( 9 | `${chalk.bold.magenta( 10 | !isPrivate 11 | ? msg.channel.guild.name 12 | : '(in PMs)' 13 | )} > ${chalk.bold.green(msg.author.username)}: ` + 14 | `${chalk.bold.blue(msg.cleanContent.replace(/\n/g, ' '))}` 15 | ) 16 | 17 | return Promise.resolve(container) 18 | } 19 | } -------------------------------------------------------------------------------- /src/middleware/parseMessage.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | priority: 2, 3 | process: container => { 4 | const { client, msg, commands } = container 5 | const isPrivate = container.isPrivate = !msg.channel.guild 6 | const prefix = container.prefix = process.env['CLIENT_PREFIX'] 7 | 8 | if (!msg.content.startsWith(prefix)) return Promise.resolve() 9 | 10 | const rawArgs = msg.content.substring(prefix.length).split(' ') 11 | const trigger = container.trigger = rawArgs[0].toLowerCase() 12 | container.isCommand = commands.has(trigger) 13 | container.rawArgs = rawArgs.slice(1).filter(v => !!v) 14 | 15 | return Promise.resolve(container) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/selfbot.js: -------------------------------------------------------------------------------- 1 | require('winston-daily-rotate-file') 2 | require('moment-duration-format') 3 | 4 | const path = require('path') 5 | const chalk = require('chalk') 6 | const winston = require('winston') 7 | const moment = require('moment') 8 | const { Client } = require('sylphy') 9 | 10 | const resolve = (str) => path.join('src', str) 11 | 12 | const logger = new (winston.Logger)({ 13 | transports: [ 14 | new (winston.transports.Console)({ 15 | level: 'silly', 16 | colorize: true, 17 | timestamp: () => `[${chalk.grey(moment().format('HH:mm:ss'))}]` 18 | }), 19 | new (winston.transports.DailyRotateFile)({ 20 | colorize: false, 21 | datePattern: '.yyyy-MM-dd', 22 | prepend: true, 23 | json: false, 24 | formatter: function ({ level, message = '', meta = {}, formatter, depth, colorize }) { 25 | const timestamp = moment().format('YYYY-MM-DD hh:mm:ss a') 26 | const obj = Object.keys(meta).length 27 | ? `\n\t${meta.stack ? meta.stack : util.inspect(meta, false, depth || null, colorize)}` 28 | : '' 29 | return `${timestamp} ${level.toUpperCase()} ${chalk.stripColor(message)} ${obj}` 30 | }, 31 | filename: path.join(process.cwd(), `logs/shard-${process.env['PROCESS_ID']}.log`), 32 | }) 33 | ] 34 | }) 35 | 36 | const bot = new Client({ 37 | token: process.env['CLIENT_TOKEN'], 38 | prefix: process.env['CLIENT_PREFIX'], 39 | modules: resolve('modules'), 40 | locales: path.resolve('res', 'i18n'), 41 | messageLimit: 0, 42 | getAllUsers: true, 43 | disableEveryone: true, 44 | selfbot: true 45 | }) 46 | 47 | bot.on('commander:registered', ({ trigger, group, aliases } = {}) => 48 | bot.logger.debug(`Command '${trigger}' in group '${group}' registered with ${aliases} aliases`) 49 | ) 50 | 51 | bot 52 | .unregister('logger', 'console') // use custom winston console transport 53 | .register('logger', 'winston', logger) 54 | .unregister('middleware', true) // use custom middleware 55 | .register('middleware', resolve('middleware')) 56 | .register('commands', resolve('commands'), { groupedCommands: true }) 57 | 58 | bot.on('ready', () => { 59 | const guilds = bot.guilds.size 60 | const users = bot.users.size 61 | const channels = Object.keys(bot.channelGuildMap).length 62 | 63 | bot.logger.info(`${chalk.red.bold(bot.user.username)} is ready!`) 64 | bot.logger.info( 65 | `G: ${chalk.green.bold(guilds)} | ` + 66 | `C: ${chalk.green.bold(channels)} | ` + 67 | `U: ${chalk.green.bold(users)}` 68 | ) 69 | bot.logger.info(`Prefix: ${chalk.cyan.bold(bot.prefix)}`) 70 | }) 71 | 72 | bot.on('error', err => bot.logger.error(err)) 73 | 74 | bot.run() 75 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | ansi-regex@^2.0.0: 4 | version "2.1.1" 5 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 6 | 7 | ansi-styles@^2.2.1: 8 | version "2.2.1" 9 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 10 | 11 | async@~1.0.0: 12 | version "1.0.0" 13 | resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" 14 | 15 | bluebird@^3.4.7: 16 | version "3.4.7" 17 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" 18 | 19 | chalk@^1.1.3: 20 | version "1.1.3" 21 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 22 | dependencies: 23 | ansi-styles "^2.2.1" 24 | escape-string-regexp "^1.0.2" 25 | has-ansi "^2.0.0" 26 | strip-ansi "^3.0.0" 27 | supports-color "^2.0.0" 28 | 29 | colors@1.0.x: 30 | version "1.0.3" 31 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" 32 | 33 | cycle@1.0.x: 34 | version "1.0.3" 35 | resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" 36 | 37 | dotenv-safe@^4.0.3: 38 | version "4.0.3" 39 | resolved "https://registry.yarnpkg.com/dotenv-safe/-/dotenv-safe-4.0.3.tgz#3c98f69f6072f7b2d0df120a65add27ac2550029" 40 | dependencies: 41 | dotenv "^4.0.0" 42 | 43 | dotenv@^4.0.0: 44 | version "4.0.0" 45 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" 46 | 47 | "eris@github:abalabahaha/eris#dev": 48 | version "0.5.2" 49 | resolved "https://codeload.github.com/abalabahaha/eris/tar.gz/20ddd9eec212a5b833b2d27e4fc9ee24820970a6" 50 | dependencies: 51 | ws "^1.1.1" 52 | optionalDependencies: 53 | opusscript "0.0.1" 54 | tweetnacl "^0.14.5" 55 | 56 | escape-string-regexp@^1.0.2: 57 | version "1.0.5" 58 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 59 | 60 | eventemitter3@^2.0.2: 61 | version "2.0.2" 62 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.2.tgz#20ce4891909ce9f35b088c94fab40e2c96f473ac" 63 | 64 | eyes@0.1.x: 65 | version "0.1.8" 66 | resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" 67 | 68 | has-ansi@^2.0.0: 69 | version "2.0.0" 70 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 71 | dependencies: 72 | ansi-regex "^2.0.0" 73 | 74 | isstream@0.1.x: 75 | version "0.1.2" 76 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 77 | 78 | longjohn@^0.2.11: 79 | version "0.2.12" 80 | resolved "https://registry.yarnpkg.com/longjohn/-/longjohn-0.2.12.tgz#7ca7446b083655c377e7512213dc754d52a64a7e" 81 | dependencies: 82 | source-map-support "0.3.2 - 1.0.0" 83 | 84 | moment-duration-format@^1.3.0: 85 | version "1.3.0" 86 | resolved "https://registry.yarnpkg.com/moment-duration-format/-/moment-duration-format-1.3.0.tgz#541771b5f87a049cc65540475d3ad966737d6908" 87 | 88 | moment@^2.17.1: 89 | version "2.17.1" 90 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" 91 | 92 | options@>=0.0.5: 93 | version "0.0.6" 94 | resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" 95 | 96 | opusscript@^0.0.2: 97 | version "0.0.2" 98 | resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.2.tgz#5fdd7274c13991fd96f64320e69ad56f5b0b9bcd" 99 | 100 | "source-map-support@0.3.2 - 1.0.0": 101 | version "0.4.11" 102 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" 103 | dependencies: 104 | source-map "^0.5.3" 105 | 106 | source-map@^0.5.3: 107 | version "0.5.6" 108 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 109 | 110 | stack-trace@0.0.x: 111 | version "0.0.9" 112 | resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" 113 | 114 | strip-ansi@^3.0.0: 115 | version "3.0.1" 116 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 117 | dependencies: 118 | ansi-regex "^2.0.0" 119 | 120 | supports-color@^2.0.0: 121 | version "2.0.0" 122 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 123 | 124 | sylphy@^0.3.4: 125 | version "0.3.6" 126 | resolved "https://registry.yarnpkg.com/sylphy/-/sylphy-0.3.6.tgz#4ad4defe25b6eabade0a7b7820bf1e67476e8ac9" 127 | dependencies: 128 | eris "github:abalabahaha/eris#dev" 129 | 130 | tweetnacl@^0.14.5: 131 | version "0.14.5" 132 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 133 | 134 | ultron@1.0.x: 135 | version "1.0.2" 136 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" 137 | 138 | winston-daily-rotate-file@^1.4.2: 139 | version "1.4.4" 140 | resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-1.4.4.tgz#3aecb5eb6ac9e309f5635524ff8f739037bd99a7" 141 | 142 | winston@^2.3.0: 143 | version "2.3.1" 144 | resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.1.tgz#0b48420d978c01804cf0230b648861598225a119" 145 | dependencies: 146 | async "~1.0.0" 147 | colors "1.0.x" 148 | cycle "1.0.x" 149 | eyes "0.1.x" 150 | isstream "0.1.x" 151 | stack-trace "0.0.x" 152 | 153 | ws@^1.1.1: 154 | version "1.1.1" 155 | resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" 156 | dependencies: 157 | options ">=0.0.5" 158 | ultron "1.0.x" 159 | 160 | --------------------------------------------------------------------------------