Merge remote-tracking branch 'upstream/indev' into indev

This commit is contained in:
abalabahaha
2015-12-05 16:57:13 -08:00
8 changed files with 244 additions and 75 deletions

1
.gitignore vendored
View File

@@ -36,5 +36,4 @@ build/Release
node_modules node_modules
test/auth.json test/auth.json
examples/auth.json examples/auth.json
test/msgbot.js
docs/_build docs/_build

View File

@@ -359,6 +359,38 @@ var Client = (function (_EventEmitter) {
return this.removeMemberFromRole(member, role, callback); return this.removeMemberFromRole(member, role, callback);
}; };
//def addMemberToRole
Client.prototype.addMemberToRoles = function addMemberToRoles(member, roles) {
var callback = arguments.length <= 2 || arguments[2] === undefined ? function () /*err*/{} : arguments[2];
return this.internal.addMemberToRoles(member, roles).then(callback, errCB(callback));
};
// def addUserToRole
Client.prototype.addUserToRoles = function addUserToRoles(member, roles) {
var callback = arguments.length <= 2 || arguments[2] === undefined ? function () /*err*/{} : arguments[2];
return this.addMemberToRoles(member, roles, callback);
};
// def removeMemberFromRole
Client.prototype.removeMemberFromRoles = function removeMemberFromRoles(member, roles) {
var callback = arguments.length <= 2 || arguments[2] === undefined ? function () /*err*/{} : arguments[2];
return this.internal.removeMemberFromRoles(member, roles).then(callback, errCB(callback));
};
// def removeUserFromRole
Client.prototype.removeUserFromRoles = function removeUserFromRoles(member, roles) {
var callback = arguments.length <= 2 || arguments[2] === undefined ? function () /*err*/{} : arguments[2];
return this.removeMemberFromRoles(member, roles, callback);
};
// def createInvite // def createInvite
Client.prototype.createInvite = function createInvite(chanServ, options) { Client.prototype.createInvite = function createInvite(chanServ, options) {

View File

@@ -662,6 +662,48 @@ var InternalClient = (function () {
}).end(); }).end();
}; };
//def addMemberToRole
InternalClient.prototype.addMemberToRoles = function addMemberToRoles(member, roles) {
member = this.resolver.resolveUser(member);
if (!member) {
return Promise.reject(new Error("member not in server"));
}
if (!Array.isArray(roles) || roles.length === 0) {
return Promise.reject(new Error("invalid array of roles"));
}
var roleIDS = roles[0].server.memberMap[member.id].roles.map(function (r) {
return r.id;
});
for (var _iterator3 = roles, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref3 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref3 = _i3.value;
}
var role = _ref3;
if (!role.server.memberMap[member.id]) {
return Promise.reject(new Error("member not in server"));
}
roleIDS.concat(role.id);
}
return _superagent2["default"].patch(_Constants.Endpoints.SERVER_MEMBERS(role.server.id) + "/" + member.id).set("authorization", this.token).send({
roles: roleIDS
}).end();
};
//def removeMemberFromRole //def removeMemberFromRole
InternalClient.prototype.removeMemberFromRole = function removeMemberFromRole(member, role) { InternalClient.prototype.removeMemberFromRole = function removeMemberFromRole(member, role) {
@@ -682,7 +724,54 @@ var InternalClient = (function () {
for (var item in roleIDS) { for (var item in roleIDS) {
if (roleIDS[item] === role.id) { if (roleIDS[item] === role.id) {
roleIDS.splice(item, 1); roleIDS.splice(item, 1);
//missing break? break;
}
}
return _superagent2["default"].patch(_Constants.Endpoints.SERVER_MEMBERS(role.server.id) + "/" + member.id).set("authorization", this.token).send({
roles: roleIDS
}).end();
};
//def removeMemberFromRoles
InternalClient.prototype.removeMemberFromRoles = function removeMemberFromRoles(member, roles) {
member = this.resolver.resolveUser(member);
if (!member) {
return Promise.reject(new Error("member not in server"));
}
if (!Array.isArray(roles) || roles.length === 0) {
return Promise.reject(new Error("invalid array of roles"));
}
var roleIDS = roles[0].server.memberMap[member.id].roles.map(function (r) {
return r.id;
});
for (var _iterator4 = roles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i4 >= _iterator4.length) break;
_ref4 = _iterator4[_i4++];
} else {
_i4 = _iterator4.next();
if (_i4.done) break;
_ref4 = _i4.value;
}
var role = _ref4;
if (!role.server.memberMap[member.id]) {
return Promise.reject(new Error("member not in server"));
}
for (var item in roleIDS) {
if (roleIDS[item] === role.id) {
roleIDS.splice(item, 1);
break;
}
} }
} }
@@ -1140,19 +1229,19 @@ var InternalClient = (function () {
var server = self.servers.get("id", data.id); var server = self.servers.get("id", data.id);
if (server) { if (server) {
for (var _iterator3 = server.channels, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { for (var _iterator5 = server.channels, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref3; var _ref5;
if (_isArray3) { if (_isArray5) {
if (_i3 >= _iterator3.length) break; if (_i5 >= _iterator5.length) break;
_ref3 = _iterator3[_i3++]; _ref5 = _iterator5[_i5++];
} else { } else {
_i3 = _iterator3.next(); _i5 = _iterator5.next();
if (_i3.done) break; if (_i5.done) break;
_ref3 = _i3.value; _ref5 = _i5.value;
} }
var channel = _ref3; var channel = _ref5;
self.channels.remove(channel); self.channels.remove(channel);
} }

View File

@@ -22,7 +22,7 @@ var AudioEncoder = (function () {
_classCallCheck(this, AudioEncoder); _classCallCheck(this, AudioEncoder);
if (opus) { if (opus) {
this.opus = new opus.OpusEncoder(48000, 1); this.opus = new opus.OpusEncoder(48000, 2);
} }
this.choice = false; this.choice = false;
} }
@@ -67,8 +67,7 @@ var AudioEncoder = (function () {
var self = this; var self = this;
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var enc = _child_process2["default"].spawn(self.getCommand(), ["-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. var enc = _child_process2["default"].spawn(self.getCommand(), ['-i', "-", '-f', 's16le', '-ar', '48000', '-ac', 2, 'pipe:1']);
"-af", "volume=1", "pipe:1", "-i", "-"]);
stream.pipe(enc.stdin); stream.pipe(enc.stdin);
@@ -76,12 +75,14 @@ var AudioEncoder = (function () {
callback(null, { callback(null, {
proc: enc, proc: enc,
stream: enc.stdout, stream: enc.stdout,
instream: stream instream: stream,
channels: 2
}); });
resolve({ resolve({
proc: enc, proc: enc,
stream: enc.stdout, stream: enc.stdout,
instream: stream instream: stream,
channels: 2
}); });
}); });
@@ -102,26 +103,29 @@ var AudioEncoder = (function () {
var self = this; var self = this;
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var enc = _child_process2["default"].spawn(self.getCommand(), ["-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. var enc = _child_process2["default"].spawn(self.getCommand(), ['-i', file, '-f', 's16le', '-ar', '48000', '-ac', 2, 'pipe:1']);
"-af", "volume=1", "pipe:1", "-i", file]);
enc.stdout.once("readable", function () { enc.stdout.once("readable", function () {
callback(null, { callback(null, {
proc: enc, proc: enc,
stream: enc.stdout stream: enc.stdout,
channels: 2
}); });
resolve({ resolve({
proc: enc, proc: enc,
stream: enc.stdout stream: enc.stdout,
channels: 2
}); });
}); });
enc.stdout.on("end", function () { enc.stdout.on("end", function () {
console.log("end");
callback("end"); callback("end");
reject("end"); reject("end");
}); });
enc.stdout.on("close", function () { enc.stdout.on("close", function () {
console.log("close");
callback("close"); callback("close");
reject("close"); reject("close");
}); });

View File

@@ -103,6 +103,7 @@ var VoiceConnection = (function (_EventEmitter) {
}; };
VoiceConnection.prototype.playStream = function playStream(stream) { VoiceConnection.prototype.playStream = function playStream(stream) {
var channels = arguments.length <= 1 || arguments[1] === undefined ? 2 : arguments[1];
var self = this; var self = this;
@@ -122,21 +123,21 @@ var VoiceConnection = (function (_EventEmitter) {
self.playingIntent = retStream; self.playingIntent = retStream;
function send() { function send() {
if (!self.playingIntent || !self.playing) { if (!self.playingIntent || !self.playing) {
self.setSpeaking(false); self.setSpeaking(false);
retStream.emit("end"); retStream.emit("end");
self; console.log("ending 1");
return; return;
} }
try { try {
var buffer = stream.read(1920); var buffer = stream.read(1920 * channels);
if (!buffer) { if (!buffer) {
if (onWarning) { if (onWarning) {
retStream.emit("end"); retStream.emit("end");
self.setSpeaking(false); self.setSpeaking(false);
console.log("ending 2");
return; return;
} else { } else {
onWarning = true; onWarning = true;
@@ -145,8 +146,8 @@ var VoiceConnection = (function (_EventEmitter) {
} }
} }
if (buffer.length !== 1920) { if (buffer.length !== 1920 * channels) {
var newBuffer = new Buffer(1920).fill(0); var newBuffer = new Buffer(1920 * channels).fill(0);
buffer.copy(newBuffer); buffer.copy(newBuffer);
buffer = newBuffer; buffer = newBuffer;
} }
@@ -238,7 +239,7 @@ var VoiceConnection = (function (_EventEmitter) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
_this.encoder.encodeFile(stream)["catch"](error).then(function (data) { _this.encoder.encodeFile(stream)["catch"](error).then(function (data) {
self.streamProc = data.proc; self.streamProc = data.proc;
var intent = self.playStream(data.stream); var intent = self.playStream(data.stream, 2);
resolve(intent); resolve(intent);
callback(null, intent); callback(null, intent);
}); });

View File

@@ -3,36 +3,36 @@
import cpoc from "child_process"; import cpoc from "child_process";
var opus; var opus;
try{ try {
opus = require("node-opus"); opus = require("node-opus");
}catch(e){ } catch (e) {
// no opus! // no opus!
} }
export default class AudioEncoder { export default class AudioEncoder {
constructor(){ constructor() {
if(opus){ if (opus) {
this.opus = new opus.OpusEncoder(48000, 1); this.opus = new opus.OpusEncoder(48000, 2);
} }
this.choice = false; this.choice = false;
} }
opusBuffer(buffer){ opusBuffer(buffer) {
return this.opus.encode(buffer, 1920); return this.opus.encode(buffer, 1920);
} }
getCommand(force){ getCommand(force) {
if(this.choice && force) if (this.choice && force)
return choice; return choice;
var choices = ["avconv", "ffmpeg"]; var choices = ["avconv", "ffmpeg"];
for(var choice of choices){ for (var choice of choices) {
var p = cpoc.spawnSync(choice); var p = cpoc.spawnSync(choice);
if(!p.error){ if (!p.error) {
this.choice = choice; this.choice = choice;
return choice; return choice;
} }
@@ -41,74 +41,78 @@ export default class AudioEncoder {
return "help"; return "help";
} }
encodeStream(stream, callback=function(err, buffer){}){ encodeStream(stream, callback = function (err, buffer) { }) {
var self = this; var self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var enc = cpoc.spawn(self.getCommand() , [ var enc = cpoc.spawn(self.getCommand(), [
"-f", "s16le", '-i', "-",
"-ar", "48000", '-f', 's16le',
"-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. '-ar', '48000',
"-af", "volume=1", '-ac', 2,
"pipe:1", 'pipe:1'
"-i", "-"
]); ]);
stream.pipe(enc.stdin); stream.pipe(enc.stdin);
enc.stdout.once("readable", function() { enc.stdout.once("readable", function () {
callback(null, { callback(null, {
proc : enc, proc: enc,
stream : enc.stdout, stream: enc.stdout,
instream : stream instream: stream,
channels : 2
}); });
resolve({ resolve({
proc : enc, proc: enc,
stream : enc.stdout, stream: enc.stdout,
instream : stream instream: stream,
channels : 2
}); });
}); });
enc.stdout.on("end", function() { enc.stdout.on("end", function () {
callback("end"); callback("end");
reject("end"); reject("end");
}); });
enc.stdout.on("close", function() { enc.stdout.on("close", function () {
callback("close"); callback("close");
reject("close"); reject("close");
}); });
}); });
} }
encodeFile(file, callback=function(err, buffer){}){ encodeFile(file, callback = function (err, buffer) { }) {
var self = this; var self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var enc = cpoc.spawn(self.getCommand() , [ var enc = cpoc.spawn(self.getCommand(), [
"-f", "s16le", '-i', file,
"-ar", "48000", '-f', 's16le',
"-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. '-ar', '48000',
"-af", "volume=1", '-ac', 2,
"pipe:1", 'pipe:1'
"-i", file
]); ]);
enc.stdout.once("readable", function() { enc.stdout.once("readable", function () {
callback(null, { callback(null, {
proc : enc, proc: enc,
stream : enc.stdout stream: enc.stdout,
channels : 2
}); });
resolve({ resolve({
proc : enc, proc: enc,
stream : enc.stdout stream: enc.stdout,
channels : 2
}); });
}); });
enc.stdout.on("end", function() { enc.stdout.on("end", function () {
console.log("end");
callback("end"); callback("end");
reject("end"); reject("end");
}); });
enc.stdout.on("close", function() { enc.stdout.on("close", function () {
console.log("close");
callback("close"); callback("close");
reject("close"); reject("close");
}); });

View File

@@ -73,7 +73,7 @@ export default class VoiceConnection extends EventEmitter {
} }
} }
playStream(stream) { playStream(stream, channels=2) {
var self = this; var self = this;
@@ -93,21 +93,21 @@ export default class VoiceConnection extends EventEmitter {
self.playingIntent = retStream; self.playingIntent = retStream;
function send() { function send() {
if (!self.playingIntent || !self.playing) { if (!self.playingIntent || !self.playing) {
self.setSpeaking(false); self.setSpeaking(false);
retStream.emit("end"); retStream.emit("end");
self console.log("ending 1");
return; return;
} }
try { try {
var buffer = stream.read(1920); var buffer = stream.read(1920 * channels);
if (!buffer) { if (!buffer) {
if (onWarning) { if (onWarning) {
retStream.emit("end"); retStream.emit("end");
self.setSpeaking(false); self.setSpeaking(false);
console.log("ending 2");
return; return;
} else { } else {
onWarning = true; onWarning = true;
@@ -116,8 +116,8 @@ export default class VoiceConnection extends EventEmitter {
} }
} }
if(buffer.length !== 1920) { if(buffer.length !== 1920 * channels) {
var newBuffer = new Buffer(1920).fill(0); var newBuffer = new Buffer(1920 * channels).fill(0);
buffer.copy(newBuffer); buffer.copy(newBuffer);
buffer = newBuffer; buffer = newBuffer;
} }
@@ -213,7 +213,7 @@ export default class VoiceConnection extends EventEmitter {
.catch(error) .catch(error)
.then(data => { .then(data => {
self.streamProc = data.proc; self.streamProc = data.proc;
var intent = self.playStream(data.stream); var intent = self.playStream(data.stream, 2);
resolve(intent); resolve(intent);
callback(null, intent); callback(null, intent);

40
test/msgbot.js Normal file
View File

@@ -0,0 +1,40 @@
/* global describe */
/* global process */
var Discord = require("../");
var client = new Discord.Client();
var request = require("superagent");
client.on("ready", () => {
console.log("ready");
});
client.on("message", msg => {
if(!msg.sender.equals(client.user))
console.log("received message from " + msg.sender.username);
if (msg.content === "$bind") {
msg.channel.server.channels.get("type", "voice").join();
}
if (msg.content.startsWith("$play")) {
var url = msg.content.split(" ")[1];
client.voiceConnection.playFile(url);
console.log(request.get(url).end());
}
if (msg.content === "$$$") {
client.sendMessage(msg.sender, "hi!");
}
});
console.log("INIT");
client.on("debug", console.log)
client.login(process.env["ds_email"], process.env["ds_password"]).catch(console.log);