├── .eslintignore ├── permissions ├── Member.js └── Owner.js ├── events └── example.js ├── functions ├── snippets │ └── example.js ├── observers │ └── prefixHelp.js └── engines │ └── checkUpdate.js ├── commands ├── reboot.js ├── ping.js ├── about.js ├── reload.js └── help.js ├── .gitattributes ├── .travis.yml ├── src ├── dataStore.js ├── module_classes │ ├── Snippet.js │ ├── Permission.js │ ├── Event.js │ ├── Observer.js │ ├── Engine.js │ └── Command.js ├── DisableCache.js ├── search_files │ ├── loadSnippet.js │ ├── loadPermission.js │ ├── loadEngines.js │ ├── loadCommands.js │ ├── loadObserver.js │ └── loadEvent.js ├── confirmConfig.js ├── CustomConfig.js ├── search.js └── start.js ├── package.json ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── LICENSE ├── README.md ├── CONTRIBUTING.md ├── .npmignore ├── .gitignore ├── test └── test.js ├── app.js └── .eslintrc.js /.eslintignore: -------------------------------------------------------------------------------- 1 | test/ 2 | -------------------------------------------------------------------------------- /permissions/Member.js: -------------------------------------------------------------------------------- 1 | const Spark = require("../") 2 | const Permission = Spark.permission("Member", {level: 0}) 3 | Permission.code = () => { 4 | 5 | return false; 6 | } 7 | 8 | module.exports = Permission 9 | -------------------------------------------------------------------------------- /events/example.js: -------------------------------------------------------------------------------- 1 | const Spark = require("../"); 2 | const Event = Spark.event("example") 3 | 4 | Event.event = "debug"; 5 | 6 | var debug = false; 7 | Event.code = (Client, data) => { 8 | if (debug) {console.log(data)} 9 | } 10 | 11 | module.exports = Event; 12 | -------------------------------------------------------------------------------- /functions/snippets/example.js: -------------------------------------------------------------------------------- 1 | const Spark = require("../../"); 2 | const Snippet = Spark.snippet("example") 3 | 4 | Snippet.code = () => { 5 | console.log("This is an example snippet, you can use this like a global function throughout your entire code.") 6 | } 7 | 8 | module.exports = Snippet; 9 | -------------------------------------------------------------------------------- /permissions/Owner.js: -------------------------------------------------------------------------------- 1 | const Spark = require("../") 2 | const Permission = Spark.permission("Owner", {level: 10}) 3 | Permission.code = (client, message) => { 4 | if (client.config.ownerID !== message.author.id) { 5 | return true 6 | } 7 | return false; 8 | 9 | } 10 | 11 | module.exports = Permission 12 | -------------------------------------------------------------------------------- /commands/reboot.js: -------------------------------------------------------------------------------- 1 | /* eslint no-process-exit: 0*/ 2 | var Spark = require("../") 3 | const Command = Spark.command("reboot") 4 | 5 | Command.addAlias("restart") 6 | Command.setLevel(10) 7 | Command.setDescription("Restart your bot.") 8 | 9 | Command.code = async (client, message) => { 10 | await message.channel.send("Rebooting your bot..."); 11 | process.exit(); 12 | } 13 | module.exports = Command; 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /commands/ping.js: -------------------------------------------------------------------------------- 1 | var Spark = require("../") 2 | const Command = Spark.command("ping") 3 | 4 | Command.addAlias("test-alias") 5 | Command.setLevel(0) 6 | Command.allowDms(true) 7 | Command.setDescription("Test the latency between Discord's servers and the bot.") 8 | 9 | Command.code = async (client, message) => { 10 | var result = await message.channel.send("Ping!") 11 | result.edit(`Pong! | Took **${result.createdTimestamp - message.createdTimestamp}**ms.`) 12 | 13 | } 14 | module.exports = Command; 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | - "8" 5 | - "9" 6 | 7 | install: npm install 8 | script: node app 9 | jobs: 10 | include: 11 | - stage: ESLint 12 | node_js: "8" 13 | script: npm test 14 | - stage: Mocha 15 | node_js: "8" 16 | script: npm run mocha-test 17 | 18 | matrix: 19 | allow_failures: 20 | - node_js: "7" 21 | 22 | notifications: 23 | webhooks: 24 | urls: 25 | - https://api.discordspark.com/travis 26 | on_success: always 27 | on_failure: always 28 | on_start: always 29 | on_cancel: always 30 | on_error: always 31 | email: false 32 | -------------------------------------------------------------------------------- /src/dataStore.js: -------------------------------------------------------------------------------- 1 | /* eslint class-methods-use-this: ["error", { "exceptMethods": ["filter"] }] */ 2 | 3 | module.exports = class DataStore extends Map { 4 | 5 | filter(func) { 6 | const data = new DataStore() 7 | this.forEach((value, key) => { 8 | if (func(value, key)) {data.set(key, value)} 9 | }) 10 | return data 11 | } 12 | 13 | map(func) { 14 | const array = new Array(this.size); 15 | let nr = 0; 16 | this.forEach((value, key) => { 17 | array[nr] = func(value, key) 18 | nr = nr + 1 19 | }) 20 | return array 21 | } 22 | 23 | 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/module_classes/Snippet.js: -------------------------------------------------------------------------------- 1 | module.exports = function(client) { 2 | return class Snippet { 3 | 4 | constructor(name, options) { 5 | this.name = name; 6 | if (!options) {options = {}} 7 | this.options = options 8 | this.client = client 9 | this.disabled = options.disabled 10 | if (this.disabled) { 11 | this.client.config.disabled.add("snippets", this.name) 12 | } 13 | 14 | } 15 | 16 | disable() { 17 | this.client.config.disabled.add("snippets", this.name) 18 | } 19 | 20 | export (module) { 21 | module.exports = this; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/module_classes/Permission.js: -------------------------------------------------------------------------------- 1 | module.exports = function(client) { 2 | return class Permission { 3 | 4 | constructor(name, options) { 5 | this.name = name; 6 | if (!options) {options = {}} 7 | this.options = options 8 | this.client = client 9 | this.level = (options.level || 0) 10 | this.disabled = options.disabled 11 | if (this.disabled) { 12 | this.client.config.disabled.add("permissions", this.name) 13 | } 14 | 15 | } 16 | disable() { 17 | this.client.config.disabled.add("permissions", this.name) 18 | } 19 | setLevel(level) { 20 | if (typeof level != "number") { 21 | return console.log("To set a level, use a number") 22 | } 23 | this.level = level; 24 | } 25 | export (module) { 26 | module.exports = this; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/module_classes/Event.js: -------------------------------------------------------------------------------- 1 | module.exports = function(client) { 2 | return class Event { 3 | 4 | constructor(name, options) { 5 | this.name = name; 6 | this.options = options 7 | this.client = client 8 | if (!options) { 9 | options = {} 10 | } 11 | this.event = options.event 12 | this.disabled = options.disabled 13 | if (this.disabled) { 14 | this.client.config.disabled.add("events", this.name) 15 | } 16 | 17 | } 18 | 19 | disable() { 20 | this.client.config.disabled.add("events", this.name) 21 | } 22 | 23 | setEvent(event) { 24 | if (!event || typeof event != "string") { 25 | console.error(this.name + " | Error on function setEvent: | Please use a string") 26 | } else { 27 | this.event = event 28 | } 29 | } 30 | export (module) { 31 | module.exports = this; 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sparkbots", 3 | "version": "0.1.0", 4 | "description": "Spark is a powerful modular framework that makes creating Discord bots easy.", 5 | "main": "app.js", 6 | "dependencies": { 7 | "chalk": "^2.3.0", 8 | "discord.js": "11.3.2", 9 | "fs-extra": "^5.0.0", 10 | "request": "latest", 11 | "request-promise": "^4.2.2", 12 | "socket.io-client": "^2.0.4" 13 | }, 14 | "devDependencies": { 15 | "chai": "^4.1.2", 16 | "eslint": "^4.18.0", 17 | "mocha": "^5.0.0" 18 | }, 19 | "scripts": { 20 | "test": "./node_modules/.bin/eslint .", 21 | "mocha-test": "./node_modules/.bin/mocha test/test.js" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/TobiasFeld22/Spark.git" 26 | }, 27 | "keywords": [ 28 | "discord", 29 | "nodejs", 30 | "spark" 31 | ], 32 | "author": "Tobias Feld (tobias.feld@hotmail.com)", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/TobiasFeld22/Spark/issues" 36 | }, 37 | "homepage": "https://github.com/TobiasFeld22/Spark#readme", 38 | "lock": false 39 | } 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Spark 4 | 5 | --- 6 | 7 | #### **Bug information** 8 | Please describe what this bug includes. 9 | 10 | 11 | #### **To Reproduce** 12 | Steps to reproduce the behavior: 13 | 1. Do this: "" 14 | 2. Do that: "" 15 | 3. See this unexpected behaviour happen 16 | 17 | #### **Expected behavior** 18 | Be clear on what you expected to happen. 19 | 20 | 21 | > **Side note:** 22 | > Make sure a complete idiot could follow these steps and expected behaviours to make sure everyone can quickly and easily find out how to fix this bug. 23 | >(you can remove this part when submitting) 24 | 25 | 26 | #### **Screenshots** 27 | upload or drag relevant screenshots and pictures to show how this bug. 28 | 29 | #### **Supporting information:** 30 | - OS: [Windows, Mac Os, Linux] ... 31 | - Version [0.1] ... 32 | If you're on a development build: 33 | - git hash: ... 34 | 35 | 36 | #### **Additional context** 37 | Add any other context about the problem here. 38 | 39 | 40 | #### **On a realistic scale from 1 - 3 (1 is high, 3 low), what is the priority for this bug and why?** 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Tobias Feld (tobias.feld@hotmail.com) 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![header](https://cdn.discordapp.com/attachments/237019716546199552/432200563485179906/banner-outlined-no-bg4x.png) 2 | ## Spark is a powerful modular framework that makes creating Discord bots easy 3 | 4 | [![Discord](https://discordapp.com/api/guilds/248505281741455360/embed.png)](https://discord.gg/TezD2Zg) 5 | [![npm](https://api.discordspark.com/badge/npm)](https://npmjs.com/sparkbots) 6 | [![Build Status](https://api.travis-ci.org/Sparkbots/Spark.svg?branch=Stable)](https://travis-ci.org/TobiasFeld22/Spark)
7 | 8 | 9 | ##### About Spark. 10 | Spark is a framework created so everyone can easily make powerful modular bots. 11 | Spark handles the heavy work in the background so you can work on your own commands and data. 12 | We promote sharing modules you have made so other people can use these to learn and create their own bots. 13 | 14 | We are always into people wanting to help out or having some fun, which can be done in our Discord server: https://discord.gg/TezD2Zg 15 | 16 | Get ready to dive into Spark and learn how to set it up! 17 | 18 | [![Get_started](https://cdn.discordapp.com/attachments/237019716546199552/432194740801241089/unknown.png)](https://discordspark.com/documentation/intro/) 19 | -------------------------------------------------------------------------------- /src/module_classes/Observer.js: -------------------------------------------------------------------------------- 1 | module.exports = function(client) { 2 | return class Observer { 3 | 4 | constructor(name, options) { 5 | this.name = name; 6 | this.options = options 7 | this.client = client 8 | if (!options) { 9 | options = {} 10 | } 11 | if (options.type) { 12 | this.type = options.type 13 | } 14 | this.disabled = options.disabled 15 | if (this.disabled) { 16 | this.client.config.disabled.add("observers", this.name) 17 | } 18 | 19 | } 20 | 21 | disable() { 22 | this.disabled = true 23 | this.client.config.disabled.add("observers", this.name) 24 | } 25 | 26 | setType(type) { 27 | if (!type || typeof type != "string" || ![ 28 | "message", 29 | "command", 30 | "all" 31 | ].includes(type)) { 32 | console.error(this.name + " | Error on function setType: | Please use one of these 3 types: \"message\" \"command\" \"all\"") 33 | this.type = "all" 34 | } else { 35 | this.type = type 36 | } 37 | 38 | 39 | } 40 | export (module) { 41 | module.exports = this; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/module_classes/Engine.js: -------------------------------------------------------------------------------- 1 | module.exports = function(client) { 2 | return class Engine { 3 | constructor(name, options) { 4 | this.name = name; 5 | this.options = options 6 | this.client = client 7 | if (!options) { 8 | options = {} 9 | } 10 | this.time = options.time 11 | this.delay = options.delay 12 | this.disabled = options.disabled 13 | if (this.disabled) { 14 | this.client.config.disabled.add("engine", this.name) 15 | } 16 | } 17 | 18 | 19 | setTime(nr) { 20 | if (!nr || typeof nr != "number") { 21 | console.error(this.name + " | Error on function setTime: | Please use a number that's greater then 0") 22 | } else { 23 | this.time = nr 24 | } 25 | } 26 | 27 | setDelay(nr) { 28 | if (!nr || typeof nr != "number") { 29 | console.error(this.name + " | Error on function setDelay: | Please use a number that's greater then 0") 30 | } else { 31 | this.delay = nr 32 | } 33 | } 34 | 35 | disable() { 36 | this.client.config.disabled.add("engines", this.name) 37 | } 38 | 39 | export (module) { 40 | module.exports = this; 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to Spark 2 | 3 | We want to make it easy for you to help with developing, we just want to make sure of a few things. 4 | 5 | 1. All code is examined using eslint (`npm install eslint && eslint .`), using our configuration file included inside of the repository. 6 | 2. Malicious code is not allowed, deliberately adding bugs or causing (parts of) the framework to crash. 7 | 3. All code submitted must be "beautified" before posting, if you want to keep it simple, just use [this one](http://jsbeautifier.org) 8 | 4. Never submit a pull request to the master branch. This is reserved for new updates. 9 | 5. Please test your code before sending it off and trying to pr, use `npm test` and it will try to test with Eslint. 10 | 11 | ## Submitting a new issue 12 | 13 | Before submitting a new issue: 14 | 15 | - Search the issues to see if your issue hasn't been added before, (and if it has a fix already.) 16 | - No issues about external modules used for commands etc., we will only look at the issue if the cause of the issue lies within the framework's code. Contact the developer that made the module for more information. 17 | - No issues asking us for help on how to set up a bot. You can find info about how to set a bot up on our website. If the website is not clear enough, create an issue and tell us what should be made easier to understand for other users. 18 | - Don't add "me 2" or something like that in the comments. You can react with :thumbsup: on the initial issue to show us. 19 | -------------------------------------------------------------------------------- /src/DisableCache.js: -------------------------------------------------------------------------------- 1 | module.exports = class DisableCache { 2 | 3 | constructor(initial) { 4 | this.commands = []; 5 | this.observers = []; 6 | this.engines = []; 7 | this.snippets = []; 8 | this.permissions = []; 9 | this.events = []; 10 | 11 | if (initial.commands && initial.commands.length > 0) { 12 | initial.commands.forEach(i => this.add("commands", i)) 13 | } 14 | if (initial.observers && initial.observers.length > 0) { 15 | initial.observers.forEach(i => this.add("observers", i)) 16 | } 17 | if (initial.engines && initial.engines.length > 0) { 18 | initial.engines.forEach(i => this.add("engines", i)) 19 | } 20 | if (initial.events && initial.events.length > 0) { 21 | initial.events.forEach(i => this.add("events", i)) 22 | } 23 | if (initial.permissions && initial.permissions.length > 0) { 24 | initial.permissions.forEach(i => this.add("permissions", i)) 25 | } 26 | if (initial.snippets && initial.snippets.length > 0) { 27 | initial.snippets.forEach(i => this.add("snippets", i)) 28 | } 29 | } 30 | 31 | has(type, name) { 32 | return this[type].indexOf(name) != -1 33 | } 34 | 35 | add(type, name) { 36 | this[type].push(name) 37 | } 38 | 39 | remove(type, name) { 40 | var nr = this[type].indexOf(name) 41 | if (nr != -1) { 42 | this[type].splice(nr, 1) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /functions/observers/prefixHelp.js: -------------------------------------------------------------------------------- 1 | /* eslint prefer-destructuring: 0 */ 2 | var Spark = require("../../") 3 | const observer = Spark.observer("prefixHelp") 4 | observer.setType("message") 5 | 6 | observer.code = (client, message) => { 7 | var first = message.content; 8 | if (message.content.includes(" ") > 0) { 9 | return 10 | } 11 | first = first.match(/<@!?[0-9]+>/g) 12 | if (first) { 13 | if (client.user.id == first[0].replace(/<@!?/, "").slice(0, -1)) { 14 | prefixHelp(client, message) 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | module.exports = observer; 21 | 22 | function prefixHelp(client, message) { 23 | if (client.customConfig.has(message.guild.id)) { 24 | var {prefix} = client.customConfig.get(message.guild.id) 25 | 26 | if (typeof prefix == "string") { 27 | message.channel.send("My prefix is: `" + prefix + "`") 28 | return false; 29 | } else if (typeof prefix == "object" && prefix.constructor.name == "Array") { 30 | if (prefix.length == 1) { 31 | message.channel.send("My prefix is: `" + prefix[0] + "`") 32 | return false; 33 | } 34 | message.channel.send("My prefixes are: " + prefix.map(i => "`" + i + "`").join(" ")) 35 | return false; 36 | } 37 | } 38 | if (client.config.prefix.length > 1) { 39 | message.channel.send("My prefixes are: " + client.config.prefix.map(i => "`" + i + "`").join(" ")) 40 | } else { 41 | message.channel.send("My prefix is: `" + client.config.prefix + "`") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 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 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directories 27 | node_modules 28 | jspm_packages 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | 36 | # ========================= 37 | # Operating System Files 38 | # ========================= 39 | 40 | # OSX 41 | # ========================= 42 | 43 | .DS_Store 44 | .AppleDouble 45 | .LSOverride 46 | 47 | # Thumbnails 48 | ._* 49 | 50 | # Files that might appear in the root of a volume 51 | .DocumentRevisions-V100 52 | .fseventsd 53 | .Spotlight-V100 54 | .TemporaryItems 55 | .Trashes 56 | .VolumeIcon.icns 57 | 58 | # Directories potentially created on remote AFP share 59 | .AppleDB 60 | .AppleDesktop 61 | Network Trash Folder 62 | Temporary Items 63 | .apdisk 64 | 65 | # Windows 66 | # ========================= 67 | 68 | # Windows image file caches 69 | Thumbs.db 70 | ehthumbs.db 71 | 72 | # Folder config file 73 | Desktop.ini 74 | 75 | # Recycle Bin used on file shares 76 | $RECYCLE.BIN/ 77 | 78 | # Windows Installer files 79 | *.cab 80 | *.msi 81 | *.msm 82 | *.msp 83 | 84 | # Windows shortcuts 85 | *.lnk 86 | 87 | # custom. 88 | config.json 89 | -------------------------------------------------------------------------------- /.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 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directories 27 | node_modules 28 | jspm_packages 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | 36 | # ========================= 37 | # Operating System Files 38 | # ========================= 39 | 40 | # OSX 41 | # ========================= 42 | 43 | .DS_Store 44 | .AppleDouble 45 | .LSOverride 46 | 47 | # Thumbnails 48 | ._* 49 | 50 | # Files that might appear in the root of a volume 51 | .DocumentRevisions-V100 52 | .fseventsd 53 | .Spotlight-V100 54 | .TemporaryItems 55 | .Trashes 56 | .VolumeIcon.icns 57 | 58 | # Directories potentially created on remote AFP share 59 | .AppleDB 60 | .AppleDesktop 61 | Network Trash Folder 62 | Temporary Items 63 | .apdisk 64 | 65 | # Windows 66 | # ========================= 67 | 68 | # Windows image file caches 69 | Thumbs.db 70 | ehthumbs.db 71 | 72 | # Folder config file 73 | Desktop.ini 74 | 75 | # Recycle Bin used on file shares 76 | $RECYCLE.BIN/ 77 | 78 | # Windows Installer files 79 | *.cab 80 | *.msi 81 | *.msm 82 | *.msp 83 | 84 | # Windows shortcuts 85 | *.lnk 86 | 87 | # custom. 88 | config.json 89 | package-lock.json 90 | -------------------------------------------------------------------------------- /src/search_files/loadSnippet.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) {data.dataStore = {}} 4 | if (!data.dataStore.functions) { 5 | data.dataStore.functions = {}; 6 | } 7 | data.dataStore.functions.snippet = new DataStore(); 8 | var temp = await data.searchInDirectories(location); 9 | var snippets = []; 10 | temp.forEach(i => { 11 | try { 12 | var temp = require(i) 13 | snippets.push({snippet: temp, location: i}) 14 | } catch (e) { 15 | console.error(`${i} | Error while loading snippet: \n ${e}`) 16 | } 17 | 18 | }) 19 | 20 | snippets.forEach(i => { 21 | var {snippet} = i 22 | if (snippet.constructor.name !== "Snippet") { 23 | console.warn(`${i.location} | Error while loading snippet: \n File is not a snippet class | See https://discordspark.com/documentation/snippets for more info.`) 24 | i = null; 25 | return; 26 | } 27 | if (typeof snippet.code != "function") { 28 | console.warn(`${i.location} | Error while loading snippet: \n No code specified. | see https://discordspark.com/documentation/snippets for more info.`) 29 | i = null; 30 | } 31 | 32 | }) 33 | snippets = snippets.filter(i => { 34 | return i != null 35 | }) 36 | snippets.forEach(i => { 37 | if (!data.dataStore.functions.snippet.has(i.snippet.name.toLowerCase())) { 38 | data.dataStore.functions.snippet.set(i.snippet.name.toLowerCase(), i) 39 | } 40 | }) 41 | return snippets 42 | } 43 | -------------------------------------------------------------------------------- /src/search_files/loadPermission.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) {data.dataStore = {}} 4 | 5 | data.dataStore.permissions = new DataStore(); 6 | var temp = await data.searchInDirectories(location); 7 | var permissions = []; 8 | temp.forEach(i => { 9 | try { 10 | var temp = require(i) 11 | permissions.push({permission: temp, location: i}) 12 | } catch (e) { 13 | console.error(`${i} | Error while loading permission: \n ${e}`) 14 | } 15 | 16 | }) 17 | 18 | permissions.forEach(i => { 19 | var {permission} = i 20 | if (permission.constructor.name !== "Permission") { 21 | console.warn(`${i.location} | Error while loading permission: \n File is not a permission class | See https://discordspark.com/documentation/permissions for more info.`) 22 | i = null; 23 | return; 24 | } 25 | if (typeof permission.level != "number") { 26 | console.warn(`${i.location} | Error while loading permission: \n No level specified | See https://discordspark.com/documentation/permissions for more info.`) 27 | i = null; 28 | } 29 | if (typeof permission.code != "function") { 30 | console.warn(`${i.location} | Error while loading permission: \n No code specified. | see https://discordspark.com/documentation/permissions for more info.`) 31 | i = null; 32 | } 33 | 34 | }) 35 | permissions = permissions.filter(i => { 36 | return i != null 37 | }) 38 | permissions.forEach(i => { 39 | if (!data.dataStore.permissions.has(i.permission.name.toLowerCase())) { 40 | data.dataStore.permissions.set(i.permission.name.toLowerCase(), i) 41 | } 42 | }) 43 | return permissions; 44 | } 45 | -------------------------------------------------------------------------------- /src/search_files/loadEngines.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) {data.dataStore = {}} 4 | if (!data.dataStore.functions) { 5 | data.dataStore.functions = {}; 6 | } 7 | data.dataStore.functions.engines = new DataStore(); 8 | var temp = await data.searchInDirectories(location); 9 | var engines = []; 10 | temp.forEach(i => { 11 | try { 12 | var temp = require(i) 13 | engines.push({engine: temp, location: i}) 14 | } catch (e) { 15 | console.error(`${i} | Error while loading engine: \n ${e}`) 16 | } 17 | }) 18 | 19 | engines.forEach(i => { 20 | var {engine} = i 21 | if (engine.constructor.name !== "Engine") { 22 | console.warn(`${i.location} | Error while loading engine: \n File is not an engine class | See https://discordspark.com/documentation/engines for more info.`) 23 | i = null; 24 | return; 25 | } 26 | if (typeof engine.time != "number" || engine.time < 0) { 27 | engine.time = 0 28 | } 29 | if (typeof engine.delay != "number" || engine.delay < 0) { 30 | engine.delay = 0 31 | } 32 | if (typeof engine.code != "function") { 33 | console.warn(`${i.location} | Error while loading engine: \n No code specified. | see https://discordspark.com/documentation/engines for more info.`) 34 | i = null; 35 | // add return if more checks are added. 36 | } 37 | 38 | }) 39 | engines = engines.filter(i => { 40 | return i != null 41 | }) 42 | engines.forEach(i => { 43 | if (!data.dataStore.functions.engines.has(i.engine.name.toLowerCase())) { 44 | data.dataStore.functions.engines.set(i.engine.name.toLowerCase(), i) 45 | } 46 | }) 47 | return engines; 48 | } 49 | -------------------------------------------------------------------------------- /src/confirmConfig.js: -------------------------------------------------------------------------------- 1 | var DisableCache = require("./DisableCache.js") 2 | var chalk = require("chalk") 3 | module.exports = (options) => { 4 | if (typeof options != "object") { 5 | return console.log(`You are trying to start without ${chalk.red("a starting object")}.\nPlease read this article:\n${chalk.blue("https://discordspark.com/documentation/intro")}`) 6 | } else if (typeof options.token != "string") { 7 | return console.log(`You are trying to start without ${chalk.red("a valid token")}.\nPlease read this article:\n${chalk.blue("https://discordspark.com/documentation/intro")}`) 8 | } 9 | if (options.disabled == null) { 10 | options.disabled = new DisableCache({}) 11 | } else if (typeof options.disabled == "object") { 12 | options.disabled = new DisableCache(options.disabled) 13 | } else { 14 | options.disabled = new DisableCache({}) 15 | } 16 | if (typeof options.prefix == "string") { 17 | if (options.prefix.includes(" ")) { 18 | return console.log(`You are trying to start without ${chalk.red("a valid prefix")}.\nPlease read this article:\n${chalk.blue("https://discordspark.com/documentation/intro")}`) 19 | } 20 | options.prefix = [options.prefix] 21 | } else if (options.prefix instanceof Array) { 22 | options.prefix.forEach(i => { 23 | if (i.includes(" ")) { 24 | return console.log(`You are trying to start without ${chalk.red("a valid prefix")}.\nPlease read this article:\n${chalk.blue("https://discordspark.com/documentation/intro")}`) 25 | } 26 | }) 27 | } else { 28 | return console.log(`You are trying to start without ${chalk.red("a valid prefix")}.\nPlease read this article:\n${chalk.blue("https://discordspark.com/documentation/intro")}`) 29 | } 30 | if (typeof options.clientOptions != "object") { 31 | options.clientOptions = {} 32 | } 33 | return true; 34 | } 35 | -------------------------------------------------------------------------------- /src/search_files/loadCommands.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) { 4 | data.dataStore = {} 5 | } 6 | data.dataStore.commands = new DataStore(); 7 | data.dataStore.aliases = new DataStore(); 8 | var tempcommands = await data.searchInDirectories(location); 9 | var commands = []; 10 | tempcommands.forEach(i => { 11 | try { 12 | var temp = require(i) 13 | commands.push({ 14 | command: temp, 15 | location: i 16 | }) 17 | } catch (e) { 18 | console.error(`${i} | Error while loading command: \n ${e}`) 19 | } 20 | 21 | }) 22 | commands = commands.filter(i => { 23 | var {command} = i 24 | if (command.constructor.name !== "Command") { 25 | console.warn(`${i.location} | Error while loading command: \n File is not a Command class | See https://discordspark.com/documentation/commands for more info.`) 26 | return false; 27 | } 28 | if (command.aliases.length > 0) { 29 | command.aliases.forEach(i => { 30 | if (!data.dataStore.aliases.has(i.name)) { 31 | data.dataStore.aliases.set(i.name, command.name.toLowerCase()) 32 | } 33 | }) 34 | } 35 | if (typeof command.code != "function") { 36 | console.warn(`${i.location} | Error while loading command: \n No code specified. | see https://discordspark.com/documentation/commands for more info.`) 37 | return false; 38 | } 39 | return true; 40 | }) 41 | commands = commands.filter(i => { 42 | return i != null 43 | }) 44 | commands.forEach(i => { 45 | if (!data.dataStore.commands.has(i.command.name.toLowerCase())) { 46 | data.dataStore.commands.set(i.command.name.toLowerCase(), i) 47 | } 48 | }) 49 | return commands; 50 | } 51 | -------------------------------------------------------------------------------- /src/search_files/loadObserver.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) { 4 | data.dataStore = {} 5 | } 6 | if (!data.dataStore.functions) { 7 | data.dataStore.functions = {}; 8 | } 9 | data.dataStore.functions.observer = new DataStore(); 10 | var temp = await data.searchInDirectories(location); 11 | var observer = []; 12 | temp.forEach(i => { 13 | try { 14 | var temp = require(i) 15 | observer.push({ 16 | observer: temp, 17 | location: i 18 | }) 19 | } catch (e) { 20 | console.error(`${i} | Error while loading observer: \n ${e}`) 21 | } 22 | 23 | }) 24 | 25 | observer.forEach(i => { 26 | var {observer} = i 27 | if (observer.constructor.name !== "Observer") { 28 | console.warn(`${i.location} | Error while loading observer: \n File is not an Observer class | See https://discordspark.com/documentation/observers for more info.`) 29 | i = null; 30 | return; 31 | } 32 | if (typeof observer.type != "string" || ![ 33 | "message", 34 | "command", 35 | "all" 36 | ].includes(observer.type)) { 37 | observer.type = "all" 38 | } 39 | if (typeof observer.code != "function") { 40 | console.warn(`${i.location} | Error while loading observer: \n No code specified. | see https://discordspark.com/documentation/observers for more info.`) 41 | i = null; 42 | // add return if more checks are added. 43 | } 44 | 45 | }) 46 | observer = observer.filter(i => { 47 | return i != null 48 | }) 49 | observer.forEach(i => { 50 | if (!data.dataStore.functions.observer.has(i.observer.name.toLowerCase())) { 51 | data.dataStore.functions.observer.set(i.observer.name.toLowerCase(), i) 52 | } 53 | }) 54 | return observer 55 | } 56 | -------------------------------------------------------------------------------- /src/search_files/loadEvent.js: -------------------------------------------------------------------------------- 1 | const DataStore = require("./../dataStore.js") 2 | module.exports = async function(data, location) { 3 | if (!data.dataStore) { 4 | data.dataStore = {} 5 | } 6 | 7 | data.dataStore.events = new DataStore(); 8 | var temp = await data.searchInDirectories(location); 9 | var events = []; 10 | temp.forEach(i => { 11 | try { 12 | var temp = require(i) 13 | events.push({ 14 | event: temp, 15 | location: i 16 | }) 17 | } catch (e) { 18 | console.error(`${i} | Error while loading event: \n ${e}`) 19 | } 20 | 21 | }) 22 | 23 | events.forEach(function(i) { 24 | var {event} = i 25 | if (event.constructor.name !== "Event") { 26 | console.warn(`${i.location} | Error while loading event: \n File is not a event class | See https://discordspark.com/docs/events for more info.`) 27 | i = null; 28 | } 29 | if (typeof event.name != "string" || event.name.length < 1) { 30 | console.warn(`${i.location} | Error while loading event: \n No event name specified | See https://discordspark.com/documentation/events for more info.`) 31 | i = null; 32 | } 33 | if (typeof event.event != "string") { 34 | console.warn(`${i.location} | Error while loading event: \n No event specified | See https://discordspark.com/documentation/events for more info.`) 35 | i = null; 36 | } 37 | if (typeof event.code != "function") { 38 | console.warn(`${i.location} | Error while loading event: \n No code specified | See https://discordspark.com/documentation/events for more info.`) 39 | i = null; 40 | } 41 | 42 | }) 43 | events = events.filter(i => { 44 | return i != null 45 | }) 46 | events.forEach(i => { 47 | if (!data.dataStore.events.has(i.event.name.toLowerCase())) { 48 | data.dataStore.events.set(i.event.name.toLowerCase(), i) 49 | } 50 | }) 51 | return events; 52 | } 53 | -------------------------------------------------------------------------------- /src/CustomConfig.js: -------------------------------------------------------------------------------- 1 | var DisableCache = require("./DisableCache.js") 2 | class CustomConfig { 3 | 4 | constructor(client, id) { 5 | this.id = id; 6 | this.client = client; 7 | this.ignoreBots = null; 8 | this.disabled = new DisableCache({}) 9 | } 10 | 11 | setPrefix(prefix) { 12 | if (typeof prefix == "string") { 13 | this.prefix = []; 14 | this.prefix.push(prefix) 15 | this.client.emit("cc_update", this) 16 | return "success" 17 | } else if (typeof prefix == "object" && prefix.constructor.name == "Array") { 18 | if (prefix.filter(i => { 19 | return typeof i == "string" 20 | }).length === prefix.length) { 21 | this.prefix = prefix; 22 | this.client.emit("cc_update", this) 23 | return "success" 24 | } 25 | throw new Error("Expected argument to be String or Array including string") 26 | 27 | } else { 28 | throw new Error("Expected argument to be String or Array including string") 29 | } 30 | } 31 | clearPrefix() { 32 | this.prefix = null; 33 | this.client.emit("cc_update", this) 34 | } 35 | setIgnoreBots(type) { 36 | if (typeof type != "string" && typeof type != "boolean") { 37 | throw new Error("Expected argument to be a string or boolean.") 38 | } 39 | if (type == true) { 40 | this.ignoreBots = 4; 41 | this.client.emit("cc_update", this) 42 | } else if (type == false) { 43 | this.ignoreBots = 0; 44 | this.client.emit("cc_update", this) 45 | } else if (type == "message") { 46 | this.ignoreBots = 1; 47 | this.client.emit("cc_update", this) 48 | } else if (type == "command") { 49 | this.ignoreBots = 2; 50 | this.client.emit("cc_update", this) 51 | } 52 | } 53 | clearIgnoreBots() { 54 | this.ignoreBots = null; 55 | this.client.emit("cc_update") 56 | } 57 | disable(type, name) { 58 | this.disabled.add(type, name) 59 | } 60 | enable(type, name) { 61 | this.disabled.remove(type, name) 62 | } 63 | } 64 | module.exports = CustomConfig 65 | -------------------------------------------------------------------------------- /src/module_classes/Command.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return class Command { 3 | 4 | constructor(name, options, client) { 5 | this.name = name; 6 | if (!options) { 7 | options = {} 8 | } 9 | this.options = options 10 | this.client = client 11 | this.aliases = [] 12 | this.level = (options.level || 0) 13 | this.helpFields = [] 14 | this.dms = false 15 | this.description = "No Description Provided" 16 | this.disabled = options.disabled 17 | if (this.disabled) { 18 | this.client.config.disabled.add("commands", this.name) 19 | } 20 | 21 | } 22 | 23 | disable() { 24 | this.client.config.disabled.add("commands", this.name) 25 | } 26 | 27 | addAlias(alias) { 28 | if (typeof alias != "string") { 29 | return console.log("Incorrect alias type, use a string") 30 | } 31 | if (this.aliases.map(i => (i.name)).indexOf == -1) { 32 | return console.log("This alias was already added.") 33 | } 34 | this.aliases.push({ 35 | name: alias, 36 | command: this 37 | }) 38 | } 39 | 40 | setLevel(level) { 41 | if (typeof level != "number") { 42 | return console.log("To set a level, use a number") 43 | } 44 | this.level = level; 45 | } 46 | 47 | allowDms(allow) { 48 | if (typeof allow != "boolean") { 49 | return console.log("To set allowDms, use a boolean") 50 | } 51 | this.dms = allow; 52 | } 53 | 54 | setDescription(description) { 55 | if (typeof description != "string") { 56 | return console.log("To set a description, use a string") 57 | } 58 | this.description = description; 59 | } 60 | addHelpField(title, desc, inline) { 61 | this.helpFields.push({ 62 | title, 63 | desc, 64 | inline 65 | }) 66 | } 67 | 68 | export (module) { 69 | module.exports = this; 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /commands/about.js: -------------------------------------------------------------------------------- 1 | var Spark = require("../") 2 | const Command = Spark.command("about") 3 | 4 | Command.setLevel(0) 5 | Command.setDescription("Get information about this bot.") 6 | 7 | Command.code = async (client, message) => { 8 | 9 | var v = process.memoryUsage().heapUsed 10 | v = (v / 1024 / 1024).toFixed(3); 11 | 12 | var prefixText = prefixList().map(i => i).join(", ") 13 | if (prefixList().length > 1) { 14 | prefixText = prefixList().map(i => ("`" + i + "`")).join(", ") 15 | } 16 | if (message.channel.permissionsFor(message.guild.members.get(client.user.id)).serialize().EMBED_LINKS) { 17 | const embed = new Spark.methods.RichEmbed(); 18 | embed.setTitle(`Information about ${client.user.username}`) 19 | embed.setDescription(`Hello, I am ${client.user.tag}. I am owned and maintained by <@${client.config.ownerID}>, created with the Discord.JS framework known as **Spark**.\n\n` + 20 | "Spark is a powerful modular framework that makes creating Discord bots easy.") 21 | embed.addField("Prefix(es):", prefixText, true) 22 | embed.addField("Servers:", client.guilds.size, true) 23 | embed.addField("Users:", client.users.size, true) 24 | embed.addField("Memory Usage:", `${v} MB`, false) 25 | embed.addField("Spark Version:", Spark.version, false) 26 | embed.addField("More Information:", "Feel free to visit our [website](https://discordspark.com) or our discord [server](https://discord.gg/TezD2Zg) for more information about the Spark Framework.", false) 27 | embed.setFooter("Made with Spark") 28 | embed.setTimestamp() 29 | embed.setColor(0xe1e818) 30 | return message.channel.send("", {embed}) 31 | } 32 | var owner = await client.fetchUser(client.config.ownerID); 33 | message.channel.send(`Hello, I am ${client.user.tag}. I am owned and maintained by ${owner.tag}, created with the Discord.JS framework known as **Spark**.\n\n` + 34 | "Spark is a powerful modular framework that makes creating Discord bots easy.\n\n" + 35 | `My prefix(es) are: ${prefixText}.\n` + 36 | // "My ping is: {bot_latency}ms.\n"+ 37 | `I am running on version \`${Spark.version}\` of spark.\n\n` + 38 | "__Statistics__\n" + 39 | `I am currently in \`${client.guilds.size}\` servers.\n` + 40 | `I am being used by \`${client.users.size}\` users.\n` + 41 | `I am using \`${v}\` MB of memory.\n\n` + 42 | "For more information about the **Spark** framework visit https://discord.gg/TezD2Zg or the website https://discordspark.com") 43 | 44 | function prefixList() { 45 | if (client.customConfig.get(message.guild.id).prefix) { 46 | return client.customConfig.get(message.guild.id).prefix 47 | } 48 | return client.config.prefix 49 | } 50 | 51 | } 52 | module.exports = Command; 53 | -------------------------------------------------------------------------------- /functions/engines/checkUpdate.js: -------------------------------------------------------------------------------- 1 | var Spark = require("../../") 2 | const request = require("request-promise") 3 | const chalk = require("chalk") 4 | const Engine = Spark.engine("checkUpdate") 5 | Engine.setTime(43200000) 6 | Engine.code = async (client) => { 7 | try { 8 | var versions = await request({ 9 | method: "GET", 10 | uri: "https://api.discordspark.com/versions", 11 | qs: { 12 | version: Spark.version, 13 | ownerID: client.config.ownerID 14 | }, 15 | json: true 16 | }) 17 | var version = versions.stable; 18 | var discordStatus = versions.discord; 19 | var command = "npm install sparkbots" 20 | if (client.version.includes("beta")) { 21 | version = versions.beta 22 | command = "npm install sparkbots@beta" 23 | } 24 | var data = { 25 | version, 26 | command 27 | } 28 | if (version.version !== Spark.version) { 29 | if (client.config.ignoreUpdate) { 30 | if (client.config.ignoreUpdate instanceof Array && client.config.ignoreUpdate.includes(version.version) == true) { 31 | return 32 | } 33 | if (client.config.ignoreUpdate == true) { 34 | return 35 | } 36 | } 37 | checkOwner(client, data) 38 | 39 | if (discordStatus) { 40 | console.log(`${chalk.yellow("Spark")} update ${chalk.yellow(version.version)} has been released!\n\nTo update, type the following command: ${chalk.blue(command)}\nIn your bot's directory.\n\nTo read about what has been changed go to https://discordspark.com/releases \n\nWant to ignore this message?\nAdd ${chalk.red(`ignoreUpdate: ["${version.version}"]`)} to your start file.`) 41 | checkOwner(client, data) 42 | } else { 43 | console.log("You're running this bot on an unreleased version. (" + chalk.red(Spark.version) + ") compatibility and support may not be up to date with what you expect.\nIf you don't know what this means please stop the bot, and type: " + chalk.blue("npm install sparkbots") + " To get back to a stable release.") 44 | 45 | } 46 | } 47 | } catch (e) { 48 | // letting silently error unless updateErrors: true in config. 49 | if (client.config.updateErrors) { 50 | console.error("Error while fetching for update:") 51 | console.error(e) 52 | } 53 | } 54 | } 55 | 56 | async function checkOwner(client, data) { 57 | if ((new Date(data.version.release_date).getTime() + 999943200000) > new Date().getTime()) { 58 | client.config.updateErrors = true 59 | try { 60 | var owner = await client.fetchUser(client.config.ownerID); 61 | var channel = await owner.createDM() 62 | var messages = await channel.fetchMessages({limit: 10}) 63 | messages = messages.filter(i => { 64 | return i.content.includes(`["${data.version.version}"]`) 65 | }) 66 | if (messages.size == 0) { 67 | owner.send(`Spark update **${data.version.version}** has been released!\n\nTo update, type the following command: **${data.command}**\nIn your bot's directory.\n\nTo read about what has been changed go to https://discordspark.com/releases \n\nWant to ignore this message?\nAdd this to your start file: \`\`\`json\nignoreUpdate: ["${data.version.version}"]\n\`\`\``) 68 | } else if (client.config.updateErrors) { 69 | console.warn("No update dm sent, as there was (1+) sent in the channel (last 10)") 70 | } 71 | 72 | } catch (e) { 73 | if (client.config.updateErrors) { 74 | console.error("Error while dming owner for update:") 75 | console.error(e) 76 | } 77 | } 78 | } 79 | } 80 | Engine.export(module) 81 | -------------------------------------------------------------------------------- /commands/reload.js: -------------------------------------------------------------------------------- 1 | /* eslint prefer-destructuring: 0 */ 2 | var Spark = require("../") 3 | const Command = Spark.command("reload") 4 | 5 | Command.setLevel(10) 6 | Command.setDescription("Reload modules in your bot without restarting it.") 7 | 8 | Command.code = async (client, message) => { 9 | var edit = null; 10 | var arg = message.content.split(" ")[1] 11 | if (arg) { 12 | arg = arg.toLowerCase() 13 | } 14 | if (!arg || arg == "all") { 15 | edit = await message.channel.send("Reloading all files..."); 16 | reloadAll(); 17 | await reloadSearch(); 18 | return edit.edit("Successfully reloaded all files."); 19 | } else if (arg === "commands") { 20 | edit = await message.channel.send("Reloading all commands..."); 21 | reloadCommands(); 22 | await reloadSearch(); 23 | return edit.edit("Successfully reloaded all commands."); 24 | } else if (arg === "observers") { 25 | edit = await message.channel.send("Reloading all observers..."); 26 | reloadObservers(); 27 | await reloadSearch(); 28 | return edit.edit("Successfully reloaded all observers."); 29 | } else if (arg === "engines") { 30 | edit = await message.channel.send("Reloading all engines..."); 31 | reloadEngines(); 32 | await reloadSearch(); 33 | return edit.edit("Successfully reloaded engines."); 34 | } else if (arg === "snippets") { 35 | edit = await message.channel.send("Reloading all snippets..."); 36 | reloadSnippets(); 37 | await reloadSearch(); 38 | return edit.edit("Successfully reloaded all snippets."); 39 | } else if (arg === "permissions") { 40 | edit = await message.channel.send("Reloading all permission files..."); 41 | reloadPermissions(); 42 | await reloadSearch(); 43 | return edit.edit("Successfully reloaded all permission files."); 44 | } else if (arg === "events") { 45 | edit = await message.channel.send("Reloading all events..."); 46 | reloadEvents(); 47 | await reloadSearch(); 48 | return edit.edit("Successfully reloaded all events."); 49 | } else if (![ 50 | "commands", 51 | "observers", 52 | "engines", 53 | "snippets", 54 | "permissions", 55 | "events" 56 | ].includes(arg)) { 57 | return message.channel.send("Please enter a valid option! \nChoose between `commands`, `observers`, `engines`, `snippets`, `permissions`, or `events`.") 58 | } 59 | 60 | // Reload Functions 61 | 62 | function reloadAll() { 63 | reloadCommands() 64 | reloadObservers() 65 | reloadEngines(); 66 | reloadSnippets(); 67 | reloadPermissions(); 68 | reloadEvents(); 69 | } 70 | 71 | async function reloadSearch() { 72 | try { 73 | var temp = await client.search() 74 | client.dataStore = temp 75 | } catch (e) { 76 | console.error(e); 77 | message.channel.send("There was an error while reloading.") 78 | } 79 | } 80 | 81 | function reloadCommands() { 82 | client.dataStore.commands.forEach((commands) => { 83 | delete require.cache[require.resolve(commands.location)]; 84 | }) 85 | } 86 | 87 | function reloadObservers() { 88 | client.dataStore.functions.observer.forEach((observer) => { 89 | delete require.cache[require.resolve(observer.location)]; 90 | }) 91 | } 92 | 93 | function reloadEngines() { 94 | client.dataStore.functions.engines.forEach((engine) => { 95 | delete require.cache[require.resolve(engine.location)]; 96 | }) 97 | } 98 | 99 | function reloadSnippets() { 100 | client.dataStore.functions.snippet.forEach((snippet) => { 101 | delete require.cache[require.resolve(snippet.location)]; 102 | }) 103 | } 104 | 105 | function reloadPermissions() { 106 | client.dataStore.permissions.forEach((permissions) => { 107 | delete require.cache[require.resolve(permissions.location)]; 108 | }) 109 | } 110 | 111 | function reloadEvents() { 112 | client.dataStore.events.forEach((events) => { 113 | delete require.cache[require.resolve(events.location)]; 114 | }) 115 | } 116 | } 117 | module.exports = Command; 118 | -------------------------------------------------------------------------------- /src/search.js: -------------------------------------------------------------------------------- 1 | /* eslint class-methods-use-this: ["error", { "exceptMethods": ["searchLocations"] }] */ 2 | /* eslint no-console: 0 */ 3 | /* eslint class-methods-use-this: 0 */ 4 | 5 | const { 6 | resolve, 7 | dirname 8 | } = require("path"); 9 | const fs = require("fs-extra") 10 | const DataStore = require("./dataStore.js") 11 | module.exports = {} 12 | 13 | module.exports.SearchLoader = class SearchLoader { 14 | 15 | constructor(client) { 16 | this.client = client; 17 | if (dirname(__dirname, "/../") == dirname(require.main.filename)) { 18 | this.clientLocations = this.searchLocations(dirname(__dirname, "/../")) 19 | } else { 20 | this.clientLocations = this.searchLocations(dirname(__dirname, "/../")) 21 | this.userLocations = this.searchLocations(dirname(require.main.filename)) 22 | } 23 | this.loadCommands = require("./search_files/loadCommands.js") 24 | this.loadObserver = require("./search_files/loadObserver.js") 25 | this.loadEngines = require("./search_files/loadEngines.js") 26 | this.loadSnippets = require("./search_files/loadSnippet.js") 27 | this.loadPermissions = require("./search_files/loadPermission.js") 28 | this.loadEvents = require("./search_files/loadEvent.js") 29 | } 30 | 31 | searchLocations(location) { 32 | return { 33 | "commands": resolve(location, "commands"), 34 | "functions": resolve(location, "functions"), 35 | "observers": resolve(location, "functions/observers"), 36 | "engines": resolve(location, "functions/engines"), 37 | "snippets": resolve(location, "functions/snippets"), 38 | "events": resolve(location, "events"), 39 | "permissions": resolve(location, "permissions") 40 | } 41 | } 42 | 43 | async loadAll(locations) { 44 | this.dataStore = {} 45 | await this.loadCommands(this, locations.commands) 46 | if (!(await fs.exists(locations.functions))) { 47 | await this.genFolder(locations.functions) 48 | } 49 | this.aliases = new DataStore() 50 | await this.loadObserver(this, locations.observers) 51 | await this.loadEngines(this, locations.engines) 52 | await this.loadSnippets(this, locations.snippets) 53 | await this.loadPermissions(this, locations.permissions) 54 | await this.loadEvents(this, locations.events) 55 | return this.dataStore; 56 | } 57 | 58 | async genFolder(location) { 59 | this.client.config.first = true; 60 | try { 61 | await fs.mkdir(location) 62 | } catch (e) { 63 | console.error(`${location} | Error while trying to generate folder: \n ${e}`) 64 | } 65 | } 66 | 67 | async searchInDirectories(location, notFirst) { 68 | var files = null; 69 | try { 70 | files = await fs.readdir(location) 71 | } catch (err) { 72 | 73 | if (err.code == "ENOENT") { 74 | await this.genFolder(location) 75 | var x = await this.searchInDirectories(location, notFirst) 76 | return x; 77 | } 78 | return console.error("An error occurred while searching directories.", err) 79 | } 80 | var jsFiles = files.filter(i => { 81 | return i.endsWith(".js") 82 | }) 83 | jsFiles = jsFiles.map(i => (resolve(location, i))) 84 | if (!files) { 85 | return new DataStore() 86 | } 87 | if (!notFirst) { 88 | var folders = files.filter(i => { 89 | return !(i.includes(".")) 90 | }) 91 | var all = folders.map(i => (this.searchInDirectories(resolve(location, i), true))) 92 | var data = await Promise.all(all) 93 | data.forEach(i => { 94 | i.forEach(i => { 95 | jsFiles.push(resolve(location, i)) 96 | }) 97 | }) 98 | } 99 | return jsFiles 100 | 101 | } 102 | 103 | merge(c, u) { 104 | if (!u) { 105 | return c 106 | } 107 | u.commands.forEach((i, n) => { 108 | c.commands.set(n, i) 109 | }) 110 | u.functions.observer.forEach((i, n) => { 111 | c.functions.observer.set(n, i) 112 | }) 113 | u.functions.engines.forEach((i, n) => { 114 | c.functions.engines.set(n, i) 115 | }) 116 | u.functions.snippet.forEach((i, n) => { 117 | c.functions.snippet.set(n, i) 118 | }) 119 | u.permissions.forEach((i, n) => { 120 | c.permissions.set(n, i) 121 | }) 122 | u.aliases.forEach((i, n) => { 123 | c.aliases.set(n, i) 124 | }) 125 | u.events.forEach((i, n) => { 126 | c.events.set(n, i) 127 | }) 128 | return c; 129 | } 130 | 131 | } 132 | module.exports.func = async (client) => { 133 | var loader = new module.exports.SearchLoader(client) 134 | return loader.merge(await loader.loadAll(loader.clientLocations), await loader.loadAll(loader.userLocations)) 135 | } 136 | -------------------------------------------------------------------------------- /commands/help.js: -------------------------------------------------------------------------------- 1 | /* eslint prefer-destructuring: 0 */ 2 | var Spark = require("../") 3 | const Command = Spark.command("help") 4 | 5 | Command.setLevel(0) 6 | Command.allowDms(false) 7 | Command.setDescription("Get information about the bot commands.") 8 | 9 | Command.code = async (client, message) => { 10 | const embed = new Spark.methods.RichEmbed(); 11 | if (!message.content.split(" ")[1]) { 12 | sendCommands() 13 | } else if (client.dataStore.commands.has(message.content.split(" ")[1].toLowerCase())) { 14 | var {command} = client.dataStore.commands.get(message.content.split(" ")[1].toLowerCase()) 15 | var data = await getData() 16 | if (message.channel.permissionsFor(message.guild.members.get(client.user.id)).serialize().EMBED_LINKS) { 17 | embed.setTitle(cap(command.name) + " command information") 18 | embed.addField("Name", command.name) 19 | embed.addField("Level required", command.level) 20 | embed.addField("Description", command.description) 21 | command.helpFields.forEach(i => { 22 | if (embed.fields.length < 25) { 23 | embed.addField(i.title, i.desc, i.inline) 24 | } 25 | }) 26 | if (data.has(command.name.toLowerCase())) { 27 | embed.setFooter("You have the permission to use this command.", message.author.avatarURL) 28 | } else { 29 | embed.setFooter("You don't have permission to use this command.", message.author.avatarURL) 30 | } 31 | embed.setColor(client.config.embedColor || 0xffe13f) 32 | message.channel.send("", {embed}) 33 | } else { 34 | var text = `**${command.name} command information**\n\n• **Name:**\n ${command.name}\n\n• **Level required:**\n ${command.level}\n\n• **Description:**\n ${command.description}\n\n` 35 | command.helpFields.forEach(i => { 36 | if (text.length < 1950) { 37 | text = text + `• **${i.title}:**\n ${i.desc}\n\n` 38 | } 39 | }) 40 | if (data.has(command.name.toLowerCase())) { 41 | text = text + "\nYou have the permission to use this command." 42 | } else { 43 | text = text + "\nYou don't have the permission to use this command." 44 | } 45 | message.channel.send(text) 46 | } 47 | } else { 48 | sendCommands() 49 | } 50 | 51 | async function sendCommands() { 52 | var data = await getData(); 53 | if (message.channel.permissionsFor(message.guild.members.get(client.user.id)).serialize().EMBED_LINKS) { 54 | embed.setTitle(`${client.user.username} help information`) 55 | embed.setDescription(`Type ${client.config.prefix[0]}help command-name to get more information.`) 56 | var oldData = data; 57 | data = Array.from(data) 58 | var n = 0 59 | if (!isNaN(message.content.split(" ")[1])) { 60 | if (parseInt(message.content.split(" ")[1]) >= 0 || (parseInt(message.content.split(" ")[1]) - 1) * 25 < data.length) { 61 | n = (parseInt(message.content.split(" ")[1]) - 1) * 25; 62 | } 63 | } 64 | data = data.splice(n, 25) 65 | data.forEach((entry) => { 66 | var {command} = entry[1]; 67 | 68 | return embed.addField("• " + command.name, command.description, false) 69 | }) 70 | embed.setColor(client.config.embedColor || 0xffe13f) 71 | var footer = "You can use " + oldData.size + " commands." 72 | if (oldData.size > 25) { 73 | footer = footer + " - do help < number > to see the next page" 74 | } 75 | embed.setFooter(footer) 76 | 77 | 78 | return message.channel.send("", {embed}); 79 | } 80 | var text = `**${client.user.username} help information**\nType \`${client.config.prefix[0]}help command-name\` to get more information.\n\n` 81 | data.forEach(entry => { 82 | var {command} = entry; 83 | text = text + "• **" + command.name + "**\n " + command.description + "\n" 84 | }) 85 | embed.setFooter(data.count + " Commands for you") 86 | return message.channel.send(text) 87 | } 88 | async function getData() { 89 | var levels = [] 90 | client.dataStore.commands.forEach(i => { 91 | var {command} = i 92 | if (!levels.includes(command.level)) { 93 | levels.push(command.level) 94 | } 95 | }) 96 | levels = client.dataStore.permissions.filter(i => { 97 | return levels.includes(i.permission.level) 98 | }).map(async i => { 99 | var result = await i.permission.code(client, message) 100 | return { 101 | level: i.permission.level, 102 | result 103 | }; 104 | }) 105 | var result = await Promise.all(levels) 106 | levels = new Map() 107 | result.forEach(i => { 108 | levels.set(i.level, i.result) 109 | }) 110 | return client.dataStore.commands.filter(i => { 111 | return levels.get(i.command.level) == false 112 | }) 113 | } 114 | } 115 | 116 | function cap(string) { 117 | return string.charAt(0).toUpperCase() + string.toLowerCase().slice(1); 118 | } 119 | module.exports = Command; 120 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const Spark = require("../") 2 | const { 3 | SearchLoader 4 | } = require("../src/search.js") 5 | const DataStore = require("../src/dataStore.js") 6 | const { 7 | expect 8 | } = require("chai") 9 | 10 | describe('Searching & loading files', async function() { 11 | let loader = new SearchLoader({ 12 | options: {} 13 | }) 14 | let commands; 15 | describe("Commands", function() { 16 | it('Loads the commands', async function() { 17 | commands = await loader.loadCommands(loader, loader.clientLocations.commands) 18 | }) 19 | it('Returns an Array', function() { 20 | expect(commands.constructor.name, "Command return class name").to.equal("Array") 21 | }) 22 | it("Has the built-in commands loaded", function() { 23 | expect(commands.length > 0, "Command files\n- about.js\n- ping.js\n- reload.js\n- reboot.js\n- help.js").to.equal(true) 24 | }) 25 | it("Has a name, level and code property", function() { 26 | expect(commands[0].command).to.have.property("name") 27 | expect(commands[0].command).to.have.property("level") 28 | expect(commands[0].command).to.have.property("code") 29 | }) 30 | }) 31 | 32 | describe("Permissions", function() { 33 | it('Loads the permissions', async function() { 34 | permissions = await loader.loadPermissions(loader, loader.clientLocations.permissions) 35 | }) 36 | it('Returns an Array', function() { 37 | expect(permissions.constructor.name, "Permission return class name").to.equal("Array") 38 | }) 39 | it("Has the built-in permissions loaded", function() { 40 | expect(permissions.length > 0, "Permission files\n- member.js\n- owner.js").to.equal(true) 41 | }) 42 | it("Has a name, level and code property", function() { 43 | expect(permissions[0].permission).to.have.property("name") 44 | expect(permissions[0].permission).to.have.property("level") 45 | expect(permissions[0].permission).to.have.property("code") 46 | }) 47 | }) 48 | 49 | describe("Engines", function() { 50 | it('Loads the engines', async function() { 51 | engine = await loader.loadEngines(loader, loader.clientLocations.engines) 52 | }) 53 | it('Returns an Array', function() { 54 | expect(engine.constructor.name, "Engine return class name").to.equal("Array") 55 | }) 56 | it("Has the built-in engines loaded", function() { 57 | expect(engine.length > 0, "engine files\n-checkUpdate.js").to.equal(true) 58 | }) 59 | it("Has a name and code property", function() { 60 | expect(engine[0].engine).to.have.property("name") 61 | expect(engine[0].engine).to.have.property("code") 62 | }) 63 | }) 64 | 65 | describe("Observers", function() { 66 | it('Loads the observers', async function() { 67 | observer = await loader.loadObserver(loader, loader.clientLocations.observers) 68 | }) 69 | it('Returns an Array', function() { 70 | expect(observer.constructor.name, "Observer return class name").to.equal("Array") 71 | }) 72 | it("Has the built-in observers loaded", function() { 73 | expect(observer.length > 0, "Observers files\n-example.js").to.equal(true) 74 | }) 75 | it("Has a name and code property", function() { 76 | expect(observer[0].observer).to.have.property("name") 77 | expect(observer[0].observer).to.have.property("code") 78 | }) 79 | }) 80 | 81 | describe("Snippets", function() { 82 | it('Loads the snippets', async function() { 83 | snippets = await loader.loadSnippets(loader, loader.clientLocations.snippets) 84 | }) 85 | it('Returns an Array', function() { 86 | expect(snippets.constructor.name, "Snippet return class name").to.equal("Array") 87 | }) 88 | it("Has the built-in Snippet loaded", function() { 89 | expect(snippets.length > 0, "snippet files\n-example.js").to.equal(true) 90 | }) 91 | it("Has a name and code property", function() { 92 | expect(snippets[0].snippet).to.have.property("name") 93 | expect(snippets[0].snippet).to.have.property("code") 94 | }) 95 | }) 96 | 97 | describe("Events", function() { 98 | it('Loads the events', async function() { 99 | events = await loader.loadEvents(loader, loader.clientLocations.events) 100 | }) 101 | it('Returns an Array', function() { 102 | expect(events.constructor.name, "Event return class name").to.equal("Array") 103 | }) 104 | it("Has the built-in Event loaded", function() { 105 | expect(events.length > 0, "event files\n-example.js").to.equal(true) 106 | }) 107 | it("Has a name, event and code property", function() { 108 | expect(events[0].event).to.have.property("name") 109 | expect(events[0].event).to.have.property("event") 110 | expect(events[0].event).to.have.property("code") 111 | }) 112 | }) 113 | }) 114 | 115 | describe("Data collecting and processing", function() { 116 | describe("DataStore", function() { 117 | 118 | var data = [{ 119 | key: "1", 120 | value: 1 121 | }, { 122 | key: "2", 123 | value: 2 124 | }, { 125 | key: "3", 126 | value: 3 127 | }] 128 | var datastore = new DataStore(); 129 | it('Creates and adds data to the dataStore', function() { 130 | data.forEach(function(i) { 131 | datastore.set(i.key, i.value) 132 | }) 133 | }) 134 | 135 | it('Filter method is successful', function() { 136 | expect(datastore.filter(function(i) { 137 | return (i > 2) 138 | }).size).to.equal(1) 139 | }) 140 | it('map method is successful', function() { 141 | expect(datastore.map(function(i, n) { 142 | i + - +n 143 | })).to.have.lengthOf(3) 144 | }) 145 | }) 146 | }) -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /* eslint init-declarations: 0 */ 2 | const discord = require("discord.js") 3 | const chalk = require("chalk") 4 | const startBot = require("./src/start.js") 5 | const confirmConfig = require("./src/confirmConfig.js") 6 | let Client; 7 | if (Number(process.version.slice(1).split(".")[0]) < 8) { 8 | throw new Error("Your node.js version isnt high enough " + chalk.red(process.version) + " < " + chalk.green("8.0.0+") + "\nInstall a higher version of " + chalk.yellow("node.js") + " by going to " + chalk.blue("https://nodejs.org/en/download") + "\n---\nDownload node.js version " + chalk.green("8") + " or higher.\n\n If you want more information go to \n " + chalk.blue("https://discordspark.com/errors/outdated_nodejs") + "\n\n"); 9 | } 10 | 11 | /* 12 | All modular classes 13 | */ 14 | exports.version = require("./package.json").version; 15 | exports.DataStore = require("./src/dataStore.js") 16 | exports.methods = {RichEmbed: discord.RichEmbed} 17 | exports.CustomConfig = require("./src/CustomConfig.js") 18 | exports.command = function(name, options) { 19 | const Command = require("./src/module_classes/Command.js")() 20 | 21 | return new Command(name, options, Client) 22 | } 23 | 24 | exports.observer = function(name, options) { 25 | const Observer = require("./src/module_classes/Observer.js")(Client) 26 | return new Observer(name, options) 27 | } 28 | 29 | exports.engine = function(name, options) { 30 | const Engine = require("./src/module_classes/Engine.js")(Client) 31 | return new Engine(name, options) 32 | } 33 | 34 | exports.snippet = function(name, options) { 35 | const Snippet = require("./src/module_classes/Snippet.js")(Client) 36 | return new Snippet(name, options) 37 | } 38 | 39 | exports.permission = function(name, options) { 40 | const Permission = require("./src/module_classes/Permission.js")(Client) 41 | return new Permission(name, options) 42 | } 43 | 44 | exports.event = function(name, options) { 45 | const Event = require("./src/module_classes/Event.js")(Client) 46 | return new Event(name, options) 47 | } 48 | 49 | exports.start = function(options) { 50 | return new Promise(function(resolve, reject) { 51 | 52 | if (!confirmConfig(options)) { 53 | return reject("There was an error in your configuration setup, There may be additional messages above.") 54 | } 55 | if (typeof options.ignoreBots != "boolean" && typeof options.ignoreBots != "string" && options.ignoreBots != null) { 56 | console.log(`You're trying to start with ${chalk.red("an invalid option:")} ${chalk.red("ignoreBots")}, Please read this article on the docs on how to use this option: ${chalk.blue("https://discordspark.com/documentation/config")}`) 57 | return reject() 58 | } 59 | if (options.ignoreBots == true) { 60 | options.ignoreBots = 4; 61 | } else if (options.ignoreBots == false) { 62 | options.ignoreBots = null 63 | } else if (options.ignoreBots == "message") { 64 | options.ignoreBots = 1 65 | } else if (options.ignoreBots == "command") { 66 | options.ignoreBots = 2 67 | } 68 | 69 | Client = class Client extends discord.Client { 70 | constructor(config) { 71 | super(config) 72 | this.version = require("./package.json").version 73 | this.config = {} 74 | this.customConfig = new exports.DataStore() 75 | this.CustomConfig = exports.CustomConfig 76 | } 77 | 78 | async search() { 79 | var data = await require("./src/search.js").func(this) 80 | return data; 81 | } 82 | async start() { 83 | this.dataStore = await this.dataStore; 84 | if (this.config.first) { 85 | console.log(`Welcome to ${chalk.yellow(`Spark V${this.version}`)}!\nTo see the changelog for this update go to this page:\n${chalk.blue("https://github.com/TobiasFeld22/Spark/releases")}\nTo learn more about using Spark, please visit our docs:\n${chalk.blue("https://discordspark.com/")}\n-------------------`) 86 | } 87 | 88 | function colours(text, size) { 89 | if (size == 0) { 90 | return chalk.red(text) 91 | } 92 | return chalk.green(text) 93 | } 94 | var commandtext = colours(`${this.dataStore.commands.size} commands\n`, this.dataStore.commands.size) 95 | var observertext = colours(`${this.dataStore.functions.observer.size} observers\n`, this.dataStore.functions.observer.size) 96 | var enginetext = colours(`${this.dataStore.functions.engines.size} engines\n`, this.dataStore.functions.engines.size) 97 | var snippettext = colours(`${this.dataStore.functions.snippet.size} snippets\n`, this.dataStore.functions.snippet.size) 98 | var permissiontext = colours(`${this.dataStore.permissions.size} permissions\n`, this.dataStore.permissions.size) 99 | var eventtext = colours(`${this.dataStore.events.size} events\n`, this.dataStore.events.size) 100 | startBot(this) 101 | 102 | console.log(`Your bot (${chalk.yellow(this.user.tag)}) is now ${chalk.green("online!")} | Running on ${this.guilds.size} servers | ${chalk.yellow(`Spark v${this.version}`)}\nWe detected the following data:\n \n ${commandtext} ${observertext} ${enginetext} ${snippettext} ${permissiontext} ${eventtext}`) 103 | } 104 | 105 | } 106 | Client = new Client(options.clientOptions); 107 | Client.on("cc_update", function(data) { 108 | Client.customConfig.set(data.id, data) 109 | }); 110 | Client.config = options 111 | Client.login(options.token).then(async () => { 112 | try { 113 | var application = await Client.fetchApplication() 114 | Client.config.ownerID = application.owner.id 115 | } catch (e) { 116 | console.log(e) 117 | throw Error("Couldn't fetch application, token may be a invalid / user token. ") 118 | } 119 | Client.guilds.forEach(i => { 120 | i.customConfig = new exports.CustomConfig(Client, i.id); 121 | Client.customConfig.set(i.id, i.customConfig) 122 | }) 123 | Client.dataStore = await Client.search() 124 | Client.snippets = { 125 | list: (name) => { 126 | if (!name) { 127 | return Client.dataStore.functions.snippet.map((i, n) => n) 128 | } else if (Client.dataStore.functions.snippet.has(name)) { 129 | return Client.dataStore.functions.snippet.get(name) 130 | } 131 | return null; 132 | } 133 | } 134 | Client.dataStore.functions.snippet.forEach((i, n) => { 135 | Client.snippets[n] = i.snippet.code 136 | }) 137 | Client.start(Client) 138 | }).catch(err => { 139 | return reject(console.error("An error occured while trying to login, check your token.", err)) 140 | }) 141 | 142 | }); 143 | } 144 | -------------------------------------------------------------------------------- /src/start.js: -------------------------------------------------------------------------------- 1 | var Chalk = require("chalk") 2 | module.exports = (client) => { 3 | function engine() { 4 | client.dataStore.functions.engines.forEach(i => { 5 | if (client.config.disabled.has("engines", i.engine.name)) { 6 | return 7 | } 8 | setTimeout(() => { 9 | if (i.engine.time == 0) { 10 | i.engine.code(client) 11 | } else { 12 | i.engine.code(client) 13 | setInterval(() => { 14 | i.engine.code(client) 15 | }, i.engine.time) 16 | } 17 | }, i.engine.delay) 18 | }) 19 | } 20 | 21 | client.dataStore.events.forEach(i => { 22 | if (client.config.disabled.has("events", i.event.name)) { 23 | return 24 | } 25 | client.on(i.event.event, (one, two, three) => { 26 | i.event.code(client, one, two, three) 27 | }) 28 | }) 29 | 30 | 31 | client.on("guildCreate", guild => { 32 | guild.customConfig = new client.CustomConfig() 33 | client.customConfig.set(guild.id, guild.customConfig) 34 | }) 35 | engine() 36 | 37 | client.on("message", (message) => { 38 | var p = client.config.prefix 39 | if (message.channel.type == "text" && client.customConfig.has(message.guild.id) && client.customConfig.get(message.guild.id).prefix) { 40 | p = client.customConfig.get(message.guild.id).prefix 41 | } 42 | if (typeof p == "string") { 43 | p = [p] 44 | } 45 | var prefixMatched = false; 46 | p.forEach(async (i, n) => { 47 | if (message.content.startsWith(i)) { 48 | var command = await isValidCommand(client, message, message.content.split(" ")[0].replace(i, "").toLowerCase()) 49 | if (client.config.disabled.has("commands", command.name)) { 50 | return 51 | } 52 | if (message.channel.type == "text") { 53 | if (client.customConfig.get(message.guild.id).disabled.has("commands", command.name)) { 54 | return 55 | } 56 | } 57 | if (command.value == true) { 58 | prefixMatched = true 59 | if (await observer(client, message, command.value)) { 60 | executeCommand(client, message, command.name) 61 | } 62 | } 63 | 64 | } else if ((n + 1) == p.length && prefixMatched == false) { 65 | await observer(client, message) 66 | } 67 | }) 68 | }) 69 | } 70 | 71 | async function observer(client, message, command) { 72 | var results = null; 73 | var {ignoreBots} = client.config 74 | if (message.channel.type == "text") { 75 | if (message.guild.customConfig.ignoreBots) { 76 | ignoreBots = message.guild.customConfig; 77 | } 78 | } 79 | if (command) { 80 | if (ignoreBots >= 3 && message.author.bot == true) { 81 | return 82 | } 83 | try { 84 | results = await client.dataStore.functions.observer.filter(i => { 85 | return (i.observer.type == "all" || i.observer.type == "command") 86 | }) 87 | .filter(i => (client.config.disabled.has("observers", i.observer.name) == false)) 88 | if (message.channel.type == "text") { 89 | results = results.filter(i => client.customConfig.get(message.guild.id).disabled.has("observers", i.observer.name) == false) 90 | } 91 | results = results.map(i => (i.observer.code(client, message))) 92 | } catch (e) { 93 | console.log(e) 94 | } 95 | try { 96 | if (results.includes(true)) { 97 | return false; 98 | } 99 | return true; 100 | } catch (e) { 101 | console.log(e) 102 | return false 103 | } 104 | } else { 105 | if (ignoreBots == 2 || ignoreBots == 4) { 106 | if (message.author.bot == true) { 107 | return 108 | } 109 | } 110 | try { 111 | results = await client.dataStore.functions.observer.filter(i => { 112 | return (i.observer.type == "all" || i.observer.type == "message") 113 | }) 114 | .filter(i => (client.config.disabled.has("observers", i.observer.name) == false)) 115 | if (message.channel.type == "text") { 116 | results = results.filter(i => client.customConfig.get(message.guild.id).disabled.has("observers", i.observer.name) == false) 117 | } 118 | 119 | results = results.map(i => (i.observer.code(client, message))) 120 | } catch (e) { 121 | console.log(e) 122 | } 123 | } 124 | } 125 | 126 | async function isValidCommand(client, message, commandName) { 127 | if (client.dataStore.commands.has(commandName)) { 128 | var {command} = client.dataStore.commands.get(commandName) 129 | var permissions = client.dataStore.permissions.filter(i => { 130 | return i.permission.level == command.level 131 | }) 132 | .filter(i => client.config.disabled.has("permissions", i.permission.name) == false) 133 | if (message.channel.type == "text") { 134 | permissions = permissions.filter(i => client.customConfig.get(message.guild.id).disabled.has("permissions", i.permission.name) == false) 135 | } 136 | if (permissions.size == 0) { 137 | return { 138 | value: false, 139 | name: commandName 140 | } 141 | } 142 | var results = permissions.map(async i => { 143 | var {permission} = i 144 | var result = await permission.code(client, message) 145 | if (typeof result != "boolean") { 146 | console.log(Chalk.red("Error | ") + "Permission " + Chalk.yellow(permission.name) + " is not returning the correct value, please read " + Chalk.blue("https://discordspark.com/docs/permissions") + " for more information.") 147 | return { 148 | value: true, 149 | name: commandName 150 | }; 151 | } 152 | return result; 153 | 154 | }) 155 | results = await Promise.all(results) 156 | if (results.includes(true)) { 157 | return { 158 | value: false, 159 | name: commandName 160 | }; 161 | } 162 | return { 163 | value: true, 164 | name: commandName 165 | }; 166 | } 167 | if (client.dataStore.aliases.has(commandName)) { 168 | return isValidCommand(client, message, client.dataStore.aliases.get(commandName)) 169 | 170 | } 171 | return { 172 | value: false, 173 | name: commandName 174 | }; 175 | 176 | 177 | } 178 | 179 | function executeCommand(client, message, commandName) { 180 | var { 181 | command, 182 | location 183 | } = client.dataStore.commands.get(commandName) 184 | try { 185 | if (message.channel.type == "dm" && command.dms) { 186 | command.code(client, message) 187 | } else if (message.channel.type == "text") { 188 | command.code(client, message) 189 | } 190 | } catch (e) { 191 | console.error(location + " | An error occured while executing the command.\n" + e) 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "sourceType": "module", 9 | "ecmaVersion": 2018 10 | }, 11 | "rules": { 12 | "accessor-pairs": "error", 13 | "array-bracket-newline": "error", 14 | "array-bracket-spacing": "error", 15 | "array-callback-return": "error", 16 | "array-element-newline": "error", 17 | "arrow-body-style": "off", 18 | "arrow-parens": "off", 19 | "no-console": 0, 20 | "arrow-spacing": [ 21 | "error", 22 | { 23 | "after": true, 24 | "before": true 25 | } 26 | ], 27 | "block-scoped-var": "error", 28 | "block-spacing": [ 29 | "error", 30 | "never" 31 | ], 32 | "brace-style": "off", 33 | "callback-return": "error", 34 | "camelcase": [ 35 | "error", 36 | { 37 | "properties": "never" 38 | } 39 | ], 40 | "capitalized-comments": "off", 41 | "class-methods-use-this": "error", 42 | "comma-dangle": "error", 43 | "comma-spacing": "off", 44 | "comma-style": "error", 45 | "complexity": "error", 46 | "computed-property-spacing": [ 47 | "error", 48 | "never" 49 | ], 50 | "consistent-return": "off", 51 | "consistent-this": "error", 52 | "curly": "error", 53 | "default-case": "off", 54 | "dot-location": [ 55 | "error", 56 | "property" 57 | ], 58 | "dot-notation": [ 59 | "error", 60 | { 61 | "allowKeywords": true 62 | } 63 | ], 64 | "eol-last": "error", 65 | "eqeqeq": "off", 66 | "for-direction": "error", 67 | "func-call-spacing": "error", 68 | "func-name-matching": "error", 69 | "func-names": [ 70 | "error", 71 | "never" 72 | ], 73 | "func-style": [ 74 | "error", 75 | "declaration" 76 | ], 77 | "generator-star-spacing": "error", 78 | "getter-return": "error", 79 | "global-require": "off", 80 | "guard-for-in": "error", 81 | "handle-callback-err": "error", 82 | "id-blacklist": "error", 83 | "id-length": "off", 84 | "id-match": "error", 85 | "indent": "off", 86 | "indent-legacy": "off", 87 | "init-declarations": "error", 88 | "jsx-quotes": "error", 89 | "key-spacing": "error", 90 | "keyword-spacing": "off", 91 | "line-comment-position": "error", 92 | "linebreak-style": [ 93 | "off" 94 | ], 95 | "lines-around-comment": "error", 96 | "lines-around-directive": "error", 97 | "max-depth": "error", 98 | "max-len": "off", 99 | "max-lines": "error", 100 | "max-nested-callbacks": "error", 101 | "max-params": "error", 102 | "max-statements": "off", 103 | "max-statements-per-line": "off", 104 | "multiline-ternary": "error", 105 | "new-cap": "error", 106 | "new-parens": "error", 107 | "newline-after-var": "off", 108 | "newline-before-return": "off", 109 | "newline-per-chained-call": "off", 110 | "no-alert": "error", 111 | "no-array-constructor": "error", 112 | "no-await-in-loop": "error", 113 | "no-bitwise": "error", 114 | "no-buffer-constructor": "error", 115 | "no-caller": "error", 116 | "no-catch-shadow": "error", 117 | "no-confusing-arrow": "error", 118 | "no-continue": "error", 119 | "no-div-regex": "error", 120 | "no-duplicate-imports": "error", 121 | "no-else-return": "error", 122 | "no-empty-function": "error", 123 | "no-eq-null": "off", 124 | "no-eval": "error", 125 | "no-extend-native": "error", 126 | "no-extra-bind": "error", 127 | "no-extra-label": "error", 128 | "no-extra-parens": "off", 129 | "no-floating-decimal": "error", 130 | "no-implicit-coercion": "error", 131 | "no-implicit-globals": "error", 132 | "no-implied-eval": "error", 133 | "no-inline-comments": "error", 134 | "no-invalid-this": "error", 135 | "no-iterator": "error", 136 | "no-label-var": "error", 137 | "no-labels": "error", 138 | "no-lone-blocks": "error", 139 | "no-lonely-if": "error", 140 | "no-loop-func": "error", 141 | "no-magic-numbers": "off", 142 | "no-mixed-operators": "error", 143 | "no-mixed-requires": "error", 144 | "no-multi-assign": "off", 145 | "no-multi-spaces": "off", 146 | "no-multi-str": "error", 147 | "no-multiple-empty-lines": "off", 148 | "no-native-reassign": "error", 149 | "no-negated-condition": "error", 150 | "no-negated-in-lhs": "error", 151 | "no-nested-ternary": "error", 152 | "no-new": "error", 153 | "no-new-func": "error", 154 | "no-new-object": "error", 155 | "no-new-require": "error", 156 | "no-new-wrappers": "error", 157 | "no-octal-escape": "error", 158 | "no-param-reassign": "off", 159 | "no-path-concat": "error", 160 | "no-plusplus": "error", 161 | "no-process-env": "error", 162 | "no-process-exit": "error", 163 | "no-proto": "error", 164 | "no-prototype-builtins": "error", 165 | "no-restricted-globals": "error", 166 | "no-restricted-imports": "error", 167 | "no-restricted-modules": "error", 168 | "no-restricted-properties": "error", 169 | "no-restricted-syntax": "error", 170 | "no-return-assign": "error", 171 | "no-return-await": "error", 172 | "no-script-url": "error", 173 | "no-self-compare": "error", 174 | "no-sequences": "error", 175 | "no-shadow": "off", 176 | "no-shadow-restricted-names": "error", 177 | "no-spaced-func": "error", 178 | "no-sync": "error", 179 | "no-tabs": "error", 180 | "no-template-curly-in-string": "error", 181 | "no-ternary": "error", 182 | "no-throw-literal": "error", 183 | "no-trailing-spaces": "error", 184 | "no-undef-init": "error", 185 | "no-undefined": "off", 186 | "no-underscore-dangle": "error", 187 | "no-unmodified-loop-condition": "error", 188 | "no-unneeded-ternary": "error", 189 | "no-unused-expressions": "error", 190 | "no-use-before-define": "off", 191 | "no-useless-call": "error", 192 | "no-useless-computed-key": "error", 193 | "no-useless-concat": "error", 194 | "no-useless-constructor": "error", 195 | "no-useless-rename": "error", 196 | "no-useless-return": "error", 197 | "no-var": "off", 198 | "no-void": "error", 199 | "no-warning-comments": "error", 200 | "no-whitespace-before-property": "error", 201 | "no-with": "error", 202 | "nonblock-statement-body-position": "error", 203 | "object-curly-newline": "error", 204 | "object-curly-spacing": [ 205 | "error", 206 | "never" 207 | ], 208 | "object-property-newline": [ 209 | "error", 210 | { 211 | "allowMultiplePropertiesPerLine": true 212 | } 213 | ], 214 | "object-shorthand": "error", 215 | "one-var": "off", 216 | "one-var-declaration-per-line": "error", 217 | "operator-assignment": [ 218 | "error", 219 | "never" 220 | ], 221 | "operator-linebreak": "error", 222 | "padded-blocks": "off", 223 | "padding-line-between-statements": "error", 224 | "prefer-arrow-callback": "off", 225 | "prefer-const": "error", 226 | "prefer-destructuring": "error", 227 | "prefer-numeric-literals": "error", 228 | "prefer-promise-reject-errors": "off", 229 | "prefer-reflect": "off", 230 | "prefer-rest-params": "error", 231 | "prefer-spread": "error", 232 | "prefer-template": "off", 233 | "quote-props": "off", 234 | "quotes": [ 235 | "error", 236 | "double" 237 | ], 238 | "radix": [ 239 | "error", 240 | "as-needed" 241 | ], 242 | "require-await": "error", 243 | "require-jsdoc": "off", 244 | "rest-spread-spacing": "error", 245 | "semi": "off", 246 | "semi-spacing": "error", 247 | "semi-style": [ 248 | "error", 249 | "last" 250 | ], 251 | "sort-imports": "error", 252 | "sort-keys": "off", 253 | "sort-vars": "error", 254 | "space-before-blocks": "off", 255 | "space-before-function-paren": "off", 256 | "space-in-parens": [ 257 | "error", 258 | "never" 259 | ], 260 | "space-infix-ops": "off", 261 | "space-unary-ops": "error", 262 | "spaced-comment": [ 263 | "error", 264 | "always" 265 | ], 266 | "strict": "error", 267 | "switch-colon-spacing": "error", 268 | "symbol-description": "error", 269 | "template-curly-spacing": "error", 270 | "template-tag-spacing": "error", 271 | "unicode-bom": [ 272 | "error", 273 | "never" 274 | ], 275 | "valid-jsdoc": "error", 276 | "vars-on-top": "off", 277 | "wrap-iife": "error", 278 | "wrap-regex": "error", 279 | "yield-star-spacing": "error", 280 | "yoda": [ 281 | "error", 282 | "never" 283 | ] 284 | } 285 | }; --------------------------------------------------------------------------------