discord-dj
Version:
Discord DJ Bot. Let you play music in your server. Inspired by PlugDJ
1 lines • 5.58 kB
JavaScript
"use strict";
var Discordie = require('discordie');
var Utils = require('./Utils.js');
class InternalDJ {
constructor(bot, voiceConnection, wrapper, handler, keys) {
this.bot = bot;
this.wrapper = wrapper;
this.handler = handler; /* TODO: use it in the future */
this.voiceConnection = voiceConnection;
this.playable = null;
this.musicQueue = [];
this.stream = null;
this.decoder = null;
this.encoder = null;
this.multithreaded = false;
this.bitrate = 64;
this.stopping = false;
this.keys = keys;
this.disconnectedEvent = function(info) {
if(info.voiceConnection == this.voiceConnection) this.destroy();
}.bind(this);
this.bot.Dispatcher.on(Discordie.Events.VOICE_DISCONNECTED, this.disconnectedEvent);
}
destroy() {
this.bot.Dispatcher.removeListener(Discordie.Events.VOICE_DISCONNECTED, this.disconnectedEvent);
}
decodeStream(stream, format, sampleRate, channels) {
if(typeof format == 'undefined') format = null;
var options = {
sampleRate: sampleRate,
channels: channels
};
var decoders = Utils.getDecoders();
for(var i = 0; i < decoders.length; i++) {
var decoder = decoders[i];
if(decoder.canDecode(format)) {
this.decoder = decoder;
return decoder.createDecoder(stream, options);
}
}
return Promise.reject('No decoder found');
}
playStream(stream, sampleRate, channels, bitDepth) {
var options = {
frameDuration: 60,
sampleRate: sampleRate,
channels: channels,
float: false,
multiThreadedVoice: this.multithreaded,
bitrate: this.bitrate
};
var readSize = sampleRate / 1000 * options.frameDuration * bitDepth / 8 * channels;
var playable = this.playable;
stream.once('readable', function() {
if(this.playable != playable) return;
this.encoder = this.voiceConnection.getEncoder(options);
if(this.encoder == null) return;
this.encoder.onNeedBuffer = function() {
if(this.stopping) return;
if(this.playable != playable) return this.stop();
if(this.decoder == null) return;
if(stream == null) return;
var chunk = stream.read(readSize);
if(!chunk) return setTimeout(this.encoder.onNeedBuffer, options.frameDuration);
var sampleCount = readSize / channels / (bitDepth / 8);
this.encoder.enqueue(chunk, sampleCount);
}.bind(this);
this.encoder.onNeedBuffer();
}.bind(this));
}
play(playable) {
this.stop();
playable.init(this);
this.playable = playable;
var sampleRate = 48000;
var bitDepth = 16;
var channels = 2;
playable.createStream().then(function(stream) {
if(this.playable != playable) return;
this.stream = stream;
this.decodeStream(this.stream, playable.getFormat(), sampleRate, channels).then(function(decodedStream) {
decodedStream.once('end', function() {
if(this.stopping) return;
if(this.playable != playable) return;
this.playable = null;
this.stream = null;
this.skip();
}.bind(this));
decodedStream.once('readable', function() {
if(this.playable != playable) return;
this.wrapper.emit('play');
}.bind(this));
this.playStream(decodedStream, sampleRate, channels, bitDepth);
}.bind(this), function(err) {
console.log("Music skipped by a decoder error: " + err);
});
}.bind(this), function(error) {
console.log("Music skipped by an error: " + error);
this.skip();
}.bind(this));
}
stop() {
if(this.stopping) return;
this.stopping = true;
try {
if(this.decoder != null) {
this.decoder.destroyDecoder();
this.decoder = null;
}
if(this.encoder != null) {
this.encoder.kill();
this.encoder = null;
}
if(this.stream != null) {
if(this.stream.end) this.stream.end();
if(this.stream.destroy) this.stream.destroy();
this.stream = null;
}
} catch(e) {
console.log("An error ocurred while stopping the current music: " + e);
}
this.stopping = false;
}
skip() {
this.stop();
if(this.playable != null) {
this.playable.removeAllListeners('data-changed');
this.playable = null;
}
this.wrapper.emit('skip');
if(this.playable == null && this.musicQueue.length > 0) {
this.play(this.musicQueue.shift());
}
}
addToQueue(playable) {
playable.on('data-changed', function() {
this.wrapper.emit('data-changed');
}.bind(this));
playable.loadData();
if(this.playable == null) {
this.play(playable);
} else {
this.musicQueue.push(playable);
}
}
}
module.exports = InternalDJ;