├── .circleci └── config.yml ├── .eslintrc.json ├── .github ├── FUNDING.yml ├── stale.yml └── workflows │ ├── codeql-analysis.yml │ └── stale.yml ├── .gitignore ├── CHANGELOGS.md ├── CODE_OF_CONDUCT.md ├── Cards.js ├── LICENSE ├── README.md ├── botconfig.json copy.exemple ├── commandhandler file exemple.txt ├── commands ├── dev │ └── eval.js ├── info │ ├── addcard.js │ ├── botInfo.js │ ├── game.js │ ├── help.js │ ├── invit.js │ ├── lbtop10.js │ ├── ping.js │ ├── rank.js │ ├── reddit.js │ ├── serverinfo.js │ ├── uptime.js │ ├── whois.js │ ├── wink.js │ └── wow.js ├── moderation │ ├── ban.js │ ├── clear.js │ ├── kick.js │ ├── mute.js │ └── say.js └── music │ ├── join.js │ ├── leave.js │ ├── pause.js │ ├── play.js │ ├── queue.js │ ├── resume.js │ ├── skip.js │ └── volume.js ├── deploy-commands.js ├── events ├── disconnect.js ├── guildMemberAdd.js ├── guildMemberRemove.js ├── interactionCreate.js ├── messageCreate.js ├── ready.js └── reconnecting.js ├── function.js ├── handler └── command.js ├── index.js ├── model ├── card.js └── xp.js ├── package.json └── slash └── commands └── ping.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # JavaScript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:7.10 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mongo:3.4.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - checkout 21 | 22 | # Download and cache dependencies 23 | - restore_cache: 24 | keys: 25 | - v1-dependencies-{{ checksum "package.json" }} 26 | # fallback to using the latest cache if no exact match is found 27 | - v1-dependencies- 28 | 29 | - run: npm install 30 | - run: mv botconfig.json.exemple botconfig.json 31 | 32 | - save_cache: 33 | paths: 34 | - node_modules 35 | key: v1-dependencies-{{ checksum "package.json" }} 36 | 37 | # run tests! 38 | - run: npm start 39 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2019 9 | }, 10 | "rules": { 11 | "brace-style": ["warn", "stroustrup", { "allowSingleLine": true }], 12 | "comma-dangle": ["warn", "always-multiline"], 13 | "comma-spacing": "warn", 14 | "comma-style": "warn", 15 | "curly": ["warn", "multi-line", "consistent"], 16 | "dot-location": ["warn", "property"], 17 | "handle-callback-err": "off", 18 | "indent": ["warn", "tab"], 19 | "max-nested-callbacks": ["warn", { "max": 4 }], 20 | "max-statements-per-line": ["warn", { "max": 2 }], 21 | "no-console": "off", 22 | "no-empty-function": "warn", 23 | "no-floating-decimal": "warn", 24 | "no-inline-comments": "warn", 25 | "no-inner-declarations": "off", 26 | "no-lonely-if": "warn", 27 | "no-multi-spaces": "warn", 28 | "no-multiple-empty-lines": ["warn", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], 29 | "no-shadow": ["warn", { "allow": ["err", "resolve", "reject"] }], 30 | "no-trailing-spaces": ["warn"], 31 | "no-var": "warn", 32 | "object-curly-spacing": ["warn", "always"], 33 | "prefer-const": "warn", 34 | "quotes": ["warn", "double"], 35 | "semi": ["warn", "always"], 36 | "space-before-blocks": "warn", 37 | "space-before-function-paren": ["warn", { 38 | "anonymous": "never", 39 | "named": "never", 40 | "asyncArrow": "always" 41 | }], 42 | "space-in-parens": "warn", 43 | "space-infix-ops": "warn", 44 | "space-unary-ops": "warn", 45 | "spaced-comment": "warn", 46 | "yoda": "warn" 47 | } 48 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: Asthriona 4 | ko_fi: Asthriona 5 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 7 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 5 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: true 18 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "dev" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "dev" ] 20 | schedule: 21 | - cron: '26 19 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "30 1 * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v1 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | stale-issue-message: 'Stale issue message' 17 | stale-pr-message: 'Stale pull request message' 18 | stale-issue-label: 'no-issue-activity' 19 | stale-pr-label: 'no-pr-activity' 20 | -------------------------------------------------------------------------------- /.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 (https://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 | # next.js build output 61 | .next 62 | 63 | botconfig.json 64 | .env 65 | ./node_modules 66 | 67 | package-lock.json 68 | 69 | test.js 70 | IbeatYou.js 71 | createinvite.js 72 | commands/dev/fetch.js 73 | commands/dev/create.js 74 | package-lock.json 75 | -------------------------------------------------------------------------------- /CHANGELOGS.md: -------------------------------------------------------------------------------- 1 | # Change Logs 2 | Cette page me sert a noter l'avancement du bot au file des mise a jours, j'y note tout les Add, les bug fix (réparation de bug), les supressions, et modification. 3 | 4 | # 1.0 5 | ## ***It's alive!*** 6 | + Add ban 7 | + Add kick 8 | + Add Mute 9 | + Add warn 10 | + Add report 11 | + Add ping 12 | + Add Présence personalisé 13 | + Add help (WIP) 14 | + Add help-commands (WIP) 15 | + Add help-game (WIP) 16 | + Add uptime 17 | + Add Clear (1 - 100) 18 | 19 | # 1.0.1 20 | ## ***[OwO]?*** 21 | + Fix: permission warn/unwarn 22 | + Fix: Erreur Ban sans raison 23 | + Fix: Erreur Kick sans raison 24 | + Fix: Permission command Watch, Play, stream 25 | + Edit: changed the link of a!help commands 26 | + Edit: Traduction francaise a!server-info 27 | + Edit: Traduction francaise a!info 28 | + Update: Change logs 29 | + Deleted: Weebness de Ash. 30 | 31 | # 1.1.0 32 | ## ***[UwU Music? OwO]*** 33 | + add: Music module [BETA] used with a!play a!skip a!stop 34 | + Edit: a!play has been changed to /game 35 | + Update: Change logs 36 | + deleted: Weebness de Ash. 37 | ## 1.1.1 38 | + Add: Queue system 39 | ## 1.1.2 40 | + Add: Better youtube support 41 | ## 1.1.3 42 | + Add: System play/pause 43 | + Add: volume commands 44 | + Add: Send music title when playing 45 | + Add: Now Playing command 46 | ## 1.1.4 47 | + Add: a!play now support playlists 48 | + Add: a!play now support youtube search 49 | + Add: Server Info 50 | + Add: User info 51 | + Update: Change logs 52 | + Deleted: Weebness de Ash. 53 | ## 2.0.0 [i'm Back to rules them all!] 54 | + Bot completely rewrited. 55 | + deleted: Mute commands [Temp] 56 | + Add: better commands handler 57 | + Add: a!animeFM is now playing [AnimeFM](https://Animefm.co) Main station 58 | + Update: Dynamic help commands 59 | + Update: a!help can now take argument like a command name to get more information on the commands. 60 | 61 | 62 | ### Bug 63 | + Warn reason can't contain only one word (fix in progress) 64 | + Uptime command is using his own time system. 65 | 66 | 67 | ## Road-Map 68 | + Custom rank cards -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at im@asthriona.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Cards.js: -------------------------------------------------------------------------------- 1 | const { MessageAttachment } = require("discord.js"); 2 | const { getMember } = require("./function"); 3 | const Canvas = require("canvas"); 4 | const Cards = require("./model/card"); 5 | 6 | module.exports = { 7 | // Level up image 8 | async lvlupimg(message, users) { 9 | const applyText = (canvas, text) => { 10 | const ctx = canvas.getContext("2d"); 11 | let fontSize = 70; 12 | do { 13 | ctx.font = `${fontSize -= 10}px sans-serif`; 14 | } while (ctx.measureText(text).width > canvas.width - 300); 15 | return ctx.font; 16 | }; 17 | const canvas = Canvas.createCanvas(934, 282); 18 | const ctx = canvas.getContext("2d"); 19 | Cards.findOne({ 20 | did: message.author.id, 21 | }, async (err, cards)=>{ 22 | const cardbg = cards.link; 23 | const member = getMember(message); 24 | const background = await Canvas.loadImage(cardbg); 25 | ctx.drawImage(background, 0, 0, canvas.width, canvas.height); 26 | // Draw rectangle 27 | ctx.beginPath(); 28 | ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; 29 | ctx.fillRect(260, 80, 650, 160); 30 | ctx.closePath(); 31 | ctx.stroke(); 32 | // show Username 33 | ctx.font = applyText(canvas, member.displayName); 34 | ctx.fillStyle = "#fff"; 35 | ctx.fillText(member.displayName + " Level up!", 280, 136); 36 | // Show Level & XP 37 | const nxtlvl = 300 * Math.pow(2, users.level); 38 | const xpleft = nxtlvl - users.xp; 39 | ctx.font = "40px sans-serif"; 40 | ctx.fillStyle = "#fff"; 41 | ctx.fillText("You are level now " + users.level + " - " + users.xp + " XP", 280, 180); 42 | // xp Left 43 | ctx.font = "50px sans-serif"; 44 | ctx.fillStyle = "#fff"; 45 | ctx.fillText("Next Level in " + xpleft + " xp", 280, 225); 46 | // Get avatar 47 | const avatar = await Canvas.loadImage(message.author.displayAvatarURL({ format: "jpg" })); 48 | ctx.beginPath(); 49 | ctx.arc(125, 140, 100, 0, Math.PI * 2); 50 | ctx.closePath(); 51 | ctx.clip(); 52 | ctx.drawImage(avatar, 25, 40, 200, 200); 53 | // put image together and send it 54 | const lvlupimg = new MessageAttachment(canvas.toBuffer(), "lvlup-image.png"); 55 | message.channel.send(lvlupimg); 56 | }); 57 | }, 58 | 59 | // Welcome Cards 60 | async WelcomeCad(member, channel) { 61 | const applyText = (canvas, text) => { 62 | const ctx = canvas.getContext("2d"); 63 | let fontSize = 70; 64 | do { 65 | ctx.font = `${fontSize -= 10}px sans-serif`; 66 | } while (ctx.measureText(text).width > canvas.width - 300); 67 | return ctx.font; 68 | }; 69 | Cards.findOne({ 70 | did: member.user.id, 71 | }, async (err, cards)=>{ 72 | const canvas = Canvas.createCanvas(934, 282); 73 | const ctx = canvas.getContext("2d"); 74 | const cardbg = cards.link; 75 | const background = await Canvas.loadImage(cardbg); 76 | ctx.drawImage(background, 0, 0, canvas.width, canvas.height); 77 | ctx.beginPath(); 78 | ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; 79 | ctx.fillRect(260, 80, 650, 130); 80 | ctx.stroke(); 81 | // get username 82 | ctx.font = applyText(canvas, member.user.username); 83 | ctx.fillStyle = "#fff"; 84 | ctx.fillText(member.user.username, 280, 141); 85 | // Get guild name 86 | ctx.font = applyText(canvas, member.guild.name); 87 | ctx.fillStyle = "#fff"; 88 | ctx.fillText("Joined the server! ", 280, 195); 89 | // Get avatar 90 | const avatar = await Canvas.loadImage(member.user.displayAvatarURL({ format: "jpg" })); 91 | ctx.beginPath(); 92 | ctx.arc(140, 128, 110, 0, Math.PI * 2); 93 | ctx.closePath(); 94 | ctx.clip(); 95 | ctx.drawImage(avatar, 25, 15, 256, 256); 96 | const attachment = new MessageAttachment(canvas.toBuffer(), "welcome-image.png"); 97 | channel.send(`Welcome ${member.user}`, attachment); 98 | }); 99 | }, 100 | // Farewell Cards 101 | async farewell(member, channel) { 102 | const applyText = (canvas, text) => { 103 | const ctx = canvas.getContext("2d"); 104 | let fontSize = 70; 105 | do { 106 | ctx.font = `${fontSize -= 10}px sans-serif`; 107 | } while (ctx.measureText(text).width > canvas.width - 300); 108 | return ctx.font; 109 | }; 110 | Cards.findOne({ 111 | did: member.user.id, 112 | }, async (err, cards) =>{ 113 | if(err) return console.log(err); 114 | const canvas = Canvas.createCanvas(934, 282); 115 | const ctx = canvas.getContext("2d"); 116 | const background = await Canvas.loadImage(cards.link); 117 | ctx.drawImage(background, 0, 0, canvas.width, canvas.height); 118 | ctx.beginPath(); 119 | ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; 120 | ctx.fillRect(260, 80, 650, 130); 121 | ctx.stroke(); 122 | // get username 123 | ctx.font = applyText(canvas, member.user.username); 124 | ctx.fillStyle = "#fff"; 125 | ctx.fillText(member.user.username, 280, 141); 126 | // Get guild name 127 | ctx.font = applyText(canvas, member.guild.name); 128 | ctx.fillStyle = "#fff"; 129 | ctx.fillText("Left the server! ", 280, 195); 130 | // Get avatar 131 | const avatar = await Canvas.loadImage(member.user.displayAvatarURL({ format: "jpg" })); 132 | ctx.beginPath(); 133 | ctx.arc(140, 128, 110, 0, Math.PI * 2); 134 | ctx.closePath(); 135 | ctx.clip(); 136 | ctx.drawImage(avatar, 25, 15, 256, 256); 137 | const attachment = new MessageAttachment(canvas.toBuffer(), "farewell-image.png"); 138 | channel.send(attachment); 139 | }); 140 | }, 141 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Asthriona 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PROJECT NO LONGER SUPPORTED! 2 | As Yukiko 2.0 (Closed sources) grow I don't have much time to work and update this version. if you need a great bot to help with your Discord guilds please use [Yukiko.app](https://Yukiko.app) 3 | 4 | [![Discord Bots](https://top.gg/api/widget/status/641626560457342987.svg)](https://top.gg/bot/641626560457342987) 5 | 6 | ## Edit (21/04/21) 7 | You are a lot to still star this thing so I updated it, should be working fine now, and updated to djs 12 and better music system. I didnt put as much work or code quality than on Yukiko.app but its working. You are very welcome :) 8 | 9 | # Yukiko 10 | Yukiko is a powerfull Discord bot that include XP system, Leaderboard, Music, Welcome and farewell message, Moderation, and much more! 11 | 12 | This bot is in developement state and actively updated, Feel free to come back take a look to our change logs! 13 | 14 | 15 | # I want to use it! 16 | Nice! Let me help you! 17 | ### I don't want / don't know how to host it. 18 | In that case feel free to add the Official Yukiko bot to your Discord server via this [Check on our website to invite Yukiko](https://yukiko.app/) to your server! 19 | 20 | ### I want to host it myself! 21 | Okay cool! you save me few bucks for the hosting :3 22 | Here is the tutorial on how to install and configure the bot! 23 | 24 | # Install 25 | To install and use this bot you need few things first. 26 | ## If you are on debian/ubuntu 27 | ``` 28 | curl -fsSL https://deb.nodesource.com/setup_14.x | bash - 29 | apt-get install -y nodejs 30 | apt install build-essential 31 | ``` 32 | ## for Windows: 33 | Install nodeJS from this [link](https://nodejs.org/en/) 34 | Open a powershell in admin mode `win+x` 35 | You can install gitbash or download the code via [this link](https://github.com/Asthriona/Yukiko/archive/master.zip) 36 | ``` 37 | npm install --global windows-build-tools 38 | ``` 39 | Then your system should be ready. 40 | ``` 41 | git clone https://github.com/Asthriona/Yukiko.git 42 | cd Yukiko 43 | npm install 44 | npm run start 45 | ``` 46 | For Linux you should install "screen" package to be able to keep the bot running in the background. you can also use [PM2](https://pm2.io/) 47 | 48 | # Lavalink 49 | I switched the Music bot to Lavalink and Erela.js for practical reasons (Youtube-DL was a pain to set up in the code and require a lot of ressources.) 50 | Please find [Lavalink](https://github.com/freyacodes/Lavalink-Client) on the Author repo and follow their install instruction (Don't worry thats very easy.) 51 | ## Update 52 | The author changed their name to Freyacodes and someone else too their old name, if you google 'Lavalink' you'll find the old name repo, Follow the link upthere to get the right one. 53 | The [Yukiko Dev Team](https://github.com/Yukiko-Dev-Team) forked it you can follow that link too. 54 | 55 | # Configuration 56 | Yukiko's configuration is pretty simple. 57 | You need a MongoDB database, and a Discord bot 58 | [Discord Developper portal](https://discordapp.com/developers/applications/) 59 | [Free mongoDB Database Culsters](https://www.mongodb.com/cloud/atlas) 60 | 61 | copy the exemple file 62 | ``` 63 | cp botconfig.json.exemple botconfig.json 64 | ``` 65 | `token` is your Discord bot token 66 | `prefix` a! by default you can change it for whatever you want. 67 | `dbLink` The login link of your database. 68 | 69 | # Official Discord Server. 70 | For now Yukiko don't have any public place. Just a nice little home called "Dev Bot Zone." This is a private server dedicated to my developement bot. 71 | If you want to contact me to get some help, or having an idea, please feel free to open an issue, or contact me on Twitter [@Asthriona](https://twitter.com/Asthriona) 72 | for bug report, please open an issue, and give me all the information you have! 73 | (She have very quite room mate, one of them is a [wall](https://github.com/Asthriona/TheWallDiscordBot)!) 74 | ![devServer](https://asthriona.s3.fr-par.scw.cloud/ShareX/2021/05/Discord_020521-011537AM.png) 75 | 76 | # Modification 77 | You can modify the bos as you pleased. But you have to credit me, and my collaborator. 78 | Please leave the credit in the "bot info" commands. 79 | 80 | # Help me 81 | Hi, I'am [Asthriona](https://Asthriona.com) Full time WoW player, and some kind of developper. i'm doing stuff on internet for quite a long time... a decade now, and I love making stuff that can be usefull or help other. 82 | But if you want to help me, Feel free to take a look at the code, Create issue for idea/bugs, or pull request. 83 | 84 | As I said, i'm full time doing this, and now days, being indie developper don't really pay the bills (not even talking about server bill.), so if you really want to help, and have some bucks to spare, Feel free to pay me a ko-fi 85 | 86 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/C0C61FCVH) 87 | 88 | Thanks for your interest in Yukiko! <3 89 | -------------------------------------------------------------------------------- /botconfig.json copy.exemple: -------------------------------------------------------------------------------- 1 | { 2 | "token": "Bot tokken", 3 | "prefix": "a!", 4 | "dbLink": "mongodb://yukiko:127.0.0.1", 5 | "lavaHost": "localhost", 6 | "lavaPort": "2333", 7 | "lavaPasswd": "youshallnotpass" 8 | } 9 | -------------------------------------------------------------------------------- /commandhandler file exemple.txt: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: " ", 3 | category: "info", 4 | description: " ", 5 | run: async (bot, message, args) => { 6 | message.channel.send(`POG`) 7 | } 8 | } -------------------------------------------------------------------------------- /commands/dev/eval.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const beautify = require("beautify"); 3 | const Config = require("../../botconfig.json"); 4 | module.exports = { 5 | name: "eval", 6 | category: "dev", 7 | description: "Run some code directly in discord! (developper only!)", 8 | run: async (bot, message, args) => { 9 | if(!Config.owners.includes(message.author.id)) return message.reply("You are not a developper! you can't run code just like that!"); 10 | if(!args[0]) return message.channel.send("Please gimme some good code!"); 11 | 12 | try { 13 | if(args.join(" ").toLowerCase().includes("token")) { 14 | return message.channel.send("No, I'm not gonna give you my token! Nice try tho!"); 15 | } 16 | const toEval = args.join(" "); 17 | const evaluated = eval(toEval); 18 | 19 | const embed = new MessageEmbed() 20 | .setColor("PURPLE") 21 | .setTimestamp() 22 | .setFooter(bot.user.username, bot.user.displayAvatarURL()) 23 | .setTitle("Elva") 24 | .addField("To Evaluate:", `\`\`\`js\n${beautify(args.join(" "), { format: "js" })}\n\`\`\``) 25 | .addField("Evaluated:", evaluated) 26 | .addField("Type of:", typeof (evaluated)); 27 | 28 | message.channel.send({ embeds: [embed] }); 29 | } 30 | catch (e) { 31 | message.channel.send("ERROR! \n ```" + e + "```"); 32 | } 33 | }, 34 | }; -------------------------------------------------------------------------------- /commands/info/addcard.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const botConfig = require("../../botconfig.json"); 3 | mongoose.connect(botConfig.dbLink, { 4 | useNewUrlParser: true, 5 | useUnifiedTopology: true, 6 | }); 7 | 8 | const Cards = require("../../model/card.js"); 9 | module.exports = { 10 | name: "card", 11 | aliases: ["cards", "rankcards", "changeCards", "newcards"], 12 | category: "info", 13 | description: "give you the possibility to change your card background!", 14 | usage: " | ", 15 | run: async (bot, message, args) => { 16 | if(args[0] === "info") { 17 | message.reply("You can send a custom image to use as a rank card.\n Your image must be in **934x282**. if it's not it will be stretched to this resolution. \n you must send a link to an image in ***.jpg*** or ***.png***. Any other link will be refused."); 18 | } 19 | console.log(args[0]); 20 | if(!args[0]) return message.reply("Please send a link to your image!"); 21 | if(!args[0].startsWith("http" || "https")) return message.reply("please send a valid link."); 22 | // fix this. 23 | // aaah. I cant remember the issue. well test and fix this future me please. 24 | if(!args[0].endsWith(".png") || !args[0].endsWith(".jpg")) return message.reply("please send a link to an image in jpg or png."); 25 | Cards.findOne({ 26 | did: message.author.id, 27 | }, (err, cards)=>{ 28 | if(err) console.log(err); 29 | if (!cards) { 30 | const newCards = new Cards({ 31 | did: message.author.id, 32 | link: args[0], 33 | }); 34 | newCards.save().catch(error => console.log(error)); 35 | message.reply("Your card has been saved!"); 36 | } 37 | else { 38 | cards.link = args[0]; 39 | cards.save().catch(error => console.log(error)); 40 | message.reply("Your card has been saved!"); 41 | } 42 | }); 43 | }, 44 | 45 | }; -------------------------------------------------------------------------------- /commands/info/botInfo.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const pjson = require("../../package.json"); 3 | module.exports = { 4 | name: "botinfo", 5 | category: "info", 6 | description: "show you information about this bot.", 7 | run: async (bot, message) => { 8 | const botembed = new MessageEmbed() 9 | .setThumbnail(bot.user.displayAvatarURL) 10 | .setTitle("About this bot:") 11 | .setAuthor({ name: bot.user.username, iconURL: bot.user.displayAvatarURL() }) 12 | .setDescription("this bot can make your cat explode, Mount the DOGO, burn your egg and clean your house. (but not your room. we tested all of this.(RIP my cat...))") 13 | .setColor("#800080") 14 | .addField("Bot name:", bot.user.username, true) 15 | .addField("Version:", `${pjson.version} ${pjson.codeName}`, true) 16 | .addField("Developped by:", "[Asthriona](https://Asthriona.com) / [RiseDev](https://twitter.com/_RiseDev)", true) 17 | .addField("Developpers Website", "[Yukiko Dev Team](https://team.yukiko.app/), [Asthriona](https://Asthriona.com), [RiseDev](https://twitter.com/_RiseDev)", true) 18 | // Please DO NOT un-credit us. feel free to un-comment the line below to credit yourself :) 19 | // .addField("Edited by", "[Your Name](https://YourWebsiteOrLink.com)") 20 | .addField("Created on", bot.user.createdAt, true) 21 | .addField("On the server since:", bot.user.joinedAt, true) 22 | .addField("Git:", "https://github.com/Asthriona/Yukiko", true) 23 | .addField("Site: ", "http://yukiko.nishikino.me/", true) 24 | .addField("Guilds Using this bot: ", bot.guilds.size, true) 25 | .setTimestamp() 26 | .setFooter({ text: bot.user.username, iconURL: bot.user.displayAvatarURL() }); 27 | return message.reply({ embeds: [botembed] }); 28 | }, 29 | }; -------------------------------------------------------------------------------- /commands/info/game.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "game", 3 | category: "info", 4 | description: "change what bot is actually playing.", 5 | aliases: ["setgame"], 6 | run: async (bot, message, args) => { 7 | if(message.member.permissions.has("BAN_MEMBERS")) { 8 | bot.user.setPresence({ activities: [{ name: args.join(" ") }] }); 9 | } 10 | else{ 11 | return message.reply("Oy! You can't tell me what to do! "); 12 | } 13 | 14 | }, 15 | }; -------------------------------------------------------------------------------- /commands/info/help.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { stripIndents } = require("common-tags"); 3 | // var { botConfig } = require("../../botconfig.json") 4 | module.exports = { 5 | name: "help", 6 | category: "info", 7 | description: "Return all the commands for this bot.", 8 | usage: "[command | alias]", 9 | run: async (bot, message, args) => { 10 | if(args[0]) { 11 | return getCMD(bot, message, args[0]); 12 | } 13 | else { 14 | return getAll(bot, message); 15 | } 16 | }, 17 | }; 18 | // var prefix = botConfig.prefix; 19 | 20 | function getAll(bot, message) { 21 | const embed = new MessageEmbed() 22 | .setColor("RANDOM"); 23 | const commands = (category) => { 24 | return bot.Commands 25 | .filter(cmd => cmd.category === category) 26 | .map(cmd => `\`${cmd.name}\``) 27 | .join(", "); 28 | }; 29 | const info = bot.Categories 30 | .map(cat => stripIndents`**${cat[0].toUpperCase() + cat.slice(1)}** \n ${commands(cat)}`) 31 | .reduce((string, category) => string + "\n" + category); 32 | embed.setDescription(info); 33 | return message.reply({ embeds: [embed] }); 34 | } 35 | function getCMD(bot, message, input) { 36 | const embed = new MessageEmbed(); 37 | const cmd = bot.Commands.get(input.toLowerCase()) || bot.commands.get(bot.alias.get(input.toLowerCase())); 38 | let info = `No information for the commands ***${input.toLowerCase}`; 39 | embed.setColor("RED") 40 | .setDescription(info); 41 | if(!cmd) { 42 | return message.reply({ embeds: [embed] }); 43 | } 44 | if(cmd.name) info = `**command name** ${cmd.name}`; 45 | if(cmd.alias) info += `\n**Alialses** ${cmd.aliases.map(a => `\`${a}\``).join(", ")}`; 46 | if(cmd.description) info += `\n**Description**: ${cmd.description}`; 47 | if(cmd.usage) { 48 | info += `\n**Usage**: ${cmd.usage}`; 49 | embed.setFooter("Syntax: <> = Is required, [] = is optional") 50 | .setColor("PURPLE") 51 | .setDescription(info); 52 | } 53 | return message.reply({ embeds: [embed] }); 54 | } -------------------------------------------------------------------------------- /commands/info/invit.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "invite", 3 | category: "info", 4 | description: "Create an invitation to this server", 5 | run: async (bot, message) => { 6 | message.channel.createInvite() 7 | .then(invite => message.channel.send(`Here is your invitation! => \n ${invite}`)) 8 | .catch(console.error); 9 | }, 10 | }; -------------------------------------------------------------------------------- /commands/info/lbtop10.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const mongoose = require("mongoose"); 3 | const botConfig = require("../../botconfig.json"); 4 | 5 | mongoose.connect(botConfig.dbLink, { 6 | useNewUrlParser: true, 7 | useUnifiedTopology: true, 8 | }); 9 | const Users = require("../../model/xp.js"); 10 | 11 | module.exports = { 12 | name: "top", 13 | category: "info", 14 | description: "Show the top 10 leaderboard!", 15 | run: async (bot, message) => { 16 | Users.find({ 17 | serverID: message.guild.id, 18 | }).sort([ 19 | ["xp", "descending"], 20 | ]).exec((err, res) => { 21 | if(err) console.log(err); 22 | const embed = new MessageEmbed() 23 | .setTitle("Yukiko's Leaderboard!") 24 | .setThumbnail(message.guild.iconURL()) 25 | .setDescription("Here is our top10!") 26 | .setFooter(`Powered by ${bot.user.username}`, bot.user.displayAvatarURL()); 27 | if(res.length === 0) { 28 | // if no result 29 | embed.setColor("red"); 30 | embed.addField("No Data :c"); 31 | } 32 | else if(res.length < 10) { 33 | // if less than 10 34 | embed.setColor("#351B96"); 35 | let i; 36 | for(i = 0; i < res.length; i++) { 37 | const member = message.guild.members.cache.get(res[i].did) || "User is gone :/"; 38 | if(member === "User is gone :/") { 39 | embed.addField(`${i + 1}. ${member}`, `**Level**: ${res[i].level} || **XP**: ${res[i].xp}`); 40 | 41 | } 42 | else{ 43 | embed.addField(`${i + 1}. ${member.user.username}`, `**Level**: ${res[i].level} || **XP**: ${res[i].xp}`); 44 | } 45 | } 46 | } 47 | else{ 48 | // if more than 10 49 | embed.setColor("#351B96"); 50 | let i; 51 | for(i = 0; i < 10; i++) { 52 | const member = message.guild.members.get(res[i].did) || "User is gone :/"; 53 | if(member === "User is gone :/") { 54 | embed.addField(`${i + 1}. ${member}`, `**Level**: ${res[i].level} || **XP**: ${res[i].xp}`); 55 | 56 | } 57 | else{ 58 | embed.addField(`${i + 1}. ${member.user.username}`, `**Level**: ${res[i].level} || **XP**: ${res[i].xp}`, true); 59 | } 60 | } 61 | } 62 | message.reply({ embeds: [embed] }); 63 | }); 64 | 65 | }, 66 | }; -------------------------------------------------------------------------------- /commands/info/ping.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-useless-escape */ 2 | module.exports = { 3 | name: "ping", 4 | category: "info", 5 | description: "return bot latency and API ping.", 6 | run: async (bot, message) => { 7 | const spells = [ 8 | "Agi", "Maragi", "Agilao", "Maragion", 9 | "Agidyne", "Maragidyne", 10 | ]; 11 | const shadows = [ 12 | "Lying Hablerie", "Calm Pesce", "Trance Twins", "Black Raven", 13 | "Magic Hand", "Secret Bambino", "Positive King", "Brinze Dice", 14 | "Burning Beetle", "Phantom Mage", "Heat Balance", "Laughing Table", 15 | "Avenger knight", 16 | ]; 17 | const randomSpell = spells[Math.floor(Math.random() * spells.length)]; 18 | const randomShadow = shadows[Math.floor(Math.random() * shadows.length)]; 19 | const msg = await message.reply(`\* Yukiko cast ${randomSpell} against ${randomShadow} \*`); 20 | msg.edit(`**Pong!** \n Gateway latency: ${Math.floor(msg.createdAt - message.createdAt)}ms. \n API latency: ${Math.round(bot.ws.ping)}ms.`); 21 | }, 22 | }; -------------------------------------------------------------------------------- /commands/info/rank.js: -------------------------------------------------------------------------------- 1 | const discord = require("discord.js"); 2 | const mongoose = require("mongoose"); 3 | const Canvas = require("canvas"); 4 | 5 | const botConfig = require("../../botconfig.json"); 6 | const { getMember } = require("../../function"); 7 | 8 | mongoose.connect(botConfig.dbLink, { 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true, 11 | }); 12 | const Users = require("../../model/xp.js"); 13 | const Cards = require("../../model/card.js"); 14 | 15 | module.exports = { 16 | name: "rank", 17 | aliases: ["level", "card"], 18 | description: "Show you your XP Card.", 19 | category: "info", 20 | usage: "[username | id | mention]", 21 | run: async (bot, message, args) => { 22 | const canvas = Canvas.createCanvas(934, 282); 23 | const ctx = canvas.getContext("2d"); 24 | // Get Background Image 25 | Cards.findOne({ 26 | did: message.author.id, 27 | }, (err, cards) => { 28 | if (err) { 29 | console.log(err); 30 | return message.reply("An error happened. ```" + err + "```"); 31 | } 32 | const cardBg = cards.link; 33 | Users.findOne({ 34 | did: message.author.id, 35 | serverID: message.guild.id, 36 | }, async (err, users) => { 37 | if (err) { 38 | console.log(err); 39 | return message.reply("An error happened. ```" + err + "```"); 40 | } 41 | const member = getMember(message, args.join(" ")); 42 | const background = await Canvas.loadImage(cardBg); 43 | ctx.drawImage(background, 0, 0, canvas.width, canvas.height); 44 | // Draw rectangle 45 | ctx.beginPath(); 46 | ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; 47 | ctx.fillRect(260, 80, 650, 160); 48 | ctx.closePath(); 49 | ctx.stroke(); 50 | // Get Username 51 | ctx.font = "60px sans-serif"; 52 | ctx.fillStyle = "#fff"; 53 | ctx.fillText(member.displayName, 280, 136); 54 | // Show XP and levels 55 | const nxtlvl = 300 * Math.pow(2, users.level); 56 | ctx.font = "40px sans-serif"; 57 | ctx.fillStyle = "#fff"; 58 | ctx.fillText("You are level " + users.level + " - " + users.xp + " XP", 280, 180); 59 | // xp left 60 | const xpLeft = nxtlvl - users.xp; 61 | ctx.font = "50px sans-serif"; 62 | ctx.fillStyle = "#fff"; 63 | ctx.fillText(`next level in ${xpLeft} XP`, 280, 225); 64 | // Get avatar 65 | console.log("pog"); 66 | await GetAvatar(message, ctx); 67 | // Put all the things together and send it in a nice package. 68 | const lvlimg = new discord.MessageAttachment(canvas.toBuffer(), "rank-cards.png"); 69 | message.reply({ files: [lvlimg] }); 70 | }); 71 | }); 72 | }, 73 | }; 74 | 75 | async function GetAvatar(message, ctx) { 76 | // I HATE this part. I think here at the Yukiko Dev Team Incorporation ltd llc Group we all hate this part. 77 | // If Anyone know how to use canvas and this part better than us, please feel free to PR :) 78 | // (or if you are a dev of node-canvas please contact me on Twitter/Github @Asthriona ) 79 | 80 | // EDIT: We did it better on Yukiko :) (https://Yukiko.app) - Asthriona. 81 | // EDIT2: I should seriously update that ahah! 82 | 83 | // Avatar function 84 | // get user in the database. 85 | Users.findOne({ 86 | did: message.author.id, 87 | }, async (err, users)=>{ 88 | // XP bar calculus. (Help) 89 | const nxtlvl = 300 * Math.pow(2, users.level); 90 | const n = ((users.xp - nxtlvl) / nxtlvl) * -100; 91 | const member = getMember(message); 92 | const arc = (100 - n) / 100 * Math.PI; 93 | // Image arc draw (Cry in js) 94 | ctx.strokeStyle = member.displayHexColor; 95 | ctx.beginPath(); 96 | ctx.lineWidth = 15; 97 | ctx.arc(125, 140, 102, Math.PI * 1.5, arc); 98 | ctx.stroke(); 99 | }); 100 | // lvlbar background 101 | ctx.strokeStyle = "rgba(0, 0, 0, 0.8)"; 102 | ctx.beginPath(); 103 | ctx.lineWidth = 20; 104 | ctx.arc(125, 140, 102, 0, Math.PI * 2); 105 | ctx.stroke(); 106 | // Print the profile picture. 107 | const avatar = await Canvas.loadImage(message.author.displayAvatarURL({ format: "jpg" })); 108 | ctx.beginPath(); 109 | ctx.arc(125, 140, 100, 0, Math.PI * 2); 110 | ctx.closePath(); 111 | ctx.clip(); 112 | ctx.drawImage(avatar, 25, 40, 200, 200); 113 | } 114 | -------------------------------------------------------------------------------- /commands/info/reddit.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const { MessageEmbed } = require("discord.js"); 3 | 4 | module.exports = { 5 | name: "reddit", 6 | category: "info", 7 | description: "Send an image from a sub reddit!", 8 | usage: "$reddit [sub-reddit]", 9 | run: async (bot, message, args) => { 10 | const { body } = await axios 11 | .get(`https://www.reddit.com/r/${args}.json?sort=top&t=week`) 12 | .query({ limit: 800 }); 13 | 14 | const allowed = message.channel.nsfw ? body.data.children : body.data.children.filter(post => !post.data.over_18); 15 | if(!allowed.length) return message.reply("We are running out of dank meme. 😂😂😂"); 16 | const randomNumber = Math.floor(Math.random() * allowed.length); 17 | const embed = new MessageEmbed() 18 | .setColor("PURPLE") 19 | .setTitle(allowed[randomNumber].data.title) 20 | .setDescription(allowed[randomNumber].data.author) 21 | .setImage(allowed[randomNumber].data.url) 22 | .addField("Information: ", "Up vote:" + allowed[randomNumber].data.ups + " / Comment: " + allowed[randomNumber].data.num_comments) 23 | .setURL("https://reddit.com" + allowed[randomNumber].data.permalink) 24 | .setTimestamp() 25 | .setFooter(bot.user.username, bot.user.displayAvatarURL()); 26 | return message.channel.send({ embeds: [embed] }); 27 | }, 28 | }; -------------------------------------------------------------------------------- /commands/info/serverinfo.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const moment = require("moment"); 3 | module.exports = { 4 | name: "server", 5 | aliases: ["server-info", "serverinfo"], 6 | category: "info", 7 | description: "Return server infos.", 8 | run: async (bot, message) => { 9 | const guildOwner = bot.users.cache.get(message.guild.ownerId); 10 | const serverembed = new MessageEmbed() 11 | .setDescription("Server Information") 12 | .setColor("#800080") 13 | .setThumbnail(message.guild.iconURL()) 14 | .addField("Server name", `${message.guild.name}`) 15 | .addField("Created at", `${moment(message.guild.createdAt).format("MMMM Do YYYY, h:mm:ss a")} (${moment(message.guild.createdAt).fromNow()})`) 16 | .addField("Joined at: ", `${moment(message.member.joinedAt).format("MMMM Do YYYY, h:mm:ss a")} (${moment(message.member.joinedAt).fromNow()})`) 17 | .addField("Owner: ", `${guildOwner}`) 18 | .addField("Total members: ", `${message.guild.memberCount}`) 19 | .setFooter(bot.user.username, bot.user.displayAvatarURL()) 20 | .setTimestamp(); 21 | return message.channel.send({ embeds: [serverembed] }); 22 | }, 23 | }; -------------------------------------------------------------------------------- /commands/info/uptime.js: -------------------------------------------------------------------------------- 1 | // Geez. I had no idea how time works. 2 | // Message to Future Asthriona. use Day.js or moment for that pls. 3 | module.exports = { 4 | name: "uptime", 5 | category: "info", 6 | description: "Show bot's uptime", 7 | run: async (bot, message) => { 8 | let totalSeconds = (bot.uptime / 1000); 9 | const days = Math.floor(totalSeconds / 86400); 10 | const hours = Math.floor(totalSeconds / 3600); 11 | totalSeconds %= 3600; 12 | const minutes = Math.floor(totalSeconds / 60); 13 | const seconds = Math.floor(totalSeconds / 60); 14 | const uptime = `${days} days, ${hours} hours, ${minutes} minutes and ${seconds} seconds`; 15 | message.channel.send(uptime); 16 | }, 17 | }; -------------------------------------------------------------------------------- /commands/info/whois.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { stripIndents } = require("common-tags"); 3 | const { getMember, formatDate } = require("../../function"); 4 | 5 | module.exports = { 6 | name: "whois", 7 | aliases: ["who", "user", "info", "tamer"], 8 | description: "Returns user information", 9 | category: "info", 10 | usage: "[username | id | mention]", 11 | run: (bot, message, args) => { 12 | const member = getMember(message, args.join(" ")); 13 | 14 | // Member variables 15 | const joined = formatDate(member.joinedAt); 16 | const roles = member.roles.cache 17 | .filter(r => r.id !== message.guild.id) 18 | .map(r => r).join(", ") || "none"; 19 | 20 | // User variables 21 | const created = formatDate(member.user.createdAt); 22 | 23 | const embed = new MessageEmbed() 24 | .setAuthor({ name: message.author.username, iconURL: message.author.displayAvatarURL() }) 25 | .setThumbnail(member.user.displayAvatarURL({ dynamic: true })) 26 | .setColor(member.displayHexColor === "#000000" ? "#ffffff" : member.displayHexColor) 27 | .setFooter({ text: bot.user.username, iconURL: bot.user.displayAvatarURL() }) 28 | 29 | .addField("Member information:", stripIndents`**=> Display name:** ${member.displayName} 30 | **=> Joined at:** ${joined} 31 | **=> Roles:** ${roles}`, true) 32 | 33 | .addField("User information:", stripIndents`**=> ID:** ${member.user.id} 34 | **=> Username:** ${member.user.username} 35 | **=> Tag:** ${member.user.tag} 36 | **=> Created at:** ${created}`, true) 37 | 38 | .setTimestamp(); 39 | message.channel.send({ embeds: [embed] }); 40 | }, 41 | }; -------------------------------------------------------------------------------- /commands/info/wink.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const { MessageEmbed } = require("discord.js"); 3 | module.exports = { 4 | name: "wink", 5 | category: "info", 6 | description: "send a Winky face!", 7 | run: async (bot, message) => { 8 | const { body } = await axios 9 | .get("https://some-random-api.ml/animu/wink"); 10 | const winkembed = new MessageEmbed() 11 | .setColor("#800080") 12 | .setTitle("winky Face! ;)") 13 | .setImage(body.link); 14 | 15 | message.channel.send({ embeds: [winkembed] }); 16 | }, 17 | }; -------------------------------------------------------------------------------- /commands/info/wow.js: -------------------------------------------------------------------------------- 1 | // Well... I got this commands working on another bot (private commission) but I think i never finished it here. 2 | // Naw worries, its on my todo list :) 3 | const { MessageEmbed } = require("discord.js"); 4 | const axios = require("axios"); 5 | const botConfig = require("../../botconfig.json"); 6 | 7 | module.exports = { 8 | name: "wow", 9 | category: "info", 10 | description: "Return your World of warcraft character!", 11 | usage: "", 12 | run: async (bot, message, args) => { 13 | const char = args[0]; 14 | const realm = args[1]; 15 | let region = args[2]; 16 | if(!region) region = "eu"; 17 | console.log(args[0] + " " + args[1]); 18 | axios.get("https://" + region + ".api.blizzard.com/wow/character/" + realm + "/" + char + "?locale=en_US&access_token=" + botConfig.wowAT).then(function(res) { 19 | 20 | if(message.author.id === "186195458182479874") { 21 | if(res.data.faction === 0) { 22 | const wowembed = new MessageEmbed()() 23 | .setTitle("Infos for: " + args) 24 | .addField("Name:", res.data.name, true) 25 | .addField("Realm", res.data.realm, true) 26 | .addField("Battlegroup", res.data.battlegroup, true) 27 | .addField("Class:", res.data.class, true) 28 | .addField("Race", res.data.race, true) 29 | .addField("Gender", res.data.gender, true) 30 | .addField("level", res.data.level, true) 31 | .addField("Achievement Points", res.data.achievementPoints, true) 32 | .addField("Calc Class", res.data.calcClass, true) 33 | .addField("faction", "Alliance", true) 34 | .addField("Total Honorable Kills", res.data.totalHonorableKills, true) 35 | .addField("ID", res.data.id, true); 36 | message.channel.send({ embeds: [wowembed] }); 37 | } 38 | else{ 39 | const wowembed = new MessageEmbed()() 40 | .setTitle("Infos for: " + args) 41 | .addField("Name:", res.data.name, true) 42 | .addField("Realm", res.data.realm, true) 43 | .addField("Battlegroup", res.data.battlegroup, true) 44 | .addField("Class:", res.data.class, true) 45 | .addField("Race", res.data.race, true) 46 | .addField("Gender", res.data.gender, true) 47 | .addField("level", res.data.level, true) 48 | .addField("Achievement Points", res.data.achievementPoints, true) 49 | .addField("Calc Class", res.data.calcClass, true) 50 | .addField("faction", "Horde", true) 51 | .addField("Total Honorable Kills", res.data.totalHonorableKills, true) 52 | .addField("ID", res.data.id, true); 53 | message.channel.send({ embeds: [wowembed] }); 54 | } 55 | } 56 | }).catch(err => message.channel.send("WAW! an error sucessfully happened! ```" + err + "```")); 57 | }, 58 | }; -------------------------------------------------------------------------------- /commands/moderation/ban.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { stripIndents } = require("common-tags"); 3 | const { promptMessage } = require("../../function"); 4 | module.exports = { 5 | name: "ban", 6 | category: "moderation", 7 | description: "Ban a user that break the law!", 8 | usage: "", 9 | run: async (bot, message, args) => { 10 | const logChannel = message.guild.channels.find(c => c.name === "incident") || message.channel; 11 | if(!args[0]) { 12 | return message.reply(" ❌ You forgot to tell me wich user you want to ban."); 13 | } 14 | if(!args[1]) { 15 | return message.reply(" ❌ Please provide a reason to ban someone."); 16 | } 17 | if(!message.member.permissions.has("BAN_MEMBERS")) { 18 | return message.reply(" ❌ You don't have the permission to ban somebody. Please use a!report."); 19 | } 20 | if(!message.guild.me.permissions.has("BAN_MEMBERS")) { 21 | return message.reply(" ❌ I don't have to permissions to ban."); 22 | } 23 | 24 | const toban = message.mentions.members.first() || message.guild.members.get(args[0]); 25 | if(!toban) { 26 | return message.reply(" ❌ Cannot find that user :/"); 27 | } 28 | if(toban.id === "186195458182479874") { 29 | return message.reply(" ❌ Dont you dare ban my dad?! D:<"); 30 | } 31 | if(toban.id === "635422418424299521") { 32 | return message.reply(" ❌ Dont you dare ban my mum?! D:<"); 33 | } 34 | if(message.author.id === toban.id) { 35 | return message.reply(" ❌ You can't ban yourself you smart ass... 🤷‍♀️🤷‍♂️"); 36 | } 37 | if(bot.user.id === toban.id) { 38 | return message.reply(" ❌ Dont you dare try to ban me?!"); 39 | } 40 | if(!toban.bannable) { 41 | return message.reply("You can't ban this user because he/she is better than u **:)**"); 42 | } 43 | 44 | const embed = new MessageEmbed()() 45 | .setAuthor({ name: "~Ban!~", iconURL: message.author.displayAvatarURL()}) 46 | .setColor("#FF0000") 47 | .setThumbnail(toban.user.displayAvatarURL()) 48 | .setFooter(bot.user.username, bot.user.displayAvatarURL()) 49 | .setTimestamp() 50 | .setDescription(stripIndents`**=> baned Member:** ${toban} (${toban.id}) 51 | ***=> baned by:*** ${message.author} (${message.author.id}) 52 | ***=> Reason:*** ${args.slice(1).join(" ")}`, true); 53 | 54 | const promptEmbed = new MessageEmbed()() 55 | .setColor("GREEN") 56 | .setAuthor({ name: "This verification becomes invalid after 30s." }) 57 | .setDescription(`Do you want to ban ${toban}?`) 58 | .setTimestamp(); 59 | 60 | const publicEmbed = new MessageEmbed()() 61 | .setColor("PURLPLE") 62 | .setAuthor({ name: bot.user.username, iconURL: bot.user.displayAvatarURL() }) 63 | .setDescription(`${toban} Just got baned by ${message.author}!`) 64 | .setImage("https://media.giphy.com/media/xUO4t2gkWBxDi/giphy.gif") 65 | .setTimestamp() 66 | .setFooter({ text: bot.user.username, iconURL: bot.user.displayAvatarURL() }); 67 | 68 | await message.channel.send({ embeds: [promptEmbed] }).then(async msg =>{ 69 | const emoji = await promptMessage(msg, message.author, 30, ["✔️", "❌"]); 70 | if(emoji === "✔️") { 71 | msg.delete(); 72 | logChannel.send({ embeds: [embed] }); 73 | message.channel.send({ embeds: [publicEmbed] }); 74 | toban.ban(args.slice(1).join(" ") + " by " + message.author.username) 75 | .catch(err => { 76 | if(err) return message.channel.send("Error: \n ```" + err + "```"); 77 | }); 78 | } 79 | else if (emoji === "❌") { 80 | msg.delete(); 81 | message.reply(`ban cancelled. \n You got lucky this time ${toban}!`); 82 | } 83 | }); 84 | }, 85 | }; -------------------------------------------------------------------------------- /commands/moderation/clear.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "clear", 3 | category: "Moderation", 4 | aliases: ["delete", "suppr", "remove"], 5 | description: "delete a lot of message :O", 6 | usage: "!clear [1 - 100]", 7 | run: async (bot, message, args) => { 8 | if(message.deletable) { 9 | message.delete(); 10 | } 11 | if (!message.member.permissions.has("MANAGE_MESSAGES")) { 12 | return message.reply("you dont have the permissions to delete those message!"); 13 | } 14 | if (isNaN(args[0]) || parseInt(args[0]) <= 0) { 15 | return message.reply("Oh my... Is this even a number?! Please use a number between 0 and 100 in numeric value."); 16 | } 17 | if(!message.guild.me.permissions.has("MANAGE_MESSAGES")) { 18 | return message.reply("I dont have the permissions to do that. Please add 'MANAGE_MESSAGES' to my permissions."); 19 | } 20 | let deleteAmount; 21 | if(parseInt(args[0]) > 100) { 22 | deleteAmount = 100; 23 | } 24 | else{ 25 | deleteAmount = parseInt(args[0]); 26 | } 27 | message.channel.bulkDelete(deleteAmount, true) 28 | .then(deleted => message.channel.send(`I deleted ${deleted.size} messages.`)).then(m => m.delete({ timeout: 20000 })) 29 | .catch(err => message.reply("Yikes! An error sucessfully happened! " + err)); 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /commands/moderation/kick.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { stripIndents } = require("common-tags"); 3 | const { promptMessage } = require("../../function"); 4 | module.exports = { 5 | name: "kick", 6 | category: "moderation", 7 | description: "Kick a user that break the law!", 8 | usage: "", 9 | run: async (bot, message, args) => { 10 | const logChannel = message.guild.channels.find(c => c.name === "incident") || message.channel; 11 | if(!args[0]) { 12 | return message.reply(" ❌ You forgot to tell me wich user you want to kick."); 13 | } 14 | if(!args[1]) { 15 | return message.reply(" ❌ Please provide a reason to kick someone."); 16 | } 17 | if(!message.member.permissions.has("KICK_MEMBERS")) { 18 | return message.reply(" ❌ You don't have the permission to kick somebody. Please use a!report."); 19 | } 20 | if(!message.guild.me.permissions.has("KICK_MEMBERS")) { 21 | return message.reply(" ❌ I don't have to permissions to Kick."); 22 | } 23 | 24 | const toKick = message.mentions.members.first() || message.guild.members.get(args[0]); 25 | if(!toKick) { 26 | return message.reply(" ❌ Cannot find that user :/"); 27 | } 28 | if(toKick.id === "186195458182479874") { 29 | return message.reply(" ❌ Dont you dare kick my dad?! D:<"); 30 | } 31 | if(toKick.id === "635422418424299521") { 32 | return message.reply(" ❌ Dont you dare kick my mum?! D:<"); 33 | } 34 | if(message.author.id === toKick.id) { 35 | return message.reply(" ❌ You can't kick yourself you smart ass... 🤷‍♀️🤷‍♂️"); 36 | } 37 | if(bot.user.id === toKick.id) { 38 | return message.reply(" ❌ Dont you dare try to kick me?!"); 39 | } 40 | if(!toKick.kickable) { 41 | return message.reply("You can't kick this user because he/she is better than u **:)**"); 42 | } 43 | 44 | const embed = new MessageEmbed()() 45 | .setAuthor({ name: "~Kick!~"}) 46 | .setColor("#FF0000") 47 | .setThumbnail(toKick.user.displayAvatarURL()) 48 | .setFooter(bot.user.username, bot.user.displayAvatarURL()) 49 | .setTimestamp() 50 | .setDescription(stripIndents`**=> Kicked Member:** ${toKick} (${toKick.id}) 51 | ***=> Kicked by:*** ${message.author} (${message.author.id}) 52 | ***=> Reason:*** ${args.slice(1).join(" ")}`, true); 53 | 54 | const promptEmbed = new MessageEmbed()() 55 | .setColor("GREEN") 56 | .setAuthor({ name: "This verification becomes invalid after 30s."}) 57 | .setDescription(`Do you want to kick ${toKick}?`) 58 | .setTimestamp(); 59 | 60 | const publicEmbed = new MessageEmbed()() 61 | .setColor("PURLPLE") 62 | .setAuthor({ name: bot.user.username, iconURL: bot.user.displayAvatarURL() }) 63 | .setDescription(`${toKick} Just got kicked by ${message.author}!`) 64 | .setImage("https://cdn.asthriona.com/kick.gif") 65 | .setTimestamp() 66 | .setFooter({ text: "Kick Sponsored by Asthriona LLC!", iconURL: bot.user.displayAvatarURL() }); 67 | 68 | await message.channel.send(promptEmbed).then(async msg =>{ 69 | const emoji = await promptMessage(msg, message.author, 30, ["✔️", "❌"]); 70 | if(emoji === "✔️") { 71 | msg.delete(); 72 | logChannel.send(embed); 73 | message.channel.send(publicEmbed); 74 | toKick.kick(args.slice(1).join(" ")) 75 | .catch(err => { 76 | if(err) return message.channel.send("Error: \n ```" + err + "```"); 77 | }); 78 | } 79 | else if (emoji === "❌") { 80 | msg.delete(); 81 | message.reply(`Kick cancelled. \n You got lucky this time ${toKick}!`); 82 | } 83 | }); 84 | }, 85 | }; -------------------------------------------------------------------------------- /commands/moderation/mute.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unreachable */ 2 | const { MessageEmbed } = require("discord.js"); 3 | const ms = require("ms"); 4 | 5 | module.exports = { 6 | name: "mute", 7 | category: "Moderation", 8 | description: "Create a new role!", 9 | usage: "!mute <@mention>