├── .env.example
├── .eslintignore
├── .eslintrc.json
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── general-issue.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── .vscode
├── launch.json
└── tasks.json
├── LICENSE
├── README.md
├── appveyor.yml
├── azure-pipelines.yml
├── base
├── Command.js
└── Indev.js
├── build
├── appveyor
│ └── send.ps1
├── azure-pipelines
│ ├── darwin
│ │ └── continuous-build-darwin.yml
│ └── win32
│ │ └── continuous-build-win32.yml
├── text.js
└── travis
│ └── send.sh
├── commands
├── Debug
│ ├── eval.js
│ ├── event.js
│ ├── exec.js
│ └── filesize.js
├── Fun
│ ├── 8ball.js
│ ├── bigletter.js
│ ├── cleverbot.js
│ ├── dadjoke.js
│ ├── expand.js
│ ├── flip.js
│ ├── joke.js
│ ├── lmgtfy.js
│ ├── rate.js
│ ├── roll.js
│ ├── say.js
│ ├── slots.js
│ ├── tableflip.js
│ ├── trivia.js
│ ├── urban.js
│ ├── vaportext.js
│ └── vaporwave.js
├── Image
│ ├── cat.js
│ ├── changemymind.js
│ ├── dog.js
│ ├── faketweet.js
│ ├── giphy.js
│ ├── image.js
│ ├── imagesearch.js
│ ├── jpeg.js
│ ├── lizard.js
│ ├── magik.js
│ ├── robot.js
│ └── snake.js
├── Information
│ ├── about.js
│ ├── avatar.js
│ ├── channelid.js
│ ├── channelinfo.js
│ ├── discriminator.js
│ ├── dsdev.js
│ ├── emojiimage.js
│ ├── emojiinfo.js
│ ├── feedback.js
│ ├── github.js
│ ├── logo.js
│ ├── nasa.js
│ ├── serverinfo.js
│ ├── stats.js
│ ├── time.js
│ ├── timezones.js
│ ├── tweet.js
│ ├── twitter.js
│ ├── uptime.js
│ ├── userid.js
│ ├── userinfo.js
│ ├── version.js
│ └── weather.js
├── Maths
│ ├── maths.js
│ ├── pi.js
│ └── prime.js
├── Misc
│ ├── announce.js
│ ├── help.js
│ ├── icon.js
│ ├── invite.js
│ ├── invites.js
│ ├── lastmessage.js
│ ├── loremipsum.js
│ ├── mylevel.js
│ ├── quote.js
│ ├── tutorial.js
│ └── youtube.js
├── Moderation
│ ├── ban.js
│ ├── banlist.js
│ ├── bans.js
│ ├── clearnick.js
│ ├── forceban.js
│ ├── kick.js
│ ├── lockdown.js
│ ├── mute.js
│ ├── purge.js
│ ├── report.js
│ ├── unmute.js
│ └── warn.js
├── Music
│ ├── README.md
│ ├── np.js
│ ├── pause.js
│ ├── play.js
│ ├── queue.js
│ ├── resume.js
│ ├── skip.js
│ ├── stop.js
│ └── volume.js
├── System
│ ├── conf.js
│ ├── leave.js
│ ├── ping.js
│ ├── prefix.js
│ ├── reboot.js
│ ├── reload.js
│ ├── set.js
│ ├── shutdown.js
│ └── status.js
└── Utility
│ ├── emoji.js
│ └── shorten.js
├── config.js.example
├── dashboard
├── public
│ ├── css
│ │ ├── bootstrap.min.css
│ │ ├── darkly.css
│ │ ├── dashboard.css
│ │ ├── flatly.css
│ │ └── font-awesome.min.css
│ ├── images
│ │ └── bot.png
│ └── js
│ │ └── bootstrap.min.js
└── templates
│ ├── admin.ejs
│ ├── autherror.ejs
│ ├── blocks
│ ├── footer.ejs
│ ├── guild-card.ejs
│ ├── guild-modals.ejs
│ ├── guild-nav.ejs
│ └── header.ejs
│ ├── commands.ejs
│ ├── dashboard.ejs
│ ├── guild
│ ├── manage.ejs
│ ├── members.ejs
│ └── stats.ejs
│ ├── index.ejs
│ └── stats.ejs
├── docs
├── .gitignore
├── CNAME
├── _config.yml
├── assets
│ └── css
│ │ └── style.css
└── index.html
├── events
├── error.js
├── guildCreate.js
├── guildDelete.js
├── guildMemberAdd.js
├── guildMemberRemove.js
├── message.js
├── messageDelete.js
└── ready.js
├── index.js
├── locales
└── en-GB.js
├── modules
├── dashboard.js
└── functions.js
├── music
└── js
│ ├── config.js.example
│ └── music.js
├── package-lock.json
├── package.json
└── util
├── Logger.js
├── Utils.js
├── data.js
├── setup.js
└── setup_base.txt
/.env.example:
--------------------------------------------------------------------------------
1 | # Environment
2 | NODE_ENV=development
3 |
4 | # Google
5 | GOOGLE_API_KEY=
6 |
7 | # delet
8 | DELET_TOKEN=TOKEN_HERE
9 |
10 | # Twitter
11 | TWITTER_API_KEY=
12 | TWITTER_SECRET=
13 |
14 | # Giphy
15 | GIPHY_API_KEY=
16 |
17 | # Cleverbot
18 | CLEVERBOT_API_USER=
19 | CLEVERBOT_API_KEY=
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /dashboard
2 | /docs
3 | /node_modules
4 | /tags
5 | /test
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 2017
4 | },
5 | "env": {
6 | "es6": true,
7 | "node": true
8 | },
9 | "extends": "eslint:recommended",
10 | "rules": {
11 | "no-console": "off",
12 | "no-undef": "off",
13 | "quotes": [
14 | "warn",
15 | "double"
16 | ],
17 | "semi": [
18 | "warn",
19 | "always"
20 | ],
21 | "keyword-spacing": [
22 | "error", {
23 | "before": true,
24 | "after": true
25 | }
26 | ],
27 | "space-before-blocks": [
28 | "error", {
29 | "functions": "always",
30 | "keywords": "always",
31 | "classes": "always"
32 | }
33 | ],
34 | "space-before-function-paren": [
35 | "error", {
36 | "anonymous": "never",
37 | "named": "never",
38 | "asyncArrow": "always"
39 | }
40 | ],
41 | "prefer-const": [
42 | "error", {
43 | "destructuring": "any",
44 | "ignoreReadBeforeAssign": false
45 | }
46 | ],
47 | "comma-dangle": [
48 | "warn", {
49 | "arrays": "never",
50 | "objects": "never",
51 | "imports": "never",
52 | "exports": "never",
53 | "functions": "ignore"
54 | }
55 | ]
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | *.js text
4 | *.json text
5 | *.md text
6 | *.example text
7 | *.sh linguist-language=Shell
8 |
9 | dashboard/public/css/darkly.css linguist-vendored
10 | dashboard/public/css/flatly.css linguist-vendored
11 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | **We accept contributions for anything!** Just fork this repository, make any changes you desire, and submit a pull request!
3 | Examples of things you can contribute are fortunes for the 8ball command, new commands and improvements to existing features, but you can submit a PR for basically anything.
4 |
5 | ## Fortunes for the 8ball command
6 | Check the comments in the file [here](https://github.com/DS-Development/delet/blob/master/commands/Fun/8ball.js).
7 |
8 | ## Translations
9 | If you'd like to sign up to be a translator for delet, you can do so [here](https://delet.js.org/go/translate). Note that the process of adding translations to the bot has not started yet, and we cannot guarantee that it will ever take place, as it will only do so if there is enough demand for this feature. The purpose of signing up is so we know who to go to in the event that we do end up implementing this feature.
10 |
11 | ## Commands
12 | The default command base we use is as follows:
13 | ```js
14 | const Command = require("../../base/Command.js");
15 |
16 | class CommandName extends Command {
17 | constructor(client) {
18 | super(client, {
19 | // The name of the command. In most cases, this should match the class and file name.
20 | name: "",
21 | // State what the command does
22 | description: "",
23 | // Choose from one of the directory names within the `commands` folder
24 | category: "",
25 | // State the command usage including all possible parameters/arguments
26 | usage: "",
27 | // An array of any other names the command can be invoked with.
28 | // Each value in the array must be a string.
29 | aliases: [],
30 | // If the command can be run in DMs, remove this property or set it to false.
31 | guildOnly: true,
32 | // Choose from "User", "Moderator", "Admin", "Bot Support", "Bot Admin" or "Bot Owner".
33 | // If the permLevel is just "User", the `permLevel` property can be removed from the constructor.
34 | permLevel: ""
35 | });
36 | }
37 |
38 | // Make sure to remove all unused params or add `// eslint-disable-line no-unused-vars` on the line
39 | async run(message, args, level, settings, texts) {
40 | // Command code here
41 | }
42 | }
43 |
44 | module.exports = CommandName;
45 | ```
46 |
47 | ### Want to join the DS Development Group?
48 | Head to [delet.js.org/go/join](https://delet.js.org/go/join)!
49 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Encountered a bug? Report it to us here.
4 |
5 | ---
6 |
7 |
9 |
10 | **Brief description of the bug/issue being encountered**
11 |
12 | **Expected behaviour**
13 |
14 | **Actual behaviour**
15 |
16 | **Steps to reproduce**
17 |
18 | 1.
19 | 2.
20 | 3.
21 | 4.
22 |
23 | **Additional info**
24 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for delet
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. E.g. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/general-issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: General issue
3 | about: Encountered an issue that isn't a bug? Tell us about it.
4 |
5 | ---
6 |
7 | **What's the expected behaviour of delet in this situation?**
8 |
9 | **What's the actual behaviour you're getting?**
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Type**
2 |
3 | - [ ] Bugfix
4 | - [ ] Enhancement
5 | - [ ] New feature
6 |
7 | **Description of the changes**
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | config.json
8 | config.js
9 | data/
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # Environment variables
18 | .env
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (http://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Typescript v1 declaration files
46 | typings/
47 |
48 | # Optional npm cache directory
49 | .npm
50 |
51 | # Optional eslint cache
52 | .eslintcache
53 |
54 | # Optional REPL history
55 | .node_repl_history
56 |
57 | # Output of 'npm pack'
58 | *.tgz
59 |
60 | # Yarn Integrity file
61 | .yarn-integrity
62 |
63 | # dotenv environment variables file
64 | .env
65 |
66 | # Specific files & folders
67 | session-encrypt.txt
68 | /assets/
69 | music/js/config.js
70 | music/js/audiotest.js
71 | .vscode/settings.json
72 | commands/embed.js
73 | docs/elements.html
74 | docs/generic.html
75 | docs/assets/xcf
76 | indev
77 | /test/
78 | /notes/
79 | /security/
80 | /docker-compose.yml
81 | /base/DS.js
82 | /points/
83 |
84 | # Temporary
85 | /tags/
86 | /Dockerfile
87 | /currency/
88 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "9"
4 | - "8"
5 |
6 | cache:
7 | directories:
8 | - "node_modules"
9 |
10 | addons:
11 | apt:
12 | update: true
13 |
14 | sudo: enabled
15 |
16 | before_install:
17 | - sudo apt-get update
18 | - sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
19 |
20 | # after_success:
21 | # - wget https://raw.githubusercontent.com/DS-Development/delet/master/build/travis/send.sh
22 | # - chmod +x send.sh
23 | # - ./send.sh success $WEBHOOK_URL
24 | after_failure:
25 | - wget https://raw.githubusercontent.com/DS-Development/delet/master/build/travis/send.sh
26 | - chmod +x send.sh
27 | - ./send.sh failure $WEBHOOK_URL
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Audio",
11 | "program": "${workspaceFolder}/music/js/audio.js"
12 | },
13 | {
14 | "type": "node",
15 | "request": "launch",
16 | "name": "Launch Index",
17 | "program": "${workspaceFolder}\\index.js"
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "test",
9 | "group": {
10 | "kind": "build",
11 | "isDefault": true
12 | }
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## NO LONGER MAINTAINED - will be replaced by delet3
2 | ### delet3 : https://github.com/suvanl/delet3
3 |
4 |
5 | ---
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | delet is a powerful, configurable and multipurpose Discord bot, made using the Discord.js library for the Discord API.
19 | Please ensure you read the section regarding self-hosting and portability in this README document.
20 |
21 | **[outdated content removed]**
22 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # AppVeyor file
2 | # http://www.appveyor.com/docs/appveyor-yml
3 |
4 | #---------------------------------#
5 | # General Configuration #
6 | #---------------------------------#
7 |
8 | # Build version format
9 | version: "{build}"
10 |
11 | # What combinations to test
12 | environment:
13 | matrix:
14 | - nodejs_version: "8"
15 | - nodejs_version: "9"
16 |
17 | # Caches the directory containing all installed npm modules
18 | cache:
19 | - node_modules
20 |
21 | branches:
22 | only:
23 | - master
24 |
25 | #---------------------------------#
26 | # Installation #
27 | #---------------------------------#
28 |
29 | install:
30 | # Get the latest stable version of Node.js
31 | - ps: Install-Product node $env:nodejs_version
32 | # Install latest version of npm
33 | - npm install npm@latest -g
34 | # Install node-gyp
35 | - npm install -g node-gyp
36 | # Install modules
37 | - npm install
38 |
39 | build: off
40 |
41 | #---------------------------------#
42 | # Tests #
43 | #---------------------------------#
44 |
45 | test_script:
46 | - npm test
47 |
48 | #---------------------------------#
49 | # Post-build #
50 | #---------------------------------#
51 |
52 | # on_success:
53 | # - ps: Invoke-RestMethod https://raw.githubusercontent.com/DS-Development/delet/master/build/appveyor/send.ps1 -o send.ps1
54 | # - ps: ./send.ps1 success $env:WEBHOOK_URL
55 | on_failure:
56 | - ps: Invoke-RestMethod https://raw.githubusercontent.com/DS-Development/delet/master/build/appveyor/send.ps1 -o send.ps1
57 | - ps: ./send.ps1 failure $env:WEBHOOK_URL
58 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: Windows
3 | pool:
4 | vmImage: VS2017-Win2016
5 | steps:
6 | - template: build/azure-pipelines/win32/continuous-build-win32.yml
7 |
8 | - job: macOS
9 | pool:
10 | vmImage: macOS 10.13
11 | steps:
12 | - template: build/azure-pipelines/darwin/continuous-build-darwin.yml
--------------------------------------------------------------------------------
/base/Command.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | class Command {
5 | constructor(client, {
6 | name = null,
7 | description = "No description provided.",
8 | category = "Miscellaneous",
9 | usage = "No usage provided.",
10 | enabled = true,
11 | guildOnly = false,
12 | aliases = new Array(),
13 | permLevel = "User"
14 | }) {
15 | this.client = client;
16 | this.conf = { enabled, guildOnly, aliases, permLevel };
17 | this.help = { name, description, category, usage };
18 | }
19 | }
20 | module.exports = Command;
21 |
--------------------------------------------------------------------------------
/base/Indev.js:
--------------------------------------------------------------------------------
1 | class Indev {
2 | constructor(client, {
3 | name = null,
4 | description = "No description provided.",
5 | category = "Miscellaneous",
6 | usage = "No usage provided.",
7 | enabled = false,
8 | guildOnly = false,
9 | aliases = new Array(),
10 | permLevel = "Bot Owner"
11 | }) {
12 | this.client = client;
13 | this.conf = { enabled, guildOnly, aliases, permLevel };
14 | this.help = { name, description, category, usage };
15 | }
16 | }
17 | module.exports = Indev;
18 |
--------------------------------------------------------------------------------
/build/appveyor/send.ps1:
--------------------------------------------------------------------------------
1 | # Forked from https://github.com/k3rn31p4nic/appveyor-discord-webhook
2 |
3 | # Author: Sankarsan Kampa (a.k.a. k3rn31p4nic)
4 | # License: MIT
5 |
6 | $STATUS=$args[0]
7 | $WEBHOOK_URL=$args[1]
8 |
9 | if (!$WEBHOOK_URL) {
10 | Write-Output "WARNING!!"
11 | Write-Output "You need to pass the WEBHOOK_URL environment variable as the second argument to this script."
12 | Write-Output "For details & guide, visit: https://github.com/k3rn31p4nic/appveyor-discord-webhook"
13 | Exit
14 | }
15 |
16 | Write-Output "[Webhook]: Sending webhook to Discord..."
17 |
18 | Switch ($STATUS) {
19 | "success" {
20 | $EMBED_COLOR=3066993
21 | $STATUS_MESSAGE="Passed"
22 | Break
23 | }
24 | "failure" {
25 | $EMBED_COLOR=15158332
26 | $STATUS_MESSAGE="Failed"
27 | Break
28 | }
29 | default {
30 | Write-Output "Default!"
31 | Break
32 | }
33 | }
34 | $AVATAR="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Appveyor_logo.svg/256px-Appveyor_logo.svg.png"
35 |
36 | if (!$env:APPVEYOR_REPO_COMMIT) {
37 | $env:APPVEYOR_REPO_COMMIT="$(git log -1 --pretty="%H")"
38 | }
39 |
40 | $AUTHOR_NAME="$(git log -1 "$env:APPVEYOR_REPO_COMMIT" --pretty="%aN")"
41 | $COMMITTER_NAME="$(git log -1 "$env:APPVEYOR_REPO_COMMIT" --pretty="%cN")"
42 | $COMMIT_SUBJECT="$(git log -1 "$env:APPVEYOR_REPO_COMMIT" --pretty="%s")"
43 | $COMMIT_MESSAGE="$(git log -1 "$env:APPVEYOR_REPO_COMMIT" --pretty="%b")"
44 |
45 | if ($AUTHOR_NAME -eq $COMMITTER_NAME) {
46 | $CREDITS="$AUTHOR_NAME authored & committed"
47 | }
48 | else {
49 | $CREDITS="$AUTHOR_NAME authored & $COMMITTER_NAME committed"
50 | }
51 |
52 | if ($env:APPVEYOR_PULL_REQUEST_NUMBER) {
53 | $URL="https://github.com/$env:APPVEYOR_REPO_NAME/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER"
54 | }
55 | else {
56 | $URL=""
57 | }
58 |
59 | $TIMESTAMP="$(Get-Date -format s)Z"
60 | $WEBHOOK_DATA="{
61 | ""username"": """",
62 | ""avatar_url"": ""$AVATAR"",
63 | ""embeds"": [ {
64 | ""color"": $EMBED_COLOR,
65 | ""author"": {
66 | ""name"": ""Job #$env:APPVEYOR_JOB_NUMBER (Build #$env:APPVEYOR_BUILD_NUMBER) $STATUS_MESSAGE - $env:APPVEYOR_REPO_NAME"",
67 | ""url"": ""https://ci.appveyor.com/project/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/build/$env:APPVEYOR_BUILD_VERSION"",
68 | ""icon_url"": ""$AVATAR""
69 | },
70 | ""title"": ""$COMMIT_SUBJECT"",
71 | ""url"": ""$URL"",
72 | ""description"": ""$COMMIT_MESSAGE $CREDITS"",
73 | ""fields"": [
74 | {
75 | ""name"": ""Commit"",
76 | ""value"": ""[``$($env:APPVEYOR_REPO_COMMIT.substring(0, 7))``](https://github.com/$env:APPVEYOR_REPO_NAME/commit/$env:APPVEYOR_REPO_COMMIT)"",
77 | ""inline"": true
78 | },
79 | {
80 | ""name"": ""Branch/Tag"",
81 | ""value"": ""[``$env:APPVEYOR_REPO_BRANCH``](https://github.com/$env:APPVEYOR_REPO_NAME/tree/$env:APPVEYOR_REPO_BRANCH)"",
82 | ""inline"": true
83 | }
84 | ],
85 | ""timestamp"": ""$TIMESTAMP""
86 | } ]
87 | }"
88 |
89 | Invoke-RestMethod -Uri "$WEBHOOK_URL" -Method "POST" -UserAgent "AppVeyor-Webhook" `
90 | -ContentType "application/json" -Header @{"X-Author"="boxeh#3254"} `
91 | -Body $WEBHOOK_DATA
92 |
93 | Write-Output "[Webhook]: Successfully sent."
94 |
--------------------------------------------------------------------------------
/build/azure-pipelines/darwin/continuous-build-darwin.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: NodeTool@0
3 | inputs:
4 | versionSpec: "8.12.0"
5 |
6 | - script: |
7 | npm install npm@latest -g
8 | displayName: Update npm
9 |
10 | - script: |
11 | npm install -g node-gyp
12 | displayName: Install node-gyp
13 |
14 | - script: |
15 | npm install
16 | displayName: Install dependencies
17 |
18 | - script: |
19 | npm audit
20 | displayName: Audit packages
21 |
22 | - script: |
23 | npm test
24 | displayName: Build & test
--------------------------------------------------------------------------------
/build/azure-pipelines/win32/continuous-build-win32.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: NodeTool@0
3 | inputs:
4 | versionSpec: "8.12.0"
5 |
6 | - powershell: |
7 | npm install npm@latest -g
8 | displayName: Update npm
9 |
10 | - powershell: |
11 | npm install -g node-gyp
12 | displayName: Install node-gyp
13 |
14 | - powershell: |
15 | npm install
16 | displayName: Install dependencies
17 |
18 | - powershell: |
19 | npm audit
20 | displayName: Audit packages
21 |
22 | - powershell: |
23 | npm test
24 | displayName: Build & test
--------------------------------------------------------------------------------
/build/text.js:
--------------------------------------------------------------------------------
1 | console.log(`
2 |
3 | dddddddd
4 | d::::::d lllllll tttt
5 | d::::::d l:::::l ttt:::t
6 | d::::::d l:::::l t:::::t
7 | d:::::d l:::::l t:::::t
8 | ddddddddd:::::d eeeeeeeeeeee l::::l eeeeeeeeeeee ttttttt:::::ttttttt
9 | dd::::::::::::::d ee::::::::::::ee l::::l ee::::::::::::ee t:::::::::::::::::t
10 | d::::::::::::::::d e::::::eeeee:::::eel::::l e::::::eeeee:::::eet:::::::::::::::::t
11 | d:::::::ddddd:::::d e::::::e e:::::el::::l e::::::e e:::::etttttt:::::::tttttt
12 | d::::::d d:::::d e:::::::eeeee::::::el::::l e:::::::eeeee::::::e t:::::t
13 | d:::::d d:::::d e:::::::::::::::::e l::::l e:::::::::::::::::e t:::::t
14 | d:::::d d:::::d e::::::eeeeeeeeeee l::::l e::::::eeeeeeeeeee t:::::t
15 | d:::::d d:::::d e:::::::e l::::l e:::::::e t:::::t tttttt
16 | d::::::ddddd::::::dde::::::::e l::::::le::::::::e t::::::tttt:::::t
17 | d:::::::::::::::::d e::::::::eeeeeeee l::::::l e::::::::eeeeeeee tt::::::::::::::t
18 | d:::::::::ddd::::d ee:::::::::::::e l::::::l ee:::::::::::::e tt:::::::::::tt
19 | ddddddddd ddddd eeeeeeeeeeeeee llllllll eeeeeeeeeeeeee ttttttttttt
20 |
21 | `);
22 |
23 | console.log(`Build completed @ ${new Date()}.`);
24 |
--------------------------------------------------------------------------------
/build/travis/send.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "$2" ]; then
4 | echo -e "WARNING!!\nYou need to pass the WEBHOOK_URL environment variable as the second argument to this script.\nFor details & guide, visit: https://github.com/k3rn31p4nic/travis-ci-discord-webhook" && exit
5 | fi
6 |
7 | echo -e "[Webhook]: Sending webhook to Discord...\\n";
8 |
9 | case $1 in
10 | "success" )
11 | EMBED_COLOR=3066993
12 | STATUS_MESSAGE="Passed"
13 | AVATAR="https://travis-ci.org/images/logos/TravisCI-Mascot-blue.png"
14 | ;;
15 |
16 | "failure" )
17 | EMBED_COLOR=15158332
18 | STATUS_MESSAGE="Failed"
19 | AVATAR="https://travis-ci.org/images/logos/TravisCI-Mascot-red.png"
20 | ;;
21 |
22 | * )
23 | EMBED_COLOR=0
24 | STATUS_MESSAGE="Status Unknown"
25 | AVATAR="https://travis-ci.org/images/logos/TravisCI-Mascot-1.png"
26 | ;;
27 | esac
28 |
29 | AUTHOR_NAME="$(git log -1 "$TRAVIS_COMMIT" --pretty="%aN")"
30 | COMMITTER_NAME="$(git log -1 "$TRAVIS_COMMIT" --pretty="%cN")"
31 | COMMIT_SUBJECT="$(git log -1 "$TRAVIS_COMMIT" --pretty="%s")"
32 | COMMIT_MESSAGE="$(git log -1 "$TRAVIS_COMMIT" --pretty="%b")"
33 |
34 | if [ "$AUTHOR_NAME" == "$COMMITTER_NAME" ]; then
35 | CREDITS="$AUTHOR_NAME authored & committed"
36 | else
37 | CREDITS="$AUTHOR_NAME authored & $COMMITTER_NAME committed"
38 | fi
39 |
40 | if [[ $TRAVIS_PULL_REQUEST != false ]]; then
41 | URL="https://github.com/$TRAVIS_REPO_SLUG/pull/$TRAVIS_PULL_REQUEST"
42 | else
43 | URL=""
44 | fi
45 |
46 | TIMESTAMP=$(date --utc +%FT%TZ)
47 | WEBHOOK_DATA='{
48 | "username": "",
49 | "avatar_url": "https://travis-ci.org/images/logos/TravisCI-Mascot-1.png",
50 | "embeds": [ {
51 | "color": '$EMBED_COLOR',
52 | "author": {
53 | "name": "Job #'"$TRAVIS_JOB_NUMBER"' (Build #'"$TRAVIS_BUILD_NUMBER"') '"$STATUS_MESSAGE"' - '"$TRAVIS_REPO_SLUG"'",
54 | "url": "https://travis-ci.org/'"$TRAVIS_REPO_SLUG"'/builds/'"$TRAVIS_BUILD_ID"'",
55 | "icon_url": "'$AVATAR'"
56 | },
57 | "title": "'"$COMMIT_SUBJECT"'",
58 | "url": "'"$URL"'",
59 | "description": "'"${COMMIT_MESSAGE//$'\n'/ }"\\n\\n"$CREDITS"'",
60 | "fields": [
61 | {
62 | "name": "Commit",
63 | "value": "'"[\`${TRAVIS_COMMIT:0:7}\`](https://github.com/$TRAVIS_REPO_SLUG/commit/$TRAVIS_COMMIT)"'",
64 | "inline": true
65 | },
66 | {
67 | "name": "Branch/Tag",
68 | "value": "'"[\`$TRAVIS_BRANCH\`](https://github.com/$TRAVIS_REPO_SLUG/tree/$TRAVIS_BRANCH)"'",
69 | "inline": true
70 | }
71 | ],
72 | "timestamp": "'"$TIMESTAMP"'"
73 | } ]
74 | }'
75 |
76 | (curl --fail --progress-bar -A "TravisCI-Webhook" -H Content-Type:application/json -H X-Author:boxeh#3254 -d "$WEBHOOK_DATA" "$2" \
77 | && echo -e "\\n[Webhook]: Successfully sent the webhook.") || echo -e "\\n[Webhook]: Unable to send webhook."
--------------------------------------------------------------------------------
/commands/Debug/eval.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | // The EVAL command will execute **ANY** arbitrary JavaScript code given to it.
5 | // Therefore, this command is permission level 10 to prevent others using it. It
6 | // can be dangerous, as Eval can be used to do anything on the host machine.
7 | // However, it's extremely useful for troubleshooting and doing stuff you don't
8 | // want to put in a command.
9 |
10 | const Command = require("../../base/Command.js");
11 |
12 | class Eval extends Command {
13 | constructor(client) {
14 | super(client, {
15 | name: "eval",
16 | description: "Evaluates arbitrary JavaScript.",
17 | category: "Debug",
18 | usage: "eval ",
19 | aliases: ["ev"],
20 | permLevel: "Bot Owner"
21 | });
22 | }
23 |
24 | async run(message, args, level) { // eslint-disable-line no-unused-vars
25 | this.client.logger.warn("Eval command used");
26 |
27 | const code = args.join(" ");
28 | try {
29 | const evaled = eval(code);
30 | const clean = await this.client.clean(this.client, evaled);
31 | const MAX_CHARS = 3 + 2 + clean.length + 3;
32 | if (MAX_CHARS > 2000) {
33 | return message.channel.send("Output exceeded 2000 characters, sending as a file.", { files: [{ attachment: Buffer.from(clean), name: "output.txt" }] });
34 | }
35 | message.channel.send(`\`\`\`js\n${clean}\n\`\`\``);
36 | } catch (err) {
37 | message.channel.send(`\`ERROR\` \`\`\`xl\n${await this.client.clean(this.client, err)}\n\`\`\``);
38 | }
39 | }
40 | }
41 |
42 | module.exports = Eval;
43 |
--------------------------------------------------------------------------------
/commands/Debug/event.js:
--------------------------------------------------------------------------------
1 | // The EVENT command will emit an event. This is useful, but should only
2 | // be used for debugging purposes.
3 |
4 | const Command = require("../../base/Command.js");
5 |
6 | class Event extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "event",
10 | description: "Emits an event.",
11 | category: "Debug",
12 | usage: "event",
13 | aliases: ["emit"],
14 | permLevel: "Bot Owner",
15 | guildOnly: true
16 | });
17 | }
18 |
19 | async run(message, args, level) { // eslint-disable-line no-unused-vars
20 | const member = message.mentions.members.first() || message.member;
21 |
22 | await this.client.emit("guildMemberAdd", member);
23 | }
24 | }
25 |
26 | module.exports = Event;
--------------------------------------------------------------------------------
/commands/Debug/exec.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/NotAWeebDev/Misaki
3 |
4 | // The EXEC command will execute **ANY** new specified process. This can be
5 | // extremely dangerous if used incorrectly, hence why it is reserved strictly
6 | // for the bot owner only. This command spawns a new child process, and
7 | // executes the given command. It should only be used for debugging purposes.
8 |
9 | const Command = require("../../base/Command.js");
10 | const exec = require("child_process").exec;
11 |
12 | class Exec extends Command {
13 | constructor(client) {
14 | super(client, {
15 | name: "exec",
16 | description: "Evaluates arbitrary JavaScript.",
17 | category: "Debug",
18 | usage: "exec ",
19 | permLevel: "Bot Owner"
20 | });
21 | }
22 |
23 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
24 | this.client.logger.warn("Exec command used");
25 |
26 | try {
27 | exec(`${args.join(" ")}`, (error, stdout) => {
28 | const response = (error || stdout);
29 | message.channel.send(`Ran command **\`${message.content.slice(6)}\`**:\n\`\`\`${response}\`\`\``, {split: true});
30 | });
31 | } catch (error) {
32 | this.client.logger.error(error.stack);
33 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
34 | }
35 | }
36 | }
37 |
38 | module.exports = Exec;
39 |
--------------------------------------------------------------------------------
/commands/Debug/filesize.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fs = require("fs");
3 |
4 | class FileSize extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "filesize",
8 | description: "Returns the value of the size of the specified file.",
9 | category: "Debug",
10 | usage: "filesize ",
11 | aliases: ["fs"],
12 | permLevel: "Bot Admin"
13 | });
14 | }
15 |
16 | async run(message, args, level) { // eslint-disable-line no-unused-vars
17 | const file = args[0];
18 | if (!file) return message.channel.send("You must provide a file (and location if non-root file), and the correct syntax must be used.");
19 |
20 | try {
21 | const stats = fs.statSync(file);
22 | const fileBytes = stats["size"];
23 | const fileKB = fileBytes / 1024;
24 |
25 | message.channel.send(`\`${file}\` currently has a size of **${fileBytes}** bytes (${fileKB.toFixed(2)}KB).`);
26 | } catch (error) {
27 | if (error.code === "ENOENT") return message.channel.send(`The file \`${file}\` could not be found.`);
28 | else this.client.logger.error(error);
29 | }
30 | }
31 | }
32 |
33 | module.exports = FileSize;
34 |
--------------------------------------------------------------------------------
/commands/Fun/bigletter.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class BigLetter extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "bigletter",
7 | description: "Converts the specified text to regional indicators.",
8 | category: "Fun",
9 | usage: "bigletter ",
10 | aliases: ["regional", "regional-indicator"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const generate = () => {
16 | let text = args.join(" ");
17 | if (!text) return message.channel.send("You must provide some text to convert to regional indicator emojis.");
18 | else text = args.join(" ").toLowerCase();
19 |
20 | const numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
21 | const isAlphaNumeric = (str) => {
22 | let code, i, len;
23 | for (i = 0, len = str.length; i < len; i++) {
24 | code = str.charCodeAt(i);
25 | if (!(code > 47 && code < 58) && !(code > 64 && code < 91) && !(code > 96 && code < 123) && code !== 32) {
26 | return false;
27 | }
28 | }
29 | return true;
30 | };
31 |
32 | if (!isAlphaNumeric(text)) return message.channel.send("Invalid character(s) provided.\nPlease ensure you have only provided alphanumeric characters.");
33 |
34 | let output = "";
35 |
36 | for (let i = 0; i < text.length; i++) {
37 | const char = text.charAt(i);
38 | if (char === " ") output += char;
39 | else if (numbers.includes(char)) output += numberToString(char);
40 | else output += `:regional_indicator_${char}: `;
41 | }
42 |
43 | return output;
44 | };
45 |
46 | const numberToString = (number) => {
47 | let value = "";
48 |
49 | switch (number) {
50 | case "0":
51 | value = ":zero :";
52 | break;
53 |
54 | case "1":
55 | value = ":one: ";
56 | break;
57 |
58 | case "2":
59 | value = ":two: ";
60 | break;
61 |
62 | case "3":
63 | value = ":three: ";
64 | break;
65 |
66 | case "4":
67 | value = ":four: ";
68 | break;
69 |
70 | case "5":
71 | value = ":five: ";
72 | break;
73 |
74 | case "6":
75 | value = ":six: ";
76 | break;
77 |
78 | case "7":
79 | value = ":seven: ";
80 | break;
81 |
82 | case "8":
83 | value = ":eight: ";
84 | break;
85 |
86 | case "9":
87 | value = ":nine: ";
88 | break;
89 | }
90 | return value;
91 | };
92 |
93 | message.channel.send(generate())
94 | .catch(error => {
95 | if (error.message === "Cannot send an empty message") return;
96 | else this.client.logger.error(error.message);
97 | });
98 | }
99 | }
100 |
101 | module.exports = BigLetter;
102 |
--------------------------------------------------------------------------------
/commands/Fun/cleverbot.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const cleverbot = require("cleverbot.io");
3 | const { CLEVERBOT_API_USER, CLEVERBOT_API_KEY } = process.env;
4 | const bot = new cleverbot(CLEVERBOT_API_USER, CLEVERBOT_API_KEY);
5 |
6 | class CleverBot extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "cleverbot",
10 | description: "Talks to cleverbot!",
11 | category: "Fun",
12 | usage: "cleverbot ",
13 | aliases: ["cb"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | bot.setNick("delet");
19 | bot.create(function() {
20 | const query = args.join(" ");
21 | if (!query) return message.channel.send("You must provide a message to say to me.");
22 |
23 | message.channel.startTyping();
24 |
25 | bot.ask(query, (err, response) => {
26 | message.channel.send(response.includes("Cleverbot") ? response.replace(/Cleverbot/g, "delet") : response);
27 | message.channel.stopTyping(true);
28 |
29 | if (err) {
30 | this.client.logger.error(err);
31 | return message.channel.send(texts.general.error.replace(/{{err}}/g, err.message));
32 | }
33 | });
34 | });
35 | }
36 | }
37 |
38 | module.exports = CleverBot;
39 |
--------------------------------------------------------------------------------
/commands/Fun/dadjoke.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class DadJoke extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "dadjoke",
8 | description: "Sends a random dad joke.",
9 | category: "Fun",
10 | usage: "dadjoke",
11 | aliases: ["dad", "dadj", "badjoke"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const meta = { "Accept": "text/plain" };
17 |
18 | fetch("https://icanhazdadjoke.com/", { headers: meta })
19 | .then(res => res.text())
20 | .then(body => message.channel.send(body))
21 | .catch(error => {
22 | this.client.logger.error(error);
23 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
24 | });
25 | }
26 | }
27 |
28 | module.exports = DadJoke;
29 |
--------------------------------------------------------------------------------
/commands/Fun/expand.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Expand extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "expand",
8 | description: "Makes the specified text T H I C C",
9 | category: "Fun",
10 | usage: "expand "
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const text = encodeURIComponent(args.join(" "));
16 | if (!text) return message.channel.send("You must provide some text to expand.");
17 | const tooLong = "Unfortunately, the specified text is too long. Please try again with something a little shorter.";
18 |
19 | fetch(`http://artii.herokuapp.com/make?text=${text}`)
20 | .then(res => res.text())
21 | .then(body => {
22 | if (body.length > 2000) return message.channel.send(tooLong);
23 | return message.channel.send(body, { code: "fix" });
24 | })
25 | .catch(error => {
26 | this.client.logger.error(error);
27 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
28 | });
29 | }
30 | }
31 |
32 | module.exports = Expand;
33 |
--------------------------------------------------------------------------------
/commands/Fun/flip.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { currencies } = require("../../util/data.js");
3 | const { RichEmbed } = require("discord.js");
4 | const { stripIndents } = require("common-tags");
5 |
6 | const fullName = {
7 | "EUR": "Euro",
8 | "GBP": "Pound Sterling",
9 | "NOK": "Norwegian Kroner",
10 | "USD": "US Dollar"
11 | };
12 |
13 | class Flip extends Command {
14 | constructor(client) {
15 | super(client, {
16 | name: "flip",
17 | description: "Flips/tosses a coin.",
18 | category: "Fun",
19 | usage: "flip",
20 | aliases: ["toss"],
21 | guildOnly: true
22 | });
23 | }
24 |
25 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
26 | // If no currency is set
27 | if (settings.currency === ">>No currency set<<") return message.channel.send(stripIndents`
28 | I cannot run this command, as I don't know which currency to use on this server. Please set a currency by using:
29 | \`\`\`${settings.prefix}set edit currency TYPE\`\`\`
30 | Currently available types: ${currencies.map(c => "`" + c + "`").join(", ")}`);
31 |
32 | const coinFlip = () => (Math.floor(Math.random() * 2) == 0) ? "heads" : "tails";
33 | const flip = coinFlip();
34 |
35 | const embed = new RichEmbed()
36 | .setDescription(`This flip's result was **${flip}**!\n\nTime taken: ${(this.client.ping / 1000).toFixed(3)}s\nCurrency: ${fullName[settings.currency]} (${settings.currency})`)
37 | .setThumbnail(flip === "heads" ? `https://delet.js.org/imgstore/currency/${settings.currency}/${settings.currency}heads.png` : `https://delet.js.org/imgstore/currency/${settings.currency}/${settings.currency}tails.png`);
38 | return message.channel.send({ embed });
39 | }
40 | }
41 |
42 | module.exports = Flip;
43 |
--------------------------------------------------------------------------------
/commands/Fun/joke.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Joke extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "joke",
8 | description: "Tells a general or programming-related joke.",
9 | category: "Fun",
10 | usage: "joke",
11 | aliases: ["humour", "humor"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | fetch("https://official-joke-api.appspot.com/random_joke")
17 | .then(res => res.json())
18 | .then(data => message.channel.send(`${data.setup} ${data.punchline}`))
19 | .catch(error => {
20 | this.client.logger.error(error);
21 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error));
22 | });
23 | }
24 | }
25 |
26 | module.exports = Joke;
27 |
--------------------------------------------------------------------------------
/commands/Fun/lmgtfy.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class LMGTFY extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "lmgtfy",
7 | description: "Why don't you just... Google it?",
8 | category: "Fun",
9 | usage: "lmgtfy ",
10 | aliases: ["googleit"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
15 | const textQuery = args.join(" ");
16 | const query = encodeURIComponent(args.join(" "));
17 | const url = `https://lmgtfy.com/?q=${query}`;
18 |
19 | if (!query) return message.channel.send(`Please enter a query. For example, \`${settings.prefix}lmgtfy How to create a Discord server\`.`);
20 | else message.channel.send(`"${textQuery}"\n**<${url}>**`);
21 | }
22 | }
23 |
24 | module.exports = LMGTFY;
--------------------------------------------------------------------------------
/commands/Fun/rate.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Rate extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "rate",
7 | description: "Rates something out of 10.",
8 | category: "Fun",
9 | usage: "rate "
10 | });
11 | }
12 |
13 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
14 | const rateObject = args.join(" ");
15 | if (!rateObject) return message.channel.send(texts.cmd.fun.noRate);
16 | const rate = Math.floor(Math.random() * 10) +1;
17 |
18 | let rateMsg;
19 |
20 | if (rate === 0) rateMsg = "a big fat";
21 | if (rate === 0 || rate === 1 || rate === 2) rateMsg = "quite a poor";
22 | if (rate === 3 || rate === 4) rateMsg = "an improvable";
23 | if (rate === 5 || rate === 6) rateMsg = "a pretty moderate";
24 | if (rate === 7 || rate === 8 || rate === 9) rateMsg = "a high";
25 | if (rate === 10) rateMsg = "a solid";
26 |
27 | message.channel.send(`I'd give "${rateObject}" ${rateMsg} ${rate}/10.`);
28 | }
29 | }
30 |
31 | module.exports = Rate;
--------------------------------------------------------------------------------
/commands/Fun/roll.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Roll extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "roll",
7 | description: "Rolls a regular six-sided dice.",
8 | category: "Fun",
9 | usage: "roll",
10 | aliases: ["dice"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const numbers = [
16 | ":one:",
17 | ":two:",
18 | ":three:",
19 | ":four:",
20 | ":five:",
21 | ":six:"
22 | ];
23 |
24 | try {
25 | const roll = numbers.random();
26 | const msg = await message.channel.send(`${texts.cmd.fun.rolling} 🎲`);
27 | msg.edit(texts.cmd.fun.rolled.replace(/{{result}}/g, roll));
28 | } catch (error) {
29 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
30 | }
31 | }
32 | }
33 |
34 | module.exports = Roll;
35 |
--------------------------------------------------------------------------------
/commands/Fun/say.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Say extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "say",
7 | description: "Repeats your message.",
8 | category: "Fun",
9 | usage: "say [tts] ",
10 | aliases: ["repeat", "echo"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
15 | const msg = args.join(" ");
16 | if (!msg) return message.channel.send("You must provide a message for me to repeat.");
17 | if (args[0].toLowerCase() === "tts" && !args[1]) return message.channel.send("You must provide a message for me to repeat with TTS.");
18 |
19 | return message.channel.send(args[0].toLowerCase() === "tts" ? msg.slice(4) : msg, { tts: args[0].toLowerCase() === "tts" ? true : false });
20 | }
21 | }
22 |
23 | module.exports = Say;
--------------------------------------------------------------------------------
/commands/Fun/slots.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { stripIndents } = require("common-tags");
3 | const slots = ["🍇", "🍊", "🍐", "🍒", "🍋"];
4 |
5 | class Slots extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "slots",
9 | description: "Spin the slot machine!",
10 | category: "Fun",
11 | usage: "slots",
12 | aliases: ["slotmachine"],
13 | guildOnly: true
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | const slotOne = slots[Math.floor(Math.random() * slots.length)];
19 | const slotTwo = slots[Math.floor(Math.random() * slots.length)];
20 | const slotThree = slots[Math.floor(Math.random() * slots.length)];
21 | if (slotOne === slotTwo && slotOne === slotThree) {
22 | return message.channel.send(stripIndents`
23 | ${slotOne}|${slotTwo}|${slotThree}
24 | ${texts.cmd.fun.slotWin}
25 | `);
26 | }
27 | return message.channel.send(stripIndents`
28 | ${slotOne}|${slotTwo}|${slotThree}
29 | ${texts.cmd.fun.slotLoss}
30 | `);
31 | }
32 | }
33 |
34 | module.exports = Slots;
35 |
--------------------------------------------------------------------------------
/commands/Fun/tableflip.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const flipFrames = [
3 | "(-°□°)- ┬─┬",
4 | "(╯°□°)╯ ]",
5 | "(╯°□°)╯ ︵ ┻━┻",
6 | "(╯°□°)╯ [",
7 | "(╯°□°)╯ ┬─┬"
8 | ];
9 |
10 | class TableFlip extends Command {
11 | constructor(client) {
12 | super(client, {
13 | name: "tableflip",
14 | description: "Flips a table, in real-time! (╯°□°)╯",
15 | category: "Fun",
16 | usage: "tableflip"
17 | });
18 | }
19 |
20 | async run(message, args, level) { // eslint-disable-line no-unused-vars
21 | const msg = await message.channel.send("(\\\\°□°)\\\\ ┬─┬");
22 |
23 | for (const frame of flipFrames) {
24 | await this.client.wait(300);
25 | await msg.edit(frame);
26 | }
27 | return msg;
28 | }
29 | }
30 |
31 | module.exports = TableFlip;
--------------------------------------------------------------------------------
/commands/Fun/trivia.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/NotAWeebDev/Misaki
3 |
4 | const Command = require("../../base/Command.js");
5 | const { RichEmbed } = require("discord.js");
6 | const { stripIndents } = require("common-tags");
7 | const snekfetch = require("snekfetch");
8 | const h = new (require("html-entities").AllHtmlEntities)();
9 |
10 | class Trivia extends Command {
11 | constructor(client) {
12 | super(client, {
13 | name: "trivia",
14 | description: "Puts your general knowledge to the test.",
15 | category: "Fun",
16 | usage: "trivia [difficulty]",
17 | aliases: ["randomtrivia", "randomq", "testme", "quiz"]
18 | });
19 | }
20 |
21 | async run(message, args, level) { // eslint-disable-line no-unused-vars
22 | const levels = ["easy", "medium", "hard"];
23 | const difficulty = args[0] || "medium";
24 | if (!levels.includes(difficulty.toLowerCase())) return message.channel.send("Invalid difficulty specified. Please choose from one of **easy**, **medium** or **hard**.");
25 |
26 | const { body } = await snekfetch.get(`https://opentdb.com/api.php?amount=50&difficulty=${difficulty.toLowerCase()}&type=multiple`);
27 | const quiz = body.results.random();
28 | const choices = quiz.incorrect_answers.map(ans => h.decode(ans));
29 | choices.push(h.decode(quiz.correct_answer));
30 |
31 | const randomChoices = new Array(4);
32 | for (let i = 0; i < 4; i++) {
33 | randomChoices[i] = choices.random();
34 | choices.splice(choices.indexOf(randomChoices[i]), 1);
35 | }
36 |
37 | const embed = new RichEmbed()
38 | .setColor(5360873)
39 | .setAuthor("Trivia", "https://vgy.me/9UDUk0.png")
40 | .setDescription(stripIndents`
41 | **Question**
42 | ${h.decode(quiz.question)}
43 |
44 | :regional_indicator_a: ${randomChoices[0]}
45 | :regional_indicator_b: ${randomChoices[1]}
46 | :regional_indicator_c: ${randomChoices[2]}
47 | :regional_indicator_d: ${randomChoices[3]}
48 |
49 | **Category & Difficulty**
50 | ${h.decode(quiz.category)} | ${h.decode(quiz.difficulty.toProperCase())}
51 | `)
52 | .setFooter("Reply with the correct letter within 60 seconds!", message.author.displayAvatarURL);
53 |
54 | const question = await this.client.awaitEmbedReply(message, "", m => m.author.id === message.author.id, 60000, {embed: embed});
55 | if (!question) return message.channel.send("**Trivia session ended**\nThe session timed out as you did not answer within 60 seconds.");
56 |
57 | const choice = randomChoices[["a", "b", "c", "d"].indexOf(question.toLowerCase())];
58 | if (!choice) return message.channel.send("That's not a valid answer!\nFor future reference, please ensure your answer is either **A**, **B**, **C**, or **D** (lowercase and uppercase are both accepted).");
59 | if (choice === h.decode(quiz.correct_answer)) return message.channel.send("Well done, your answer is correct!\nTrivia session ended.");
60 | else return message.channel.send(`Unfortunately, that's the wrong answer. The correct answer was **${h.decode(quiz.correct_answer)}**, and you chose **${choice}**.\nTrivia session ended.`);
61 | }
62 | }
63 |
64 | module.exports = Trivia;
65 |
--------------------------------------------------------------------------------
/commands/Fun/urban.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const fetch = require("node-fetch");
4 |
5 | class Urban extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "urban",
9 | description: "Searches the Urban Dictionary for the specified query.",
10 | category: "Fun",
11 | usage: "urban ",
12 | aliases: ["urbandictionary", "udictionary", "urban-dictionary"]
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | const query = args.join(" ");
18 | if (!query) return message.channel.send("You must provide a term to search for.");
19 |
20 | fetch(`http://api.urbandictionary.com/v0/define?term=${query}`)
21 | .then(res => res.json())
22 | .then(json => {
23 | const data = json.list[0];
24 | const definition = data.definition.replace(/[[\]]+/g, "");
25 | const example = data.example.replace(/[[\]]+/g, "");
26 | const embed = new RichEmbed()
27 | .setColor(50687)
28 | .setAuthor("Urban Dictionary", "https://vgy.me/ScvJzi.jpg")
29 | .setDescription(`Displaying Urban Dictionary definition for "**${data.word}**"\n<${data.permalink}>`)
30 | .addField("» Definition", `**${definition.substring(0, 1000)}...**`)
31 | .addField("» Example", `${example.substring(0, 1000)}...`)
32 | .setFooter(`Definition 1 of ${json.list.length}`)
33 | .setTimestamp();
34 | return message.channel.send({ embed });
35 | })
36 | .catch(error => {
37 | this.client.logger.error(error);
38 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
39 | });
40 | }
41 | }
42 |
43 | module.exports = Urban;
--------------------------------------------------------------------------------
/commands/Fun/vaportext.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Vaportext extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "vaportext",
7 | description: "A E S T H E T I C",
8 | category: "Fun",
9 | usage: "vaportext ",
10 | aliases: ["vapor", "vapour", "vapourtext"]
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | if (!args.length) return message.channel.send("You must provide some text to make ***A E S T H E T I C A L L Y P L E A S I N G***.");
16 |
17 | let msg = "";
18 | for (let i = 0; i < args.length; i++) {
19 | msg += args[i].toUpperCase().split("").join(" ") + " ";
20 | }
21 |
22 | return message.channel.send(msg);
23 | }
24 | }
25 |
26 | module.exports = Vaportext;
27 |
--------------------------------------------------------------------------------
/commands/Fun/vaporwave.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | const songs = [
4 | `${process.cwd()}/assets/audio/Vaporwave1.mp3`,
5 | `${process.cwd()}/assets/audio/Vaporwave2.mp3`,
6 | `${process.cwd()}/assets/audio/Vaporwave3.mp3`,
7 | `${process.cwd()}/assets/audio/Vaporwave4.mp3`
8 | ];
9 |
10 | class Vaporwave extends Command {
11 | constructor(client) {
12 | super(client, {
13 | name: "vaporwave",
14 | description: "Plays vaporwave music.",
15 | category: "Fun",
16 | usage: "vaporwave ",
17 | aliases: ["vapourwave"]
18 | });
19 | }
20 |
21 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
22 | const voiceChannel = message.member.voiceChannel;
23 | if (!voiceChannel) return message.channel.send("You must be in a voice channel to be able to play VAPORWAVE MUSIC 可益ビ.");
24 |
25 | const permissions = voiceChannel.permissionsFor(message.client.user);
26 | if (!permissions.has("CONNECT")) return message.channel.send("I cannot play any music, as I do not have the \"CONNECT\" permission.");
27 | if (!permissions.has("SPEAK")) return message.channel.send("I cannot play any music, as I do not have the \"SPEAK\" permission.");
28 |
29 | if (args[0] && args[0].toLowerCase() === "stop") {
30 | if (!voiceChannel) return message.channel.send("You must be in a VOICE CHANNEL to use this command.");
31 | voiceChannel.leave();
32 | return message.channel.send("STOPPED");
33 | }
34 |
35 | try {
36 | const connection = await voiceChannel.join(); // eslint-disable-line no-unused-vars
37 | } catch (error) {
38 | this.client.logger.error(`Couldn't join voice channel: ${error}`);
39 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
40 | }
41 |
42 | const connection = await voiceChannel.join();
43 | const dispatcher = connection.playFile(songs.random())
44 | .on("end", () => voiceChannel.leave())
45 | .on("error", error => this.client.logger.error(error));
46 | dispatcher.setVolumeLogarithmic(5 / 5);
47 | }
48 | }
49 |
50 | module.exports = Vaporwave;
--------------------------------------------------------------------------------
/commands/Image/cat.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Cat extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "cat",
8 | description: "Sends a random image of a cat.",
9 | category: "Image",
10 | usage: "cat"
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | message.channel.startTyping();
16 |
17 | fetch("https://aws.random.cat/meow")
18 | .then(res => res.json())
19 | .then(data => message.channel.send({ file: data.file }))
20 | .catch(error => {
21 | this.client.logger.error(error);
22 | message.channel.stopTyping(true);
23 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
24 | });
25 |
26 | message.channel.stopTyping(true);
27 | }
28 | }
29 |
30 | module.exports = Cat;
--------------------------------------------------------------------------------
/commands/Image/changemymind.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class ChangeMyMind extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "changemymind",
8 | description: "Change my mind...",
9 | category: "Image",
10 | usage: "changemymind ",
11 | aliases: ["change-my-mind", "change"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | let text = args.join(" ");
17 | if (!text) return message.channel.send("You must provide some text to appear on the image.");
18 | else text = encodeURIComponent(args.join(" "));
19 |
20 | message.channel.startTyping();
21 |
22 | fetch(`https://nekobot.xyz/api/imagegen?type=changemymind&text=${text}`)
23 | .then(res => res.json())
24 | .then(data => message.channel.send({ file: data.message }))
25 | .catch(error => {
26 | this.client.logger.error(error);
27 | message.channel.stopTyping(true);
28 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
29 | });
30 |
31 | message.channel.stopTyping(true);
32 | }
33 | }
34 |
35 | module.exports = ChangeMyMind;
36 |
--------------------------------------------------------------------------------
/commands/Image/dog.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Dog extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "dog",
8 | description: "Sends a random image of a dog.",
9 | category: "Image",
10 | usage: "dog"
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | message.channel.startTyping();
16 |
17 | fetch("https://dog.ceo/api/breeds/image/random")
18 | .then(res => res.json())
19 | .then(data => message.channel.send({ file: data.message }))
20 | .catch(error => {
21 | this.client.logger.error(error);
22 | message.channel.stopTyping(true);
23 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
24 | });
25 |
26 | message.channel.stopTyping(true);
27 | }
28 | }
29 |
30 | module.exports = Dog;
--------------------------------------------------------------------------------
/commands/Image/faketweet.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class FakeTweet extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "faketweet",
8 | description: "Creates a fake tweet.",
9 | category: "Image",
10 | usage: "faketweet ",
11 | aliases: ["fake-tweet"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | let user = args[0];
17 | let text = args.slice(1).join(" ") || undefined;
18 | if (!user) return message.channel.send("You must provide a Twitter username, to have as the author of the tweet.");
19 | if (user.startsWith("@")) user = args[0].slice(1);
20 |
21 | const type = user.toLowerCase() === "realdonaldtrump" ? "trumptweet" : "tweet";
22 | const u = user.startsWith("@") ? user.slice(1) : user;
23 |
24 | if (!text) {
25 | text = await this.client.awaitReply(message, "Please enter the tweet's message...\nReply with `cancel` to exit this text-entry period.", 30000);
26 | if (text.toLowerCase() === "cancel") return message.channel.send("Cancelled.");
27 | }
28 |
29 | message.channel.startTyping();
30 |
31 | fetch(`https://nekobot.xyz/api/imagegen?type=${type}&username=${u}&text=${encodeURIComponent(text)}`)
32 | .then(res => res.json())
33 | .then(data => message.channel.send({ file: data.message }))
34 | .catch(error => {
35 | this.client.logger.error(error);
36 | message.channel.stopTyping(true);
37 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
38 | });
39 |
40 | message.channel.stopTyping(true);
41 | }
42 | }
43 |
44 | module.exports = FakeTweet;
45 |
--------------------------------------------------------------------------------
/commands/Image/giphy.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 | const { URLSearchParams } = require("url");
4 | const { GIPHY_API_KEY } = process.env;
5 |
6 | class Giphy extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "giphy",
10 | description: "Returns a GIF from Giphy based on your query.",
11 | category: "Image",
12 | usage: "giphy ",
13 | aliases: ["gif"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | const query = args[0];
19 | if (!query) return message.channel.send("You must provide a query to return a GIF for.");
20 |
21 | const url = "http://api.giphy.com/v1/gifs/search?";
22 | const params = new URLSearchParams({
23 | q: query,
24 | api_key: GIPHY_API_KEY,
25 | rating: "pg"
26 | });
27 |
28 | fetch(url + params)
29 | .then(res => res.json())
30 | .then(json => message.channel.send(json.data.random().images.original.url))
31 | .catch(error => {
32 | this.client.logger.error(error);
33 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
34 | });
35 | }
36 | }
37 |
38 | module.exports = Giphy;
39 |
--------------------------------------------------------------------------------
/commands/Image/image.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Image extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "image",
8 | description: "Returns a random image.",
9 | category: "Image",
10 | usage: "image [size (e.g. 1920x1080)]",
11 | aliases: ["randomimage", "random-image"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | let size = args[0];
17 | if (!args[0]) size = "";
18 |
19 | message.channel.startTyping();
20 |
21 | fetch(`https://source.unsplash.com/random/${size}`)
22 | .then(res => message.channel.send({ files: [{ attachment: res.body, name: "image.jpg" }] })
23 | .catch(error => {
24 | this.client.logger.error(error);
25 | message.channel.stopTyping(true);
26 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
27 | }));
28 |
29 | message.channel.stopTyping(true);
30 | }
31 | }
32 |
33 | module.exports = Image;
34 |
--------------------------------------------------------------------------------
/commands/Image/imagesearch.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 | const { RichEmbed } = require("discord.js");
4 | const { UNSPLASH_ACCESS_KEY } = process.env;
5 |
6 | class ImageSearch extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "imagesearch",
10 | description: "Sends a random image based on your query.",
11 | category: "Image",
12 | usage: "imagesearch ",
13 | aliases: ["isearch", "i-search", "image-search"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | let query = args.join(" ");
19 | if (!query) return message.channel.send("You must specify a search query.");
20 | else query = encodeURIComponent(args.join(" "));
21 |
22 | const page = Math.floor(Math.random() * 5) + 1;
23 | const index = Math.floor(Math.random() * 10) + 1;
24 |
25 | const randomColor = "#0000".replace(/0/g, () => {
26 | return (~~(Math.random() * 16)).toString(16);
27 | });
28 |
29 | const meta = { "Authorization": `Client-ID ${UNSPLASH_ACCESS_KEY}` };
30 |
31 | message.channel.startTyping();
32 |
33 | fetch(`https://api.unsplash.com/search/photos?page=${page}&query=${query}`, { headers: meta })
34 | .then(res => res.json())
35 | .then(json => {
36 | const data = json.results[parseInt(index.toFixed(0))];
37 | const embed = new RichEmbed()
38 | .setTitle("📷 Image")
39 | .setURL(data.urls.raw)
40 | .setDescription(`Photo by [${data.user.name}](${data.user.links.html}) on [Unsplash](https://unsplash.com)`)
41 | .setImage(data.urls.raw)
42 | .setColor(randomColor)
43 | .setTimestamp();
44 | message.channel.send({ embed });
45 | })
46 | .catch(error => {
47 | message.channel.stopTyping(true);
48 | if (error.message === "Cannot read property 'urls' of undefined") return message.channel.send(texts.general.noResultsFound);
49 | this.client.logger.error(error);
50 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
51 | });
52 |
53 | message.channel.stopTyping(true);
54 | }
55 | }
56 |
57 | module.exports = ImageSearch;
58 |
--------------------------------------------------------------------------------
/commands/Image/jpeg.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class JPEG extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "jpeg",
8 | description: "Needs more JPEG.",
9 | category: "Image",
10 | usage: "jpeg ",
11 | aliases: ["jpegify"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const url = args[0] ? args[0].replace(/<(.+)>/g, "$1") : null;
17 | if (!url || !url.startsWith("http")) return message.channel.send("You must provide a valid image URL to JPEGify.");
18 |
19 | message.channel.startTyping();
20 |
21 | fetch(`https://nekobot.xyz/api/imagegen?type=jpeg&url=${url}`)
22 | .then(res => res.json())
23 | .then(data => {
24 | if (!data.success) return message.channel.send("An error occurred. Please ensure the URL you're providing is an image URL.");
25 | message.channel.stopTyping(true);
26 | return message.channel.send({ file: data.message });
27 | })
28 | .catch(error => {
29 | this.client.logger.error(error);
30 | message.channel.stopTyping(true);
31 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
32 | });
33 | }
34 | }
35 |
36 | module.exports = JPEG;
37 |
--------------------------------------------------------------------------------
/commands/Image/lizard.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Lizard extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "lizard",
8 | description: "Sends a random image of a lizard.",
9 | category: "Image",
10 | usage: "lizard"
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | message.channel.startTyping();
16 |
17 | fetch("https://nekos.life/api/v2/img/lizard")
18 | .then(res => res.json())
19 | .then(data => message.channel.send({ file: data.url }))
20 | .catch(error => {
21 | this.client.logger.error(error);
22 | message.channel.stopTyping(true);
23 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
24 | });
25 |
26 | message.channel.stopTyping(true);
27 | }
28 | }
29 |
30 | module.exports = Lizard;
--------------------------------------------------------------------------------
/commands/Image/magik.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Magik extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "magik",
8 | description: "Adds a \"magik\" effect to the specified image.",
9 | category: "Image",
10 | usage: "magik "
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const url = args[0] ? args[0].replace(/<(.+)>/g, "$1") : null;
16 | if (!url || !url.startsWith("http")) return message.channel.send("You must provide a valid image URL to apply some ***m a g i k*** to.");
17 |
18 | message.channel.startTyping();
19 |
20 | fetch(`https://nekobot.xyz/api/imagegen?type=magik&image=${url}`)
21 | .then(res => res.json())
22 | .then(data => {
23 | if (!data.success) return message.channel.send("An error occurred. Please ensure the URL you're providing is an image URL.");
24 | message.channel.stopTyping(true);
25 | return message.channel.send({ file: data.message });
26 | })
27 | .catch(error => {
28 | this.client.logger.error(error);
29 | message.channel.stopTyping(true);
30 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
31 | });
32 | }
33 | }
34 |
35 | module.exports = Magik;
36 |
--------------------------------------------------------------------------------
/commands/Image/robot.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Robot extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "robot",
8 | description: "Generates a picture of a robot from some given text.",
9 | category: "Image",
10 | usage: "robot ",
11 | aliases: ["robohash"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const query = args.join(" ");
17 | if (!query) return message.channel.send("You must some text to use to generate the robot.");
18 | if (query.match(/[-!$%^&*()_+|~=`{}[\]:";'<>?,./]/g)) return message.channel.send("Your query cannot include symbols.");
19 |
20 | message.channel.startTyping();
21 |
22 | fetch(`https://robohash.org/${encodeURIComponent(query)}.png`)
23 | .then(res => message.channel.send({ files: [{ attachment: res.body, name: `${query}.png` }] })
24 | .catch(error => {
25 | this.client.logger.error(error);
26 | message.channel.stopTyping(true);
27 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
28 | }));
29 |
30 | message.channel.stopTyping(true);
31 | }
32 | }
33 |
34 | module.exports = Robot;
35 |
--------------------------------------------------------------------------------
/commands/Image/snake.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 | const { RichEmbed } = require("discord.js");
4 | const { UNSPLASH_ACCESS_KEY } = process.env;
5 |
6 | class Snake extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "snake",
10 | description: "Sends a random image of a snake.",
11 | category: "Image",
12 | usage: "snake",
13 | aliases: ["snek"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | const page = Math.floor(Math.random() * 5) + 1;
19 | const index = Math.floor(Math.random() * 10) + 1;
20 |
21 | const randomColor = "#0000".replace(/0/g, () => {
22 | return (~~(Math.random() * 16)).toString(16);
23 | });
24 |
25 | const meta = { "Authorization": `Client-ID ${UNSPLASH_ACCESS_KEY}` };
26 |
27 | message.channel.startTyping();
28 |
29 | fetch(`https://api.unsplash.com/search/photos?page=${page}&query=snake`, { headers: meta })
30 | .then(res => res.json())
31 | .then(json => {
32 | const data = json.results[parseInt(index.toFixed(0))];
33 | const embed = new RichEmbed()
34 | .setTitle("🐍 Snake")
35 | .setURL(data.urls.raw)
36 | .setDescription(`Photo by [${data.user.name}](${data.user.links.html}) on [Unsplash](https://unsplash.com)`)
37 | .setImage(data.urls.raw)
38 | .setColor(randomColor)
39 | .setTimestamp();
40 | message.channel.send({ embed });
41 | })
42 | .catch(error => {
43 | message.channel.stopTyping(true);
44 | if (error.message === "Cannot read property 'urls' of undefined") return message.channel.send(texts.general.noResultsFound);
45 | this.client.logger.error(error);
46 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
47 | });
48 |
49 | message.channel.stopTyping(true);
50 | }
51 | }
52 |
53 | module.exports = Snake;
54 |
--------------------------------------------------------------------------------
/commands/Information/about.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const delet = require("../../package.json");
3 | const { RichEmbed, version } = require("discord.js");
4 | const moment = require("moment");
5 |
6 | class About extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "about",
10 | description: "Displays information about me!",
11 | category: "Information",
12 | usage: "about",
13 | aliases: ["info"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) {
18 | let displayColor;
19 | if (message.channel.type === "text") displayColor = message.guild.me.displayColor;
20 | else if (message.channel.type === "dm" || message.channel.type === "group") {
21 | displayColor = "#0000".replace(/0/g, () => {
22 | return (~~(Math.random() * 16)).toString(16);
23 | });
24 | }
25 |
26 | try {
27 | const embed = new RichEmbed()
28 | .setColor(displayColor)
29 | .setThumbnail(this.client.user.displayAvatarURL)
30 | .setTitle(`Hey ${message.author.username}, I'm delet!`)
31 | .setDescription("I'm a bot developed and maintained by the DS Development Group.")
32 | .addField("Version", delet.version, true)
33 | .addField("Website", "https://delet.js.org", true)
34 | .addField("Users", this.client.users.size, true)
35 | .addField("Invite link", "[Click here](https://delet.js.org/go/invite)", true)
36 | .addField("Uptime", `${moment.utc(this.client.uptime).format("DD")-1} day(s), ${moment.utc(this.client.uptime).format("HH:mm:ss")}`, true)
37 | .addField("GitHub", "[Click here](https://github.com/DS-Development/delet)", true)
38 | .addField("Node.js version", process.version, true)
39 | .addField("Memory usage", `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`, true)
40 | .setFooter(`Made with Discord.js (v${version})`, "https://vgy.me/ZlOMAx.png")
41 | .setTimestamp();
42 |
43 | message.channel.send({ embed });
44 | } catch (error) {
45 | this.client.logger.error(error);
46 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
47 | }
48 | }
49 | }
50 |
51 | module.exports = About;
--------------------------------------------------------------------------------
/commands/Information/avatar.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class Avatar extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "avatar",
8 | description: "Sends the mentioned user's avatar.",
9 | category: "Information",
10 | usage: "avatar [@mention]",
11 | aliases: ["ava", "avy"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const user = message.mentions.users.first() || message.author;
17 |
18 | const embed = new RichEmbed()
19 | .setTitle(`🖼️ ${texts.cmd.info.avatar.replace(/{{user}}/g, user.tag)}`)
20 | .setDescription(`🔗 **[Direct URL](${user.displayAvatarURL})**`)
21 | .setImage(user.displayAvatarURL);
22 | return message.channel.send({ embed });
23 | }
24 | }
25 |
26 | module.exports = Avatar;
--------------------------------------------------------------------------------
/commands/Information/channelid.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class ChannelID extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "channelid",
7 | description: "Returns the ID of the current channel.",
8 | category: "Information",
9 | usage: "channelid",
10 | aliases: ["channel-id", "cid"]
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | message.channel.send(`This channel (${message.channel}) has an ID of \`${message.channel.id}\`.`);
16 | }
17 | }
18 |
19 | module.exports = ChannelID;
--------------------------------------------------------------------------------
/commands/Information/channelinfo.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const moment = require("moment");
4 |
5 | class ChannelInfo extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "channelinfo",
9 | description: "Displays information about the current channel.",
10 | category: "Information",
11 | usage: "channelinfo",
12 | aliases: ["channel", "cinfo"],
13 | guildOnly: true
14 | });
15 | }
16 |
17 | async run(message, args, level) { // eslint-disable-line no-unused-vars
18 | const chan = message.channel;
19 |
20 | let topic;
21 | if (chan.topic && chan.topic.length > 2048) topic = "[Too long to display!]";
22 | else topic = chan.topic;
23 |
24 | const createdTimestamp = moment.utc(chan.createdAt).format("YYYYMMDD");
25 | const randomColor = "#0000".replace(/0/g, () => {
26 | return (~~(Math.random() * 16)).toString(16);
27 | });
28 |
29 | const embed = new RichEmbed()
30 | .setColor(randomColor)
31 | .setThumbnail("https://vgy.me/9fSC7k.png")
32 | .setTitle(`Channel Information for #${chan.name}`)
33 | .addField("Created", chan.createdAt, true)
34 | .addField("Age", moment(createdTimestamp, "YYYYMMDD").fromNow().slice(0, -4), true)
35 | .addField("Type", chan.type.toProperCase(), true)
36 | .addField("Position", chan.calculatedPosition, true)
37 | .addField("Parent", !chan.parent ? "None" : chan.parent.name, true)
38 | .addField("NSFW", chan.nsfw.toString().toProperCase(), true)
39 | .addField("Deletable", chan.deletable.toString().toProperCase(), true)
40 | .addField("Topic", !topic ? "No topic set." : topic, true)
41 | .setFooter(`Channel ID: ${chan.id}`, "https://vgy.me/167efD.png")
42 | .setTimestamp();
43 |
44 | message.channel.send({ embed });
45 | }
46 | }
47 |
48 | module.exports = ChannelInfo;
49 |
--------------------------------------------------------------------------------
/commands/Information/discriminator.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Discriminator extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "discriminator",
7 | description: "Searches for users with the specified discriminator.",
8 | category: "Information",
9 | usage: "discriminator [#xxxx]",
10 | aliases: ["discrim", "discriminator-search", "discrim-search"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | let discrim = args[0];
16 | if (!discrim) {
17 | discrim = message.author.discriminator;
18 | }
19 |
20 | if (discrim.startsWith("#")) {
21 | discrim = discrim.slice(1);
22 | }
23 |
24 | if (/^[0-9]+$/.test(discrim) && discrim.length === 4) {
25 | const users = this.client.users.filter(user => user.discriminator === discrim).map(user => user.username);
26 | if (users.length === 0) return message.channel.send(`${texts.cmd.info.discrimNotFound.replace(/{{discrim}}/g, discrim)} <:feelsbadman:379645743583199232>`);
27 | return message.channel.send(`**${users.length}** ${texts.cmd.info.discrim.replace(/{{discrim}}/g, discrim)}:\n\`\`\`yml\n${users.join(", ")}\`\`\``);
28 | } else {
29 | return message.channel.send(texts.cmd.info.invalidDiscrim);
30 | }
31 | }
32 | }
33 |
34 | module.exports = Discriminator;
--------------------------------------------------------------------------------
/commands/Information/dsdev.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class DSDev extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "dsdev",
7 | description: "Interested in joining my development team?",
8 | category: "Information",
9 | usage: "dsdev",
10 | aliases: ["hireme", "joinus", "ds-development"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | message.channel.send(`${texts.cmd.info.dsDev} **https://delet.js.org/go/join**.`);
16 | }
17 | }
18 |
19 | module.exports = DSDev;
20 |
--------------------------------------------------------------------------------
/commands/Information/emojiimage.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class EmojiImage extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "emojiimage",
8 | description: "Sends the specified emoji as an image.",
9 | category: "Information",
10 | usage: "emojiimage ",
11 | aliases: ["emoji-image", "bigemoji", "hugemoji", "hugeemoji"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | if (!args[0]) return message.channel.send(texts.cmd.info.noEmoji);
17 | if (args[0].startsWith("= 55296) return message.channel.send(`${texts.cmd.info.regularEmoji.replace(/{{emoji}}/g, args[0])}\nhttps://twemoji.twitter.com`);
19 |
20 | const match = args[0].match(/<:[a-zA-Z0-9_-]+:(\d{18})>/);
21 | if (!match || !match[1]) return message.channel.send(texts.cmd.info.invalidEmoji);
22 |
23 | // Using the `emojis` property from Client rather than Guild so Nitro users can use this command for a wider range of emojis
24 | const emoji = this.client.emojis.get(match[1]);
25 | if (!emoji) return message.channel.send(texts.cmd.info.invalidEmoji);
26 |
27 | const embed = new RichEmbed()
28 | .setColor(2934736)
29 | .setTitle(emoji.name)
30 | .setImage(emoji.url);
31 |
32 | return message.channel.send({ embed });
33 | }
34 | }
35 |
36 | module.exports = EmojiImage;
37 |
--------------------------------------------------------------------------------
/commands/Information/emojiinfo.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const moment = require("moment");
4 |
5 | class EmojiInfo extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "emojiinfo",
9 | description: "Displays information about the specified emoji.",
10 | category: "Information",
11 | usage: "emojiinfo ",
12 | aliases: ["emoji-info", "einfo"]
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | if (!args[0]) return message.channel.send(texts.cmd.info.noEmoji);
18 | if (args[0].startsWith("= 55296) return message.channel.send(`${texts.cmd.info.regularEmoji.replace(/{{emoji}}/g, args[0])}\nhttps://twemoji.twitter.com`);
20 |
21 | const match = args[0].match(/<:[a-zA-Z0-9_-]+:(\d{18})>/);
22 | if (!match || !match[1]) return message.channel.send(texts.cmd.info.invalidEmoji);
23 |
24 | // Using the `emojis` property from Client rather than Guild so Nitro users can use this command for a wider range of emojis
25 | const emoji = this.client.emojis.get(match[1]);
26 | if (!emoji) return message.channel.send(texts.cmd.info.invalidEmoji);
27 |
28 | const embed = new RichEmbed()
29 | .setColor(2934736)
30 | .setTitle("Emoji Information")
31 | .setThumbnail(emoji.url)
32 | .addField("❯ Name", emoji.name, true)
33 | .addField("❯ ID", emoji.id, true)
34 | .addField("❯ Created", moment.utc(emoji.createdAt).format("DD/MM/YYYY"), true)
35 | .addField("❯ From", emoji.guild, true)
36 | .setFooter(`Info requested by ${message.author.tag}`, message.author.displayAvatarURL)
37 | .setTimestamp();
38 |
39 | return message.channel.send({ embed });
40 | }
41 | }
42 |
43 | module.exports = EmojiInfo;
44 |
--------------------------------------------------------------------------------
/commands/Information/feedback.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const delet = require("../../package.json");
3 | const { stripIndents } = require("common-tags");
4 |
5 | class Feedback extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "feedback",
9 | description: "Want to give feedback? Encountered any bugs?",
10 | category: "Information",
11 | usage: "feedback",
12 | aliases: ["suggestion", "suggestions", "suggest", "bug", "bugs"]
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | const suggest = "";
18 | const issues = `<${delet.bugs.url}>`;
19 |
20 | message.channel.send(stripIndents`
21 | ${texts.cmd.info.feedbackQuestion}
22 |
23 | **${texts.cmd.info.suggestions}**: ${suggest}.
24 | **${texts.cmd.info.issues}**: ${issues}.`);
25 | }
26 | }
27 |
28 | module.exports = Feedback;
29 |
--------------------------------------------------------------------------------
/commands/Information/github.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const fetch = require("node-fetch");
4 | const moment = require("moment");
5 |
6 | class GitHub extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "github",
10 | description: "Returns information about the specified GitHub repository.",
11 | category: "Information",
12 | usage: "github ",
13 | aliases: ["repo", "repo-info", "repository-info"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | let owner = args[0];
19 | if (!owner) return message.channel.send("You must provide the repository owner's username or organisation name.");
20 | else owner = encodeURIComponent(args[0]);
21 |
22 | let repo = args[1];
23 | if (!repo) return message.channel.send("You must provide a repository name to search for.");
24 | else repo = encodeURIComponent(args[1]);
25 |
26 | fetch(`https://api.github.com/repos/${owner}/${repo}`)
27 | .then(res => res.json())
28 | .then(data => {
29 | const embed = new RichEmbed()
30 | .setColor(0)
31 | .setThumbnail(data.owner.avatar_url)
32 | .setAuthor("GitHub", "https://vgy.me/B4CvF1.png")
33 | .setTitle(data.full_name)
34 | .setURL(data.html_url)
35 | .setDescription(data.description ? data.description : "[No description set]")
36 | .addField("❯ Created", moment.utc(data.created_at).format("DD/MM/YYYY HH:mm:ss"), true)
37 | .addField("❯ Last updated", moment.utc(data.updated_at, "YYYYMMDD").fromNow(), true)
38 | .addField("❯ Stars", data.stargazers_count, true)
39 | .addField("❯ Forks", data.forks, true)
40 | .addField("❯ Issues", data.open_issues, true)
41 | .addField("❯ Language", data.language || "No language", true)
42 | .addField("❯ License", data.license ? data.license.spdx_id : "Unlicensed", true)
43 | .addField("❯ Archived?", data.archived.toString().toProperCase(), true)
44 | .setFooter("All times are UTC")
45 | .setTimestamp();
46 | return message.channel.send({ embed });
47 | })
48 | .catch(error => {
49 | if (error.status === 404) return message.channel.send(texts.general.noResultsFound);
50 | this.client.logger.error(error);
51 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
52 | });
53 | }
54 | }
55 |
56 | module.exports = GitHub;
57 |
--------------------------------------------------------------------------------
/commands/Information/logo.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 |
4 | class Logo extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "logo",
8 | description: "Sends a website's logo.",
9 | category: "Information",
10 | usage: "logo "
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const query = args[0];
16 | if (!query) return message.channel.send(texts.general.invalidURL);
17 |
18 | const url = `https://logo.clearbit.com/${query.startsWith("<") ? query.replace(/<(.+)>/g, "$1") : query}?size=500`;
19 |
20 | fetch(url)
21 | .then(res => message.channel.send({ files: [{ attachment: res.body, name: "logo.jpg" }] }))
22 | .catch(error => {
23 | if (error.message === "404 Not Found") return message.channel.send(texts.general.noResultsFound);
24 | this.client.logger.error(error);
25 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
26 | });
27 | }
28 | }
29 |
30 | module.exports = Logo;
31 |
--------------------------------------------------------------------------------
/commands/Information/nasa.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 | const h = new (require("html-entities").AllHtmlEntities)();
4 |
5 | class NASA extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "nasa",
9 | description: "Searches NASA's image database.",
10 | usage: "nasa ",
11 | aliases: ["space"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | let query = args.join(" ");
17 | if (!query) return message.channel.send("You must provide a query to search NASA's image database for.");
18 | else query = encodeURIComponent(args.join(" "));
19 |
20 | fetch(`https://images-api.nasa.gov/search?q=${query}&media_type=image`)
21 | .then(res => res.json())
22 | .then(body => {
23 | const images = body.collection.items;
24 | if (!images.length || images.length === 0) return message.channel.send("No results found.");
25 |
26 | const data = images.random();
27 | const description = h.decode(data.data[0].description);
28 |
29 | message.channel.send(description.length > 1997 ? description.substring(0, 1997) + "..." : description.substring(0, 2000) + " <:NASA:476079744857931796>", {
30 | file: data.links[0].href
31 | });
32 | })
33 | .catch(error => {
34 | this.client.logger.error(error);
35 | message.channel.send(texts.general.error.replace(/{{err}}/g, error));
36 | });
37 | }
38 | }
39 |
40 | module.exports = NASA;
41 |
--------------------------------------------------------------------------------
/commands/Information/serverinfo.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const { stripIndents } = require("common-tags");
4 | const moment = require("moment");
5 |
6 | const verificationLevels = {
7 | 0: "None",
8 | 1: "Low",
9 | 2: "Medium",
10 | 3: "(╯°□°)╯︵ ┻━┻",
11 | 4: "┻━┻ ミヽ(ಠ益ಠ)ノ彡┻━┻"
12 | };
13 |
14 | const contentFilterLevels = {
15 | 0: "None",
16 | 1: "Medium",
17 | 2: "High"
18 | };
19 |
20 | class ServerInfo extends Command {
21 | constructor(client) {
22 | super(client, {
23 | name: "serverinfo",
24 | description: "Displays information about the current server.",
25 | category: "Information",
26 | usage: "serverinfo",
27 | aliases: ["sinfo", "server", "guildinfo", "guild"],
28 | guildOnly: true
29 | });
30 | }
31 |
32 | async run(message, args, level) { // eslint-disable-line no-unused-vars
33 | const randomColor = "#0000".replace(/0/g, () => {
34 | return (~~(Math.random() * 16)).toString(16);
35 | });
36 |
37 | const createdTimestamp = moment.utc(message.guild.createdAt).format("YYYYMMDD");
38 |
39 | const embed = new RichEmbed()
40 | .setColor(randomColor)
41 | .setThumbnail(message.guild.iconURL)
42 | .setTitle(`Server Information for ${message.guild.name}`)
43 | .setDescription(`**Server ID:** ${message.guild.id}`)
44 |
45 | .addField("❯ Details", stripIndents`
46 | • Created: **${moment.utc(message.guild.createdAt).format("dddd, Do MMMM YYYY @ HH:mm:ss")}** (${moment(createdTimestamp, "YYYYMMDD").fromNow()})
47 | • Owner: **${message.guild.owner.user.tag}**
48 | • Region: **${message.guild.region.toProperCase()}**
49 | • Verification: **${verificationLevels[message.guild.verificationLevel]}**
50 |
51 | `, true)
52 |
53 | .addField("❯ Users", stripIndents`
54 | • Users: **${message.guild.memberCount - message.guild.members.filter(m => m.user.bot).size}**
55 | • Bots: **${message.guild.members.filter(m => m.user.bot).size}**
56 |
57 | `, true)
58 |
59 | .addField("❯ Roles", stripIndents`
60 | • Default: **${message.guild.defaultRole.name}**
61 | • Count: **${message.guild.roles.size} roles**
62 | `, true)
63 |
64 | .addField("❯ Channels", stripIndents`
65 | • Text: **${message.guild.channels.filter(ch => ch.type === "text").size}**
66 | • Voice: **${message.guild.channels.filter(ch => ch.type === "voice").size}**
67 | • AFK: **${message.guild.afkChannel ? message.guild.afkChannel.name : "None"}**
68 | `, true)
69 |
70 | .addField("❯ Other", stripIndents`
71 | • AFK: After **${message.guild.afkTimeout / 60} min**
72 | • Large? **${message.guild.large.toString().toProperCase()}**
73 | • Content filter level: **${contentFilterLevels[message.guild.explicitContentFilter]}**
74 |
75 | `, true)
76 |
77 | .setFooter(`Info requested by ${message.author.tag} • All times are UTC`, message.author.displayAvatarURL);
78 |
79 | message.channel.send({ embed });
80 | }
81 | }
82 |
83 | module.exports = ServerInfo;
--------------------------------------------------------------------------------
/commands/Information/stats.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const Command = require("../../base/Command.js");
5 | const pkg = require("../../package.json");
6 | const { NODE_ENV } = process.env;
7 | const { version } = require("discord.js");
8 | const { stripIndents } = require("common-tags");
9 | const moment = require("moment");
10 | require("moment-duration-format");
11 |
12 | class Stats extends Command {
13 | constructor(client) {
14 | super(client, {
15 | name: "stats",
16 | description: "Sends some useful bot statistics.",
17 | category: "Information",
18 | usage: "stats",
19 | aliases: ["statistics"]
20 | });
21 | }
22 |
23 | async run(message, args, level) { // eslint-disable-line no-unused-vars
24 | const duration = moment.duration(this.client.uptime).format(" D [days], H [hrs], m [mins], s [secs]");
25 |
26 | message.channel.send(stripIndents`
27 | = STATISTICS =
28 | • Users :: ${this.client.users.size.toLocaleString()}
29 | • Servers :: ${this.client.guilds.size.toLocaleString()}
30 | • Channels :: ${this.client.channels.size.toLocaleString()}
31 | • Uptime :: ${duration}
32 | • RAM usage :: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB
33 | • Build :: ${NODE_ENV.toProperCase()}
34 | • Platform :: ${process.platform === "win32" ? "Windows" : process.platform.toProperCase()}
35 |
36 | = VERSIONS =
37 | • delet :: v${pkg.version}
38 | • Discord.js :: v${version}
39 | • Node.js :: ${process.version}`, { code: "asciidoc" });
40 | }
41 | }
42 |
43 | module.exports = Stats;
44 |
--------------------------------------------------------------------------------
/commands/Information/time.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { stripIndents } = require("common-tags");
3 |
4 | class Time extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "time",
8 | description: "Returns the current time in a specified timezone.",
9 | category: "Information",
10 | usage: "time /",
11 | aliases: ["timezone", "worldtime"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const link = "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List";
17 | const timeZone = args.join("_").toUpperCase();
18 | if (!timeZone) return message.channel.send(stripIndents`
19 | You must provide a timezone to look up the time for.
20 | For a full list of timezones, refer to the "TZ" column here: **<${link}>**.
21 | `);
22 |
23 | try {
24 | const time = new Date().toLocaleTimeString("en-GB", { timeZone, hour12: false });
25 | const friendly = timeZone.substring(timeZone.indexOf("/") + 1).replace(/_/g, " ");
26 | return message.channel.send(`The time in **${friendly.toProperCase()}** is currently **${time}**.`);
27 | } catch (err) {
28 | message.channel.send(stripIndents`
29 | ${texts.general.error.replace(/{{err}}/g, err.message)}
30 | For a full list of timezones, refer to the "TZ" column here: **<${link}>**.
31 |
32 | • Please ensure you are using the correct format, e.g. \`${settings.prefix}time europe/london\`.
33 | • Note that the continent of North America is split into **America** and **Canada**, e.g. \`${settings.prefix}time america/new york\`.
34 | `);
35 | }
36 | }
37 | }
38 |
39 | module.exports = Time;
--------------------------------------------------------------------------------
/commands/Information/timezones.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const moment = require("moment-timezone");
3 | const { stripIndents } = require("common-tags");
4 |
5 | const unix = Math.round(+new Date() / 1000);
6 |
7 | class Timezones extends Command {
8 | constructor(client) {
9 | super(client, {
10 | name: "timezones",
11 | description: "Returns a list of current times in popular timezones.",
12 | category: "Information",
13 | usage: "timezones",
14 | aliases: ["times", "worldtimes", "now"]
15 | });
16 | }
17 |
18 | async run(message, args, level) { // eslint-disable-line no-unused-vars
19 | message.channel.send(stripIndents`
20 | = T I M E Z O N E S =
21 |
22 | // Africa
23 | • EAT :: [${moment().tz("Africa/Nairobi").format("HH:mm ZZ")}]
24 | • CAT :: [${moment().tz("Africa/Maputo").format("HH:mm ZZ")}]
25 | • WAT :: [${moment().tz("Africa/Lagos").format("HH:mm ZZ")}]
26 | • WEST :: [${moment().tz("Africa/Accra").format("HH:mm ZZ")}]
27 |
28 | // America
29 | • EDT :: [${moment().tz("America/New_York").format("HH:mm ZZ")}]
30 | • CDT :: [${moment().tz("America/Chicago").format("HH:mm ZZ")}]
31 | • MDT :: [${moment().tz("America/Denver").format("HH:mm ZZ")}]
32 | • AKDT :: [${moment().tz("America/Anchorage").format("HH:mm ZZ")}]
33 | • UTC-10 :: [${moment().tz("Pacific/Honolulu").format("HH:mm ZZ")}]
34 |
35 | // Asia
36 | • MVT :: [${moment().tz("Indian/Maldives").format("HH:mm ZZ")}]
37 | • IST :: [${moment().tz("Asia/Calcutta").format("HH:mm ZZ")}]
38 | • BTT :: [${moment().tz("Asia/Dhaka").format("HH:mm ZZ")}]
39 | • ICT :: [${moment().tz("Asia/Bangkok").format("HH:mm ZZ")}]
40 | • CST :: [${moment().tz("Asia/Hong_Kong").format("HH:mm ZZ")}]
41 |
42 | // Europe
43 | • UTC/GMT :: [${moment.utc().format("HH:mm ZZ")}]
44 | • BST :: [${moment().tz("Europe/London").format("HH:mm ZZ")}]
45 | • CEST :: [${moment().tz("Europe/Zurich").format("HH:mm ZZ")}]
46 | • EEST :: [${moment().tz("Europe/Helsinki").format("HH:mm ZZ")}]
47 | • FET :: [${moment().tz("Europe/Minsk").format("HH:mm ZZ")}]
48 |
49 | // Oceania
50 | • AWST :: [${moment().tz("Australia/Perth").format("HH:mm ZZ")}]
51 | • ACST :: [${moment().tz("Australia/Darwin").format("HH:mm ZZ")}]
52 | • AEST :: [${moment().tz("Australia/Sydney").format("HH:mm ZZ")}]
53 | • NZST :: [${moment().tz("Pacific/Auckland").format("HH:mm ZZ")}]
54 |
55 | // Other
56 | • UNIX :: [${unix}]`, { code: "asciidoc" });
57 | }
58 | }
59 |
60 | module.exports = Timezones;
--------------------------------------------------------------------------------
/commands/Information/tweet.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const fetch = require("node-fetch");
3 | const snekfetch = require("snekfetch");
4 | const { RichEmbed } = require("discord.js");
5 | const { base64 } = require("../../util/Utils.js");
6 | const { TWITTER_API_KEY, TWITTER_SECRET } = process.env;
7 |
8 | class Tweet extends Command {
9 | constructor(client) {
10 | super(client, {
11 | name: "tweet",
12 | description: "Returns the specified user's latest tweet.",
13 | category: "Information",
14 | usage: "tweet ",
15 | aliases: ["latesttweet", "latest-tweet"]
16 | });
17 |
18 | this.token = null;
19 | }
20 |
21 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
22 | const user = args[0];
23 | if (!user) return message.channel.send("You must specify a Twitter user whose latest tweet you'd like to see.");
24 |
25 | if (!this.token) await this.fetchToken();
26 |
27 | const url = `https://api.twitter.com/1.1/users/show.json?screen_name=${user}`;
28 | const meta = { "Authorization": `Bearer ${this.token}` };
29 |
30 | fetch(url, { headers: meta })
31 | .then(res => res.json())
32 | .then(data => {
33 | const embed = new RichEmbed()
34 | .setColor(12639981)
35 | .setThumbnail(data.profile_image_url_https)
36 | .setAuthor("Latest Tweet", "https://vgy.me/8tgKd0.png")
37 | .setTitle(`${data.name} (@${data.screen_name})`)
38 | .setURL(`https://twitter.com/${data.screen_name}`)
39 | .setDescription(data.status ? data.status.text : "???");
40 | return message.channel.send({ embed });
41 | })
42 | .catch(error => {
43 | if (error.statusCode === 401) this.fetchToken();
44 | if (error.statusCode === 404) return message.channel.send(texts.general.noResultsFound);
45 | this.client.logger.error(error);
46 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
47 | });
48 | }
49 |
50 | async fetchToken() {
51 | const { body } = await snekfetch
52 | .post("https://api.twitter.com/oauth2/token")
53 | .set({
54 | Authorization: `Basic ${base64(`${TWITTER_API_KEY}:${TWITTER_SECRET}`)}`,
55 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
56 | })
57 | .send("grant_type=client_credentials");
58 |
59 | this.token = body.access_token;
60 | return body;
61 | }
62 | }
63 |
64 | module.exports = Tweet;
65 |
--------------------------------------------------------------------------------
/commands/Information/twitter.js:
--------------------------------------------------------------------------------
1 | // Based on Xiao's Twitter command (https://github.com/dragonfire535/xiao/)
2 | // Licensed under the GNU General Public License v3.0
3 |
4 | const Command = require("../../base/Command.js");
5 | const snekfetch = require("snekfetch");
6 | const { RichEmbed } = require("discord.js");
7 | const { base64 } = require("../../util/Utils.js");
8 | const { TWITTER_API_KEY, TWITTER_SECRET } = process.env;
9 |
10 | class Twitter extends Command {
11 | constructor(client) {
12 | super(client, {
13 | name: "twitter",
14 | description: "Returns info about a Twitter user.",
15 | category: "Information",
16 | usage: "twitter ",
17 | aliases: ["twitterinfo", "twitter-info", "tinfo"]
18 | });
19 |
20 | this.token = null;
21 | }
22 |
23 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
24 | const user = args[0];
25 | if (!user) return message.channel.send("You must specify a Twitter user to get information on.");
26 |
27 | try {
28 | if (!this.token) await this.fetchToken();
29 | const { body } = await snekfetch
30 | .get("https://api.twitter.com/1.1/users/show.json")
31 | .set({ Authorization: `Bearer ${this.token}` })
32 | .query({ screen_name: user });
33 |
34 | const embed = new RichEmbed()
35 | .setColor(44269)
36 | .setThumbnail(body.profile_image_url_https)
37 | .setAuthor("Twitter", "https://vgy.me/a7ii9V.png")
38 | .setTitle(`${body.name} (@${body.screen_name})`)
39 | .setURL(`https://twitter.com/${body.screen_name}`)
40 | .setDescription(body.description)
41 | .addField("❯ Followers", body.followers_count, true)
42 | .addField("❯ Following", body.friends_count, true)
43 | .addField("❯ Tweets", body.statuses_count, true)
44 | .addField("❯ Protected", body.protected ? "Yes" : "No", true)
45 | .addField("❯ Verified", body.verified ? "Yes" : "No", true)
46 | .addField("❯ Created", new Date(body.created_at).toDateString(), true)
47 | .addField("❯ Latest Tweet", body.status ? body.status.text : "???")
48 | .setFooter(`Info requested by ${message.author.tag}`, message.author.displayAvatarURL)
49 | .setTimestamp();
50 |
51 | return message.channel.send({ embed });
52 | } catch (error) {
53 | if (error.statusCode === 401) await this.fetchToken();
54 | if (error.statusCode === 404) return message.channel.send(texts.general.noResultsFound);
55 | this.client.logger.error(error);
56 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
57 | }
58 | }
59 |
60 | async fetchToken() {
61 | const { body } = await snekfetch
62 | .post("https://api.twitter.com/oauth2/token")
63 | .set({
64 | Authorization: `Basic ${base64(`${TWITTER_API_KEY}:${TWITTER_SECRET}`)}`,
65 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
66 | })
67 | .send("grant_type=client_credentials");
68 |
69 | this.token = body.access_token;
70 | return body;
71 | }
72 | }
73 |
74 | module.exports = Twitter;
75 |
--------------------------------------------------------------------------------
/commands/Information/uptime.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { stripIndents } = require("common-tags");
3 | const moment = require("moment");
4 | require("moment-duration-format");
5 |
6 | class Uptime extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "uptime",
10 | description: "Displays delet's uptime.",
11 | category: "Information",
12 | usage: "uptime"
13 | });
14 | }
15 |
16 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
17 | const uptime = moment.duration(this.client.uptime).format("D [days], H [hrs], m [mins], s [secs]");
18 | message.channel.send(stripIndents`
19 | \`\`\`asciidoc
20 | • Uptime :: ${uptime}
21 | \`\`\`
22 | For a full list of bot stats, use the \`${settings.prefix}stats\` command.
23 | `);
24 | }
25 | }
26 |
27 | module.exports = Uptime;
--------------------------------------------------------------------------------
/commands/Information/userid.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class UserID extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "userid",
7 | description: "Returns the mentioned user's user ID.",
8 | category: "Information",
9 | usage: "userid [@user]",
10 | aliases: ["id"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const user = message.mentions.users.first() || message.author;
16 |
17 | message.channel.send(`**${user.tag}**'s user ID is: \`${user.id}\`.`)
18 | .catch((e) => {
19 | this.client.logger.error(e.stack);
20 | return message.channel.send(texts.general.error.replace(/{{err}}/g, e.message));
21 | });
22 | }
23 | }
24 |
25 | module.exports = UserID;
--------------------------------------------------------------------------------
/commands/Information/userinfo.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const { stripIndents } = require("common-tags");
4 | const moment = require("moment");
5 |
6 | class UserInfo extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "userinfo",
10 | description: "Displays information about the mentioned user.",
11 | category: "Information",
12 | usage: "userinfo [@user]",
13 | aliases: ["uinfo", "user", "whois"],
14 | guildOnly: true
15 | });
16 | }
17 |
18 | async run(message, args, level) { // eslint-disable-line no-unused-vars
19 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
20 |
21 | const user = message.mentions.users.first() || message.author;
22 |
23 | let status;
24 | if (user.presence.status.toProperCase() === "Dnd") {
25 | status = "Do Not Disturb";
26 | } else {
27 | status = user.presence.status.toProperCase();
28 | }
29 |
30 | let activity = "";
31 |
32 | if (!user.presence.game) {
33 | activity = "Nothing";
34 | }
35 |
36 | if (user.presence.game) {
37 | activity = `Playing **${user.presence.game ? user.presence.game.name : "Nothing"}**`;
38 | }
39 |
40 | // if (user.presence.game.name === "Spotify") {
41 | // activity = "Listening to **Spotify**";
42 | // }
43 |
44 | const embed = new RichEmbed()
45 | .setColor(message.guild.member(user).displayColor)
46 | .setThumbnail(user.displayAvatarURL)
47 | .setTitle(`User Information for ${user.tag}`)
48 | .setDescription(`**User ID**: ${user.id}`)
49 |
50 | .addField("❯ Details", stripIndents`
51 | • Status: **${status}**
52 | • Activity: ${activity}
53 |
54 | `, true)
55 |
56 | .addField("❯ Roles", stripIndents`
57 | • Highest: **\`${message.guild.member(user).highestRole.name}\`**
58 | • All: ${message.guild.member(user).roles.map(roles => `\`${roles.name}\``).slice(1).join(", ")}
59 |
60 | `, true)
61 |
62 | .addField("❯ Join Dates", stripIndents`
63 | • ${message.guild.name}: **${moment.utc(message.guild.member(user).joinedAt).format("dddd, Do MMMM YYYY @ HH:mm:ss")}**
64 | • Discord: **${moment.utc(user.createdAt).format("dddd, Do MMMM YYYY @ HH:mm:ss")}**
65 | `, true)
66 |
67 | .setFooter(`Info requested by ${message.author.tag} • All times are UTC`, `${message.author.displayAvatarURL}`);
68 |
69 | message.channel.send({ embed });
70 | }
71 | }
72 |
73 | module.exports = UserInfo;
--------------------------------------------------------------------------------
/commands/Information/version.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const moment = require("moment");
3 | const snekfetch = require("snekfetch");
4 | const { version } = require("../../package.json");
5 |
6 | class Version extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "version",
10 | description: "Returns delet's version.",
11 | category: "Information",
12 | usage: "version",
13 | aliases: ["ver"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
18 | try {
19 | var { body } = await snekfetch.get("https://api.github.com/repos/DS-Development/delet");
20 | } catch (error) {
21 | this.client.logger.error(error);
22 | body = "[Error occurred whilst fetching date]";
23 | }
24 |
25 | message.channel.send(`**Version:** ${version}\n**Last updated:** ${moment.utc(body.updated_at).format("dddd Do MMMM YYYY") || body}`);
26 | }
27 | }
28 |
29 | module.exports = Version;
--------------------------------------------------------------------------------
/commands/Information/weather.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const { stripIndents } = require("common-tags");
4 | const weather = require("weather-js");
5 |
6 | class Weather extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "weather",
10 | description: "Displays weather information for the specified location.",
11 | category: "Information",
12 | usage: "weather "
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | weather.find({ search: args.join(" "), degreeType: "C" }, function(err, result) {
18 | if (!args[0]) return message.channel.send(`You must provide a place to look up weather information for.\nTo see how to use this command, use \`${settings.prefix}help weather\`.`);
19 | if (err) return message.channel.send(`${texts.general.error.replace(/{{err}}/g, err.message)}\nTo see how to use this command, use \`${settings.prefix}help weather\`.`);
20 |
21 | try {
22 | var current = result[0].current;
23 | } catch (error) {
24 | if (error.message === "Cannot read property 'current' of undefined") return message.channel.send("Invalid location provided.");
25 | if (error.message === "ESOCKETTIMEDOUT") return message.channel.send("Request timed out. Please try again.");
26 | console.error(error.message);
27 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
28 | }
29 |
30 | const location = result[0].location; // eslint-disable-line no-unused-vars
31 | const ct = current.temperature;
32 |
33 | let col;
34 |
35 | if (ct <= 0) col = 13431807;
36 | else if (ct < 0 && ct >= 5) col = 12579071;
37 | else if (ct >= 6 && ct <= 10) col = 11861906;
38 | else if (ct >= 11 && ct <= 15) col = 9238900;
39 | else if (ct >= 16 && ct <= 20) col = 15531898;
40 | else if (ct >= 21 && ct <= 25) col = 16763258;
41 | else if (ct >= 26 && ct <= 30) col = 16739910;
42 | else if (ct >= 31 && ct <= 35) col = 16730914;
43 | else if (ct >= 36 && ct <= 40) col = 16727074;
44 | else if (ct >= 40) col = 12386304;
45 | else col = 7654911; // fallback
46 |
47 | const embed = new RichEmbed()
48 | .setColor(col)
49 | .setTitle(`Weather information for ${current.observationpoint}`)
50 | .setDescription(stripIndents`
51 | The weather is **${current.skytext.toLowerCase()}** at the moment.
52 |
53 | • Temperature: **${ct}°C** / ${((1.8 * ct) + 32).toFixed(0)}°F
54 | • Feels like: **${current.feelslike}°C** / ${((1.8 * current.feelslike) + 32).toFixed(0)}°F
55 | • Humidity: **${current.humidity}%**
56 | • Wind: **${current.winddisplay.toLowerCase()}** / ~${(current.winddisplay.toLowerCase().replace(/[^0-9]/g,"") * 0.621).toFixed(1)} mph
57 | `)
58 | .setThumbnail(current.imageUrl)
59 | .setFooter(`Correct as of ${current.observationtime.slice(0, -3)} local time`)
60 | .setTimestamp();
61 |
62 | message.channel.send({ embed });
63 | });
64 | }
65 | }
66 |
67 | module.exports = Weather;
68 |
--------------------------------------------------------------------------------
/commands/Maths/maths.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const math = require("mathjs");
3 |
4 | class Maths extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "maths",
8 | description: "Evaluates/calculates a given mathematical expression.",
9 | category: "Maths",
10 | usage: "maths ",
11 | aliases: ["math", "calculate"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | let exp = args.join(" ");
17 | if (!exp) return message.channel.send(texts.cmd.math.noExp.replace(/{{prefix}}/g, settings.prefix));
18 | if (exp.includes("°")) exp = exp.replace(/°/g, "deg");
19 |
20 | const msg = await message.channel.send(texts.cmd.math.calculating);
21 |
22 | try {
23 | let evaled = math.eval(exp);
24 | if (isNaN(evaled)) evaled = texts.cmd.math.isNaN;
25 | if (exp.length + evaled.length > 2000) return message.channel.send("Output is too long to fit into a message!");
26 |
27 | msg.edit(`${exp} = **${evaled}**`);
28 | } catch (error) {
29 | if (error.toString().startsWith("SyntaxError:") || error.message.startsWith("Undefined symbol")) return msg.edit(`**\`SyntaxError:\`** \`${error.message}\``);
30 |
31 | this.client.logger.error(error);
32 | msg.edit(texts.general.error.replace(/{{err}}/g, error.message));
33 | }
34 | }
35 | }
36 |
37 | module.exports = Maths;
38 |
--------------------------------------------------------------------------------
/commands/Maths/pi.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Pi extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "pi",
7 | description: "Returns the value of Pi (π).",
8 | category: "Maths",
9 | usage: "pi",
10 | aliases: ["π"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
15 | message.channel.send(`π = **${Math.PI}**...`);
16 | }
17 | }
18 |
19 | module.exports = Pi;
20 |
--------------------------------------------------------------------------------
/commands/Maths/prime.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Prime extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "prime",
7 | description: "Checks if a number is a prime number.",
8 | category: "Maths",
9 | usage: "prime ",
10 | aliases: ["primenumber", "isprime"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | const n = parseInt(args[0]);
16 | if (!n) return message.channel.send(texts.cmd.math.noNum);
17 |
18 | const isPrime = n => {
19 | if (isNaN(n) || !isFinite(n) || n%1 || n < 2) return false;
20 | if (n%2 == 0) return (n == 2);
21 | if (n%3 == 0) return (n == 3);
22 |
23 | const m = Math.sqrt(n);
24 |
25 | for (let i = 5; i <= m; i += 6) {
26 | if (n%i == 0) return false;
27 | if (n%(i + 2) == 0) return false;
28 | }
29 | return true;
30 | };
31 |
32 | if (isPrime(n) === true) {
33 | message.channel.send(`<:tick:398228298842374154> **${n}** ${texts.cmd.math.isPrime}.`);
34 | }
35 |
36 | if (isPrime(n) === false) {
37 | message.channel.send(`<:redX:398228298708025344> **${n}** ${texts.cmd.math.isNotPrime}.`);
38 | }
39 | }
40 | }
41 |
42 | module.exports = Prime;
43 |
--------------------------------------------------------------------------------
/commands/Misc/announce.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Announce extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "announce",
7 | description: "Sends a specified message to a specified channel.",
8 | usage: "announce ",
9 | aliases: ["send"],
10 | permLevel: "Server Owner",
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const content = args.join(" ");
17 | if (!content) return message.channel.send(texts.cmd.system.noMessage);
18 |
19 | const id = await this.client.awaitReply(message, texts.cmd.system.idRequest, 30000);
20 | if (!message.guild.channels.find(c => c.id === id)) return message.channel.send("A channel with that ID does not exist on this server.");
21 |
22 | message.guild.channels.get(id).send(content)
23 | .then(message.react("✅"))
24 | .catch(error => {
25 | if (error.message === "Missing Access") return message.channel.send(`I do not have sufficient permissions to send messages in <#${id}>.`);
26 | this.client.logger.error(error);
27 | });
28 | }
29 | }
30 |
31 | module.exports = Announce;
32 |
--------------------------------------------------------------------------------
/commands/Misc/icon.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class Icon extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "icon",
8 | description: "Sends the current server's icon.",
9 | usage: "icon",
10 | aliases: ["server-icon", "guild-icon"]
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
16 |
17 | const embed = new RichEmbed()
18 | .setTitle(`Server icon of ${message.guild.name}`)
19 | .setImage(message.guild.iconURL);
20 |
21 | message.channel.send({ embed });
22 | }
23 | }
24 |
25 | module.exports = Icon;
--------------------------------------------------------------------------------
/commands/Misc/invite.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { botPerms } = require("../../util/data.js");
3 |
4 | class Invite extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "invite",
8 | description: "Generates an invite link, for adding delet to a server.",
9 | usage: "invite",
10 | aliases: ["join"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | this.client.generateInvite(botPerms).then(link => {
16 | message.channel.send(texts.general.generating)
17 | .then(msg => {
18 | msg.edit(`${texts.cmd.misc.generated}:\n**<${link}>**`);
19 | });
20 | });
21 | }
22 | }
23 |
24 | module.exports = Invite;
--------------------------------------------------------------------------------
/commands/Misc/invites.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const arraySort = require("array-sort");
3 | const t = require("table");
4 |
5 | class Invites extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "invites",
9 | description: "Displays the server's invite leaderboard.",
10 | usage: "invites",
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | if (!message.guild.me.hasPermission("MANAGE_GUILD")) return message.channel.send(texts.general.missingPerm.replace(/{{perm}}/g, "Manage Server"));
17 |
18 | let invites = await message.guild.fetchInvites();
19 | if (invites.size === 0) return message.channel.send(texts.cmd.misc.noInvites);
20 | invites = invites.array();
21 |
22 | arraySort(invites, "uses", { reverse: true });
23 |
24 | const usedInvites = [["User", "Uses"]];
25 | invites.forEach(invite => usedInvites.push([invite.inviter.tag, invite.uses]));
26 |
27 | return message.channel.send(`**Server Invite Leaderboard** for ${message.guild.name}\n\`\`\`${t.table(usedInvites)}\`\`\``);
28 | }
29 | }
30 |
31 | module.exports = Invites;
--------------------------------------------------------------------------------
/commands/Misc/lastmessage.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class LastMessage extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "lastmessage",
8 | description: "Returns the mentioned user's last message.",
9 | usage: "lastmessage [@user]",
10 | aliases: ["lm"],
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | const member = message.mentions.members.first() || message.member;
17 | if (!member) return message.channel.send(texts.cmd.misc.noMember);
18 |
19 | const lastMsg = message.guild.member(member).lastMessage;
20 | if (!lastMsg) return message.channel.send("This user's last message could not be found, or they simply may not have sent any messages here.");
21 |
22 | const embed = new RichEmbed()
23 | .setColor(message.guild.member(member).displayColor)
24 | .setAuthor(member.user.tag, member.user.displayAvatarURL)
25 | .setDescription(`*${lastMsg}*`)
26 | .setFooter(`#${message.channel.name}`)
27 | .setTimestamp();
28 |
29 | message.channel.send({ embed });
30 | }
31 | }
32 |
33 | module.exports = LastMessage;
34 |
--------------------------------------------------------------------------------
/commands/Misc/loremipsum.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { get } = require("snekfetch");
3 |
4 | class LoremIpsum extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "loremipsum",
8 | description: "Need placeholder text for your website? Look no further.",
9 | usage: "loremipsum",
10 | aliases: ["placeholder", "lorem", "lorem-ipsum"]
11 | });
12 | }
13 |
14 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
15 | try {
16 | const { raw } = await get("https://loripsum.net/api").set("Accept", "text/plain");
17 | const text = raw.toString();
18 | message.channel.send(text.length >= 2000 ? text.substring(0, 1980) + "... " : text, { code: "html" });
19 | } catch (error) {
20 | this.client.logger.error(error);
21 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
22 | }
23 | }
24 | }
25 |
26 | module.exports = LoremIpsum;
27 |
--------------------------------------------------------------------------------
/commands/Misc/mylevel.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const Command = require("../../base/Command.js");
5 |
6 | class MyLevel extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "mylevel",
10 | description: "Displays your permission level for your location.",
11 | usage: "mylevel",
12 | aliases: ["myrank", "level", "permlevel"],
13 | guildOnly: true
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) {
18 | const friendly = this.client.config.permLevels.find(l => l.level === level).name;
19 | message.reply(`${texts.cmd.misc.permLevel}: **${level}** (${friendly}).`);
20 | }
21 | }
22 |
23 | module.exports = MyLevel;
24 |
--------------------------------------------------------------------------------
/commands/Misc/quote.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const { stripIndents } = require("common-tags");
4 |
5 | class Quote extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "quote",
9 | description: "Quotes the specified message (by ID).",
10 | usage: "quote ",
11 | aliases: ["q"],
12 | guildOnly: true
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | const id = args[0];
18 | if (!id) return message.channel.send(stripIndents`
19 | You must provide a message ID.
20 | To do so, you need to have developer mode turned on to obtain a message ID (Settings → Appearance → Developer Mode).
21 | Then, upon right-clicking a message, you'll be presented with an option called "Copy ID".`,
22 | { file: !message.guild.me.hasPermission("ATTACH_FILES") ? null : "https://vgy.me/cQbRf7.png" });
23 |
24 | message.channel.fetchMessage(id)
25 | .then(message => {
26 | const embed = new RichEmbed()
27 | .setColor(message.guild.member(message.author).displayColor)
28 | .setAuthor(message.author.tag, message.author.displayAvatarURL)
29 | .setDescription(message.content)
30 | .setFooter(`#${message.channel.name}`)
31 | .setTimestamp();
32 | message.channel.send({ embed });
33 | })
34 | .catch(error => {
35 | if (error.code === 10008) return message.channel.send("Unknown message. Please ensure the message ID is from a message in this channnel.");
36 | this.client.logger.error(error);
37 | message.channel.send(texts.general.error.replace(/{{err}}/g, error));
38 | });
39 | }
40 | }
41 |
42 | module.exports = Quote;
43 |
--------------------------------------------------------------------------------
/commands/Misc/tutorial.js:
--------------------------------------------------------------------------------
1 | // Previously, in the older version of delet (https://github.com/suvanl/delet),
2 | // the tutorial command used a series of `awaitMessages` methods. However, we
3 | // have decided to replace that with the online documentation, which will be much
4 | // clearer and more informative. It also reduces the amount of messy code.
5 |
6 | const Command = require("../../base/Command.js");
7 |
8 | class Tutorial extends Command {
9 | constructor(client) {
10 | super(client, {
11 | name: "tutorial",
12 | description: "Directs the user towards the docs.",
13 | usage: "tutorial",
14 | aliases: ["guide"]
15 | });
16 | }
17 |
18 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
19 | message.channel.send(texts.cmd.misc.tutorial);
20 | }
21 | }
22 |
23 | module.exports = Tutorial;
24 |
--------------------------------------------------------------------------------
/commands/Misc/youtube.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const YouTube = require("simple-youtube-api");
3 | const { GOOGLE_API_KEY } = process.env;
4 |
5 | const yt = new YouTube(GOOGLE_API_KEY);
6 |
7 | class YouTubeSearch extends Command {
8 | constructor(client) {
9 | super(client, {
10 | name: "youtube",
11 | description: "Searches YouTube for a specified video.",
12 | usage: "youtube ",
13 | aliases: ["yt"]
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | const searchString = args.join(" ");
19 | if (!searchString) return message.channel.send(texts.cmd.misc.noVid);
20 |
21 | try {
22 | const video = await yt.searchVideos(searchString, 1);
23 | message.channel.send(video.map(vid => vid.shortURL));
24 | } catch (error) {
25 | this.client.logger.error(error);
26 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
27 | }
28 | }
29 | }
30 |
31 | module.exports = YouTubeSearch;
32 |
--------------------------------------------------------------------------------
/commands/Moderation/banlist.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { stripIndents } = require("common-tags");
3 |
4 | class BanList extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "banlist",
8 | description: "DMs you a list of banned users.",
9 | category: "Moderation",
10 | usage: "banlist",
11 | guildOnly: true,
12 | aliases: ["bl"],
13 | permLevel: "Moderator"
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
19 | if (!message.guild.me.hasPermission("BAN_MEMBERS")) return message.channel.send(texts.general.missingPerm.replace(/{{perm}}/g, "Ban Members"));
20 |
21 | message.guild.fetchBans()
22 | .then(bans => {
23 | const obj = bans.map(b => ({
24 | user: `${b.username}#${b.discriminator}`
25 | }));
26 | const bList = Array.from(obj);
27 | if (bList.length < 1) return message.author.send(`There are no banned users on **${message.guild.name}**.`);
28 | let index = 0;
29 |
30 | message.author.send(stripIndents`
31 | __**Ban List for ${message.guild.name}**__
32 |
33 | ${bList.map(bl => `**${++index} -** ${bl.user}`).join("\n")}
34 | `);
35 |
36 | message.react("👌");
37 | });
38 | }
39 | }
40 |
41 | module.exports = BanList;
--------------------------------------------------------------------------------
/commands/Moderation/bans.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Bans extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "bans",
7 | description: "Checks how many users are banned on the current server.",
8 | category: "Moderation",
9 | usage: "bans",
10 | guildOnly: true,
11 | aliases: ["fetchbans"],
12 | permLevel: "Moderator"
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
18 | if (!message.guild.me.hasPermission("BAN_MEMBERS")) return message.channel.send(texts.general.missingPerm.replace(/{{perm}}/g, "Ban Members"));
19 | message.guild.fetchBans()
20 | .then(bans => {
21 | // TODO: change to "user(s)" if multi-locale support is added
22 | message.channel.send(`This server has **${bans.size}** banned ${bans.size === 1 ? "user" : "users"}.`);
23 | })
24 | .catch(error => {
25 | this.client.logger.error(error);
26 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
27 | });
28 | }
29 | }
30 |
31 | module.exports = Bans;
32 |
--------------------------------------------------------------------------------
/commands/Moderation/clearnick.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class ClearNick extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "clearnick",
7 | description: "Clears a user's nickname.",
8 | category: "Moderation",
9 | usage: "clearnick <@user>",
10 | aliases: ["clearnickname", "cn"],
11 | permLevel: "Moderator",
12 | guildOnly: true
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | const user = message.mentions.users.first();
18 | if (!user) return message.channel.send("You must provide a user to clear a nickname for.");
19 | const nick = message.guild.member(user).nickname;
20 | if (!nick) return message.channel.send("The mentioned user does not currently have a nickname.");
21 | if (!message.guild.me.hasPermission("MANAGE_NICKNAMES")) return message.channel.send("I cannot change any nicknames, as I do not have the \"Manage Nicknames\" permission.");
22 | if (message.guild.member(user).highestRole.position >= message.guild.me.highestRole.position) return message.channel.send("I do not have permission to change this user's nickname.");
23 |
24 | message.guild.member(user).setNickname("", "Clearing bad nickname")
25 | .catch(error => {
26 | if (error.message === "Privilege is too low...") {
27 | return message.channel.send("I do not have permission to change this user's nickname.");
28 | } else {
29 | this.client.logger.error(error);
30 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
31 | }
32 | });
33 | }
34 | }
35 |
36 | module.exports = ClearNick;
--------------------------------------------------------------------------------
/commands/Moderation/forceban.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class ForceBan extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "forceban",
8 | description: "Bans a user, even if they aren't in your server.",
9 | category: "Moderation",
10 | usage: "ban ",
11 | guildOnly: true,
12 | aliases: ["hackban", "xban"],
13 | permLevel: "Moderator"
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
19 |
20 | const userID = args[0];
21 | const reason = args.slice(1).join(" ");
22 | const modLog = message.guild.channels.find(c => c.name === settings.modLogChannel);
23 | if (!modLog) return message.channel.send(texts.moderation.modLogNotFound.replace(/{{prefix}}/g, settings.prefix));
24 | if (!userID) return message.channel.send("You must provide a user ID to ban.");
25 | if (!reason) return message.channel.send("Please provide a reason for the punishment.");
26 | if (userID === message.author.id) return message.channel.send("You cannot ban yourself. ");
27 |
28 | message.guild.ban(userID, { reason: reason })
29 | .then(() => {
30 | message.reply(`successfully banned the user with the ID **${userID}**.`);
31 | message.react("👌");
32 | })
33 | .catch(error => {
34 | this.client.logger.error(error);
35 | return message.channel.send(`An error occurred whilst trying to ban the specified user ID:\n\`\`\`${error.message}\`\`\``);
36 | });
37 |
38 | const embed = new RichEmbed()
39 | .setTitle(`🚫 Member force-banned from ${message.guild.name}`)
40 | .setColor(13838185)
41 | .setDescription(`\`\`\`css\nTarget: ${userID}\nIssued by: ${message.author.tag} (${message.author.id})\nReason: ${reason}\`\`\``)
42 | .setFooter(texts.moderation.poweredBy, this.client.user.displayAvatarURL)
43 | .setTimestamp();
44 |
45 | this.client.channels.get(modLog.id).send({ embed });
46 | }
47 | }
48 |
49 | module.exports = ForceBan;
--------------------------------------------------------------------------------
/commands/Moderation/kick.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class Kick extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "kick",
8 | description: "Kicks the mentioned user from the server.",
9 | category: "Moderation",
10 | usage: "kick <@user> ",
11 | guildOnly: true,
12 | aliases: ["boot"],
13 | permLevel: "Moderator"
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
19 |
20 | const user = message.mentions.users.first();
21 | let reason = args.slice(1).join(" ") || undefined;
22 | const modLog = message.guild.channels.find(c => c.name === settings.modLogChannel);
23 | if (!modLog) return message.channel.send(texts.moderation.modLogNotFound.replace(/{{prefix}}/g, settings.prefix));
24 | if (!user) return message.channel.send(texts.moderation.noUser);
25 | if (user === message.author) return message.channel.send(`${texts.moderation.selfPunish} `);
26 | if (message.guild.member(message.author).highestRole.position <= message.guild.member(user).highestRole.position) return message.channel.send("You cannot ban this user as they have a higher role than you.");
27 | if (!reason) {
28 | message.channel.send(texts.moderation.awaitReason);
29 | await message.channel.awaitMessages(m => m.author.id === message.author.id, {
30 | "errors": ["time"],
31 | "max": 1,
32 | time: 30000
33 | }).then(resp => {
34 | if (!resp) return message.channel.send(texts.moderation.timedOut);
35 | resp = resp.array()[0];
36 | if (resp.content.toLowerCase() === "cancel") return message.channel.send(texts.moderation.cancel);
37 | reason = resp.content;
38 | if (resp) resp.react("✅");
39 | }).catch(error => {
40 | this.client.logger.error(error);
41 | message.channel.send(texts.moderation.timedOut);
42 | });
43 | }
44 |
45 | if (reason) {
46 | try {
47 | if (!message.guild.member(user).kickable) return message.reply("I cannot ban that user from this server!\nThis may be because I do not have the required permissions to do so, or they may be the server owner.");
48 | if (user === message.author) return message.channel.send(texts.moderation.selfPunish);
49 | try {
50 | message.guild.member(user).kick(`${reason} (Issued by ${message.author.tag})`);
51 | message.react("👌");
52 | } catch (error) {
53 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
54 | }
55 |
56 | const embed = new RichEmbed()
57 | .setTitle(`👢 Member kicked in #${message.channel.name}`)
58 | .setColor(16733525)
59 | .setDescription(`\`\`\`ruby\nIssued to: ${user.tag} (${user.id})\nIssued by: ${message.author.tag} (${message.author.id})\nReason: ${reason}\`\`\``)
60 | .setFooter(texts.moderation.poweredBy, this.client.user.displayAvatarURL)
61 | .setTimestamp();
62 |
63 | this.client.channels.get(modLog.id).send({ embed });
64 | } catch (error) {
65 | this.client.logger.error(error);
66 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
67 | }
68 | }
69 | }
70 | }
71 |
72 | module.exports = Kick;
--------------------------------------------------------------------------------
/commands/Moderation/lockdown.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 | const ms = require("ms");
4 |
5 | class Lockdown extends Command {
6 | constructor(client) {
7 | super(client, {
8 | name: "lockdown",
9 | description: "Locks a channel down for a set duration. Use \"lockdown release\" to end the lockdown prematurely.",
10 | category: "Moderation",
11 | usage: "lockdown ",
12 | guildOnly: true,
13 | aliases: ["ld"],
14 | permLevel: "Moderator"
15 | });
16 | }
17 |
18 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
19 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
20 |
21 | const modLog = message.guild.channels.find(c => c.name === settings.modLogChannel);
22 | if (!modLog) return message.channel.send(texts.moderation.modLogNotFound.replace(/{{prefix}}/g, settings.prefix));
23 |
24 | if (!this.client.lockit) this.client.lockit = [];
25 | const time = args.join(" ");
26 | const validUnlocks = ["release", "rel", "unlock", "end", "stop"];
27 | if (!time) return message.channel.send("A duration for the lockdown must be set. This can be in hours, minutes or seconds. Example command usage:\n```%lockdown 5 m```");
28 |
29 | try {
30 | if (validUnlocks.includes(time)) {
31 | message.channel.overwritePermissions(message.guild.id, {
32 | SEND_MESSAGES: null
33 | }).then(() => {
34 | message.channel.send("Lockdown lifted.");
35 | clearTimeout(this.client.lockit[message.channel.id]);
36 | delete this.client.lockit[message.channel.id];
37 | });
38 | } else {
39 | message.channel.overwritePermissions(message.guild.id, {
40 | SEND_MESSAGES: false
41 | }).then(() => {
42 | const embed = new RichEmbed()
43 | .setTitle("🔒 Channel locked down")
44 | .setColor(16753762)
45 | .setDescription(`\`\`\`ruby\nChannel: #${message.channel.name} (${message.channel.id})\nDuration: ${ms(ms(time), { long: true })}\nIssued by: ${message.author.tag}\`\`\``)
46 | .setFooter(texts.moderation.poweredBy, this.client.user.displayAvatarURL)
47 | .setTimestamp();
48 | this.client.channels.get(modLog.id).send({ embed })
49 | .then(() => {
50 | this.client.lockit[message.channel.id] = setTimeout(() => {
51 | message.channel.overwritePermissions(message.guild.id, {
52 | SEND_MESSAGES: null
53 | })
54 | .then(message.channel.send("Lockdown lifted."));
55 | delete this.client.lockit[message.channel.id];
56 | }, ms(time));
57 | });
58 | });
59 | }
60 | } catch (error) {
61 | message.channel.send(`An error occurred whilst trying to lock this channel down. Use \`${settings.prefix}help lockdown\` to see how to use this command.`);
62 | }
63 | }
64 | }
65 |
66 | module.exports = Lockdown;
--------------------------------------------------------------------------------
/commands/Moderation/purge.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Purge extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "purge",
7 | description: "Purges (bulk-deletes) between 2 and 99 messages.",
8 | category: "Moderation",
9 | usage: "purge <@user> [number]",
10 | aliases: ["prune", "delet", "bulkdelete"],
11 | permLevel: "Moderator",
12 | guildOnly: true
13 | });
14 | }
15 |
16 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
17 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
18 | if (!message.guild.me.hasPermission("MANAGE_MESSAGES")) return message.channel.send(texts.general.missingPerm.replace(/{{perm}}/g, "Manage Messages"));
19 |
20 | const user = message.mentions.users.first();
21 | const amount = parseInt(message.content.split(" ")[1]) ? parseInt(message.content.split(" ")[1]) : parseInt(message.content.split(" ")[2]);
22 |
23 | if (!amount && !user) return message.channel.send(`You must specify a user and amount, or just an amount, of messages to purge.\nUse \`${settings.prefix}help purge\` for more information.`);
24 | if (!amount) return message.channel.send("You must specify an amount to delete.");
25 | if (amount < 2 || amount > 99) return message.channel.send("You've provided an invalid number of messages to delete. Please ensure it's between 2 and 99 (inclusive).");
26 |
27 | let messages = await message.channel.fetchMessages({ limit: amount });
28 |
29 | if (user) {
30 | const filterBy = user ? user.id : this.client.user.id;
31 | messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount);
32 |
33 | this.client.emit("messageDeleteBulk", messages);
34 | for (const msg of messages) msg.channel.messages.delete(msg.id);
35 |
36 | message.channel.bulkDelete(messages)
37 | .then(() => {
38 | message.channel.send(`**${amount}** messages were purged.`);
39 | })
40 | .catch(error => {
41 | this.client.logger.error(error);
42 | message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
43 | });
44 | } else {
45 | this.client.emit("messageDeleteBulk", messages);
46 | for (const msg of messages.values()) msg.channel.messages.delete(msg.id);
47 |
48 | message.channel.bulkDelete(messages)
49 | .then(() => {
50 | message.channel.send(`**${amount}** messages were purged.`);
51 | })
52 | .catch(error => {
53 | if (error.message === "You can only bulk delete messages that are under 14 days old.") return message.channel.send(error.message);
54 | this.client.logger.error(error);
55 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
56 | });
57 |
58 | //return message.channel.send(`**${amount}** messages were purged.`);
59 | }
60 | }
61 | }
62 |
63 | module.exports = Purge;
--------------------------------------------------------------------------------
/commands/Moderation/report.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class Report extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "report",
8 | description: "Reports a user to the server's staff.",
9 | category: "Moderation",
10 | usage: "report <@user> ",
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
17 | if (!message.guild.me.hasPermission("EMBED_LINKS")) return message.channel.send(texts.general.missingPerm.replace(/{{perm}}/g, "Embed Links"));
18 |
19 | const user = message.mentions.users.first();
20 | const reason = args.slice(1).join(" ");
21 | const modLog = message.guild.channels.find(c => c.name === settings.modLogChannel);
22 | if (!modLog) return message.channel.send(texts.moderation.modLogNotFound.replace(/{{prefix}}/g, settings.prefix));
23 | if (!user) return message.channel.send("You must mention a user to report.");
24 | if (!reason) return message.channel.send("You must provide a reason for the report.");
25 |
26 | message.delete();
27 |
28 | const embed = new RichEmbed()
29 | .setTitle(`🚩 Report received from ${message.author.tag} (${message.author.id})`)
30 | .setColor(message.guild.member(user).displayColor)
31 | .setDescription(`\`\`\`css\nTarget: ${user.tag} (${user.id})\nReason: ${reason}\nChannel: #${message.channel.name}\`\`\``)
32 | .setFooter(texts.moderation.poweredBy, this.client.user.displayAvatarURL)
33 | .setTimestamp();
34 |
35 |
36 | this.client.channels.get(modLog.id).send({ embed })
37 | .then(() => {
38 | message.channel.send("<:tick:398228298842374154> Report successfully sent.");
39 | })
40 | .catch(error => {
41 | this.client.logger.error(error);
42 | return message.channel.send("<:redX:398228298708025344> An error occurred whilst submitting the report.");
43 | });
44 | }
45 | }
46 |
47 | module.exports = Report;
--------------------------------------------------------------------------------
/commands/Moderation/warn.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const { RichEmbed } = require("discord.js");
3 |
4 | class Warn extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "warn",
8 | description: "Issues a warning to the specified user.",
9 | category: "Moderation",
10 | usage: "warn <@user> ",
11 | guildOnly: true,
12 | aliases: ["w"],
13 | permLevel: "Moderator"
14 | });
15 | }
16 |
17 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
18 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
19 | if (!message.guild.me.permissions.has(["EMBED_LINKS", "ADD_REACTIONS"])) return message.channel.send(texts.general.missingPerms.replace(/{{perms}}/g, "\"Embed Links\" & \"Add Reactions\""));
20 |
21 | const user = message.mentions.users.first();
22 | let reason = args.slice(1).join(" ") || undefined;
23 | const modLog = message.guild.channels.find(c => c.name === settings.modLogChannel);
24 | if (!modLog) return message.channel.send(texts.moderation.modLogNotFound.replace(/{{prefix}}/g, settings.prefix));
25 | if (!user) return message.channel.send(texts.moderation.noWarnUser);
26 | if (message.guild.member(message.author).highestRole.position <= message.guild.member(user).highestRole.position) return message.channel.send("You cannot warn this user as they have the same role or a higher role than you.");
27 | if (!reason) {
28 | message.channel.send(texts.moderation.awaitWarnReason);
29 | await message.channel.awaitMessages(m => m.author.id === message.author.id, {
30 | "errors": ["time"],
31 | "max": 1,
32 | time: 30000
33 | }).then(resp => {
34 | if (!resp) return message.channel.send("Timed out. The user has not been warned.");
35 | resp = resp.array()[0];
36 | if (resp.content.toLowerCase() === "cancel") return message.channel.send("Cancelled. The user has not been warned.");
37 | reason = resp.content;
38 | if (resp) resp.react("✅");
39 | }).catch(() => {
40 | message.channel.send("Timed out. The user has not been warned.");
41 | });
42 | }
43 |
44 | if (reason) {
45 | try {
46 | const embed = new RichEmbed()
47 | .setTitle(`⚠️ Warning issued in #${message.channel.name}`)
48 | .setColor(16381497)
49 | .setDescription(`\`\`\`ruby\nIssued to: ${user.tag} (${user.id})\nIssued by: ${message.author.tag} (${message.author.id})\nReason: ${reason}\`\`\``)
50 | .setFooter(texts.moderation.poweredBy, this.client.user.displayAvatarURL)
51 | .setTimestamp();
52 |
53 | this.client.channels.get(modLog.id).send({ embed });
54 |
55 | if (!user.bot) user.send(`Hello,\nYou were warned in **${message.guild.name}** for the reason "**${reason}**".\nPlease make sure you always follow the rules, because not doing so can lead to punishments. <:feelsbanman:405126279025917962>`);
56 |
57 | message.react("👌");
58 | } catch (error) {
59 | this.client.logger.error(error);
60 | return message.channel.send(texts.general.error.replace(/{{err}}/g, error.message));
61 | }
62 | }
63 | }
64 | }
65 |
66 | module.exports = Warn;
67 |
--------------------------------------------------------------------------------
/commands/Music/README.md:
--------------------------------------------------------------------------------
1 | ## Important
2 | **Please note that these commands do not have anything in their `run` functions as the actual commands exist in delet's music system ([`music/js/*`](https://github.com/DS-Development/delet/tree/master/music/js)).**
3 |
4 | These commands in this "Music" directory exist for the purpose being included in the output of the `help` command, so users are aware of how to use the music system.
5 |
--------------------------------------------------------------------------------
/commands/Music/np.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class NP extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "np",
7 | description: "Returns the title of the song that's currently playing.",
8 | category: "Music",
9 | usage: "np",
10 | aliases: ["song"],
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level) { // eslint-disable-line no-unused-vars
16 | // See README.md to see why there is no code in here.
17 | }
18 | }
19 |
20 | module.exports = NP;
--------------------------------------------------------------------------------
/commands/Music/pause.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Pause extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "pause",
7 | description: "Pauses the current song.",
8 | category: "Music",
9 | usage: "pause",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Pause;
--------------------------------------------------------------------------------
/commands/Music/play.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Play extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "play",
7 | description: "Plays a song.",
8 | category: "Music",
9 | usage: "play ",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Play;
--------------------------------------------------------------------------------
/commands/Music/queue.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Queue extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "queue",
7 | description: "Sends the current queue.",
8 | category: "Music",
9 | usage: "queue",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Queue;
--------------------------------------------------------------------------------
/commands/Music/resume.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Resume extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "resume",
7 | description: "Resumes the music if currently paused.",
8 | category: "Music",
9 | usage: "resume",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Resume;
--------------------------------------------------------------------------------
/commands/Music/skip.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Skip extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "skip",
7 | description: "Skips the song that's currently playing.",
8 | category: "Music",
9 | usage: "skip",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Skip;
--------------------------------------------------------------------------------
/commands/Music/stop.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Stop extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "stop",
7 | description: "Ends the current song and deletes the entire queue.",
8 | category: "Music",
9 | usage: "stop",
10 | guildOnly: true
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | // See README.md to see why there is no code in here.
16 | }
17 | }
18 |
19 | module.exports = Stop;
--------------------------------------------------------------------------------
/commands/Music/volume.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Volume extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "volume",
7 | description: "Changes the volume of the current song. Default volume is 5.",
8 | category: "Music",
9 | usage: "volume ",
10 | aliases: ["vol"],
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level) { // eslint-disable-line no-unused-vars
16 | // See README.md to see why there is no code in here.
17 | }
18 | }
19 |
20 | module.exports = Volume;
--------------------------------------------------------------------------------
/commands/System/leave.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Leave extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "leave",
7 | description: "Leaves the current server.",
8 | category: "System",
9 | usage: "leave",
10 | guildOnly: true,
11 | permLevel: "Bot Admin" // users with lower permLevels can simply kick delet from within Discord's tooltip menu
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
17 |
18 | message.reply("are you sure you want me to leave this guild? I can only be added back by users with the `MANAGE_GUILD` (Manage Server) permission. **(Y/N)**");
19 |
20 | return message.channel.awaitMessages(m => m.author.id === message.author.id, {
21 | "errors": ["time"],
22 | "max": 1,
23 | time: 20000
24 | }).then(resp => {
25 | if (!resp) return message.channel.send("Timed out.");
26 | resp = resp.array()[0];
27 | const validAnswers = [
28 | "Y",
29 | "N",
30 | "y",
31 | "n"
32 | ];
33 | if (validAnswers.includes(resp.content)) {
34 | if (resp.content === "N" || resp.content === "n") {
35 | return message.channel.send("Cool, looks like I won't be leaving. <:feelsgoodman:319952439602184232>");
36 | } else if (resp.content === "Y" || resp.content === "y") {
37 | message.channel.send("Use this if you ever want to add me back!\n****");
38 | message.guild.leave()
39 | .then(g => this.client.logger.info(`Left guild via command: ${g}`))
40 | .catch(e => {
41 | this.client.logger.error(e);
42 | returnmessage.channel.send(`I tried to leave, but couldn't. ${texts.general.error.replace(/{{err}}/g, e.message)}`);
43 | });
44 | }
45 | }
46 | });
47 | }
48 | }
49 |
50 | module.exports = Leave;
--------------------------------------------------------------------------------
/commands/System/ping.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const Command = require("../../base/Command.js");
5 |
6 | class Ping extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "ping",
10 | description: "Displays bot latency and API response times.",
11 | category: "System",
12 | usage: "ping",
13 | aliases: ["pong"]
14 | });
15 | }
16 |
17 | async run(message, args, level) { // eslint-disable-line no-unused-vars
18 | try {
19 | const msg = await message.channel.send("Ping! 🏓");
20 | msg.edit(`Pong! 🏓\nMessage roundtrip took: \`${msg.createdTimestamp - message.createdTimestamp}ms\`. Heartbeat (ping): \`${Math.round(this.client.ping)}ms\`.`);
21 | } catch (e) {
22 | this.client.logger.error(e);
23 | }
24 | }
25 | }
26 |
27 | module.exports = Ping;
28 |
--------------------------------------------------------------------------------
/commands/System/prefix.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Prefix extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "prefix",
7 | description: "Returns my command prefix/invoker for the current server.",
8 | category: "System",
9 | usage: "prefix",
10 | aliases: ["invoker"],
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level, settings) { // eslint-disable-line no-unused-vars
16 | message.channel.send(`My prefix here on ${message.guild.name} is "**${settings.prefix}**".\nTo change my prefix, do \`${settings.prefix}set edit prefix [NewPrefix]\`.`);
17 | }
18 | }
19 |
20 | module.exports = Prefix;
21 |
--------------------------------------------------------------------------------
/commands/System/reboot.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const Command = require("../../base/Command.js");
5 |
6 | class Reboot extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "reboot",
10 | description: "If running under PM2, the bot will restart.",
11 | category: "System",
12 | usage: "reboot",
13 | aliases: ["restart"],
14 | permLevel: "Bot Admin"
15 | });
16 | }
17 |
18 | async run(message, args, level) { // eslint-disable-line no-unused-vars
19 | try {
20 | await message.channel.send("Rebooting, please wait...");
21 | this.client.commands.forEach(async cmd => {
22 | await this.client.unloadCommand(cmd);
23 | });
24 | // Exiting with a code of 1 triggers an automatic restart for the PM2 process
25 | process.exit(1);
26 | } catch (e) {
27 | this.client.logger.error(e);
28 | }
29 | }
30 | }
31 |
32 | module.exports = Reboot;
--------------------------------------------------------------------------------
/commands/System/reload.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const Command = require("../../base/Command.js");
5 |
6 | class Reload extends Command {
7 | constructor(client) {
8 | super(client, {
9 | name: "reload",
10 | description: "Reloads a command that has been modified.",
11 | category: "System",
12 | usage: "reload ",
13 | permLevel: "Bot Admin"
14 | });
15 | }
16 |
17 | async run(message, args, level) { // eslint-disable-line no-unused-vars
18 | if (!args[0]) return message.reply("you must provide a command to reload.");
19 |
20 | const commands = this.client.commands.get(args[0]) || this.client.commands.get(this.client.aliases.get(args[0]));
21 | if (!commands) return message.reply(`the command \`${args[0]}\` does not exist, nor is it an alias.`);
22 |
23 | let response = await this.client.unloadCommand(commands.conf.location, commands.help.name);
24 | if (response) return message.channel.send(`Error Unloading: \`${response}\`.`);
25 |
26 | response = this.client.loadCommand(commands.conf.location, commands.help.name);
27 | if (response) return message.channel.send(`Error loading: \`${response}\`.`);
28 |
29 | message.channel.send(`The command \`${commands.help.name}\` has been reloaded.`);
30 | }
31 | }
32 |
33 | module.exports = Reload;
34 |
--------------------------------------------------------------------------------
/commands/System/shutdown.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Shutdown extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "shutdown",
7 | description: "Shuts down delet.",
8 | category: "System",
9 | usage: "shutdown",
10 | aliases: ["kill", "endprocess", "shut-down"],
11 | permLevel: "Bot Owner"
12 | });
13 | }
14 |
15 | async run(message, args, level) { // eslint-disable-line no-unused-vars
16 | try {
17 | await message.channel.send("Shutting down... :wave:");
18 | this.client.commands.forEach(async cmd => {
19 | await this.client.unloadCommand(cmd);
20 | });
21 | process.exit(0);
22 | } catch (e) {
23 | this.client.logger.error(e);
24 | }
25 | }
26 | }
27 |
28 | module.exports = Shutdown;
--------------------------------------------------------------------------------
/commands/System/status.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Status extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "status",
7 | description: "Sets delet's presence/status.",
8 | category: "System",
9 | usage: "status ",
10 | permLevel: "Bot Admin"
11 | });
12 | }
13 |
14 | async run(message, args, level) { // eslint-disable-line no-unused-vars
15 | const status = args[0];
16 | if (!status) return message.channel.send("A status type must be provided.");
17 |
18 | const statusType = args[0].toLowerCase();
19 |
20 | if (statusType === "online" || statusType === "idle" || statusType === "dnd" || statusType === "invisible") {
21 | this.client.user.setStatus(status);
22 | message.channel.send(`Status successfully changed to **${statusType}**.\nPlease note that initially changing status may take up to a minute or two.`);
23 | } else {
24 | return message.channel.send(`"${statusType}" is not a valid status type.`);
25 | }
26 | }
27 | }
28 |
29 | module.exports = Status;
--------------------------------------------------------------------------------
/commands/Utility/emoji.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 |
3 | class Emoji extends Command {
4 | constructor(client) {
5 | super(client, {
6 | name: "emoji",
7 | description: "Creates a new emoji.",
8 | category: "Utility",
9 | usage: "emoji ",
10 | aliases: ["createemoji", "create-emoji"],
11 | guildOnly: true
12 | });
13 | }
14 |
15 | async run(message, args, level) { // eslint-disable-line no-unused-vars
16 | if (!message.guild.available) return this.client.logger.info(`Guild "${message.guild.name}" (${message.guild.id}) is unavailable.`);
17 | if (!message.member.hasPermission("MANAGE_EMOJIS")) return message.reply("as you do not have the \"Manage Emojis\" permission, you cannot use this command.");
18 |
19 | const image = args[0] ? args[0].replace(/<(.+)>/g, "$1") : null;
20 | const name = args[1];
21 | let isImgLink;
22 |
23 | if (!image) return message.channel.send("You must provide a valid **Imgur** or **vgy.me** image link, to create an emoji from.");
24 |
25 | if (image.startsWith("https://i.imgur") || image.startsWith("https://vgy.me")) {
26 | isImgLink = true;
27 | } else {
28 | isImgLink = false;
29 | }
30 |
31 | if (image.split(".").pop() !== "png") isImgLink = false;
32 |
33 | if (isImgLink === false) return message.channel.send("Invalid image link.\nPlease ensure the image link you've provided is from either Imgur or vgy.me, starts with `https://` and ends with `.png`.");
34 | if (!name) return message.channel.send("You must provide a name for the new emoji.");
35 |
36 | message.guild.createEmoji(image, name)
37 | .then(emoji => message.channel.send(`Created new emoji: <:${emoji.name}:${emoji.id}>.`))
38 | .catch(error => {
39 | if (error.message === "404 Not Found") return message.reply("an image could not be found at that link.");
40 | this.client.logger.error(error);
41 | message.channel.send(`An error occurred: \`\`\`${error.message}\`\`\``);
42 | });
43 | }
44 | }
45 |
46 | module.exports = Emoji;
--------------------------------------------------------------------------------
/commands/Utility/shorten.js:
--------------------------------------------------------------------------------
1 | const Command = require("../../base/Command.js");
2 | const shortener = require("isgd");
3 |
4 | class Shorten extends Command {
5 | constructor(client) {
6 | super(client, {
7 | name: "shorten",
8 | description: "Shortens the specified link.",
9 | category: "Utility",
10 | usage: "shorten [custom title]",
11 | aliases: ["isgd", "urlshortner", "shorten-url"]
12 | });
13 | }
14 |
15 | async run(message, args, level, settings, texts) { // eslint-disable-line no-unused-vars
16 | if (!args[0]) return message.channel.send(texts.cmd.util.noLink);
17 | if (!args[1]) {
18 | shortener.shorten(args[0], function(res) {
19 | if (res.startsWith("Error:")) return message.channel.send(texts.general.invalidURL);
20 | message.channel.send(`${texts.cmd.util.shortened} **<${res}>**.`);
21 | });
22 | } else {
23 | shortener.custom(args[0], args[1], function(res) {
24 | if (res.startsWith("Error:")) return message.channel.send(texts.general.error.replace(/{{err}}/g, res.slice(7)));
25 | message.channel.send(`${texts.cmd.util.shortened} **<${res}>**.`);
26 | });
27 | }
28 | }
29 | }
30 |
31 | module.exports = Shorten;
32 |
--------------------------------------------------------------------------------
/config.js.example:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const config = {
5 | // Bot Admins, level 9 by default. Array of user ID strings.
6 | "admins": [],
7 |
8 | // Bot Support, level 8 by default. Array of user ID strings.
9 | "support": [],
10 |
11 | // Dashboard settings
12 | "dashboard" : {
13 | "oauthSecret": "",
14 | "callbackURL": "",
15 | "sessionSecret": "",
16 | "domain": "",
17 | "port": 3030
18 | },
19 |
20 | // PERMISSION LEVEL DEFINITIONS
21 |
22 | permLevels: [
23 | // Default permLevel for regular users
24 | { level: 0,
25 | name: "User",
26 | // No need to check; just returns true which allows them to execute any command their
27 | // level allows them to.
28 | check: () => true
29 | },
30 | { level: 2,
31 | name: "Moderator",
32 | // The following lines check the guild the message came from for the roles.
33 | // Then it checks if the member that authored the message has the role.
34 | // If they do, it returns true, which will allow them to execute the command in question.
35 | // If they don't, it returns false, which will prevent them from executing the command.
36 | check: (message) => {
37 | try {
38 | const modRole = message.guild.roles.find(r => r.name.toLowerCase() === message.settings.modRole.toLowerCase());
39 | if (modRole && message.member.roles.has(modRole.id)) return true;
40 | } catch (e) {
41 | return false;
42 | }
43 | }
44 | },
45 | { level: 3,
46 | name: "Administrator",
47 | check: (message) => {
48 | try {
49 | const adminRole = message.guild.roles.find(r => r.name.toLowerCase() === message.settings.adminRole.toLowerCase());
50 | return (adminRole && message.member.roles.has(adminRole.id));
51 | } catch (e) {
52 | return false;
53 | }
54 | }
55 | },
56 | { level: 4,
57 | name: "Server Owner",
58 | // Simple check - checks if the guild owner id matches the message author's ID, and if so, it will return true.
59 | // Otherwise, it will return false.
60 | check: (message) => message.channel.type === "text" ? (message.guild.owner.user.id === message.author.id ? true : false) : false
61 | },
62 | // Bot Support is a special "in-between" level that has the equivalent access level of the server
63 | // owner on any server they join, in order to help troubleshoot the bot on behalf of owners.
64 | { level: 8,
65 | name: "Bot Support",
66 | // The check is carried out by reading if an ID is part of this array.
67 | // This means that the bot must be rebooted once an ID has been added.
68 | check: (message) => config.support.includes(message.author.id)
69 | },
70 | // Bot Admin has some access to functions like rebooting the bot or reloading commands.
71 | { level: 9,
72 | name: "Bot Admin",
73 | check: (message) => config.admins.includes(message.author.id)
74 | },
75 |
76 | // This is the bot owner. This should be the highest permission level available.
77 | // The reason this should be the highest level is because of dangerous commands such as eval
78 | // or exec (if the owner has that).
79 | { level: 10,
80 | name: "Bot Owner",
81 | check: (message) => message.client.appInfo.owner.id === message.author.id
82 | }
83 | ]
84 | };
85 |
86 | module.exports = config;
87 |
--------------------------------------------------------------------------------
/dashboard/public/css/dashboard.css:
--------------------------------------------------------------------------------
1 | .roleBox {
2 | border-radius: 3px;
3 | padding: 0px 3px;
4 | font-size: 0.8em;
5 | white-space: nowrap;
6 | }
7 |
8 | .status {
9 | box-sizing: border-box;
10 | border-width: 2px;
11 | border-radius: 50%;
12 | height: 15px;
13 | width: 15px;
14 | float: left;
15 | vertical-align: middle;
16 | margin: 5px;
17 | }
18 |
19 | .online {
20 | background-color: #42b581;
21 | border-color: #69c49a;
22 | }
23 |
24 | .idle {
25 | background-color: #faa61a;
26 | border-color: #fbb848;
27 | }
28 |
29 | .dnd {
30 | background-color: #f04747;
31 | border-color: #f36c6c;
32 | }
33 |
34 | .offline {
35 | background-color: #747f8d;
36 | border-color: #9099a4;
37 | }
--------------------------------------------------------------------------------
/dashboard/public/images/bot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/suvanl/delet2/877670080f01700620a0b9cea37b41a6718571ab/dashboard/public/images/bot.png
--------------------------------------------------------------------------------
/dashboard/templates/admin.ejs:
--------------------------------------------------------------------------------
1 | <%- include('blocks/header', {bot, user, path}) %>
2 | Administration
3 |
4 | <% bot.guilds.forEach(guild => { %>
5 |
6 | <% if (guild.icon) { %>
7 |
8 | <% } else { %>
9 |
10 |
20 | <% } %>
21 |
22 |
23 | <%= guild.name %>
24 |
25 | <%
26 | let href, text;
27 | if(bot.guilds.get(guild.id)) {
28 | href = `/dashboard/${guild.id}/manage`;
29 | text = "Manage";
30 | } else {
31 | href = `https://discordapp.com/oauth2/authorize?client_id=${bot.config.dashboard.clientID}&scope=bot&guild_id=${guild.id}&response_type=code&redirect_uri=${encodeURIComponent(client.config.dashboard.callbackURL)}`;
32 | text = "Invite Bot";
33 | }
34 | %>
35 |
<%= text %>
36 |
37 |
38 | <% }); %>
39 |
40 |
41 | <% include blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/autherror.ejs:
--------------------------------------------------------------------------------
1 | <%- include('blocks/header', {bot, user, path}) %>
2 |
3 |
4 |
Authentication Error
5 |
There has been a problem with authentication.
6 |
7 |
8 | <% include ./blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/blocks/footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Server
7 |
Support server, and the home of delet
8 |
Join Server
9 |
10 |
11 |
Main Website
12 |
Navigate back to the main website
13 |
Main Website
14 |
15 |
16 |
GitHub
17 |
View delet's source code on GitHub
18 |
View Source
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/dashboard/templates/blocks/guild-card.ejs:
--------------------------------------------------------------------------------
1 |
2 | <% if (guild.icon) { %>
3 |
4 | <% } else { %>
5 |
6 |
17 | <% } %>
18 |
19 |
<%= guild.name %>
20 |
<%= guild.createdTimestamp %>
21 |
22 | Owner : <%= `${guild.owner.user.tag}` %>
23 | Members : <%= `${guild.memberCount}` %> ( <%= `${guild.members.filter(m => m.user.bot).size}` %> Bot(s) )
24 | Roles : <%= guild.roles.size %>
25 | Channels : <%= `${guild.channels.filter(c => c.type === 'text').size}`%> <%= `${guild.channels.filter(c => c.type === 'voice').size}`%>
26 |
27 |
Leave
28 |
29 |
--------------------------------------------------------------------------------
/dashboard/templates/blocks/guild-modals.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 | Are you sure you want
14 | <%= bot.user.username %> to leave this server?
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
35 |
36 | Are you sure you want to reset to the default settings?
37 |
38 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/dashboard/templates/blocks/guild-nav.ejs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dashboard/templates/commands.ejs:
--------------------------------------------------------------------------------
1 | <%- include('blocks/header', {bot, user, path}) %>
2 |
3 | To see the command prefix for your server, use the prefix command.
4 |
5 | <% const help = {};
6 | bot.commands.forEach((command) => {
7 | const cat = command.help.category;
8 | if (!help.hasOwnProperty(cat)) help[cat] = [];
9 | help[cat].push(command);
10 | });
11 | %>
12 | <% for (const category in help) { %>
13 | <%= category %>
14 |
15 |
16 | <% for (const command of help[category]) { %>
17 |
18 |
19 |
20 |
<%= command.help.description %>
21 |
Permission level: <%= command.conf.permLevel %> more...
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
Usage Example: <%= command.help.usage %>
33 |
Command Aliases: <%= `${command.conf.aliases.join(', ')}` %>
34 |
35 |
36 |
37 |
38 |
39 | <% } %>
40 |
41 | <% } %>
42 | <% include ./blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/dashboard.ejs:
--------------------------------------------------------------------------------
1 | <%- include('blocks/header', {bot, user, path}) %>
2 | Dashboard
3 |
4 | <% user.guilds.forEach(guild => {
5 | const permsOnGuild = new perms(guild.permissions);
6 | if(!permsOnGuild.has("MANAGE_GUILD")) return;
7 | %>
8 |
9 |
10 | <% if (guild.icon) { %>
11 |
12 | <% } else { %>
13 |
14 |
24 | <% } %>
25 |
26 |
<%= guild.name %>
27 | <%
28 | let href, text;
29 | let enabled;
30 | if(bot.guilds.get(guild.id)) {
31 | href = `/dashboard/${guild.id}/manage`;
32 | text = "Manage";
33 | enabled = true;
34 | } else {
35 | href = `https://discordapp.com/oauth2/authorize?client_id=${bot.appInfo.id}&scope=bot&guild_id=${guild.id}&response_type=code&redirect_uri=${encodeURIComponent(bot.config.dashboard.callbackURL)}`;
36 | text = "Invite Bot";
37 | enabled = bot.appInfo.botPublic;
38 | }
39 | %>
40 |
<%= text %>
41 |
42 |
43 | <% }); %>
44 |
45 |
46 | <% include ./blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/guild/manage.ejs:
--------------------------------------------------------------------------------
1 | <%- include('../blocks/header', {bot, user, path}) %>
2 | Server Management
3 |
4 |
5 | <%- include('../blocks/guild-card', {guild}) %>
6 |
7 |
8 | <%- include('../blocks/guild-nav.ejs', {active: "manage", guild}) %>
9 |
32 |
33 |
34 | <% include ../blocks/guild-modals %>
35 |
39 | <% include ../blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/guild/stats.ejs:
--------------------------------------------------------------------------------
1 | <%- include('../blocks/header', {bot, user, path}) %>
2 | Server Statistics
3 |
4 |
5 |
6 | <%- include('../blocks/guild-card', {guild}) %>
7 |
8 |
9 |
10 | <%- include('../blocks/guild-nav', {active: "stats", guild}) %>
11 |
Full Stats
12 |
13 |
14 |
15 | ❯ Details
16 |
17 | Created:
18 |
19 | Owner: <%= guild.owner.user.tag %>
20 |
21 | Region: <%= guild.region.toProperCase() %>
22 |
23 | Verification:
24 |
25 |
26 |
27 |
28 |
29 | <% include ../blocks/guild-modals %>
30 |
34 |
35 | <% include ../blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/index.ejs:
--------------------------------------------------------------------------------
1 |
2 | <%- include('blocks/header', {bot, user, path}) %>
3 |
4 |
5 |
Welcome
6 |
<% if(bot.appInfo.description.length > 3) { %> <%= bot.appInfo.description %> <% } else { %>No description given.<% }%>
7 |
Command Help »
8 |
9 |
10 | <% include ./blocks/footer %>
--------------------------------------------------------------------------------
/dashboard/templates/stats.ejs:
--------------------------------------------------------------------------------
1 | <%- include('blocks/header', {bot, user, path}) %>
2 |
3 |
4 |
5 |
6 |
Live Statistics
7 |
8 |
9 |
10 |
Servers:
11 |
<%= stats.servers %>
12 |
13 |
14 |
Uptime:
15 |
<%= stats.uptime %>
16 |
17 |
18 |
Users:
19 |
<%= stats.members %>
20 |
21 |
22 |
Memory:
23 |
<%= stats.memoryUsage %> MB
24 |
25 |
26 |
Text Channels:
27 |
<%= stats.text %>
28 |
29 |
30 |
Voice Channels:
31 |
<%= stats.voice %>
32 |
33 |
34 |
Discord.js Version:
35 |
<%= stats.dVersion %>
36 |
37 |
38 |
Node.js Version:
39 |
<%= stats.nVersion %>
40 |
41 |
42 |
43 | <% include ./blocks/footer %>
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | delet.js.org
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | title: delet
2 | description: delet³ for Discord - coming soon
3 | permalink: /index.html
--------------------------------------------------------------------------------
/docs/assets/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, Oxygen, Ubuntu, Cantarell, "Open Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
3 | }
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | delet³ - redirecting...
11 |
12 |
13 |
14 | If you aren't redirected within the next few seconds,
15 | click here .
16 |
17 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/events/error.js:
--------------------------------------------------------------------------------
1 | module.exports = class {
2 | constructor(client) {
3 | this.client = client;
4 | }
5 |
6 | async run(error) {
7 | this.client.logger.error(`Discord API Error: ${error.message}`);
8 | }
9 | };
--------------------------------------------------------------------------------
/events/guildCreate.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | // This event executes whenever a new guild (server) is joined.
5 |
6 | const { stripIndents } = require("common-tags");
7 |
8 | module.exports = class {
9 | constructor(client) {
10 | this.client = client;
11 | }
12 |
13 | async run(guild) {
14 | // Updates number of guilds (servers) on the bot's status
15 | this.client.user.setActivity(`over ${this.client.guilds.size} servers`, { type: "WATCHING" });
16 |
17 | // Logs it
18 | this.client.logger.log(`New guild has been joined: ${guild.name} (${guild.id}) with ${guild.memberCount - 1} members`);
19 |
20 | // Notifies server owner
21 | const guildOwner = guild.owner;
22 | guildOwner.send(stripIndents`
23 | Hey! I'm delet, and I was invited to your server "**${guild.name}**" by someone with the Manage Server permission there. My prefix is \`%\` (but can be changed).
24 | To see how to get started, please go to **https://delet.js.org/#docs**.
25 |
26 | Hope to be of service to you and your server!`);
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/events/guildDelete.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | // This event executes when a new guild (server) has been left.
5 |
6 | module.exports = class {
7 | constructor(client) {
8 | this.client = client;
9 | }
10 |
11 | async run(guild) {
12 | // Logs it
13 | this.client.logger.log(`Left guild: ${guild.name} (${guild.id}) with ${guild.memberCount - 1} members`);
14 |
15 | // Updates number of guilds (servers) on the bot's status.
16 | this.client.user.setActivity(`over ${this.client.guilds.size} servers`, { type: "WATCHING" });
17 |
18 | // Well, they're gone :^) (removes them from the settings database)
19 | if (this.client.settings.has(guild.id)) {
20 | this.client.settings.delete(guild.id);
21 | }
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/events/guildMemberAdd.js:
--------------------------------------------------------------------------------
1 | // This event executes when a new member joins a server.
2 |
3 | module.exports = class {
4 | constructor(client) {
5 | this.client = client;
6 | }
7 |
8 | async run(member) {
9 | // Return if guild is unavailable
10 | if (!member.guild.available) return;
11 |
12 | // Loads the guild's settings
13 | const settings = this.client.getSettings(member.guild);
14 |
15 | // Checks if the modLogChannel exists
16 | const modLog = member.guild.channels.find(c => c.name === settings.modLogChannel);
17 | if (!modLog) this.client.logger.info(`modLogChannel not found in "${member.guild.name}" (${member.guild.id})`);
18 |
19 | // Creates and sends embed
20 | const { RichEmbed } = require("discord.js");
21 | const embed = new RichEmbed()
22 | .setColor(11861937)
23 | .setTitle("🎉 User Joined")
24 | .setDescription(`**${member.user.tag}** (${member.user.id})`)
25 | .setFooter(`Member #${member.guild.memberCount}`)
26 | .setTimestamp();
27 | member.guild.channels.get(modLog.id).send({ embed });
28 |
29 | // If welcome is off, don't proceed (doesn't welcome the user).
30 | if (settings.welcomeEnabled.toLowerCase() !== "true") return;
31 |
32 | // Checks if the welcomeChannel exists
33 | const welcomeChannel = member.guild.channels.find(c => c.name === settings.welcomeChannel);
34 | if (!welcomeChannel) return;
35 |
36 | // Replaces the placeholder in the welcome message with actual data.
37 | const welcomeMessage = settings.welcomeMessage.replace(/{{user}}/g, member.user.tag);
38 |
39 | // Sends the welcome message to the welcome channel.
40 | member.guild.channels.get(welcomeChannel.id).send(welcomeMessage).catch(console.error);
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/events/guildMemberRemove.js:
--------------------------------------------------------------------------------
1 | // This event executes when a member leaves a server.
2 |
3 | module.exports = class {
4 | constructor(client) {
5 | this.client = client;
6 | }
7 |
8 | async run(member) {
9 | // Return if guild is unavailable
10 | if (!member.guild.available) return;
11 |
12 | // Loads the guild's settings
13 | const settings = this.client.getSettings(member.guild.id);
14 |
15 | // TODO: re-add leave message to settings and handle sending of said message in this event
16 |
17 | // Checks if the modLogChannel exists
18 | const modLog = member.guild.channels.find(c => c.name === settings.modLogChannel);
19 | if (!modLog) return this.client.logger.info(`modLogChannel not found in "${member.guild.name}" (${member.guild.id})`);
20 |
21 | // Creates and sends embed
22 | const { RichEmbed } = require("discord.js");
23 | const embed = new RichEmbed()
24 | .setColor(16767063)
25 | .setTitle("🚪 User Left")
26 | .setDescription(`**${member.user.tag}** (${member.user.id})`)
27 | .setFooter(`There are now ${member.guild.memberCount} members`)
28 | .setTimestamp();
29 | return member.guild.channels.get(modLog.id).send({ embed });
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/events/messageDelete.js:
--------------------------------------------------------------------------------
1 | module.exports = class {
2 | constructor(client) {
3 | this.client = client;
4 | }
5 |
6 | async run(message) { // eslint-disable-line no-unused-vars
7 | //this.client.on("messageDelete", () => this.client.logger.debug("Message deleted."));
8 | }
9 | };
--------------------------------------------------------------------------------
/events/ready.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | module.exports = class {
5 | constructor(client) {
6 | this.client = client;
7 | }
8 |
9 | async run() {
10 |
11 | // Await is used here because the ready event isn't actually ready; sometimes
12 | // guild information will come in AFTER ready. 1 second (1000ms) is generally enough time
13 | // for everything to be loaded.
14 | // NOTE: client.wait and client.log are added by ./modules/functions.js
15 | await this.client.wait(1000);
16 |
17 | // This loop ensures that client.appInfo always contains up to date data
18 | // about the app's status. This includes whether the bot is public or not,
19 | // its description, owner, etc. Primarily used for the dashboard amongst other things.
20 | this.client.appInfo = await this.client.fetchApplication();
21 | setInterval( async () => {
22 | this.client.appInfo = await this.client.fetchApplication();
23 | }, 60000);
24 |
25 | // Now checks whether the "Default" guild settings are loaded in the enmap.
26 | // If they're not, they'll be written in. This should only happen on first load.
27 | if (!this.client.settings.has("default")) {
28 | if (!this.client.config.defaultSettings) throw new Error("defaultSettings not preset in config.js or settings database. Bot cannot load.");
29 | this.client.settings.set("default", this.client.config.defaultSettings);
30 | }
31 |
32 | // Initialises the dashboard, which must be done during the `ready` event.
33 | // Otherwise, some data may be missing from the dashboard.
34 | require("../modules/dashboard.js")(this.client);
35 |
36 | // Sets the status to Do Not Disturb for 5 seconds, to visually indicate to
37 | // users that the client is restarting or has just been started up.
38 | this.client.user.setStatus("dnd");
39 | await this.client.wait(5000);
40 |
41 | // Sets the client's status back to Online to visually indicate to users that
42 | // it is (almost) ready.
43 | this.client.user.setStatus("online");
44 |
45 | // Sets the bot's game/status as "Watching over {number} servers"
46 | // NOTE: This is also set in the guildCreate and guildDelete events.
47 | this.client.user.setActivity(`over ${this.client.guilds.size} servers`, { type: "WATCHING" });
48 |
49 | // Logs that the bot is ready to serve and run, so we know the bot accepts commands.
50 | this.client.logger.log(`${this.client.user.tag}, ready to serve ${this.client.users.size} users in ${this.client.guilds.size} servers.`, "ready");
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/music/js/config.js.example:
--------------------------------------------------------------------------------
1 | exports.TOKEN = "TOKEN-HERE";
2 |
3 | exports.PREFIX = "%";
4 |
5 | exports.GOOGLE_API_KEY = "";
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "delet",
3 | "version": "2.8.3",
4 | "description": "An in-development, open-source bot for Discord written in JavaScript, using the Discord.js API library",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "eslint . && npm run text",
8 | "text": "node build/text.js",
9 | "start": "node index.js"
10 | },
11 | "engines": {
12 | "node": ">=8"
13 | },
14 | "nodemonConfig": {
15 | "ignore": [
16 | "./data/*",
17 | "README.md",
18 | "*.example"
19 | ]
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "git+https://github.com/DS-Development/delet.git"
24 | },
25 | "author": "suvanl (https://github.com/suvanl)",
26 | "contributors": [
27 | "nitramleo (https://github.com/nitramleo)",
28 | "tale-zero (https://github.com/tale-zero)"
29 | ],
30 | "license": "GPL-3.0",
31 | "bugs": {
32 | "url": "https://github.com/DS-Development/delet/issues"
33 | },
34 | "homepage": "https://delet.js.org",
35 | "dependencies": {
36 | "array-sort": "^1.0.0",
37 | "body-parser": "^1.19.0",
38 | "chalk": "^3.0.0",
39 | "cleverbot.io": "^1.0.4",
40 | "common-tags": "^1.8.0",
41 | "discord.js": "^11.5.1",
42 | "dotenv": "^8.2.0",
43 | "ejs": "^3.0.1",
44 | "enmap": "^4.0.6",
45 | "express": "^4.17.1",
46 | "express-passport": "^0.1.0",
47 | "express-session": "^1.17.0",
48 | "ffmpeg": "0.0.4",
49 | "helmet": "^3.21.2",
50 | "html-entities": "^1.2.1",
51 | "isgd": "^1.1.3",
52 | "klaw": "^3.0.0",
53 | "marked": "^0.8.2",
54 | "mathjs": "^6.6.2",
55 | "memorystore": "^1.6.2",
56 | "moment": "^2.24.0",
57 | "moment-duration-format": "^2.3.2",
58 | "moment-timezone": "^0.5.27",
59 | "ms": "^2.1.2",
60 | "node-fetch": "^2.6.0",
61 | "passport": "^0.4.1",
62 | "passport-discord": "^0.1.3",
63 | "readline-sync": "^1.4.10",
64 | "sequelize": "^5.21.3",
65 | "simple-youtube-api": "^5.2.1",
66 | "snekfetch": "^4.0.4",
67 | "sqlite3": "^4.1.1",
68 | "table": "^5.4.6",
69 | "weather-js": "^2.0.0"
70 | },
71 | "optionalDependencies": {
72 | "canvas": "^2.6.1",
73 | "node-opus": "^0.3.3",
74 | "ytdl-core": "^2.0.1"
75 | },
76 | "devDependencies": {
77 | "eslint": "^6.8.0"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/util/Logger.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | // Logger class for easy and aesthetically pleasing console logging
5 | const chalk = require("chalk");
6 | const moment = require("moment");
7 |
8 | class Logger {
9 | static log(content, type = "log") {
10 | const timestamp = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]:`;
11 | switch (type) {
12 | case "log": {
13 | return console.log(`${timestamp} ${chalk.bgBlue(type.toUpperCase())} ${content} `);
14 | }
15 | case "warn": {
16 | return console.log(`${timestamp} ${chalk.black.bgYellow(type.toUpperCase())} ${content} `);
17 | }
18 | case "info": {
19 | return console.log(`${timestamp} ${chalk.cyan(type.toUpperCase())} ${content} `);
20 | }
21 | case "error": {
22 | return console.log(`${timestamp} ${chalk.bgRed(type.toUpperCase())} ${content} `);
23 | }
24 | case "debug": {
25 | return console.log(`${timestamp} ${chalk.green(type.toUpperCase())} ${content} `);
26 | }
27 | case "cmd": {
28 | return console.log(`${timestamp} ${chalk.black.bgWhite(type.toUpperCase())} ${content}`);
29 | }
30 | case "panel": {
31 | return console.log(`${timestamp} ${chalk.black.bgCyan(type.toUpperCase())} ${content}`);
32 | }
33 | case "ready": {
34 | return console.log(`${timestamp} ${chalk.black.bgGreen(type.toUpperCase())} ${content}`);
35 | }
36 | default: throw new TypeError("Logger type must be one of either log, warn, info, error, debug, cmd, panel or ready.");
37 | }
38 | }
39 |
40 | static error(content) {
41 | return this.log(content, "error");
42 | }
43 |
44 | static warn(content) {
45 | return this.log(content, "warn");
46 | }
47 |
48 | static info(content) {
49 | return this.log(content, "info");
50 | }
51 |
52 | static debug(content) {
53 | return this.log(content, "debug");
54 | }
55 |
56 | static cmd(content) {
57 | return this.log(content, "cmd");
58 | }
59 |
60 | static panel(content) {
61 | return this.log(content, "panel");
62 | }
63 | }
64 |
65 | module.exports = Logger;
66 |
--------------------------------------------------------------------------------
/util/Utils.js:
--------------------------------------------------------------------------------
1 | class Utils {
2 | static base64(text, mode = "encode") {
3 | if (mode === "encode") return Buffer.from(text).toString("base64");
4 | if (mode === "decode") return Buffer.from(text, "base64").toString("utf8") || null;
5 | throw new TypeError(`${mode} is not a supported Base64 mode`);
6 | }
7 | }
8 |
9 | module.exports = Utils;
--------------------------------------------------------------------------------
/util/data.js:
--------------------------------------------------------------------------------
1 | // Arrays
2 | exports.botPerms = [
3 | "MANAGE_ROLES",
4 | "KICK_MEMBERS",
5 | "MANAGE_CHANNELS",
6 | "BAN_MEMBERS",
7 | "VIEW_AUDIT_LOG",
8 | "VIEW_CHANNEL",
9 | "SEND_TTS_MESSAGES",
10 | "EMBED_LINKS",
11 | "READ_MESSAGE_HISTORY",
12 | "USE_EXTERNAL_EMOJIS",
13 | "MANAGE_EMOJIS",
14 | "SEND_MESSAGES",
15 | "MANAGE_MESSAGES",
16 | "MANAGE_NICKNAMES",
17 | "ATTACH_FILES",
18 | "ADD_REACTIONS",
19 | "CONNECT",
20 | "SPEAK",
21 | "USE_VAD"
22 | ];
23 |
24 | exports.currencies = [
25 | "EUR",
26 | "GBP",
27 | "NOK",
28 | "USD"
29 | ];
--------------------------------------------------------------------------------
/util/setup.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const input = require("readline-sync");
5 | const Enmap = require("enmap");
6 | const path = require("path");
7 | const fs = require("fs");
8 | const envExamplePath = path.join(__dirname, "..", ".env.example");
9 | const envPath = path.join(__dirname, "..", ".env");
10 |
11 | let baseConfig = fs.readFileSync("./util/setup_base.txt", "utf8");
12 | let env = fs.readFileSync(envExamplePath, "utf8");
13 |
14 | const defaultSettings = {
15 | "prefix": "%",
16 | "modLogChannel": "mod-log",
17 | "modRole": "Moderator",
18 | "adminRole": "Administrator",
19 | "systemNotice": "true",
20 | "welcomeChannel": "general",
21 | "welcomeMessage": "Say hello to {{user}}, everyone! 🎉👋",
22 | "welcomeEnabled": "false",
23 | "currency": ">>No currency set<<",
24 | "language": "en-GB"
25 | };
26 |
27 | const settings = new Enmap({ name: "settings", cloneLevel: "deep" });
28 |
29 | (async function() {
30 | console.log("Setting up delet's configuration...\nCTRL + C if you want to manually edit `config.js.example` into config.js!");
31 | await settings.defer;
32 | if (settings.has("default")) {
33 | if (input.keyInYN("Default settings already exist. Reset to default?")) {
34 | settings.set("default", defaultSettings);
35 | } else {
36 | console.log("First start - inserting default guild settings into the database...");
37 | settings.set("default", defaultSettings);
38 | }
39 | }
40 |
41 | const isGlitch = input.keyInYN("Are you hosted on Glitch.com? ");
42 |
43 | if (isGlitch.glitch) {
44 | baseConfig = baseConfig
45 | .replace("{{defaultSettings}}", JSON.stringify(defaultSettings, null, 2))
46 | .replace("{{fullURL}}", "${process.env.PROJECT_DOMAIN}")
47 | .replace("{{domain}}", "`${process.env.PROJECT_DOMAIN}.glitch.me`")
48 | .replace("{{port}}", "process.env.PORT")
49 | .replace("{{token}}", "process.env.TOKEN")
50 | .replace("{{oauthSecret}}", "process.env.SECRET")
51 | .replace("{{sessionSecret}}", "process.env.SESSION_SECRET");
52 |
53 | console.log("REMEMBER TO PLACE THE TOKEN, SECRET AND SESSION_SECRET IN YOUR .ENV FILE!");
54 | fs.writeFileSync("./config.js", baseConfig);
55 | console.log("Configuration has been written, enjoy!");
56 | return;
57 | }
58 |
59 | const token = input.question("Please enter the bot's token from the application page: ");
60 | const oauthSecret = input.question("Please enter the client secret from the application page: ");
61 | const saltyKey = input.question("Please enter a session security passphrase (used to encrypt session data): ");
62 | const host = input.question("Please enter your domain name (no http prefix, port optional. E.g. `localhost:8080` or `www.example.com`): ");
63 | const port = input.question("Please enter the port on which to host the local server (default is 81): ", {
64 | defaultInput: 81
65 | });
66 |
67 | baseConfig = baseConfig
68 | .replace("{{defaultSettings}}", JSON.stringify(defaultSettings, null, 2))
69 | .replace("{{fullURL}}", host)
70 | .replace("{{domain}}", `"${host.split(":")[0]}"`)
71 | .replace("{{port}}", port)
72 | // .replace("{{token}}", `"${token}"`)
73 | .replace("{{oauthSecret}}", `"${oauthSecret}"`)
74 | .replace("{{sessionSecret}}", `"${saltyKey}"`);
75 |
76 | env = env
77 | .replace("TOKEN_HERE", token);
78 |
79 | fs.writeFileSync("./config.js", baseConfig);
80 | fs.writeFileSync(envPath, env);
81 | console.log("REMEMBER TO NEVER SHARE YOUR TOKEN WITH ANYONE!");
82 | console.log("Configuration has been written, enjoy!");
83 | await settings.close();
84 | }());
--------------------------------------------------------------------------------
/util/setup_base.txt:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 An Idiot's Guide. All rights reserved. MIT license.
2 | // https://github.com/AnIdiotsGuide/guidebot-class
3 |
4 | const config = {
5 | "admins": [],
6 | "support": [],
7 | "dashboard" : {
8 | "oauthSecret": {{oauthSecret}},
9 | "callbackURL": "http://{{fullURL}}/callback",
10 | "sessionSecret": {{sessionSecret}},
11 | "domain": {{domain}},
12 | "port": {{port}}
13 | },
14 | defaultSettings: {{defaultSettings}},
15 | permLevels: [
16 | { level: 0,
17 | name: "User",
18 | check: () => true
19 | },
20 | { level: 2,
21 | name: "Moderator",
22 | check: (message) => {
23 | try {
24 | const modRole = message.guild.roles.find(r => r.name.toLowerCase() === message.settings.modRole.toLowerCase());
25 | if (modRole && message.member.roles.has(modRole.id)) return true;
26 | } catch (e) {
27 | return false;
28 | }
29 | }
30 | },
31 | { level: 3,
32 | name: "Administrator",
33 | check: (message) => {
34 | try {
35 | const adminRole = message.guild.roles.find(r => r.name.toLowerCase() === message.settings.adminRole.toLowerCase());
36 | return (adminRole && message.member.roles.has(adminRole.id));
37 | } catch (e) {
38 | return false;
39 | }
40 | }
41 | },
42 | { level: 4,
43 | name: "Server Owner",
44 | check: (message) => message.channel.type === "text" ? (message.guild.owner.user.id === message.author.id ? true : false) : false
45 | },
46 | { level: 8,
47 | name: "Bot Support",
48 | check: (message) => config.support.includes(message.author.id)
49 | },
50 | { level: 9,
51 | name: "Bot Admin",
52 | check: (message) => config.admins.includes(message.author.id)
53 | },
54 | { level: 10,
55 | name: "Bot Owner",
56 | check: (message) => message.client.appInfo.owner.id === message.author.id
57 | }
58 | ]
59 | };
60 |
61 | module.exports = config;
62 |
--------------------------------------------------------------------------------