Merge branch 'master' into fix-33

This commit is contained in:
Christer Warén 2021-09-05 06:32:46 +03:00
commit f5ef44b12a
23 changed files with 409 additions and 510 deletions

12
package-lock.json generated
View File

@ -1252,9 +1252,9 @@
} }
}, },
"node_modules/deep-is": { "node_modules/deep-is": {
"version": "0.1.3", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true "dev": true
}, },
"node_modules/defer-to-connect": { "node_modules/defer-to-connect": {
@ -4876,9 +4876,9 @@
"dev": true "dev": true
}, },
"deep-is": { "deep-is": {
"version": "0.1.3", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true "dev": true
}, },
"defer-to-connect": { "defer-to-connect": {

View File

@ -39,6 +39,9 @@ class RadioClient extends Client {
this.funcs.statisticsUpdate = require("./client/funcs/statisticsUpdate.js"); this.funcs.statisticsUpdate = require("./client/funcs/statisticsUpdate.js");
this.funcs.saveState = require("./client/funcs/saveState.js"); this.funcs.saveState = require("./client/funcs/saveState.js");
this.funcs.loadState = require("./client/funcs/loadState.js"); this.funcs.loadState = require("./client/funcs/loadState.js");
this.funcs.searchStation = require("./client/funcs/searchStation.js");
this.funcs.play = require("./client/funcs/play.js");
this.funcs.listStations = require("./client/funcs/listStations.js");
console.log('RadioX ' + this.config.version); console.log('RadioX ' + this.config.version);
console.log('Internet Radio to your Discord guild'); console.log('Internet Radio to your Discord guild');

View File

@ -44,16 +44,17 @@ module.exports = {
try { try {
await rest.put( await rest.put(
Routes.applicationGuildCommands(client.user.id, guild.id), Routes.applicationGuildCommands(client.user.id, guild.id),
{ body: commands }, { body: commands }
); );
client.funcs.logger('Slash Commands', 'Guild Applications Successful' + "\n" + guild.id + " / " + guild.name);
} catch (DiscordAPIError) { } catch (DiscordAPIError) {
client.funcs.logger('Slash Commands', 'Guild Applications Failed' + "\n" + guild.id + " / " + guild.name);
} }
}); });
} else { } else {
await rest.put( await rest.put(
Routes.applicationCommands(client.user.id), Routes.applicationCommands(client.user.id),
{ body: commands }, { body: commands }
); );
} }

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'bug', name: 'bug',
alias: 'none',
usage: '',
description: 'Report a bug', description: 'Report a bug',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
async execute(interaction, client, Discord, command) { async execute(interaction, client) {
let message = {}; let message = {};
message.bugTitle = client.messages.bugTitle.replace("%client.user.username%", client.user.username); message.bugTitle = client.messages.bugTitle.replace("%client.user.username%", client.user.username);

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'help', name: 'help',
alias: 'h',
usage: '<command(opt)>',
description: 'Get help using bot', description: 'Get help using bot',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
execute(interaction, client, Discord, command) { execute(interaction, client) {
let message = {}; let message = {};
const categories = []; const categories = [];

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'invite', name: 'invite',
alias: 'i',
usage: '',
description: 'Invite Bot', description: 'Invite Bot',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
execute(interaction, client, Discord, command) { execute(interaction, client) {
let message = {}; let message = {};
message.inviteTitle = client.messages.inviteTitle.replace("%client.user.username%", client.user.username); message.inviteTitle = client.messages.inviteTitle.replace("%client.user.username%", client.user.username);
const embed = new Discord.MessageEmbed() const embed = new Discord.MessageEmbed()

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'list', name: 'list',
alias: 'l',
usage: '',
description: 'List radio stations', description: 'List radio stations',
permission: 'none', permission: 'none',
category: 'radio', category: 'radio',
execute(interaction, client, Discord, command) { execute(interaction, client) {
let message = {}; let message = {};
if(!client.stations) { if(!client.stations) {
message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild);
@ -15,49 +15,7 @@ module.exports = {
const radio = client.radio.get(interaction.guild.id); const radio = client.radio.get(interaction.guild.id);
if(radio){ if(radio){
let menu = []; client.funcs.listStations(client, interaction);
let stations = new Array();
let options = new Array();
options[1] = new Array();
options[2] = new Array();
stations[1] = client.stations.slice(0,24).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[1].push(station);
});
stations[2] = client.stations.slice(25).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[2].push(station);
});
menu = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageSelectMenu()
.setCustomId('play')
.setPlaceholder('Change station')
.addOptions(options[1])
.addOptions(options[2])
);
stations = null;
options = null;
interaction.reply({
content: '**Select station:**',
components: [menu],
ephemeral: true
});
} else { } else {
let stations = `${client.stations.map(s => `**#** ${s.name}`).join('\n')}` let stations = `${client.stations.map(s => `**#** ${s.name}`).join('\n')}`
const hashs = stations.split('**#**').length; const hashs = stations.split('**#**').length;

View File

@ -1,52 +1,62 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'maintenance', name: 'maintenance',
alias: 'm',
usage: '',
description: 'Bot Maintenance', description: 'Bot Maintenance',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
execute(interaction, client, Discord, command) { execute(interaction, client) {
let message = {}; let message = {};
if(!client.funcs.isDev(client.config.devId, interaction.user.id)) return interaction.reply(client.messageEmojis["error"] + client.messages.notAllowed); if(!client.funcs.isDev(client.config.devId, interaction.user.id)) return interaction.reply(client.messageEmojis["error"] + client.messages.notAllowed);
if(!client.stations) { if(client.config.version.includes("-dev")){
message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); interaction.reply({
return interaction.reply(client.messageEmojis["error"] + message.errorToGetPlaylist); content: "Maintenance Initiated",
} ephemeral: true
});
let currentRadios = client.radio.keys(); process.emit('SIGINT');
let radio = currentRadios.next(); } else {
let stoppedRadios = ""; if(!client.stations) {
message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild);
client.user.setStatus('dnd'); return interaction.reply(client.messageEmojis["error"] + message.errorToGetPlaylist);
while (!radio.done) {
let currentRadio = client.radio.get(radio.value);
currentRadio.guild = client.datastore.getEntry(radio.value).guild;
if(currentRadio){
client.funcs.statisticsUpdate(client, currentRadio.guild, currentRadio);
currentRadio.connection?.destroy();
currentRadio.audioPlayer?.stop();
currentRadio.message?.delete();
client.radio.delete(radio.value);
stoppedRadios += "-" + radio.value + ": " + currentRadio.guild.name + "\n";
} }
radio = currentRadios.next();
let currentRadios = client.radio.keys();
let radio = currentRadios.next();
let stoppedRadios = "";
client.user.setStatus('dnd');
while (!radio.done) {
let currentRadio = client.radio.get(radio.value);
currentRadio.guild = client.datastore.getEntry(radio.value).guild;
if(currentRadio){
client.funcs.statisticsUpdate(client, currentRadio.guild, currentRadio);
currentRadio.connection?.destroy();
currentRadio.audioPlayer?.stop();
currentRadio.message?.delete();
client.radio.delete(radio.value);
stoppedRadios += "-" + radio.value + ": " + currentRadio.guild.name + "\n";
}
radio = currentRadios.next();
}
const embed = new Discord.MessageEmbed()
.setTitle(client.messages.maintenanceTitle)
.setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["maintenance"].replace(/[^0-9]+/g, ''))
.setColor(client.config.embedColor)
.setDescription("Stopped all radios" + "\n" + stoppedRadios)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
interaction.reply({
embeds: [embed],
ephemeral: true
});
} }
const embed = new Discord.MessageEmbed()
.setTitle(client.messages.maintenanceTitle)
.setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["maintenance"].replace(/[^0-9]+/g, ''))
.setColor(client.config.embedColor)
.setDescription("Stopped all radios" + "\n" + stoppedRadios)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
interaction.reply({
embeds: [embed],
ephemeral: true
});
} }
}; };

View File

@ -0,0 +1,35 @@
module.exports = {
name: 'next',
description: 'Next Station',
permission: 'none',
category: 'radio',
async execute(interaction, client, command) {
if (client.funcs.check(client, interaction, command)) {
const radio = client.radio.get(interaction.guild.id);
let index = client.stations.findIndex(station => station.name == radio.station.name) + 1;
if(index == client.stations.length) index = 0;
let station = client.stations[index];
if(!station) return interaction.reply({
content: client.messageEmojis["error"] + client.messages.noSearchResults,
ephemeral: true
});
interaction.deferUpdate();
let url = station.stream[station.stream.default];
client.funcs.statisticsUpdate(client, interaction.guild, radio);
radio.audioPlayer.stop();
let date = new Date();
radio.station = station;
radio.textChannel = interaction.channel;
radio.startTime = date.getTime();
client.funcs.play(null, interaction.guild, client, url);
}
}
}

View File

@ -1,45 +1,36 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'nowplaying', name: 'nowplaying',
alias: 'np',
usage: '',
description: 'Current Radio Station', description: 'Current Radio Station',
permission: 'none', permission: 'none',
category: 'radio', category: 'radio',
async execute(interaction, client, Discord, command) { async execute(interaction, client, command) {
let message = {}; if (client.funcs.check(client, interaction, command)) {
const radio = client.radio.get(interaction.guild.id); let message = {};
if (!radio) return interaction.reply({ const radio = client.radio.get(interaction.guild.id);
content: 'There is nothing playing.',
ephemeral: true let date = new Date();
}); radio.currentTime = date.getTime();
if(!client.stations) { radio.playTime = parseInt(radio.currentTime)-parseInt(radio.startTime);
message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); const completed = (radio.playTime);
return interaction.reply({
content: client.messageEmojis["error"] + message.errorToGetPlaylist, message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name);
message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.owner);
message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", client.funcs.msToTime(completed));
const embed = new Discord.MessageEmbed()
.setTitle(client.messages.nowplayingTitle)
.setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, '')))
.setColor(client.config.embedColor)
.setDescription(message.nowplayingDescription)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
interaction.reply({
embeds: [embed],
ephemeral: true ephemeral: true
}); });
} }
let date = new Date();
radio.currentTime = date.getTime();
radio.playTime = parseInt(radio.currentTime)-parseInt(radio.startTime);
const completed = (radio.playTime);
message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name);
message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.owner);
message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", client.funcs.msToTime(completed));
const embed = new Discord.MessageEmbed()
.setTitle(client.messages.nowplayingTitle)
.setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, '')))
.setColor(client.config.embedColor)
.setDescription(message.nowplayingDescription)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
interaction.reply({
embeds: [embed],
ephemeral: true
});
} }
}; };

View File

@ -1,13 +1,11 @@
const { const {
createAudioPlayer, createAudioPlayer,
createAudioResource,
getVoiceConnection, getVoiceConnection,
joinVoiceChannel joinVoiceChannel
} = require("@discordjs/voice"); } = require("@discordjs/voice");
module.exports = { module.exports = {
name: "play", name: "play",
alias: "p",
usage: "<song name>", usage: "<song name>",
description: "Play radio", description: "Play radio",
options: [ options: [
@ -15,7 +13,7 @@ module.exports = {
], ],
permission: "none", permission: "none",
category: "radio", category: "radio",
async execute(interaction, client, Discord, command) { async execute(interaction, client) {
let message = {}; let message = {};
let query = interaction.options?.getString("query") ?? interaction.values?.[0]; let query = interaction.options?.getString("query") ?? interaction.values?.[0];
if(!query){ if(!query){
@ -24,47 +22,7 @@ module.exports = {
return interaction.reply(client.messageEmojis["error"] + message.errorToGetPlaylist); return interaction.reply(client.messageEmojis["error"] + message.errorToGetPlaylist);
} }
let stations = new Array(); client.funcs.listStations(client, interaction);
let options = new Array();
options[1] = new Array();
options[2] = new Array();
stations[1] = client.stations.slice(0,24).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[1].push(station);
});
stations[2] = client.stations.slice(25).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[2].push(station);
});
const menu = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageSelectMenu()
.setCustomId('play')
.setPlaceholder('Nothing selected')
.addOptions(options[1])
.addOptions(options[2])
);
stations = null;
options = null;
return interaction.reply({
content: '**Select station:**',
components: [menu],
ephemeral: true
});
} }
let url = query ? query.replace(/<(.+)>/g, "$1") : ""; let url = query ? query.replace(/<(.+)>/g, "$1") : "";
const radio = client.radio.get(interaction.guild.id); const radio = client.radio.get(interaction.guild.id);
@ -123,7 +81,7 @@ module.exports = {
content: client.messageEmojis["error"] + client.messages.tooShortSearch, content: client.messageEmojis["error"] + client.messages.tooShortSearch,
ephemeral: true ephemeral: true
}); });
const sstation = await searchStation(query, client); const sstation = await client.funcs.searchStation(query, client);
if (!sstation) if (!sstation)
return interaction.reply({ return interaction.reply({
content: client.messageEmojis["error"] + client.messages.noSearchResults, content: client.messageEmojis["error"] + client.messages.noSearchResults,
@ -141,7 +99,7 @@ module.exports = {
radio.station = station; radio.station = station;
radio.textChannel = interaction.channel; radio.textChannel = interaction.channel;
radio.startTime = date.getTime(); radio.startTime = date.getTime();
play(interaction, interaction.guild, client, url, Discord); client.funcs.play(interaction, interaction.guild, client, url);
return; return;
} }
@ -167,7 +125,7 @@ module.exports = {
construct.connection = connection; construct.connection = connection;
let date = new Date(); let date = new Date();
construct.startTime = date.getTime(); construct.startTime = date.getTime();
play(interaction, interaction.guild, client, url, Discord); client.funcs.play(interaction, interaction.guild, client, url);
client.datastore.checkEntry(interaction.guild.id); client.datastore.checkEntry(interaction.guild.id);
construct.currentGuild = client.datastore.getEntry(interaction.guild.id); construct.currentGuild = client.datastore.getEntry(interaction.guild.id);
@ -185,157 +143,3 @@ module.exports = {
} }
} }
}; };
async function play(interaction, guild, client, url, Discord) {
let message = {};
const radio = client.radio.get(guild.id);
const resource = createAudioResource(url);
radio.connection.subscribe(radio.audioPlayer);
radio.audioPlayer.play(resource);
resource.playStream
.on("readable", () => {
client.funcs.logger('Radio', 'Stream started' + " / " + guild.id + " / " + radio.station.name);
})
.on("finish", () => {
client.funcs.logger('Radio', 'Stream finished' + " / " + guild.id);
client.funcs.statisticsUpdate(client, guild, radio);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
return;
})
.on("error", error => {
client.funcs.logger('Radio', 'Stream errored');
console.error(error);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
return interaction.reply(client.messages.errorPlaying);
});
message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name);
message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.owner);
message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", "");
message.nowplayingDescription = message.nowplayingDescription.replace("Owner: ", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
const embed = new Discord.MessageEmbed()
.setTitle(client.user.username)
.setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, '')))
.setColor(client.config.embedColor)
.addField(client.messages.nowplayingTitle, message.nowplayingDescription, true)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
const buttons = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageButton()
.setCustomId('list')
.setEmoji(client.messageEmojis["list"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('prev')
.setEmoji(client.messageEmojis["prev"])
.setStyle('SECONDARY')
.setDisabled(true)
)
.addComponents(
new Discord.MessageButton()
.setCustomId('stop')
.setEmoji(client.messageEmojis["stop"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('next')
.setEmoji(client.messageEmojis["next"])
.setStyle('SECONDARY')
.setDisabled(true)
)
.addComponents(
new Discord.MessageButton()
.setCustomId('statistics')
.setEmoji(client.messageEmojis["statistics"])
.setStyle('SECONDARY')
);
if(!radio.message){
radio.message = await radio.textChannel.send({ embeds: [embed], components: [buttons] });
} else {
radio.message.edit({ embeds: [embed], components: [buttons] });
}
message.play = client.messages.play.replace("%radio.station.name%", radio.station.name);
interaction.reply({
content: client.messageEmojis["play"] + message.play,
ephemeral: true
});
}
function searchStation(key, client) {
if (client.stations === null) return false;
let foundStations = [];
if (!key) return false;
if (key == "radio") return false;
client.stations
.filter(
x => x.name.toUpperCase().includes(key.toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: 100 })
);
if (key.startsWith("radio ")) key = key.slice(6);
const probabilityIncrement = 100 / key.split(" ").length / 2;
for (let i = 0; i < key.split(" ").length; i++) {
client.stations
.filter(
x => x.name.toUpperCase().includes(key.split(" ")[i].toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: probabilityIncrement })
);
}
if (foundStations.length === 0) return false;
for (let i = 0; i < foundStations.length; i++) {
for (let j = 0; j < foundStations.length; j++) {
if (foundStations[i] === foundStations[j] && i !== j) foundStations.splice(i, 1);
}
}
for (let i = 0; i < foundStations.length; i++) {
if (foundStations[i].name.length > key.length) {
foundStations[i].probability -=
(foundStations[i].name.split(" ").length - key.split(" ").length) *
(probabilityIncrement * 0.5);
} else if (foundStations[i].name.length === key.length) {
foundStations[i].probability += probabilityIncrement * 0.9;
}
for (let j = 0; j < key.split(" ").length; j++) {
if (!foundStations[i].name.toUpperCase().includes(key.toUpperCase().split(" ")[j])) {
foundStations[i].probability -= probabilityIncrement * 0.5;
}
}
}
let highestProbabilityStation;
for (let i = 0; i < foundStations.length; i++) {
if (
!highestProbabilityStation ||
highestProbabilityStation.probability < foundStations[i].probability
)
highestProbabilityStation = foundStations[i];
if (
highestProbabilityStation &&
highestProbabilityStation.probability === foundStations[i].probability
) {
highestProbabilityStation = foundStations[i].station;
}
}
return highestProbabilityStation;
}

View File

@ -0,0 +1,35 @@
module.exports = {
name: 'prev',
description: 'Previous Station',
permission: 'none',
category: 'radio',
async execute(interaction, client, command) {
if (client.funcs.check(client, interaction, command)) {
const radio = client.radio.get(interaction.guild.id);
let index = client.stations.findIndex(station => station.name == radio.station.name) - 1;
if(index == -1) index = client.stations.length - 1;
let station = client.stations[index];
if(!station) return interaction.reply({
content: client.messageEmojis["error"] + client.messages.noSearchResults,
ephemeral: true
});
interaction.deferUpdate();
let url = station.stream[station.stream.default];
client.funcs.statisticsUpdate(client, interaction.guild, radio);
radio.audioPlayer.stop();
let date = new Date();
radio.station = station;
radio.textChannel = interaction.channel;
radio.startTime = date.getTime();
client.funcs.play(null, interaction.guild, client, url);
}
}
}

View File

@ -1,14 +1,15 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'statistics', name: 'statistics',
alias: 'stats',
usage: '',
description: 'Show statistics', description: 'Show statistics',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
execute(interaction, client, Discord, command) { execute(interaction, client) {
let message = {}; let message = {};
let stations = client.stations; let stations = client.stations;
let currentGuild = client.datastore.getEntry(interaction.guild.id); let currentGuild = client.datastore.getEntry(interaction.guild.id);
let global = client.datastore.getEntry("global");
let statistics = ""; let statistics = "";
if(!client.stations) { if(!client.stations) {
@ -21,9 +22,13 @@ module.exports = {
} else { } else {
Object.keys(stations).forEach(function(station) { Object.keys(stations).forEach(function(station) {
if(currentGuild.statistics[stations[station].name] && currentGuild.statistics[stations[station].name].time && parseInt(currentGuild.statistics[stations[station].name].time) > 0 && currentGuild.statistics[stations[station].name].used && parseInt(currentGuild.statistics[stations[station].name].used) > 0){ if(currentGuild.statistics[stations[station].name] && currentGuild.statistics[stations[station].name].time && parseInt(currentGuild.statistics[stations[station].name].time) > 0 && currentGuild.statistics[stations[station].name].used && parseInt(currentGuild.statistics[stations[station].name].used) > 0){
statistics += `**${parseInt(station) + 1}** ` + stations[station].name + " \n"; statistics += `**${parseInt(station) + 1}. ` + stations[station].name + "** \n";
statistics += "Time: " + client.funcs.msToTime(currentGuild.statistics[stations[station].name].time) + "\n"; if(global && global.statistics[stations[station].name] && global.statistics[stations[station].name].time && parseInt(global.statistics[stations[station].name].time) > 0 && global.statistics[stations[station].name].used && parseInt(global.statistics[stations[station].name].used) > 0){
statistics += "Used: " + currentGuild.statistics[stations[station].name].used + "\n"; statistics += "Guild Time: " + client.funcs.msToTime(currentGuild.statistics[stations[station].name].time) + " (" + ((currentGuild.statistics[stations[station].name].time / global.statistics[stations[station].name].time) * 100) + "%" + ")" + " / " + "Used: " + currentGuild.statistics[stations[station].name].used + " (" + ((currentGuild.statistics[stations[station].name].used / global.statistics[stations[station].name].used) * 100) + "%" + ")" + "\n";
statistics += "Global Time: " + client.funcs.msToTime(global.statistics[stations[station].name].time) + " / " + "Used: " + global.statistics[stations[station].name].used + "\n\n";
} else {
statistics += "Time: " + client.funcs.msToTime(currentGuild.statistics[stations[station].name].time) + " / " + "Used: " + currentGuild.statistics[stations[station].name].used + "\n\n";
}
} }
}); });
} }

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'status', name: 'status',
alias: 'st',
usage: '',
description: 'Bot Status', description: 'Bot Status',
permission: 'none', permission: 'none',
category: 'info', category: 'info',
async execute(interaction, client, Discord, command) { async execute(interaction, client) {
let message = {}; let message = {};
message.statusTitle = client.messages.statusTitle.replace("%client.user.username%", client.user.username); message.statusTitle = client.messages.statusTitle.replace("%client.user.username%", client.user.username);

View File

@ -1,11 +1,11 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'stop', name: 'stop',
description: 'Stop radio', description: 'Stop radio',
alias: 's',
usage: '',
permission: 'none', permission: 'none',
category: 'radio', category: 'radio',
async execute(interaction, client, Discord, command) { async execute(interaction, client, command) {
const radio = client.radio.get(interaction.guild.id); const radio = client.radio.get(interaction.guild.id);
if (client.funcs.check(client, interaction, command)) { if (client.funcs.check(client, interaction, command)) {
client.funcs.statisticsUpdate(client, interaction.guild, radio); client.funcs.statisticsUpdate(client, interaction.guild, radio);

View File

@ -35,7 +35,7 @@ module.exports = {
radio = currentRadios.next(); radio = currentRadios.next();
} }
const rest = new REST({ version: '9' }).setToken(token); /*const rest = new REST({ version: '9' }).setToken(token);
if(version.includes("-dev")){ if(version.includes("-dev")){
await rest.put( await rest.put(
Routes.applicationCommands(client.user.id), Routes.applicationCommands(client.user.id),
@ -47,13 +47,13 @@ module.exports = {
try { try {
await rest.put( await rest.put(
Routes.applicationGuildCommands(client.user.id, guild.id), Routes.applicationGuildCommands(client.user.id, guild.id),
{ body: [] }, { body: [] }
); );
} catch (DiscordAPIError) { } catch (DiscordAPIError) {
} }
}); });
} }*/
setInterval(() => { setInterval(() => {
if(radio.done){ if(radio.done){

View File

@ -1,11 +1,9 @@
import Discord from "discord.js";
module.exports = { module.exports = {
name: 'interactionCreate', name: 'interactionCreate',
async execute(client, interaction) { async execute(client, interaction) {
const permissions = interaction.channel.permissionsFor(interaction.client.user); const permissions = interaction.channel.permissionsFor(interaction.client.user);
if (!permissions.has('EMBED_LINKS')) return interaction.send(client.messages.noPermsEmbed); if (!permissions.has('EMBED_LINKS')) return interaction.reply(client.messages.noPermsEmbed);
if(interaction.isCommand()){ if(interaction.isCommand()){
const commandName = interaction.commandName; const commandName = interaction.commandName;
@ -13,7 +11,7 @@ module.exports = {
if (!command) return; if (!command) return;
try { try {
command.execute(interaction, client, Discord, command); command.execute(interaction, client);
} catch (error) { } catch (error) {
interaction.reply({ interaction.reply({
content: client.messages.runningCommandFailed, content: client.messages.runningCommandFailed,
@ -27,7 +25,7 @@ module.exports = {
if (!command) return; if (!command) return;
try { try {
command.execute(interaction, client, Discord, command); command.execute(interaction, client, command);
} catch (error) { } catch (error) {
interaction.reply({ interaction.reply({
content: client.messages.runningCommandFailed, content: client.messages.runningCommandFailed,

View File

@ -22,7 +22,7 @@ module.exports = {
if (!args[0]) return; if (!args[0]) return;
const commandName = args[0].toLowerCase(); const commandName = args[0].toLowerCase();
if (commandName === 'none') return; if (commandName === 'none') return;
const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)) || client.commandAliases.get(commandName); const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command && message.content !== `${prefix}`) return; if (!command && message.content !== `${prefix}`) return;
const permissions = message.channel.permissionsFor(message.client.user); const permissions = message.channel.permissionsFor(message.client.user);
if (!permissions.has('EMBED_LINKS')) return message.channel.send(client.messages.noPermsEmbed); if (!permissions.has('EMBED_LINKS')) return message.channel.send(client.messages.noPermsEmbed);

View File

@ -2,6 +2,14 @@ module.exports = function (client, interaction, command) {
let message = {}; let message = {};
const radio = client.radio.get(interaction.guild.id); const radio = client.radio.get(interaction.guild.id);
const permissions = interaction.channel.permissionsFor(interaction.user); const permissions = interaction.channel.permissionsFor(interaction.user);
if(!client.stations) {
message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild);
interaction.reply({
content: client.messageEmojis["error"] + message.errorToGetPlaylist,
ephemeral: true
});
return false;
}
if (!radio) { if (!radio) {
interaction.reply({ interaction.reply({
content: client.messageEmojis["error"] + client.messages.notPlaying, content: client.messageEmojis["error"] + client.messages.notPlaying,

View File

@ -0,0 +1,45 @@
import Discord from "discord.js";
module.exports = function (client, interaction){
let stations = new Array();
let options = new Array();
options[1] = new Array();
options[2] = new Array();
stations[1] = client.stations.slice(0,24).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[1].push(station);
});
stations[2] = client.stations.slice(25).forEach(station => {
station = {
label: station.name,
description: station.owner,
value: station.name
};
options[2].push(station);
});
const menu = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageSelectMenu()
.setCustomId('play')
.setPlaceholder('Nothing selected')
.addOptions(options[1])
.addOptions(options[2])
);
stations = null;
options = null;
return interaction.reply({
content: '**Select station:**',
components: [menu],
ephemeral: true
});
}

93
src/client/funcs/play.js Normal file
View File

@ -0,0 +1,93 @@
import Discord from "discord.js";
const {
createAudioResource
} = require("@discordjs/voice");
module.exports = async function play(interaction, guild, client, url) {
let message = {};
const radio = client.radio.get(guild.id);
const resource = createAudioResource(url);
radio.connection.subscribe(radio.audioPlayer);
radio.audioPlayer.play(resource);
resource.playStream
.on("readable", () => {
client.funcs.logger('Radio', 'Stream started' + " / " + guild.id + " / " + radio.station.name);
})
.on("finish", () => {
client.funcs.logger('Radio', 'Stream finished' + " / " + guild.id);
client.funcs.statisticsUpdate(client, guild, radio);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
return;
})
.on("error", error => {
client.funcs.logger('Radio', 'Stream errored');
console.error(error);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
return interaction.reply(client.messages.errorPlaying);
});
message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name);
message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.owner);
message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", "");
message.nowplayingDescription = message.nowplayingDescription.replace("Owner: ", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
const embed = new Discord.MessageEmbed()
.setTitle(client.user.username)
.setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, '')))
.setColor(client.config.embedColor)
.addField(client.messages.nowplayingTitle, message.nowplayingDescription, true)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
const buttons = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageButton()
.setCustomId('list')
.setEmoji(client.messageEmojis["list"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('prev')
.setEmoji(client.messageEmojis["prev"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('stop')
.setEmoji(client.messageEmojis["stop"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('next')
.setEmoji(client.messageEmojis["next"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('statistics')
.setEmoji(client.messageEmojis["statistics"])
.setStyle('SECONDARY')
);
if(!radio.message){
radio.message = await radio.textChannel.send({ embeds: [embed], components: [buttons] });
} else {
radio.message.edit({ embeds: [embed], components: [buttons] });
}
message.play = client.messages.play.replace("%radio.station.name%", radio.station.name);
interaction?.reply({
content: client.messageEmojis["play"] + message.play,
ephemeral: true
});
}

View File

@ -0,0 +1,62 @@
module.exports = function searchStation(key, client) {
if (client.stations === null) return false;
let foundStations = [];
if (!key) return false;
if (key == "radio") return false;
client.stations
.filter(
x => x.name.toUpperCase().includes(key.toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: 100 })
);
if (key.startsWith("radio ")) key = key.slice(6);
const probabilityIncrement = 100 / key.split(" ").length / 2;
for (let i = 0; i < key.split(" ").length; i++) {
client.stations
.filter(
x => x.name.toUpperCase().includes(key.split(" ")[i].toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: probabilityIncrement })
);
}
if (foundStations.length === 0) return false;
for (let i = 0; i < foundStations.length; i++) {
for (let j = 0; j < foundStations.length; j++) {
if (foundStations[i] === foundStations[j] && i !== j) foundStations.splice(i, 1);
}
}
for (let i = 0; i < foundStations.length; i++) {
if (foundStations[i].name.length > key.length) {
foundStations[i].probability -=
(foundStations[i].name.split(" ").length - key.split(" ").length) *
(probabilityIncrement * 0.5);
} else if (foundStations[i].name.length === key.length) {
foundStations[i].probability += probabilityIncrement * 0.9;
}
for (let j = 0; j < key.split(" ").length; j++) {
if (!foundStations[i].name.toUpperCase().includes(key.toUpperCase().split(" ")[j])) {
foundStations[i].probability -= probabilityIncrement * 0.5;
}
}
}
let highestProbabilityStation;
for (let i = 0; i < foundStations.length; i++) {
if (
!highestProbabilityStation ||
highestProbabilityStation.probability < foundStations[i].probability
)
highestProbabilityStation = foundStations[i];
if (
highestProbabilityStation &&
highestProbabilityStation.probability === foundStations[i].probability
) {
highestProbabilityStation = foundStations[i].station;
}
}
return highestProbabilityStation;
}

View File

@ -1,7 +1,6 @@
import Discord from "discord.js"; import Discord from "discord.js";
const { const {
createAudioPlayer, createAudioPlayer,
createAudioResource,
getVoiceConnection, getVoiceConnection,
joinVoiceChannel joinVoiceChannel
} = require("@discordjs/voice"); } = require("@discordjs/voice");
@ -15,7 +14,7 @@ module.exports = {
if(!state) return; if(!state) return;
if(!state.station || !state.channels.voice || !state.channels.text) return; if(!state.station || !state.channels.voice || !state.channels.text) return;
const sstation = await searchStation(state.station.name, client); const sstation = await client.funcs.searchStation(state.station.name, client);
let url = sstation.stream[sstation.stream.default]; let url = sstation.stream[sstation.stream.default];
let station = sstation; let station = sstation;
@ -43,7 +42,7 @@ module.exports = {
let date = new Date(); let date = new Date();
construct.startTime = date.getTime(); construct.startTime = date.getTime();
play(null, guild, client, url, Discord); client.funcs.play(null, guild, client, url, Discord);
client.datastore.checkEntry(guild.id); client.datastore.checkEntry(guild.id);
construct.datastore = client.datastore.getEntry(guild.id); construct.datastore = client.datastore.getEntry(guild.id);
@ -60,151 +59,3 @@ module.exports = {
}); });
} }
} }
async function play(interaction, guild, client, url, Discord) {
let message = {};
const radio = client.radio.get(guild.id);
const resource = createAudioResource(url);
radio.connection.subscribe(radio.audioPlayer);
radio.audioPlayer.play(resource);
resource.playStream
.on("readable", () => {
client.funcs.logger('Radio', 'Stream started' + " / " + guild.id + " / " + radio.station.name);
})
.on("finish", () => {
client.funcs.logger('Radio', 'Stream finished' + " / " + guild.id);
client.funcs.statisticsUpdate(client, guild, radio);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
return;
})
.on("error", error => {
client.funcs.logger('Radio', 'Stream errored');
console.error(error);
radio.connection?.destroy();
radio.audioPlayer?.stop();
client.radio.delete(guild.id);
});
message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name);
message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.owner);
message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", "");
message.nowplayingDescription = message.nowplayingDescription.replace("Owner: ", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
message.nowplayingDescription = message.nowplayingDescription.replace("**", "");
const embed = new Discord.MessageEmbed()
.setTitle(client.user.username)
.setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, '')))
.setColor(client.config.embedColor)
.addField(client.messages.nowplayingTitle, message.nowplayingDescription, true)
.setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png')
.setFooter(client.messages.footerText, "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, ''));
const buttons = new Discord.MessageActionRow()
.addComponents(
new Discord.MessageButton()
.setCustomId('list')
.setEmoji(client.messageEmojis["list"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('prev')
.setEmoji(client.messageEmojis["prev"])
.setStyle('SECONDARY')
.setDisabled(true)
)
.addComponents(
new Discord.MessageButton()
.setCustomId('stop')
.setEmoji(client.messageEmojis["stop"])
.setStyle('SECONDARY')
)
.addComponents(
new Discord.MessageButton()
.setCustomId('next')
.setEmoji(client.messageEmojis["next"])
.setStyle('SECONDARY')
.setDisabled(true)
)
.addComponents(
new Discord.MessageButton()
.setCustomId('statistics')
.setEmoji(client.messageEmojis["statistics"])
.setStyle('SECONDARY')
);
if(!radio.message){
radio.message = await radio.textChannel.send({ embeds: [embed], components: [buttons] });
} else {
radio.message.edit({ embeds: [embed], components: [buttons] });
}
message.play = client.messages.play.replace("%radio.station.name%", radio.station.name);
}
function searchStation(key, client) {
if (client.stations === null) return false;
let foundStations = [];
if (!key) return false;
if (key == "radio") return false;
client.stations
.filter(
x => x.name.toUpperCase().includes(key.toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: 100 })
);
if (key.startsWith("radio ")) key = key.slice(6);
const probabilityIncrement = 100 / key.split(" ").length / 2;
for (let i = 0; i < key.split(" ").length; i++) {
client.stations
.filter(
x => x.name.toUpperCase().includes(key.split(" ")[i].toUpperCase()) || x === key
)
.forEach(x =>
foundStations.push({ station: x, name: x.name, probability: probabilityIncrement })
);
}
if (foundStations.length === 0) return false;
for (let i = 0; i < foundStations.length; i++) {
for (let j = 0; j < foundStations.length; j++) {
if (foundStations[i] === foundStations[j] && i !== j) foundStations.splice(i, 1);
}
}
for (let i = 0; i < foundStations.length; i++) {
if (foundStations[i].name.length > key.length) {
foundStations[i].probability -=
(foundStations[i].name.split(" ").length - key.split(" ").length) *
(probabilityIncrement * 0.5);
} else if (foundStations[i].name.length === key.length) {
foundStations[i].probability += probabilityIncrement * 0.9;
}
for (let j = 0; j < key.split(" ").length; j++) {
if (!foundStations[i].name.toUpperCase().includes(key.toUpperCase().split(" ")[j])) {
foundStations[i].probability -= probabilityIncrement * 0.5;
}
}
}
let highestProbabilityStation;
for (let i = 0; i < foundStations.length; i++) {
if (
!highestProbabilityStation ||
highestProbabilityStation.probability < foundStations[i].probability
)
highestProbabilityStation = foundStations[i];
if (
highestProbabilityStation &&
highestProbabilityStation.probability === foundStations[i].probability
) {
highestProbabilityStation = foundStations[i].station;
}
}
return highestProbabilityStation;
}