From 8be39f8eb7d04c1beeae80e05802c2be6c6772f3 Mon Sep 17 00:00:00 2001 From: izy521 Date: Wed, 22 Mar 2017 22:07:06 -0700 Subject: [PATCH 01/54] Get webp instead of jpg for avatarURL --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 45d682f9..d797d2c6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2542,7 +2542,7 @@ Object.defineProperty(User.prototype, 'avatarURL', { get: function() { if (!this.avatar) return null; var animated = this.avatar.indexOf("a_") > -1; - return Discord.Endpoints.CDN + "/avatars/" + this.id + "/" + this.avatar + (animated ? ".gif" : ".jpg"); + return Discord.Endpoints.CDN + "/avatars/" + this.id + "/" + this.avatar + (animated ? ".gif" : ".webp"); }, set: function() {} }); From f6bc9b7d3ff2b85ef8b22734e093bcee76bccf45 Mon Sep 17 00:00:00 2001 From: izy521 Date: Sat, 25 Mar 2017 20:47:45 -0700 Subject: [PATCH 02/54] acceptInvite functionally removed Method still works and callback will be ran --- lib/index.js | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/lib/index.js b/lib/index.js index d797d2c6..416d29b5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -720,29 +720,11 @@ DCP.transferOwnership = function(input, callback) { }; /** - * Accept an invite to a server [User Only] - * @arg {String} inviteCode - The code part of an invite URL (e.g. 0MvHMfHcTKVVmIGP) + * (Used to) Accept an invite to a server [User Only]. Can no longer be used. + * @deprecated */ -DCP.acceptInvite = function(inviteCode, callback) { - if (this.bot) return handleErrCB("[acceptInvite] This account is a 'bot' type account, and cannot use 'acceptInvite'. Please use the client's inviteURL property instead.", callback); - var client = this, joinedServers = Object.keys(client.servers); - this._req('post', Endpoints.INVITES(inviteCode), function(err, res) { - try { - //Try to create the server with the small amount of data - //that Discord provides directly from the HTTP response - //since the websocket event may take a second to show. - if (!client.servers[res.body.guild.id]) { - client.servers[res.body.guild.id] = res.body.guild; - client.servers[res.body.guild.id].channels = {}; - client.servers[res.body.guild.id].channels[res.body.channel.id] = res.body.channel; - } else { - if (joinedServers.indexOf(res.body.guild.id) > -1) { - return handleErrCB(("Already joined server: " + res.body.guild.id), callback); - } - } - } catch(e) {} - handleResCB(("The invite code provided " + inviteCode + " is incorrect."), err, res, callback); - }); +DCP.acceptInvite = function(NUL, callback) { + return handleErrCB("acceptInvite can no longer be used", callback); }; /** From 698a91a8e9bbfbb925aebda491fc30ac30934726 Mon Sep 17 00:00:00 2001 From: izy521 Date: Sat, 25 Mar 2017 23:32:06 -0700 Subject: [PATCH 03/54] createInvite functionally removed --- lib/index.js | 52 +++++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/lib/index.js b/lib/index.js index 416d29b5..f1a7d5e1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -728,37 +728,11 @@ DCP.acceptInvite = function(NUL, callback) { }; /** - * Generate an invite URL for a channel. - * @arg {Object} input - * @arg {Snowflake} input.channelID - * @arg {Number} [input.max_age] - Time in seconds. - * @arg {Number} [input.max_users] - The amount of times the invite code can be used. - * @arg {Boolean} [input.temporary] - Any users who use this invite will be removed when they disconnect, unless given a role. + * (Used to) Generate an invite URL for a channel. + * @deprecated */ -DCP.createInvite = function(input, callback) { - var payload, client = this; - - payload = { - max_age: 0, - max_users: 0, - temporary: false - }; - - if ( Object.keys(input).length === 1 && input.channelID ) { - payload = { - validate: client.internals.lastInviteCode || null - }; - } - - for (var key in input) { - if (Object.keys(payload).indexOf(key) < 0) continue; - payload[key] = input[key]; - } - - this._req('post', Endpoints.CHANNEL(input.channelID) + "/invites", payload, function(err, res) { - try {client.internals.lastInviteCode = res.body.code;} catch(e) {} - handleResCB('Unable to create invite', err, res, callback); - }); +DCP.createInvite = function(NUL, callback) { + return handleErrCB("createInvite can no longer be used", callback); }; /** @@ -894,12 +868,12 @@ DCP.editChannelInfo = function(input, callback) { /** * Edit (or creates) a permission override for a channel. * @arg {Object} input - * @arg {Snowflake} channelID - * @arg {Snowflake} [userID] - * @arg {Snowflake} [roleID] - * @arg {Array} allow - An array of permissions to allow. Discord.Permissions.XXXXXX. - * @arg {Array} deny - An array of permissions to deny, same as above. - * @arg {Array} default - An array of permissions that cancels out allowed and denied permissions. + * @arg {Snowflake} input.channelID + * @arg {Snowflake} [input.userID] + * @arg {Snowflake} [input.roleID] + * @arg {Array} input.allow - An array of permissions to allow. Discord.Permissions.XXXXXX. + * @arg {Array} input.deny - An array of permissions to deny, same as above. + * @arg {Array} input.default - An array of permissions that cancels out allowed and denied permissions. */ DCP.editChannelPermissions = function(input, callback) { //Will shrink this up later var payload, pType, ID, channel, permissions, allowed_values; @@ -959,9 +933,9 @@ DCP.editChannelPermissions = function(input, callback) { //Will shrink this up l /** * Delete a permission override for a channel. * @arg {Object} input - * @arg {Snowflake} channelID - * @arg {Snowflake} [userID] - * @arg {Snowflake} [roleID] + * @arg {Snowflake} input.channelID + * @arg {Snowflake} [input.userID] + * @arg {Snowflake} [input.roleID] */ DCP.deleteChannelPermission = function(input, callback) { var payload, pType, ID; From b4cd8ca2212b9fc98414850b7141318ec2ec55aa Mon Sep 17 00:00:00 2001 From: izy521 Date: Sun, 26 Mar 2017 00:21:18 -0700 Subject: [PATCH 04/54] gitignore update --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8b137891..360ea127 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ - +.vs From fdc7e2940dc1d1248a09610154fec0fd3ea19eae Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 26 Mar 2017 11:48:18 +0300 Subject: [PATCH 05/54] Update index.d.ts Updated the type `uploadFileOpts` to allow `file` to be of type `Buffer` --- typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 5f1b000e..305edfe6 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -128,7 +128,7 @@ declare type sendMessageOpts = { declare type uploadFileOpts = { to: string, - file: string, + file: string|Buffer, filename?: string, message?: string } From 88721e7d8f6777e7eee8d93b954e80624b1f7144 Mon Sep 17 00:00:00 2001 From: izy521 Date: Sun, 2 Apr 2017 17:57:50 -0700 Subject: [PATCH 06/54] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f81be44c..c76d8f14 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@

discord.io

+ A small, single-file, fully featured [Discordapp](https://discordapp.com) library for Node.js and browsers. [![Discord](https://discordapp.com/api/guilds/66192955777486848/widget.png)](https://discord.gg/0MvHMfHcTKVVmIGP) [![NPM](https://img.shields.io/npm/v/discord.io.svg)](https://img.shields.io/npm/v/gh-badges.svg) From 0aff9e2c40f5357d84b1e69e03b5271d66764bc5 Mon Sep 17 00:00:00 2001 From: izy521 Date: Tue, 11 Apr 2017 20:21:37 -0700 Subject: [PATCH 07/54] fix JSDoc argument type --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index f1a7d5e1..0d3a7ada 100644 --- a/lib/index.js +++ b/lib/index.js @@ -285,7 +285,7 @@ DCP.getMessages = function(input, callback) { * @arg {Object} input * @arg {Snowflake} input.channelID * @arg {Snowflake} input.messageID - * @arg {Snowflake} input.message - The new message content + * @arg {String} input.message - The new message content * @arg {Object} [input.embed] - The new Discord Embed object */ DCP.editMessage = function(input, callback) { From cf819533c61cd67ad2092bf80af409c326e4489a Mon Sep 17 00:00:00 2001 From: izy521 Date: Tue, 11 Apr 2017 20:53:25 -0700 Subject: [PATCH 08/54] Small changes to uploadFile --- lib/index.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/index.js b/lib/index.js index 0d3a7ada..9fe4982d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -180,13 +180,20 @@ DCP.getAccountSettings = function(callback) { DCP.uploadFile = function(input, callback) { /* After like 15 minutes of fighting with Request, turns out Discord doesn't allow multiple files in one message... despite having an attachments array.*/ - var file, - client = this, multi = new Multipart(), message = generateMessage(input.message || ""), - isBuffer = (input.file instanceof Buffer), isString = (type(input.file) === 'string'); - - if (!isBuffer && !isString) return handleErrCB("[uploadFile] uploadFile requires a String or Buffer as the 'file' value", callback); - if (isBuffer) if (input.filename) file = input.file; else return handleErrCB("[uploadFile] uploadFile requires a 'filename' value to be set if using a Buffer", callback); - if (isString) try { file = FS.readFileSync(input.file); } catch(e) { return handleErrCB("[uploadFile] File does not exist: " + input.file, callback); } + var file, client, multi, message, isBuffer, isString; + + client = this; + multi = new Multipart(); + message = generateMessage(input.message || ""); + isBuffer = (input.file instanceof Buffer); + isString = (type(input.file) === 'string'); + + if (!isBuffer && !isString) return handleErrCB("uploadFile requires a String or Buffer as the 'file' value", callback); + if (isBuffer) { + if (!input.filename) return handleErrCB("uploadFile requires a 'filename' value to be set if using a Buffer", callback); + file = input.filename; + } + if (isString) try { file = FS.readFileSync(input.file); } catch(e) { return handleErrCB("File does not exist: " + input.file, callback); } [ ["content", message.content], @@ -1372,7 +1379,7 @@ function APIRequest(method, url) { }; if (type(data) === 'object' || method.toLowerCase() === 'get') req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); if (data instanceof Multipart) req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary); - if (data) return req[ (data.result ? "sendAsBinary" : "send") ]( data.result ? data.result : JSON.stringify(data) ); + if (data) return req.send( data.result ? data.result : JSON.stringify(data) ); req.send(null); } function send(ws, data) { From 180e6192751759fa7bfc785d4b20fa5b60b33f7b Mon Sep 17 00:00:00 2001 From: izy521 Date: Thu, 13 Apr 2017 00:20:15 -0700 Subject: [PATCH 09/54] Logs added, started on connect and disconnect --- lib/index.js | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/index.js b/lib/index.js index 9fe4982d..2b255cd0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -73,21 +73,20 @@ var DCP = Discord.Client.prototype; /** * Manually initiate the WebSocket connection to Discord. */ -DCP.connect = function() { - if (!this.connected && !this._connecting) return setTimeout( - init, - Math.max(0, CONNECT_WHEN - Date.now()), - this, - arguments[0], - void( CONNECT_WHEN = Math.max(CONNECT_WHEN, Date.now()) + 6000 ) - ); +DCP.connect = function () { + var opts = arguments[0]; + if (!this.connected && !this._connecting) return setTimeout(function() { + init(this, opts); + CONNECT_WHEN = Math.max(CONNECT_WHEN, Date.now()) + 6000; + }.bind(this), Math.max( 0, CONNECT_WHEN - Date.now() )); }; /** * Disconnect the WebSocket connection to Discord. */ -DCP.disconnect = function() { - if (this._ws) this._ws.close(); +DCP.disconnect = function () { + if (this._ws) return this._ws.close() && log(this, "Manual disconnect called, websocket closed"); + return log(this, Discord.LogLevels.Warn, "Manual disconnect called with no WebSocket active, ignored"); }; /** @@ -1466,6 +1465,17 @@ function colorFromRole(server, member) { return role.position > array[0] && role.color ? [role.position, role.color] : array; }, [-1, null])[1]; } +function log(client, level_message) { + var level, message; + if (arguments.length === 2) { + level = Discord.LogLevels.Info; + message = level_message; + } else { + level = level_message; + message = arguments[2]; + } + return client.emit('log', level, message); +} function givePermission(bit, permissions) { return permissions | (1 << bit); @@ -2582,6 +2592,12 @@ Discord.Permissions = { VOICE_MOVE_MEMBERS: 24, VOICE_USE_VAD: 25, }; +Discord.LogLevels = { + Verbose: 0, + Info: 1, + Warn: 2, + Error: 3 +}; Object.keys(Discord.Permissions).forEach(function(pn) { Object.defineProperty(Role.prototype, pn, { From fa9f8b20f2f752aca6dbe5ab054799e609fc3fe5 Mon Sep 17 00:00:00 2001 From: izy521 Date: Wed, 12 Apr 2017 15:00:28 -0700 Subject: [PATCH 10/54] Small fix --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 2b255cd0..f32be5e7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -85,7 +85,7 @@ DCP.connect = function () { * Disconnect the WebSocket connection to Discord. */ DCP.disconnect = function () { - if (this._ws) return this._ws.close() && log(this, "Manual disconnect called, websocket closed"); + if (this._ws) return this._ws.close(), log(this, "Manual disconnect called, websocket closed"); return log(this, Discord.LogLevels.Warn, "Manual disconnect called with no WebSocket active, ignored"); }; From fbf32cdae6bdac373e69008594842102ce633839 Mon Sep 17 00:00:00 2001 From: izy521 Date: Thu, 13 Apr 2017 11:21:50 -0700 Subject: [PATCH 11/54] Fix lib crashing attempting to close when no heartbeat received --- lib/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index f32be5e7..bbd02074 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1636,7 +1636,9 @@ function handleWSMessage(data, flags) { client.connected = true; client._mainKeepAlive = setInterval(function() { - client.internals.heartbeat = setTimeout(client._ws.close.bind(client._ws, 1e3, 'No heartbeat received'), 15e3); + client.internals.heartbeat = setTimeout(function() { + client._ws && client._ws.close(1e3, 'No heartbeat received'); + }, 15e3); client.internals._lastHB = Date.now(); send(client._ws, Payloads.HEARTBEAT(client)); }, _data.heartbeat_interval); From 55f2efe5b46777de193a7182d70e4dd9aab7b021 Mon Sep 17 00:00:00 2001 From: Jacob Gunther Date: Thu, 18 May 2017 18:37:42 -0500 Subject: [PATCH 12/54] Un-did spacing --- lib/index.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index bbd02074..f46b25dc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -738,7 +738,29 @@ DCP.acceptInvite = function(NUL, callback) { * @deprecated */ DCP.createInvite = function(NUL, callback) { - return handleErrCB("createInvite can no longer be used", callback); + var payload, client = this; + + payload = { + max_age: 0, + max_users: 0, + temporary: false + }; + + if ( Object.keys(input).length === 1 && input.channelID ) { + payload = { + validate: client.internals.lastInviteCode || null + }; + } + + for (var key in input) { + if (Object.keys(payload).indexOf(key) < 0) continue; + payload[key] = input[key]; + } + + this._req('post', Endpoints.CHANNEL(input.channelID) + "/invites", payload, function(err, res) { + try {client.internals.lastInviteCode = res.body.code;} catch(e) {} + handleResCB('Unable to create invite', err, res, callback); + }); }; /** From e1458c124fe5f93b442466f3d08c1c2157dc1052 Mon Sep 17 00:00:00 2001 From: nickoplier Date: Tue, 6 Jun 2017 12:06:43 -0600 Subject: [PATCH 13/54] Update for reason support on bans. used optimized version from last pull request from izy --- lib/index.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/index.js b/lib/index.js index f46b25dc..af13427f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -464,19 +464,27 @@ DCP.kick = function(input, callback) { * @arg {Object} input * @arg {Snowflake} input.serverID * @arg {Snowflake} input.userID + * @arg {String} input.reason * @arg {Number} [input.lastDays] - Removes their messages up until this point, either 1 or 7 days. */ DCP.ban = function(input, callback) { - if (input.lastDays) { - input.lastDays = Number(input.lastDays); - input.lastDays = Math.min(input.lastDays, 7); - input.lastDays = Math.max(input.lastDays, 1); + var url = Endpoints.Bans(input.serverID, input.userID); + var opts = {}; + + if (input.lastDays) { + opts.lastDays = Number(input.lastDays); + opts.lastDays = Math.min(opts.lastDays, 7); + opts.lastDays = Math.max(opts.lastDays, 1); } - this._req('put', Endpoints.BANS(input.serverID, input.userID) + (input.lastDays ? "?delete-message-days=" + input.lastDays : ""), function(err, res) { - handleResCB("Could not ban user", err, res, callback); - }); -}; + if (input.reason) opts.reason = input.reason; + + url += qstringify(opts); + + this._req('put', url, function(err, res) { + handleResCB("Could not ban user", err, res, callback); + }); +} /** * Unban a user from a server. From 0e0e41323b38e38acee41bd3b5ef51e7c24c478a Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Thu, 6 Jul 2017 19:24:04 -0400 Subject: [PATCH 14/54] Fixed the typo on line 1988 https://github.com/izy521/discord.io/issues/174 --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index af13427f..f770d38a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1985,7 +1985,7 @@ function getVoiceSession(client, channelID, server) { function checkVoiceReady(voiceSession, callback) { return setTimeout(function() { - if (voiceSession.error) return call(callback, [error]); + if (voiceSession.error) return call(callback, [voiceSession.error]); if (voiceSession.joined) return call(callback, [null, voiceSession.emitter]); return checkVoiceReady(voiceSession, callback); }, 1); From a938d60429f663570ccb8428c87446dff5d7ab39 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Sat, 8 Jul 2017 00:42:44 -0400 Subject: [PATCH 15/54] Update index.js --- lib/index.js | 108 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/lib/index.js b/lib/index.js index f770d38a..02d6e364 100644 --- a/lib/index.js +++ b/lib/index.js @@ -536,7 +536,7 @@ DCP.unmute = function(input, callback) { }; /** - * Server-deafan a user. + * Server-deafen a user. * @arg {Object} input * @arg {Snowflake} input.serverID * @arg {Snowflake} input.userID @@ -548,7 +548,7 @@ DCP.deafen = function(input, callback) { }; /** - * Remove the server-deafan from a user. + * Remove the server-deafen from a user. * @arg {Object} input * @arg {Snowflake} input.serverID * @arg {Snowflake} input.userID @@ -559,6 +559,82 @@ DCP.undeafen = function(input, callback) { }); }; +/** + * Self-mute the client from speaking in all voice channels. + * @arg {Snowflake} serverID + */ +DCP.muteSelf = function(serverID, callback) { + var server = this.servers[serverID], channelID, voiceSession; + if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); + + server.self_mute = true; + + if (!server.voiceSession) return call(callback, [null, true]); + + voiceSession = server.voiceSession; + voiceSession.self_mute = true; + channelID = voiceSession.channelID; + if (!channelID) return call(callback, [null, true]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, true, server.self_deaf)), true]); +}; + +/** + * Remove the self-mute from the client. + * @arg {Snowflake} serverID + */ +DCP.unmuteSelf = function(serverID, callback) { + var server = this.servers[serverID], channelID, voiceSession; + if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); + + server.self_mute = false; + + if (!server.voiceSession) return call(callback, [null, true]); + + voiceSession = server.voiceSession; + voiceSession.self_mute = false; + channelID = voiceSession.channelID; + if (!channelID) return call(callback, [null, true]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, false, server.self_deaf)), true]); +}; + +/** + * Self-deafen the client. + * @arg {Snowflake} serverID + */ +DCP.deafenSelf = function(serverID, callback) { + var server = this.servers[serverID], channelID, voiceSession; + if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); + + server.self_deaf = true; + + if (!server.voiceSession) return call(callback, [null, true]); + + voiceSession = server.voiceSession; + voiceSession.self_deaf = true; + channelID = voiceSession.channelID; + if (!channelID) return call(callback, [null, true]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, true)), true]); +}; + +/** + * Remove the self-deafen from the client. + * @arg {Snowflake} serverID + */ +DCP.undeafenSelf = function(serverID, callback) { + var server = this.servers[serverID], channelID, voiceSession; + if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); + + server.self_deaf = false; + + if (!server.voiceSession) return call(callback, [null, true]); + + voiceSession = server.voiceSession; + voiceSession.self_deaf = false; + channelID = voiceSession.channelID; + if (!channelID) return call(callback, [null, true]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, false)), true]); +}; + /*Bot server management actions*/ /** @@ -1229,8 +1305,10 @@ DCP.joinVoiceChannel = function(channelID, callback) { if (this._vChannels[channelID]) return handleErrCB(("Voice channel already active: " + channelID), callback); voiceSession = getVoiceSession(this, channelID, server); + voiceSession.self_mute = server.self_mute; + voiceSession.self_deaf = server.self_deaf; checkVoiceReady(voiceSession, callback); - return send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID)); + return send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, server.self_deaf)); }; /** @@ -1652,7 +1730,8 @@ function handleWSMessage(data, flags) { var message = decompressWSMessage(data, flags); var _data = message.d; var client = this, user, server, member, old, - userID, serverID, channelID, currentVCID; + userID, serverID, channelID, currentVCID, + self_mute, self_deaf; client.internals.sequence = message.s; switch (message.op) { @@ -1819,6 +1898,8 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; + self_mute = server.self_mute = !!_data.self_mute; + self_deaf = server.self_deaf = !!_data.self_deaf; try { currentVCID = server.members[userID].voice_channel_id; @@ -1841,6 +1922,8 @@ function handleWSMessage(data, flags) { } server.voiceSession.session = _data.session_id; + server.voiceSession.self_mute = self_mute; + server.voiceSession.self_deaf = self_deaf; } break; case "VOICE_SERVER_UPDATE": @@ -1952,7 +2035,7 @@ function leaveVoiceChannel(client, channelID, callback) { client._vChannels[channelID].udp.connection.close(); } catch(e) {} - send(client._ws, Payloads.UPDATE_VOICE(client.channels[channelID].guild_id, null)); + send(client._ws, Payloads.UPDATE_VOICE(client.channels[channelID].guild_id, null, false, false)); return call(callback, [null]); } @@ -1979,7 +2062,9 @@ function getVoiceSession(client, channelID, server) { channelID: channelID, token: null, session: null, - endpoint: null + endpoint: null, + self_mute: false, + self_deaf: false }; } @@ -2256,6 +2341,7 @@ function prepareAudioOld(ACBI, readableStream) { function sendAudio(ACBI, buffer) { ACBI._sequence = (ACBI._sequence + 1 ) < 0xFFFF ? ACBI._sequence + 1 : 0; ACBI._timestamp = (ACBI._timestamp + 960) < 0xFFFFFFFF ? ACBI._timestamp + 960 : 0; + if (ACBI._voiceSession.self_mute) return; var audioPacket = AudioCB.VoicePacket(buffer, ACBI._voiceSession.ws.ssrc, ACBI._sequence, ACBI._timestamp, ACBI._secretKey); try { @@ -2266,7 +2352,7 @@ function sendAudio(ACBI, buffer) { function handleIncomingAudio(msg) { //The response from the UDP keep alive ping - if (msg.length === 8) return; + if (msg.length === 8 || this._voiceSession.self_deaf) return; var header = msg.slice(0, 12), audio = msg.slice(12), @@ -2373,6 +2459,8 @@ function Server(client, data) { copyKeys(data, this); this.large = this.large || this.member_count > LARGE_THRESHOLD; this.voiceSession = null; + this.self_mute = !!this.self_mute; + this.self_deaf = !!this.self_deaf; if (data.unavailable) return; //Objects so we can use direct property accessing without for loops @@ -2836,14 +2924,14 @@ function Websocket(url, opts) { } }; }, - UPDATE_VOICE: function(serverID, channelID) { + UPDATE_VOICE: function(serverID, channelID, self_mute, self_deaf) { return { op: 4, d: { guild_id: serverID, channel_id: channelID, - self_mute: false, - self_deaf: false + self_mute: self_mute, + self_deaf: self_deaf } }; }, From eeccdfc443e83257c7015b15dcc49ad491960cd3 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Sat, 8 Jul 2017 01:08:19 -0400 Subject: [PATCH 16/54] Fixed a bug related to my PR https://github.com/izy521/discord.io/pull/177 I tried to take a shortcut and of course it failed... so I fixed the issue, everything *should* be working now! --- lib/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 02d6e364..c0747248 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1898,8 +1898,8 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; - self_mute = server.self_mute = !!_data.self_mute; - self_deaf = server.self_deaf = !!_data.self_deaf; + self_mute = !!_data.self_mute; + self_deaf = !!_data.self_deaf; try { currentVCID = server.members[userID].voice_channel_id; @@ -1909,6 +1909,8 @@ function handleWSMessage(data, flags) { } catch(e) {} if (userID === client.id) { + server.self_mute = self_mute; + server.self_deaf = self_deaf; if (channelID === null) { if (server.voiceSession) leaveVoiceChannel(client, server.voiceSession.channelID); return void(server.voiceSession = null); From 35c5f2e8c988aae36eebe9424db6adf9313bf848 Mon Sep 17 00:00:00 2001 From: izy521 Date: Mon, 17 Jul 2017 12:15:15 -0700 Subject: [PATCH 17/54] Update index.js --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index f770d38a..cbd7c1c0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -468,7 +468,7 @@ DCP.kick = function(input, callback) { * @arg {Number} [input.lastDays] - Removes their messages up until this point, either 1 or 7 days. */ DCP.ban = function(input, callback) { - var url = Endpoints.Bans(input.serverID, input.userID); + var url = Endpoints.BANS(input.serverID, input.userID); var opts = {}; if (input.lastDays) { From 8d3e91702e8c43bc05ef619ee5bbe876df7c7355 Mon Sep 17 00:00:00 2001 From: Ronin Date: Wed, 16 Aug 2017 16:13:46 -0400 Subject: [PATCH 18/54] Fixed status update Apparently after today, updating the status requires a type. I set the default to be zero. --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index cbd7c1c0..0a3786f5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2829,7 +2829,7 @@ function Websocket(url, opts) { game: type(input.game) === 'object' ? { name: input.game.name ? String(input.game.name) : null, - type: input.game.type ? Number(input.game.type) : null, + type: input.game.type ? Number(input.game.type) : 0, url: input.game.url ? String(input.game.url) : null } : null From 2f3d96f1194f47c3e3b6038d5d29fa6dccc6d971 Mon Sep 17 00:00:00 2001 From: Ronin Date: Sat, 19 Aug 2017 19:05:16 -0400 Subject: [PATCH 19/54] Update mute/deafen update on member object of guild. It seems that member.mute/member.deaf didn't update when the VOICE_STATE_UPDATE event fired. --- lib/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/index.js b/lib/index.js index 0a3786f5..e91979ee 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1819,11 +1819,17 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; + let mute = _data.mute; + let selfMute = _data.self_mute; + let deaf = _data.deaf; + let selfDeaf = _data.self_deaf; try { currentVCID = server.members[userID].voice_channel_id; if (currentVCID) delete( server.channels[currentVCID].members[userID] ); if (channelID) server.channels[channelID].members[userID] = _data; + mute || selfMute ? server.members[userID].mute = true : server.members[userID].mute = false; + deaf || selfDeaf ? server.members[userID].deaf = true : server.members[userID].deaf = false; server.members[userID].voice_channel_id = channelID; } catch(e) {} From caf86a09e8d2e6bab9fe6d47b558d01716a385f5 Mon Sep 17 00:00:00 2001 From: Ronin Date: Sat, 19 Aug 2017 22:12:00 -0400 Subject: [PATCH 20/54] Change variables to var --- lib/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index e91979ee..1cba4769 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1819,10 +1819,10 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; - let mute = _data.mute; - let selfMute = _data.self_mute; - let deaf = _data.deaf; - let selfDeaf = _data.self_deaf; + var mute = _data.mute; + var selfMute = _data.self_mute; + var deaf = _data.deaf; + var selfDeaf = _data.self_deaf; try { currentVCID = server.members[userID].voice_channel_id; From 2163e8b1685a6493114c6a317940f594dcb0bc23 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 21 Aug 2017 22:38:53 -0700 Subject: [PATCH 21/54] Version 2.5.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2ff8452..150ffb74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.io", - "version": "2.5.1", + "version": "2.5.2", "description": "JavaScript interface for Discord.", "main": "./lib/index.js", "typings": "./typings/index.d.ts", From ac116cf7972182cbcf68cf5d8014b35a1551f1bd Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 30 Aug 2017 03:53:10 -0400 Subject: [PATCH 22/54] More status possibilities for client use. --- lib/index.js | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/index.js b/lib/index.js index 0a3786f5..1e65d04d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -134,18 +134,19 @@ DCP.editUserInfo = function(input, callback) { /** * Change the client's presence. * @arg {Object} input - * @arg {Number|null} input.idle_since - Use a Number before the current point in time. + * @arg {String|null} input.status - Used to set the status. online, idle, dnd, invisible, and offline are the possible states. + * @arg {Boolean|null} input.afk - Optional, changes how Discord handles push notifications. * @arg {Object|null} input.game - Used to set game information. * @arg {String|null} input.game.name - The name of the game. - * @arg {Number|null} input.game.type - Streaming activity, 0 for nothing, 1 for Twitch. + * @arg {Number|null} input.game.type - Activity type, 0 for game, 1 for Twitch. * @arg {String|null} input.game.url - A URL matching the streaming service you've selected. */ DCP.setPresence = function(input) { - var payload = Payloads.STATUS(input); - send(this._ws, payload); + var payload = Payloads.STATUS(input); + send(this._ws, payload); - if (payload.d.idle_since === null) return void(this.presenceStatus = 'online'); - this.presenceStatus = 'idle'; + if (payload.d.since === null) return void(this.presenceStatus = input.status); + this.presenceStatus = input.status; }; /** @@ -1408,7 +1409,7 @@ function APIRequest(method, url) { }; if (type(data) === 'object' || method.toLowerCase() === 'get') req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); if (data instanceof Multipart) req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary); - if (data) return req.send( data.result ? data.result : JSON.stringify(data) ); + if (data) return req.send( data.result ? data.result : JSON.stringify(data) ); req.send(null); } function send(ws, data) { @@ -2087,7 +2088,7 @@ function AudioCB(voiceSession, audioChannels, encoder, maxStreamSize) { ["_secretKey", new Uint8Array(voiceSession.secretKey)], ["_mixedDecoder", Opus && new Opus.OpusEncoder( 48000, audioChannels ) || null] ]); - + createAudioEncoder(this, encoder); this._write = function _write(chunk, encoding, callback) { @@ -2544,7 +2545,7 @@ Object.defineProperty(Role.prototype, "permission_values", { enumerable: true }); Object.defineProperty(User.prototype, 'avatarURL', { - get: function() { + get: function() { if (!this.avatar) return null; var animated = this.avatar.indexOf("a_") > -1; return Discord.Endpoints.CDN + "/avatars/" + this.id + "/" + this.avatar + (animated ? ".gif" : ".webp"); @@ -2821,21 +2822,23 @@ function Websocket(url, opts) { ALL_USERS: function(client) { return {op: 12, d: Object.keys(client.servers)}; }, - STATUS: function(input) { - return { - op: 3, - d: { - idle_since: input.idle_since || null, - game: type(input.game) === 'object' ? - { - name: input.game.name ? String(input.game.name) : null, - type: input.game.type ? Number(input.game.type) : 0, - url: input.game.url ? String(input.game.url) : null - } : - null - } - }; - }, + STATUS: function(input) { + return { + op: 3, + d: { + status: input.status, + afk: input.afk !== null ? input.afk : false, + since: input.status.toLowerCase === 'idle' ? Date.now() : null, + game: type(input.game) === 'object' ? + { + name: input.game.name ? String(input.game.name) : null, + type: input.game.type ? Number(input.game.type) : 0, + url: input.game.url ? String(input.game.url) : null + } : + null + } + }; + }, UPDATE_VOICE: function(serverID, channelID) { return { op: 4, From 15da0479e613d2d7cb1de25b0b9a16af7ec9c0ac Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 30 Aug 2017 05:13:21 -0400 Subject: [PATCH 23/54] Make this change non-breaking by allowing status or idle_since --- lib/index.js | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/index.js b/lib/index.js index 1e65d04d..af03a299 100644 --- a/lib/index.js +++ b/lib/index.js @@ -135,6 +135,7 @@ DCP.editUserInfo = function(input, callback) { * Change the client's presence. * @arg {Object} input * @arg {String|null} input.status - Used to set the status. online, idle, dnd, invisible, and offline are the possible states. + * @arg {Number|null} input.idle_since - Optional, use a Number before the current point in time. * @arg {Boolean|null} input.afk - Optional, changes how Discord handles push notifications. * @arg {Object|null} input.game - Used to set game information. * @arg {String|null} input.game.name - The name of the game. @@ -142,11 +143,11 @@ DCP.editUserInfo = function(input, callback) { * @arg {String|null} input.game.url - A URL matching the streaming service you've selected. */ DCP.setPresence = function(input) { - var payload = Payloads.STATUS(input); - send(this._ws, payload); + var payload = Payloads.STATUS(input); + send(this._ws, payload); - if (payload.d.since === null) return void(this.presenceStatus = input.status); - this.presenceStatus = input.status; + if (payload.d.idle_since === null) return void(this.presenceStatus = payload.d.status); + this.presenceStatus = payload.d.status; }; /** @@ -2822,21 +2823,21 @@ function Websocket(url, opts) { ALL_USERS: function(client) { return {op: 12, d: Object.keys(client.servers)}; }, - STATUS: function(input) { - return { - op: 3, - d: { - status: input.status, - afk: input.afk !== null ? input.afk : false, - since: input.status.toLowerCase === 'idle' ? Date.now() : null, - game: type(input.game) === 'object' ? - { - name: input.game.name ? String(input.game.name) : null, - type: input.game.type ? Number(input.game.type) : 0, - url: input.game.url ? String(input.game.url) : null - } : - null - } + STATUS: function(input) { + return { + op: 3, + d: { + status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, + afk: input.afk !== null ? input.afk : false, + since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, + game: type(input.game) === 'object' ? + { + name: input.game.name ? String(input.game.name) : null, + type: input.game.type ? Number(input.game.type) : 0, + url: input.game.url ? String(input.game.url) : null + } : + null + } }; }, UPDATE_VOICE: function(serverID, channelID) { From 4e0241509f5a29d0d7af82c52eb4a070f8829023 Mon Sep 17 00:00:00 2001 From: izy521 Date: Mon, 4 Sep 2017 12:07:56 -0700 Subject: [PATCH 24/54] Enable `createInvite` again --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index af03a299..b6e2041b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -747,7 +747,7 @@ DCP.acceptInvite = function(NUL, callback) { * (Used to) Generate an invite URL for a channel. * @deprecated */ -DCP.createInvite = function(NUL, callback) { +DCP.createInvite = function(input, callback) { var payload, client = this; payload = { From ef2d1f296a4a74d5e86badecb882362bf7e75430 Mon Sep 17 00:00:00 2001 From: izy521 Date: Thu, 14 Sep 2017 23:00:36 -0700 Subject: [PATCH 25/54] Fix set status crash --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 67505120..9f4d6c93 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2834,7 +2834,7 @@ function Websocket(url, opts) { op: 3, d: { status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, - afk: input.afk !== null ? input.afk : false, + afk: !!input.afk, since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, game: type(input.game) === 'object' ? { From b2023c2801c8935984cda2f08110bcd7ffcf3b32 Mon Sep 17 00:00:00 2001 From: Isaac Banner Date: Tue, 19 Sep 2017 12:09:02 -0700 Subject: [PATCH 26/54] Fix bug in uploadFile when Buffer is passed. Setting file to input.filename just results in the bot sending the filename as the contents of the file, rather than sending the contents of the buffer. Should be input.file, in which case the buffer data is actually sent. --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 9f4d6c93..c6203717 100644 --- a/lib/index.js +++ b/lib/index.js @@ -192,7 +192,7 @@ DCP.uploadFile = function(input, callback) { if (!isBuffer && !isString) return handleErrCB("uploadFile requires a String or Buffer as the 'file' value", callback); if (isBuffer) { if (!input.filename) return handleErrCB("uploadFile requires a 'filename' value to be set if using a Buffer", callback); - file = input.filename; + file = input.file; } if (isString) try { file = FS.readFileSync(input.file); } catch(e) { return handleErrCB("File does not exist: " + input.file, callback); } From 7f425bf551ca4e5f9303bf4d95ceade851133a5b Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Wed, 20 Sep 2017 18:44:54 -0400 Subject: [PATCH 27/54] Fixed indents & improved member.mute/deaf logic --- lib/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index e5320983..5eb6e153 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1900,7 +1900,7 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; - mute = !!_data.mute; + mute = !!_data.mute; self_mute = !!_data.self_mute; deaf = !!_data.deaf; self_deaf = !!_data.self_deaf; @@ -1909,8 +1909,8 @@ function handleWSMessage(data, flags) { currentVCID = server.members[userID].voice_channel_id; if (currentVCID) delete( server.channels[currentVCID].members[userID] ); if (channelID) server.channels[channelID].members[userID] = _data; - mute || self_mute ? server.members[userID].mute = true : server.members[userID].mute = false; - deaf || self_deaf ? server.members[userID].deaf = true : server.members[userID].deaf = false; + server.members[userID].mute = (mute || self_mute); + server.members[userID].deaf = (deaf || self_deaf); server.members[userID].voice_channel_id = channelID; } catch(e) {} From 783be8ae4271087eac91e7e4c173159e09ece95b Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Wed, 20 Sep 2017 18:48:06 -0400 Subject: [PATCH 28/54] Fixed #172 https://github.com/izy521/discord.io/issues/172 --- lib/index.js | 145 +++++++++++---------------------------------------- 1 file changed, 29 insertions(+), 116 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5eb6e153..db95a111 100644 --- a/lib/index.js +++ b/lib/index.js @@ -538,7 +538,7 @@ DCP.unmute = function(input, callback) { }; /** - * Server-deafen a user. + * Server-deafan a user. * @arg {Object} input * @arg {Snowflake} input.serverID * @arg {Snowflake} input.userID @@ -550,7 +550,7 @@ DCP.deafen = function(input, callback) { }; /** - * Remove the server-deafen from a user. + * Remove the server-deafan from a user. * @arg {Object} input * @arg {Snowflake} input.serverID * @arg {Snowflake} input.userID @@ -561,82 +561,6 @@ DCP.undeafen = function(input, callback) { }); }; -/** - * Self-mute the client from speaking in all voice channels. - * @arg {Snowflake} serverID - */ -DCP.muteSelf = function(serverID, callback) { - var server = this.servers[serverID], channelID, voiceSession; - if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); - - server.self_mute = true; - - if (!server.voiceSession) return call(callback, [null, true]); - - voiceSession = server.voiceSession; - voiceSession.self_mute = true; - channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, true, server.self_deaf)), true]); -}; - -/** - * Remove the self-mute from the client. - * @arg {Snowflake} serverID - */ -DCP.unmuteSelf = function(serverID, callback) { - var server = this.servers[serverID], channelID, voiceSession; - if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); - - server.self_mute = false; - - if (!server.voiceSession) return call(callback, [null, true]); - - voiceSession = server.voiceSession; - voiceSession.self_mute = false; - channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, false, server.self_deaf)), true]); -}; - -/** - * Self-deafen the client. - * @arg {Snowflake} serverID - */ -DCP.deafenSelf = function(serverID, callback) { - var server = this.servers[serverID], channelID, voiceSession; - if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); - - server.self_deaf = true; - - if (!server.voiceSession) return call(callback, [null, true]); - - voiceSession = server.voiceSession; - voiceSession.self_deaf = true; - channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, true)), true]); -}; - -/** - * Remove the self-deafen from the client. - * @arg {Snowflake} serverID - */ -DCP.undeafenSelf = function(serverID, callback) { - var server = this.servers[serverID], channelID, voiceSession; - if (!server) return handleErrCB(("Cannot find the server provided: " + serverID), callback); - - server.self_deaf = false; - - if (!server.voiceSession) return call(callback, [null, true]); - - voiceSession = server.voiceSession; - voiceSession.self_deaf = false; - channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, false)), true]); -}; - /*Bot server management actions*/ /** @@ -1307,10 +1231,8 @@ DCP.joinVoiceChannel = function(channelID, callback) { if (this._vChannels[channelID]) return handleErrCB(("Voice channel already active: " + channelID), callback); voiceSession = getVoiceSession(this, channelID, server); - voiceSession.self_mute = server.self_mute; - voiceSession.self_deaf = server.self_deaf; checkVoiceReady(voiceSession, callback); - return send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, server.self_deaf)); + return send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID)); }; /** @@ -1732,8 +1654,7 @@ function handleWSMessage(data, flags) { var message = decompressWSMessage(data, flags); var _data = message.d; var client = this, user, server, member, old, - userID, serverID, channelID, currentVCID, - mute, deaf, self_mute, self_deaf; + userID, serverID, channelID, currentVCID; client.internals.sequence = message.s; switch (message.op) { @@ -1900,38 +1821,35 @@ function handleWSMessage(data, flags) { channelID = _data.channel_id; userID = _data.user_id; server = client.servers[serverID]; - mute = !!_data.mute; - self_mute = !!_data.self_mute; - deaf = !!_data.deaf; - self_deaf = !!_data.self_deaf; + var mute = _data.mute; + var selfMute = _data.self_mute; + var deaf = _data.deaf; + var selfDeaf = _data.self_deaf; try { currentVCID = server.members[userID].voice_channel_id; if (currentVCID) delete( server.channels[currentVCID].members[userID] ); if (channelID) server.channels[channelID].members[userID] = _data; - server.members[userID].mute = (mute || self_mute); - server.members[userID].deaf = (deaf || self_deaf); + mute || selfMute ? server.members[userID].mute = true : server.members[userID].mute = false; + deaf || selfDeaf ? server.members[userID].deaf = true : server.members[userID].deaf = false; server.members[userID].voice_channel_id = channelID; } catch(e) {} if (userID === client.id) { - server.self_mute = self_mute; - server.self_deaf = self_deaf; if (channelID === null) { if (server.voiceSession) leaveVoiceChannel(client, server.voiceSession.channelID); - return void(server.voiceSession = null); - } - if (!server.voiceSession) { - server.voiceSession = getVoiceSession(client, channelID, server); - } - if (channelID !== server.voiceSession.channelID) { - delete( client._vChannels[server.voiceSession.channelID] ); - getVoiceSession(client, channelID, server).channelID = channelID; - } + server.voiceSession = null; + } else { + if (!server.voiceSession) { + server.voiceSession = getVoiceSession(client, channelID, server); + } + if (channelID !== server.voiceSession.channelID) { + delete( client._vChannels[server.voiceSession.channelID] ); + getVoiceSession(client, channelID, server).channelID = channelID; + } - server.voiceSession.session = _data.session_id; - server.voiceSession.self_mute = self_mute; - server.voiceSession.self_deaf = self_deaf; + server.voiceSession.session = _data.session_id; + } } break; case "VOICE_SERVER_UPDATE": @@ -2043,7 +1961,7 @@ function leaveVoiceChannel(client, channelID, callback) { client._vChannels[channelID].udp.connection.close(); } catch(e) {} - send(client._ws, Payloads.UPDATE_VOICE(client.channels[channelID].guild_id, null, false, false)); + send(client._ws, Payloads.UPDATE_VOICE(client.channels[channelID].guild_id, null)); return call(callback, [null]); } @@ -2070,9 +1988,7 @@ function getVoiceSession(client, channelID, server) { channelID: channelID, token: null, session: null, - endpoint: null, - self_mute: false, - self_deaf: false + endpoint: null }; } @@ -2349,7 +2265,6 @@ function prepareAudioOld(ACBI, readableStream) { function sendAudio(ACBI, buffer) { ACBI._sequence = (ACBI._sequence + 1 ) < 0xFFFF ? ACBI._sequence + 1 : 0; ACBI._timestamp = (ACBI._timestamp + 960) < 0xFFFFFFFF ? ACBI._timestamp + 960 : 0; - if (ACBI._voiceSession.self_mute) return; var audioPacket = AudioCB.VoicePacket(buffer, ACBI._voiceSession.ws.ssrc, ACBI._sequence, ACBI._timestamp, ACBI._secretKey); try { @@ -2360,7 +2275,7 @@ function sendAudio(ACBI, buffer) { function handleIncomingAudio(msg) { //The response from the UDP keep alive ping - if (msg.length === 8 || this._voiceSession.self_deaf) return; + if (msg.length === 8) return; var header = msg.slice(0, 12), audio = msg.slice(12), @@ -2467,8 +2382,6 @@ function Server(client, data) { copyKeys(data, this); this.large = this.large || this.member_count > LARGE_THRESHOLD; this.voiceSession = null; - this.self_mute = !!this.self_mute; - this.self_deaf = !!this.self_deaf; if (data.unavailable) return; //Objects so we can use direct property accessing without for loops @@ -2932,16 +2845,16 @@ function Websocket(url, opts) { } : null } - }; - }, - UPDATE_VOICE: function(serverID, channelID, self_mute, self_deaf) { + }; + }, + UPDATE_VOICE: function(serverID, channelID) { return { op: 4, d: { guild_id: serverID, channel_id: channelID, - self_mute: self_mute, - self_deaf: self_deaf + self_mute: false, + self_deaf: false } }; }, From 56c71273185fc80fd0a12c94eebb5d44862f4172 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Wed, 20 Sep 2017 19:11:57 -0400 Subject: [PATCH 29/54] Combined #177 and #205 Merging #205 cancelled the changes made in #177. This PR combines them into one. --- lib/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 5eb6e153..07876484 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1919,7 +1919,8 @@ function handleWSMessage(data, flags) { server.self_deaf = self_deaf; if (channelID === null) { if (server.voiceSession) leaveVoiceChannel(client, server.voiceSession.channelID); - return void(server.voiceSession = null); + server.voiceSession = null; + break; } if (!server.voiceSession) { server.voiceSession = getVoiceSession(client, channelID, server); From 845cad9e331e8fc9b644412204a203198f849217 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Thu, 21 Sep 2017 11:53:28 -0400 Subject: [PATCH 30/54] Removed the extra "true" arg being passed to CB --- lib/index.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/index.js b/lib/index.js index 3547d4dd..29f3f6e8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -571,13 +571,13 @@ DCP.muteSelf = function(serverID, callback) { server.self_mute = true; - if (!server.voiceSession) return call(callback, [null, true]); + if (!server.voiceSession) return call(callback, [null]); voiceSession = server.voiceSession; voiceSession.self_mute = true; channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, true, server.self_deaf)), true]); + if (!channelID) return call(callback, [null]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, true, server.self_deaf))]); }; /** @@ -590,13 +590,13 @@ DCP.unmuteSelf = function(serverID, callback) { server.self_mute = false; - if (!server.voiceSession) return call(callback, [null, true]); + if (!server.voiceSession) return call(callback, [null]); voiceSession = server.voiceSession; voiceSession.self_mute = false; channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, false, server.self_deaf)), true]); + if (!channelID) return call(callback, [null]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, false, server.self_deaf))]); }; /** @@ -609,13 +609,13 @@ DCP.deafenSelf = function(serverID, callback) { server.self_deaf = true; - if (!server.voiceSession) return call(callback, [null, true]); + if (!server.voiceSession) return call(callback, [null]); voiceSession = server.voiceSession; voiceSession.self_deaf = true; channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, true)), true]); + if (!channelID) return call(callback, [null]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, true))]); }; /** @@ -628,13 +628,13 @@ DCP.undeafenSelf = function(serverID, callback) { server.self_deaf = false; - if (!server.voiceSession) return call(callback, [null, true]); + if (!server.voiceSession) return call(callback, [null]); voiceSession = server.voiceSession; voiceSession.self_deaf = false; channelID = voiceSession.channelID; - if (!channelID) return call(callback, [null, true]); - return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, false)), true]); + if (!channelID) return call(callback, [null]); + return call(callback, [send(this._ws, Payloads.UPDATE_VOICE(serverID, channelID, server.self_mute, false))]); }; /*Bot server management actions*/ @@ -2986,4 +2986,4 @@ function Websocket(url, opts) { } })(); -})(typeof exports === 'undefined'? this.Discord = {} : exports); \ No newline at end of file +})(typeof exports === 'undefined'? this.Discord = {} : exports); From f5b838b5f5c11cd9284b261e3cd00ad67e12417a Mon Sep 17 00:00:00 2001 From: Xhip Date: Fri, 22 Sep 2017 00:54:26 +0100 Subject: [PATCH 31/54] Disconnect after a Invalid Session This will disconnect after a Invalid Session (op9) Thanks: Technidecimal for the reminder on the internals vars. --- lib/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/index.js b/lib/index.js index db95a111..c0760985 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1658,6 +1658,13 @@ function handleWSMessage(data, flags) { client.internals.sequence = message.s; switch (message.op) { + case 9: + //Disconnect after a Invalid Session + //Disconnect the client if the client has received an invalid session id + delete client.internals.sequence; + delete client.internals.sessionID; + client._ws && client._ws.close(1e3, 'Received an invalid session id'); + break; case 10: //Start keep-alive interval //Disconnect the client if no ping has been received From 08ddaf915d5894d8576b4711b2ef2ece7add6b14 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Fri, 22 Sep 2017 07:59:59 -0400 Subject: [PATCH 32/54] Might fix session sometimes becoming invalid maybe --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 412cfe0d..26fe34a7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1734,7 +1734,7 @@ function handleWSMessage(data, flags) { var client = this, user, server, member, old, userID, serverID, channelID, currentVCID, mute, deaf, self_mute, self_deaf; - client.internals.sequence = message.s; + if (message.s) client.internals.sequence = message.s; switch (message.op) { case 9: From dd1cedefaa457a4b0f86798975689c0e31db48eb Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Fri, 22 Sep 2017 09:03:06 -0400 Subject: [PATCH 33/54] Changed message.s check to typeof --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 26fe34a7..7ac6250d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1734,7 +1734,7 @@ function handleWSMessage(data, flags) { var client = this, user, server, member, old, userID, serverID, channelID, currentVCID, mute, deaf, self_mute, self_deaf; - if (message.s) client.internals.sequence = message.s; + if (typeof message.s !== "undefined") client.internals.sequence = message.s; switch (message.op) { case 9: @@ -1746,7 +1746,7 @@ function handleWSMessage(data, flags) { break; case 10: //Start keep-alive interval - //Disconnect the client if no ping has been received +q //Disconnect the client if no ping has been received //in 15 seconds (I think that's a decent duration) //Since v3 you the IDENTIFY/RESUME payload here. identifyOrResume(client); From f32f71397a09a1447987aba6e60ce7d388edbc84 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Fri, 22 Sep 2017 09:05:28 -0400 Subject: [PATCH 34/54] Fixed typo --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 7ac6250d..4b218597 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1746,7 +1746,7 @@ function handleWSMessage(data, flags) { break; case 10: //Start keep-alive interval -q //Disconnect the client if no ping has been received + //Disconnect the client if no ping has been received //in 15 seconds (I think that's a decent duration) //Since v3 you the IDENTIFY/RESUME payload here. identifyOrResume(client); From 990f3417f8bc1360f089f4897e9b4439cbb24d81 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Fri, 22 Sep 2017 09:25:06 -0400 Subject: [PATCH 35/54] typeof message.s === "number" --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 4b218597..7cea1574 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1734,7 +1734,7 @@ function handleWSMessage(data, flags) { var client = this, user, server, member, old, userID, serverID, channelID, currentVCID, mute, deaf, self_mute, self_deaf; - if (typeof message.s !== "undefined") client.internals.sequence = message.s; + if (typeof message.s === "number") client.internals.sequence = message.s; switch (message.op) { case 9: From a0dcdb7b434dc0957784751b3f2a2d4e6dc3a667 Mon Sep 17 00:00:00 2001 From: Joseph Fasulo Date: Fri, 22 Sep 2017 10:42:50 -0400 Subject: [PATCH 36/54] Moved sequence setting to message.op switch case 0 --- lib/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 7cea1574..a712be3e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1734,9 +1734,12 @@ function handleWSMessage(data, flags) { var client = this, user, server, member, old, userID, serverID, channelID, currentVCID, mute, deaf, self_mute, self_deaf; - if (typeof message.s === "number") client.internals.sequence = message.s; switch (message.op) { + case 0: + //Event dispatched - update our sequence number + client.internals.sequence = message.s; + break; case 9: //Disconnect after a Invalid Session //Disconnect the client if the client has received an invalid session id From 875dc8c21c34dac01a9b6c97119e3ffb20de1c21 Mon Sep 17 00:00:00 2001 From: izy521 Date: Mon, 25 Sep 2017 22:41:30 -0700 Subject: [PATCH 37/54] 2.5.3: Fixed uploadFile --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 150ffb74..c1176136 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.io", - "version": "2.5.2", + "version": "2.5.3", "description": "JavaScript interface for Discord.", "main": "./lib/index.js", "typings": "./typings/index.d.ts", From 1dc313425b3496d57ade7eb5d28d41409055eefb Mon Sep 17 00:00:00 2001 From: Gilles May Date: Mon, 2 Oct 2017 02:28:27 +0200 Subject: [PATCH 38/54] Changes to make discord.io compatible with V6 --- lib/index.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/index.js b/lib/index.js index a712be3e..bf6992ae 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ (function discordio(Discord){ var isNode = typeof(window) === "undefined" && typeof(navigator) === "undefined"; var CURRENT_VERSION = "2.x.x", - GATEWAY_VERSION = 5, + GATEWAY_VERSION = 6, LARGE_THRESHOLD = 250, CONNECT_WHEN = null, Endpoints, Payloads; @@ -906,7 +906,6 @@ DCP.createChannel = function(input, callback) { try { var serverID = res.body.guild_id; var channelID = res.body.id; - client.channels[channelID] = new Channel( client, client.servers[serverID], res.body ); } catch(e) {} handleResCB('Unable to create channel', err, res, callback); @@ -1775,11 +1774,11 @@ function handleWSMessage(data, flags) { client.emit('any', message); //TODO: Remove in v3 client.emit('debug', message); + switch (message.t) { case "READY": copyKeys(_data.user, client); client.internals.sessionID = _data.session_id; - getServerInfo(client, _data.guilds); getDirectMessages(client, _data.private_channels); @@ -1879,12 +1878,11 @@ function handleWSMessage(data, flags) { case "CHANNEL_CREATE": channelID = _data.id; - if (_data.is_private) { + if (_data.type == 1) { if (client.directMessages[channelID]) return; client.directMessages[channelID] = new DMChannel(client._uIDToDM, _data); return emit(client, message, client.directMessages[channelID]); } - if (client.channels[channelID]) return; client.channels[channelID] = new Channel(client, client.servers[_data.guild_id], _data); return emit(client, message, client.channels[channelID]); @@ -1893,7 +1891,7 @@ function handleWSMessage(data, flags) { Channel.update(client, _data); return emit(client, message, old, client.channels[_data.id]); case "CHANNEL_DELETE": - if (_data.is_private === true) { + if (_data.type == 1) { emit(client, message, client.directMessages[_data.id]); delete(client.directMessages[_data.id]); return delete(client._uIDToDM[_data.recipient.id]); @@ -2526,26 +2524,28 @@ function Channel(client, server, data) { var channel = this; this.members = {}; this.permissions = { user: {}, role: {} }; + this.guild_id = server.id; + copyKeys(data, this, ['permission_overwrites', 'emojis']); + Object.defineProperty(server.channels, channel.id, { get: function() { return client.channels[channel.id]; }, set: function(v) { client.channels[channel.id] = v; }, enumerable: true, configurable: true }); + data.permission_overwrites.forEach(function(p) { var type = (p.type === 'member' ? 'user' : 'role'); this.permissions[type][p.id] = {allow: p.allow, deny: p.deny}; }, this); - - - delete(this.is_private); } function DMChannel(translator, data) { copyKeys(data, this); - translator[data.recipient.id] = data.id; - delete(this.is_private); + data.recipients.forEach(function(recipient) { + translator[recipient.id] = data.id; + }); } function User(data) { copyKeys(data, this); @@ -2625,7 +2625,6 @@ Channel.update = function(client, data) { } client.channels[data.id][key] = data[key]; } - delete(client.channels[data.id].is_private); }; Member.update = function(client, server, data) { if (!server.members[data.user.id]) return server.members[data.user.id] = new Member(client, server, data); @@ -2932,9 +2931,9 @@ function Websocket(url, opts) { return { op: 3, d: { - status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, + status: type(input.idle) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, afk: !!input.afk, - since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, + since: type(input.idle) === 'number' || input.status === 'idle' ? Date.now() : null, game: type(input.game) === 'object' ? { name: input.game.name ? String(input.game.name) : null, From cb8eb10de9ea507e058eda693831779c976daf33 Mon Sep 17 00:00:00 2001 From: Gilles May Date: Mon, 2 Oct 2017 02:55:42 +0200 Subject: [PATCH 39/54] Revert "Changes to make discord.io compatible with V6" This reverts commit 1dc313425b3496d57ade7eb5d28d41409055eefb. --- lib/index.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/index.js b/lib/index.js index bf6992ae..a712be3e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ (function discordio(Discord){ var isNode = typeof(window) === "undefined" && typeof(navigator) === "undefined"; var CURRENT_VERSION = "2.x.x", - GATEWAY_VERSION = 6, + GATEWAY_VERSION = 5, LARGE_THRESHOLD = 250, CONNECT_WHEN = null, Endpoints, Payloads; @@ -906,6 +906,7 @@ DCP.createChannel = function(input, callback) { try { var serverID = res.body.guild_id; var channelID = res.body.id; + client.channels[channelID] = new Channel( client, client.servers[serverID], res.body ); } catch(e) {} handleResCB('Unable to create channel', err, res, callback); @@ -1774,11 +1775,11 @@ function handleWSMessage(data, flags) { client.emit('any', message); //TODO: Remove in v3 client.emit('debug', message); - switch (message.t) { case "READY": copyKeys(_data.user, client); client.internals.sessionID = _data.session_id; + getServerInfo(client, _data.guilds); getDirectMessages(client, _data.private_channels); @@ -1878,11 +1879,12 @@ function handleWSMessage(data, flags) { case "CHANNEL_CREATE": channelID = _data.id; - if (_data.type == 1) { + if (_data.is_private) { if (client.directMessages[channelID]) return; client.directMessages[channelID] = new DMChannel(client._uIDToDM, _data); return emit(client, message, client.directMessages[channelID]); } + if (client.channels[channelID]) return; client.channels[channelID] = new Channel(client, client.servers[_data.guild_id], _data); return emit(client, message, client.channels[channelID]); @@ -1891,7 +1893,7 @@ function handleWSMessage(data, flags) { Channel.update(client, _data); return emit(client, message, old, client.channels[_data.id]); case "CHANNEL_DELETE": - if (_data.type == 1) { + if (_data.is_private === true) { emit(client, message, client.directMessages[_data.id]); delete(client.directMessages[_data.id]); return delete(client._uIDToDM[_data.recipient.id]); @@ -2524,28 +2526,26 @@ function Channel(client, server, data) { var channel = this; this.members = {}; this.permissions = { user: {}, role: {} }; - this.guild_id = server.id; - copyKeys(data, this, ['permission_overwrites', 'emojis']); - Object.defineProperty(server.channels, channel.id, { get: function() { return client.channels[channel.id]; }, set: function(v) { client.channels[channel.id] = v; }, enumerable: true, configurable: true }); - data.permission_overwrites.forEach(function(p) { var type = (p.type === 'member' ? 'user' : 'role'); this.permissions[type][p.id] = {allow: p.allow, deny: p.deny}; }, this); + + + delete(this.is_private); } function DMChannel(translator, data) { copyKeys(data, this); - data.recipients.forEach(function(recipient) { - translator[recipient.id] = data.id; - }); + translator[data.recipient.id] = data.id; + delete(this.is_private); } function User(data) { copyKeys(data, this); @@ -2625,6 +2625,7 @@ Channel.update = function(client, data) { } client.channels[data.id][key] = data[key]; } + delete(client.channels[data.id].is_private); }; Member.update = function(client, server, data) { if (!server.members[data.user.id]) return server.members[data.user.id] = new Member(client, server, data); @@ -2931,9 +2932,9 @@ function Websocket(url, opts) { return { op: 3, d: { - status: type(input.idle) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, + status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, afk: !!input.afk, - since: type(input.idle) === 'number' || input.status === 'idle' ? Date.now() : null, + since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, game: type(input.game) === 'object' ? { name: input.game.name ? String(input.game.name) : null, From c40ba0ef2aa7f93354018e2bbb220e23ca315b6b Mon Sep 17 00:00:00 2001 From: Gilles May Date: Mon, 2 Oct 2017 03:10:47 +0200 Subject: [PATCH 40/54] Changes to make discord.io compatible with V6 gateway. (2nd try) --- lib/index.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/index.js b/lib/index.js index a712be3e..7d3609b4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ (function discordio(Discord){ var isNode = typeof(window) === "undefined" && typeof(navigator) === "undefined"; var CURRENT_VERSION = "2.x.x", - GATEWAY_VERSION = 5, + GATEWAY_VERSION = 6, LARGE_THRESHOLD = 250, CONNECT_WHEN = null, Endpoints, Payloads; @@ -1879,7 +1879,7 @@ function handleWSMessage(data, flags) { case "CHANNEL_CREATE": channelID = _data.id; - if (_data.is_private) { + if (_data.type == 1) { if (client.directMessages[channelID]) return; client.directMessages[channelID] = new DMChannel(client._uIDToDM, _data); return emit(client, message, client.directMessages[channelID]); @@ -1893,7 +1893,7 @@ function handleWSMessage(data, flags) { Channel.update(client, _data); return emit(client, message, old, client.channels[_data.id]); case "CHANNEL_DELETE": - if (_data.is_private === true) { + if (_data.type == 1) { emit(client, message, client.directMessages[_data.id]); delete(client.directMessages[_data.id]); return delete(client._uIDToDM[_data.recipient.id]); @@ -2538,14 +2538,12 @@ function Channel(client, server, data) { var type = (p.type === 'member' ? 'user' : 'role'); this.permissions[type][p.id] = {allow: p.allow, deny: p.deny}; }, this); - - - delete(this.is_private); } function DMChannel(translator, data) { copyKeys(data, this); - translator[data.recipient.id] = data.id; - delete(this.is_private); + data.recipients.forEach(function(recipient) { + translator[recipient.id] = data.id; + }); } function User(data) { copyKeys(data, this); @@ -2625,7 +2623,6 @@ Channel.update = function(client, data) { } client.channels[data.id][key] = data[key]; } - delete(client.channels[data.id].is_private); }; Member.update = function(client, server, data) { if (!server.members[data.user.id]) return server.members[data.user.id] = new Member(client, server, data); @@ -2932,9 +2929,9 @@ function Websocket(url, opts) { return { op: 3, d: { - status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, + status: type(input.idle) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, afk: !!input.afk, - since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, + since: type(input.idle) === 'number' || input.status === 'idle' ? Date.now() : null, game: type(input.game) === 'object' ? { name: input.game.name ? String(input.game.name) : null, From 1d403d84ce7a492d65af14740920cab0a80ea39c Mon Sep 17 00:00:00 2001 From: Gilles May Date: Mon, 2 Oct 2017 03:20:33 +0200 Subject: [PATCH 41/54] Revert "Changes to make discord.io compatible with V6 gateway. (2nd try)" This reverts commit c40ba0ef2aa7f93354018e2bbb220e23ca315b6b. --- lib/index.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/index.js b/lib/index.js index 7d3609b4..a712be3e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ (function discordio(Discord){ var isNode = typeof(window) === "undefined" && typeof(navigator) === "undefined"; var CURRENT_VERSION = "2.x.x", - GATEWAY_VERSION = 6, + GATEWAY_VERSION = 5, LARGE_THRESHOLD = 250, CONNECT_WHEN = null, Endpoints, Payloads; @@ -1879,7 +1879,7 @@ function handleWSMessage(data, flags) { case "CHANNEL_CREATE": channelID = _data.id; - if (_data.type == 1) { + if (_data.is_private) { if (client.directMessages[channelID]) return; client.directMessages[channelID] = new DMChannel(client._uIDToDM, _data); return emit(client, message, client.directMessages[channelID]); @@ -1893,7 +1893,7 @@ function handleWSMessage(data, flags) { Channel.update(client, _data); return emit(client, message, old, client.channels[_data.id]); case "CHANNEL_DELETE": - if (_data.type == 1) { + if (_data.is_private === true) { emit(client, message, client.directMessages[_data.id]); delete(client.directMessages[_data.id]); return delete(client._uIDToDM[_data.recipient.id]); @@ -2538,12 +2538,14 @@ function Channel(client, server, data) { var type = (p.type === 'member' ? 'user' : 'role'); this.permissions[type][p.id] = {allow: p.allow, deny: p.deny}; }, this); + + + delete(this.is_private); } function DMChannel(translator, data) { copyKeys(data, this); - data.recipients.forEach(function(recipient) { - translator[recipient.id] = data.id; - }); + translator[data.recipient.id] = data.id; + delete(this.is_private); } function User(data) { copyKeys(data, this); @@ -2623,6 +2625,7 @@ Channel.update = function(client, data) { } client.channels[data.id][key] = data[key]; } + delete(client.channels[data.id].is_private); }; Member.update = function(client, server, data) { if (!server.members[data.user.id]) return server.members[data.user.id] = new Member(client, server, data); @@ -2929,9 +2932,9 @@ function Websocket(url, opts) { return { op: 3, d: { - status: type(input.idle) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, + status: type(input.idle_since) === 'number' ? 'idle' : input.status !== undefined ? input.status : null, afk: !!input.afk, - since: type(input.idle) === 'number' || input.status === 'idle' ? Date.now() : null, + since: type(input.idle_since) === 'number' || input.status === 'idle' ? Date.now() : null, game: type(input.game) === 'object' ? { name: input.game.name ? String(input.game.name) : null, From e1dd7fa21a7e7c6ba5aa02ea4c18a38fb4574081 Mon Sep 17 00:00:00 2001 From: Woor <17484890+Woor@users.noreply.github.com> Date: Mon, 2 Oct 2017 03:29:50 +0200 Subject: [PATCH 42/54] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c76d8f14..4c432489 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ A small, single-file, fully featured [Discordapp](https://discordapp.com) librar [![Discord](https://discordapp.com/api/guilds/66192955777486848/widget.png)](https://discord.gg/0MvHMfHcTKVVmIGP) [![NPM](https://img.shields.io/npm/v/discord.io.svg)](https://img.shields.io/npm/v/gh-badges.svg) +**With the end of V5 gateway this is a first step at getting it to work on V6** + ### Requirements **Required**: * **Node.js 0.10.x** or greater From f2591b9a3eda9db1ce1a03e288ba87a13055c9b7 Mon Sep 17 00:00:00 2001 From: Gilles May Date: Mon, 2 Oct 2017 03:32:54 +0200 Subject: [PATCH 43/54] Revert "Update README.md" This reverts commit e1dd7fa21a7e7c6ba5aa02ea4c18a38fb4574081. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 4c432489..c76d8f14 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ A small, single-file, fully featured [Discordapp](https://discordapp.com) librar [![Discord](https://discordapp.com/api/guilds/66192955777486848/widget.png)](https://discord.gg/0MvHMfHcTKVVmIGP) [![NPM](https://img.shields.io/npm/v/discord.io.svg)](https://img.shields.io/npm/v/gh-badges.svg) -**With the end of V5 gateway this is a first step at getting it to work on V6** - ### Requirements **Required**: * **Node.js 0.10.x** or greater From 3d72457a1eacec3bc550350da5d7af6d90f0b988 Mon Sep 17 00:00:00 2001 From: Woor Date: Mon, 2 Oct 2017 03:39:30 +0200 Subject: [PATCH 44/54] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 4c432489..c76d8f14 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ A small, single-file, fully featured [Discordapp](https://discordapp.com) librar [![Discord](https://discordapp.com/api/guilds/66192955777486848/widget.png)](https://discord.gg/0MvHMfHcTKVVmIGP) [![NPM](https://img.shields.io/npm/v/discord.io.svg)](https://img.shields.io/npm/v/gh-badges.svg) -**With the end of V5 gateway this is a first step at getting it to work on V6** - ### Requirements **Required**: * **Node.js 0.10.x** or greater From e7e6ee3f9f3b68b7cbe31dd68521db1c8a88054b Mon Sep 17 00:00:00 2001 From: Woor Date: Fri, 27 Oct 2017 10:22:29 +0200 Subject: [PATCH 45/54] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c76d8f14..5843e698 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ A small, single-file, fully featured [Discordapp](https://discordapp.com) librar [![Discord](https://discordapp.com/api/guilds/66192955777486848/widget.png)](https://discord.gg/0MvHMfHcTKVVmIGP) [![NPM](https://img.shields.io/npm/v/discord.io.svg)](https://img.shields.io/npm/v/gh-badges.svg) +**You are probably here for the gateway_v6 branch. (https://github.com/Woor/discord.io/tree/gateway_v6) ** + ### Requirements **Required**: * **Node.js 0.10.x** or greater From ae17caa04603a7012c44ae9f55c1290389eeb895 Mon Sep 17 00:00:00 2001 From: izy521 Date: Mon, 16 Oct 2017 15:53:23 -0700 Subject: [PATCH 46/54] Merge pull request #214 from HazardDev/master Added embed options --- typings/index.d.ts | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 305edfe6..cef92bc7 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -120,10 +120,36 @@ declare interface permissions { */ declare type sendMessageOpts = { to: string, - message: string, + message?: string, tts?: boolean, nonce?: string, - typing?: boolean + typing?: boolean, + embed?: embedMessageOpts +} + +declare type embedMessageOpts = { + author?: { + icon_url?: string, + name: string, + url?: string + }, + color?: number, + description?: string, + fields?: [{ + name: string, + value?: string, + inline?: boolean + }], + thumbnail?: { + url: string + }, + title: string, + timestamp?: Date + url?: string, + footer?: { + icon_url?: string, + text: string + } } declare type uploadFileOpts = { @@ -325,6 +351,12 @@ declare type getMembersOpts = { after: string } +declare type reactionOpts = { + channelID: string, + messageID: string, + reaction: string +} + /** * CLASSES */ @@ -506,7 +538,7 @@ declare namespace Discord { pinMessage(options: pinMessageOpts, callback?: callbackFunc): void deletePinnedMessage(options: deletePinnedMessageOpts, callback?: callbackFunc): void getPinnedMessages(options: getPinnedMessagesOpts, callback?: callbackFunc): void - + addReaction(options: reactionOpts, callback?: callbackFunc): void /** * VOICE CHANNELS */ From 66a285612f771cc986d506ec428c3eb577d0b746 Mon Sep 17 00:00:00 2001 From: izy521 Date: Sat, 28 Oct 2017 22:08:36 -0700 Subject: [PATCH 47/54] Merge pull request #139 from RaidAndFade/patch-2 Added a way to move roles --- lib/index.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index a712be3e..dcf06fce 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1129,7 +1129,52 @@ DCP.editRole = function(input, callback) { }); } catch(e) {return handleErrCB(('[editRole] ' + e), callback);} }; + +/** + * Move a role up or down relative to it's current position. + * @arg {Object} input + * @arg {Snowflake} input.serverID + * @arg {Snowflake} input.roleID - The ID of the role. + * @arg {Number} input.position - A relative number to move the role up or down. + */ +DCP.moveRole = function(input,callback){ + if(input.position===0)return handleErrCB("Desired role position is same as current", callback); //Don't do anything if they dont want it to move + + try { + var role = new Role(this.servers[input.serverID].roles[input.roleID]); + var curPos = role.position; + var newPos = curPos + input.position; + + if(newPos < 1) + newPos = 1; //make sure it doesn't go under the possible positions + + if(newPos > Object.keys(this.servers[input.serverID].roles).length-1) + newPos = Object.keys(this.servers[input.serverID].roles).length-1; //make sure it doesn't go above the possible positions + + var currentOrder = []; + for(var roleID in this.servers[input.serverID].roles){ + if(roleID == input.serverID) continue; //the everyone role cannot be changed, so best to not try. + var _role = new Role(this.servers[input.serverID].roles[roleID]); + currentOrder[_role.position] = roleID; + } + var payload = []; + + + for(var pos in currentOrder){ + var roleID = currentOrder[pos]; + if(newPos>curPos && curPos < pos && pos <= newPos) + payload.push({id:roleID, position:pos-1}); + if(curPos>newPos && curPos > pos && pos >= newPos) + payload.push({id:roleID, position:(pos-(-1))}); + } + payload.push({id:input.roleID,position:newPos}); + this._req('patch', Endpoints.ROLES(input.serverID), payload, function(err, res) { + handleResCB("Unable to move role", err, res, callback); + }); + } catch(e) {return handleErrCB(e, callback);} +}; + /** * Delete a role. * @arg {Object} input @@ -1465,7 +1510,7 @@ function APIRequest(method, url) { }); }); }); - if (type(data) === 'object' || method.toLowerCase() === 'get') req.setHeader("Content-Type", "application/json; charset=utf-8"); + if (typeof(data) == 'object' || method.toLowerCase() === 'get') req.setHeader("Content-Type", "application/json; charset=utf-8"); if (data instanceof Multipart) req.setHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary); if (data) req.write( data.result || JSON.stringify(data), data.result ? 'binary' : 'utf-8' ); req.end(); @@ -1486,7 +1531,7 @@ function APIRequest(method, url) { callback(null, req); } }; - if (type(data) === 'object' || method.toLowerCase() === 'get') req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); + if (typeof(data) == 'object' || method.toLowerCase() === 'get') req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); if (data instanceof Multipart) req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary); if (data) return req.send( data.result ? data.result : JSON.stringify(data) ); req.send(null); From 6245f1fd38674c3b5a287e0a60fcd208346fd94d Mon Sep 17 00:00:00 2001 From: izy521 Date: Sat, 28 Oct 2017 22:09:08 -0700 Subject: [PATCH 48/54] Merge pull request #138 from Adryd/patch-1 Allow users to set typing time in miliseconds when sending message --- lib/index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index dcf06fce..2671b0ff 100644 --- a/lib/index.js +++ b/lib/index.js @@ -227,7 +227,7 @@ DCP.sendMessage = function(input, callback) { message.tts = (input.tts === true); message.nonce = input.nonce || message.nonce; - if (input.typing === true) { + if (typof input.typing === "boolean" && input.typing === true) { return simulateTyping( this, input.to, @@ -235,6 +235,14 @@ DCP.sendMessage = function(input, callback) { ( (message.content.length * 0.12) * 1000 ), callback ); + } else if (typof input.typing === "number") { + return simulateTyping( + this, + input.to, + message, + input.typing + callback + ); } sendMessage(this, input.to, message, callback); From cd10791c9caa51692de2edfaf4df6cac6804b77d Mon Sep 17 00:00:00 2001 From: izy521 Date: Sun, 29 Oct 2017 10:25:20 -0700 Subject: [PATCH 49/54] Merge pull request #217 from Seth177/patch-1 Fixed typo --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 2671b0ff..cd243c79 100644 --- a/lib/index.js +++ b/lib/index.js @@ -227,7 +227,7 @@ DCP.sendMessage = function(input, callback) { message.tts = (input.tts === true); message.nonce = input.nonce || message.nonce; - if (typof input.typing === "boolean" && input.typing === true) { + if (typeof input.typing === "boolean" && input.typing === true) { return simulateTyping( this, input.to, @@ -235,7 +235,7 @@ DCP.sendMessage = function(input, callback) { ( (message.content.length * 0.12) * 1000 ), callback ); - } else if (typof input.typing === "number") { + } else if (typeof input.typing === "number") { return simulateTyping( this, input.to, From 416c7684a008386d39dc767cdea0c8c1ff0e9ddb Mon Sep 17 00:00:00 2001 From: izy521 Date: Sun, 29 Oct 2017 10:29:29 -0700 Subject: [PATCH 50/54] Merge pull request #218 from Seth177/patch-2 Someone forgot a comma too --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index cd243c79..08e05116 100644 --- a/lib/index.js +++ b/lib/index.js @@ -240,7 +240,7 @@ DCP.sendMessage = function(input, callback) { this, input.to, message, - input.typing + input.typing, callback ); } From af547c0c395c44a71f3167598ff2366a5cbd5243 Mon Sep 17 00:00:00 2001 From: izy521 Date: Sat, 28 Oct 2017 22:06:55 -0700 Subject: [PATCH 51/54] Merge pull request #216 from mastastealth/master Fixes DM Channel Issue --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 08e05116..b692f0df 100644 --- a/lib/index.js +++ b/lib/index.js @@ -928,7 +928,7 @@ DCP.createChannel = function(input, callback) { DCP.createDMChannel = function(userID, callback) { var client = this; this._req('post', Endpoints.USER(client.id) + "/channels", {recipient_id: userID}, function(err, res) { - if (!err && goodResponse(res)) client._uIDToDM[res.body.recipient.id] = res.body.id; + if (!err && goodResponse(res)) client._uIDToDM[res.body.recipient_id] = res.body.id; handleResCB("Unable to create DM Channel", err, res, callback); }); }; From 6212c8586903fbd59f5c22b15a89be24492c4020 Mon Sep 17 00:00:00 2001 From: pix674 <38077439+pix674@users.noreply.github.com> Date: Thu, 5 Apr 2018 09:40:17 +0200 Subject: [PATCH 52/54] Allow GENERAL_MANAGE_WEBHOOKS & TEXT_ADD_REACTIONS in editChannelPermissions in function : editChannelPermissions - Add GENERAL_MANAGE_WEBHOOKS & TEXT_ADD_REACTIONS in allowed_values --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index b692f0df..7f4752d3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1008,8 +1008,8 @@ DCP.editChannelPermissions = function(input, callback) { //Will shrink this up l channel = this.channels[ input.channelID ]; permissions = channel.permissions[pType][ID] || { allow: 0, deny: 0 }; allowed_values = [0, 4, 28].concat((channel.type === 'text' ? - [10, 11, 12, 13, 14, 15, 16, 17, 18] : - [20, 21, 22, 23, 24, 25] )); + [6, 10, 11, 12, 13, 14, 15, 16, 17, 18] : + [20, 21, 22, 23, 24, 25, 29] )); //Take care of allow first if (type(input.allow) === 'array') { From 5f20a4c4e602787410b268aca2acae6ecc9d359b Mon Sep 17 00:00:00 2001 From: pix674 <38077439+pix674@users.noreply.github.com> Date: Thu, 5 Apr 2018 09:43:58 +0200 Subject: [PATCH 53/54] Add in permissions interface GENERAL_MANAGE_WEBHOOKS and TEXT_ADD_REACTIONS have been added to the permissions interface. --- typings/index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/typings/index.d.ts b/typings/index.d.ts index cef92bc7..19311154 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -97,7 +97,9 @@ declare interface permissions { GENERAL_MANAGE_ROLES?: boolean; GENERAL_MANAGE_NICKNAMES?: boolean; GENERAL_CHANGE_NICKNAME?: boolean; + GENERAL_MANAGE_WEBHOOKS?: boolean; + TEXT_ADD_REACTIONS?: boolean; TEXT_READ_MESSAGES?: boolean; TEXT_SEND_MESSAGES?: boolean; TEXT_SEND_TTS_MESSAGE?: boolean; From 68564d12e79acc24a105b70be76b4442e80c239f Mon Sep 17 00:00:00 2001 From: Brad Nakken <3517352+bradnak@users.noreply.github.com> Date: Thu, 11 Oct 2018 16:48:14 +1100 Subject: [PATCH 54/54] Add DMRecipient class type to describe DMChannel.recipient --- typings/index.d.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 19311154..e1860d9b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -407,11 +407,18 @@ declare namespace Discord { } export class DMChannel extends Resource { - recipient: Object; + recipient: DMRecipient; last_message_id: string; id: string; } + export class DMRecipient extends Resource { + username: string; + id: string; + discriminator: string; + avatar: string; + } + export class User extends Resource { username: string; id: string;