├── .eslintrc.js ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── test.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── assets ├── fonts │ ├── NotoEmoji-Regular.ttf │ ├── Roboto-Regular.ttf │ ├── RobotoCondensed-Regular.ttf │ └── RobotoMono-Light.ttf ├── manipulation │ └── lio.png ├── profiles │ ├── backgrounds │ │ ├── birdie.png │ │ ├── butterflies.png │ │ ├── cherry-blossoms.png │ │ ├── courtyard.png │ │ ├── default.png │ │ ├── people.png │ │ ├── progressbar.png │ │ ├── stars.png │ │ ├── sunset-palms.png │ │ ├── sunset-tree.png │ │ ├── template.png │ │ └── tracks.png │ └── bg │ │ ├── birdie.png │ │ ├── butterflies.png │ │ ├── cherry-blossoms.png │ │ ├── courtyard.png │ │ ├── default.png │ │ ├── people.png │ │ ├── stars.png │ │ ├── sunset-palms.png │ │ ├── sunset-tree.png │ │ └── tracks.png └── weather │ ├── base │ ├── cloudy.png │ ├── day.png │ ├── night.png │ ├── rain.png │ ├── snow.png │ ├── thunderstorm.png │ └── windy.png │ └── icons │ ├── dark │ ├── clear-day.png │ ├── clear-night.png │ ├── cloudy.png │ ├── flurries.png │ ├── fog.png │ ├── humidity.png │ ├── partly-cloudy-day.png │ ├── partly-cloudy-night.png │ ├── pointer.png │ ├── precip.png │ ├── rain.png │ ├── sleet.png │ ├── snow.png │ ├── thunderstorm.png │ ├── unknown.png │ └── wind.png │ └── light │ ├── clear-day.png │ ├── clear-night.png │ ├── cloudy.png │ ├── flurries.png │ ├── fog.png │ ├── humidity.png │ ├── partly-cloudy-day.png │ ├── partly-cloudy-night.png │ ├── pointer.png │ ├── precip.png │ ├── rain.png │ ├── sleet.png │ ├── snow.png │ ├── thunderstorm.png │ ├── unknown.png │ └── wind.png ├── docker-compose.yml ├── package.json ├── src ├── PenguBot.js ├── arguments │ ├── channelname.js │ ├── membername.js │ ├── rolename.js │ └── username.js ├── commands │ ├── Developer │ │ ├── eval.js │ │ ├── exec.js │ │ ├── setgame.js │ │ └── togglepatronguild.js │ ├── Game Statistics │ │ ├── clashofclans.js │ │ ├── csgo.js │ │ ├── fortnite.js │ │ └── osu.js │ ├── Games │ │ ├── 8ball.js │ │ ├── rps.js │ │ └── slots.js │ ├── General │ │ └── Chat Bot Info │ │ │ ├── donate.js │ │ │ ├── help.js │ │ │ ├── info.js │ │ │ ├── nodeinfo.js │ │ │ ├── settings.js │ │ │ ├── stats.js │ │ │ ├── support.js │ │ │ └── upvote.js │ ├── Images │ │ ├── cat.js │ │ ├── cookie.js │ │ ├── cuddle.js │ │ ├── dog.js │ │ ├── feed.js │ │ ├── fox.js │ │ ├── hug.js │ │ ├── kiss.js │ │ ├── meme.js │ │ ├── pat.js │ │ ├── pengu.js │ │ ├── poke.js │ │ ├── punch.js │ │ ├── randomcomic.js │ │ ├── slap.js │ │ ├── tickle.js │ │ └── wholesome.js │ ├── Jokes and Stuff │ │ ├── chucknorris.js │ │ ├── compliment.js │ │ ├── dadjoke.js │ │ ├── dice.js │ │ ├── fml.js │ │ ├── insult.js │ │ ├── randomfact.js │ │ ├── trump.js │ │ └── yomomma.js │ ├── Management │ │ ├── Automod │ │ │ ├── manageautomod.js │ │ │ └── toggleinvites.js │ │ ├── Autoroles │ │ │ ├── addautoroles.js │ │ │ └── toggleautoroles.js │ │ ├── Custom Commands │ │ │ ├── createcmd.js │ │ │ ├── deletecmd.js │ │ │ ├── listcmds.js │ │ │ ├── togglecustomcmds.js │ │ │ └── updatecmd.js │ │ ├── Level Roles │ │ │ ├── listlevelroles.js │ │ │ ├── managelevelroles.js │ │ │ └── togglelevelroles.js │ │ ├── Logging │ │ │ ├── log.js │ │ │ ├── loggingchannel.js │ │ │ └── modlogs.js │ │ ├── Self Roles │ │ │ ├── manageselfroles.js │ │ │ ├── selfroles.js │ │ │ └── toggleselfroles.js │ │ ├── Starboard │ │ │ ├── starboard.js │ │ │ ├── starboardchannel.js │ │ │ ├── starsrequired.js │ │ │ └── togglestarboard.js │ │ └── Welcome & Leave │ │ │ ├── setleavechannel.js │ │ │ ├── setleavemsg.js │ │ │ ├── setwelcomechannel.js │ │ │ ├── setwelcomemsg.js │ │ │ ├── toggleleave.js │ │ │ └── togglewelcome.js │ ├── Manipulation │ │ ├── achievement.js │ │ ├── approved.js │ │ ├── batslap.js │ │ ├── beautiful.js │ │ ├── changemymind.js │ │ ├── facepalm.js │ │ ├── garbage.js │ │ ├── illegal.js │ │ ├── lio.js │ │ ├── missing.js │ │ ├── rejected.js │ │ ├── respect.js │ │ ├── snap.js │ │ ├── superpunch.js │ │ ├── tattoo.js │ │ ├── tinder.js │ │ ├── triggered.js │ │ ├── vault.js │ │ └── wanted.js │ ├── Moderation │ │ ├── ban.js │ │ ├── case.js │ │ ├── history.js │ │ ├── kick.js │ │ ├── mute.js │ │ ├── prune.js │ │ ├── reason.js │ │ ├── softban.js │ │ └── warn.js │ ├── Music │ │ └── music.js │ ├── Profiles │ │ ├── backgrounds.js │ │ ├── daily.js │ │ ├── leaderboard.js │ │ ├── levelup.js │ │ ├── managexp.js │ │ ├── profile.js │ │ ├── rank.js │ │ ├── rep.js │ │ ├── snowflakes.js │ │ └── title.js │ ├── Settings │ │ ├── disablecmd.js │ │ ├── manageadmin.js │ │ ├── managedj.js │ │ ├── managemod.js │ │ ├── managestaff.js │ │ ├── prefix.js │ │ ├── setlanguage.js │ │ └── togglecategory.js │ └── Utilities │ │ ├── afk.js │ │ ├── avatar.js │ │ ├── choose.js │ │ ├── covid.js │ │ ├── emote.js │ │ ├── guild.js │ │ ├── lmgtfy.js │ │ ├── poll.js │ │ ├── quote.js │ │ ├── reddit.js │ │ ├── remind.js │ │ ├── roleinfo.js │ │ ├── say.js │ │ ├── shorten.js │ │ ├── translate.js │ │ ├── twstats.js │ │ ├── urban.js │ │ ├── userinfo.js │ │ ├── weather.js │ │ └── ytstats.js ├── events │ ├── channelCreate.js │ ├── channelDelete.js │ ├── commandError.js │ ├── commandUnknown.js │ ├── debug.js │ ├── disconnect.js │ ├── eventError.js │ ├── guildBanAdd.js │ ├── guildBanRemove.js │ ├── guildCreate.js │ ├── guildDelete.js │ ├── guildMemberAdd.js │ ├── guildMemberRemove.js │ ├── klasaReady.js │ ├── messageDelete.js │ ├── messageDeleteBulk.js │ ├── messageReactionAdd.js │ ├── messageReactionRemove.js │ ├── messageUpdate.js │ ├── reconnecting.js │ ├── resumed.js │ ├── roleCreate.js │ ├── roleDelete.js │ └── shardError.js ├── extendables │ ├── fetchURL.js │ └── prompt.js ├── finalizers │ └── commandCounter.js ├── functions │ ├── friendlyDuration.js │ ├── images.js │ ├── isPatron.js │ ├── isUpvoter.js │ ├── randomNumber.js │ └── scrapeSubreddit.js ├── index.js ├── inhibitors │ ├── disabledGroup.js │ ├── patronOnly.js │ ├── requireDJ.js │ ├── requireMusic.js │ └── upvoterOnly.js ├── languages │ ├── en-US.js │ ├── es-ES.js │ ├── fr-FR.js │ ├── it-IT.js │ └── sar-IT.js ├── lib │ ├── constants │ │ ├── facts.json │ │ ├── nsfw │ │ │ └── subreddits.json │ │ └── yomomma.json │ ├── structures │ │ ├── KlasaCommand.js │ │ ├── ModLog.js │ │ ├── PenguClient.js │ │ ├── PenguGuild.js │ │ ├── PenguMember.js │ │ ├── PenguMemberManager.js │ │ ├── ServerLog.js │ │ ├── permissionLevels.js │ │ └── schemas │ │ │ ├── defaultClientSchema.js │ │ │ ├── defaultGuildSchema.js │ │ │ ├── defaultMemberSchema.js │ │ │ └── defaultUserSchema.js │ ├── tags │ │ ├── getjson.js │ │ └── sendchannel.js │ └── util │ │ └── Util.js ├── main.js ├── middlewares │ ├── headers.js │ └── json.js ├── monitors │ ├── afk.js │ ├── antiinvites.js │ ├── memberProfiles.js │ ├── perspectivemod.js │ └── profiles.js ├── providers │ └── rethinkdb.js ├── routes │ ├── application.js │ ├── dblHook.js │ ├── kdhGuild.js │ ├── pieces.js │ └── syncdb.js └── tasks │ ├── datadog.js │ ├── memorySweeper.js │ ├── reminder.js │ ├── stats.js │ ├── tempMute.js │ └── timedBan.js └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: PenguBot 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: # Replace with a single custom sponsorship URL -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Type command '....' 14 | 3. Do something '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Versions** 24 | - NodeJS: [e.g. 8, 10] 25 | - Klasa [e.g. 0.5.0-dev] 26 | - Discord.JS [e.g. 12] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 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. Ex. 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/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description of Your Pull Request 2 | What does your pull request specifically does by adding/modifying or removing code? 3 | 4 | ### Changes Proposed and or Files Changed 5 | - Example Change 6 | 7 | ### Label Your Pull Request 8 | - [ ] This PR modifies existing code to enhance the bot 9 | - [ ] This PR fixes a bug within the bot 10 | - [ ] This PR removes/renames methods or properties 11 | - [ ] This PR adds methods, features, commands or properties 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | name: Node v${{ matrix.node_version }} - ${{ matrix.os }} 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | node_version: [14] 16 | os: [ubuntu-latest] 17 | steps: 18 | - name: Checkout Project 19 | uses: actions/checkout@v1 20 | - name: Use Node.js ${{ matrix.node_version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node_version }} 24 | - name: Restore CI Cache 25 | uses: actions/cache@v1 26 | with: 27 | path: node_modules 28 | key: ${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles(matrix.os == 'windows-latest' && '**\yarn.lock' || '**/yarn.lock') }} 29 | - name: Install Dependencies 30 | run: | 31 | yarn add https://{{secrets.TOKEN}}:x-oauth-basic@github.com/PenguBot/music.git#build 32 | yarn 33 | - name: Test 34 | run: yarn test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # config file 61 | config.js 62 | 63 | # npm lock file 64 | package-lock.json 65 | 66 | # VSCode User Data 67 | .vscode 68 | 69 | # yarn lock 70 | yarn-error.log 71 | 72 | dist 73 | 74 | .yarn 75 | .yarnrc 76 | .yarnrc.yml -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.9.0-alpine 2 | 3 | RUN mkdir -p /home/pengubot/ 4 | WORKDIR /home/pengubot/ 5 | 6 | RUN apk add --no-cache \ 7 | build-base \ 8 | cairo-dev \ 9 | freetype-dev \ 10 | g++ \ 11 | gcc \ 12 | giflib-dev \ 13 | git \ 14 | jpeg-dev \ 15 | libjpeg-turbo-dev \ 16 | musl-dev \ 17 | pango-dev \ 18 | pangomm-dev \ 19 | pixman-dev \ 20 | pkgconfig \ 21 | python 22 | 23 | COPY package.json /home/pengubot/ 24 | COPY yarn.lock /home/pengubot/ 25 | 26 | ARG PAT 27 | 28 | RUN sed -i "s|github:pengubot/music#build|git+https://AdityaTD:${PAT}@github.com/PenguBot/music.git#build|g" ./package.json 29 | RUN yarn install --link-duplicates --build-links --production 30 | 31 | COPY /src /home/pengubot/src 32 | COPY /assets /home/pengubot/assets 33 | COPY config.js /home/pengubot/config.js 34 | COPY .git /home/pengubot/.git 35 | 36 | WORKDIR /home/pengubot/src 37 | CMD ["node", "main.js"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 Aditya N. Tripathi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/fonts/NotoEmoji-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/fonts/NotoEmoji-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/RobotoCondensed-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/fonts/RobotoCondensed-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/RobotoMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/fonts/RobotoMono-Light.ttf -------------------------------------------------------------------------------- /assets/manipulation/lio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/manipulation/lio.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/birdie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/birdie.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/butterflies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/butterflies.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/cherry-blossoms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/cherry-blossoms.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/courtyard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/courtyard.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/default.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/people.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/people.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/progressbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/progressbar.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/stars.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/sunset-palms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/sunset-palms.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/sunset-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/sunset-tree.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/template.png -------------------------------------------------------------------------------- /assets/profiles/backgrounds/tracks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/backgrounds/tracks.png -------------------------------------------------------------------------------- /assets/profiles/bg/birdie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/birdie.png -------------------------------------------------------------------------------- /assets/profiles/bg/butterflies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/butterflies.png -------------------------------------------------------------------------------- /assets/profiles/bg/cherry-blossoms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/cherry-blossoms.png -------------------------------------------------------------------------------- /assets/profiles/bg/courtyard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/courtyard.png -------------------------------------------------------------------------------- /assets/profiles/bg/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/default.png -------------------------------------------------------------------------------- /assets/profiles/bg/people.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/people.png -------------------------------------------------------------------------------- /assets/profiles/bg/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/stars.png -------------------------------------------------------------------------------- /assets/profiles/bg/sunset-palms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/sunset-palms.png -------------------------------------------------------------------------------- /assets/profiles/bg/sunset-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/sunset-tree.png -------------------------------------------------------------------------------- /assets/profiles/bg/tracks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/profiles/bg/tracks.png -------------------------------------------------------------------------------- /assets/weather/base/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/cloudy.png -------------------------------------------------------------------------------- /assets/weather/base/day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/day.png -------------------------------------------------------------------------------- /assets/weather/base/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/night.png -------------------------------------------------------------------------------- /assets/weather/base/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/rain.png -------------------------------------------------------------------------------- /assets/weather/base/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/snow.png -------------------------------------------------------------------------------- /assets/weather/base/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/thunderstorm.png -------------------------------------------------------------------------------- /assets/weather/base/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/base/windy.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/clear-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/clear-day.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/clear-night.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/cloudy.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/flurries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/flurries.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/fog.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/humidity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/humidity.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/partly-cloudy-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/partly-cloudy-day.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/partly-cloudy-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/partly-cloudy-night.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/pointer.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/precip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/precip.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/rain.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/sleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/sleet.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/snow.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/thunderstorm.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/unknown.png -------------------------------------------------------------------------------- /assets/weather/icons/dark/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/dark/wind.png -------------------------------------------------------------------------------- /assets/weather/icons/light/clear-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/clear-day.png -------------------------------------------------------------------------------- /assets/weather/icons/light/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/clear-night.png -------------------------------------------------------------------------------- /assets/weather/icons/light/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/cloudy.png -------------------------------------------------------------------------------- /assets/weather/icons/light/flurries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/flurries.png -------------------------------------------------------------------------------- /assets/weather/icons/light/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/fog.png -------------------------------------------------------------------------------- /assets/weather/icons/light/humidity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/humidity.png -------------------------------------------------------------------------------- /assets/weather/icons/light/partly-cloudy-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/partly-cloudy-day.png -------------------------------------------------------------------------------- /assets/weather/icons/light/partly-cloudy-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/partly-cloudy-night.png -------------------------------------------------------------------------------- /assets/weather/icons/light/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/pointer.png -------------------------------------------------------------------------------- /assets/weather/icons/light/precip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/precip.png -------------------------------------------------------------------------------- /assets/weather/icons/light/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/rain.png -------------------------------------------------------------------------------- /assets/weather/icons/light/sleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/sleet.png -------------------------------------------------------------------------------- /assets/weather/icons/light/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/snow.png -------------------------------------------------------------------------------- /assets/weather/icons/light/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/thunderstorm.png -------------------------------------------------------------------------------- /assets/weather/icons/light/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/unknown.png -------------------------------------------------------------------------------- /assets/weather/icons/light/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adiologydev/PenguBot/be75addea7b29cf27d49bb9cddd4286dfe7390b6/assets/weather/icons/light/wind.png -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | pengubot: 4 | container_name: pengubot 5 | image: pengubot 6 | build: 7 | context: . 8 | args: 9 | PAT: ${PAT} 10 | restart: always 11 | network_mode: host -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pengubot", 3 | "version": "2.0.8", 4 | "description": "PenguBot Rewrite for Performance and Stability.", 5 | "main": "src/main.js", 6 | "scripts": { 7 | "start": "node src/main", 8 | "test": "eslint .", 9 | "lint": "eslint --fix ." 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/AdityaTD/PenguBot.git" 14 | }, 15 | "keywords": [ 16 | "pengubot", 17 | "pengu", 18 | "bot", 19 | "discord", 20 | "bot", 21 | "discord" 22 | ], 23 | "author": "Aditya Nath Tripathi", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/AdityaTD/PenguBot/issues" 27 | }, 28 | "homepage": "https://github.com/AdityaTD/PenguBot#readme", 29 | "dependencies": { 30 | "@k3rn31p4nic/google-translate-api": "^1.1.1", 31 | "@kcp/functions": "github:pengubot/functions#build", 32 | "@lavacord/discord.js": "^0.0.7", 33 | "@pengubot/music": "github:pengubot/music#build", 34 | "breadtags": "github:PenguBot/bread-tags", 35 | "bufferutil": "^4.0.3", 36 | "canvas": "^2.6.0", 37 | "canvas-constructor": "3.0.3", 38 | "discord.js": "^12.5.1", 39 | "hot-shots": "^8.3.0", 40 | "klasa": "github:pengubot/klasa#stable", 41 | "klasa-api": "github:PenguBot/klasa-api#v1-alpha", 42 | "kurasuta": "^2.2.0", 43 | "node-fetch": "^2.6.0", 44 | "node-html-parser": "^2.0.2", 45 | "raven": "^2.6.4", 46 | "rethinkdbdash": "^2.3.31", 47 | "utf-8-validate": "^5.0.4", 48 | "zlib-sync": "^0.1.6" 49 | }, 50 | "devDependencies": { 51 | "eslint": "7.17.0", 52 | "eslint-plugin-node": "^11.1.0", 53 | "eslint-plugin-promise": "^4.2.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/PenguBot.js: -------------------------------------------------------------------------------- 1 | const { BaseCluster } = require("kurasuta"); 2 | const Raven = require("raven"); 3 | const config = require("../config.js"); 4 | const { execSync } = require("child_process"); 5 | 6 | Raven.config(config.apis.sentry, { 7 | captureUnhandledRejections: true, 8 | environment: config.production ? "production" : "development", 9 | release: execSync("git rev-parse HEAD").toString() 10 | }).install(); 11 | 12 | module.exports = class extends BaseCluster { 13 | 14 | launch() { 15 | return this.client.login(this.manager.token); 16 | } 17 | 18 | }; 19 | 20 | process.on("uncaughtException", err => Raven.captureException(err)); 21 | process.on("unhandledRejection", err => Raven.captureException(err)); 22 | -------------------------------------------------------------------------------- /src/arguments/channelname.js: -------------------------------------------------------------------------------- 1 | const { Argument } = require("../index"); 2 | 3 | const regex = Argument.regex.channel; 4 | 5 | module.exports = class extends Argument { 6 | 7 | async run(arg, possible, msg) { 8 | if (!msg.guild) throw "This command can only be used in a server."; 9 | const resChannel = this.resolveChannel(arg, msg.guild); 10 | if (resChannel) return resChannel; 11 | throw "That channel could not be found, please try another one."; 12 | } 13 | 14 | resolveChannel(arg, guild) { 15 | const channelID = regex.exec(arg); 16 | return (channelID !== null && guild.channels.cache.get(channelID[1])) || null; 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/arguments/membername.js: -------------------------------------------------------------------------------- 1 | const { Argument, klasaUtil: { regExpEsc }, GuildMember, User } = require("../index"); 2 | 3 | const USER_REGEXP = Argument.regex.userOrMember; 4 | 5 | module.exports = class extends Argument { 6 | 7 | async run(arg, possible, msg) { 8 | if (!msg.guild) throw "This command can only be used in guilds."; 9 | const resUser = await this.resolveMember(arg, msg.guild); 10 | if (resUser) return resUser; 11 | 12 | const results = []; 13 | const reg = new RegExp(regExpEsc(arg), "i"); 14 | for (const member of msg.guild.members.cache.values()) { 15 | if (member.user && reg.test(member.user.username)) results.push(member); 16 | if (member.nickname && reg.test(member.nickname)) results.push(member); 17 | } 18 | 19 | let querySearch; 20 | if (results.length > 0) { 21 | const regWord = new RegExp(`\\b${regExpEsc(arg)}\\b`, "i"); 22 | const filtered = results.filter(member => (member.user && regWord.test(member.user.username)) || (member.nickname && regWord.test(member.nickname))); 23 | querySearch = filtered.length > 0 ? filtered : results; 24 | } else { 25 | querySearch = results; 26 | } 27 | 28 | switch (querySearch.length) { 29 | case 0: throw `${possible.name} Must be a valid name, id or user mention`; 30 | case 1: return querySearch[0]; 31 | default: throw `Found multiple matches: \`${querySearch.map(member => member.user.tag).join("`, `")}\``; 32 | } 33 | } 34 | 35 | resolveMember(query, guild) { 36 | if (query instanceof GuildMember) return query; 37 | if (query instanceof User) return guild.members.fetch(query); 38 | if (typeof query === "string") { 39 | if (USER_REGEXP.test(query)) return guild.members.fetch(USER_REGEXP.exec(query)[1]).catch(() => null); 40 | if (/\w{1,32}#\d{4}/.test(query)) { 41 | const res = guild.members.cache.find(member => member.user.tag.toLowerCase() === query.toLowerCase()); 42 | return res || null; 43 | } 44 | return null; 45 | } 46 | return null; 47 | } 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /src/arguments/rolename.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017-2019 dirigeants. All rights reserved. MIT license. 2 | const { Argument, klasaUtil: { regExpEsc }, Role } = require("../index"); 3 | const ROLE_REGEXP = Argument.regex.role; 4 | 5 | module.exports = class extends Argument { 6 | 7 | async run(arg, possible, msg) { 8 | if (!msg.guild) return this.role(arg, possible, msg); 9 | const resRole = this.resolveRole(arg, msg.guild); 10 | if (resRole) return resRole; 11 | 12 | const results = []; 13 | const reg = new RegExp(regExpEsc(arg), "i"); 14 | for (const role of msg.guild.roles.cache.values()) if (reg.test(role.name)) results.push(role); 15 | 16 | let querySearch; 17 | if (results.length > 0) { 18 | const regWord = new RegExp(`\\b${regExpEsc(arg)}\\b`, "i"); 19 | const filtered = results.filter(role => regWord.test(role.name)); 20 | querySearch = filtered.length > 0 ? filtered : results; 21 | } else { 22 | querySearch = results; 23 | } 24 | 25 | switch (querySearch.length) { 26 | case 0: throw `${possible.name} Must be a valid name, id or role mention`; 27 | case 1: return querySearch[0]; 28 | default: throw `**Found multiple matches:** \`${querySearch.map(role => role.name).join("`, `")}\``; 29 | } 30 | } 31 | 32 | resolveRole(query, guild) { 33 | if (query instanceof Role) return guild.roles.cache.has(query.id) ? query : null; 34 | if (typeof query === "string" && ROLE_REGEXP.test(query)) return guild.roles.cache.get(ROLE_REGEXP.exec(query)[1]); 35 | return null; 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/arguments/username.js: -------------------------------------------------------------------------------- 1 | const { Argument, klasaUtil: { regExpEsc }, GuildMember, User } = require("../index"); 2 | 3 | const USER_REGEXP = Argument.regex.userOrMember; 4 | 5 | module.exports = class extends Argument { 6 | 7 | async run(arg, possible, msg) { 8 | if (!msg.guild) return this.store.get("user").run(arg, possible, msg); 9 | const resUser = await this.resolveUser(arg, msg.guild); 10 | if (resUser) return resUser; 11 | 12 | const results = []; 13 | const reg = new RegExp(regExpEsc(arg), "i"); 14 | for (const member of msg.guild.members.cache.values()) if (reg.test(member.user.username)) results.push(member.user); 15 | 16 | let querySearch; 17 | if (results.length > 0) { 18 | const regWord = new RegExp(`\\b${regExpEsc(arg)}\\b`, "i"); 19 | const filtered = results.filter(user => regWord.test(user.username)); 20 | querySearch = filtered.length > 0 ? filtered : results; 21 | } else { 22 | querySearch = results; 23 | } 24 | 25 | switch (querySearch.length) { 26 | case 0: throw `${possible.name} Must be a valid name, id or user mention`; 27 | case 1: return querySearch[0]; 28 | default: throw `Found multiple matches: \`${querySearch.map(user => user.tag).join("`, `")}\``; 29 | } 30 | } 31 | 32 | resolveUser(query, guild) { 33 | if (query instanceof GuildMember) return query.user; 34 | if (query instanceof User) return query; 35 | if (typeof query === "string") { 36 | if (USER_REGEXP.test(query)) return guild.client.users.fetch(USER_REGEXP.exec(query)[1]).catch(() => null); 37 | if (/\w{1,32}#\d{4}/.test(query)) { 38 | const res = guild.members.cache.find(member => member.user.tag === query); 39 | return res ? res.user : null; 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /src/commands/Developer/exec.js: -------------------------------------------------------------------------------- 1 | const { Command, util: { exec, codeBlock } } = require("klasa"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | aliases: ["execute"], 8 | description: "-BOT OWNER ONLY-", 9 | guarded: true, 10 | hidden: true, 11 | permissionLevel: 10, 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [input]) { 17 | const result = await exec(input, { timeout: "timeout" in msg.flagArgs ? Number(msg.flagArgs.timeout) : 60000 }) 18 | .catch(error => ({ stdout: null, stderr: error })); 19 | const output = result.stdout ? `**\`OUTPUT\`**${codeBlock("prolog", result.stdout)}` : ""; 20 | const outerr = result.stderr ? `**\`ERROR\`**${codeBlock("prolog", result.stderr)}` : ""; 21 | 22 | return msg.sendMessage([output, outerr].join("\n")); 23 | } 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/commands/Developer/setgame.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | usageDelim: " ", 8 | subcommands: true, 9 | hidden: true, 10 | aliases: ["sg"], 11 | permissionLevel: 10, 12 | usage: " [...]", 13 | description: language => language.get("COMMAND_SG_DESCRIPTION") 14 | }); 15 | } 16 | 17 | async text(msg, [...game]) { 18 | await this.client.shard.broadcastEval(`this.user.setPresence({ activity: { name: '${game.join(" ")}', status: "online" }})`); 19 | return msg.sendMessage(`**Playing status has been changed to:** ${game.join(" ")}`); 20 | } 21 | 22 | async stream(msg, [...game]) { 23 | await this.client.shard.broadcastEval(`this.user.setPresence({ activity: { name: '${game.join(" ")}', type: "STREAMING", status: "online", url: "https://twitch.tv/AdityaTD" }})`); 24 | return msg.sendMessage(`**Playing status has been changed to:** ${game.join(" ")}`); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Developer/togglepatronguild.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | aliases: ["tpg"], 8 | hidden: true, 9 | permissionLevel: 10, 10 | usage: "", 11 | description: language => language.get("COMMAND_TPG_DESCRIPTION") 12 | }); 13 | } 14 | 15 | async run(msg, [guild]) { 16 | const exists = this.client.settings.get("pGuilds").includes(guild); 17 | await this.client.settings.update("pGuilds", guild); 18 | return msg.sendMessage(`${exists ? "**Removed Guild:**" : "**Added Guild:**"} ${guild}`); 19 | } 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /src/commands/Games/8ball.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const answers = [ 3 | "Maybe.", "Certainly not.", "I hope so.", "Not in your wildest dreams.", 4 | "There is a good chance.", "Quite likely.", "I think so.", 5 | "I hope not.", "I hope so.", "Never!", "Fuhgeddaboudit.", 6 | "Ahaha! Really?!?", "Pfft.", "Sorry, bucko.", 7 | "Hell, yes.", "Hell to the no.", "The future is bleak.", 8 | "The future is uncertain.", "I would rather not say.", "Who cares?", 9 | "Possibly.", "Never, ever, ever.", "There is a small chance.", "Yes!"]; 10 | 11 | module.exports = class extends Command { 12 | 13 | constructor(...args) { 14 | super(...args, { 15 | cooldown: 8, 16 | aliases: ["yesorno"], 17 | description: language => language.get("COMMAND_8BALL_DESCRIPTION"), 18 | extendedHelp: "No extended help available.", 19 | usage: "" 20 | }); 21 | } 22 | 23 | async run(msg) { 24 | return msg.reply(`🎱 ${answers[Math.floor(Math.random() * answers.length)]}`); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Games/rps.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const choices = ["rock", "paper", "scissors"]; 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 8, 9 | aliases: ["rockpaperscissors", "rpsgame"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_RPS_DESCRIPTION"), 12 | extendedHelp: "No extended help available.", 13 | usage: "" 14 | }); 15 | } 16 | 17 | async run(msg, [move]) { 18 | if (!move.match(/Rock|Paper|Scissors/i)) return msg.reply(`${msg.language.get("CMD_RPS_INVALID")} \`rock\`. \`paper\` or \`scissors\`.`); 19 | const outcome = choices[Math.floor(Math.random() * choices.length)]; 20 | const choice = move.toLowerCase(); 21 | if (choice === "rock") { 22 | if (outcome === "rock") return msg.reply("***Rock! That's a tie!***"); 23 | if (outcome === "paper") return msg.reply("***Paper! I win, you lose!***"); 24 | if (outcome === "scissors") return msg.reply("***Scissors! No! You won...***"); 25 | } 26 | if (choice === "paper") { 27 | if (outcome === "rock") return msg.reply("***Rock! No! You won...***"); 28 | if (outcome === "paper") return msg.reply("***Paper! Yeah! That's a tie!***"); 29 | if (outcome === "scissors") return msg.reply("***Scissors! I win, you lose!***"); 30 | } 31 | if (choice === "scissors") { 32 | if (outcome === "rock") return msg.reply("***Rock! I win, you lose!***"); 33 | if (outcome === "paper") return msg.reply("***Paper! No! You won...***"); 34 | if (outcome === "scissors") return msg.reply("***Scissors! Yeah! That's a tie!***"); 35 | } 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/commands/General/Chat Bot Info/donate.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | aliases: ["patreon", "patron", "premium"], 9 | guarded: true, 10 | requiredPermissions: ["EMBED_LINKS", "ATTACH_FILES"], 11 | description: language => language.get("COMMAND_DONATE_DESCRIPTION") 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const embed = new MessageEmbed() 17 | .setDescription(msg.language.get("COMMAND_DONATE")) 18 | .setAuthor("PenguBot - Premium", this.client.user.displayAvatarURL(), "https://www.pengubot.com") 19 | .setThumbnail("https://i.imgur.com/bSOBK4s.png") 20 | .setColor("RANDOM"); 21 | return msg.sendEmbed(embed); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/General/Chat Bot Info/info.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | aliases: ["details", "what"], 9 | guarded: true, 10 | requiredPermissions: ["EMBED_LINKS"], 11 | description: language => language.get("COMMAND_INFO_DESCRIPTION") 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const embed = new MessageEmbed() 17 | .setDescription(msg.language.get("COMMAND_INFO")) 18 | .setAuthor("PenguBot - Information", this.client.user.displayAvatarURL(), "https://www.pengubot.com") 19 | .setColor("RANDOM"); 20 | return msg.sendEmbed(embed); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/General/Chat Bot Info/nodeinfo.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | requiredPermissions: [], 8 | aliases: ["nodesinfo"], 9 | cooldown: 5, 10 | description: "", 11 | extendedHelp: "No extended help available." 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const embed = new MessageEmbed() 17 | .setAuthor("PenguBot's Music Nodes Information", this.client.user.displayAvatarURL(), "https://www.pengubot.com") 18 | .setTimestamp() 19 | .setFooter("© PenguBot.com"); 20 | for (const node of this.client.lavalink.nodes.values()) { 21 | embed.addField(node.id, `**Players:** ${node.stats.playingPlayers} / ${node.stats.players} 22 | **Memory:** ${(node.stats.memory.used / 1024 / 1024).toFixed(2)} / ${(node.stats.memory.allocated / 1024 / 1024).toFixed(2)} 23 | **CPU:** ${node.stats.cpu.systemLoad.toFixed(2) * 100}%`, true); 24 | } 25 | return msg.sendEmbed(embed); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/commands/General/Chat Bot Info/support.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | guarded: true, 8 | requiredPermissions: ["EMBED_LINKS"], 9 | description: language => language.get("COMMAND_SUPPORT_DESCRIPTION") 10 | }); 11 | } 12 | 13 | async run(msg) { 14 | return msg.send(msg.language.get("COMMAND_SUPPORT")); 15 | } 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /src/commands/General/Chat Bot Info/upvote.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | guarded: true, 9 | requiredPermissions: ["EMBED_LINKS", "ATTACH_FILES"], 10 | description: language => language.get("COMMAND_UPVOTE_DESCRIPTION") 11 | }); 12 | } 13 | 14 | async run(msg) { 15 | const embed = new MessageEmbed() 16 | .setDescription(msg.language.get("COMMAND_UPVOTE")) 17 | .setAuthor("PenguBot - Upvote", this.client.user.displayAvatarURL(), "https://top.gg/bot/PenguBot/vote") 18 | .setThumbnail("https://i.imgur.com/YxmvOHj.png") 19 | .setColor("RANDOM"); 20 | return msg.sendEmbed(embed); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Images/cat.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["cats", "catfact"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_CAT_DESCRIPTION"), 11 | extendedHelp: "No extended help available." 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const { fact } = await this.fetchURL("https://catfact.ninja/fact"); 17 | if (!fact) throw msg.language.get("ERR_TRY_AGAIN"); 18 | 19 | return msg.sendEmbed(new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setColor("RANDOM") 23 | .setDescription(`**Cat Image & Fact**\n${fact}`) 24 | .setImage(`http://thecatapi.com/api/images/get?format=src&type=jpg&size=med&${Date.now()}`)); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/cookie.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | const cookies = ["http://i.imgur.com/SLwEY66.gif", "http://i.imgur.com/K6VoNp3.gif", "http://i.imgur.com/knVM6Lb.gif", 4 | "http://i.imgur.com/P1BMly5.gif", "http://i.imgur.com/I8CrTUT.gif", "https://i.imgur.com/0XTueQR.png", 5 | "https://i.imgur.com/u9k8x4J.png", "https://i.imgur.com/AUtfHnK.png", "https://i.imgur.com/XjTbrKc.png", 6 | "https://i.imgur.com/A3mgqEh.png", "https://i.imgur.com/YnkdGZd.png", "https://i.imgur.com/FJsOnOE.png", 7 | "https://i.imgur.com/RQFPwDg.png", "https://i.imgur.com/vyCTGr0.png", "https://i.imgur.com/kkXToc8.png", 8 | "https://i.imgur.com/ctHwqVL.png", "https://i.imgur.com/yUaCPvC.png", "https://i.imgur.com/IUM6Z8F.png" 9 | ]; 10 | 11 | module.exports = class extends Command { 12 | 13 | constructor(...args) { 14 | super(...args, { 15 | cooldown: 8, 16 | aliases: ["sendcookie"], 17 | description: language => language.get("COMMAND_COOKIE_DESCRIPTION"), 18 | extendedHelp: "No extended help available.", 19 | usage: "" 20 | }); 21 | } 22 | 23 | async run(msg, [user]) { 24 | const embed = new MessageEmbed() 25 | .setFooter("© PenguBot.com") 26 | .setTimestamp() 27 | .setImage(cookies[Math.floor(Math.random() * cookies.length)]) 28 | .setColor("RANDOM"); 29 | return msg.sendMessage(`***<@${user.id}>, ${msg.language.get("CMD_FUN_COOKIE")} ${msg.author}!***`, { embed: embed }); 30 | } 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /src/commands/Images/cuddle.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendcuddle"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_CUDDLE_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/cuddle"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | return msg.sendMessage(`🤗 | ***${user}, ${msg.language.get("CMD_FUN_CUDDLE")} ${msg.author}!***`, { embed }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/dog.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["doggos", "dogpic"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_DOG_DESCRIPTION"), 11 | extendedHelp: "No extended help available." 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const data = await this.fetchURL("http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=false"); 17 | if (!data || !data.length) throw msg.language.get("ERR_TRY_AGAIN"); 18 | 19 | return msg.sendEmbed(new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setColor("RANDOM") 23 | .setDescription(`**Dog Picture**`) 24 | .setImage(data[0])); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/feed.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendfood"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_FEED_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/feed"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | return msg.sendMessage(`🥘 | ***${user}, ${msg.language.get("CMD_FUN_FED")} ${msg.author}!***`, { embed }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/fox.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["foxy", "foxes"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_FOX_DESCRIPTION"), 11 | extendedHelp: "No extended help available." 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const { image } = await this.fetchURL("https://randomfox.ca/floof/"); 17 | if (!image) throw msg.language.get("ERR_TRY_AGAIN"); 18 | 19 | return msg.sendEmbed(new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setColor("RANDOM") 23 | .setDescription(`**Fox Picture**`) 24 | .setImage(image)); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/hug.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendhug"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_HUG_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/hug"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | return msg.sendMessage(`🤗 | ***${user}, ${msg.language.get("CMD_FUN_HUG")} ${msg.author}!***`, { embed }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/kiss.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendkiss"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_KISS_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/kiss"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | 20 | const embed = new MessageEmbed() 21 | .setFooter("© PenguBot.com") 22 | .setTimestamp() 23 | .setImage(url) 24 | .setColor("RANDOM"); 25 | return msg.sendMessage(`💋 | ***${user}, ${msg.language.get("CMD_FUN_KISS")} ${msg.author}!***`, { embed }); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/commands/Images/meme.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | const subReddits = ["AdviceAnimals", "MemeEconomy", "ComedyCemetery", "memes", "dankmemes", "PrequelMemes", "terriblefacebookmemes", "PewdiepieSubmissions", "funny", "wholesomememes", "fffffffuuuuuuuuuuuu", "BikiniBottomTwitter", "2meirl4meirl", "DeepFriedMemes", "surrealmemes", "firstworldanarchists"]; 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 5, 9 | aliases: ["memes", "randommeme"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_MEME_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | const subReddit = subReddits[Math.floor(Math.random() * subReddits.length)]; 18 | const data = await this.client.funcs.scrapeSubreddit(subReddit, { type: "hot" }); 19 | 20 | if (data.over_18 && !msg.channel.nsfw) return msg.sendMessage(`${this.client.emotes.cross} ***This channel is not NSFW so I can't send it here...***`); 21 | return msg.channel.send(data.url); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Images/pat.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendpat"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_PAT_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/pat"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | 25 | return msg.sendMessage(`✋ | ***${user}, ${msg.language.get("CMD_FUN_PAT")} ${msg.author}!***`, { embed }); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/commands/Images/pengu.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | const pics = ["http://i.imgur.com/Urfp335.png", 5 | "http://i.imgur.com/gC8v9fp.jpg", "http://i.imgur.com/DZ6YtvT.jpg", "http://i.imgur.com/LdWARAL.jpg", 6 | "http://i.imgur.com/7uF0u9Q.jpg", "http://i.imgur.com/0vgVnpr.png", "http://i.imgur.com/1GKlyH2.png", 7 | "http://i.imgur.com/jlzSELQ.png", "https://i.imgur.com/Vm98hJq.png", "https://i.imgur.com/RF4JeC8.png", 8 | "https://i.imgur.com/Co26qmr.png", "https://i.imgur.com/ixSGy7V.jpg", "https://i.imgur.com/WzsIIzN.png", 9 | "https://i.imgur.com/v8oxfHW.jpg", "https://i.imgur.com/RPxPRXV.png", "https://i.imgur.com/UVnwRMk.gif", 10 | "https://i.imgur.com/vfKwurE.gif", "https://i.imgur.com/XKukgBG.gif", "https://i.imgur.com/KohkQvr.gif", 11 | "https://i.imgur.com/uwdMmng.gif", "https://i.imgur.com/EOln62Q.gif", "https://i.imgur.com/8fcKsh1.gif" 12 | ]; 13 | 14 | module.exports = class extends Command { 15 | 16 | constructor(...args) { 17 | super(...args, { 18 | cooldown: 8, 19 | aliases: ["pingu", "penguin"], 20 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 21 | description: language => language.get("COMMAND_PENGU_DESCRIPTION"), 22 | extendedHelp: "No extended help available." 23 | }); 24 | } 25 | 26 | async run(msg) { 27 | const embed = new MessageEmbed() 28 | .setFooter("© PenguBot.com") 29 | .setTimestamp() 30 | .setImage(pics[Math.floor(Math.random() * pics.length)]) 31 | .setColor("RANDOM"); 32 | return msg.sendMessage(`<:pengu:383632112323919872> | ***${msg.author}, ${msg.language.get("CMD_FUN_PENGU")}!***`, { embed: embed }); 33 | } 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/commands/Images/poke.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendpoke"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_POKE_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/poke"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | 20 | const embed = new MessageEmbed() 21 | .setFooter("© PenguBot.com") 22 | .setTimestamp() 23 | .setImage(url) 24 | .setColor("RANDOM"); 25 | return msg.sendMessage(`👈 | ***${user}, ${msg.language.get("CMD_FUN_POKE")} ${msg.author}!***`, { embed }); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/commands/Images/punch.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | const punches = ["http://i.imgur.com/aGPHQ3E.gif", "http://i.imgur.com/FxFfdOZ.gif", "http://i.imgur.com/XA7PPiy.gif", 5 | "http://i.imgur.com/5hcVtGf.gif", "http://i.imgur.com/nwGsg12.gif", "http://i.imgur.com/GZX1COH.gif", 6 | "https://i.imgur.com/UcycckQ.gif", "https://i.imgur.com/VmdBxgq.gif", "https://i.imgur.com/IputsOi.gif", 7 | "https://i.imgur.com/UY3sTpj.gif", "https://i.imgur.com/VdwTwRo.gif", "https://i.imgur.com/VIKEo7q.gif", 8 | "https://i.imgur.com/XPq1P4F.gif", "https://i.imgur.com/X0uIstL.gif", "https://i.imgur.com/Of2BTLu.gif", 9 | "https://i.imgur.com/tSjlgKs.gif", "https://i.imgur.com/hEDcADi.gif" 10 | ]; 11 | 12 | module.exports = class extends Command { 13 | 14 | constructor(...args) { 15 | super(...args, { 16 | cooldown: 8, 17 | aliases: ["sendpunch"], 18 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 19 | description: language => language.get("COMMAND_PUNCH_DESCRIPTION"), 20 | extendedHelp: "No extended help available.", 21 | usage: "" 22 | }); 23 | } 24 | 25 | async run(msg, [user]) { 26 | const embed = new MessageEmbed() 27 | .setFooter("© PenguBot.com") 28 | .setTimestamp() 29 | .setImage(punches[Math.floor(Math.random() * punches.length)]) 30 | .setColor("RANDOM"); 31 | return msg.sendMessage(`👊 | ***${user}, ${msg.language.get("CMD_FUN_PUNCH")} ${msg.author}!***`, { embed: embed }); 32 | } 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/Images/randomcomic.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | const { parse } = require("node-html-parser"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 8, 9 | aliases: ["comic", "comics"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_COMIC_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | const res = await this.fetchURL(`https://c.xkcd.com/random/comic/`, { type: "text" }) 18 | .catch(() => null); 19 | if (!res) throw `${this.client.emotes.cross} ***${msg.language.get("ER_CATS_DOGS")}***`; 20 | 21 | const root = parse(res); 22 | const img = root.querySelector("#comic").querySelector("img").getAttribute("src"); 23 | console.log(img); 24 | 25 | return msg.sendEmbed(new MessageEmbed() 26 | .setFooter("© PenguBot.com - Comic by xkcd.com") 27 | .setTimestamp() 28 | .setColor("RANDOM") 29 | .setImage(`https:${img}`)); 30 | } 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /src/commands/Images/slap.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendslap"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_SLAP_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/slap"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | return msg.sendMessage(`🖐 | ***${user}, ${msg.language.get("CMD_FUN_SLAP")} ${msg.author}!***`, { embed }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/tickle.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["sendtickle"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_TICKLE_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const { url } = await this.fetchURL("https://nekos.life/api/v2/img/tickle"); 18 | if (!url) throw msg.language.get("ERR_TRY_AGAIN"); 19 | const embed = new MessageEmbed() 20 | .setFooter("© PenguBot.com") 21 | .setTimestamp() 22 | .setImage(url) 23 | .setColor("RANDOM"); 24 | return msg.sendMessage(`🤣 | ***${user}, ${msg.language.get("CMD_FUN_TICKLE")} ${msg.author}!***`, { embed }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Images/wholesome.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | const SUB_REDDITS = ["wholesome", "aww", "AnimalsBeingBros"]; 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 10, 9 | bucket: 2, 10 | aliases: ["wholesome", "aww"], 11 | requiredPermissions: ["EMBED_LINKS"], 12 | description: language => language.get("COMMAND_WHOLESOME_DESCRIPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const subReddit = SUB_REDDITS[Math.floor(Math.random() * SUB_REDDITS.length)]; 19 | const data = await this.client.funcs.scrapeSubreddit(subReddit, { type: "top" }); 20 | 21 | return msg.channel.send(data.url); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/chucknorris.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_CHUCK_DESCRIPTION"), 10 | extendedHelp: "No extended help available." 11 | }); 12 | } 13 | 14 | async run(msg) { 15 | const { value } = await this.fetchURL("http://api.chucknorris.io/jokes/random"); 16 | 17 | return msg.sendEmbed(new MessageEmbed() 18 | .setColor("RANDOM") 19 | .setDescription(`**Chuck Norris Joke**\n\n${value}`) 20 | .setThumbnail("https://i.imgur.com/3wIvF42.png")); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/dadjoke.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["joke"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_DADJOKE_DESCRIPTION"), 11 | extendedHelp: "No extended help available." 12 | }); 13 | } 14 | 15 | async run(msg) { 16 | const { joke } = await this.fetchURL("https://icanhazdadjoke.com/", { headers: { Accept: "application/json" } }); 17 | 18 | return msg.sendEmbed(new MessageEmbed() 19 | .setDescription(`**Dad Joke Alert**\n\n${joke.length < 1900 ? joke : `${joke.substring(0, 1900)}...`}`) 20 | .setThumbnail("https://i.imgur.com/IxosIBh.png") 21 | .setColor("RANDOM")); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/dice.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["die", "roll"], 9 | description: language => language.get("COMMAND_DICE_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "[sides:integer]" 12 | }); 13 | } 14 | 15 | async run(msg, [sides = 6]) { 16 | const num = Math.floor(Math.random() * sides) + 1; 17 | return msg.reply(`I rolled you a 🎲 of **${sides}** side(s) and got **${num}** as the outcome.`); 18 | } 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/fml.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | const { parse } = require("node-html-parser"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 8, 9 | aliases: ["fuckmylife"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_FML_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | const res = await this.fetchURL("http://www.fmylife.com/random", { type: "text" }) 18 | .catch(() => null); 19 | if (!res) throw `${this.client.emotes.cross} ***${msg.language.get("ER_CATS_DOGS")}***`; 20 | 21 | const root = parse(res); 22 | const article = root.querySelector(".article-link").text; 23 | 24 | return msg.sendEmbed(new MessageEmbed() 25 | .setDescription(`**F*ck My Life**\n${article}`) 26 | .setThumbnail("https://i.imgur.com/XW16vXq.png") 27 | .setColor("RANDOM")); 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/randomfact.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | const facts = require("../../lib/constants/facts.json"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 8, 9 | aliases: ["fact", "rfact"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_FACT_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | return msg.sendEmbed(new MessageEmbed() 18 | .setDescription(`**Random Fact**\n\n${facts[Math.floor(Math.random() * facts.length)]}`) 19 | .setThumbnail("https://i.imgur.com/fJiD9Jo.png") 20 | .setColor("RANDOM")); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/trump.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["trumpjoke", "trumpinsult"], 9 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_TRUMP_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const data = await this.fetchURL(`https://api.whatdoestrumpthink.com/api/v1/quotes/personalized`, { query: { q: user.username } }); 18 | if (!data.message) throw msg.language.get("ER_TRY_AGAIN"); 19 | 20 | return msg.sendEmbed(new MessageEmbed() 21 | .setDescription(`**Get Trumped**\n\n${data.message}`) 22 | .setThumbnail("https://i.imgur.com/lGJbGy6.png") 23 | .setColor("RANDOM")); 24 | } 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /src/commands/Jokes and Stuff/yomomma.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | const data = require("../../lib/constants/yomomma"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | cooldown: 8, 9 | aliases: ["yomoma", "yomommafat", "yomommasofat"], 10 | requiredPermissions: ["ATTACH_FILES", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_MOMMA_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | const joke = data[Math.floor(Math.random() * data.length)]; 18 | return msg.sendEmbed(new MessageEmbed() 19 | .setDescription(`**Yo Momma Joke**\n\n${joke}`) 20 | .setThumbnail("https://i.imgur.com/ordRh9e.png") 21 | .setColor("RANDOM")); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Management/Automod/toggleinvites.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["adblock", "antiinvites"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_ADBLOCK_DESCRIPTION"), 13 | quotedStringSupport: false, 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg) { 19 | const toggle = !msg.guild.settings.get("automod.invites"); 20 | await msg.guild.settings.update("automod.invites", toggle); 21 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ***Anti-invites have been ${toggle ? "Enabled" : "Disabled"}***`); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Management/Autoroles/addautoroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["addautorole", "removeautorole", "removeautoroles", "deleteautorole", "deleteautoroles"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "", 13 | description: language => language.get("COMMAND_ADD_ROLES_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [role]) { 19 | if (msg.guild.settings.get("roles.autorole").indexOf(role.id) !== -1) { 20 | return msg.guild.settings.update("roles.autorole", role, msg.guild).then(() => { 21 | msg.sendMessage(`${this.client.emotes.cross} ***${role.name} ${msg.language.get("MESSAGE_AUTOROLE_REMOVED")}***`); 22 | }); 23 | } else { 24 | return msg.guild.settings.update("roles.autorole", role, msg.guild).then(() => { 25 | msg.sendMessage(`${this.client.emotes.check} ***${role.name} ${msg.language.get("MESSAGE_AUTOROLE_ADDED")}***`); 26 | }); 27 | } 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/commands/Management/Autoroles/toggleautoroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["toggleautorole", "enableautoroles", "disableautoroles"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_ROLES_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const toggle = !msg.guild.settings.get("toggles.autoroles"); 19 | await msg.guild.settings.update("toggles.autoroles", toggle); 20 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ***${toggle ? msg.language.get("MESSAGE_AUTOROLES_ENABLED") : msg.language.get("MESSAGE_AUTOROLES_DISABLED")}`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Management/Custom Commands/createcmd.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["addcmd"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_ADD_CMD_DESCRIPTION"), 13 | usage: " [...]", 14 | usageDelim: " ", 15 | extendedHelp: "More Information can be Found Here: https://bit.ly/PenguCustomCommands" 16 | }); 17 | } 18 | 19 | async run(msg, [name, ...content]) { 20 | name = name.toLowerCase(); 21 | if (this.client.commands.has(name)) return msg.reply(`${this.client.emotes.cross} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_EXISTS")}***`); 22 | const cmd = msg.guild.settings.get("customcmds").find(c => c.name.toLowerCase() === name); 23 | if (cmd) return msg.reply(`${this.client.emotes.cross} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_EXISTS")}***`); 24 | await msg.guild.settings.update("customcmds", { content: content.join(" "), name: name }); 25 | return msg.sendMessage(`${this.client.emotes.check} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_ADDED")} ${msg.author.tag}!***`); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/commands/Management/Custom Commands/deletecmd.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["delcmd", "removecmd"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_DEL_CMD_DESCRIPTION"), 13 | usage: "", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [name]) { 19 | name = name.toLowerCase(); 20 | const cmd = msg.guild.settings.get("customcmds").find(c => c.name.toLowerCase() === name); 21 | if (!cmd) return msg.reply(`${this.client.emotes.cross} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_NOTFOUND")}***`); 22 | await msg.guild.settings.update("customcmds", cmd, { action: `remove` }); 23 | return msg.sendMessage(`${this.client.emotes.check} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_REMOVED")} ${msg.author.tag}!***`); 24 | } 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /src/commands/Management/Custom Commands/listcmds.js: -------------------------------------------------------------------------------- 1 | const { Command, RichDisplay, MessageEmbed } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["listcommands"], 10 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_LIST_CMDS_DESCRIPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | if (!msg.guild.settings.get("customcmds").length) return msg.reply(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_NO_CMDS")}***`); 18 | const prefix = msg.guild.settings.get("prefix"); 19 | const names = msg.guild.settings.get("customcmds").map(cmd => cmd.name.toLowerCase()); 20 | 21 | const cmds = new RichDisplay(new MessageEmbed() 22 | .setTitle("Use the reactions to change pages, select a page or stop viewing the commands.") 23 | .setAuthor("Custom Commands - PenguBot", "https://i.imgur.com/DOuCQlY.png") 24 | .setDescription("Scroll between pages to see the custom commands list.") 25 | .setColor("#F75F4E") 26 | ); 27 | 28 | for (let i = 0, temp = names.length; i < temp; i += 5) { 29 | const curr = names.slice(i, i + 5); 30 | cmds.addPage(t => t.setDescription(curr.map(c => `• ${prefix}${c}`))); 31 | } 32 | 33 | cmds.run(await msg.sendMessage(`${this.client.emotes.loading} Loading Commands...`), { 34 | time: 120000, 35 | filter: (reaction, user) => user === msg.author 36 | }); 37 | } 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /src/commands/Management/Custom Commands/togglecustomcmds.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["tccmd", "togglecustom", "tcmd", "togglecustomcommands"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_CUSTOM_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const toggle = !msg.guild.settings.get("toggles.customcmds"); 19 | await msg.guild.settings.update("toggles.customcmds", toggle); 20 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ***${toggle ? msg.language.get("MESSAGE_COMMAND_CUSTOM_ENABLED") : msg.language.get("MESSAGE_COMMAND_CUSTOM_DISABLED")}***`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Management/Custom Commands/updatecmd.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["changecmd"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_ADD_CMD_DESCRIPTION"), 13 | usage: " [...]", 14 | usageDelim: " ", 15 | extendedHelp: "More Information can be Found Here: https://bit.ly/PenguCustomCommands" 16 | }); 17 | } 18 | 19 | async run(msg, [name, ...content]) { 20 | name = name.toLowerCase(); 21 | if (this.client.commands.has(name)) return msg.reply(`${this.client.emotes.cross} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_EXISTS")}***`); 22 | const cmd = msg.guild.settings.get("customcmds").find(c => c.name.toLowerCase() === name); 23 | if (cmd) { 24 | const remove = await msg.guild.settings.update("customcmds", cmd, { action: "remove" }); 25 | const add = await msg.guild.settings.update("customcmds", { content: content.join(" "), name: cmd.name }, { action: "add" }); 26 | if (add.errors || remove.errors) return msg.sendMessage(`${this.client.emotes.cross} ***There was an error, try again.***`); 27 | return msg.sendMessage(`${this.client.emotes.check} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_UPDATED")} ${msg.author.tag}!***`); 28 | } else { 29 | return msg.reply(`${this.client.emotes.cross} ***\`${name}\` ${msg.language.get("MESSAGE_CMD_NOTFOUND")}***`); 30 | } 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/commands/Management/Level Roles/listlevelroles.js: -------------------------------------------------------------------------------- 1 | const { Command, RichDisplay, MessageEmbed } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["levelroles"], 10 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 11 | description: language => language.get("COMMAND_LIST_LVLROLES_DESCRPTION"), 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg) { 17 | const roles = msg.guild.settings.get("roles.levelrole"); 18 | if (!roles.length) return msg.sendMessage(`${this.client.emotes.cross} ***${msg.language.get("CMD_NO_SELFROLES")}***`); 19 | const pages = new RichDisplay(new MessageEmbed() 20 | .setTitle("Use the reactions to change pages, select a page, or stop viewing the roles") 21 | .setAuthor("Level Based Roles - PenguBot", msg.guild.iconURL()) 22 | .setDescription("Scroll between pages to see the self assignable roles.") 23 | .setColor("#428bca") 24 | ); 25 | pages.addPage(t => t.setDescription(roles.map(role => `\`-\` ${msg.guild.roles.cache.get(role.id) || "Role Removed"} - Level ${role.lvl}`).join("\n"))); 26 | 27 | pages.run(await msg.sendMessage(`${this.client.emotes.loading} ***Loading Roles...***`), { 28 | time: 120000, 29 | filter: (reaction, user) => user === msg.author 30 | }); 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/commands/Management/Level Roles/managelevelroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | subcommands: true, 8 | runIn: ["text"], 9 | cooldown: 10, 10 | aliases: ["managelevelrole", "addlevelrole", "removelevelrole"], 11 | permissionLevel: 6, 12 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 13 | description: language => language.get("COMMAND_LVLROLE_DESCRPTION"), 14 | usage: " [level:integer]", 15 | usageDelim: " " 16 | }); 17 | } 18 | 19 | async add(msg, [role, level]) { 20 | if (!level) throw `${this.client.emotes.cross} ***You must enter a level at which you want to award this role.***`; 21 | if (level <= 0) throw `${this.client.emotes.cross} ***You can't give people levels if they are level ZERO or Lower, use Autoroles instead.***`; 22 | const roles = msg.guild.settings.get("roles.levelrole"); 23 | if (roles.find(r => r.id === role.id)) throw `${this.client.emotes.cross} ***This role already exists in the leveled roles.***`; 24 | 25 | const myRole = msg.guild.me.roles.highest; 26 | if (role.position > myRole.positon) throw `${this.client.emotes.cross} ***That given role is above my role in the guild, please change the order.***`; 27 | 28 | await msg.guild.settings.update("roles.levelrole", { id: role.id, lvl: level }); 29 | return msg.sendMessage(`${this.client.emotes.check} **${role.name}** Role has been added for anyone who reaches **Level ${level}** in **${msg.guild.name}**`); 30 | } 31 | 32 | async remove(msg, [role]) { 33 | const levelRole = msg.guild.settings.get("roles.levelrole").find(r => r.id === role.id); 34 | if (!levelRole) throw `${this.client.emotes.cross} ***That role doesn't exist in the Level Based Roles list.***`; 35 | await msg.guild.settings.update("roles.levelrole", levelRole, { action: "remove" }); 36 | return msg.sendMessage(`${this.client.emotes.check} **${role.name}** Role has been removed from Level Based Roles list.`); 37 | } 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /src/commands/Management/Level Roles/togglelevelroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["togglelevelrole", "enablelevelroles", "disablelevelroles"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_LVLROLES_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const toggle = !msg.guild.settings.get("toggles.levelroles"); 19 | await msg.guild.settings.update("toggles.levelroles", toggle); 20 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ${toggle ? msg.language.get("MESSAGE_LEVELROLES_ENABLED") : msg.language.get("MESSAGE_LEVELROLES_DISABLED")}`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Management/Logging/loggingchannel.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["setloggingchannel", "setlogchannel"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "[Channel:channelname]", 13 | description: language => language.get("COMMAND_LOGCHAN_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [Channel = msg.channel]) { 19 | return msg.guild.settings.update("channels.logs", Channel.id).then(() => { 20 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_LOGCHAN_SET")}***`); 21 | }); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Management/Logging/modlogs.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["modlog", "managemodlogs"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: " [Channel:channelname]", 13 | usageDelim: " ", 14 | description: language => language.get("COMMAND_MODLOG_DESCRPTION"), 15 | extendedHelp: "No extended help available.", 16 | subcommands: true 17 | }); 18 | } 19 | 20 | async channel(msg, [Channel = msg.channel]) { 21 | const { errors } = await msg.guild.settings.update("channels.modlogs", Channel.id); 22 | if (errors) return msg.reply(`${this.client.emotes.cross} ***There was an error: ${errors[0]}***`); 23 | return msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_LOGCHAN_SET")}***`); 24 | } 25 | 26 | async toggle(msg) { 27 | const { errors } = await msg.guild.settings.update("toggles.modlogs", !msg.guild.settings.get("toggles.modlogs")); 28 | if (errors) return msg.reply(`${this.client.emotes.cross} ***There was an error: ${errors[0]}***`); 29 | return msg.reply(`${this.client.emotes.check} ***Mod logs have been ${msg.guild.settings.get("toggles.modlogs") ? "Enabled" : "Disabled"}.***`); 30 | } 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /src/commands/Management/Self Roles/manageselfroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | requiredPermissions: ["SEND_MESSAGES", "EMBED_LINKS", "USE_EXTERNAL_EMOJIS", "MANAGE_ROLES"], 9 | aliases: ["addselfrole", "addselfroles", "removeselfrole", "removeselfroles"], 10 | cooldown: 5, 11 | permissionLevel: 6, 12 | description: language => language.get("COMMAND_SELFROLES_MANAGE"), 13 | extendedHelp: "No extended help available.", 14 | usage: "" 15 | }); 16 | } 17 | 18 | async run(msg, [role]) { 19 | const roles = msg.guild.settings.get("roles.selfrole"); 20 | if (!roles) return msg.sendMessage(`${this.client.emotes.cross} ***${msg.language.get("CMD_NO_SELFROLES")}***`); 21 | if (!roles.includes(role.id)) { 22 | await msg.guild.settings.update("roles.selfrole", role, msg.guild); 23 | return msg.sendMessage(`${this.client.emotes.check} ***\`${role.name}\` ${msg.language.get("CMD_SELF_ASSIGNABLE")}***`); 24 | } else { 25 | await msg.guild.settings.update("roles.selfrole", role, msg.guild); 26 | return msg.sendMessage(`${this.client.emotes.cross} ***\`${role.name}\` ${msg.language.get("CMD_NO_ASSIGNABLE")}***`); 27 | } 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/commands/Management/Self Roles/toggleselfroles.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["toggleselfrole", "enableselfroles", "disableselfroles"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_SELFROLES"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const toggle = !msg.guild.settings.get("toggles.selfroles"); 19 | await msg.guild.settings.update("toggles.selfroles", toggle); 20 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ${toggle ? msg.language.get("MESSAGE_AUTOROLES_ENABLED") : msg.language.get("MESSAGE_AUTOROLES_DISABLED")}`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Management/Starboard/starboardchannel.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["ssc", "setstarboardchannel"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "[channel:channelname]", 13 | usageDelim: "", 14 | description: language => language.get("COMMAND_CHANNEL_STAR_DESCRPTION"), 15 | extendedHelp: "No extended help available." 16 | }); 17 | } 18 | 19 | async run(msg, [channel = msg.channel]) { 20 | return msg.guild.settings.update("starboard.channel", channel.id).then(() => { 21 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_STAR_CHANNEL_SET")}***`); 22 | }); 23 | } 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/commands/Management/Starboard/starsrequired.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["setstars", "setminimumstars"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "", 13 | description: language => language.get("COMMAND_REQUIRED_STAR_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [Stars]) { 19 | if (Stars < 1) return msg.sendMessage(`***${this.client.emotes.cross} Required Stars for Starboard can't be less than 1***`); 20 | return msg.guild.settings.update("starboard.required", Stars).then(() => { 21 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_STARS_REQUIRED_SET")}***`); 22 | }); 23 | } 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/commands/Management/Starboard/togglestarboard.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["tsb", "togglestarboards"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_STARBOARD_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | const toggle = !msg.guild.settings.get("toggles.starboard"); 19 | await msg.guild.settings.update("toggles.starboard", toggle); 20 | return msg.sendMessage(`${toggle ? this.client.emotes.check : this.client.emotes.cross} ${toggle ? msg.language.get("MESSAGE_STAR_ENABLED") : msg.language.get("MESSAGE_STAR_DISABLED")}`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/setleavechannel.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["slc", "setleavechan"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "[channel:channelname]", 13 | description: language => language.get("COMMAND_CHANNEL_LEAVE_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [channel = msg.channel]) { 19 | return this.dbQuery(msg, channel).then(() => { 20 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_LEAVE_CHANNEL_SET")}***`); 21 | }); 22 | } 23 | 24 | async dbQuery(msg, channel) { 25 | const r = this.client.providers.default.db; 26 | const query = await r.table("guilds").get(msg.guild.id) 27 | .update({ channels: { leave: channel.id } }) 28 | .run() 29 | .catch(e => { 30 | console.error(`${this.name} error:\n${e}`); 31 | throw `There was an error, please contact us on our support server: \n${e}`; 32 | }); 33 | 34 | await msg.guild.settings.sync(true); 35 | return query; 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/setleavemsg.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["slm", "setleavemessage"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "", 13 | description: language => language.get("COMMAND_SET_LEAVE_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [message]) { 19 | return msg.guild.settings.update("messages.leave", message).then(() => { 20 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_LEAVE_SET")}***`); 21 | }); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/setwelcomechannel.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["swc", "setwelcomechan"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "[channel:channelname]", 13 | description: language => language.get("COMMAND_CHANNEL_WELCOME_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [channel = msg.channel]) { 19 | return this.dbQuery(msg, channel).then(() => { 20 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_WELCOME_CHANNEL_SET")}***`); 21 | }); 22 | } 23 | 24 | async dbQuery(msg, channel) { 25 | const r = this.client.providers.default.db; 26 | const query = await r.table("guilds").get(msg.guild.id) 27 | .update({ channels: { join: channel.id } }) 28 | .run() 29 | .catch(e => { 30 | console.error(`${this.name} error:\n${e}`); 31 | throw `There was an error, please contact us on our support server: \n${e}`; 32 | }); 33 | 34 | await msg.guild.settings.sync(true); 35 | return query; 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/setwelcomemsg.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["swm", "setwelcomemmessage"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | usage: "", 13 | description: language => language.get("COMMAND_SET_WELCOME_DESCRPTION"), 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [message]) { 19 | return msg.guild.settings.update("messages.join", message).then(() => { 20 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_WELCOME_SET")}***`); 21 | }); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/toggleleave.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["tlm", "toggleleavemessages"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_LEAVE_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | if (!msg.guild.settings.get("toggles.leavemsg")) { 19 | if (!msg.guild.channels.cache.get(msg.guild.settings.get("channels.leave"))) { await msg.guild.settings.update("channels.leave", msg.channel.id); } 20 | if (!msg.guild.settings.get("messages.leave")) await msg.guild.settings.update("messages.leave", "It's sad to see you leaving **{USERNAME}**!", { action: "add" }); 21 | return msg.guild.settings.update("toggles.leavemsg", true).then(() => { 22 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_LEAVE_ENABLED")}***`); 23 | }); 24 | } else { 25 | return msg.guild.settings.update("toggles.leavemsg", false).then(() => { 26 | msg.sendMessage(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_LEAVE_DISABLED")}***`); 27 | }); 28 | } 29 | } 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /src/commands/Management/Welcome & Leave/togglewelcome.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["twm", "togglewelcomemessages"], 10 | permissionLevel: 6, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TOGGLE_WELCOME_DESCRPTION"), 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg) { 18 | if (!msg.guild.settings.get("toggles.joinmsg")) { 19 | if (!msg.guild.channels.cache.get(msg.guild.settings.get("channels.join"))) { await msg.guild.settings.update("channels.join", msg.channel.id); } 20 | if (!msg.guild.settings.get("messages.join")) await msg.guild.settings.update("messages.join", "Welcome {MENTION} to {SERVER}, we hope you enjoy your stay!", { action: "add" }); 21 | return msg.guild.settings.update("toggles.joinmsg", true).then(() => { 22 | msg.sendMessage(`${this.client.emotes.check} ***${msg.language.get("MESSAGE_WLCM_ENABLED")}***`); 23 | }); 24 | } else { 25 | return msg.guild.settings.update("toggles.joinmsg", false).then(() => { 26 | msg.sendMessage(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_WLCM_DISABLED")}***`); 27 | }); 28 | } 29 | } 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /src/commands/Manipulation/achievement.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["mca", "makeachievement", "achievementget"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_MCA_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [achievement]) { 17 | const image = await this.client.funcs.images("generate/achievement", { avatar: msg.author.displayAvatarURL({ format: "png", size: 128 }), text: achievement }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/approved.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_APPROVED_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "[approvewho:username]" 12 | }); 13 | } 14 | 15 | async run(msg, [approvewho = msg.author]) { 16 | const image = await this.client.funcs.images("overlay/approved", { avatar: approvewho.displayAvatarURL({ format: "png", size: 512 }) }) 17 | .catch(() => null); 18 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 19 | return msg.channel.sendFile(image); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Manipulation/batslap.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["slapme"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_BATSLAP_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const image = await this.client.funcs.images("generate/batslap", { slapper: msg.author.displayAvatarURL({ format: "png", size: 128 }), slapped: user.displayAvatarURL({ format: "png", size: 128 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/beautiful.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["beautify"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_BEAUTIFUL_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/beautiful", { avatar: user.displayAvatarURL({ format: "png", size: 128 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/changemymind.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["cmm"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_CMM_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [text]) { 17 | const image = await this.client.funcs.images("generate/changemymind", { text: text, avatar: msg.author.displayAvatarURL({ format: "png", size: 128 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/facepalm.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_FACEPALM_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "[user:username]" 12 | }); 13 | } 14 | 15 | async run(msg, [user = msg.author]) { 16 | const image = await this.client.funcs.images("generate/facepalm", { avatar: user.displayAvatarURL({ format: "png", size: 256 }) }) 17 | .catch(() => null); 18 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 19 | return msg.channel.sendFile(image); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Manipulation/garbage.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["garbagewho"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_GARBAGE_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[garbagewho:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [garbagewho = msg.author]) { 17 | const image = await this.client.funcs.images("generate/garbage", { avatar: garbagewho.displayAvatarURL({ format: "png", size: 256 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/illegal.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["isnowillegal", "trumpillegal"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_ILLEGAL_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [name]) { 17 | const image = await this.client.funcs.images("generate/illegal", { text: name }) 18 | .catch(() => null); 19 | if (!image) return msg.sendMessage(`${this.client.emotes.cross} You got Trumped, couldn't create a new bill! Try something else.`); 20 | 21 | return msg.channel.sendFile(image); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/Manipulation/lio.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["lionme"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_LIO_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/lio", { avatar: user.displayAvatarURL({ format: "png", size: 256 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/missing.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["missingposter"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_MISSING_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/missing", { text: user.username, avatar: user.displayAvatarURL({ format: "png", size: 256 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/rejected.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_REJECT_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "[rejectwho:username]" 12 | }); 13 | } 14 | 15 | async run(msg, [rejectwho = msg.author]) { 16 | const image = await this.client.funcs.images("overlay/rejected", { avatar: rejectwho.displayAvatarURL({ format: "png", size: 512 }) }) 17 | .catch(() => null); 18 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 19 | return msg.channel.sendFile(image); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Manipulation/respect.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["rip"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_RIP_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/respect", { avatar: user.displayAvatarURL({ format: "png", size: 128 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/snap.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["snapchat"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_SNAPCHAT_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [snaptext]) { 17 | const image = await this.client.funcs.images("generate/snpchat", { text: snaptext }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/superpunch.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["megapunch"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_SUPERPUNCH_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "" 13 | }); 14 | } 15 | 16 | async run(msg, [user]) { 17 | const image = await this.client.funcs.images("generate/superpunch", { avatar1: msg.author.displayAvatarURL({ format: "png", size: 128 }), avatar2: user.displayAvatarURL({ format: "png", size: 128 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/tattoo.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["tatted"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_TATTOO_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/tattoo", { avatar: user.displayAvatarURL({ format: "png", size: 512 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/tinder.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_TINDER_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "" 12 | }); 13 | } 14 | 15 | async run(msg, [matchwith]) { 16 | if (matchwith.id === msg.author.id) return msg.reply(msg.language.get("ER_TINDER")); 17 | const image = await this.client.funcs.images("generate/tinder", { avatar1: msg.author.displayAvatarURL({ format: "png", size: 256 }), avatar2: matchwith.displayAvatarURL({ format: "png", size: 256 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/triggered.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["trigger"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_TRIGGERED_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/triggered", { avatar: user.displayAvatarURL({ format: "png", size: 512 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image, "triggered.gif"); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Manipulation/vault.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 9 | description: language => language.get("COMMAND_VAULT_DESCRIPTION"), 10 | extendedHelp: "No extended help available.", 11 | usage: "[user:username]" 12 | }); 13 | } 14 | 15 | async run(msg, [user = msg.author]) { 16 | const image = await this.client.funcs.images("generate/vault", { avatar: user.displayAvatarURL({ format: "png", size: 128 }) }) 17 | .catch(() => null); 18 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 19 | return msg.channel.sendFile(image); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Manipulation/wanted.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 8, 8 | aliases: ["wantedposter"], 9 | requiredPermissions: ["ATTACH_FILES", "USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 10 | description: language => language.get("COMMAND_WANTED_DESCRIPTION"), 11 | extendedHelp: "No extended help available.", 12 | usage: "[user:username]" 13 | }); 14 | } 15 | 16 | async run(msg, [user = msg.author]) { 17 | const image = await this.client.funcs.images("generate/wanted", { avatar: user.displayAvatarURL({ format: "png", size: 512 }) }) 18 | .catch(() => null); 19 | if (!image) return msg.reply(msg.language.get("ER_TRY_AGAIN")); 20 | return msg.channel.sendFile(image); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Moderation/case.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 8 | permissionLevel: 3, 9 | runIn: ["text"], 10 | description: language => language.get("COMMAND_CASE_DESCRIPTION"), 11 | usage: "" 12 | }); 13 | } 14 | 15 | async run(msg, [selected]) { 16 | const log = msg.guild.settings.get("modlogs")[selected]; 17 | if (!log) return msg.send(`${this.client.emotes.cross} ${msg.author}, That case could not be found, please try another ID.`); 18 | 19 | const [user, moderator] = await Promise.all([ 20 | this.client.users.fetch(log.user), 21 | this.client.users.fetch(log.moderator) 22 | ]); 23 | 24 | return msg.sendEmbed(new MessageEmbed() 25 | .setDescription([ 26 | `❯ **User**: ${user.tag} (${user.id})`, 27 | `❯ **Moderator**: ${moderator.tag} (${moderator.id})`, 28 | `❯ **Reason**: ${log.reason || `No Reason Specified. Use \`${msg.guild.settings.get("prefix")}reason ${log.case}\` to claim this log.`}` 29 | ].join("\n")) 30 | .setTimestamp(log.timestamp) 31 | .setFooter("PenguBot.com - Case Date") 32 | .setAuthor(`Case: ${log.case}`, this.client.user.displayAvatarURL()) 33 | .setColor("#52c6ff")); 34 | } 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /src/commands/Moderation/history.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 8 | permissionLevel: 3, 9 | runIn: ["text"], 10 | description: language => language.get("COMMAND_HISTORY_DESCRIPTION"), 11 | usage: "" 12 | }); 13 | } 14 | 15 | async run(msg, [user]) { 16 | const userlogs = msg.guild.settings.get("modlogs").filter(log => log.user === user.id); 17 | if (!userlogs) return msg.send(`${this.client.emotes.cross} ***No history for this user could be found in the mod logs.***`); 18 | const actions = { 19 | ban: 0, 20 | unban: 0, 21 | softban: 0, 22 | kick: 0, 23 | warn: 0, 24 | mute: 0, 25 | unmute: 0 26 | }; 27 | 28 | for (const log of userlogs) actions[log.type]++; 29 | 30 | return msg.sendEmbed(new MessageEmbed() 31 | .setDescription([ 32 | `❯ **User**: ${user.tag} (${user.id})`, 33 | `❯ **Ban**: ${actions.ban}`, 34 | `❯ **Unban**: ${actions.unban}`, 35 | `❯ **Mute**: ${actions.mute}`, 36 | `❯ **Unmute**: ${actions.unmute}`, 37 | `❯ **Warn**: ${actions.warn}`, 38 | `❯ **Kick**: ${actions.kick}` 39 | ].join("\n")) 40 | .setTimestamp() 41 | .setFooter("PenguBot.com") 42 | .setAuthor(`User History`, this.client.user.displayAvatarURL()) 43 | .setColor("#52c6ff")); 44 | } 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /src/commands/Moderation/kick.js: -------------------------------------------------------------------------------- 1 | const { Command, ModLog } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["kickmember"], 10 | permissionLevel: 5, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "KICK_MEMBERS"], 12 | description: language => language.get("COMMAND_KICK_DESCRIPTION"), 13 | quotedStringSupport: false, 14 | usage: " [reason:string] [...]", 15 | usageDelim: " ", 16 | extendedHelp: "No extended help available." 17 | }); 18 | } 19 | 20 | async run(msg, [member, ...reason]) { 21 | reason = reason ? reason.join(" ") : null; 22 | 23 | if (member.id === msg.author.id) return msg.reply(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_KICK_YOURSELF")}***`); 24 | if (member.id === this.client.user.id) return msg.reply(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_KICK_PENGU")}***`); 25 | 26 | if (member.roles.highest.position >= msg.member.roles.highest.position) { 27 | return msg.send(`${this.client.emotes.cross} ***Target member is higher in role hierarchy than you.***`); 28 | } else if (member.kickable === false) { 29 | return msg.send(`${this.client.emotes.cross} ***${msg.language.get("MESSAGE_KICK_CANT")}***`); 30 | } 31 | 32 | await member.kick(reason) 33 | .catch(e => msg.reply(`${this.client.emotes.cross} ***There was an error: ${e}***`)); 34 | 35 | if (msg.guild.settings.get("toggles.modlogs")) { 36 | await new ModLog(msg.guild) 37 | .setType("kick") 38 | .setModerator(msg.author) 39 | .setUser(member.user) 40 | .setReason(reason) 41 | .send(); 42 | } 43 | 44 | 45 | return msg.sendMessage(`${this.client.emotes.check} ***${member.user.tag} ${msg.language.get("MESSAGE_KICKED")}***`); 46 | } 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /src/commands/Moderation/warn.js: -------------------------------------------------------------------------------- 1 | const { Command, ModLog } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | requiredPermissions: ["USE_EXTERNAL_EMOJIS", "EMBED_LINKS"], 8 | permissionLevel: 3, 9 | runIn: ["text"], 10 | description: language => language.get("COMMAND_WARN_DESCRIPTION"), 11 | usage: " [reason:string] [...]", 12 | usageDelim: " " 13 | }); 14 | } 15 | 16 | async run(msg, [member, ...reason]) { 17 | reason = reason ? reason.join(" ") : null; 18 | 19 | if (member.roles.highest.position >= msg.member.roles.highest.position) { 20 | return msg.sendMessage(`${this.client.emotes.cross} ***Target member is higher in role hierarchy than you.***`); 21 | } 22 | 23 | await new ModLog(msg.guild) 24 | .setType("warn") 25 | .setModerator(msg.author) 26 | .setUser(member.user) 27 | .setReason(reason) 28 | .send(); 29 | 30 | await member.user.sendCode("http", [ 31 | `You've been warned in ${msg.guild.name}`, 32 | `Reason : ${reason ? reason : "No Reason Specified"}` 33 | ].join("\n")).catch(() => null); 34 | 35 | return msg.sendMessage(`${this.client.emotes.check} ***This user has been sucessfully warned:*** ${member.user.tag}${reason ? `\n***Reason:*** ${reason}` : ""}`); 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/commands/Profiles/managexp.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | subcommands: true, 8 | runIn: ["text"], 9 | cooldown: 10, 10 | permissionLevel: 6, 11 | aliases: ["setxp", "setexperience", "resetxp", "resetexperience"], 12 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 13 | description: language => language.get("COMMAND_MANAGEXP_DESCRIPTION"), 14 | usage: " [amount:integer]", 15 | usageDelim: " " 16 | }); 17 | } 18 | 19 | async set(msg, [member, amount]) { 20 | if (!amount) throw `${this.client.emotes.cross} ***Amount not specified.***`; 21 | await member.settings.update("xp", amount); 22 | return msg.sendMessage(`${this.client.emotes.check} ***XP Amount Set to \`${amount}\` XP(s) for ${member.user.tag}.***`); 23 | } 24 | 25 | async add(msg, [member, amount]) { 26 | if (!amount) throw `${this.client.emotes.cross} ***Amount not specified.***`; 27 | await member.settings.update("xp", member.settings.get("xp") + amount); 28 | return msg.sendMessage(`${this.client.emotes.check} ***\` ${amount}\` XP(s) Added to ${member.user.tag}.***`); 29 | } 30 | 31 | async reset(msg, [member]) { 32 | await member.settings.reset("xp"); 33 | return msg.sendMessage(`${this.client.emotes.check} ***XP(s) Reset For ${member.user.tag}.***`); 34 | } 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /src/commands/Profiles/title.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | permissionLevel: 0, 10 | aliases: ["settitle"], 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_TITLE_DESCRIPTION"), 13 | usage: "", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [title]) { 19 | if (title.length > 30) { 20 | return msg.reply("Your title can not be more than 30 characters long, please enter a smaller one."); 21 | } 22 | await msg.author.settings.sync(true); 23 | msg.author.settings.update("title", title); 24 | return msg.sendMessage(`${this.client.emotes.check} ***Your profile title has been updated to:*** ${title}`); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Settings/prefix.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | aliases: ["setprefix"], 10 | permissionLevel: 0, 11 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_PREFIX_DESCRIPTION"), 13 | quotedStringSupport: false, 14 | usage: "[prefix:string]", 15 | extendedHelp: "No extended help available." 16 | }); 17 | } 18 | 19 | async run(msg, [prefix]) { 20 | if (!await msg.hasAtLeastPermissionLevel(6)) return msg.sendMessage(`👉 ***${msg.language.get("MESSAGE_CURRENT_PREFIX")}*** ${msg.guild.settings.get("prefix")}`); 21 | if (!prefix) return msg.sendMessage(`👉 ***${msg.language.get("MESSAGE_CURRENT_PREFIX")}*** ${msg.guild.settings.get("prefix")}`); 22 | await msg.guild.settings.update({ prefix: prefix }).then(() => { 23 | msg.sendMessage(`<:penguSuccess:435712876506775553> ***${msg.language.get("MESSAGE_PREFIX_SET")}*** ${prefix}`); 24 | }); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Settings/togglecategory.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 10, 9 | guarded: true, 10 | hidden: true, 11 | aliases: ["enablegroup", "disablecommandgroup", "enablecommandgroup", "disablecommandcategory", "enablecommandcategory", "disablecategory", "enablecategory", "disablegroup"], 12 | permissionLevel: 6, 13 | requiredPermissions: ["USE_EXTERNAL_EMOJIS"], 14 | description: language => language.get("COMMAND_TOGGLE_GROUP_DESCRPTION"), 15 | usage: "(category:string)", 16 | extendedHelp: "No extended help available." 17 | }); 18 | } 19 | 20 | async run(msg, [category]) { 21 | category = category.toLowerCase(); 22 | if (!this.categories.includes(category)) throw "That is not a valid category."; 23 | 24 | await msg.guild.settings.update("disabledCommandsGroup", category, { guild: msg.guild }); 25 | const exists = msg.guild.settings.get("disabledCommandsGroup").includes(category); 26 | return msg.sendMessage(`${exists ? this.client.emotes.cross : this.client.emotes.check} ***${category[0].toUpperCase() + category.slice(1)} commands category has been ${exists ? "Disabled" : "Enabled"} by ${msg.author.tag}!***`); 27 | } 28 | 29 | get categories() { 30 | return [...new Set(this.client.commands.map(u => u.category.toLowerCase()))]; 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/commands/Utilities/afk.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 5, 8 | description: language => language.get("COMMAND_AFK_DESCRIPTION"), 9 | extendedHelp: "No extended help available.", 10 | usage: "[reason:string]" 11 | }); 12 | } 13 | 14 | async run(msg, [reason = "No reason"]) { 15 | await msg.author.settings.sync(); 16 | const afk = await msg.author.settings.get("afk"); 17 | 18 | if (afk.time) { 19 | await msg.author.settings.reset(["afk.time", "afk.reason"]); 20 | return msg.sendLocale("COMMAND_AFK_REMOVED", [msg.author.username]); 21 | } 22 | 23 | await msg.author.settings.update([["afk.time", Date.now()], ["afk.reason", reason]]); 24 | return msg.sendLocale("COMMAND_AFK_SET", [msg.author.username, reason]); 25 | } 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/Utilities/avatar.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text", "dm"], 8 | cooldown: 5, 9 | aliases: ["pp", "profilepicture"], 10 | permissionLevel: 0, 11 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_AVATAR_DESCRIPTION"), 13 | usage: "[person:username]", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [person = msg.author]) { 19 | return msg.sendMessage(`<:blobsmilehappy:373821679132213248> | ***${msg.language.get("MESSAGE_AVATAR")} ${person.tag}:*** ${person.displayAvatarURL({ size: 2048 })}`); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Utilities/choose.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text", "dm"], 8 | cooldown: 5, 9 | aliases: ["pick", "random"], 10 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 11 | description: language => language.get("COMMAND_CHOOSE_DESCRIPTION"), 12 | usage: " [...]", 13 | usageDelim: "|", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, choices) { 19 | return msg.reply(choices.length === 1 ? `${this.client.emotes.cross} ***${msg.language.get("ER_CHOICES_SENSE")}***` : `${this.client.emotes.check} ${msg.language.get("CHOICE_SELECT")} ***"${choices[Math.floor(Math.random() * choices.length)]}"***`); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Utilities/emote.js: -------------------------------------------------------------------------------- 1 | const { Command, discordUtil: { parseEmoji }, util: { toCodePoint } } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | aliases: ["emoji", "jumbo"], 9 | cooldown: 3, 10 | description: "Shows you an emote.", 11 | extendedHelp: "This command shows an image of an emote.", 12 | usage: "", 13 | requiredPermissions: ["ATTACH_FILES"] 14 | }); 15 | 16 | this 17 | .createCustomResolver("customemote", arg => { 18 | if (!arg) throw "No Emoji Provided, please provide one in order to use this command."; 19 | const discordEmoji = parseEmoji(arg); 20 | if (discordEmoji && discordEmoji.id) return `https://cdn.discordapp.com/emojis/${discordEmoji.id}.${discordEmoji.animated ? "gif" : "png"}`; 21 | 22 | const unicode = toCodePoint(arg); 23 | return `https://twemoji.maxcdn.com/2/72x72/${unicode}.png`; 24 | }); 25 | } 26 | 27 | async run(msg, [emote]) { 28 | const emoji = await this.fetchURL(emote, { type: "buffer" }).catch(() => null); 29 | 30 | if (emoji === null) throw `The provided emoji is invalid. Please try a different one.`; 31 | 32 | return msg.channel.sendFile(emote); 33 | } 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/commands/Utilities/guild.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | const filterLevels = { 5 | DISABLED: "None", 6 | MEMBERS_WITHOUT_ROLES: "Low", 7 | ALL_MEMBERS: "High" 8 | }; 9 | 10 | const verificationLevels = { 11 | NONE: "None", 12 | LOW: "Low", 13 | MEDIUM: "Medium", 14 | HIGH: "(╯°□°)╯︵ ┻━┻", 15 | VERY_HIGH: "┻━┻ ミヽ(ಠ 益 ಠ)ノ彡 ┻━┻" 16 | }; 17 | 18 | module.exports = class extends Command { 19 | 20 | constructor(...args) { 21 | super(...args, { 22 | runIn: ["text"], 23 | aliases: ["server", "guildinfo", "sererinfo"], 24 | cooldown: 5, 25 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 26 | description: language => language.get("COMMAND_GUILDINFO_DESCRIPTION"), 27 | extendedHelp: "No extended help available." 28 | }); 29 | } 30 | 31 | async run(msg) { 32 | const embed = new MessageEmbed() 33 | .setColor("RANDOM") 34 | .setTimestamp() 35 | .setFooter("© PenguBot.com") 36 | .setThumbnail(msg.guild.iconURL()) 37 | .addField("❯ Name", msg.guild.name, true) 38 | .addField("❯ ID", msg.guild.id, true) 39 | .addField("❯ Region", msg.guild.region.toUpperCase(), true) 40 | .addField("❯ Creation Date", msg.guild.createdAt.toDateString(), true) 41 | .addField("❯ Explicit Filter", filterLevels[msg.guild.explicitContentFilter], true) 42 | .addField("❯ Verification Level", verificationLevels[msg.guild.verificationLevel], true) 43 | .addField("❯ Owner", `<@${msg.guild.ownerID}>`, true) 44 | .addField("❯ Members", msg.guild.memberCount, true) 45 | .addField("❯ Roles", msg.guild.roles.cache.size, true) 46 | .addField("❯ Channels", msg.guild.channels.cache.size, true); 47 | 48 | return msg.sendEmbed(embed); 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /src/commands/Utilities/lmgtfy.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text", "dm"], 8 | cooldown: 5, 9 | aliases: ["letmegoogleitforyou", "google"], 10 | permissionLevel: 0, 11 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_LMGTFY_DESCRIPTION"), 13 | usage: "", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [query]) { 19 | return msg.sendMessage(`<:blobsmilehappy:373821679132213248> | ***Here's your LMGTFY Link: ***`); 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/Utilities/poll.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 10, 8 | aliases: ["strawpoll", "createpoll"], 9 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 10 | description: language => language.get("COMMAND_POLL_DESCRIPTION"), 11 | usage: " [...]", 12 | usageDelim: "|", 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg, [title, ...options]) { 18 | try { 19 | const data = await this.fetchURL("https://www.strawpoll.me/api/v2/polls", { 20 | method: "POST", 21 | headers: { "Content-Type": "application/json" }, 22 | body: JSON.stringify({ 23 | title, 24 | options, 25 | multi: "multi" in msg.flagArgs ? msg.flagArgs.multi : true, 26 | captcha: "captcha" in msg.flagArgs ? msg.flagArgs.captcha : true 27 | }) 28 | }); 29 | return msg.sendMessage(`<:penguCheck1:431440099675209738> ***Here's the poll you requested:*** https://www.strawpoll.me/${data.id}`); 30 | } catch (e) { 31 | return msg.sendMessage(":penguError: There was an error trying to create this poll, please try again."); 32 | } 33 | } 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/commands/Utilities/quote.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | const { Argument } = require("klasa"); 3 | const { MessageEmbed } = require("discord.js"); 4 | 5 | module.exports = class extends Command { 6 | 7 | constructor(...args) { 8 | super(...args, { 9 | runIn: ["text"], 10 | cooldown: 8, 11 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_QUOTE_DESCRIPTION"), 13 | usage: "[channel:channel] ", 14 | usageDelim: " " 15 | }); 16 | } 17 | 18 | async run(msg, [channel = msg.channel, msgId]) { 19 | if (!Argument.regex.snowflake.test(msgId)) throw "Invalid message ID. Use developer mode to copy IDs."; 20 | const message = await channel.messages.fetch(msgId).catch(() => null); 21 | if (!message) throw "Your message does not exist or is not in this channel. Try specifying the channel it is from."; 22 | const image = message.attachments.size > 0 ? this.checkAttachments(message.attachments.first().url) : null; 23 | const embed = new MessageEmbed() 24 | .setColor("#FAFAFA") 25 | .setDescription(message.content) 26 | .setTimestamp(message.createdAt) 27 | .setAuthor(message.author.tag, message.author.displayAvatarURL()); 28 | if (image) embed.setImage(image); 29 | return msg.sendEmbed(embed); 30 | } 31 | 32 | checkAttachments(attachment) { 33 | const imageLink = attachment.split("."); 34 | const typeOfImage = imageLink[imageLink.length - 1]; 35 | const image = /(jpg|jpeg|png|gif)/gi.test(typeOfImage); 36 | if (!image) return null; 37 | return attachment; 38 | } 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /src/commands/Utilities/remind.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text", "dm"], 8 | cooldown: 10, 9 | permissionLevel: 0, 10 | aliases: ["remindme", "setreminder", "remindmein"], 11 | requiredPermissions: ["MANAGE_MESSAGES", "USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_REMIND_DESCRIPTION"), 13 | usage: " [...]", 14 | usageDelim: " ", 15 | extendedHelp: "No extended help available." 16 | }); 17 | } 18 | 19 | async run(msg, [time, ...message]) { 20 | const r = await this.client.schedule.create("reminder", time, { 21 | data: { 22 | channel: msg.channel.id, 23 | user: msg.author.id, 24 | text: message.join(" ") 25 | } 26 | }); 27 | return msg.reply(`<:penguSuccess:435712876506775553> ***${msg.language.get("MESSAGE_NEW_REMINDER")} \`${r.id}\`***`); 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/commands/Utilities/roleinfo.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 5, 9 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 10 | description: language => language.get("COMMAND_ROLEINFO_DESCRIPTION"), 11 | usage: "", 12 | extendedHelp: "No extended help available." 13 | }); 14 | } 15 | 16 | async run(msg, [role]) { 17 | return msg.sendEmbed(new MessageEmbed() 18 | .setColor(role.hexColor) 19 | .setTimestamp(role.createdAt) 20 | .setFooter("© PenguBot.com • Role Created At") 21 | .addField("❯ Name", role.name, true) 22 | .addField("❯ ID", role.id, true) 23 | .addField("❯ Color", role.hexColor, true) 24 | .addField("❯ Members", role.members.size, true) 25 | .addField("❯ Hoisted", role.hoist ? "Yes" : "No", true) 26 | .addField("❯ Mentionable", role.mentionable ? "Yes" : "No", true) 27 | .addField(`❯ Permission(s)`, role.permissions.toArray().length ? role.permissions.toArray().join(", ") : "None")); 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/commands/Utilities/say.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../lib/structures/KlasaCommand"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | cooldown: 5, 9 | permissionLevel: 3, 10 | requiredPermissions: ["MANAGE_MESSAGES", "USE_EXTERNAL_EMOJIS"], 11 | description: language => language.get("COMMAND_SAY_DESCRIPTION"), 12 | usage: "", 13 | extendedHelp: "No extended help available." 14 | }); 15 | } 16 | 17 | async run(msg, [message]) { 18 | if (message.length < 1) return msg.sendMessage("<:penguError:435712890884849664> Message length can't be less than one character."); 19 | msg.delete(); 20 | return msg.sendMessage(message); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Utilities/shorten.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text", "dm"], 8 | cooldown: 10, 9 | aliases: ["shortener", "shortlink"], 10 | permissionLevel: 0, 11 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 12 | description: language => language.get("COMMAND_SHORTEN_DESCRIPTION"), 13 | usage: "", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | 18 | async run(msg, [link]) { 19 | const data = await this.fetchURL(`https://is.gd/create.php?format=json&url=${encodeURIComponent(link)}`); 20 | return msg.sendMessage(`<:penguSuccess:435712876506775553> ***${msg.language.get("MESSAGE_LINK_SHORTEN")}*** ${data.shorturl}`); 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/commands/Utilities/translate.js: -------------------------------------------------------------------------------- 1 | const { Command } = require("../../index"); 2 | const translate = require("@k3rn31p4nic/google-translate-api"); 3 | 4 | module.exports = class extends Command { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | description: language => language.get("COMMAND_TRANSLATE_DESCRIPTION"), 9 | usageDelim: "|", 10 | usage: " " 11 | }); 12 | } 13 | 14 | async run(msg, [content, language]) { 15 | const { text } = await translate(content, { to: language }) 16 | .catch(() => { throw "That language is not supported, please try again."; }); 17 | 18 | return msg.sendMessage(`**Translated Message:** ${text}`); 19 | } 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /src/commands/Utilities/twstats.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed, Timestamp, config: { apis } } = require("../../index"); 2 | 3 | const timestamp = new Timestamp("d MMMM YYYY"); 4 | 5 | module.exports = class extends Command { 6 | 7 | constructor(...args) { 8 | super(...args, { 9 | cooldown: 15, 10 | aliases: ["twitchstats", "twitchstatistics"], 11 | requiredPermissions: ["EMBED_LINKS"], 12 | description: "Get twitch channel statisitcs directly from twitch.", 13 | usage: "", 14 | extendedHelp: "No extended help available." 15 | }); 16 | } 17 | async run(msg, [channel]) { 18 | const body = await this.fetchURL(`https://api.twitch.tv/kraken/channels/${channel}`, { query: { client_id: apis.twitch } }) 19 | .catch(() => { throw "I'm having trouble communicating with twitch, make sure you entered the right username."; }); 20 | 21 | return msg.sendEmbed(new MessageEmbed() 22 | .setColor("#1976D2") 23 | .setAuthor(body.display_name, body.logo, body.url) 24 | .setTimestamp() 25 | .setFooter(`Requested by ${msg.author.tag}`) 26 | .setDescription(` 27 | ❯ **Views:** ${body.views.toLocaleString()} 28 | ❯ **Followers:** ${body.followers.toLocaleString()} 29 | ❯ **Game:** ${body.game} 30 | ❯ **Status:** ${body.status} 31 | ❯ **Mature?:** ${body.mature ? "Yes" : "No"} 32 | ❯ **Created At:** ${timestamp.display(body.created_at)} 33 | `)); 34 | } 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /src/commands/Utilities/urban.js: -------------------------------------------------------------------------------- 1 | const { Command, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | cooldown: 10, 8 | aliases: ["urband", "ud"], 9 | description: "Get meaning for a word from Urban Dictionary.", 10 | usage: "", 11 | nsfw: true 12 | }); 13 | } 14 | 15 | async run(msg, [word]) { 16 | const info = await this.getDefinition(word); 17 | 18 | return msg.sendEmbed(new MessageEmbed() 19 | .setAuthor(`Word: ${info.word}`, info.link) 20 | .setDescription(`**Definition:** ${info.definition}`) 21 | .setColor("RANDOM") 22 | .setFooter("Urban Dictionary", this.client.user.displayAvatarURL()) 23 | .addField("Votes", `👍 ${info.thumbsUp} **|** 👎 ${info.thumbsDown}`, true) 24 | .addField("Example", info.example, true)); 25 | } 26 | 27 | async getDefinition(term) { 28 | const { list: [word] } = await this.fetchURL(`http://api.urbandictionary.com/v0/define`, { query: { term } }); 29 | 30 | if (!word) throw "No entry found"; 31 | 32 | return { 33 | definition: word.definition.length >= 1984 ? `${word.definition.substr(0, 1984)}...` : word.definition, 34 | word: word.word, 35 | link: word.permalink, 36 | thumbsUp: word.thumbs_up, 37 | thumbsDown: word.thumbs_down, 38 | example: word.example, 39 | author: word.author 40 | }; 41 | } 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /src/commands/Utilities/userinfo.js: -------------------------------------------------------------------------------- 1 | const { Command, Timestamp, MessageEmbed } = require("../../index"); 2 | 3 | module.exports = class extends Command { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | runIn: ["text"], 8 | aliases: ["uinfo"], 9 | cooldown: 5, 10 | requiredPermissions: ["EMBED_LINKS", "USE_EXTERNAL_EMOJIS"], 11 | description: language => language.get("COMMAND_USERINFO_DESCRIPTION"), 12 | usage: "[user:membername]", 13 | extendedHelp: "No extended help available." 14 | }); 15 | this.timestamp = new Timestamp("DD MMMM YYYY, HH:MM"); 16 | } 17 | 18 | async run(msg, [user]) { 19 | if (!user) user = await msg.guild.members.fetch(msg.author.id).catch(() => null); 20 | const embed = new MessageEmbed() 21 | .setColor(user.displayHexColor ? user.displayHexColor : "#32c4e3") 22 | .setTimestamp() 23 | .setFooter("© PenguBot.com") 24 | .setThumbnail(user.user.displayAvatarURL()) 25 | .addField("❯ Name", user.user.tag, true) 26 | .addField("❯ ID", user.id, true) 27 | .addField("❯ Discord Join Date", this.timestamp.display(user.user.createdAt), true) 28 | .addField("❯ Server Join Date", user.joinedTimestamp ? this.timestamp.display(user.joinedTimestamp) : "Unknown", true) 29 | .addField("❯ Nickname", user.nickname || "None", true) 30 | .addField("❯ Bot?", user.user.bot ? "Yes" : "No", true) 31 | .addField("❯ Roles", user.roles.cache.size - 1, true); 32 | 33 | if ((user.roles.size - 1) > 0) embed.setDescription(`<@&${user.roles.map(r => r.id).filter(r => r !== msg.guild.roles.everyone.id).join("> <@&")}>`); 34 | return msg.sendEmbed(embed); 35 | } 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /src/events/channelCreate.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(channel) { 7 | if (channel.type !== "text") return; 8 | await new ServerLog(channel.guild) 9 | .setColor("green") 10 | .setType("channels") 11 | .setName("Channel Created") 12 | .setMessage(`📗 **#${channel.name}** (${channel.id}) channel was \`created\``) 13 | .send(); 14 | 15 | const role = channel.guild.roles.cache.filter(r => r.name === "PENGU_MUTED"); 16 | if (role) await channel.updateOverwrite(role, { SEND_MESSAGES: false, ADD_REACTIONS: false, CONNECT: false }, `New Channel Created`).catch(() => null); 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/events/channelDelete.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(channel) { 7 | if (channel.type === "voice") { 8 | if (channel.guild.music.queue && !channel.guild.music.voiceChannel) { 9 | if (channel.guild.music.textChannel) channel.guild.music.textChannel.sendMessage(`${this.client.emotes.check} ***Queue cleared, leaving voice channel.***`).catch(() => null); 10 | channel.guild.music.destroy(); 11 | } 12 | return; 13 | } else if (channel.type === "text") { 14 | await new ServerLog(channel.guild) 15 | .setColor("red") 16 | .setType("channels") 17 | .setName("Channel Deleted") 18 | .setMessage(`📕 **#${channel.name}** (${channel.id}) channel was \`deleted\``) 19 | .send(); 20 | } 21 | return; 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/events/commandError.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const Raven = require("raven"); 3 | 4 | module.exports = class extends Event { 5 | 6 | run(message, command, params, error) { 7 | if (error instanceof Error) { 8 | this.client.emit("wtf", `[COMMAND] ${command.path}\n${error.stack || error}`); 9 | Raven.captureMessage(`commandError: ${command.name}\n${error.stack || error}`); 10 | } 11 | if (error.message) message.sendCode("JSON", error.message).catch(err => this.client.emit("wtf", err)); 12 | else message.sendMessage(error).catch(err => this.client.emit("wtf", err)); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/commandUnknown.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const Parser = require("breadtags"); 3 | const { join } = require("path"); 4 | 5 | const timeout = new Set(); 6 | 7 | module.exports = class extends Event { 8 | 9 | async run(msg, command, prefixLength) { 10 | if (!msg.guild || !msg.guild.settings.get("customcmds").length) return; 11 | await msg.guild.settings.sync(true); 12 | command = command.toLowerCase(); 13 | const customCommand = msg.guild.settings.get("customcmds").find(c => c.name.toLowerCase() === command); 14 | if (!customCommand) return; 15 | 16 | if (timeout.has(`${msg.author.id}-${msg.guild.id}`)) return msg.sendMessage(`${this.client.emotes.cross} **Ooh, Not so quickly. Please wait and try again!**`); 17 | 18 | const args = msg.content.slice(prefixLength).trim().split(" ").slice(1); 19 | const parsed = await this.parser.parse(customCommand.content, { 20 | guild: msg.guild, 21 | user: msg.author, 22 | member: msg.member, 23 | channel: msg.channel, 24 | args 25 | }); 26 | 27 | await msg.channel.send(parsed ? parsed : customCommand.content); 28 | timeout.add(`${msg.author.id}-${msg.guild.id}`); 29 | setTimeout(() => timeout.delete(`${msg.author.id}-${msg.guild.id}`), 3500); 30 | return; 31 | } 32 | 33 | async init() { 34 | this.parser = new Parser(); 35 | this.parser.loadAll(join(__dirname, "..", "lib", "tags")); 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/events/debug.js: -------------------------------------------------------------------------------- 1 | const { Event, config } = require("../index"); 2 | 3 | module.exports = class extends Event { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | enabled: "debug" in config ? config.debug : false 8 | }); 9 | } 10 | 11 | async run(info) { 12 | this.client.console.debug(info); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/disconnect.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | 3 | module.exports = class extends Event { 4 | 5 | async run() { 6 | this.client.console.warn(`[${this.client.shard.id}]: Disconnected`); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/events/eventError.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const Raven = require("raven"); 3 | 4 | module.exports = class extends Event { 5 | 6 | run(event, args, error) { 7 | this.client.emit("wtf", `[EVENT] ${event.path}\n${error ? error.stack ? error.stack : error : "Unknown error"}`); 8 | Raven.captureMessage(`eventError: ${event.name}\n${error ? error.stack ? error.stack : error : "Unknown error"}`); 9 | } 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /src/events/guildBanAdd.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(guild, user) { 7 | await new ServerLog(guild) 8 | .setColor("red") 9 | .setType("moderation") 10 | .setName("Member Banned") 11 | .setMessage(`🔨 ${user} (${user.id}) has been **banned**.`) 12 | .send(); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/guildBanRemove.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(guild, user) { 7 | await new ServerLog(guild) 8 | .setColor("yellow") 9 | .setType("moderation") 10 | .setName("Member Unbanned") 11 | .setMessage(`🔨 ${user} (${user.id}) has been **unbanned**.`) 12 | .send(); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/guildDelete.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | 3 | module.exports = class extends Event { 4 | 5 | async run() { 6 | this.client.dogstats.increment("pengubot.guildsremoved"); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/events/guildMemberRemove.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(member) { 7 | await new ServerLog(member.guild) 8 | .setColor("red") 9 | .setType("leave") 10 | .setName("Member Joined") 11 | .setMessage(`📤 ${member.user} (${member.id}) has left **${member.guild.name}**.`) 12 | .send(); 13 | 14 | await this.leaveMessage(member); 15 | } 16 | 17 | leaveMessage(member) { 18 | if (!member.guild.settings.get("toggles.leavemsg")) return; 19 | const channel = member.guild.channels.cache.get(member.guild.settings.get("channels.leave")); 20 | if (!channel || (channel && !channel.postable)) return; 21 | return channel.send(this.replaceText(member.guild.settings.get("messages.leave"), member)); 22 | } 23 | 24 | replaceText(str, member) { 25 | return str.replace(/\{(mention|server|server\.id|username|user\.tag|user\.id|user|displayname|id|size|members|count)\}/gi, (__, match) => { 26 | switch (match.toLowerCase()) { 27 | case "mention": return member.toString(); 28 | case "server": return member.guild.name; 29 | case "server.id": return member.guild.id; 30 | case "user": 31 | case "displayname": 32 | case "username": return member.user.username; 33 | case "user.tag": return member.user.tag; 34 | case "user.id": 35 | case "id": return member.id; 36 | case "size": 37 | case "members": 38 | case "count": return member.guild.memberCount; 39 | default: return __; 40 | } 41 | }); 42 | } 43 | 44 | }; 45 | -------------------------------------------------------------------------------- /src/events/klasaReady.js: -------------------------------------------------------------------------------- 1 | const { Event, config } = require("../index"); 2 | 3 | module.exports = class extends Event { 4 | 5 | async run() { 6 | // Memory Sweeper task 7 | if (!this.client.schedule.tasks.some(task => task.taskName === "memorySweeper")) { 8 | await this.client.schedule.create("memorySweeper", "*/10 * * * *"); 9 | } 10 | 11 | // Health task 12 | if (!this.client.schedule.tasks.some(task => task.taskName === "health")) { 13 | await this.client.schedule.create("health", "* * * * *"); 14 | } 15 | 16 | // sendStats task 17 | if (config.production && !this.client.schedule.tasks.some(task => task.taskName === "stats")) { 18 | await this.client.schedule.create("stats", "*/20 * * * *"); 19 | } 20 | 21 | // Datadog task 22 | if (config.production && !this.client.schedule.tasks.some(task => task.taskName === "datadog")) { 23 | await this.client.schedule.create("datadog", "*/1 * * * *"); 24 | } 25 | 26 | this.client.console.log(`[${this.client.shard.id}]: Online`); 27 | } 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /src/events/messageDelete.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(message) { 7 | if (!message.guild || message.author.bot) return; 8 | 9 | await new ServerLog(message.guild) 10 | .setColor("red") 11 | .setType("messages") 12 | .setName("Message Deleted") 13 | .setAuthor(`${message.author.tag} in #${message.channel.name}`, message.author.displayAvatarURL()) 14 | .setMessage(`**Content:**\n${message.content}`) 15 | .send(); 16 | } 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /src/events/messageDeleteBulk.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(messages) { 7 | if (!messages.first().guild) return; 8 | 9 | await new ServerLog(messages.first().guild) 10 | .setColor("red") 11 | .setType("messages") 12 | .setName("Bulk Messages Deleted") 13 | .setMessage(`❌ \`${messages.size}\` Messages Deleted in ${messages.first().channel}`) 14 | .send(); 15 | } 16 | 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /src/events/messageUpdate.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(oldMessage, newMessage) { 7 | if (this.client.ready && oldMessage.content !== newMessage.content) this.client.monitors.run(newMessage); 8 | if (!oldMessage.guild || oldMessage.author.bot || oldMessage.content === newMessage.content) return; 9 | 10 | await new ServerLog(oldMessage.guild) 11 | .setColor("blue") 12 | .setType("messages") 13 | .setName("Message Updated") 14 | .setAuthor(`${oldMessage.author.tag} in #${oldMessage.channel.name}`, oldMessage.author.displayAvatarURL()) 15 | .setMessage(`[► View The Message](https://discordapp.com/channels/${oldMessage.guild.id}/${oldMessage.channel.id}/${oldMessage.id})\n\n**Old:**\n${oldMessage.content}\n\n**New:**\n${newMessage.content}`) 16 | .send(); 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/events/reconnecting.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | 3 | module.exports = class extends Event { 4 | 5 | async run() { 6 | this.client.console.warn(`[${this.client.shard.id}]: Reconnecting`); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/events/resumed.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | 3 | module.exports = class extends Event { 4 | 5 | run() { 6 | this.client.console.warn(`[${this.client.shard.id}]: Reconnected`); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/events/roleCreate.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(role) { 7 | await new ServerLog(role.guild) 8 | .setColor("green") 9 | .setType("roles") 10 | .setName("Role Created") 11 | .setMessage(`☑ **${role}** (${role.id}) role was \`created\``) 12 | .send(); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/roleDelete.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | const ServerLog = require("../lib/structures/ServerLog"); 3 | 4 | module.exports = class extends Event { 5 | 6 | async run(role) { 7 | await new ServerLog(role.guild) 8 | .setColor("red") 9 | .setType("roles") 10 | .setName("Role Deleted") 11 | .setMessage(`❌ **${role}** (${role.id}) role was \`deleted\``) 12 | .send(); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/shardError.js: -------------------------------------------------------------------------------- 1 | const { Event } = require("klasa"); 2 | 3 | module.exports = class extends Event { 4 | 5 | async run(error, shardID) { 6 | this.client.console.error(`[${shardID}]:`, error); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/extendables/fetchURL.js: -------------------------------------------------------------------------------- 1 | const { Extendable, Piece, Util: { fetch } } = require("../index"); 2 | 3 | module.exports = class extends Extendable { 4 | 5 | constructor(...args) { 6 | super(...args, { appliesTo: [Piece] }); 7 | } 8 | 9 | fetchURL(url, options = {}) { 10 | options.headers = options.headers ? { ...options.headers, "User-Agent": this.client.userAgent } : { "User-Agent": this.client.userAgent }; 11 | return fetch(url, options, options.type || "json").catch(error => { 12 | Error.captureStackTrace(error); 13 | this.client.emit("error", error); 14 | throw error; 15 | }); 16 | } 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /src/extendables/prompt.js: -------------------------------------------------------------------------------- 1 | const { Extendable } = require("klasa"); 2 | const { Message } = require("discord.js"); 3 | 4 | module.exports = class extends Extendable { 5 | 6 | constructor(...args) { 7 | super(...args, { appliesTo: [Message] }); 8 | } 9 | 10 | async prompt(text, time = 30000) { 11 | const message = await this.channel.send(text); 12 | const responses = await this.channel.awaitMessages(msg => msg.author === this.author, { time, max: 1 }); 13 | message.delete(); 14 | if (responses.size === 0) throw this.language.get("MESSAGE_PROMPT_TIMEOUT"); 15 | return responses.first(); 16 | } 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /src/finalizers/commandCounter.js: -------------------------------------------------------------------------------- 1 | const { Finalizer } = require("klasa"); 2 | 3 | module.exports = class extends Finalizer { 4 | 5 | async run() { 6 | const r = this.client.providers.default.db; 7 | 8 | const query = await r.table("clientStorage") 9 | .get(this.client.user.id) 10 | .getField("counter") 11 | .run(); 12 | 13 | await r.table("clientStorage") 14 | .get(this.client.user.id) 15 | .update({ 16 | counter: { 17 | total: query.total + 1 18 | } 19 | }) 20 | .run(); 21 | 22 | await this.client.shard.broadcastEval("this.settings.sync(true);"); 23 | } 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/functions/friendlyDuration.js: -------------------------------------------------------------------------------- 1 | const { Function } = require("@kcp/functions"); 2 | 3 | module.exports = class extends Function { 4 | 5 | run(ms) { 6 | const sec = Math.floor((ms / 1000) % 60).toString(); 7 | const min = Math.floor((ms / (1000 * 60)) % 60).toString(); 8 | const hrs = Math.floor(ms / (1000 * 60 * 60)).toString(); 9 | return `${hrs.padStart(2, "0")}:${min.padStart(2, "0")}:${sec.padStart(2, "0")}`; 10 | } 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /src/functions/images.js: -------------------------------------------------------------------------------- 1 | const { Function, config, util: { fetch } } = require("../index"); 2 | 3 | module.exports = class extends Function { 4 | 5 | run(endpoint, load = {}) { 6 | return fetch(`https://server.pengubot.com/${endpoint}`, { method: "POST", headers: { authorization: config.apis.pengu }, body: JSON.stringify(load) }, "buffer"); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/functions/isPatron.js: -------------------------------------------------------------------------------- 1 | const { Function } = require("@kcp/functions"); 2 | 3 | module.exports = class extends Function { 4 | 5 | run(guild) { 6 | return this.client.settings.get("pGuilds").includes(guild.id); 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /src/functions/isUpvoter.js: -------------------------------------------------------------------------------- 1 | const { Function } = require("@kcp/functions"); 2 | 3 | module.exports = class extends Function { 4 | 5 | run(user) { 6 | const diff = Date.now() - user.settings.get("lastUpvote"); 7 | if (diff <= 43200000) return true; 8 | return false; 9 | } 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /src/functions/randomNumber.js: -------------------------------------------------------------------------------- 1 | const { Function } = require("@kcp/functions"); 2 | 3 | module.exports = class extends Function { 4 | 5 | run(min, max) { 6 | if (typeof min !== "number") throw "Minimun value must be a number"; 7 | if (typeof max !== "number") throw "Maximum value must be a number"; 8 | if (min >= max) throw "Minimun must be less than Maximum to determine the range"; 9 | min = Math.ceil(min); 10 | max = Math.floor(max); 11 | return Math.floor(Math.random() * (max - min)) + min; 12 | } 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /src/functions/scrapeSubreddit.js: -------------------------------------------------------------------------------- 1 | const { util: { fetch }, Function } = require("../index"); 2 | 3 | module.exports = class extends Function { 4 | 5 | async run(subreddit, options = { }) { 6 | let type; 7 | if (options.type) type = `/${options.type.toLowerCase()}`; 8 | const data = await fetch(`https://www.reddit.com/r/${subreddit}${type ? type : ""}/.json?limit=100`) 9 | .then(res => res.data) 10 | .catch(() => null); 11 | if (!data) throw "Houston we have a problem, please try again!"; 12 | 13 | const random = data.children[Math.floor(Math.random() * data.children.length)]; 14 | if (!random || !random.data) throw "Houston we have a problem, please try again!"; 15 | 16 | return random.data; 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const klasa = require("klasa"); 2 | const discord = require("discord.js"); 3 | const klasaApi = require("klasa-api"); 4 | const klasaFunctions = require("@kcp/functions"); 5 | const { version } = require("../package.json"); 6 | 7 | module.exports = { 8 | ...klasa, 9 | ...discord, 10 | ...klasaApi, 11 | ...klasaFunctions, 12 | Util: require("./lib/util/Util"), 13 | util: require("./lib/util/Util"), 14 | config: require("../config.js"), 15 | klasaUtil: klasa.util, 16 | discordUtil: discord.Util, 17 | version, 18 | klasaVersion: klasa.version, 19 | discordVersion: discord.version, 20 | klasaConstants: klasa.constants, 21 | discordConstants: discord.Constants, 22 | Command: require("./lib/structures/KlasaCommand"), 23 | ModLog: require("./lib/structures/ModLog"), 24 | ServerLog: require("./lib/structures/ServerLog") 25 | }; 26 | -------------------------------------------------------------------------------- /src/inhibitors/disabledGroup.js: -------------------------------------------------------------------------------- 1 | const { Inhibitor } = require("klasa"); 2 | 3 | module.exports = class extends Inhibitor { 4 | 5 | constructor(...args) { 6 | super(...args, { spamProtection: true }); 7 | } 8 | 9 | async run(msg, cmd) { 10 | if (!msg.guild || !msg.guild.settings.get("disabledCommandsGroup").includes(cmd.category.toLowerCase())) return; 11 | throw msg.sendMessage(`${msg.language.get("INHIBITOR_DISABLED_GROUP")}: \`${cmd.category}\``); 12 | } 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /src/inhibitors/patronOnly.js: -------------------------------------------------------------------------------- 1 | const { Inhibitor } = require("../index"); 2 | 3 | module.exports = class extends Inhibitor { 4 | 5 | constructor(...args) { 6 | super(...args, { spamProtection: false }); 7 | } 8 | 9 | async run(msg, cmd) { 10 | if (!cmd.patronOnly || this.client.funcs.isPatron(msg.guild)) return; 11 | throw `🔒 ***${msg.language.get("CMD_PATRON_ONLY")}***`; 12 | } 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /src/inhibitors/requireDJ.js: -------------------------------------------------------------------------------- 1 | const { Inhibitor } = require("klasa"); 2 | 3 | module.exports = class extends Inhibitor { 4 | 5 | constructor(...args) { 6 | super(...args, { spamProtection: true }); 7 | } 8 | 9 | async run(msg, cmd) { 10 | if (cmd.requireDJ !== true) return; 11 | if (msg.channel.type !== "text") throw "This command may be only executed in a server."; 12 | 13 | if (!msg.guild.settings.get("toggles.djmode")) return; 14 | if (await msg.hasAtLeastPermissionLevel(2)) return; 15 | throw `${this.client.emotes.cross} ***${msg.language.get("INHIBITOR_DJ_ONLY")}***`; 16 | } 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /src/inhibitors/requireMusic.js: -------------------------------------------------------------------------------- 1 | const { Inhibitor } = require("klasa"); 2 | 3 | module.exports = class extends Inhibitor { 4 | 5 | constructor(...args) { 6 | super(...args, { spamProtection: false }); 7 | } 8 | 9 | async run(msg, cmd) { 10 | if (!msg.guild || cmd.requireMusic !== true) return; 11 | 12 | const force = "force" in msg.flagArgs; 13 | 14 | await msg.guild.members.fetch(msg.author).catch(() => null); 15 | 16 | const { music } = msg.guild; 17 | 18 | if (!msg.member.voice.channel && !force) throw "You are not connected in a voice channel."; 19 | if (!music.voiceChannel) throw "I am not connected in a voice channel."; 20 | if (msg.member.voice.channel !== msg.guild.me.voice.channel && !force) throw "You must be in the same voice channel as me."; 21 | if (!music.queue.length) throw msg.language.get("MUSIC_NO_SONGS_IN_QUEUE"); 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/inhibitors/upvoterOnly.js: -------------------------------------------------------------------------------- 1 | const { Inhibitor } = require("../index"); 2 | 3 | module.exports = class extends Inhibitor { 4 | 5 | constructor(...args) { 6 | super(...args, { spamProtection: false }); 7 | } 8 | 9 | async run(msg, cmd) { 10 | if (!msg.guild || !cmd.upvoteOnly) return; 11 | if (this.client.funcs.isUpvoter(msg.author) || this.client.funcs.isPatron(msg.guild)) return; 12 | throw `🔒 ***${msg.language.get("CMD_UPVOTE_ONLY")}***`; 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /src/lib/constants/nsfw/subreddits.json: -------------------------------------------------------------------------------- 1 | { 2 | "amateur": ["Amateur", "RealGirls", "randomsexiness", "PetiteGoneWild", "homemadexxx", "AmateurArchives"], 3 | "anal": ["anal", "buttsex", "AnalPorn", "upherbutt", "CumFromAnal"], 4 | "asiannsfw": ["AsianHotties", "juicyasians", "AsianNSFW", "AsianPorn", "AsianHottiesGIFS"], 5 | "bdsm": ["bdsm", "Spanking", "kinkyporn"], 6 | "blowjob": ["Blowjobs", "OnHerKnees", "deepthroat", "BlowjobGifs", "OralSex", "dreamjobs", "lickingdick"], 7 | "boobs": ["Boobies", "TittyDrop", "boobbounce", "boobs", "boobgifs", "tits", "BreastEnvy", "PerfectTits"], 8 | "booty": ["booty", "SpreadEm", "twerking", "ButtsAndBareFeet", "booty_gifs"], 9 | "ass": ["ass", "TheUnderbun", "HighResASS", "AssOnTheGlass", "datass", "assgifs"], 10 | "cosplay": ["nsfwcosplay", "starwarsnsfw", "cosplayonoff", "Cosporn", "CosplayBoobs", "PornParody", "Cosplayheels"], 11 | "fitgirls": ["fitgirls", "AthleticGirls", "Ohlympics", "NSFW_Hardbodies", "LockerRoom", "GymnastGirls", "worldcupgirls"], 12 | "gifs": ["NSFW_GIF", "nsfw_gifs", "60fpsporn", "NSFW_HTML5", "porn_gifs", "adultgifs", "randomsexygifs", "PornGifs"], 13 | "gonewild": ["gonewild", "gonewildcurvy", "asstastic", "AsiansGoneWild", "GWCouples", "GoneWildPlus", "GoneWildTube", "ladybonersgw"], 14 | "hentai": ["hentai", "ecchi", "HENTAI_GIF", "doujinshi", "WesternHentai", "pantsu", "hentaivids", "hentaibondage", "MonsterGirl", "Lolicons"], 15 | "lesbian": ["lesbians", "StraightGirlsPlaying", "girlskissing", "mmgirls", "scissoring", "dyke", "GirlsCuddling", "amateurlesbians", "Lesbian_gifs"], 16 | "milfs": ["milf", "MilfsAndHousewives", "maturemilf", "realmilf", "ChocolateMilf", "GroupOfNudeMILFS", "HotAsianMilfs", "MILFS", "realmoms"], 17 | "nsfw": ["nsfw", "nsfwhardcore", "nsfw2", "HighResNSFW", "BonerMaterial", "porn", "iWantToFuckHer", "Sexy", "nude", "NSFWCute", "HotGirls"], 18 | "nsfwsnapchat": ["NSFW_Snapchat", "snapcgatgw", "snapchatboobs", "SnapchatImages", "NudeSelfies", "CellShots", "selfshots", "selfpix", "xPosing"], 19 | "pussy": ["pussy", "rearpussy", "vagaina", "PussyMound", "PerfectPussies", "TheRearPussy", "PussySlip"], 20 | "teen": ["LegalTeens", "just18", "youngporn", "Barelylegal", "barelylegalteens"] 21 | } -------------------------------------------------------------------------------- /src/lib/structures/KlasaCommand.js: -------------------------------------------------------------------------------- 1 | const { Command: KlasaCommand } = require("klasa"); 2 | 3 | class Command extends KlasaCommand { 4 | 5 | constructor(store, file, core, { upvoteOnly = false, patronOnly = false, ...options }) { 6 | super(store, file, core, options); 7 | this.upvoteOnly = upvoteOnly; 8 | this.patronOnly = patronOnly; 9 | } 10 | 11 | } 12 | 13 | module.exports = Command; 14 | -------------------------------------------------------------------------------- /src/lib/structures/PenguClient.js: -------------------------------------------------------------------------------- 1 | const { Client, Gateway } = require("klasa"); 2 | const config = require("../../../config.js"); 3 | const { StatsD } = require("hot-shots"); 4 | 5 | // Extensions 6 | require("./PenguGuild"); 7 | require("./PenguMember"); 8 | 9 | // Custom 10 | const permissionLevels = require(`./permissionLevels`); 11 | 12 | // Plugins 13 | Client.use(require("@kcp/functions").Client); 14 | if (config.musicEnabled) Client.use(require("@pengubot/music")); 15 | if (config.apiEnabled) Client.use(require("klasa-api")); 16 | 17 | // Schemas 18 | const defaultMemberSchema = require(`./schemas/defaultMemberSchema`); 19 | const defaultGuildSchema = require(`./schemas/defaultGuildSchema`); 20 | const defaultClientSchema = require(`./schemas/defaultClientSchema`); 21 | const defaultUserSchema = require(`./schemas/defaultUserSchema`); 22 | 23 | class PenguClient extends Client { 24 | 25 | constructor(options) { 26 | super({ ...options, permissionLevels, defaultGuildSchema, defaultClientSchema, defaultUserSchema }); 27 | this.topCache = []; 28 | this.health = Object.seal({ 29 | commands: { 30 | temp: { 31 | count: 0, 32 | ran: {} 33 | }, 34 | cmdCount: new Array(60).fill({ 35 | count: 0, 36 | ran: {} 37 | }) 38 | } 39 | }); 40 | this.emotes = { check: "<:penguSuccess:435712876506775553>", cross: "<:penguError:435712890884849664>", loading: "" }; 41 | this.dogstats = new StatsD("localhost", 8125); 42 | 43 | this.version = "2.0.0"; 44 | this.userAgent = `PenguBot/${this.version}/${this.options.production ? "Production" : "Development"}`; 45 | 46 | this.gateways.register(new Gateway(this, "members", { schema: defaultMemberSchema })); 47 | } 48 | 49 | } 50 | 51 | module.exports = PenguClient; 52 | -------------------------------------------------------------------------------- /src/lib/structures/PenguGuild.js: -------------------------------------------------------------------------------- 1 | const { Structures } = require("discord.js"); 2 | const PenguMemberManager = require("./PenguMemberManager"); 3 | 4 | Structures.extend("Guild", Guild => { 5 | class KlasaGuild extends Guild { 6 | 7 | constructor(client, data) { 8 | // avoid double iteration by the super class populating the members collection 9 | const { members, ...restData } = data || {}; 10 | super(client, Object.keys(restData).length ? restData : undefined); 11 | 12 | this.members = new PenguMemberManager(this); 13 | if (members) for (const member of members) this.members.add(member); 14 | } 15 | 16 | } 17 | 18 | return KlasaGuild; 19 | }); 20 | -------------------------------------------------------------------------------- /src/lib/structures/PenguMember.js: -------------------------------------------------------------------------------- 1 | const { Structures } = require("discord.js"); 2 | 3 | module.exports = Structures.extend("GuildMember", GuildMember => { 4 | class KlasaMember extends GuildMember { 5 | 6 | constructor(...args) { 7 | super(...args); 8 | 9 | this.settings = this.client.gateways.get("members").acquire(this, `${this.guild.id}.${this.id}`); 10 | } 11 | 12 | toJSON() { 13 | return { ...super.toJSON(), settings: this.settings.toJSON() }; 14 | } 15 | 16 | } 17 | 18 | return KlasaMember; 19 | }); 20 | -------------------------------------------------------------------------------- /src/lib/structures/PenguMemberManager.js: -------------------------------------------------------------------------------- 1 | const { GuildMemberManager } = require("discord.js"); 2 | 3 | module.exports = class PenguMemberManager extends GuildMemberManager { 4 | 5 | async _fetchSingle(...args) { 6 | const member = await super._fetchSingle(...args); 7 | await member.settings.sync(); 8 | return member; 9 | } 10 | 11 | async _fetchMany(...args) { 12 | const members = await super._fetchMany(...args); 13 | await Promise.all(members.map(member => member.settings.sync())); 14 | return members; 15 | } 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/structures/schemas/defaultClientSchema.js: -------------------------------------------------------------------------------- 1 | const { KlasaClient } = require("klasa"); 2 | 3 | module.exports = KlasaClient.defaultClientSchema 4 | 5 | .add("pGuilds", "string", { array: true, configurable: false }) 6 | .add("counter", folder => folder 7 | .add("total", "integer") 8 | .add("commands", "any", { array: true })) 9 | 10 | .add("patrons", folder => folder 11 | .add("users", "user", { array: true, configurable: false }) 12 | .add("guilds", "guild", { array: true, configurable: false })); 13 | 14 | -------------------------------------------------------------------------------- /src/lib/structures/schemas/defaultMemberSchema.js: -------------------------------------------------------------------------------- 1 | const { Schema } = require("klasa"); 2 | 3 | module.exports = new Schema() 4 | 5 | // Profiles 6 | .add("xp", "integer", { default: 0, configurable: false }) 7 | .add("level", "integer", { default: 0, configurable: false }); 8 | -------------------------------------------------------------------------------- /src/lib/structures/schemas/defaultUserSchema.js: -------------------------------------------------------------------------------- 1 | const { KlasaClient } = require("klasa"); 2 | 3 | module.exports = KlasaClient.defaultUserSchema 4 | 5 | // Profiles 6 | .add("daily", "integer", { default: 0, configurable: false }) 7 | .add("xp", "integer", { default: 0, configurable: false }) 8 | .add("snowflakes", "integer", { default: 0, configurable: false }) 9 | .add("level", "integer", { default: 0, configurable: false }) 10 | .add("profilebg", "string", { default: "default", configurable: false }) 11 | .add("backgrounds", "string", { default: ["default"], array: true, configurable: false }) 12 | .add("reps", "integer", { default: 0, configurable: false }) 13 | .add("repcooldown", "integer", { default: 0, configurable: false }) 14 | .add("title", "string", { default: "No Title Set", configurable: false, min: 1, max: 30 }) 15 | .add("lastUpvote", "integer", { default: 0, configurable: false }) 16 | 17 | // AFK 18 | .add("afk", folder => folder 19 | .add("time", "integer", { configurable: false }) 20 | .add("reason", "string", { configurable: false })) 21 | 22 | // Patreon 23 | .add("patreon", folder => folder 24 | .add("paying", "boolean", { default: false, configurable: false }) 25 | .add("guilds", "guild", { array: true, configurable: false }) 26 | .add("pledged", "integer", { default: 0, configurable: false }) 27 | .add("current", "integer", { default: 0, configurable: false }) 28 | .add("tokens", "integer", { default: 0, configurable: false })); 29 | 30 | -------------------------------------------------------------------------------- /src/lib/tags/getjson.js: -------------------------------------------------------------------------------- 1 | const { util: { fetch } } = require("../../index"); 2 | 3 | module.exports = { 4 | name: "getjson", 5 | run: async ctx => { 6 | const [str, propPath] = ctx.value; 7 | const body = await fetch(str); 8 | if (!body) throw "No JSON found."; 9 | if (!propPath) return JSON.stringify(body); 10 | return getProp(body, propPath); 11 | } 12 | }; 13 | 14 | function getProp(body, prop) { 15 | if (prop === undefined) return body; 16 | const propParts = `${prop}`.split("."); 17 | let result = body, lastProp; 18 | while ((lastProp = propParts.shift()) !== undefined) { 19 | if (result[lastProp] === undefined) return undefined; 20 | result = result[lastProp]; 21 | } 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/tags/sendchannel.js: -------------------------------------------------------------------------------- 1 | const { Argument } = require("klasa"); 2 | 3 | module.exports = { 4 | name: "sendchannel", 5 | aliases: ["channelsend"], 6 | run: ctx => { 7 | const [id, message] = ctx.value; 8 | if (!id || !message) throw "You must provide a valid channel ID and content."; 9 | let channel; 10 | if (Argument.regex.channel.test(id)) { 11 | channel = ctx.guild.channels.cache.get(id); 12 | } else { 13 | channel = ctx.guild.channels.cache.find(chan => chan.name === id); 14 | } 15 | if (!channel || channel.type === "voice") throw "An invalid channel or channel type was specified."; 16 | if (!channel.postable) throw "I do not have permissions to send messages to that channel."; 17 | return channel.sendMessage(message); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const { ShardingManager } = require("kurasuta"); 2 | const { join } = require("path"); 3 | const config = require("../config.js"); 4 | const PenguClient = require("./lib/structures/PenguClient"); 5 | 6 | const status = "PenguBot.com/premium - p!help"; 7 | 8 | const sharder = new ShardingManager(join(__dirname, "PenguBot"), { 9 | token: config.token, 10 | client: PenguClient, 11 | clientOptions: { 12 | prefix: "p!", 13 | commandEditing: true, 14 | disableEveryone: true, 15 | regexPrefix: /^((?:Hey |Ok )?Pengu(?:,|!| ))/i, 16 | typing: false, 17 | pieceDefaults: { 18 | commands: { deletable: true, quotedStringSupport: true, bucket: 2 }, 19 | rawEvents: { enabled: true } 20 | }, 21 | providers: { 22 | default: "rethinkdb", 23 | rethinkdb: config.database 24 | }, 25 | console: { useColor: true }, 26 | production: config.production, 27 | presence: { activity: { name: status, type: "LISTENING" } }, 28 | prefixCaseInsensitive: true, 29 | noPrefixDM: true, 30 | aliasFunctions: { returnMethod: "run", enabled: true, prefix: "funcs" }, 31 | api: { 32 | port: 2006, 33 | prefix: "/" 34 | }, 35 | messageSweepInterval: 480, 36 | messageCacheLifetime: 120, 37 | commandMessageLifetime: 120, 38 | owners: ["136549806079344640"], 39 | music: { nodes: config.nodes, lyrics: config.apis.lyrics, spotify: { buffer: config.apis.spotify, token: "" } }, 40 | ws: { 41 | intents: ["GUILDS", "GUILD_MESSAGES", "GUILD_MEMBERS", "GUILD_BANS", "GUILD_VOICE_STATES", "GUILD_MESSAGE_REACTIONS", "DIRECT_MESSAGES", "DIRECT_MESSAGE_REACTIONS"] 42 | } 43 | }, 44 | shardCount: config.shards, 45 | ipcSocket: config.patreon ? 12168 : 12169, 46 | timeout: 60000 47 | }); 48 | 49 | sharder.spawn() 50 | .catch(console.error); 51 | -------------------------------------------------------------------------------- /src/middlewares/headers.js: -------------------------------------------------------------------------------- 1 | const { Middleware } = require("../index"); 2 | 3 | module.exports = class extends Middleware { 4 | 5 | constructor(...args) { 6 | super(...args, { priority: 10 }); 7 | } 8 | 9 | run(req, res) { 10 | res.setHeader("X-Content-Type-Options", "nosniff"); 11 | res.setHeader("Access-Control-Allow-Origin", "*"); 12 | res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); 13 | res.setHeader("Access-Control-Allow-Headers", "*"); 14 | 15 | const matches = /msie\s*(\d+)/i.exec(req.headers["user-agent"]); 16 | res.setHeader("X-XSS-Protection", !matches || (Number(matches[1]) >= 9) ? "1; mode=block" : "0"); 17 | 18 | if (req.method === "OPTIONS") return res.end("Something"); 19 | 20 | res.setHeader("Content-Type", "application/json"); 21 | return undefined; 22 | } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/middlewares/json.js: -------------------------------------------------------------------------------- 1 | const { Middleware } = require("../index"); 2 | const zlib = require("zlib"); 3 | 4 | module.exports = class extends Middleware { 5 | 6 | constructor(...args) { 7 | super(...args, { priority: 20 }); 8 | } 9 | 10 | async run(req) { 11 | if (req.method !== "POST") return; 12 | 13 | req.body = {}; 14 | 15 | const stream = this.contentStream(req); 16 | let body = ""; 17 | 18 | for await (const chunk of stream) body += chunk; 19 | 20 | try { 21 | req.body = JSON.parse(body); 22 | } catch (noop) { 23 | // Yeah nah 24 | } 25 | } 26 | 27 | contentStream(req) { 28 | const length = req.headers["content-length"]; 29 | let stream; 30 | switch ((req.headers["content-encoding"] || "identity").toLowerCase()) { 31 | case "deflate": 32 | stream = zlib.createInflate(); 33 | req.pipe(stream); 34 | break; 35 | case "gzip": 36 | stream = zlib.createGunzip(); 37 | req.pipe(stream); 38 | break; 39 | case "identity": 40 | stream = req; 41 | stream.length = length; 42 | break; 43 | } 44 | return stream; 45 | } 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /src/monitors/afk.js: -------------------------------------------------------------------------------- 1 | const { Monitor } = require("../index"); 2 | 3 | module.exports = class extends Monitor { 4 | 5 | constructor(...args) { 6 | super(...args, { ignoreOthers: false }); 7 | } 8 | 9 | async run(msg) { 10 | if (!msg.guild || !msg.channel || !msg.channel.postable) return; 11 | 12 | if (msg.author.settings.get("afk.time")) await this.checkAfk(msg); 13 | if (msg.mentions.users.size) await this.afkMentioned(msg); 14 | } 15 | 16 | async checkAfk(msg) { 17 | await msg.author.settings.reset(["afk.time", "afk.reason"]); 18 | 19 | const message = await msg.sendLocale("MONITOR_AFK_REMOVED", [msg.author.username]); 20 | return message.delete({ timeout: 10000, reason: "Pengubot AFK Feature" }).catch(() => null); 21 | } 22 | 23 | async afkMentioned(msg) { 24 | const mentioned = msg.mentions.users.first(); 25 | 26 | const afkTime = mentioned.settings.get("afk.time"); 27 | if (!afkTime) return; 28 | 29 | const afkReason = mentioned.settings.get("afk.reason"); 30 | return msg.sendLocale("MONITOR_AFK_ISAFK", [mentioned.username, afkReason, afkTime]); 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/monitors/antiinvites.js: -------------------------------------------------------------------------------- 1 | const { Monitor, ServerLog } = require("../index"); 2 | const inviteRegex = /(https?:\/\/)?(www\.)?(discord\.(gg|li|me|io)|(discordapp|discord)\.com\/invite|invite\.gg)\/.+/; 3 | 4 | module.exports = class extends Monitor { 5 | 6 | constructor(...args) { 7 | super(...args, { 8 | ignoreBots: false, 9 | ignoreSelf: true, 10 | ignoreOthers: false 11 | }); 12 | } 13 | 14 | async run(msg) { 15 | if (!msg.guild || !msg.guild.settings.get("automod.invites")) return; 16 | if (this.client.user.id !== "303181184718995457" && await msg.guild.members.fetch("303181184718995457").catch(() => null)) return; 17 | 18 | if (msg.guild.settings.get("toggles.staffbypass") && await msg.hasAtLeastPermissionLevel(3)) return; 19 | 20 | if (!inviteRegex.test(msg.content)) return; 21 | 22 | const deleted = await msg.delete().catch(() => null); 23 | if (!deleted) return; 24 | await new ServerLog(msg.guild) 25 | .setColor("red") 26 | .setType("automod") 27 | .setName("Automod - Invite Deleted") 28 | .setAuthor(`${msg.author.tag} in #${msg.channel.name}`, msg.author.displayAvatarURL()) 29 | .setMessage(`**Content:**\n${msg.content}`) 30 | .send(); 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/monitors/perspectivemod.js: -------------------------------------------------------------------------------- 1 | const { Monitor, ServerLog, config } = require("../index"); 2 | 3 | module.exports = class extends Monitor { 4 | 5 | constructor(...args) { 6 | super(...args, { ignoreOthers: false }); 7 | } 8 | 9 | async run(msg) { 10 | if (!msg.guild || !msg.content || msg.command) return; 11 | if (!msg.guild.settings.get("toggles.perspective")) return; 12 | 13 | if (msg.guild.settings.get("toggles.staffbypass") && await msg.hasAtLeastPermissionLevel(3)) return; 14 | 15 | const body = await this.fetchURL("https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze", { 16 | query: { key: config.apis.perspective }, 17 | headers: { "Content-Type": "application/json" }, 18 | method: "POST", 19 | body: JSON.stringify({ 20 | comment: { text: msg.content }, 21 | requestedAttributes: { SEVERE_TOXICITY: {}, TOXICITY: {}, OBSCENE: {}, THREAT: {}, SEXUALLY_EXPLICIT: {}, SPAM: {}, PROFANITY: {} } 22 | }) 23 | }).catch(() => null); 24 | 25 | if (!body) return; 26 | 27 | const perspectiveMap = msg.guild.settings.get("automod.perspective"); 28 | const perspective = Object.fromEntries(perspectiveMap); 29 | 30 | for (const key of Object.keys(body.attributeScores)) { 31 | if (!perspective[key].enabled) continue; 32 | if (body.attributeScores[key].summaryScore.value >= perspective[key].threshold) { 33 | await msg.delete().catch(() => null); 34 | await new ServerLog(msg.guild) 35 | .setColor("red") 36 | .setType("automod") 37 | .setName(`Automod - Perspective | ${key}`) 38 | .setAuthor(`${msg.author.tag} in #${msg.channel.name}`, msg.author.displayAvatarURL()) 39 | .setMessage(`**Content:**\n${msg.content}`) 40 | .send(); 41 | } 42 | } 43 | } 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /src/routes/application.js: -------------------------------------------------------------------------------- 1 | const { Route, Duration } = require("../index"); 2 | 3 | module.exports = class extends Route { 4 | 5 | constructor(...args) { 6 | super(...args, { route: "application" }); 7 | } 8 | 9 | async get(request, response) { 10 | let [users, guilds, channels, memory, vc, cpm] = [0, 0, 0, 0, 0, 0]; 11 | 12 | const results = await this.client.shard.broadcastEval(`[this.guilds.cache.reduce((prev, val) => val.memberCount + prev, 0), this.guilds.cache.size, this.channels.cache.size, (process.memoryUsage().heapUsed / 1024 / 1024), this.lavalink.players.size, this.health.commands.cmdCount[59].count]`); // eslint-disable-line max-len 13 | for (const result of results) { 14 | users += result[0]; 15 | guilds += result[1]; 16 | channels += result[2]; 17 | memory += result[3]; 18 | vc += result[4]; 19 | cpm += result[5]; 20 | } 21 | 22 | return response.end(JSON.stringify({ 23 | users: users, 24 | guilds: guilds, 25 | channels: channels, 26 | shards: this.client.options.shardCount, 27 | uptime: Duration.toNow(Date.now() - (process.uptime() * 1000)), 28 | latency: this.client.ws.ping.toFixed(0), 29 | memory: memory, 30 | voice: vc, 31 | cmdstotal: this.client.settings.get("counter.total"), 32 | cpm: cpm, 33 | invite: this.client.invite, 34 | ...this.client.application 35 | })); 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /src/routes/dblHook.js: -------------------------------------------------------------------------------- 1 | const { Route, config } = require("../index"); 2 | 3 | module.exports = class extends Route { 4 | 5 | constructor(...args) { 6 | super(...args, { 7 | route: "votes/dbl" 8 | }); 9 | } 10 | 11 | async post(req, res) { 12 | if (req.headers.authorization !== config.apis.dbl) { 13 | res.statusCode = 401; 14 | return res.end(JSON.stringify({ message: "Unauthenticated" })); 15 | } 16 | 17 | const data = req.body; 18 | 19 | const user = await this.client.users.fetch(data.user).catch(() => null); 20 | if (!user) { 21 | res.statusCode = 404; 22 | return res.end(JSON.stringify({ message: "User not found" })); 23 | } 24 | 25 | await user.settings.sync(true); 26 | let amount = this.client.funcs.randomNumber(100, 200); 27 | 28 | if (data.isWeekend) amount *= 2; 29 | if (user && user.send) user.send(`<:penguSuccess:435712876506775553> ***Thank you for Upvoting PenguBot on DiscordBots.org, you've recieved ❄ \`${amount}\` Snowflakes as a bonus! You can do this again after 12 hours at . You can use these Snowflakes to play games, give them to other people, buy profile backgrounds or save up for upcoming features!***\n\n**Tip: **\`Voting on Weekends will give you double reward than usual so don't forget to upvote then as well!\``).catch(() => null); 30 | await user.settings.update([["snowflakes", user.settings.get("snowflakes") + amount], ["lastUpvote", Date.now()]]); 31 | 32 | res.statusCode = 200; 33 | return res.end(JSON.stringify({ message: "Successful" })); 34 | } 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /src/routes/kdhGuild.js: -------------------------------------------------------------------------------- 1 | const { Route } = require("../index"); 2 | 3 | module.exports = class extends Route { 4 | 5 | constructor(...args) { 6 | super(...args, { route: "guild/:id" }); 7 | } 8 | 9 | async get(request, response) { 10 | const { id } = request.params; 11 | if (!id) { 12 | response.statusCode = 400; 13 | return response.end(JSON.stringify({ message: "No id provided" })); 14 | } 15 | 16 | const guild = await this.client.shard.fetchGuild(id) 17 | .catch(() => null); 18 | 19 | if (!guild) { 20 | response.statusCode = 404; 21 | return response.end(JSON.stringify({ message: "Guild not found" })); 22 | } 23 | 24 | response.statusCode = 200; 25 | return response.end(JSON.stringify(guild)); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/routes/pieces.js: -------------------------------------------------------------------------------- 1 | const { Route } = require("../index"); 2 | 3 | module.exports = class extends Route { 4 | 5 | constructor(...args) { 6 | super(...args, { route: "pieces/:type/:name" }); 7 | } 8 | 9 | get(request, response) { 10 | const { type, name } = request.params; 11 | const store = this.client.pieceStores.get(type); 12 | if (!store) response.end("[]"); 13 | if (name === "all") return response.end(JSON.stringify(store.array())); 14 | const piece = store.get(name); 15 | if (!piece) return response.end("{}"); 16 | return response.end(JSON.stringify(piece)); 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/routes/syncdb.js: -------------------------------------------------------------------------------- 1 | const { Route } = require("../index"); 2 | const config = require("../../config.js"); 3 | 4 | module.exports = class extends Route { 5 | 6 | constructor(...args) { 7 | super(...args, { route: "syncdb/:type/:id" }); 8 | } 9 | 10 | async get(request, response) { 11 | if (!request.headers.authorization || request.headers.authorization !== config.dashboard.internalSecret) { 12 | response.statusCode = 401; 13 | return response.end(JSON.stringify({ success: false, body: "Not Authorized" })); 14 | } 15 | 16 | const { type, id } = request.params; 17 | if (!type || !id) { 18 | response.statusCode = 400; 19 | return response.end(JSON.stringify({ success: false, body: "No Type or ID Provided" })); 20 | } 21 | 22 | if (type === "server") { 23 | const guild = await this.client.shard.broadcastEval(`this.guilds.cache.get("${id}") ? this.guilds.cache.get("${id}").settings.sync(true) : null`) 24 | .catch(() => null); 25 | 26 | if (!guild || !guild.length || !guild.filter(u => u !== null)) { 27 | response.statusCode = 500; 28 | return response.end(JSON.stringify({ success: false, body: "Server Error" })); 29 | } 30 | 31 | return response.end(JSON.stringify({ success: true, body: "Sync has been commissioned." })); 32 | } else if (type === "user") { 33 | const user = await this.client.shard.broadcastEval(`this.users.cache.get("${id}") ? this.users.cache.get("${id}").settings.sync(true) : null`) 34 | .catch(() => null); 35 | 36 | if (!user || !user.length || !user.filter(u => u !== null)) { 37 | response.statusCode = 500; 38 | return response.end(JSON.stringify({ success: false, body: "Server Error" })); 39 | } 40 | 41 | return response.end(JSON.stringify({ success: true, body: "Sync has been commissioned." })); 42 | } else { 43 | response.statusCode = 400; 44 | return response.end(JSON.stringify({ success: false, body: "Invalid Request" })); 45 | } 46 | } 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /src/tasks/datadog.js: -------------------------------------------------------------------------------- 1 | const { Task } = require("../index"); 2 | 3 | module.exports = class MemorySweeper extends Task { 4 | 5 | async run() { 6 | if (!this.client.ready) return; 7 | let [users, guilds, vc, cpm] = [0, 0, 0, 0]; 8 | const results = await this.client.shard.broadcastEval(`[this.guilds.cache.reduce((prev, val) => val.memberCount + prev, 0), this.guilds.cache.size, this.music.filter(music => music.playing).size, this.health.commands.cmdCount[59].count]`); 9 | 10 | for (const result of results) { 11 | users += result[0]; 12 | guilds += result[1]; 13 | vc += result[2]; 14 | cpm += result[3]; 15 | } 16 | 17 | this.client.dogstats.gauge("pengubot.totalcommands", this.client.settings.get("counter.total")); 18 | this.client.dogstats.gauge("pengubot.users", users); 19 | this.client.dogstats.gauge("pengubot.cpm", cpm); 20 | this.client.dogstats.gauge("pengubot.guilds", guilds); 21 | this.client.dogstats.gauge("pengubot.voicestreams", vc); 22 | } 23 | 24 | init() { 25 | if (this.client.user.id !== "303181184718995457" || this.client.shard.id !== 0) return this.disable(); 26 | } 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/tasks/reminder.js: -------------------------------------------------------------------------------- 1 | const { Task } = require("../index"); 2 | 3 | module.exports = class extends Task { 4 | 5 | async run({ channel, user, text }) { 6 | const _channel = this.client.channels.fetch(channel).catch(() => null); 7 | const _user = await this.client.users.fetch(user).catch(() => null); 8 | 9 | if (_user) return _user.send(`⏰ **Reminder:** ${text}`).catch(() => null); 10 | if (_channel) return _channel.send(`📘 | <@${user}>, **Reminder:** ${text}`).catch(() => null); 11 | } 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /src/tasks/stats.js: -------------------------------------------------------------------------------- 1 | const { Task, config } = require("../index"); 2 | 3 | module.exports = class extends Task { 4 | 5 | async run() { 6 | if (this.client.user.id !== "303181184718995457" || this.client.shard.id !== 0) return; 7 | if (!this.client.ready) return; 8 | 9 | let [guilds, vc, users] = [0, 0, 0]; 10 | const scount = this.client.shard.shardCount; 11 | const results = await this.client.shard.broadcastEval(`[this.guilds.cache.reduce((prev, val) => val.memberCount + prev, 0), this.guilds.cache.size, this.music.filter(music => music.playing).size]`); 12 | for (const result of results) { 13 | users += result[0]; 14 | guilds += result[1]; 15 | vc += result[2]; 16 | } 17 | 18 | return this.fetchURL("https://server.pengubot.com/bot/statposting", { 19 | method: "POST", 20 | headers: { authorization: config.apis.pengu, "Content-Type": "application/json" }, 21 | body: JSON.stringify({ servers: guilds, shards: scount, voice: vc, users: users }) 22 | }); 23 | } 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/tasks/tempMute.js: -------------------------------------------------------------------------------- 1 | const { Task } = require("klasa"); 2 | const ModLog = require("../lib/structures/ModLog"); 3 | 4 | module.exports = class extends Task { 5 | 6 | async run({ guildID, userID }) { 7 | const guild = this.client.guilds.cache.get(guildID); 8 | const member = await guild.members.fetch(userID).catch(() => null); 9 | if (!guild || !member) return; 10 | 11 | const roleID = guild.settings.get("roles.muted"); 12 | const role = await guild.roles.cache.get(roleID); 13 | 14 | if (!role) return; 15 | const myRole = guild.me.roles.highest; 16 | if (role.position > myRole.positon) return; 17 | 18 | const unmute = await member.roles.remove(role).catch(() => null); 19 | 20 | if (!unmute) return; 21 | 22 | if (guild.settings.get("channels.modlogs")) { 23 | await new ModLog(guild) 24 | .setType("unmute") 25 | .setModerator(this.client.user) 26 | .setReason("Timed Mute Limit Over") 27 | .setUser(member.user) 28 | .send(); 29 | } 30 | } 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /src/tasks/timedBan.js: -------------------------------------------------------------------------------- 1 | const { Task } = require("klasa"); 2 | const ModLog = require("../lib/structures/ModLog"); 3 | 4 | module.exports = class extends Task { 5 | 6 | async run({ guildID, userID }) { 7 | const guild = this.client.guilds.cache.get(guildID); 8 | const user = await this.client.users.fetch(userID).catch(() => null); 9 | if (!guild || !user) return; 10 | 11 | const unban = await guild.members.unban(user).catch(() => null); 12 | if (!unban) return; 13 | 14 | if (guild.settings.get("channels.modlogs")) { 15 | await new ModLog(guild) 16 | .setType("unban") 17 | .setModerator(this.client.user) 18 | .setReason("Timed Ban Limit Over") 19 | .setUser(user) 20 | .send(); 21 | } 22 | } 23 | 24 | }; 25 | --------------------------------------------------------------------------------