Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Music fix #1046

Merged
merged 5 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
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
32 changes: 20 additions & 12 deletions actions/control_music_MOD.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ module.exports = {
authorUrl: 'https://github.com/dbm-network/mods',
downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/control_music_MOD.js',
},
requiresAudioLibraries: true,
fields: ['action', 'volume', 'bitrate'],

subtitle(data) {
Expand Down Expand Up @@ -92,7 +91,7 @@ module.exports = {
action(cache) {
const { Bot } = this.getDBM();
const data = cache.actions[cache.index];
const queue = Bot.bot.player.getQueue(cache.server);
const server = cache.server;
const action = parseInt(data.action, 10);
const volume = parseInt(this.evalMessage(data.volume, cache), 10);
const bitrate = this.evalMessage(data.bitrate, cache);
Expand All @@ -102,36 +101,45 @@ module.exports = {
return this.callNexAction(cache);
}

if (!Bot.bot.queue) return this.callNextAction(cache);

const queue = Bot.bot.queue.get(server.id);
if (!queue) return this.callNextAction(cache);

try {
switch (action) {
case 0:
queue.destroy();
queue.connection.disconnect();
break;
case 1:
queue.setPaused(true);
queue.player.pause();
break;
case 2:
queue.setPaused(false);
queue.player.unpause();
break;
case 3:
queue.skip();
queue.player.stop();
break;
case 4:
queue.back();
queue.currentIndex -= 2;
queue.player.stop();
break;
case 5:
queue.destroy(false);
queue.songs = [];
break;
case 6:
queue.shuffle();
case 6: {
const currentIndex = queue.currentIndex + 1;
for (let i = queue.songs.length - 1; i > currentIndex; i--) {
const j = Math.floor(Math.random() * (i - currentIndex + 1)) + currentIndex;
[queue.songs[i], queue.songs[j]] = [queue.songs[j], queue.songs[i]];
}
break;
}
case 7:
queue.setVolume(volume);
queue.player.state.resource.volume.setVolume(volume / 100);
break;
case 8:
queue.setBitrate(bitrate);
queue.player.state.resource.encoder.setBitrate(bitrate);
break;
}
} catch (err) {
Expand Down
210 changes: 165 additions & 45 deletions actions/play_music_MOD.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
authorUrl: 'https://github.com/dbm-network/mods',
downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/play_music_MOD.js',
},
requiresAudioLibraries: true,
fields: ['query', 'voiceChannel', 'varName', 'storage', 'varName2', 'type', 'volume', 'leaveOnEmpty', 'leaveOnEnd'],

subtitle(data) {
Expand All @@ -24,8 +23,8 @@
return `
<div style="max-height: 350px; overflow-y: scroll;">
<div style="padding-top: 8px;">
<span class="dbminputlabel">YouTube Search</span><br>
<input id="query" class="round" type="text" placeholder="Search for a song from youtube"><br>
<span class="dbminputlabel">YouTube URL</span><br>
<input id="query" class="round" type="text" placeholder="Play URL from YouTube"><br>
</div>

<div>
Expand Down Expand Up @@ -61,10 +60,7 @@
<br><br><br>
<p>
<u><b><span style="color: white;">NOTE:</span></b></u><br>
Youtube URLs and IDs are hit and miss due to using ytdl-core.<br>
In theory you should be able to use the following:<br>
Soundcloud URL, YouTube Search, YouTube song/playlist URL, YouTube ID,<br>
Spotify Song/playlist/album, vimeo, facebook and reverbnation.
Supports both videos and playlists.<br>
</p>
</div>
`;
Expand All @@ -75,66 +71,190 @@
async action(cache) {
const data = cache.actions[cache.index];
const server = cache.server;
const channel = cache.msg?.channel ?? cache.interaction?.channel;
const { Bot, Files } = this.getDBM();
const Mods = this.getMods();
const playdl = Mods.require('play-dl');
const player = Bot.bot.player;
const ytdl = Mods.require('@distube/ytdl-core');
const ytpl = Mods.require('@distube/ytpl');
const {
joinVoiceChannel,
createAudioPlayer,
createAudioResource,
AudioPlayerStatus,
VoiceConnectionStatus,
} = require('@discordjs/voice');
const voiceChannel = await this.getVoiceChannelFromData(data.voiceChannel, data.varName, cache);

let volume = 80;
if (data.volume) volume = parseInt(this.evalMessage(data.volume, cache), 10) || 80;
if (!Bot.bot.queue) Bot.bot.queue = new Map();

// leaveOnEnd & leaveOnEmpty Cooldowns from DBM Settings
const volume = parseInt(this.evalMessage(data.volume, cache), 10) || 80;
const leaveOnEnd = data.leaveOnEnd;
const leaveOnEmpty = data.leaveOnEmpty;
const autoDeafen = (Files.data.settings.autoDeafen ?? 'true') === 'true';
const leaveVoiceTimeout = Files.data.settings.leaveVoiceTimeout ?? '10';
let seconds = parseInt(leaveVoiceTimeout, 10);

if (isNaN(seconds) || seconds < 0) seconds = 0;
if (leaveVoiceTimeout === '' || !isFinite(seconds)) seconds = 0;
// Needs to be converted to Milliseconds, keeping the same variable.
if (seconds > 0) seconds *= 1000;

const query = this.evalMessage(data.query, cache);
const queue = player.createQueue(server, {
metadata: {
channel,
},
autoSelfDeaf: (Files.data.settings.autoDeafen ?? 'true') === 'true',
initialVolume: volume,
leaveOnEmpty: data.leaveOnEmpty,
leaveOnEmptyCooldown: seconds,
leaveOnEnd: data.leaveOnEnd,
async onBeforeCreateStream(track, source) {
if (source === 'youtube') {
return (await playdl.stream(track.url, { discordPlayerCompatibility: true })).stream;
}
},
});

const track = await player.search(query, {
requestedBy: cache.getUser(),
});
const serverQueue = Bot.bot.queue.get(server.id);

let songs = [];

if (ytpl.validateID(query)) {
let playlist;
try {
playlist = await ytpl(query);
} catch (error) {
console.log(error);
return this.callNextAction(cache);
}

songs = playlist.items.map((item) => ({
title: item.title,
thumbnail: item.thumbnail,
url: item.shortUrl,
author: item.author.name,
duration: item.duration.split(':').reduce((acc, time) => 60 * acc + Number(time)),
requestedBy: cache.getUser().id,
}));
} else {
let songInfo;
try {
songInfo = await ytdl.getInfo(query);
} catch (error) {
console.log(error);
return this.callNextAction(cache);
}

songs.push({
title: songInfo.videoDetails.title,
thumbnail: songInfo.videoDetails.thumbnails[songInfo.videoDetails.thumbnails.length - 1].url,
url: songInfo.videoDetails.video_url,
author: songInfo.videoDetails.author.name,
duration: songInfo.videoDetails.lengthSeconds,
requestedBy: cache.getUser().id,
});
}

if (!serverQueue) {
const queueData = {
connection: null,
player: createAudioPlayer(),
songs: [],
currentIndex: 0,
repeatMode: 0,
};

Bot.bot.queue.set(server.id, queueData);
queueData.songs.push(...songs);

if (track.tracks.length > 0) {
let connection;
try {
if (!queue.connection) await queue.connect(voiceChannel);
connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: server.id,
adapterCreator: server.voiceAdapterCreator,
selfDeaf: autoDeafen,
});
} catch {
queue.destroy();
console.log('Could not join voice channel');
queueData.player.stop();
queueData.player.removeAllListeners();
Bot.bot.queue.delete(server.id);
return this.callNextAction(cache);
}

track.playlist ? queue.addTracks(track.tracks) : queue.addTrack(track.tracks[0]);
if (data.type === '1') {
await queue.play();
}
if (data.type === '0') {
if (!queue.playing) await queue.play();
queueData.connection = connection;
connection.subscribe(queueData.player);

const stream = ytdl(queueData.songs[queueData.currentIndex].url, {
filter: 'audioonly',
fmt: 'mp3',
highWaterMark: 1 << 30,
liveBuffer: 20000,
dlChunkSize: 1024 * 1024,
quality: 'lowestaudio',
bitrate: 128,
});
const resource = createAudioResource(stream, { inlineVolume: true });
resource.volume.setVolume(volume / 100);
queueData.player.play(resource);

queueData.player.on(AudioPlayerStatus.Idle, async () => {
let nextSongUrl;
if (queueData.repeatMode === 1) {
nextSongUrl = queueData.songs[queueData.currentIndex].url;
} else if (queueData.repeatMode === 2 && queueData.songs.length > 0) {
queueData.currentIndex = (queueData.currentIndex + 1) % queueData.songs.length;
nextSongUrl = queueData.songs[queueData.currentIndex].url;
} else {
queueData.currentIndex += 1;
if (queueData.currentIndex < queueData.songs.length) {
nextSongUrl = queueData.songs[queueData.currentIndex].url;
} else {
if (leaveOnEnd) {
connection.disconnect();
}
return;
}
}

const nextStream = ytdl(nextSongUrl, {
filter: 'audioonly',
fmt: 'mp3',
highWaterMark: 1 << 30,
liveBuffer: 20000,
dlChunkSize: 1024 * 1024,
quality: 'lowestaudio',
bitrate: 128,
});
const nextResource = createAudioResource(nextStream, { inlineVolume: true });
nextResource.volume.setVolume(volume / 100);
queueData.player.play(nextResource);
});

if (leaveOnEmpty) {
Bot.bot.on('voiceStateUpdate', (oldState, newState) => {

Check warning on line 219 in actions/play_music_MOD.js

View workflow job for this annotation

GitHub Actions / ESLint

'oldState' is defined but never used

Check warning on line 219 in actions/play_music_MOD.js

View workflow job for this annotation

GitHub Actions / ESLint

'newState' is defined but never used
const botChannel = connection.joinConfig.channelId;
if (!botChannel) return;

const botVoiceChannel = server.channels.cache.get(botChannel);
if (botVoiceChannel && botVoiceChannel.members.size === 1) {
setTimeout(() => {
if (botVoiceChannel.members.size === 1) {
connection.disconnect();
}
}, seconds);
}
});
}
const storage = parseInt(data.storage, 10);
const varName2 = this.evalMessage(data.varName2, cache);
this.storeValue(track, storage, varName2, cache);

Bot.bot.on('voiceStateUpdate', (oldState, newState) => {
if (oldState.channelId && !newState.channelId && oldState.member.id === Bot.bot.user.id) {
connection.disconnect();
}
});

connection.on(VoiceConnectionStatus.Disconnected, () => {
connection.destroy();
queueData.player.stop();
queueData.player.removeAllListeners();
Bot.bot.queue.delete(server.id);
});
} else if (data.type === '1') {
const currentSong = serverQueue.songs[serverQueue.currentIndex];
serverQueue.songs.splice(serverQueue.currentIndex + 1, 0, songs[0]);
serverQueue.songs.splice(serverQueue.currentIndex + 2, 0, currentSong);
serverQueue.player.stop();
} else {
serverQueue.songs.push(...songs);
}

const storage = parseInt(data.storage, 10);
const varName2 = this.evalMessage(data.varName2, cache);
this.storeValue(songs[0], storage, varName2, cache);
this.callNextAction(cache);
},

Expand Down
Loading
Loading