Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 110 additions & 62 deletions listeners/channelState.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const utils = require('../utils.js');
const Discord = require('discord.js');

/**
* Checks to see if the voice channel is a child of a category we can manage
Expand All @@ -25,66 +26,42 @@ function canActOn(channel) {
*
* @param {CategoryChannel} category The category
*/
function manageChannels(category) {
let guild = category.guild,
voiceChannels,
emptyVoiceChannels,
promises,
createNewChannel = false;

voiceChannels = category.children.filter(channel => {
return channel.type === 'voice';
});
function manageChannels(cat) {

emptyVoiceChannels = voiceChannels.filter(channel => {
return channel.members.size === 0;
});
cat.fetch()
.then((category) => {
let guild = category.guild;

//Ensure one empty channel
promises = [];
if (emptyVoiceChannels.size > 0) {
emptyVoiceChannels.forEach(channel => {
let permissionOverwrites = category.permissionOverwrites.map(() => {});
if (channel.id === emptyVoiceChannels.first().id) {
//Edit happens in lockPermissions. Set userLimit on channel data.
/*promises.push(channel.edit({
userLimit: 0
}));*/
channel.userLimit = 0;
promises.push(channel.lockPermissions());
} else {
promises.push(channel.delete());
voiceChannels.delete(channel.id);
}
});
} else if (emptyVoiceChannels.size === 0) {
createNewChannel = true;
}
let voiceChannels = category.children.filter(channel => {
return channel.type === 'voice';
});

Promise.all(promises).then(() => {
let index = 1,
channelName;
let index = 1,
channelName;

voiceChannels = category.children.filter(channel => {
return channel.type === 'voice';
});
let populatedChannels = voiceChannels.filter(channel => {
return channel.members.size > 0;
});

voiceChannels.forEach(channel => {
channelName = getChannelName(channel, index);
if (channelName !== channel.name) {
channel.setName(channelName);
}
index++;
});
populatedChannels.forEach(channel => {
channelName = getChannelName(channel, index);
renameChannel(channel, channelName);
index++;
});

let emptyVoiceChannels = voiceChannels.filter(channel => {
return channel.members.size === 0;
});

emptyVoiceChannels.forEach(channel => {
channel.delete();
});

if (createNewChannel) {
guild.channels.create('Voice #' + index, {
type: 'voice',
parent: category
});
}
});

});
}

/**
Expand All @@ -98,10 +75,11 @@ function getChannelName(channel, index) {
max = 0,
activityName, channelName;


channel.members.forEach(member => {
let activities = utils.get(member, 'presence.activities');

if(member.user.bot) {
if (member.user.bot) {
return;
}

Expand Down Expand Up @@ -144,6 +122,78 @@ function getChannelName(channel, index) {
return channelName;
}

const renameCoolDowns = new Discord.Collection();
const rateLimit = (1000 * 60 * 10) + 1000;

/**
* An attempt to avoid rate limits. If it can delete and recreate the channel it will. Otherwise,
* it will queue the latest name until such time as it can rename it.
* @param {Channel} channel the channel to be renamed
* @param {String} name the new name of the channel
*/
function renameChannel(channel, name) {
if (channel.members.size === 0) { //Empty channel. Delete and re-create
let category = channel.parent;
channel.delete().then(() => {
guild.channels.create(name, {
type: 'voice',
parent: category
});
});
return;
}

if (channel.name === name) {
return;
}

let channelCoolDown;
let channelId = channel.id;
if (!renameCoolDowns.has(channelId)) {
channelCoolDown = new Discord.Collection();
channelCoolDown.set('count', 0);
channelCoolDown.set('name', undefined);
renameCoolDowns.set(channelId, channelCoolDown);
} else {
channelCoolDown = renameCoolDowns.get(channelId);
}
let count = channelCoolDown.get('count');
count++;
console.log(`${count} requests to rename channel: ${channelId}(${channel.name}). Requested name is '${name}'`);
channelCoolDown.set('count', count);
channelCoolDown.set('channel', channel);

if (count < 3) {
channel.setName(name).catch((e) => {
//Channel likely does not exist. Ignore.
});
} else {
console.log(`Queueing name '${name}' for channel: ${channelId}(${channel.name})`);
channelCoolDown.set('name', name);

if (!channelCoolDown.get('timeout')) {
console.log(`Cooldown started for channel: ${channelId}(${channel.name})`);
channelCoolDown.set('timeout', setTimeout(() => {
let ccd = renameCoolDowns.get(channelId);
let queuedName = ccd.get('name');
if (queuedName !== undefined) {
ccd.get('channel').fetch()
.then((queuedChannel) => {
console.log(`Completing rename of channel: ${channelId}(${queuedChannel.name}). New name should be ${queuedName}`);
queuedChannel.setName(queuedName).catch((e) => {
//Channel likely deleted before the timeout completed. Ignore.
});
})
.catch((e) => {
//Channel likely deleted before the timeout completed. Ignore.
});
}
renameCoolDowns.delete(channelId);
}, rateLimit));
}
}
}

module.exports = {
init: function (client) {

Expand All @@ -166,19 +216,17 @@ module.exports = {
client.on('voiceStateUpdate', (oldState, newState) => {
let newUserChannel = newState.channel,
oldUserChannel = oldState.channel,
oldCategoryID,
newCategory;
newCategoryID;

//If a user enters of leaves a configured category, update it.
if (oldUserChannel != null && canActOn(oldUserChannel) && (newUserChannel == null || !newUserChannel.equals(oldUserChannel))) {
oldCategoryID = oldUserChannel.parentID;
manageChannels(oldUserChannel.parent);
//If a user enters or leaves a configured category, update it.
if (newUserChannel != null && canActOn(newUserChannel) && (oldUserChannel == null || !newUserChannel.equals(oldUserChannel))) {
newCategoryID = newUserChannel.parentID;
manageChannels(newUserChannel.parent);
}


if (newUserChannel != null && canActOn(newUserChannel) && (oldUserChannel == null || !newUserChannel.equals(oldUserChannel))) {
if (oldCategoryID !== newUserChannel.parentID) { //No need to manage the same category twice.
manageChannels(newUserChannel.parent);
if (oldUserChannel != null && canActOn(oldUserChannel) && (newUserChannel == null || !newUserChannel.equals(oldUserChannel))) {
if (newCategoryID !== oldUserChannel.parentID) { //No need to manage the same category twice.
manageChannels(oldUserChannel.parent);
}
}
});
Expand All @@ -188,7 +236,7 @@ module.exports = {
let newUserChannel = utils.get(newPresence, 'member.voice.channel');
if (newUserChannel != null) {
//Shouldnt be necessary to manage an entire category when the presence updates.
newUserChannel.setName(getChannelName(newUserChannel));
renameChannel(newUserChannel, getChannelName(newUserChannel));
}
}
});
Expand Down