Merge branch 'master' into code-refactor

This commit is contained in:
hydrabolt
2015-10-03 14:45:40 +01:00
83 changed files with 29816 additions and 2791 deletions

3
.gitignore vendored
View File

@@ -4,6 +4,8 @@ hydrabot/config.json
hydrabot/authority.json
hydrabot/tokencache.json
.tmp/
### Node ###
# Logs
logs
@@ -32,3 +34,4 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
test/auth.json

3
.travis.yml Normal file
View File

@@ -0,0 +1,3 @@
language: node_js
node_js:
- "stable"

2
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,2 @@
// Place your settings in this file to overwrite default and user settings.
{ "editor.wrappingColumn": 0 }

220
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,220 @@
// Available variables which can be used inside of strings.
// ${workspaceRoot}: the root folder of the team
// ${file}: the current opened file
// ${fileBasename}: the current opened file's basename
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
// A task runner that calls the Typescript compiler (tsc) and
// Compiles a HelloWorld.ts program
{
"version": "0.1.0",
"command" : "babel",
"isShellCommand": true,
"tasks": [
{
"taskName": "watch",
"suppressTaskName": true,
"isBuildCommand": true,
"isWatching": true,
"args": [
"src", "--out-dir", "lib", "-w"
]
}
]
}
// A task runner that calls the Typescript compiler (tsc) and
// compiles based on a tsconfig.json file that is present in
// the root of the folder open in VSCode
/*
{
"version": "0.1.0",
// The command is tsc. Assumes that tsc has been installed using npm install -g typescript
"command": "tsc",
// The command is a shell script
"isShellCommand": true,
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Tell the tsc compiler to use the tsconfig.json from the open folder.
"args": ["-p", "."],
// use the standard tsc problem matcher to find compile problems
// in the output.
"problemMatcher": "$tsc"
}
*/
// A task runner configuration for gulp. Gulp provides a less task
// which compiles less to css.
/*
{
"version": "0.1.0",
"command": "gulp",
"isShellCommand": true,
"tasks": [
{
"taskName": "less",
// Make this the default build command.
"isBuildCommand": true,
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Use the standard less compilation problem matcher.
"problemMatcher": "$lessCompile"
}
]
}
*/
// Uncomment the following section to use gulp in a watching mode that compiles a
// less file. The gulp task prints "[hh:mm:ss] Starting 'clean-styles'" to the console
// when existing css files get deleted and "[hh:mm:ss] Finished 'styles'" when the
// overall less compilation has finished. When the clean pattern is detect internal less
// problems are cleaned. When the finshed pattern is detected in the output less
// problems are published.
/*
{
"version": "0.1.0",
"command": "gulp",
"isShellCommand": true,
"tasks": [
{
"taskName": "watch-less",
// Make this the default build command.
"isBuildCommand": true,
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Task is running in watching mode.
"isWatching": true,
"problemMatcher": {
// Use the standard less compilation problem matcher as the base.
"base": "$lessCompile",
// A regular expression signalling that a watched task begins executing (usually triggered through file watching).
"watchedTaskBeginsRegExp": "^\\[\\d+:\\d+:\\d+\\] Starting 'clean-styles'\\.\\.\\.$",
// A regular expression signalling that a watched tasks ends executing.
"watchedTaskEndsRegExp": "^\\[\\d+:\\d+:\\d+\\] Finished 'styles' after \\d+"
}
}
]
}
*/
// Uncomment the following section to use jake to build a workspace
// cloned from https://github.com/Microsoft/TypeScript.git
/*
{
"version": "0.1.0",
// Task runner is jake
"command": "jake",
// Need to be executed in shell / cmd
"isShellCommand": true,
"showOutput": "silent",
"tasks": [
{
// TS build command is local.
"taskName": "local",
// Make this the default build command.
"isBuildCommand": true,
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Use the redefined Typescript output problem matcher.
"problemMatcher": [
"$tsc"
]
}
]
}
*/
// Uncomment the section below to use msbuild and generate problems
// for csc, cpp, tsc and vb. The configuration assumes that msbuild
// is available on the path and a solution file exists in the
// workspace folder root.
/*
{
"version": "0.1.0",
"command": "msbuild",
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true"
],
"taskSelector": "/t:",
"showOutput": "silent",
"tasks": [
{
"taskName": "build",
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Use the standard MS compiler pattern to detect errors, warnings
// and infos in the output.
"problemMatcher": "$msCompile"
}
]
}
*/
// Uncomment the following section to use msbuild which compiles Typescript
// and less files.
/*
{
"version": "0.1.0",
"command": "msbuild",
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true"
],
"taskSelector": "/t:",
"showOutput": "silent",
"tasks": [
{
"taskName": "build",
// Show the output window only if unrecognized errors occur.
"showOutput": "silent",
// Use the standard MS compiler pattern to detect errors, warnings
// and infos in the output.
"problemMatcher": [
"$msCompile",
"$lessCompile"
]
}
]
}
*/
// A task runner example that defines a problemMatcher inline instead of using
// a predfined one.
/*
{
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"args": ["HelloWorld.ts"],
"showOutput": "silent",
"problemMatcher": {
// The problem is owned by the typescript language service. Ensure that the problems
// are merged with problems produced by Visual Studio's language service.
"owner": "typescript",
// The file name for reported problems is relative to the current working directory.
"fileLocation": ["relative", "${cwd}"],
// The actual pattern to match problems in the output.
"pattern": {
// The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'.
"regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
// The match group that denotes the file containing the problem.
"file": 1,
// The match group that denotes the problem location.
"location": 2,
// The match group that denotes the problem's severity. Can be omitted.
"severity": 3,
// The match group that denotes the problem code. Can be omitted.
"code": 4,
// The match group that denotes the problem's message.
"message": 5
}
}
}
*/

125
README.md
View File

@@ -1,68 +1,79 @@
# discord.js
Discord.js is a node module that allows you to interface with the [Discord](https://discordapp.com/) API for creation of things such as bots or loggers.
<p align="center">
<a href="https://hydrabolt.github.io/discord.js">
<img alt="discord.js" src="http://hydrabolt.github.io/discord.js/res/logo.png" width="546">
</a>
</p>
The aim of this API is to make it *really* simple to start developing your bots. This API has server, channel and user tracking, as well as tools to make identification really simple.
[![Build Status](https://travis-ci.org/hydrabolt/discord.js.svg)](https://travis-ci.org/hydrabolt/discord.js) [![Documentation Status](https://readthedocs.org/projects/discordjs/badge/?version=latest)](http://discordjs.readthedocs.org/en/latest/?badge=latest)
New update features **big speed boosts** (everything cached and sorted with around 1 second of calling the login function) upon connection and allows editing of messages!
**[Find the website here.](http://discord-js.github.io)**
**[For more information, click here.](https://github.com/hydrabolt/discord.js/wiki)**
### This module is still in alpha - especially the newer versions!
This node module is still in alpha, and some methods and functions may change or completely disappear!
discord.js is a node module used as a way of interfacing with
[Discord](https://discordapp.com/). It is a very useful module for creating
bots.
### Installation
``npm install --save discord.js``
`npm install --save discord.js`
### Features
---
* Send, Receive Delete and **Edit** messages from channels _and_ DMs! Auto-initiates DMs for you!
* Create, Delete and Leave servers and channels
* Create invites for Servers
* Silent Mention - trigger mention notification without actually @mentioning a user!
* Get complete metadata on users, channels and servers - including avatars.
* Get limitless logs from channels.
* Fast and efficient caching
* Auto-cache messages
### Example usage
### Example
```js
/*
* A basic bot that shows how to connect to a Discord account,
* how to listen to messages and how to send messages.
*
* This bot responds to every "ping" message with a "pong".
*/
var Discord = require("discord.js");
var Discord = require( "discord.js" );
var mybot = new Discord.Client();
// Create the bot
var myBot = new Discord.Client();
mybot.on("message", function(message){
if(message.content === "ping")
mybot.reply(message, "pong");
});
// Login with an example email and password
myBot.login( "hello@example.com", "password1" );
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
// Add a listener to the "message" event, which triggers upon receiving
// any message
myBot.on( "message", function( message ) {
// message.content accesses the content of the message as a string.
// If it is equal to "ping", then the bot should respond with "pong".
if ( message.content === "ping" ) {
// Send a message ("pong") to the channel the message was sent in,
// which is accessed by message.channel.
this.sendMessage( message.channel, "pong" );
}
} );
mybot.login("email", "password");
```
### TODO
* Joining servers from an invite
* Stealthy Ninja support
---
### Related Projects
Here is a list of other Discord APIs:
#### Java:
[Discord4J](https://github.com/nerd/Discord4J)
#### .NET:
[Discord.Net](https://github.com/RogueException/Discord.Net)
[DiscordSharp](https://github.com/Luigifan/DiscordSharp)
#### NodeJS
[discord.io](https://github.com/izy521/node-discord) (similar to discord.js but lower level)
#### PHP
[DiscordPHP](https://github.com/teamreflex/DiscordPHP)
#### Python
[discord.py](https://github.com/Rapptz/discord.py)
#### Ruby
[discordrb](https://github.com/meew0/discordrb)
---
### Links
**[Documentation](http://discordjs.readthedocs.org/en/latest/)**
**[GitHub](https://github.com/discord-js/discord.js)**
**[Wiki](https://github.com/discord-js/discord.js/wiki)**
**[Website](http://discord-js.github.io/)**
**[NPM](npmjs.com/package/discord.js)**
---
### Contact
If you have an issue or want to know if a feature exists, [read the documentation](http://discordjs.readthedocs.org/en/latest/) before contacting me about any issues! If it's badly/wrongly implemented, let me know!
If you would like to contact me, you can create an issue on the GitHub repo, e-mail me via the one available on my NPM profile.
Or you could just send a DM to **hydrabolt** in [**Discord API**](https://discord.gg/0SBTUU1wZTYd2XyW).

192
docs/Makefile Normal file
View File

@@ -0,0 +1,192 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/discordjs.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/discordjs.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/discordjs"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/discordjs"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

284
docs/conf.py Normal file
View File

@@ -0,0 +1,284 @@
# -*- coding: utf-8 -*-
#
# discord.js documentation build configuration file, created by
# sphinx-quickstart on Fri Sep 25 17:25:49 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import shlex
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'discord.js'
copyright = u'2015, hydrabolt'
author = u'hydrabolt'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.6'
# The full version, including alpha/beta/rc tags.
release = '3.6.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'discordjsdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'discordjs.tex', u'discord.js Documentation',
u'hydrabolt', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'discordjs', u'discord.js Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'discordjs', u'discord.js Documentation',
author, 'discordjs', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

132
docs/create_simple_bot.rst Normal file
View File

@@ -0,0 +1,132 @@
Creating a Simple Bot
=====================
This page will walk you through writing a simple bot and will introduce you to some of the most important functions and objects you will encounter in the API.
Setting up a Project
--------------------
Before you start creating your bot, you need to create a directory, for example *discordbot*.
After you've done that, open up the directory and have a look at how to `install the module`_. After you've installed the module, you can progress to the next step
Creating the Bot
----------------
Now we can begin writing the bot. This bot will just server the user their avatar but at a higher resolution - assuming they have one.
Firstly, create a file named ``bot.js`` in the directory you made earlier. Open it up, and type the following lines of code:
.. code-block:: js
var Discord = require("discord.js");
var bot = new Discord.Client();
This code firstly imports the discord.js module, which contains classes to help you create clients for Discord. The second line creates a new Discord Client, which we can manipulate later. Now, we want the client to be alerted when there is a new message and do something, so we can type this:
.. code-block:: js
bot.on("message", function(message){
} )
This will simply get our client to listen out for new messages, but not yet do anything. Let's have a look at this:
.. code-block:: js
bot.on("message", function(message){
if( message.content === "avatar me!" ){
}
} )
This code will now get our client to execute anything inside the if statement as long as the message sent was "avatar me!" We can now get it to see if the user has an avatar:
.. code-block:: js
bot.on("message", function(message){
if( message.content === "avatar me!" ){
var usersAvatar = message.sender.avatarURL;
if(usersAvatar){
// user has an avatar
}else{
// user doesn't have an avatar
}
}
} )
This code will now see if the user has an avatar and then do something based on that, let's finalise it:
.. code-block:: js
bot.on("message", function(message){
if( message.content === "avatar me!" ){
var usersAvatar = message.sender.avatarURL;
if(usersAvatar){
// user has an avatar
bot.reply(message, "your avatar can be found at " + usersAvatar);
}else{
// user doesn't have an avatar
bot.reply(message, "you don't have an avatar!");
}
}
} )
Let's have a look at the function we used here; *bot.reply*. This function takes 2 necessary parameters, a message object to reply to and a message to send. The first parameter we already have, and it is the message we have received. The second parameter is what we want to send.
Now that we've finished the listener event, we need to log the client in:
.. code-block:: js
bot.login("your discord email", "your discord password");
And that's it! Run the code with ``node bot.js`` and wait a few seconds, and then try sending *avatar me!* to any of the channels that the user you provided has details to.
Final Product
-------------
.. code-block:: js
var Discord = require("discord.js");
var bot = new Discord.Client();
bot.on("message", function(message){
if( message.content === "avatar me!" ){
var usersAvatar = message.sender.avatarURL;
if(usersAvatar){
// user has an avatar
bot.reply(message, "your avatar can be found at " + usersAvatar);
}else{
// user doesn't have an avatar
bot.reply(message, "you don't have an avatar!");
}
}
} );
bot.login("your discord email", "your discord password");
.. note:: This page is still a WIP, check back later for more documentation on it.
.. _install the module : http://discordjs.readthedocs.org/en/latest/get_started.html#installation

75
docs/docs_channel.rst Normal file
View File

@@ -0,0 +1,75 @@
.. include:: ./vars.rst
Channel Documentation
=====================
The Channel Class is used to represent data about a Channel.
Attributes
----------
client
~~~~~~
The Discord Client_ that cached the channel
server
~~~~~~
The Server_ that the channel belongs to
name
~~~~
The channel's name, as a `String`.
id
~~
The channel's id, as a `String`.
type
~~~~
The type of the channel as a `String`, either ``text`` or ``voice``.
topic
~~~~~
A `String` that is the topic of the channel, if the channel doesn't have a topic this will be `null`.
messages
~~~~~~~~
An `Array` of Message_ objects received from the channel. There are up to a 1000 messages here, and the older messages will be deleted if necessary.
members
~~~~~~~
**Aliases** : `users`
The members in the channel's server, an `Array` of User_ objects.
-----
Functions
---------
.. note:: When concatenated with a String, the object will become the channel's embed code, e.g. ``"this is " + channel`` would be ``this is <#channelid>``
getMessage(key, value)
~~~~~~~~~~~~~~~~~~~~~~
Gets a Message_ from the channel that matches the specified criteria. E.g:
.. code-block:: js
channel.getMessage("id", 1243987349) // returns a Message where message.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
equals(object)
~~~~~~~~~~~~~~
Returns a `Boolean` depending on whether the Channel's ID (``channel.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare channels. **NEVER** do ``channel1 == channel2``.

610
docs/docs_client.rst Normal file
View File

@@ -0,0 +1,610 @@
.. include:: ./vars.rst
Client Documentation
====================
This page contains documentation on the `Discord.Client` class. This should be used when you want to start creating things with the API.
It might be beneficial to use CTRL+F to search for what you're looking for, or use the navigation provided by readthedocs on the left.
Attributes
----------
options
~~~~~~~
An `Object` containing a configuration for the Client. Currently can only be configured like so:
.. code-block:: js
{
queue : false // whether messages should be sent one after the other or
// just send straight away.
}
token
~~~~~
A `String` that is the token received after logging in. It is used to authorise the Client when joining WebSockets or making HTTP requests. Example token:
.. code-block:: js
ODAzTOc4MTA2BjQ2MjY4ODg.COmrCA.fEtD_Tc0JU6iZJU_11coEWBOQHE
state
~~~~~
An `Integer` representing what state of connection the Client is in.
- **0** is idle, meaning the Client has been created but no login attempts have been made.
- **1** is logging in, meaning the Client is in the process of logging in.
- **2** is logged in, meaning the Client is logged in but not necessarily ready.
- **3** is ready, meaning the Client is ready to begin listening.
- **4** is disconnected, meaning the Client was disconnected due to any reason.
See also ready_.
.. code-block:: js
if( bot.state === 3 ) // ready to go
user
~~~~
A `User`_ object representing the account of the signed in client. This will only be available when the client is in the ready state (3).
.. code-block:: js
bot.user.username; // username of the account logged in
email
~~~~~
A `String` that is the email used to sign the client in.
password
~~~~~~~~
A `String` that is the password used to sign the client in.
readyTime
~~~~~~~~~
A `Number` representing the unix timestamp from when the client was ready. `Null` if not yet ready.
.. code-block:: js
bot.readyTime; // 1443378242464
uptime
~~~~~~
A `Number` representing how many milliseconds have passed since the client was ready. `Null` if not yet ready.
.. code-block:: js
if( bot.uptime > 5000 ) // true if the client has been up for more than 5 seconds
ready
~~~~~
A `Boolean` that is true if the client is ready. A shortcut to checking if ``bot.state === 3``.
servers
~~~~~~~
An `Array` of Server_ objects that the client has access to.
channels
~~~~~~~~
An `Array` of Channel_ objects that the client has access to.
users
~~~~~
An `Array` of User_ objects that the client has access to.
PMChannels
~~~~~~~~~~
An `Array` of PMChannel_ objects the client has access to.
messages
~~~~~~~~
An `Array` of Message_ objects the client has received over its uptime.
Functions
---------
.. note :: Any functions used here that take callbacks as an optional parameter can also be used as Promises_. Promises take the exact same parameters for each use case, except errors are moved to catch statements instead of then. For example, you can do:
.. code-block:: js
bot.login(email, password).then(success).catch(err);
function success(token){
}
function err(error){
}
// OR use callbacks:
bot.login(email, password, function(error, token){
});
-----
login(email, password, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logs the client in to set it up. Use this after registering your event listeners to ensure they are called.
- **email** - A `String` which is the email you want to sign in with.
- **password** - A `String` which is the password you want to sign in with.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **token** - if successful, it is the received authorisation token.
logout(`callback`)
~~~~~~~~~~~~~~~~~~
Logs the client out if it is logged in. If successful, ``bot.state == 4``.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
createServer(name, region, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates a server with the specified name or region. See valid regions below:
- **name** - A `String` that will be the name of your server.
- **region** - A `String` that is a valid Discord region. Currently **us-west**, **us-east**, **singapore**, **london**, **sydney** or **amsterdam**. Providing an invalid region will result in an error. To find the latest available regions, check the `official API here`_.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **server** - A Server_ that represents the created Server.
joinServer(invite, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Accepts a given invite to join a server. The server is automatically cached ASAP.
- **invite** - An `Invite Resolvable`_ which is the invite that should be accepted.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **server** - A Server_ that represents the joined Server.
leaveServer(server, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Leaves the given server.
- **server** - A `Server Resolvable`_ that represents the server you want to leave.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
createInvite(channel, options, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates an invite for the given channel and returns an Invite_.
- **channel** - A `Channel Resolvable`_ that is the channel you want to create an invite for.
- **options** - An `object` containing configurable options for the invite. See below for possible configurations.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **invite** - An Invite_ object that contains the details about the created invite.
.. code-block:: js
// default configuration of the options variable:
options = {
max_age : 0, //A number signifying the expiry time for the invite. 0 means infinite.
max_uses : 0, //A number signifying the amount of uses of the invite. 0 means infinite.
temporary : false, //boolean - whether users who use it are kicked unless promoted within 24h.
xkcd : false //boolean - whether the invite's URL should be human-readable
}
createChannel(server, channelName, channelType, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates a channel in the given server.
- **server** - A `Server Resolvable`_ that will be the server the channel is created in.
- **channelName** - A `String` that is the name of the channel.
- **channelType** - A `String` that is the type of the channel, either **voice** or **text**.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **channel** - An Channel_ object that represents the created channel.
deleteChannel(channel, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Deletes the specified channel.
- **channel** - A `Channel Resolvable`_ that will be the channel to delete.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
getChannelLogs(channel, `amount`, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Gets previous messages from the specified channel.
- **channel** - A `Channel Resolvable`_ to take logs from.
- **amount** - A `Number` that defaults to **500**. This is the amount of messages to try and get.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **logs** - An `Array` of Message_ objects that represent the previous messages.
.. warning:: If the logs contain messages from a user who is no longer in the server, the user object *MAY* be malformed.
sendMessage(channel, message, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sends a message to the specified channel.
- **channel** - A `Channel Resolvable`_ to send the message to.
- **message** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **message** - A Message_ representing the sent message.
sendFile(channel, file, `fileName`, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sends a file to the specified channel. Note that **fileName is necessary in certain cases** for when a file other than an image is sent. For example, if you send a file containing JS code, fileName should be something like ``myCode.js``.
- **channel** - A `Channel Resolvable`_ to send the file to.
- **file** - The file to send, either a `Buffer` or `String` - if a String, it should be a relative (`./`) or absolute path to a file.
- **fileName** - A `String` containing the file's name and extension, used by Discord (I didn't make this please don't shoot me :s) Examples include `picture.png`, `text.txt`, `wowanamazingscript.js`
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **message** - A Message_ representing the sent file.
updateMessage(message, content, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Updates/edits a message with new content.
- **message** - A Message_ that should be updated.
- **content** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **message** - A Message_ representing the updated message.
reply(message, yourMessage, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Alias for sendMessage, but prepends a mention to whoever sent the specified mention. Useful shortcut for directing a message at a user.
.. code-block:: js
// example usage:
the user 'bob' sent a message
bot.reply(message, "hello");
// will send the message '@bob, hello' to the channel the message that bob sent was in.
- **message** - A Message_ that should be replied to.
- **yourMessage** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
- **message** - A Message_ representing the sent message.
setUsername(newName, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the username of the logged in client.
- **newName** - The new name of the client, a `String`.
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
startTyping(channel, *stopTime*)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Makes the client appear to be typing in the specified channel.
- **channel** - A `Channel Resolvable`_ that should be the channel to start typing in
- **stopTime** - A `Number` in ms which should make the client stop typing after. Allow 5 seconds.
stopTyping(channel)
~~~~~~~~~~~~~~~~~~~
Makes the client stop typing in a specified channel.
- **channel** - A `Channel Resolvable`_ that should be the channel to stop typing in.
setStatusOnline()
~~~~~~~~~~~~~~~~~
**Aliases**: ``setStatusActive()`` and ``setStatusHere()``
Sets the client's status to online; green.
setStatusIdle()
~~~~~~~~~~~~~~~~~
**Aliases**: ``setStatusAway()``
Sets the client's status to idle; orange.
setTopic(channel, topic, `callback`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the topic of the specified channel
- **channel** - A `Channel Resolvable`_ that is the channel you want to change the topic of
- **topic** - A `String` that is the topic you want
- **callback** - A `function` that can take the following parameters:
- **error** - An error if one occurred, otherwise it is null.
getUser(key, value)
~~~~~~~~~~~~~~~~~~~
Gets a User_ that matches the specified criteria. E.g:
.. code-block:: js
bot.getUser("id", 1243987349) // returns a user where user.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
getServer(key, value)
~~~~~~~~~~~~~~~~~~~~~
Gets a Server_ that matches the specified criteria. E.g:
.. code-block:: js
bot.getServer("id", 1243987349) // returns a server where server.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
getChannel(key, value)
~~~~~~~~~~~~~~~~~~~~~~
Gets a Channel_ that matches the specified criteria. E.g:
.. code-block:: js
bot.getChannel("id", 1243987349) // returns a Channel where channel.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
getPMChannel(key, value)
~~~~~~~~~~~~~~~~~~~~~~~~
Gets a PMChannel_ that matches the specified criteria. E.g:
.. code-block:: js
bot.getPMChannel("id", 1243987349) // returns a PMChannel where pmchannel.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
setPlayingGame(id)
~~~~~~~~~~~~~~~~~~
**Aliases** : `playGame`, `playingGame`
Sets the client as playing the specified game name/id.
- **id** - Either a `Number` or a `String`. If it's a Number, it's assumed that you are using a `Discord Game ID`_ and know what you want. If you supply a `String`, it will assume you are entering a game name and try resolving it to a Discord Game ID if it's available. Example:
.. code-block:: js
client.setPlayingGame(18);
// sets the client as playing Minecraft, game ID 18
client.setPlayingGame("Minecraft");
// sets the client as playing Minecraft by resolving the ID to 18
client.setPlayingGame("my magical made up game")
// will stop the client from playing anything as it is unresolved, not a valid game.
-----
Event Management
----------------
Events are a useful way of listening to events and are available in every API.
Registering Events
~~~~~~~~~~~~~~~~~~
.. code-block:: js
bot.on("eventName", function(arg1, arg2...){
// code here is called when eventName is emitted.
})
.. note:: You can only have one listening function per event
Unregistering Events
~~~~~~~~~~~~~~~~~~~~
.. code-block:: js
bot.off("eventName")
// eventName is no longer listened for
Event Types
-----------
ready
~~~~~
Called when the bot is ready and you can begin working with it.
disconnected
~~~~~~~~~~~~
Called when the bot is disconnected for whatever reason.
error
~~~~~
Called whenever there is an error.
**Parameters**
- **error** - the encountered error
.. note:: There may be more parameters supplied depending on the errors. Use the ``arguments`` variable to check for this for advanced debugging.
debug
~~~~~
Called when the client debugs some information that might be useful for a developer but not for an end user.
**Parameters**
- **message** - the debug message as a `String`
message
~~~~~~~
Called when a message has been received by the client.
**Parameters**
- **message** - the received Message_.
messageDelete
~~~~~~~~~~~~~
Called when a message has been deleted.
**Parameters**
- **channel** - The Channel_ that the deleted message was in.
- **message** - *May* be available. If the message wasn't previously cached, this will not be supplied and all you would know is that a message was deleted in the channel. If it is available, it will be in the format of a Message_.
messageUpdate
~~~~~~~~~~~~~
Called when a message has been updated.
**Parameters**
- **newMessage** - The updated Message_.
- **oldMessage** - The old Message_ before it was updated.
serverDelete
~~~~~~~~~~~~
Called when a server is deleted.
**Parameters**
- **server** - The deleted Server_.
channelDelete
~~~~~~~~~~~~~
Called when a channel is deleted.
**Parameters**
- **channel** - The deleted Channel_.
serverCreate
~~~~~~~~~~~~
Called when a server is created/joined.
**Parameters**
- **server** - The created Server_.
channelCreate
~~~~~~~~~~~~
Called when a channel is created.
**Parameters**
- **channel** - The created Channel_.
serverNewMember
~~~~~~~~~~~~~~~
Called when a new member is added to a server.
**Parameters**
- **user** - The User_ that was added.
- **server** - The Server_ that the user was added to.
serverRemoveMember
~~~~~~~~~~~~~~~~~~
Called when a member of a server leaves or is kicked out.
**Parameters**
- **user** - The User_ that was removed.
- **server** - The Server_ that the user was removed from.
userUpdate
~~~~~~~~~~
Called when information about a user changes, such as their username.
**Parameters**
- **newUser** - A User_ object representing the changes to the old user (this will be in the cache)
- **oldUser** - A User_ object representing the user before the update.
presence
~~~~~~~~
Called when a user goes online/offline/away or starts/stops playing a game.
**Parameters**
- **dataObject** - Instead of separate arguments, presence update takes an object containing the following information:
- **user** - A User_ representing the User that had a presence update
- **status** - The status change as a `String`.
- **server** - The Server_ that the presence change occurred in.
- **gameId** - A `Number` representing the game they are playing if any. Currently, discord.js has no internal support for converting this into a game name.
unknown
~~~~~~~
Called when an unknown packet was received or there is no handler for it.
**Parameters**
- **data** - A `JSON Object` which is the message received over WebSocket.
raw
~~~
Called when a WebSocket message is received and it gives you the message.
**Parameters**
- **data** - A `JSON Object` which is the message received over WebSocket.
.. _official API here : https://discordapp.com/api/voice/regions
.. _Discord Game ID : https://raw.githubusercontent.com/hydrabolt/discord.js/master/ref/gameMap.json

64
docs/docs_invite.rst Normal file
View File

@@ -0,0 +1,64 @@
.. include:: ./vars.rst
Invite Documentation
====================
The Invite Class is used to represent data about an Invite.
Attributes
----------
max_age
~~~~~~~
A `Number` in minutes for how long the Invite should be valid for. E.g. a value of ``3600`` is equal to 30 minutes.
code
~~~~
`String` an alphanumeric code for the Invite.
revoked
~~~~~~~
`Boolean` that dictates whether the Invite has been cancelled or not
created_at
~~~~~~~~~~
A unix timestamp as a `Number` which is the time that the invite was created.
temporary
~~~~~~~~~
`Boolean` that dictates whether the invite is temporary.
uses
~~~~
`Number` the number of uses of the Invite, a value of ``0`` is none.
max_uses
~~~~~~~~
`Number` that is the maximum amount of uses of the invite, ``0`` is unlimited.
inviter
~~~~~~~
The User_ that created the invite.
xkcd
~~~~
`Boolean` that is true if the invite should be human-readable.
channel
~~~~~~~
The Channel_ that the invite is inviting to.
URL
~~~
A `String` that generates a clickable link to the invite.

84
docs/docs_message.rst Normal file
View File

@@ -0,0 +1,84 @@
.. include:: ./vars.rst
Message Documentation
=====================
The Message Class is used to represent data about a Message.
Attributes
----------
tts
~~~
A `Boolean` that is ``true`` if the sent message was text-to-speech, otherwise ``false``.
timestamp
~~~~~~~~~
A `unix timestamp` as a `Number` representing when the message was sent.
mentions
~~~~~~~~
An `Array` of User_ objects that represent the users mentioned in the message.
everyoneMentioned
~~~~~~~~~~~~~~~~~
A `Boolean` that is ``true`` if **@everyone** was used, otherwise ``false``.
id
~~
A `String` UUID of the message, will never change.
.. note:: Currently, message IDs are totally unique. However, in the future they may only be unique within a channel. Make sure to check periodically whether this has changed.
embeds
~~~~~~
A raw, unhandled `JSON object` that will contain embeds of the message - if any.
editedTimestamp
~~~~~~~~~~~~~~~
A `unix timestamp` as a `Number` that is when the message was last edited.
content
~~~~~~~
The actual content of the message as a `String`.
channel
~~~~~~~
The Channel_ that the message was sent in.
author
~~~~~~
**Aliases** : `sender`
The User_ that sent the message.
attachments
~~~~~~~~~~~
A raw, unhandled `JSON object` that will contain attachments of the message - if any.
isPrivate
~~~~~~~~~
A `Boolean` that is ``true`` if the message was sent in a PM / DM chat, or if it was sent in a group chat it will be ``false``.
Functions
---------
isMentioned(user)
~~~~~~~~~~~~~~~~~
A `Boolean` that will return ``true`` if the specified user was mentioned in the message. If everyone is mentioned, this will be false - this function checks specifically for if they were mentioned.
- **user** - The User_ that you want to see is mentioned or not.

41
docs/docs_pmchannel.rst Normal file
View File

@@ -0,0 +1,41 @@
.. include:: ./vars.rst
PMChannel Documentation
=======================
The PMChannel Class is used to represent data about a Private Message Channel.
.. note:: Beware! The PMChannel class does `not` extend the Channel_ class.
Attributes
----------
user
~~~~
The recipient User_ of the PM Channel.
id
~~
`String` UUID of the PM Channel.
messages
~~~~~~~~
An `Array` of Message_ objects. Contains all the cached messages sent in this channel up to a limit of 1000. If the limit is reached, the oldest message is removed first to make space for it.
Functions
---------
getMessage(key, value)
~~~~~~~~~~~~~~~~~~~~~~
Gets a Message_ from the PM Channel that matches the specified criteria. E.g:
.. code-block:: js
pmchannel.getMessage("id", 1243987349) // returns a Message where message.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value

27
docs/docs_resolvable.rst Normal file
View File

@@ -0,0 +1,27 @@
.. include:: ./vars.rst
Resolvable Documentation
========================
To be robust, discord.js needs to handle a wide amount of ambiguous data that is supplied to it. This means you can use functions much more easily. Anything that is resolvable means it can be normalised without you having to do it explicitly.
Resolvables are not objects or classes, they are just ways of expressing what type of data is expected.
Channel Resolvable
------------------
A Channel Resolvable is data that can be resolved to a channel ID. Here is what is currently supported:
- A Channel_ object
- A Server_ object (the #general channel of the server will be used)
- A `String` representing the channel ID
- A Message_ (the channel the message was sent in will be used)
- A User_ (will get the PM channel with the specified user)
.. note:: A User cannot always be specified in certain cases. For example, if using `bot.setTopic`, a User or PM Channel can't be specified as these do not support channel topics.
Server Resolvable
-----------------
Invite Resolvable
-----------------

107
docs/docs_server.rst Normal file
View File

@@ -0,0 +1,107 @@
.. include:: ./vars.rst
Server Documentation
==================
The Server Class is used to represent data about a server.
Attributes
----------
client
~~~~~~
The Discord Client_ that the Server was cached by.
region
~~~~~~
The region that the server is in, a `String`.
name
~~~~
The server's name, as a `String`.
id
~~
The server's id, as a `String`.
members
~~~~~~~
**Aliases** : `users`
The members in a server, an `Array` of User_ objects.
channels
~~~~~~~~
The channels in a server, an `Array` of Channel_ objects.
icon
~~~~
The icon ID of the server if it has one as a `String`, otherwise it is `null`.
iconURL
~~~~~~~
A `String` that is the URL of the server icon if it has one, otherwise it is `null`.
afkTimeout
~~~~~~~~~~
A `Number` that is the AFK Timeout of the Server.
afkChannel
~~~~~~~~~~
A Channel_ that represents the AFK Channel of the server if it has one, otherwise it is `null`.
defaultChannel
~~~~~~~~~~~~~~
The **#general** Channel_ of the server.
owner
~~~~~
A User_ object representing the user that owns the server.
-----
Functions
---------
.. note:: When concatenated with a String, the object will become the server's name, e.g. ``"this is " + server`` would be ``this is Discord API`` if the server was called `Discord API`.
getChannel(key, value)
~~~~~~~~~~~~~~~~~~~~~~
Gets a Channel_ that matches the specified criteria. E.g:
.. code-block:: js
server.getChannel("id", 1243987349) // returns a Channel where channel.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
getMember(key, value)
~~~~~~~~~~~~~~~~~~~~~
Gets a User_ that matches the specified criteria. E.g:
.. code-block:: js
bot.getUser("id", 1243987349) // returns a user where user.id === 1243987349
- **key** - a `String` that is the key
- **value** - a `String` that is the value
equals(object)
~~~~~~~~~~~~~~
Returns a `Boolean` depending on whether the Server's ID (``server.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare servers. **NEVER** do ``server1 == server2``.

67
docs/docs_user.rst Normal file
View File

@@ -0,0 +1,67 @@
.. include:: ./vars.rst
User Documentation
==================
The User Class is used to represent data about users.
Attributes
----------
username
~~~~~~~~
A `String` that is the username of the user.
discriminator
~~~~~~~~~~~~~
Used to differentiate users with the same username, provided by Discord. If you want to differentiate users, we'd recommend using the `id` attribute.
id
~~
A `String` UUID of the user, will never change.
avatar
~~~~~~
A `String` that is the user's avatar's ID, or if they don't have one this is `null`.
avatarURL
~~~~~~~~~
A `String` that points to the user's avatar's URL, or if they don't have an avatar this is `null`.
status
~~~~~~
The status of the user as a `String`; offline/online/idle.
-----
Functions
---------
mention()
~~~~~~~~~
Returns a `String`. This function will generate the mention string for the user, which when sent will preview as a mention. E.g:
.. code-block:: js
user.mention(); // something like <@3245982345035>
This is mainly used internally by the API to correct mentions when sending messages, however you can use it.
.. note:: You can also just concatenate a User object with strings to get the mention code, as the `toString()` method points to this. This is useful when sending messages.
equals(object)
~~~~~~~~~~~~~~
Returns a `Boolean` depending on whether the User's ID (``user.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare users. **NEVER** do ``user1 == user2``.
equalsStrict(object)
~~~~~~~~~~~~~~~~~~~~
Sees if the supplied object has the same username, ID, avatar and discriminator of the user. Mainly used internally. Returns a `Boolean` depending on the result.

37
docs/get_started.rst Normal file
View File

@@ -0,0 +1,37 @@
===========
Get Started
===========
Installation
------------
Linux / OS X
~~~~~~~~~~~~
Run ``npm install discord.js --save`` in your project's directory and you should be good to go!
Windows
~~~~~~~~~~~~
Unfortunately, the Windows installation process is a little more lengthy. You need to have `Visual Studio Express`_ (or any of the other distributions of it). This is necessary for build tools for the WebSocket dependency.
.. note:: If you are using another version of Visual Studio, such as 2012, replace the flag with ``--msvs_version=2012``
After you have obtained these tools, you need to run ``npm install discord.js --save --msvs_version=2015`` in your working directory. Hopefully this should all go well!
Cloning the Repo
----------------
If you want to try some examples or make your own changes to discord.js, you can `clone the repo`_. After that run ``npm install`` to install dependencies.
Running Examples
~~~~~~~~~~~~~~~~
If you've cloned the repo, you also have the option to run some examples. You can also do this by just copying the examples_ and then running them. I'd be more than happy to get some pull requests if you want to make any patches ;)
Before you run them though, you need to configure the ``examples/auth.json`` file. This should contain valid Discord credentials and passwords.
After you've configured your credentials, just run ``node examples/pingpong.js`` to run the ping pong example.
.. _Visual Studio Express: https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx
.. _clone the repo: https://github.com/hydrabolt/discord.js.git
.. _examples: https://github.com/hydrabolt/discord.js/tree/master/examples

49
docs/index.rst Normal file
View File

@@ -0,0 +1,49 @@
.. discord.js documentation master file, created by
sphinx-quickstart on Fri Sep 25 17:25:49 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to discord.js's documentation!
======================================
discord.js is an easy-to-use and intuitive JavaScript API for Discord_. It should be able to
run in node.js / io.js and in the browser.
.. note:: This documentation is still a work-in-progress, apologies if something isn't yet documented!
Contents:
.. _general-docs:
.. toctree::
:maxdepth: 2
:caption: General
get_started
troubleshooting
create_simple_bot
.. _docs:
.. toctree::
:maxdepth: 2
:caption: Documentation
docs_resolvable
docs_client
docs_user
docs_server
docs_channel
docs_pmchannel
docs_message
docs_invite
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
.. _Discord : https://discordapp.com/

263
docs/make.bat Normal file
View File

@@ -0,0 +1,263 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 2> nul
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\discordjs.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\discordjs.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

10
docs/troubleshooting.rst Normal file
View File

@@ -0,0 +1,10 @@
Troubleshooting
===============
Occasionally, the API can stop working for whatever reason. If it was working previously and it stopped working on the same version, it means that there's been a change to the Discord API. In this case, please `make an issue`_ if one relating to a similar issue doesn't exist. Please post a stacktrace if there is one, and be as detailed as possible - *"the API isn't working"* doesn't help at all.
If there is already an issue, feel free to comment that you're also experiencing the same thing. This helps to see how widespread the bug is.
You can try reconnecting before submitting an issue, as sometimes some of the servers may be slightly different.
.. _make an issue : https://github.com/hydrabolt/discord.js/issues

11
docs/vars.rst Normal file
View File

@@ -0,0 +1,11 @@
.. _Client : ./docs_client.html
.. _User : ./docs_user.html
.. _ready : #ready
.. _Server : ./docs_server.html
.. _Channel : ./docs_channel.html
.. _Message : ./docs_message.html
.. _PMChannel : ./docs_pmchannel.html
.. _Invite : ./docs_invite.html
.. _Channel Resolvable : ./docs_resolvable.html#channel-resolvable
.. _Invite Resolvable : ./docs_resolvable.html#invite-resolvable
.. _Promises : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise

4
examples/auth.json Normal file
View File

@@ -0,0 +1,4 @@
{
"email" : "your discord email here",
"password" : "your discord password here"
}

View File

@@ -1,37 +1,41 @@
/*
* A bot that shows how to mention users in messages and how to
* access user avatars.
*/
this bot is an avatar bot, and will give a user their avatar's URL
*/
var Discord = require( "../" );
var myBot = new Discord.Client();
var Discord = require("../");
myBot.login( "hello@example.com", "password1" );
// Get the email and password
var AuthDetails = require("./auth.json");
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
var bot = new Discord.Client();
myBot.on( "message", function( message ) {
// React to all messages with the content "$avatar"
if ( message.content === "$avatar" ) {
// Obtain the user who requested the avatar.
var user = message.author;
bot.on("ready", function () {
console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
});
// Check whether the user actually has an avatar.
if ( user.avatar ) {
// Construct the avatar URL from the user ID and the avatar ID.
var url = "https://discordapp.com/api/users/" + user.id + "/avatars/" + user.avatar + ".jpg";
bot.on("disconnected", function () {
// A user can be mentioned in a message by inserting the string obtained
// by user.mention() into the message.
// Note that simply writing "@user" will NOT work.
this.sendMessage( message.channel, message.author.mention() + ", here's your avatar: " + url );
} else {
// Nothing should be done if the user has not set an avatar.
this.sendMessage( message.channel, message.author.mention() + ", you don't have an avatar!" );
console.log("Disconnected!");
process.exit(1); //exit node.js with an error
});
bot.on("message", function (msg) {
if (msg.content === "$avatar") {
//see if the user has an avatar
if( msg.sender.avatarURL ){
bot.reply(msg, msg.sender.avatarURL);
}else{
//using reply with a message automatically does:
// '@sender, ' for you!
bot.reply(msg, "you don't have an avatar!");
}
//alert the console
console.log("served " + msg.sender.username);
}
} );
});
bot.login(AuthDetails.email, AuthDetails.password);

36
examples/catapi.js Normal file
View File

@@ -0,0 +1,36 @@
/*
this bot will send an image of a cat to a channel.
may be slow depending on your internet connection.
*/
var Discord = require("../");
// Get the email and password
var AuthDetails = require("./auth.json");
var bot = new Discord.Client();
bot.on("ready", function () {
console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
});
bot.on("disconnected", function () {
console.log("Disconnected!");
process.exit(1); //exit node.js with an error
});
bot.on("message", function (msg) {
if (msg.content === "$cat") {
//send a message to the channel the ping message was sent in.
bot.sendMessage(msg.channel, "pong!");
//alert the console
console.log("pong-ed " + msg.sender.username);
}
});
bot.login(AuthDetails.email, AuthDetails.password);

View File

@@ -1,24 +0,0 @@
/*
* Discord uses a subset of Markdown for formatting, so adding formatting to
* messages is as simple as inserting the formatting codes into the message.
*/
var Discord = require( "../" );
var myBot = new Discord.Client();
myBot.login( "hello@example.com", "password1" );
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
myBot.on( "message", function( message ) {
// React to all messages with the content "$formatting".
if ( message.content === "$formatting" ) {
// Show off formatting by sending a simple message with formatting codes.
this.sendMessage( message.channel, "**bold** ****semibold**** *italic* " +
"_**bold and italic**_ __underline__ ~~strikethrough~~" );
}
} );

View File

@@ -1,32 +1,37 @@
/*
* A basic bot that shows how to connect to a Discord account,
* how to listen to messages and how to send messages.
*
* This bot responds to every "ping" message with a "pong".
*/
this bot is a ping pong bot, and every time a message
beginning with "ping" is sent, it will reply with
"pong".
*/
var Discord = require( "../" );
var Discord = require("../");
// Create the bot
var myBot = new Discord.Client();
// Get the email and password
var AuthDetails = require("./auth.json");
// Login with an example email and password
myBot.login( "hello@example.com", "password1" );
var bot = new Discord.Client();
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
bot.on("ready", function () {
console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
});
bot.on("disconnected", function () {
console.log("Disconnected!");
process.exit(1); //exit node.js with an error
});
bot.on("message", function (msg) {
if (msg.content.substring(0, 4) === "ping") {
//send a message to the channel the ping message was sent in.
bot.sendMessage(msg.channel, "pong!");
//alert the console
console.log("pong-ed " + msg.sender.username);
// Add a listener to the "message" event, which triggers upon receiving
// any message
myBot.on( "message", function( message ) {
// message.content accesses the content of the message as a string.
// If it is equal to "ping", then the bot should respond with "pong".
if ( message.content === "ping" ) {
// Send a message ("pong") to the channel the message was sent in,
// which is accessed by message.channel.
this.sendMessage( message, "pong" );
}
} );
});
bot.login(AuthDetails.email, AuthDetails.password);

View File

@@ -1,26 +0,0 @@
/*
* A bot that shows how to listen to presence update events, such as a user
* joining or leaving.
*/
var Discord = require( "../" );
var myBot = new Discord.Client();
myBot.login( "hello@example.com", "password1" );
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
// The "presence" event is triggered when a user joins a server, leaves it or
// goes away.
// The status parameter can be "online", "offline" or "idle", respectively.
myBot.on( "presence", function( user, status, server ) {
// Send a message on the default channel of the server, as presence updates
// are not restricted to one channel.
var message = user.mention() + " is " + status + " in " + server.name + "!";
console.log(message);
this.sendMessage( server.getDefaultChannel(), message );
} );

View File

@@ -1,61 +0,0 @@
/*
* A bot that shows how to access and search the logs of a specific channel.
* Specifically, it returns the last message from a given user in the last
* 100 messages.
*/
var Discord = require( "discord.js" );
var myBot = new Discord.Client();
myBot.login( "hello@example.com", "password1" );
myBot.on( "message", function( message ) {
// React to all messages starting with "$query".
if ( message.content.startsWith( "$query" ) ) {
// Obtain the channel for which logs should be accessed.
var channel = message.channel;
// Find all the arguments to the command.
var arguments = message.content.split( " " );
// Get the first argument specifically, as it contains the username
// to be queried for.
var username = arguments.slice( 1 ).join( " " );
// Exit the event handler unless the user exists.
if ( !username ) {
myBot.sendMessage( channel, "That user doesn't exist!" );
return;
}
// The getChannelLogs() function takes the channel that should be accessed,
// the amount of messages to query and a callback as its arguments.
myBot.getChannelLogs( channel, 100, function( error, messageList ) {
// filter() takes three arguments, the key to be filtered for (in this
// case the username, so "username"), the value to look for, and whether
// only the first finding should be returned (true) or a list of all
// findings (false).
// Check to see if there is an error, if there isn't this will be null,
// which equates to false in a conditional.
if ( error ) {
// There was an error, so stop proceeding as if there is an error
// retrieving logs, no logs are returned. We should tell the
// users that there was an error retrieving logs and return.
myBot.sendMessage( channel, "There was an error retrieving logs!" );
return;
}
var message = messageList.filter( "username", username, true );
// Only continue if the message has been found
if ( message ) {
myBot.sendMessage( channel, "The last message from user " + username +
" is: \"" + message.content + "\"." ).
} else {
myBot.sendMessage( "That user has not sent a message " +
"for the last 100 messages!" )
}
} );
}
} );

View File

@@ -1,24 +0,0 @@
/*
* A bot that doesn't interact with Discord, but instead shows how to listen
* to the "ready" and "disconnected" events, that are triggered when the bot
* starts up or shuts down, respectively.
*/
var Discord = require( "../" );
var myBot = new Discord.Client();
myBot.login( "hello@example.com", "password1" );
// The "ready" event is triggered after the bot successfully connected to
// Discord and is ready to send messages.
myBot.on( "ready", function() {
console.log( "Bot connected successfully." );
} );
// The "disconnected" event is triggered after the connection to Discord
// ended.
// It is also triggered when the connection attempt fails, for example due
// to a wrong password.
myBot.on( "disconnected", function(e) {
console.log( "Bot disconnected from Discord -", e.reason );
} );

49
gruntfile.js Normal file
View File

@@ -0,0 +1,49 @@
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
// define source files and their destinations
babel: {
dist: {
files: [{
expand: true,
cwd: "src/",
src: ["**.*"],
dest: "lib/",
ext: ".js"
}]
}
},
browserify: {
dist: {
files: {
'web-dist/discord.<%= pkg.version %>.js': ["lib/index.js"],
},
options: {
browserifyOptions: {
standalone: "Discord"
}
}
}
},
uglify: {
min: {
files: {
"./web-dist/discord.min.<%= pkg.version %>.js": "./web-dist/discord.<%= pkg.version %>.js"
}
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-uglify');
// register at least this one task
grunt.registerTask('default', ['babel']);
grunt.registerTask('web', ['browserify', "uglify"]);
grunt.registerTask("dist", ["babel", "browserify", "uglify"])
};

2
hydrabot/.gitignore vendored
View File

@@ -1,2 +0,0 @@
config.json
authority.json

View File

@@ -1,19 +0,0 @@
# hydrabot
Hydrabot is an open-source bot made with the intents of demonstrating the capabilities of [discord.js](https://github.com/hydrabolt/discord.js/).
### Set up
The easiest setup would be to clone the discord.js repo, and then open a terminal/cmd in this directory and run `node hydrabot.js`.
If you don't want to clone the repo but instead just use this folder, you need to edit `hydrabot.js` to use `require("discord.js")` as opposed to `require("../")`. Cloned directories will always be using the latest **discord.js**.
### Setting up credentials
Create `config.json` to use your Discord email and password, and then run `node hydrabot.js`.
What config.json should look like:
```js
{
"email" : "your email",
"password" : "your password"
}
```

View File

@@ -1,37 +0,0 @@
var fs = require( "fs" );
var authCache = {};
exports.init = function() {
try {
var fd = fs.openSync( "./authority.json", "wx" );
exports.writeCache();
} catch ( e ) {
if ( e.errno !== -4075 ){
throw e;
}else{
authCache = JSON.parse(fs.readFileSync("./authority.json", "utf8"));
}
}
}
exports.getLevel = function(user){
if(authCache[user.id])
return authCache[user.id];
else
return 0;
}
exports.setLevel = function(user, level){
authCache[user.id] = level;
exports.writeCache();
}
exports.writeCache = function() {
fs.writeFile( './authority.json', JSON.stringify(authCache), function( err ) {
if ( err )
console.log("Error saving Authority Caches - " + err.code);
} );
}

View File

@@ -1,516 +0,0 @@
var Authority = require( "./authority.js" );
var BotClass = require( "./hydrabot.js" );
var Discord = BotClass.Discord;
Commands = [];
Commands[ "info" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var verbose = hasFlag( params, "verbose" ) || hasFlag( params, "v" );
var user = getUser( message, params );
bot.reply( message, [
"here's some info on " + user.mention() + ":",
"In channel **#" + message.channel.name + "**" + ( verbose ? " - ID *" + message.channel.id + "*" : "" ), ( message.isPM() ?
"You're in a private conversation with me!" + ( verbose ? " The ID is " + message.channel.id : "" ) : "In the server **" + message.channel.server.name + "**" + ( verbose ? " - ID *" + message.channel.server.id + "*" : "" )
),
"User ID is *" + user.id + "*",
"Authority/OP Level to me is **" + Authority.getLevel( user ) + "**"
], function( err ) {
if ( err )
console.log( err );
} );
}
}
Commands[ "loading" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var progress = 0;
var currentMessage;
var bars = 20;
function getM() {
var before = progress;
var after = bars - progress;
var ret = "";
for ( x = 0; x < before; x++ ) {
ret += "-";
}
ret += "**#**";
for ( y = 0; y < after; y++ ) {
ret += "-";
}
return ret;
}
function doProg() {
if ( progress === ( bars + 1 ) ) {
progress = 0;
}
if ( currentMessage ) {
bot.updateMessage( currentMessage, getM(), function( err, msg ) {
if ( !err )
currentMessage = msg;
} );
progress++;
}
}
bot.sendMessage( message.channel, getM(), function( err, message ) {
currentMessage = message;
setInterval( doProg, 200 );
} );
}
}
Commands[ "flashy" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var phase = 0;
var msg;
var textToSay = getKey( params, "m", "FLASH" );
var speed = parseInt( getKey( params, "s", "500" ) );
function change() {
if ( msg ) {
var highlighting = ( ( phase % 2 ) === 0 ? "**" : "" );
phase++;
bot.updateMessage( msg, highlighting + textToSay + highlighting, function( err, message ) {
if ( !err ) {
msg = message;
}
} );
}
}
bot.sendMessage( message.channel, textToSay, function( err, message ) {
msg = message;
setInterval( change, speed );
} );
}
}
Commands[ "echo" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
bot.sendMessage( message, params.join( " " ), function( err, msg ) {
if ( err ) {
bot.sendMessage( message, "Unable to echo!" );
console.log( err );
}
} );
}
}
Commands[ "auth" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var level = getKey( params, "level", "0" );
var method = hasFlag( params, "set" ) ? "set" : "get";
var user = getUser( message, params );
if ( method === "set" ) {
if ( authLevel( message.author ) <= level ) {
bot.reply( message, "that authority level is too high for you to set!" );
} else if ( user.equals( message.author ) ) {
bot.reply( message, "you can't alter your own authority level!" );
} else if ( authLevel( user ) >= authLevel( message.author ) ) {
bot.reply( message, "that user has a higher or equal OP level to you!" );
} else if ( level < 0 ) {
bot.reply( message, "that level's a bit too low :P" );
} else {
setAuthLevel( user, level );
bot.reply( message, "I set the authority of " + user.mention() + " to **" + level + "**" );
}
} else {
bot.reply( message, user.equals( message.author ) ? "Your authority level is **" + authLevel( user ) + "**" : "The authority level of " + user.mention() + " is **" + authLevel( user ) + "**" );
}
}
}
Commands[ "clear" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
if ( !message.isPM() ) {
if ( authLevel( message.author ) < 1 ) {
bot.reply( message, BotClass.AUTH_ERROR );
return;
}
}
var initMessage = false,
cleared = false;
bot.getChannelLogs( message.channel, 250, function( err, logs ) {
if ( err ) {
bot.sendMessage( "Couldn't grab logs to delete messages." );
} else {
var deletedCount = 0,
failedCount = 0,
todo = logs.length();
for ( msg of logs.contents ) {
if ( msg.author.equals( bot.user ) ) {
bot.deleteMessage( msg, function( err ) {
todo--;
if ( err )
failedCount++;
else
deletedCount++;
if ( todo === 0 ) {
bot.reply(
message,
"Done! " + deletedCount + " message(s) were deleted, with " + failedCount + " error(s).",
false, {
selfDestruct: 5000
}
);
cleared = true;
deleteInitMessage();
}
} );
} else {
todo--;
}
}
}
} );
bot.reply( message, "clearing up my messages...", function( err, msg ) {
if ( !err ) {
initMessage = msg;
if ( cleared )
deleteInitMessage();
}
} );
function deleteInitMessage() {
if ( initMessage ) {
bot.deleteMessage( initMessage );
}
}
}
}
Commands[ "leave" ] = {
oplevel: 3,
fn: function( bot, params, message ) {
var silent = hasFlag( params, "s" ) || hasFlag( params, "silent" );
if ( message.isPM() ) {
bot.reply( message, "Umm... I can't leave PMs... How awkward..." );
} else {
if ( !silent )
bot.reply( message, "Ok ;( I'm leaving!" );
bot.leaveServer( message.channel.server, function( err ) {
if ( err ) {
bot.reply( message, "There was an error leaving... how awkward." );
}
} );
}
}
}
Commands[ "avatar" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var user = getUser( message, params, bot );
if ( !user.avatar ) {
bot.sendMessage( message.channel, user.mention() + " does not have an avatar!" );
} else {
bot.reply( message, user.getAvatarURL() );
}
}
}
Commands[ "setusername" ] = {
oplevel: 3,
fn: function( bot, params, message ) {
var name = getKey( params, "name", "Boris Johnson" );
bot.setUsername( name, function( err ) {
if ( err )
bot.reply( message, err );
} )
}
}
Commands[ "cat" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var http = require( "http" );
var request = require( 'request' );
bot.sendFile( message, request("http://thecatapi.com/api/images/get?type=jpg"), "cat.jpg", function( err ) {
if(err)
bot.reply( message, err );
} );
}
}
Commands[ "icon" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
if ( message.isPM() ) {
bot.reply( message, "PMs don't have avatars!" );
return;
}
if ( !message.channel.server.icon ) {
bot.reply( message, "this server does not have an icon!" );
return;
}
bot.reply( message, message.channel.server.getIconURL() );
}
}
Commands[ "avataritup" ] = {
oplevel: 2,
fn: function( bot, params, message ) {
console.log( message.channel );
bot.sendMessage( message, message.channel.server.members.getValues( "avatar" ).join( "\n" ) );
}
}
Commands[ "feedback" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 1000;
bot.getChannelLogs( message.channel, amount, function( err, logs ) {
console.log( logs );
if ( err ) {
bot.reply( message, "an error occurred when grabbing the logs.", false, {
selfDestruct: 3000
} );
} else {
var found = [];
for ( msg of logs.contents ) {
if ( ~msg.content.indexOf( "[request" ) || ~msg.content.indexOf( "[feature" || ~msg.content.indexOf( "[suggestion" ) ) ) {
if ( msg.content.length > 10 ) {
found.push( msg );
}
}
}
bot.sendMessage( message.author, "Ok, here's a rundown of all feature requests so far:", function( err, ms ) {
if ( !err )
gothroughit();
} );
bot.reply( message, "I found " + found.length + " result(s) that matched this. I'll send it to you in a PM.", false, {
selfDestruct: 3000
} );
function gothroughit() {
for ( msg of found ) {
bot.sendMessage( message.author, "**" + msg.author.username + "** said:\n " + msg.content );
}
}
}
} );
}
}
Commands[ "acceptinvite" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var inv = getKey( params, "i" );
bot.joinServer( inv, function( err, server ) {
if ( err ) {
bot.reply( message, "I couldn't join that server :(" );
} else {
bot.reply( message, "I joined **" + server.name + "**, a server with " + server.channels.length() + " channels and " + server.members.length() + " members." );
}
} );
}
}
Commands[ "filtertest" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
console.log( message.channel.server.members.filter( "username", "HYDRABOLT" ) );
console.log( message.channel.server.members.filter( "username", "HYDRABOLT", false, true ) );
}
}
Commands[ "test" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
console.log( message.channel.server.channels.filter( "name", "a", true ) );
}
}
Commands[ "remind" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var time = parseInt( getKey( params, "t" ) || getKey( params, "time" ) ) * 1000 || 21000;
var msg = getKey( params, "m" ) || getKey( params, "msg" ) || getKey( params, "message" );
bot.reply( message, "I'll remind you to *" + msg + "* in *" + time / 1000 + "* seconds.", false, true, {
selfDestruct: time
} );
setTimeout( send, time );
function send() {
bot.sendMessage( message.author, time + " seconds are up! **" + msg + "**." );
}
}
}
Commands[ "annoy" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var user = getUser( message, params );
bot.sendMessage( user, "Ha I'm annoying you on " + message.author.mention() + "'s request!" );
}
}
Commands[ "activity" ] = {
oplevel: 0,
fn: function( bot, params, message ) {
var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 250;
var limit = getKey( params, "limit" ) || getKey( params, "l" ) || 10;
bot.getChannelLogs( message.channel, amount, function( err, logs ) {
if ( err ) {
bot.reply( message, "error gettings logs." );
} else {
var activity = {},
count = 0;
for ( msg of logs.contents ) {
count = logs.length();
if ( !activity[ msg.author.id ] )
activity[ msg.author.id ] = 0;
activity[ msg.author.id ]++;
}
var report = "here's a list of activity over the last " + count + " messages :\n\n";
var usernames = {};
for ( id in activity ) {
usernames[ id ] = bot.getUser( id ).username;
}
for ( id in activity ) {
report += usernames[ id ] + " | " + activity[ id ] + " | **" + Math.round( ( activity[ id ] / count ) * 100 ) + "%**.\n";
}
bot.reply( message, report, false, false );
}
} );
}
}
exports.Commands = Commands;
function hasFlag( array, flag ) {
return ~array.indexOf( flag );
}
function getKey( array, key, def ) {
for ( element of array ) {
var chunks = element.split( "=" );
if ( chunks.length > 1 ) {
if ( chunks[ 0 ] == key ) {
return chunks[ 1 ];
}
}
}
return def;
}
function authLevel( user ) {
return Authority.getLevel( user );
}
function setAuthLevel( user, level ) {
Authority.setLevel( user, level );
}
function getUser( message, params, bot ) {
var usr = false;
if ( !message.isPM() ) {
var wantedUser = getKey( params, "user", false ) || getKey( params, "u", false );
if ( wantedUser ) {
if ( bot ) {
console.log( bot.getUsers().length() );
return bot.getUsers().filter( "username", wantedUser, true );
}
usr = message.channel.server.members.filter( Discord.isUserID( wantedUser ) ? "id" : "username", wantedUser, true );
}
}
if ( !usr )
usr = message.author;
return usr;
}

View File

@@ -1,132 +0,0 @@
// If you did not clone discord.js, change the require parameter to `discord.js`
// and then run `npm install --save discord.js` in the same directory as this
// file. The bot should then run.
var Discord = require( "../" );
exports.Discord = Discord;
// Load the config file. If you have not already, make one that follows the
// structure : { "email" : "discordEmail", "password" : "discordPassword" }
var BotConfig = require( "./config.json" );
// Load the commands file
var Commands = require( "./commands.js" ).Commands;
// Load the Authority handler
var Authority = require( "./authority.js" );
// Initialise it
Authority.init();
// Create a new Discord Client
var hydrabot = new Discord.Client();
// An array of single character prefixes the bot will respond to
var commandPrefixes = [ "$", "£", "`" ];
// Log the client in using the auth details in config.json
hydrabot.on("debug", function(m){
console.log("debug", m);
})
console.time("hydrabotbenchmark");
hydrabot.login( BotConfig.email, BotConfig.password );
var time = Date.now();
// When the bot is ready to go, output to the console
hydrabot.on( "ready", function() {
console.timeEnd("hydrabotbenchmark");
} );
hydrabot.on("userupdate", function(ol, ne){
var serversInvolved = hydrabot.getServers().deepFilter(["members", "id"], ol.id);
for(server of serversInvolved.contents){
hydrabot.sendMessage(server.getDefaultChannel(), "Just sayin', "+ol.username+" changed their name to "+ne.username+". I know. Disgraceful.", function(err){
console.log(err);
}, {
selfDestruct: 5000
});
}
});
// When the bot gets disconnected, exit.
hydrabot.on( "disconnected", function( obj ) {
// Say we couldn't connect and then exit
console.log( "Disconnected - " + obj.reason );
process.exit( 0 );
} );
hydrabot.on("messageDelete", function(message){
console.log(message);
})
hydrabot.on("messageUpdate", function(former, edit){
if(former){
if(former.author.equals(this.user) || former.content === edit.content){
return;
}
var seconds = Math.round((Date.now() - former.time) / 1000);
var channel = former.channel;
hydrabot.sendMessage(channel, "**"+former.author.username + "** (edit from message "+seconds+" seconds ago):\n " + former.content);
}
})
hydrabot.on( "message", function( message ) {
// if the message doesn't begin with a valid command prefix exit
if ( commandPrefixes.indexOf( message.content.charAt( 0 ) ) == -1 )
return;
var command = "",
params = []; //set the message details
// remove the prefix from the start of the message
message.content = message.content.substr( 1 );
// split the message by slashes. This will yield something
// like: ["command", "a", "b", "c"].
var chunks = message.content.split( "/" );
for ( key in chunks ) { //loop through the chunks and trim them
chunks[ key ] = chunks[ key ].trim();
}
command = chunks[ 0 ]; //the first param will be the command
params = chunks.slice( 1 );
// it's less messy if we outsource to another function
handleMessage( command, params, message );
} );
function handleMessage( command, params, message ) {
if ( Commands[ command ] ) {
if ( Authority.getLevel( message.author ) >= Commands[ command ].oplevel ) {
//user has authority to do this
Commands[ command ].fn( hydrabot, params, message );
} else {
//user doesn't have authority
hydrabot.reply( message, exports.AUTH_ERROR );
}
} else {
hydrabot.reply( message, exports.NOT_FOUND );
}
}
exports.AUTH_ERROR = "you don't have authority to do this!";
exports.NOT_FOUND = "that command was not found!";

1068
index.js

File diff suppressed because it is too large Load Diff

6
jsconfig.json Normal file
View File

@@ -0,0 +1,6 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs"
}
}

1928
lib/Client.js Normal file

File diff suppressed because it is too large Load Diff

13
lib/Endpoints.js Normal file
View File

@@ -0,0 +1,13 @@
"use strict";
exports.BASE_DOMAIN = "discordapp.com";
exports.BASE = "https://" + exports.BASE_DOMAIN;
exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
exports.API = exports.BASE + "/api";
exports.AUTH = exports.API + "/auth";
exports.LOGIN = exports.AUTH + "/login";
exports.LOGOUT = exports.AUTH + "/logout";
exports.USERS = exports.API + "/users";
exports.SERVERS = exports.API + "/guilds";
exports.CHANNELS = exports.API + "/channels";

21
lib/Member.js Normal file
View File

@@ -0,0 +1,21 @@
"use strict";
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var User = require("./user.js");
var Member = (function (_User) {
_inherits(Member, _User);
function Member(data) {
_classCallCheck(this, Member);
_get(Object.getPrototypeOf(Member.prototype), "constructor", this).call(this, data);
}
return Member;
})(User);

View File

@@ -1,6 +1,71 @@
var User = require("./user.js").User;
"use strict";
exports.PMChannel = function(user, id){
this.user = new User(user);
this.id = id;
}
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PMChannel = (function () {
function PMChannel(data, client) {
_classCallCheck(this, PMChannel);
this.user = client.getUser("id", data.recipient.id);
this.id = data.id;
this.messages = [];
}
_createClass(PMChannel, [{
key: "addMessage",
value: function addMessage(data) {
if (!this.getMessage("id", data.id)) {
this.messages.push(data);
}
return this.getMessage("id", data.id);
}
}, {
key: "getMessage",
value: function getMessage(key, value) {
if (this.messages.length > 1000) {
this.messages.splice(0, 1);
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var message = _step.value;
if (message[key] === value) {
return message;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"]) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return null;
}
}, {
key: "isPrivate",
get: function get() {
return true;
}
}]);
return PMChannel;
})();
module.exports = PMChannel;

48
lib/Permissions.js Normal file
View File

@@ -0,0 +1,48 @@
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Permission = (function () {
function Permission(packedPermissions) {
_classCallCheck(this, Permission);
function getBit(x) {
return (this.packed >>> x & 1) === 1;
}
this.packed = packedPermissions;
this.createInstantInvite = getBit(0);
this.banMembers = getBit(1);
this.kickMembers = getBit(2);
this.manageRoles = getBit(3);
this.manageChannels = getBit(4);
this.manageServer = getBit(5);
this.readMessages = getBit(10);
this.sendMessages = getBit(11);
this.sendTTSMessages = getBit(12);
this.manageMessages = getBit(13);
this.embedLinks = getBit(14);
this.attachFiles = getBit(15);
this.readMessageHistory = getBit(16);
this.mentionEveryone = getBit(17);
this.voiceConnect = getBit(20);
this.voiceSpeak = getBit(21);
this.voiceMuteMembers = getBit(22);
this.voiceDeafenMembers = getBit(23);
this.voiceMoveMembers = getBit(24);
this.voiceUseVoiceActivation = getBit(26);
}
_createClass(Permission, [{
key: "getBit",
value: function getBit(x) {
return (this.packed >>> x & 1) === 1;
}
}]);
return Permission;
})();

View File

@@ -1,68 +0,0 @@
var fs = require( "fs" );
var crypto = require( "crypto" );
var md5 = require( "md5" );
var tokens = {};
exports.TokenManager = function( folder, file ) {
this.path = folder + file;
var self = this;
try {
var fd = fs.openSync( self.path, "wx" );
self.writeTokens();
} catch ( e ) {
self.readTokens();
}
}
exports.TokenManager.prototype.addToken = function( id, token, pass ) {
tokens[ md5( id ) ] = encrypt( token, pass );
this.writeTokens();
}
exports.TokenManager.prototype.readTokens = function() {
tokens = JSON.parse( fs.readFileSync( this.path, "utf8" ) );
for ( tkn in tokens ) {
tokens[ tkn ] = decrypt( tokens[ tkn ], tkn );
}
}
exports.TokenManager.prototype.writeTokens = function() {
var tkn = {};
for ( token in tokens ) {
tkn[ token ] = encrypt( tokens[ token ], token );
}
fs.writeFile( this.path, JSON.stringify( tkn ), function( err ) {
} );
}
exports.TokenManager.prototype.exists = function( id ) {
return tokens[ md5( id ) ];
}
exports.TokenManager.prototype.getToken = function( id, pass ) {
try{
return decrypt( tokens[ md5( id ) ], pass );
}catch(e){
return false;
}
}
function encrypt( string, password ) {
var cipher = crypto.createCipher( "aes-256-ctr", password )
var crypted = cipher.update( string, 'utf8', 'hex' )
crypted += cipher.final( 'hex' );
return crypted;
}
function decrypt( string, password ) {
var decipher = crypto.createDecipher( "aes-256-ctr", password )
var dec = decipher.update( string, 'hex', 'utf8' )
dec += decipher.final( 'utf8' );
return dec;
}

View File

@@ -1,28 +1,101 @@
var List = require("./list.js").List;
"use strict";
exports.Channel = function(name, server, type, id, isPrivate){
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
if(!type){ //there's no second argument
var channel = name;
name = channel.name;
server = server;
type = channel.type;
id = channel.id;
isPrivate = channel.is_private;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Channel = (function () {
function Channel(data, server) {
_classCallCheck(this, Channel);
this.server = server;
this.name = data.name;
this.type = data.type;
this.topic = data.topic;
this.id = data.id;
this.messages = [];
//this.isPrivate = isPrivate; //not sure about the implementation of this...
}
this.name = name;
this.server = server;
this.type = type;
this.id = id;
this.isPrivate = isPrivate;
this.messages = new List("id", 5000);
}
_createClass(Channel, [{
key: "equals",
value: function equals(object) {
return object && object.id === this.id;
}
}, {
key: "addMessage",
value: function addMessage(data) {
exports.Channel.equals = function(otherChannel){
if(otherChannel.id === this.id){
return true;
} else {
return false;
}
}
if (this.messages.length > 1000) {
this.messages.splice(0, 1);
}
if (!this.getMessage("id", data.id)) {
this.messages.push(data);
}
return this.getMessage("id", data.id);
}
}, {
key: "getMessage",
value: function getMessage(key, value) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var message = _step.value;
if (message[key] === value) {
return message;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"]) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return null;
}
}, {
key: "toString",
value: function toString() {
return "<#" + this.id + ">";
}
}, {
key: "client",
get: function get() {
return this.server.client;
}
}, {
key: "isPrivate",
get: function get() {
return false;
}
}, {
key: "users",
get: function get() {
return this.server.members;
}
}, {
key: "members",
get: function get() {
return this.server.members;
}
}]);
return Channel;
})();
module.exports = Channel;

View File

@@ -1,15 +0,0 @@
var base = "https://discordapp.com/";
var apibase = base + "api";
exports.API = apibase;
exports.WEBSOCKET_HUB = "wss://discordapp.com/hub"
exports.USERS = apibase + "/users";
exports.LOGIN = apibase + "/auth/login";
exports.LOGOUT = apibase + "/auth/logout";
exports.SERVERS = apibase + "/guilds";
exports.CHANNELS = apibase + "/channels";

12
lib/index.js Normal file
View File

@@ -0,0 +1,12 @@
"use strict";
var request = require("superagent");
var Endpoints = require("./Endpoints.js");
var Client = require("./Client.js");
var Discord = {
Endpoints: Endpoints,
Client: Client
};
module.exports = Discord;

View File

@@ -1,5 +1,7 @@
var request = require( "superagent" );
var Endpoints = require( "./endpoints.js" );
"use strict";
var request = require("superagent");
var Endpoints = require("./endpoints.js");
var Internal = {};
@@ -14,264 +16,188 @@ Internal.WebSocket.properties = {
"$referring_domain": ""
};
Internal.XHR.login = function( email, password, callback ) {
Internal.XHR.login = function (email, password, callback) {
request
.post( Endpoints.LOGIN )
.send( {
email: email,
password: password
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body.token );
}
} );
request.post(Endpoints.LOGIN).send({
email: email,
password: password
}).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body.token);
}
});
};
}
Internal.XHR.logout = function (token, callback) {
Internal.XHR.logout = function( token, callback ) {
request.post(Endpoints.LOGOUT).end(function (err, res) {
request
.post( Endpoints.LOGOUT )
.end( function( err, res ) {
err ? callback(err) : callback(null);
});
};
err ? callback( err ) : callback( null );
Internal.XHR.createServer = function (token, name, region, callback) {
} );
request.post(Endpoints.SERVERS).set("authorization", token).send({
name: name,
region: region
}).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
}
Internal.XHR.leaveServer = function (token, serverId, callback) {
Internal.XHR.createServer = function( token, name, region, callback ) {
request.del(Endpoints.SERVERS + "/" + serverId).set("authorization", token).end(function (err, res) {
request
.post( Endpoints.SERVERS )
.set( "authorization", token )
.send( {
name: name,
region: region
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
err ? callback(err) : callback(null);
});
};
Internal.XHR.leaveServer = function( token, serverId, callback ) {
Internal.XHR.createInvite = function (token, channelId, options, callback) {
request.post(Endpoints.CHANNELS + "/" + channelId + "/invites").set("authorization", token).send(options).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
request
.del( Endpoints.SERVERS + "/" + serverId )
.set( "authorization", token )
.end( function( err, res ) {
Internal.XHR.startPM = function (token, selfID, userID, callback) {
err ? callback( err ) : callback( null );
request.post(Endpoints.USERS + "/" + selfID + "/channels").set("authorization", token).send({
recipient_id: userID
}).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
} );
Internal.XHR.sendMessage = function (token, channelID, messageParameters, callback) {
request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).send(messageParameters).end(function (err, res) {
}
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
Internal.XHR.createInvite = function( token, channelId, options, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelId + "/invites" )
.set( "authorization", token )
.send( options )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} )
}
Internal.XHR.sendFile = function (token, channelID, file, fileName, callback) {
request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).attach("file", file, fileName).end(function (err, res) {
Internal.XHR.startPM = function( token, selfID, userID, callback ) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
request
.post( Endpoints.USERS + "/" + selfID + "/channels" )
.set( "authorization", token )
.send( {
recipient_id: userID
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
Internal.XHR.deleteMessage = function (token, channelID, messageID, callback) {
request.del(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).end(function (err) {
err ? callback(err) : callback(null);
});
};
}
Internal.XHR.updateMessage = function (token, channelID, messageID, messageParameters, callback) {
Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
.set( "authorization", token )
.send( messageParameters )
.end( function( err, res ) {
request.patch(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).send(messageParameters).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
Internal.XHR.getChannelLogs = function (token, channelID, amount, callback) {
request.get(Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount).set("authorization", token).end(function (err, res) {
} );
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
}
Internal.XHR.createChannel = function (token, serverID, name, type, callback) {
request.post(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).send({
name: name,
type: type
}).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
.set( "authorization", token )
.attach("file", file, fileName)
.end( function( err, res ) {
Internal.XHR.deleteChannel = function (token, channelID, callback) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
request.del(Endpoints.CHANNELS + "/" + channelID).set("authorization", token).end(function (err) {
err ? callback(err) : callback(null);
});
};
Internal.XHR.deleteServer = function (token, serverID, callback) {
request.del(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err) {
err ? callback(err) : callback(null);
});
};
} );
}
Internal.XHR.getChannels = function (token, serverID, callback) {
request.get(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).end(function (err) {
err ? callback(err) : callback(null);
});
};
Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) {
request
.del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.getServer = function (token, serverID, callback) {
Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) {
request.get(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err, res) {
request
.patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
.set( "authorization", token )
.send( messageParameters )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) {
request
.get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount )
.set( "authorization", token )
.end( function( err, res ) {
Internal.XHR.acceptInvite = function (token, inviteID, callback) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
request.post(Endpoints.API + "/invite/" + inviteID).set("authorization", token).end(function (err, res) {
if (err) {
callback(err);
} else {
callback(null, res.body);
}
});
};
} );
}
Internal.XHR.setUsername = function (token, avatar, email, newPassword, password, username, callback) {
Internal.XHR.createChannel = function( token, serverID, name, type, callback ) {
request
.post( Endpoints.SERVERS + "/" + serverID + "/channels" )
.set( "authorization", token )
.send( {
name: name,
type: type
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.deleteChannel = function( token, channelID, callback ) {
request
.del( Endpoints.CHANNELS + "/" + channelID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.deleteServer = function( token, serverID, callback ) {
request
.del( Endpoints.SERVERS + "/" + serverID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.getChannels = function( token, serverID, callback ) {
request
.get( Endpoints.SERVERS + "/" + serverID + "/channels" )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.getServer = function( token, serverID, callback ) {
request
.get( Endpoints.SERVERS + "/" + serverID )
.set( "authorization", token )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.acceptInvite = function( token, inviteID, callback ) {
request
.post( Endpoints.API + "/invite/" + inviteID )
.set( "authorization", token )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body )
}
} );
}
Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) {
request
.patch( Endpoints.API + "/users/@me" )
.set( "authorization", token )
.send( {
avatar: avatar,
email: email,
new_password: newPassword,
password: password,
username: username
} )
.end( function( err ) {
callback( err );
} );
}
request.patch(Endpoints.API + "/users/@me").set("authorization", token).send({
avatar: avatar,
email: email,
new_password: newPassword,
password: password,
username: username
}).end(function (err) {
callback(err);
});
};
exports.Internal = Internal;

View File

@@ -1,21 +1,35 @@
var User = require("./user.js").User;
"use strict";
exports.Invite = function(json){
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
this.max_age = json.max_age;
this.code = json.code;
this.server = json.guild;
this.revoked = json.revoked;
this.created_at = Date.parse(json.created_at);
this.temporary = json.temporary;
this.uses = json.uses;
this.max_uses = json.uses;
this.inviter = new User(json.inviter);
this.xkcdpass = json.xkcdpass;
this.channel = json.channel;
}
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
exports.Invite.prototype.generateInviteURL = function(xkcd){
var code = (xkcd ? this.xkcdpass : this.code);
return "https://discord.gg/"+code;
}
var Invite = (function () {
function Invite(data, client) {
_classCallCheck(this, Invite);
this.max_age = data.max_age;
this.code = data.code;
this.server = client.getServer("id", data.guild.id);
this.revoked = data.revoked;
this.created_at = Date.parse(data.created_at);
this.temporary = data.temporary;
this.uses = data.uses;
this.max_uses = data.uses;
this.inviter = client.addUser(data.inviter);
this.xkcd = data.xkcdpass;
this.channel = client.getChannel("id", data.channel.id);
}
_createClass(Invite, [{
key: "URL",
get: function get() {
var code = this.xkcd ? this.xkcdpass : this.code;
return "https://discord.gg/" + code;
}
}]);
return Invite;
})();
module.exports = Invite;

View File

@@ -1,248 +0,0 @@
/**
* Similar to a Java set. Contains no duplicate elements and includes filter
* functions. Discriminates between elements based on a discriminator passed
* when created. Generally "ID"
* @class List
*/
exports.List = function( discriminator, cap ) {
/**
* What to use to distringuish duplicates
* @attribute discriminator
* @type {String}
*/
this.discriminator = discriminator;
/**
* The maximum amount of elements allowed in the list.
* @default Infinity
* @attribute cap
* @type {Number}
*/
this.cap = cap || Number.MAX_SAFE_INTEGER;
/**
* The Array version of the List.
* @type {Array}
* @attribute contents
*/
this.contents = [];
}
/**
* Adds an element to the list if it isn't already there.
* @method add
* @param {Object/Array} element The element(s) to add
* @example
* List.add( obj );
* List.add( [ obj, obj, obj ] );
*/
exports.List.prototype.add = function( child ) {
var self = this;
if ( child.constructor === Array ) {
children = child;
for ( child of children ) {
addChild( child );
}
} else {
addChild( child );
}
function addChild( child ) {
if ( self.length() > self.cap ) {
self.splice( 0, 1 );
}
if ( self.filter( self.discriminator, child[ self.discriminator ] ).length() === 0 )
self.contents.push( child );
}
}
/**
* Returns the length of the List
* @method length
* @return {Number}
*/
exports.List.prototype.length = function() {
return this.contents.length;
}
/**
* Gets the index of an element in the List or defaults to false
* @param {Object} object The element we want to get the index of
* @return {Number/Boolean} The index if the object is in the list, or false.
* @method getIndex
*/
exports.List.prototype.getIndex = function( object ) {
var index = false;
for ( elementIndex in this.contents ) {
var element = this.contents[ elementIndex ];
if ( element[ this.discriminator ] == object[ this.discriminator ] ) {
return elementIndex;
}
}
return index;
}
/**
* Removes an element at the specified index
* @param {Number} index
* @method removeIndex
*/
exports.List.prototype.removeIndex = function( index ) {
this.contents.splice( index, 1 );
}
/**
* Removes an element from the list
* @param {Object} element
* @method removeElement
* @return {Boolean} whether the operation was successful or not.
*/
exports.List.prototype.removeElement = function( child ) {
for ( _element in this.contents ) {
var element = this.contents[ _element ];
if ( child[ this.discriminator ] == element[ this.discriminator ] ) {
this.removeIndex( _element, 1 );
return true;
}
}
return false;
}
/**
* Replaces an element in the list with a specified element
* @method updateElement
* @param {Object} element Element to update.
* @param {Object} newElement New Element
* @return {Boolean} whether the operation was successful or not.
*/
exports.List.prototype.updateElement = function( child, newChild ) {
for ( _element in this.contents ) {
var element = this.contents[ _element ];
if ( child[ this.discriminator ] == element[ this.discriminator ] ) {
this.contents[ _element ] = newChild;
return true;
}
}
return false;
}
exports.List.prototype.concatSublists = function( whereList, discriminator ) {
//this is meant to look at the contents, and assuming the contents are all lists, concatenate their values.
var concatList = new exports.List( discriminator );
for ( item of this.contents ) {
var itemList = item[ whereList ];
concatList.add( itemList.contents );
}
return concatList;
}
exports.List.prototype.filter = function( key, value, onlyOne, caseInsen ) {
var results = [];
value = change( value );
for ( index in this.contents ) {
var child = this.contents[ index ];
if ( change( child[ key ] ) == value ) {
if ( onlyOne ) {
return child;
} else {
results.push( child );
}
}
}
function change( val ) {
if ( caseInsen ) {
val = val.toUpperCase();
}
return val;
}
if ( onlyOne ) {
return false;
}
var retList = new exports.List( this.discriminator );
retList.contents = results;
return retList;
}
exports.List.prototype.getValues = function( key ){
var valList = [];
for( child of this.contents){
valList.push( child[key] );
}
return valList;
}
exports.List.prototype.deepFilter = function( keys, value, onlyOne, caseInsen ) {
var results = [];
value = change( value );
for ( index in this.contents ) {
var child = this.contents[ index ];
var buffer = child;
for ( key of keys ) {
if(buffer instanceof exports.List){
buffer = buffer.contents;
}
if(buffer instanceof Array){
for(elem of buffer){
if( change(elem[key]) == value ){
buffer = elem;
}
}
}
buffer = buffer[ key ];
}
if ( change( buffer ) == value ) {
if ( onlyOne ) {
return child;
} else {
results.push( child );
}
}
}
function change( val ) {
if ( caseInsen ) {
val = val.toUpperCase();
}
return val;
}
if ( onlyOne ) {
return false;
}
var retList = new exports.List( this.discriminator );
retList.contents = results;
return retList;
}

View File

@@ -1,39 +1,79 @@
var User = require( "./user.js" ).User;
var List = require( "./list.js" ).List;
var PMChannel = require( "./PMChannel.js" ).PMChannel;
"use strict";
exports.Message = function( time, author, content, channel, id, mentions, everyoneMentioned, embeds ) {
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
if ( !content ) {
message = time;
channel = author;
time = message.timestamp;
author = message.author;
content = message.content;
id = message.id;
mentions = message.mentions;
everyoneMentioned = message.mention_everyone;
embeds = message.embeds;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PMChannel = require("./PMChannel.js");
var Message = (function () {
function Message(data, channel, mentions, author) {
_classCallCheck(this, Message);
this.tts = data.tts;
this.timestamp = Date.parse(data.timestamp);
this.nonce = data.nonce;
this.mentions = mentions;
this.everyoneMentioned = data.mention_everyone;
this.id = data.id;
this.embeds = data.embeds;
this.editedTimestamp = data.edited_timestamp;
this.content = data.content.trim();
this.channel = channel;
this.author = author;
this.attachments = data.attachments;
}
this.time = Date.parse( time );
this.author = new User( author );
this.content = content.replace( /\s+/g, ' ' ).trim(); //content.replace(/<[^>]*>/g, "").replace(/\s+/g, ' ').trim();
this.channel = channel;
this.id = id;
this.mentions = new List( "id" );
this.everyoneMentioned = everyoneMentioned;
this.embeds = embeds;
for ( x in mentions ) {
var _mention = mentions[ x ];
this.mentions.add( new User( _mention ) );
}
}
/*exports.Message.prototype.isPM = function() {
return ( this.channel instanceof PMChannel );
}*/
exports.Message.prototype.isPM = function() {
return ( this.channel instanceof PMChannel );
}
_createClass(Message, [{
key: "isMentioned",
value: function isMentioned(user) {
var id = user.id ? user.id : user;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
exports.Message.prototype.isMentioned = function( user ) {
return ( this.mentions.filter( "id", user.id ).length > 0 );
}
try {
for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var mention = _step.value;
if (mention.id === id) {
return true;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"]) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return false;
}
}, {
key: "sender",
get: function get() {
return this.author;
}
}, {
key: "isPrivate",
get: function get() {
return this.channel.isPrivate;
}
}]);
return Message;
})();
module.exports = Message;

View File

@@ -1,106 +1,183 @@
var User = require( "./user.js" ).User;
var List = require( "./list.js" ).List;
/**
* A wrapper for Server information, contains channels and users too. Developers should not instantiate the class, instead they should
* manipulate Server objects given to them.
* @class Server
* @param {String} region The region of the server
*/
exports.Server = function( region, ownerID, name, id, members, icon, afkTimeout, afkChannelId ) {
"use strict";
/**
* The region of the Server
* @type {String}
* @attribute region
*/
this.region = region;
/**
* The ID of the owner of the Server (not a User!)
* @type {String}
* @attribute ownerID
*/
this.ownerID = ownerID;
/**
* The name of the Server
* @type {String}
* @attribute name
*/
this.name = name;
/**
* The ID of the Server
* @type {String}
* @attribute id
*/
this.id = id;
/**
* List containing members of the Server
* @param {List}
* @attribute members
*/
this.members = new List( "id" );
/**
* List containing channelss of the Server
* @param {List}
* @attribute channels
*/
this.channels = new List( "id" );
/**
* ID of the Icon of the Server
* @param {String}
* @attribute icon
*/
this.icon = icon;
/**
* The amount of seconds that should pass before the user is
* @type {Number}
* @attribute afkTimeout
*/
this.afkTimeout = afkTimeout;
/**
* The ID of the AFK Channel, evaluates to false if doesn't exist.
* @type {String}
* @attribute afkChannelId
*/
this.afkChannelId = afkChannelId;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
for ( x in members ) {
var member = members[ x ].user;
this.members.add( new User( member ) );
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Server = (function () {
function Server(data, client) {
_classCallCheck(this, Server);
this.client = client;
this.region = data.region;
this.ownerID = data.owner_id;
this.name = data.name;
this.id = data.id;
this.members = [];
this.channels = [];
this.icon = data.icon;
this.afkTimeout = data.afk_timeout;
this.afkChannelId = data.afk_channel_id;
if (!data.members) {
data.members = [client.user];
return;
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var member = _step.value;
// first we cache the user in our Discord Client,
// then we add it to our list. This way when we
// get a user from this server's member list,
// it will be identical (unless an async change occurred)
// to the client's cache.
if (member.user) this.members.push(client.addUser(member.user));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"]) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}
/**
* Returns a valid URL pointing towards the server's icon if it has one.
* @method getIconURL
* @return {String/Boolean} If there is an icon, a URL is returned. If not, false is returned.
*/
exports.Server.prototype.getIconURL = function(){
if(!this.icon)
return false;
return "https://discordapp.com/api/guilds/"+this.id+"/icons/"+this.icon+".jpg";
}
_createClass(Server, [{
key: "getChannel",
/**
* Returns the AFK Channel if a server has one
* @method getAFKChannel
* @return {Channel/Boolean} If there is an AFK Channel, a Channel is returned. If not, false is returned.
*/
exports.Server.prototype.getAFKChannel = function(){
// get/set
value: function getChannel(key, value) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
if(!this.afkChannelId)
return false;
try {
for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var channel = _step2.value;
return this.channels.filter("id", this.afkChannelId, true);
if (channel[key] === value) {
return channel;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
_iterator2["return"]();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
return null;
}
}, {
key: "getMember",
value: function getMember(key, value) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
/**
* Returns the #general channel of the server.
* @method getDefaultChannel
* @return {Channel} Returns the #general channel of the Server.
*/
exports.Server.prototype.getDefaultChannel = function() {
try {
for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var member = _step3.value;
return this.channels.filter( "name", "general", true );
if (member[key] === value) {
return member;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
_iterator3["return"]();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
return null;
}
}, {
key: "addChannel",
value: function addChannel(chann) {
if (!this.getChannel("id", chann.id)) {
this.channels.push(chann);
}
return chann;
}
}, {
key: "addMember",
value: function addMember(member) {
if (!this.getMember("id", member.id)) {
this.members.push(member);
}
return member;
}
}, {
key: "toString",
value: function toString() {
return this.name;
}
}, {
key: "equals",
value: function equals(object) {
return object.id === this.id;
}
}, {
key: "iconURL",
get: function get() {
if (!this.icon) return null;
return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
}
}, {
key: "afkChannel",
get: function get() {
if (!this.afkChannelId) return false;
return this.getChannel("id", this.afkChannelId);
}
}, {
key: "defaultChannel",
get: function get() {
return this.getChannel("name", "general");
}
}, {
key: "owner",
get: function get() {
return this.client.getUser("id", this.ownerID);
}
}, {
key: "users",
get: function get() {
return this.members;
}
}]);
return Server;
})();
module.exports = Server;

View File

@@ -1,37 +1,57 @@
exports.User = function( username, id, discriminator, avatar ) {
"use strict";
if ( !id ) { //there's no second argument
var user = username;
username = user.username;
id = user.id;
discriminator = user.discriminator;
avatar = user.avatar;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var User = (function () {
function User(data) {
_classCallCheck(this, User);
this.username = data.username;
this.discriminator = data.discriminator;
this.id = data.id;
this.avatar = data.avatar;
this.status = "offline";
}
this.username = username;
this.discriminator = discriminator;
this.id = id;
this.avatar = avatar;
}
// access using user.avatarURL;
exports.User.prototype.getAvatarURL = function() {
if ( !this.avatar )
return false;
return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
}
_createClass(User, [{
key: "mention",
value: function mention() {
return "<@" + this.id + ">";
}
}, {
key: "toString",
value: function toString() {
/*
if we embed a user in a String - like so:
"Yo " + user + " what's up?"
It would generate something along the lines of:
"Yo @hydrabolt what's up?"
*/
return this.mention();
}
}, {
key: "equals",
value: function equals(object) {
return object.id === this.id;
}
}, {
key: "equalsStrict",
value: function equalsStrict(object) {
return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
}
}, {
key: "avatarURL",
get: function get() {
if (!this.avatar) return null;
return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
}
}]);
exports.User.prototype.mention = function() {
return "<@" + this.id + ">";
}
return User;
})();
exports.User.prototype.equals = function( otherUser ) {
return otherUser.id === this.id;
}
exports.User.prototype.equalsStrict = function( otherUser ) {
return ( this.username === otherUser.username && this.discriminator === otherUser.discriminator && this.id === otherUser.id && this.avatar === otherUser.avatar );
}
module.exports = User;

View File

@@ -1,14 +1,14 @@
{
"name": "discord.js",
"version": "2.7.1",
"version": "3.7.2",
"description": "A way to interface with the Discord API",
"main": "index.js",
"main": "./lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node ./test/bot.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/discord-js/discord.js.git"
"url": "git+https://github.com/hydrabolt/discord.js.git"
},
"keywords": [
"discord",
@@ -21,12 +21,18 @@
"author": "Amish Shah <amishshah.2k@gmail.com>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/discord-js/discord.js/issues"
"url": "https://github.com/hydrabolt/discord.js/issues"
},
"homepage": "https://github.com/discord-js/discord.js#readme",
"homepage": "https://github.com/hydrabolt/discord.js#readme",
"dependencies": {
"md5": "^2.0.0",
"superagent": "^1.3.0",
"ws": "^0.7.2"
},
"devDependencies": {
"grunt": "~0.4.5",
"grunt-babel": "^5.0.1",
"grunt-browserify": "^4.0.0",
"grunt-contrib-uglify": "^0.9.2",
"load-grunt-tasks": "^3.2.0"
}
}

1
ref/gameMap.json Normal file

File diff suppressed because one or more lines are too long

1587
src/Client.js Normal file

File diff suppressed because it is too large Load Diff

11
src/Endpoints.js Normal file
View File

@@ -0,0 +1,11 @@
exports.BASE_DOMAIN = "discordapp.com";
exports.BASE = `https://${exports.BASE_DOMAIN}`;
exports.WEBSOCKET_HUB = `wss://${exports.BASE_DOMAIN}/hub`;
exports.API = `${exports.BASE}/api`;
exports.AUTH = `${exports.API}/auth`;
exports.LOGIN = `${exports.AUTH}/login`;
exports.LOGOUT = `${exports.AUTH}/logout`;
exports.USERS = `${exports.API}/users`;
exports.SERVERS = `${exports.API}/guilds`;
exports.CHANNELS = `${exports.API}/channels`;

12
src/Member.js Normal file
View File

@@ -0,0 +1,12 @@
var User = require("./user.js");
class Member extends User{
constructor(data){
super(data);
}
}

34
src/PMChannel.js Normal file
View File

@@ -0,0 +1,34 @@
class PMChannel {
constructor(data, client) {
this.user = client.getUser("id", data.recipient.id);
this.id = data.id;
this.messages = [];
}
addMessage(data){
if(!this.getMessage("id", data.id)){
this.messages.push(data);
}
return this.getMessage("id", data.id);
}
getMessage(key, value){
if(this.messages.length > 1000){
this.messages.splice(0,1);
}
for(var message of this.messages){
if(message[key] === value){
return message;
}
}
return null;
}
get isPrivate(){
return true;
}
}
module.exports = PMChannel;

38
src/Permissions.js Normal file
View File

@@ -0,0 +1,38 @@
class Permission {
constructor(packedPermissions) {
function getBit(x) {
return ((this.packed >>> x) & 1) === 1;
}
this.packed = packedPermissions;
this.createInstantInvite = getBit(0);
this.banMembers = getBit(1);
this.kickMembers = getBit(2);
this.manageRoles = getBit(3);
this.manageChannels = getBit(4);
this.manageServer = getBit(5);
this.readMessages = getBit(10);
this.sendMessages = getBit(11);
this.sendTTSMessages = getBit(12);
this.manageMessages = getBit(13);
this.embedLinks = getBit(14);
this.attachFiles = getBit(15);
this.readMessageHistory = getBit(16);
this.mentionEveryone = getBit(17);
this.voiceConnect = getBit(20);
this.voiceSpeak = getBit(21);
this.voiceMuteMembers = getBit(22);
this.voiceDeafenMembers = getBit(23);
this.voiceMoveMembers = getBit(24);
this.voiceUseVoiceActivation = getBit(26);
}
getBit(x) {
return ((this.packed >>> x) & 1) === 1;
}
}

60
src/channel.js Normal file
View File

@@ -0,0 +1,60 @@
class Channel {
constructor(data, server) {
this.server = server;
this.name = data.name;
this.type = data.type;
this.topic = data.topic;
this.id = data.id;
this.messages = [];
//this.isPrivate = isPrivate; //not sure about the implementation of this...
}
get client() {
return this.server.client;
}
equals(object) {
return (object && object.id === this.id);
}
addMessage(data){
if(this.messages.length > 1000){
this.messages.splice(0,1);
}
if(!this.getMessage("id", data.id)){
this.messages.push(data);
}
return this.getMessage("id", data.id);
}
getMessage(key, value){
for(var message of this.messages){
if(message[key] === value){
return message;
}
}
return null;
}
toString(){
return "<#" + this.id + ">";
}
get isPrivate(){
return false;
}
get users(){
return this.server.members;
}
get members(){
return this.server.members;
}
}
module.exports = Channel;

10
src/index.js Normal file
View File

@@ -0,0 +1,10 @@
var request = require("superagent");
var Endpoints = require("./Endpoints.js");
var Client = require("./Client.js");
var Discord = {
Endpoints : Endpoints,
Client : Client
}
module.exports = Discord;

277
src/internal.js Normal file
View File

@@ -0,0 +1,277 @@
var request = require( "superagent" );
var Endpoints = require( "./endpoints.js" );
var Internal = {};
Internal.XHR = {};
Internal.WebSocket = {};
Internal.WebSocket.properties = {
"$os": "discord.js",
"$browser": "discord.js",
"$device": "discord.js",
"$referrer": "",
"$referring_domain": ""
};
Internal.XHR.login = function( email, password, callback ) {
request
.post( Endpoints.LOGIN )
.send( {
email: email,
password: password
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body.token );
}
} );
}
Internal.XHR.logout = function( token, callback ) {
request
.post( Endpoints.LOGOUT )
.end( function( err, res ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.createServer = function( token, name, region, callback ) {
request
.post( Endpoints.SERVERS )
.set( "authorization", token )
.send( {
name: name,
region: region
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.leaveServer = function( token, serverId, callback ) {
request
.del( Endpoints.SERVERS + "/" + serverId )
.set( "authorization", token )
.end( function( err, res ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.createInvite = function( token, channelId, options, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelId + "/invites" )
.set( "authorization", token )
.send( options )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} )
}
Internal.XHR.startPM = function( token, selfID, userID, callback ) {
request
.post( Endpoints.USERS + "/" + selfID + "/channels" )
.set( "authorization", token )
.send( {
recipient_id: userID
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
.set( "authorization", token )
.send( messageParameters )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) {
request
.post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
.set( "authorization", token )
.attach("file", file, fileName)
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) {
request
.del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) {
request
.patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
.set( "authorization", token )
.send( messageParameters )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) {
request
.get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount )
.set( "authorization", token )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.createChannel = function( token, serverID, name, type, callback ) {
request
.post( Endpoints.SERVERS + "/" + serverID + "/channels" )
.set( "authorization", token )
.send( {
name: name,
type: type
} )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.deleteChannel = function( token, channelID, callback ) {
request
.del( Endpoints.CHANNELS + "/" + channelID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.deleteServer = function( token, serverID, callback ) {
request
.del( Endpoints.SERVERS + "/" + serverID )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.getChannels = function( token, serverID, callback ) {
request
.get( Endpoints.SERVERS + "/" + serverID + "/channels" )
.set( "authorization", token )
.end( function( err ) {
err ? callback( err ) : callback( null );
} );
}
Internal.XHR.getServer = function( token, serverID, callback ) {
request
.get( Endpoints.SERVERS + "/" + serverID )
.set( "authorization", token )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body );
}
} );
}
Internal.XHR.acceptInvite = function( token, inviteID, callback ) {
request
.post( Endpoints.API + "/invite/" + inviteID )
.set( "authorization", token )
.end( function( err, res ) {
if ( err ) {
callback( err );
} else {
callback( null, res.body )
}
} );
}
Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) {
request
.patch( Endpoints.API + "/users/@me" )
.set( "authorization", token )
.send( {
avatar: avatar,
email: email,
new_password: newPassword,
password: password,
username: username
} )
.end( function( err ) {
callback( err );
} );
}
exports.Internal = Internal;

22
src/invite.js Normal file
View File

@@ -0,0 +1,22 @@
class Invite {
constructor(data, client) {
this.max_age = data.max_age;
this.code = data.code;
this.server = client.getServer("id", data.guild.id);
this.revoked = data.revoked;
this.created_at = Date.parse(data.created_at);
this.temporary = data.temporary;
this.uses = data.uses;
this.max_uses = data.uses;
this.inviter = client.addUser(data.inviter);
this.xkcd = data.xkcdpass;
this.channel = client.getChannel("id", data.channel.id);
}
get URL() {
var code = (this.xkcd ? this.xkcdpass : this.code);
return "https://discord.gg/" + code;
}
}
module.exports = Invite;

42
src/message.js Normal file
View File

@@ -0,0 +1,42 @@
var PMChannel = require("./PMChannel.js");
class Message{
constructor(data, channel, mentions, author){
this.tts = data.tts;
this.timestamp = Date.parse(data.timestamp);
this.nonce = data.nonce;
this.mentions = mentions;
this.everyoneMentioned = data.mention_everyone;
this.id = data.id;
this.embeds = data.embeds;
this.editedTimestamp = data.edited_timestamp;
this.content = data.content.trim();
this.channel = channel;
this.author = author;
this.attachments = data.attachments;
}
isMentioned( user ){
var id = (user.id ? user.id : user);
for(var mention of this.mentions){
if(mention.id === id){
return true;
}
}
return false;
}
get sender(){
return this.author;
}
get isPrivate(){
return this.channel.isPrivate;
}
}
/*exports.Message.prototype.isPM = function() {
return ( this.channel instanceof PMChannel );
}*/
module.exports = Message;

101
src/server.js Normal file
View File

@@ -0,0 +1,101 @@
class Server {
constructor(data, client) {
this.client = client;
this.region = data.region;
this.ownerID = data.owner_id;
this.name = data.name;
this.id = data.id;
this.members = [];
this.channels = [];
this.icon = data.icon;
this.afkTimeout = data.afk_timeout;
this.afkChannelId = data.afk_channel_id;
if(!data.members){
data.members = [ client.user ];
return;
}
for (var member of data.members) {
// first we cache the user in our Discord Client,
// then we add it to our list. This way when we
// get a user from this server's member list,
// it will be identical (unless an async change occurred)
// to the client's cache.
if(member.user)
this.members.push(client.addUser(member.user));
}
}
get iconURL() {
if (!this.icon)
return null;
return `https://discordapp.com/api/guilds/${this.id}/icons/${this.icon}.jpg`;
}
get afkChannel() {
if (!this.afkChannelId)
return false;
return this.getChannel("id", this.afkChannelId);
}
get defaultChannel() {
return this.getChannel("name", "general");
}
get owner() {
return this.client.getUser("id", this.ownerID);
}
get users() {
return this.members;
}
// get/set
getChannel(key, value) {
for (var channel of this.channels) {
if (channel[key] === value) {
return channel;
}
}
return null;
}
getMember(key, value){
for (var member of this.members) {
if (member[key] === value) {
return member;
}
}
return null;
}
addChannel(chann) {
if (!this.getChannel("id", chann.id)) {
this.channels.push(chann);
}
return chann;
}
addMember(member){
if (!this.getMember("id", member.id)){
this.members.push(member);
}
return member;
}
toString(){
return this.name;
}
equals(object){
return object.id === this.id;
}
}
module.exports = Server;

40
src/user.js Normal file
View File

@@ -0,0 +1,40 @@
class User{
constructor( data ){
this.username = data.username;
this.discriminator = data.discriminator;
this.id = data.id;
this.avatar = data.avatar;
this.status = "offline";
}
// access using user.avatarURL;
get avatarURL(){
if( !this.avatar )
return null;
return `https://discordapp.com/api/users/${this.id}/avatars/${this.avatar}.jpg`;
}
mention(){
return `<@${this.id}>`;
}
toString(){
/*
if we embed a user in a String - like so:
"Yo " + user + " what's up?"
It would generate something along the lines of:
"Yo @hydrabolt what's up?"
*/
return this.mention();
}
equals(object){
return object.id === this.id;
}
equalsStrict(object){
return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
}
}
module.exports = User;

63
test/bot.1.js Normal file
View File

@@ -0,0 +1,63 @@
var Discord = require("../");
var mybot = new Discord.Client();
var fs = require("fs");
var server, channel, message, sentMessage = false;
counter = 1;
mybot.on("message", function (message) {
console.log("Everyone mentioned? " + message.everyoneMentioned);
if (mybot.user.equals(message.sender)) {
return;
}
if (message.content !== "$$$") {
return;
}
// we can go ahead :)
var onlineUsers = 0;
counter++;
mybot.playingGame( "Minecraft" );
});
mybot.on("ready", function () {
console.log("im ready");
for(var server of mybot.servers){
if(server.name === "test-server"){
mybot.leaveServer(server);
}
}
});
mybot.on("debug", function(info){
console.log(info);
})
mybot.on("unknown", function(info){
console.log("warning!", info);
})
mybot.on("channelUpdate", function(oldChan, newChan){
console.log(oldChan.topic + " vs " + newChan.topic);
});
function dump(msg) {
console.log(msg);
}
function error(err) {
console.log(err);
}
mybot.login(process.env["ds_email"], process.env["ds_password"]).catch(error);

134
test/bot.js Normal file
View File

@@ -0,0 +1,134 @@
/*
this file should be used for travis builds only
*/
var Discord = require("../");
var mybot = new Discord.Client();
var server, channel, message, sentMessage = false;
function init(){
console.log("preparing...");
}
mybot.on("ready", function(){
console.log("ready! beginning tests");
success1();
});
function success1(){ //make server
mybot.createServer("test-server", "london").then(success2).catch(error);
}
function success2(_server){ //make channel
console.log("test 1 successful");
server = _server;
mybot.createChannel(server, "test-channel", "text").then(success3).catch(error);
}
function success3(_channel){ //send message
console.log("test 2 successful");
channel = _channel;
mybot.sendMessage(channel, [mybot.user.avatarURL, "an", "array", "of", "messages"]).then(success4).catch(error);
}
function success4(_message){ //delete message
console.log("test 3 successful");
message = _message;
mybot.deleteMessage(message).then(success5).catch(error);
}
function success5(){ //send ping
console.log("test 4 successful");
mybot.sendMessage(channel, "ping").then(function(msg){
message = msg;
}).catch(error);
setTimeout(checkError, 30 * 1000);
}
function success7(){
console.log("test 6 successful");
mybot.deleteChannel(channel).then(success8).catch(error);
}
function success8(){
console.log("test 7 successful");
mybot.createInvite(server).then(success9).catch(error);
}
function success9(invite){
console.log("test 8 successful");
if(invite.code){
success10();
}else{
error("reference error");
}
}
function success10(){
console.log("test 9 succesful");
mybot.leaveServer(server).then(success11).catch(error);
}
function success11(){
console.log("test 10 succesful");
mybot.joinServer(process.env["ds_invite"]).then(success12).catch(error);
}
function success12(_server){
console.log("test 11 successful");
server = mybot.getServer("id", _server.id);
if(server){
success13();
}else{
error("reference error");
}
}
function success13(){
console.log("test 12 successful");
mybot.sendFile(server, "./test/image.png").then(function(msg){
mybot.deleteMessage(msg).then(success14).catch(error);
}).catch(error);
}
function success14(msg){
console.log("test 13 successful");
mybot.leaveServer(server).then(success15).catch(error);
}
function success15(){
console.log("test 14 successful");
mybot.logout().then(done).catch(error);
}
function done(){
console.log("All tests completed succesfully.");
process.exit(0);
}
function checkError(){
if(!sentMessage){
error("failure receiving messages");
}
}
function error(err){
console.log("error", err);
process.exit(1);
}
mybot.on("message", function(message){
if(message.channel.equals(channel)){
if(message.content === "ping"){
console.log("test 5 successful");
sentMessage = true;
mybot.updateMessage(message, "pong").then(success7).catch(error);
}
}
});
mybot.login(process.env["ds_email"], process.env["ds_password"]).then(init).catch(error);

BIN
test/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

0
test/msgbot.js Normal file
View File

10
web-dist/README.md Normal file
View File

@@ -0,0 +1,10 @@
## Web Distributions
Here you can find the latest web-ready distributions of discord.js. These distributions will allow you to run discord.js
in your browser, which is very useful for making on-the-go bots or clients. For some reason, request times are also much
shorter in browsers, so your bots will reply much faster.
Web Distributions aren't always fully functional, and sometimes catching errors is a pain. As discord.js's support for
browserifying is still maturing, please don't expect that it will work out of the box just yet.
Also, if the versions in this folder are out-dated, you can always run `grunt web` to generate the latest library.

3590
web-dist/discord.3.3.0.js Normal file

File diff suppressed because it is too large Load Diff

3590
web-dist/discord.3.3.1.js Normal file

File diff suppressed because it is too large Load Diff

3593
web-dist/discord.3.3.2.js Normal file

File diff suppressed because it is too large Load Diff

3641
web-dist/discord.3.4.0.js Normal file

File diff suppressed because it is too large Load Diff

3879
web-dist/discord.3.6.3.js Normal file

File diff suppressed because one or more lines are too long

3879
web-dist/discord.3.7.1.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long