├── .gitignore ├── README.md ├── guide ├── .vuepress │ ├── components │ │ ├── Head.js │ │ ├── Navbar.js │ │ └── Sidebar.js │ ├── config.js │ ├── public │ │ └── images │ │ │ ├── favicon.ico │ │ │ └── logo.png │ └── styles │ │ ├── index.styl │ │ └── palette.styl ├── README.md └── topics │ ├── discordjs │ ├── README.md │ ├── firstCommand.md │ ├── gettingStarted.md │ └── tableOfContents.md │ └── erelajs │ ├── README.md │ ├── advanced.md │ ├── basics.md │ ├── moreCommands.md │ └── updating.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | yarn.lock 3 | .eslintrc 4 | .vscode 5 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MenuDocs Official Written Guides. 2 | --- 3 | 4 | ## Why a written guide from MenuDocs? 5 | 6 | MenuDocs is an organisation dedicated to providing educational resources for its community and other. 7 | We value every single person and the way they best learn. Which brings us to the point that we acknowledge 8 | that fact that everyone learns different whether thats following video tutorials better, or following 9 | written tutorials better. 10 | 11 | ## How can you contribute to this growing guide? 12 | 13 | A simple PR request is one step closer to displaying your guide on our website. All credits are given where 14 | due which means you're able to display your github redirect at the top of all your guides. We advise that 15 | you join the discord to get better help with implementing your guide which you can find above. 16 | 17 | ## Can I contribute to improving the theme used on the website? 18 | 19 | You sure can! You'll be able to find the theme we use on a repository displayed on our github. 20 | 21 | ## How to create a guide? 22 | 23 | 1) Fork the guides repo here: https://github.com/MenuDocs/guides 24 | 2) First create your folder in here: https://github.com/MenuDocs/guides/tree/master/guide/topics 25 | 3) Then head on over to here to add your sidebar: https://github.com/MenuDocs/guides/blob/master/guide/.vuepress/components/Sidebar.js 26 | 4) You'll need a base README.md in the file which will be the "fallback" file. you can reference the other current guides for more information. 27 | 4) Any images you would like to have will need to go in a folder displayed here: https://github.com/MenuDocs/guides/tree/master/guide/.vuepress/public/images. You can then access them like "/images/nameOfFolder/image.png" 28 | 5) You will only need to have 1 category (the programming language used or the service used. "How to setup a VPS for Node.js" or "Introduction to Frontend Development" are examples of a name.) displayed in the README aswell as any legitimately related tags (frameworks, libraries, development type), this can be seen here: https://raw.githubusercontent.com/MenuDocs/guides/master/guide/topics/discordjs/README.md 29 | 6) Structure your guide, split your guide into Subheadings which ultimately can be subpages. 30 | 7) Review your guide to make sure it's factual, straight to the point with all the valid information required and overall has great use of the English language. 31 | 8) Add yourself and anyone that helped as an author. Note that the way our guide is designed is the author your provide must be a valid github user. 32 | 9) Create a Pull Request to the original repo which will allow it to be review and ultimately merged 33 | 10) Kachow, you're on the guide! Thank you for contributing. -------------------------------------------------------------------------------- /guide/.vuepress/components/Head.js: -------------------------------------------------------------------------------- 1 | const head = [ 2 | [ 3 | 'link', 4 | { 5 | rel: 'icon', 6 | href: '/images/favicon.ico', 7 | alt: 'menudocs logo' 8 | } 9 | ], 10 | [ 11 | 'meta', 12 | { 13 | name: 'og:title', 14 | content: 'Official MenuDocs Guide' 15 | } 16 | ], 17 | [ 18 | 'meta', 19 | { 20 | name: 'og:description', 21 | content: 'Official MenuDocs\' Written Guides for beginner to high level developers.' 22 | } 23 | ], 24 | [ 25 | 'meta', 26 | { 27 | name: 'og:type', 28 | content: 'website' 29 | } 30 | ], 31 | [ 32 | 'meta', 33 | { 34 | name: 'og:url', 35 | content: 'https://guides.menudocs.org/' 36 | } 37 | ], 38 | [ 39 | 'meta', 40 | { 41 | name: 'og:locale', 42 | content: 'en_US' 43 | } 44 | ], 45 | [ 46 | 'meta', 47 | { 48 | name: 'viewport', 49 | content: 'width=device-width,initial-scale=1,user-scalable=no' 50 | } 51 | ] 52 | ]; 53 | 54 | module.exports = head; 55 | -------------------------------------------------------------------------------- /guide/.vuepress/components/Navbar.js: -------------------------------------------------------------------------------- 1 | const navbar = [ 2 | { 3 | text: 'Home', 4 | link: '/', 5 | icon: 'reco-home' 6 | }, 7 | { 8 | text: 'Main Site', 9 | link: 'https://menudocs.org/', 10 | icon: 'reco-blog' 11 | }, 12 | { 13 | text: "Socials", 14 | items: [ 15 | { 16 | text: "Youtube", 17 | link: "https://menudocs.link/youtube" 18 | }, 19 | { 20 | text: "Twitter", 21 | link: "https://menudocs.link/twitter" 22 | }, 23 | { 24 | text: "Twitch", 25 | link: "https://menudocs.link/twitch" 26 | }, 27 | { 28 | text: "Facebook", 29 | link: "https://menudocs.link/facebook" 30 | }, 31 | { 32 | text: "Instagram", 33 | link: "https://menudocs.link/instagram" 34 | }, 35 | ], 36 | icon: 'reco-account' 37 | }, 38 | { 39 | text: 'Support', 40 | link: 'https://menudocs.link/discord', 41 | icon: 'reco-wechat' 42 | }, 43 | ]; 44 | 45 | module.exports = navbar; 46 | -------------------------------------------------------------------------------- /guide/.vuepress/components/Sidebar.js: -------------------------------------------------------------------------------- 1 | const sidebar = { 2 | '/topics/discordjs/': [ 3 | '', 4 | 'tableOfContents', 5 | 'gettingStarted', 6 | 'firstCommand', 7 | ], 8 | '/topics/erelajs/': [ 9 | '', 10 | 'basics', 11 | 'moreCommands', 12 | 'advanced', 13 | 'updating' 14 | ], 15 | }; 16 | 17 | module.exports = sidebar; 18 | -------------------------------------------------------------------------------- /guide/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const sidebar = require('./components/Sidebar.js'); 2 | const nav = require('./components/Navbar.js'); 3 | const head = require('./components/Head.js'); 4 | 5 | const config = { 6 | title: 'MenuDocs Guide', 7 | head, 8 | theme: 'dart', 9 | themeConfig: { 10 | blogConfig: { 11 | category: { 12 | location: 2, 13 | text: 'Guides' 14 | } 15 | }, 16 | logo: '/images/logo.png', 17 | author: 'MenuDocs Community', 18 | noFoundPageByTencent: false, 19 | nav, 20 | sidebar, 21 | smoothScroll: true, 22 | sidebarDepth: 1, 23 | search: false, 24 | base: '/', 25 | lastUpdated: 'Last Updated', 26 | repo: 'MenuDocs/guides', 27 | editLinks: true, 28 | docsBranch: 'master', 29 | docsDir: 'guide', 30 | editLinkText: 'Contribute on Github!', 31 | displayAllHeaders: true, 32 | startYear: '2018', 33 | notFoundMessages: [ 34 | `Fun Fact: MenuDocs was founded in 2018 by Connor.`, 35 | `Fun Fact: We're here to stay, the end game doesnt exist. Many more games to play!`, 36 | `Fun Fact: We're happily sponsored by Oxide Hosting, they're one of the best sponsors any organisations could ask for! `, 37 | `Fun Fact: You found a dead end.` 38 | ], 39 | }, 40 | plugins: [ 41 | 'vuepress-plugin-element-tabs' 42 | ] 43 | }; 44 | 45 | module.exports = config; 46 | -------------------------------------------------------------------------------- /guide/.vuepress/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenuDocs/guides/fb01f6b8ce2385ef92ef5832d67b239066aeb831/guide/.vuepress/public/images/favicon.ico -------------------------------------------------------------------------------- /guide/.vuepress/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenuDocs/guides/fb01f6b8ce2385ef92ef5832d67b239066aeb831/guide/.vuepress/public/images/logo.png -------------------------------------------------------------------------------- /guide/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | .el-tabs--border-card { 2 | background: rgba(0, 0, 0, 0) !important; 3 | border: 1px solid rgba(0, 0, 0, 0.5) !important; 4 | } 5 | 6 | .el-tabs__header { 7 | background-color: rgba(0, 0, 0, 0) !important; 8 | border-bottom: 1px solid rgba(0, 0, 0, 0.5) !important; 9 | } 10 | 11 | .el-tabs__item.is-active { 12 | background-color: rgba(0, 0, 0, 0) !important; 13 | border-bottom: 1px solid rgba(0, 0, 0, 0.5) !important; 14 | border-left-color: rgba(0, 0, 0, 0.5) !important; 15 | border-right-color: rgba(0, 0, 0, 0.5) !important; 16 | } -------------------------------------------------------------------------------- /guide/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | $accentColor = #1787d1 2 | $navbarHeight = 3.4rem -------------------------------------------------------------------------------- /guide/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /images/logo.png 4 | heroText: The Official MenuDocs Guide 5 | tagline: Our educational resources but provided in a written format because we know everyone learns differently. 6 | actionText: Guides → 7 | actionLink: /categories/Javascript/ 8 | footer: © Created by the MenuDocs Community | 2020 9 | features: 10 | - title: Education 11 | details: This guide is here to provide the best, revised guide for your needs. People learn in different ways, having something you can reference may be the best for you. 12 | - title: Why Written? 13 | details: We acknowledge that some find it easier to follow a written tutorials than videos tutorials so we've decided to finally get around to working on our written guide. 14 | - title: Community 15 | details: This is a community driven guide, which means that our community are the ones contributing, writing and reviewing said guide. 16 | --- 17 | ::: tip 18 | You can contribute to these guides by adding new markdown files or editing the current ones in a pull request on our [repo here](https://github.com/MenuDocs/guides). 19 | ::: 20 | -------------------------------------------------------------------------------- /guide/topics/discordjs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction to Discord.js 3 | authors: 4 | - Solaris9 5 | - MenuDocs 6 | categories: 7 | - Javascript 8 | tags: 9 | - Discord.js 10 | - Bot Development 11 | --- 12 | A guide for the basics to moderate level of making a discord.js discord bot. 13 | 14 | 15 | ## Introduction 16 | 17 | If you're here then you're looking to learn about making a Discord bot using Discord.JS. If you don't know what either are then continue reading, if you do then you can skip to [Getting Started](/topics/discordjs/gettingstarted.md). 18 | 19 | What is a Discord bot? It is a "bot" account ran with code that has some special abilities a user account cannot do. First the most notable ones are that it is ran with code and they have no limit on the amount of guilds they can join. 20 | 21 | What can you do with a Discord bot? There are many uses for a Discord bot, moderating a guild, providing support (tickets, suggestions) or even playing music in voice channels and much more. 22 | 23 | What is Discord.js? Discord.js is a Node.js library built for the Discord API. It's mostly used to make Discord bots, but can be used in the browser to create a dashboard for your bot and more. 24 | 25 | What should I know before continuing? It's recommended that you understand at least the basics of JavaScript and how to read documentation, there will be learning resources below. 26 | 27 | Now that you understand what a Discord bot and what Discord.JS is and how they can be used and what is needed before you can [get started](/topics/discordjs/gettingstarted.md). 28 | 29 | ## Resources 30 | 31 | ### JavaScript and Node.JS 32 | 33 | Modernized JavaScript Tutorials: \ 34 | Learn Viral JavaScript Courses: \ 35 | CodeCademy online course: \ 36 | Eloquent JavaScript, free book: \ 37 | MDN's JavaScript guide: \ 38 | You Don't Know JS (free book series): \ 39 | Some Node.JS: \ 40 | JavaScript reference/docs: \ 41 | A page with Node.JS resources: \ 42 | Node.JS docs: (Main page: ) 43 | 44 | ### Discord and Discord.JS 45 | 46 | Discord API Docs: \ 47 | Discord Applications: \ 48 | Discord.JS Docs: 49 | 50 | ### Editors and IDEs 51 | 52 | Visual Studio Code: (Insiders: ) \ 53 | Atom: \ 54 | WebStorm: (Note: this is paid but is very powerful) 55 | Komodo Edit: \ 56 | Brackets: 57 | 58 | ### Extra 59 | 60 | GitHub Education: \ 61 | If you are a student you can apply for the GitHub Education pack which has some [perks](https://education.github.com/pack#offers) 62 | 63 | JetBrains: (Some free with GitHub Education)\ 64 | Educative: (Free with GitHub Education) 65 | -------------------------------------------------------------------------------- /guide/topics/discordjs/firstCommand.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating your first command 3 | authors: 4 | - NorteX-dev 5 | - MenuDocs 6 | tags: 7 | - Discord.js 8 | - Bot Developement 9 | - Basics 10 | --- 11 | 12 | Disclaimer: this tutorial assumes you've followed the [Getting Started](gettingStarted.md) tutorial. It also uses the `stable` branch of Discord.js, so double check if you are using it, or anything older. 13 | 14 | ## Setup 15 | In the previous tutorial ([Getting Started](gettingStarted.md)) you learned how to install Node with npm, your programming environment (IDE) and initialized the project. 16 | 17 | Just to remind us, this is the code we had set up in the end: 18 | ```javascript 19 | // Import the "[Client](https://discord.js.org/#/docs/main/stable/class/Client)" class from discord.js library 20 | const { Client } = require("discord.js"); 21 | // Initialize the client and assign it to a constant variable "client" 22 | const client = new Client(); 23 | // Listen to the "ready" event and print "I am ready!" whenever the bot is ready. 24 | client.once("ready", () => console.log("I am ready!")); 25 | // Authenticate the bot with your token from the Discord Developer Page 26 | client.login("-- Your Token --"); 27 | ``` 28 | This code tells the bot to listen to the "ready" event and print "I am ready!" whenever the bot is connected to the Discord API. 29 | 30 | Now, that we are up to date with the previous tutorial, we can start writing more code. 31 | 32 | ## Creating the event 33 | First off, you have to understand that commands are in fact just messages with a specific prefix. 34 | That being said, to create commands for your bot, you'll have to listen to the `message` event. 35 | 36 | Listening to the `message` event is very similar to listening to the `ready` event and is as follows: 37 | ```javascript 38 | client.on("message", (message) => { 39 | console.log("Hello!"); 40 | }); 41 | ``` 42 | Let's break this code down. As with the `ready` event, we are accessing the `client` variable. Then, we are using `.on()` which is a method that creates an _event listener_ on our Discord bot client. Events are the Node.js way of launching code when a certain thing happens, for example in our case, the bot connects to the Discord API or a message gets sent. You can read more about events in the [Node.js Events Documentation](https://nodejs.org/api/events.html). 43 | 44 | But wait! We can notice, that in the `ready` event, the method is `.once`, not `.on`! 45 | 46 | The difference between these two, is `once` - as the name suggests - only invokes once per execution and cannot be run again. `on` on the other hand can execute however many times the event happens. For our `message` event, we want to use the `on` method, as the command is sent more than one time - unlike `ready`, which should only execute once. 47 | 48 | Now with the `once` and `on` difference out of the way, we can look at the arguments - for both methods, it will always be two: 49 | - Event name 50 | - A callback function 51 | 52 | The event name is obviously the name of the event that we want to listen to. There are many events, e.g. these which we have learnt already: `ready` and `message`, but also `guildCreate`, `guildMemberAdd`, `messageDelete`, `roleCreate` and many, many more. You can see all of them in this handy [Discord events cheatsheet by koad](https://gist.github.com/koad/316b265a91d933fd1b62dddfcc3ff584). 53 | 54 | The second parameter is a callback. This will be executed once the event is triggered. Oftentimes, it takes in parameters specific for that type of event. Our `message` event, only returns 1 parameter: a message object which we will be able to utilize later in the guide. 55 | 56 | You can place the event anywhere between the client initialization and the logging in of the client. The best place for it, would be after the `ready` event to keep the code understandable and clean. 57 | 58 | ## Responding to the message 59 | If you set up the code correctly, now, when the code is being run, and a message on any server with your bot is sent, a log should appear in our console. 60 | 61 | Next up, we will discuss how we can use the `message` object returned from the event to send a response in the channel that the message has been sent. 62 | 63 | `message` object has the following properties in it: 64 | - author - returns the [User](https://discord.js.org/#/docs/main/stable/class/User) that has sent the message. 65 | - channel - returns the [TextChannel](https://discord.js.org/#/docs/main/stable/class/TextChannel) that the message has been sent in. 66 | - content - returns the content of the message 67 | - guild - returns the [Guild](https://discord.js.org/#/docs/main/stable/class/Guild) (server) of where the message was sent in 68 | - id - returns the ID of the message - this is especially useful when saving a reference to the message 69 | 70 | And a few functions, too: 71 | - delete() - deletes the message 72 | - pin() - pins the message to the channel 73 | - react(emoji) - reacts to the message with an emoji object 74 | 75 | There are many more properties in the `message` class, however these are the most used ones. If you'd like to get to know each one of them, you can view it here: [Message Class on discord.js.org](https://discord.js.org/#/docs/main/stable/class/Message) 76 | 77 | Having these in mind, we can construct the following code: 78 | ```javascript 79 | client.on("message", (message) => { 80 | if(message.author.bot) return; 81 | if(!message.guild) return; 82 | 83 | message.channel.send(`Hello, ${message.author.username}!`); 84 | }); 85 | ``` 86 | 87 | To make sure that the bot will not fall in a loop responding to it's own messages, we have to add two `if` statements. First one is to check if the author is a bot. If so, `return` - stop - the code. That is to prevent any bots, including the one we are making, from (self-)firing commands. The second check (on line 3) sees if the guild is present in the message object, as we don't want to listen to DM messages. Now, that we are sure that the bot will not fall into a loop and that guild is present on the object, we can move on. In the first bit of the last line, we are looking at `message` and then accessing the `channel` property of it. That returns the channel that the message was sent in. Channels have a method [`.send(content)`](https://discord.js.org/#/docs/main/stable/class/TextChannel?scrollTo=send) that sends a message to them - and it requires a parameter of what the content of that message should be. 88 | 89 | With this code, we can `send` a message in `channel` that the original `message` was sent. Inside the `.send()` function, we can find a template string - indicated with backticks as opposed to the normal quotes. This allowes us to embed some code in the message: `${message.author.username}`. Here, again, we are looking at `message`, but this time not the `channel`, but instead the `author` of that message. That returns a user that sent that message. Then, we are getting the username from it. Easy! 90 | 91 | With this, the bot should respond "Hello, [username]!", for example "Hello, NorteX!" if it sees any message on any channel. 92 | 93 | ## Making a command 94 | In the first sentence of creating the event, I said that all commands are prefixed messages. So, let's try and make a very simple command handler. 95 | ```javascript 96 | client.on("message", (message) => { 97 | if(message.author.bot) return; 98 | if(!message.guild) return; 99 | 100 | // What do we split on? 101 | // We split on spaces. The text inside the slashes indicates it's a RegExp. 102 | // A RegExp is a way to match values in a string. 103 | // How this RegExp works, is that we match on " " (space). 104 | // Then the `+` indicates that we wish to match as many spaces in a row as possible. 105 | // That way the amount of spaces between your args doesn't matter. 106 | 107 | const [command, ...args] = message.content.split(/ +/g); 108 | }); 109 | ``` 110 | 111 | Before going any further, let's quickly discuss this code. Again, we are listening to the `message` event, nothing different here. In the next line, we are creating a variable named `split` which is assigned to the message content *split with spaces*. 112 | 113 | Take this example for example: 114 | 115 | The message content is: "!ban user reason", a very simple ban command. 116 | 117 | So, in the code above, we're declaring 2 variables - command and args - from message.content.split(" ") via a "destructuring assignment". Each variable represents an index in the array. So const command = `message.content.split(" ")[0];` is the same as the command variable, and the args variable will be filled with the rest - meaning, it would equal to something like `message.content.split(" ").slice(1)`. 118 | 119 | For more information on destructuring assignment, check out the [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). 120 | 121 | Ok. Now, for example `user` or `reason` in our command are going to be stored in the `args` array, so we can access it later. 122 | 123 | Ok, moving on with the code! 124 | ```javascript 125 | client.on("message", (message) => { 126 | if(message.author.bot) return; 127 | if(!message.guild) return; 128 | 129 | const [command, ...args] = message.content.split(/ +/g); 130 | 131 | if(command.toLowerCase() === "!ping") { 132 | message.channel.send("Pong!"); 133 | } 134 | }); 135 | ``` 136 | 137 | Now, a very straightforward `if` statement checks if the `command` string is equal to `!ping`. We make this comparison before sending the response to ensure the right command is ran. We also force it to lowercase to allow running commands without worrying about case sensitivity. 138 | 139 | ## Conclusion 140 | 141 | This is the basics of how you can make your own commands. You can of course add much more code to your command. Be creative! 142 | 143 | This is the final code that we made to add our simple "ping" command and set up code for further commands: 144 | 145 | ```javascript 146 | const { Client } = require("discord.js"); 147 | 148 | const client = new Client(); 149 | 150 | client.once("ready", () => console.log("I am ready!")); 151 | client.on("message", (message) => { 152 | if(message.author.bot) return; 153 | if(!message.guild) return; 154 | 155 | const [command, ...args] = message.content.split(/ +/g); 156 | 157 | if(command.toLowerCase() === "!ping") { 158 | message.channel.send("Pong!"); 159 | } 160 | }); 161 | 162 | client.login("-- Your Token --"); 163 | ``` 164 | -------------------------------------------------------------------------------- /guide/topics/discordjs/gettingStarted.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | --- 4 | 5 | ## Creating a bot 6 | 7 | Before you start programming a Discord bot you need to create a bot application first. If you would like to visually see this you can follow the video down below, but if you prefer reading you can look below for a quick and easy guide on making your bot. 8 | 9 |
11 | 18 |
19 | 20 | TODO: show how to make a bot account 21 | 22 | ## Project setup 23 | 24 | Now that you have your bot application you need to program and run it. 25 | 26 | First you will need to download and install [Node.JS](https://nodejs.org/en/download/). You might notice two different versions, LTS and Current. LTS means Long Term Support, it'll be supported for as long as the developers can. Current is the most stable version. There is also nightly builds which are previews of whats to come, these shouldn't be used as there's no guarantee it will function normally. 27 | 28 | Secondly you will need either a code editor or a IDE to edit the code. You can find some editors and IDEs [here](/topics/discordjs/#editors-and-ides). Some might require a add-on for syntax or linting support with JavaScript, if it does not it should prompt you to add it or you can search how to add it. Personally I use Visual Studio Code Insiders and **_will be throughout this guide_** but you're free to use any you like. 29 | 30 | Once you have both installed you can start setting up the project files by creating a new folder or use a existing one for the bot files to reside, you can name it anything you like. Next is to open the folder in your editor, usually this can be done by right-clicking the folder and selecting `Open with ` or clicking `File` at the top left in the editor and selecting `Open Folder`. 31 | 32 | After you have the editor open it's time to do the first step for any Node.JS project, creating a `package.json` and installing Node modules through the command line. If your editor has a integrated terminal you can open that, it does not or you prefer to use your OS terminal then you can open that. For Windows you can open the folder and click the path URL and write `cmd` and hit enter to open a Command Prompt. For Linux you usually can open the terminal from a dropdown button in the folder or right click in the empty space (TODO: improve this). 33 | 34 | Once you have a terminal open you can run your first command. 35 | 36 | ```shell 37 | npm init 38 | ``` 39 | 40 | What is `npm` though? NPM is **N**ode.JS **P**ackage **M**anager that you can use to manage your projects packages or "dependencies" as it's called when your project "depends" on another. Here we are using the main command `npm` with a sub-command `init` which will run through a few questions and create a `package.json` file once complete. This file will store some basic information and dependencies. When you get a question it will look like `package name: (discordjs-tutorial)`, for some it will show parentheses and some content inside them, that is the default answer if you do not give one. Some wont have parentheses such as `description:` because it does not have a default answer, it's optional and can be left blank. You can edit any of this in the `package.json` later on. 41 | 42 | If you are curious about the other sub-commands you can look at [NPM's command line documentation](https://docs.npmjs.com/cli-documentation/cli) but we will only cover a few throughout this guide. 43 | 44 | After that process is finished you can now install a package. 45 | 46 | ```shell 47 | npm install discord.js 48 | ``` 49 | 50 | As said before we are using the main command `npm` with a sub-command `install` and a package to install which is `discord.js`. You'll see the terminal fly through some lines and a new folder called `node_modules`, this is where your dependencies are stored to be used in your code. 51 | 52 | Next you can create a file named `index.js`, it must end in `.js` for two reasons, one for your editor to properly highlight the syntax, and two for Node.JS to know it's a JavaScript file. 53 | 54 | Congratulations, you've completed the first steps to making a Discord bot! 55 | 56 | ## Writing your first program 57 | 58 | Now that you have your project setup you can start coding. By being at this section you know at least the basics of [JavaScript and Node.JS](/topics/discordjs/#javascript-and-node-js), if not then I highly suggest you follow that hyperlink and read one of those resources. In this beginning part of this guide I will be explaining all the code I provide. 59 | 60 | Copy and paste this into your editor. 61 | 62 | ```javascript 63 | const { Client } = require("discord.js"); 64 | 65 | const client = new Client(); 66 | 67 | client.once("ready", () => console.log("I am ready!")); 68 | 69 | client.login("token"); 70 | ``` 71 | 72 | Replace `token` with your bot token found in the Discord Applications page when you created your bot and save the file. Next in your open terminal run this command. 73 | 74 | ```shell 75 | node index.js 76 | ``` 77 | 78 | You should see the terminal show `I am ready!`. Congratulations, you just programmed your first Discord bot. But what does all of that do and what command is `node`? 79 | 80 | First I'll explain what the `node` command is. Every application on your computer has a main command, for Node.JS it's `node`, running this command with a JavaScript file will execute the code inside of it. If you do not like typing the command every time you can do two things, one is use `node .` which will use the `entry point` set in the `package.json`, by default it is `index.js`, if you named your file something else or it is in a sub directory you can rename that value accordingly. The other thing you can do is press the up arrow on your keyboard, this usually scrolls through the terminal history, you can use it to quickly get the command back and run it. There are other options like using `nodemon` to restart your program every time a file is saved but we'll get to that later on. 81 | 82 | Now what does all of that code do? If you know the basics of [JavaScript and Node.JS](/topics/discordjs/#javascript-and-node-js) you should understand some, if not most of it. 83 | 84 | The first line requires the `discord.js` module and assigns the deconstructed value `Client` by its name as a constant. `require` is only available in Node.JS and it can import files, [directories](https://stackoverflow.com/a/5365577/13257043) or modules. A constant is a variable that cannot be re-declared and must have a value assigned to it. Deconstructing is taking a value by name from a object and using it by itself, an is example below. 85 | 86 | ```javascript 87 | // Define a constant with a object as the value that has it's own property and value. 88 | const foo = { bar: "bar" }; 89 | 90 | // Extract the foo variable and define it as its own. 91 | const { bar } = foo; 92 | 93 | // Print the variable to the terminal without doing "console.log(foo.bar)". 94 | console.log(bar) // bar 95 | ``` 96 | 97 | I know that was big explanation so let's move to the second line. There you initiate the `Client` class and assign it to the `client` variable as a constant. 98 | 99 | The third line is a bit special, since you have to know when the bot is ready you need an event listener, thats what this line does. The `Client` class extends `EventEmitter` and lets you listen to events using `on` and `once` methods. Here we listen to the `ready` event which is sent every time your bot becomes ready, but since we don't want our terminal being spammed with messages so we'll use `once` so it only runs `once`. The second parameter is an inline [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) that prints a message to the console letting us know the bot is ready. 100 | 101 | The last line is a method that logins into the Discord WebSocket with your bot token to receive events and to make HTTP requests for sending message, adding roles, etc. 102 | 103 | Now that you understand what that snippet of code we can dive into more. 104 | -------------------------------------------------------------------------------- /guide/topics/discordjs/tableOfContents.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Table of Contents 3 | --- 4 | 5 | Here are all of the available topics - 6 | 7 | - [Getting Started](gettingStarted.md) - The first steps to making a Discord bot. 8 | - [Creating your first command](firstCommand.md) - Learn how to create your first command. 9 | -------------------------------------------------------------------------------- /guide/topics/erelajs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction to Erela.js 3 | authors: 4 | - Solaris9 5 | - MenuDocs 6 | categories: 7 | - Javascript 8 | tags: 9 | - Erela.js 10 | - Bot Development 11 | --- 12 | 13 | ## What is Erela.js? 14 | 15 | Erela.js is a Lavalink client was made after seeing how others were made, most are bare bones and require the user to add much more complicated code. 16 | 17 | Erela.js is designed to be as easy to use and offer as many features as possible including easy to read documentation, easy overall usage, many events to listen to, extendable classes and plugins. 18 | 19 | ## Resources 20 | 21 | ### JavaScript and Node.JS 22 | 23 | Modernized JavaScript Tutorials: \ 24 | Learn Viral JavaScript Courses: \ 25 | CodeCademy online course: \ 26 | Eloquent JavaScript, free book: \ 27 | MDN's JavaScript guide: \ 28 | You Don't Know JS (free book series): \ 29 | Some Node.JS: \ 30 | JavaScript reference/docs: \ 31 | A page with Node.JS resources: \ 32 | Node.JS docs: (Main page: ) 33 | 34 | ### Discord 35 | 36 | Discord API Docs: \ 37 | Discord Applications: \ 38 | Discord.JS Docs: \ 39 | Eris Docs: 40 | -------------------------------------------------------------------------------- /guide/topics/erelajs/advanced.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Advanced 3 | displayHeaders: true 4 | sidebarDepth: 1 5 | --- 6 | 7 | ## Player data 8 | 9 | Players can hold custom data like the text channel object or more. 10 | All of this data is similar to a Map and can be referenced easily as shown below. 11 | 12 | ```javascript 13 | const player = manager.create(/* options */); 14 | 15 | // Settings data 16 | player.set("textChannel", message.channel); 17 | 18 | // Getting data 19 | const textChannel = player.get("textChannel"); 20 | ``` 21 | 22 | Now the type will show as `any` for typings, but you can add some JSDoc in your editor to give it a proper type for your editor. 23 | 24 | ```javascript 25 | /** @type {import("discord.js").TextChannel} */ 26 | const textChannel = player.get("textChannel"); 27 | ``` 28 | 29 | ## Track Partials 30 | 31 | If you only need a part of the track object then you can provide an array with the properties to keep. 32 | The [`track`](/docs/typedefs/Track.html#track) property will always be present as it's required to play tracks. 33 | 34 | ```javascript 35 | const { Manager } = require("erela.js"); 36 | 37 | const manager = new Manager({ 38 | trackPartial: [ "title", "duration", "requester" ] // Every track object will have these properties. 39 | }) 40 | ``` 41 | 42 | ## UnresolvedTrack 43 | 44 | Lavalink will only play from the sources enabled, if you want to use Spotify links you'll have to get the YouTube equivalent. 45 | Erela offers a UnresolvedTrack option that will resolve into a playable track before its played. 46 | This is useful for supporting other sources without sending dozens of requests to YouTube for playlists in a short time. 47 | 48 | ```javascript 49 | const { TrackUtils } = require("erela.js"); 50 | 51 | // Basic way using just a query. 52 | const unresolvedTrack = TrackUtils.buildUnresolved("Never gonna give you up - Rick Astley", message.author.tag); 53 | 54 | // Advanced way using the title, author, and duration for a precise search. 55 | const unresolvedTrack = TrackUtils.buildUnresolved({ 56 | title: "Never gonna give you up", 57 | author: "Rick Astley", 58 | duration: 213000 59 | }, message.author.tag); 60 | 61 | player.queue.add(unresolvedTrack); 62 | // Or. 63 | player.play(unresolvedTrack); 64 | ``` 65 | 66 | ## Extending 67 | 68 | You can extend Erela.js' classes to add more functionality like adding some extra handy methods. 69 | 70 | ::: tip 71 | You should not do exactly this as it is a waste of resources, a better way would be to slice the array before formatting it, but for space here I omitted it. 72 | ::: 73 | 74 | ```javascript 75 | const { Structure } = require("erela.js"); 76 | 77 | Structure.extend("Queue", Queue => class extends Queue { 78 | format(string, ...vars) { 79 | return this.map(track => { 80 | let local = string; 81 | for (let i in vars) local = local.replace(`{${i}}`, track[vars[i]]); 82 | return local; 83 | }) 84 | } 85 | }) 86 | ``` 87 | 88 | Then you can use it as so. 89 | 90 | ```javascript 91 | const tracks = player.queue.format("[{0}]({1})", "title", "uri"); 92 | ``` 93 | 94 | ## Plugins 95 | 96 | Erela.js' functionality can be expanded even more with the use of plugins, they can add all sorts of new functions such as saving the queue as a playlist and more. 97 | 98 | ### Using plugins 99 | 100 | ```javascript 101 | const { Manager } = require("erela.js"); 102 | const MyPlugin = require("my-erela.js-plugin"); 103 | 104 | const manager = new Manager({ 105 | plugins: [ new MyPlugin({ foo: "bar" }) ] 106 | }) 107 | ``` 108 | 109 | ### Writing plugins 110 | 111 | ```javascript 112 | const { Plugin } = require("erela.js"); 113 | 114 | module.exports = class MyPlugin extends Plugin { 115 | constructor(options) { 116 | super(); 117 | this.options = options; // will be { foo: 'bar' } 118 | } 119 | 120 | load(manager) {} 121 | } 122 | ``` 123 | 124 | ### Spotify 125 | 126 | You can search using Spotify URL's using the [Spotify plugin](https://github.com/Solaris9/erela.js-spotify) for Erela.JS. 127 | -------------------------------------------------------------------------------- /guide/topics/erelajs/basics.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basics 3 | displayHeaders: true 4 | sidebarDepth: 1 5 | --- 6 | 7 | ## Installation 8 | 9 | ::: tip 10 | This guide assumes you already have knowledge about JavaScript and a Discord API library installed, for this guide Discord.JS will be used. 11 | ::: 12 | 13 | To start using Erela.js you first have to install it using NPM or Yarn. 14 | 15 | :::: tabs type:border-card stretch:true 16 | 17 | ::: tab NPM 18 | ```bash 19 | npm install erela.js 20 | ``` 21 | ::: 22 | 23 | ::: tab Yarn 24 | ```bash 25 | yarn add erela.js 26 | ``` 27 | ::: 28 | :::: 29 | 30 | ## First start 31 | 32 | The first place to start with Erela.js is the Manager class with some [options](/docs/typedefs/ManagerOptions.html). 33 | 34 | ```javascript 35 | // Require both libraries 36 | const { Client } = require("discord.js"); 37 | const { Manager } = require("erela.js"); 38 | 39 | // Initiate both main classes 40 | const client = new Client(); 41 | 42 | // Define some options for the node 43 | const nodes = [ 44 | { 45 | host: "localhost", 46 | password: "youshallnotpass", 47 | port: 2333, 48 | } 49 | ]; 50 | 51 | // Assign Manager to the client variable 52 | client.manager = new Manager({ 53 | // The nodes to connect to, optional if using default lavalink options 54 | nodes, 55 | // Method to send voice data to Discord 56 | send: (id, payload) => { 57 | const guild = client.guilds.cache.get(id); 58 | // NOTE: FOR ERIS YOU NEED JSON.stringify() THE PAYLOAD 59 | if (guild) guild.shard.send(payload); 60 | } 61 | }); 62 | 63 | // Emitted whenever a node connects 64 | client.manager.on("nodeConnect", node => { 65 | console.log(`Node "${node.options.identifier}" connected.`) 66 | }) 67 | 68 | // Emitted whenever a node encountered an error 69 | client.manager.on("nodeError", (node, error) => { 70 | console.log(`Node "${node.options.identifier}" encountered an error: ${error.message}.`) 71 | }) 72 | 73 | // Listen for when the client becomes ready 74 | client.once("ready", () => { 75 | // Initiates the manager and connects to all the nodes 76 | client.manager.init(client.user.id); 77 | console.log(`Logged in as ${client.user.tag}`); 78 | }); 79 | 80 | // THIS IS REQUIRED. Send raw events to Erela.js 81 | client.on("raw", d => client.manager.updateVoiceState(d)); 82 | 83 | // Finally login at the END of your code 84 | client.login("your bot token here"); 85 | ``` 86 | 87 | ## The play command 88 | 89 | The whole idea of a music bot is to play music right? So let's write a command to play songs. 90 | 91 | First you want to listen to the message event. 92 | 93 | ```javascript 94 | // Add the previous code block to this 95 | 96 | client.on("message", async message => { 97 | // Some checks to see if it's a valid message 98 | if (!message.content.startsWith("!") || !message.guild || message.author.bot) return; 99 | 100 | // Get the command name and arguments 101 | const [command, ...args] = message.content.slice(1).split(/\s+/g); 102 | 103 | // Check if it's the play command 104 | if (command === "play") { 105 | if (!message.member.voice.channel) return message.reply("you need to join a voice channel."); 106 | if (!args.length) return message.reply("you need to give me a URL or a search term."); 107 | 108 | const search = args.join(" "); 109 | let res; 110 | 111 | try { 112 | // Search for tracks using a query or url, using a query searches youtube automatically and the track requester object 113 | res = await client.manager.search(search, message.author); 114 | // Check the load type as this command is not that advanced for basics 115 | if (res.loadType === "LOAD_FAILED") throw res.exception; 116 | else if (res.loadType === "PLAYLIST_LOADED") throw { message: "Playlists are not supported with this command." }; 117 | } catch (err) { 118 | return message.reply(`there was an error while searching: ${err.message}`); 119 | } 120 | 121 | if (res.loadType === "NO_MATCHES") return message.reply("there was no tracks found with that query."); 122 | 123 | // Create the player 124 | const player = client.manager.create({ 125 | guild: message.guild.id, 126 | voiceChannel: message.member.voice.channel.id, 127 | textChannel: message.channel.id, 128 | }); 129 | 130 | // Connect to the voice channel and add the track to the queue 131 | player.connect(); 132 | player.queue.add(res.tracks[0]); 133 | 134 | // Checks if the client should play the track if it's the first one added 135 | if (!player.playing && !player.paused && !player.queue.size) player.play() 136 | 137 | return message.reply(`enqueuing ${res.tracks[0].title}.`); 138 | } 139 | }); 140 | ``` 141 | 142 | ## Events 143 | 144 | You can play songs but what about knowing when a song starts or end? Those are events that the Manager class emits. 145 | 146 | ```javascript 147 | client.manager = new Manager(/* options above */) 148 | // Chain it off of the Manager instance 149 | // Emitted when a node connects 150 | .on("nodeConnect", node => console.log(`Node "${node.options.identifier}" connected.`)); 151 | 152 | // Or each listener on their own 153 | // Emitted when a track starts 154 | client.manager.on("trackStart", (player, track) => { 155 | const channel = client.channels.cache.get(player.textChannel); 156 | // Send a message when the track starts playing with the track name and the requester's Discord tag, e.g. username#discriminator 157 | channel.send(`Now playing: \`${track.title}\`, requested by \`${track.requester.tag}\`.`); 158 | }); 159 | 160 | // Emitted the player queue ends 161 | client.manager.on("queueEnd", player => { 162 | const channel = client.channels.cache.get(player.textChannel); 163 | channel.send("Queue has ended."); 164 | player.destroy(); 165 | }); 166 | ``` 167 | -------------------------------------------------------------------------------- /guide/topics/erelajs/moreCommands.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: More Commands 3 | displayHeaders: true 4 | sidebarDepth: 1 5 | --- 6 | 7 | 8 | A music bot with one command isn't really the best so let's add a few more! This will go through most commands including an improved play command. 9 | 10 | ## Before you start 11 | 12 | Writing every command in the main file will get a bit chaotic so let's move each command to its own file. 13 | 14 | First we need to modify the code a bit to add a map of the commands. 15 | 16 | ```diff 17 | - const { Client } = require("discord.js"); 18 | + const { Client, Collection } = require("discord.js"); 19 | + const { readdirSync } = require("fs"); 20 | const { Manager } = require("erela.js"); 21 | 22 | const client = new Client(); 23 | client.manager = new Manager(/* options */); 24 | 25 | + client.commands = new Collection(); 26 | ``` 27 | 28 | ## Loading commands 29 | 30 | We have to find and load all the commands in the `commands` folder so add the following below `client.commands`. 31 | 32 | ```javascript 33 | // Read all the files in the ./commands directory 34 | const files = readdirSync("./commands").filter(file => file.endsWith(".js")); 35 | 36 | // Iterate over all the found files 37 | for (const file of files) { 38 | // Require the file 39 | const command = require(`./commands/${file}`); 40 | // Set the command in the commands collection 41 | client.commands.set(command.name, command); 42 | } 43 | ``` 44 | 45 | ## Running commands 46 | 47 | Then we have to run the command in the message event. Remove the current event as we'll be rewriting it. 48 | 49 | ```javascript 50 | // Previous code blocks in #basics before the message event with the modified code above 51 | 52 | client.on("message", async message => { 53 | if (!message.content.startsWith("!") || !message.guild || message.author.bot) return; 54 | const [name, ...args] = message.content.slice(1).split(/\s+/g); 55 | 56 | // Get the command and check if it exists 57 | const command = client.commands.get(name); 58 | if (!command) return; 59 | 60 | // Run the command and catch any errors 61 | try { 62 | command.run(message, args); 63 | } catch (e) { 64 | message.reply(`an error occurred while running the command: ${err.message}`); 65 | } 66 | }); 67 | ``` 68 | 69 | ## Adding commands 70 | 71 | Lastly, we need a command to load. Let's start with a simple `ping` command to make sure the command handler works. 72 | 73 | In the `commands` folder add a `ping.js` file with the following contents. 74 | 75 | ::: tip 76 | Here I omitted the `args` parameter as it is not used, Node.js will not throw an error if you do not have a parameter passed in the function call. 77 | ::: 78 | 79 | ```javascript 80 | module.exports = { 81 | // The name of the command, this has to be different in every command 82 | name: "ping", 83 | // The function to run every time the command is ran by a user 84 | run: (message) => { 85 | message.reply("Pong!") 86 | } 87 | } 88 | ``` 89 | 90 | Now start your bot and run `!ping`, you should see the bot reply with `@User, Pong!`, congratulations! 91 | 92 | ## More Commands 93 | 94 | A music bot with only a ping command isn't really that great, so I've created some basic commands you can find in the [examples folder](https://github.com/Solaris9/erela.js/tree/HEAD/examples). 95 | 96 | Those aren't the only commands you can have. You can make some clear the queue, remove tracks, skip the current track and even more! 97 | 98 | -------------------------------------------------------------------------------- /guide/topics/erelajs/updating.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Updating 3 | displayHeaders: true 4 | sidebarDepth: 1 5 | --- 6 | 7 | ::: tip 8 | Anything not specified means it was not changed or forgotten to be added here. Feel free to send a PR with the changed item. 9 | ::: 10 | 11 | ## ErelaClient 12 | 13 | Previously: 14 | ```javascript 15 | const { ErelaClient } = require("erela.js"); 16 | const { Client } = require("discord.js"); 17 | 18 | const client = new Client(); 19 | const nodes = [ 20 | { 21 | host: "localhost", 22 | password: "youshallnotpass", 23 | port: 2333 24 | } 25 | ]; 26 | 27 | const options = {}; 28 | 29 | client.music = new ErelaClient(client, nodes, options) 30 | ``` 31 | New: 32 | ```javascript 33 | const { Manager } = require("erela.js"); 34 | const { Client } = require("discord.js"); 35 | 36 | const client = new Client(); 37 | const nodes = [ 38 | { 39 | host: "localhost", 40 | password: "youshallnotpass", 41 | port: 2333 42 | } 43 | ]; 44 | 45 | client.music = new Manager({ 46 | nodes, 47 | send: (id, payload) => { 48 | const guild = client.guilds.cache.get(id); 49 | if (guild) guild.shard.send(payload); 50 | } 51 | }) 52 | ``` 53 | 54 | Previous in Erela.js v1 you would initiate the ErelaClient class, this was changed to Manager with different parameters. 55 | 56 |

What changed

57 | 58 | - ErelaClient was renamed to Manager 59 | - You no longer need to pass the client 60 | - Most of the node options can be omitted 61 | - You no longer need to provide a node if you're using completely default lavalink options 62 | - You ***need*** provide a `send` function to send voice data to Discord 63 | 64 | ## Player 65 | 66 | ## Creating players 67 | 68 | Before you had to get the PlayerStore and use the `spawn` method to create a Player, now PlayerStore was removed as it's completely useless and bloated the package. 69 | 70 | You can still create players using a similar method named `create` like so: 71 | 72 | ```javascript 73 | const player = manager.create(options); 74 | ``` 75 | 76 | Or directly off the Player class: 77 | 78 | ```javascript 79 | const player = new Player(options); 80 | ``` 81 | 82 | In both these examples the [`options`](/docs/typedefs/ManagerOptions.html) is same as before. 83 | 84 | ## Destroying players 85 | 86 | In v1 you had to destroy players using the PlayerStore `destroy` method, now you use it off of the Manager class or directly on the Player class. 87 | 88 | ```javascript 89 | const player = manager.get("guildId") 90 | 91 | manager.destroy("guildId"); 92 | 93 | // Or 94 | 95 | player.destroy(); 96 | ``` 97 | 98 | ## Setting equalizer 99 | 100 | Before v2 you had to provide an array of objects to set the equalizer, now you just have to put each object on their own. 101 | If your band objects are in an array you can use the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to *spread* the objects out. 102 | 103 | ```javascript 104 | // Before 105 | player.setEQ([{ band: 0, gain: .25}, { band: 2, gain: .25}]) 106 | 107 | // After 108 | player.setEQ({ band: 0, gain: .25}, { band: 1, gain: .25}) 109 | ``` 110 | 111 | ## Connecting to voice 112 | 113 | Before Erela.js would automatically connect to the voice channel. Now you must use the Player#connect() method. 114 | 115 | ```javascript 116 | const player = new Player(options); 117 | player.connect(); 118 | ``` 119 | 120 | ## Queue 121 | 122 | The Queue class had some changed regarding the current song, before it was the first element in the array but was changed to the `current` property. 123 | 124 | ## Utils 125 | 126 | The utils was removed as it bloated the package and didn't offer as much flexibility. There are some packages below to parse and format times. 127 | 128 | ## Format time 129 | 130 | - [https://www.npmjs.com/package/humanize-duration](https://www.npmjs.com/package/humanize-duration) 131 | 132 | ## Parse time 133 | 134 | - [https://www.npmjs.com/package/timestring](https://www.npmjs.com/package/timestring) 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "menudocs-guide", 3 | "version": "0.0.2", 4 | "description": "This is the long awaited guide for menudocs", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "dev": "vuepress dev guide", 8 | "build": "vuepress build guide" 9 | }, 10 | "author": "Connor Moriarty", 11 | "license": "MIT", 12 | "dependencies": { 13 | "vuepress": "^1.5.0", 14 | "vuepress-plugin-element-tabs": "^0.2.8", 15 | "vuepress-theme-dart": "git+https://github.com/MenuDocs/vuepress-theme-dart.git" 16 | }, 17 | "devDependencies": { 18 | "eslint": "^7.1.0", 19 | "eslint-config-tesseract": "^0.0.2", 20 | "watchpack": "^1.6.1" 21 | } 22 | } 23 | --------------------------------------------------------------------------------