feat: play soundcloud tracks (#35)
This commit is contained in:
parent
86cedbafad
commit
334dacd880
2 changed files with 75 additions and 1 deletions
|
@ -33,6 +33,7 @@
|
||||||
"merge-options": "^2.0.0",
|
"merge-options": "^2.0.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"simple-youtube-api": "^5.2.1",
|
"simple-youtube-api": "^5.2.1",
|
||||||
|
"soundcloud-downloader": "0.0.9",
|
||||||
"ytsr": "^0.1.15"
|
"ytsr": "^0.1.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const ytdl = require('discord-ytdl-core')
|
const ytdl = require('discord-ytdl-core')
|
||||||
const Discord = require('discord.js')
|
const Discord = require('discord.js')
|
||||||
const ytsr = require('ytsr')
|
const ytsr = require('ytsr')
|
||||||
|
const scdl = require('soundcloud-downloader')
|
||||||
|
|
||||||
const Queue = require('./Queue')
|
const Queue = require('./Queue')
|
||||||
const Track = require('./Track')
|
const Track = require('./Track')
|
||||||
|
@ -43,6 +44,7 @@ const filters = {
|
||||||
* @property {boolean} [leaveOnEnd=true] Whether the bot should leave the current voice channel when the queue ends.
|
* @property {boolean} [leaveOnEnd=true] Whether the bot should leave the current voice channel when the queue ends.
|
||||||
* @property {boolean} [leaveOnStop=true] Whether the bot should leave the current voice channel when the stop() function is used.
|
* @property {boolean} [leaveOnStop=true] Whether the bot should leave the current voice channel when the stop() function is used.
|
||||||
* @property {boolean} [leaveOnEmpty=true] Whether the bot should leave the voice channel if there is no more member in it.
|
* @property {boolean} [leaveOnEmpty=true] Whether the bot should leave the voice channel if there is no more member in it.
|
||||||
|
* @property {string} [soundcloudClientID=""] The client ID for Soundcloud, optional
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,7 +55,8 @@ const filters = {
|
||||||
const defaultPlayerOptions = {
|
const defaultPlayerOptions = {
|
||||||
leaveOnEnd: true,
|
leaveOnEnd: true,
|
||||||
leaveOnStop: true,
|
leaveOnStop: true,
|
||||||
leaveOnEmpty: true
|
leaveOnEmpty: true,
|
||||||
|
soundcloudClientID: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
|
@ -164,6 +167,21 @@ class Player {
|
||||||
const matchURL = query.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/)
|
const matchURL = query.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/)
|
||||||
if (matchURL) {
|
if (matchURL) {
|
||||||
query = matchURL[1]
|
query = matchURL[1]
|
||||||
|
} else if (this.options.soundcloudClientID) {
|
||||||
|
const scRegex = /^https?:\/\/(soundcloud\.com)\/(.*)$/
|
||||||
|
if (query.match(scRegex) && query.match(scRegex)[2]) {
|
||||||
|
const info = await scdl.getInfo(query, this.options.soundcloudClientID)
|
||||||
|
const details = {
|
||||||
|
title: info.title,
|
||||||
|
link: info.uri,
|
||||||
|
duration: info.duration,
|
||||||
|
description: info.description,
|
||||||
|
thumbnail: info.artwork_url,
|
||||||
|
views: info.playback_count,
|
||||||
|
author: { name: info.user.username }
|
||||||
|
}
|
||||||
|
return resolve([new Track(details, null, null)])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ytsr(query, (err, results) => {
|
ytsr(query, (err, results) => {
|
||||||
if (err) return []
|
if (err) return []
|
||||||
|
@ -762,6 +780,51 @@ class Player {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play a Soundcloud stream in a channel
|
||||||
|
* @ignore
|
||||||
|
* @private
|
||||||
|
* @param {Queue} queue The queue to play
|
||||||
|
* @param {*} updateFilter Whether this method is called to update some ffmpeg filters
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
_playSouncloudStream (queue, updateFilter) {
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
const currentStreamTime = updateFilter ? queue.voiceConnection.dispatcher.streamTime / 1000 : undefined
|
||||||
|
const encoderArgsFilters = []
|
||||||
|
Object.keys(queue.filters).forEach((filterName) => {
|
||||||
|
if (queue.filters[filterName]) {
|
||||||
|
encoderArgsFilters.push(filters[filterName])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let encoderArgs
|
||||||
|
if (encoderArgsFilters.length < 1) {
|
||||||
|
encoderArgs = []
|
||||||
|
} else {
|
||||||
|
encoderArgs = ['-af', encoderArgsFilters.join(',')]
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = await scdl.getInfo(queue.playing.url, this.options.soundcloudClientID)
|
||||||
|
const opus = scdl.filterMedia(info.media.transcodings, { format: scdl.FORMATS.OPUS })
|
||||||
|
const newStream = await scdl.downloadFromURL(opus[0].url, this.options.soundcloudClientID)
|
||||||
|
setTimeout(() => {
|
||||||
|
queue.voiceConnection.play(newStream, {
|
||||||
|
type: 'ogg/opus'
|
||||||
|
})
|
||||||
|
queue.voiceConnection.dispatcher.setVolumeLogarithmic(queue.volume / 200)
|
||||||
|
// When the track starts
|
||||||
|
queue.voiceConnection.dispatcher.on('start', () => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
// When the track ends
|
||||||
|
queue.voiceConnection.dispatcher.on('finish', () => {
|
||||||
|
// Play the next track
|
||||||
|
return this._playTrack(queue.guildID, false)
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start playing a track in a guild
|
* Start playing a track in a guild
|
||||||
* @ignore
|
* @ignore
|
||||||
|
@ -790,6 +853,16 @@ class Player {
|
||||||
const nowPlaying = queue.playing = queue.repeatMode ? wasPlaying : queue.tracks.shift()
|
const nowPlaying = queue.playing = queue.repeatMode ? wasPlaying : queue.tracks.shift()
|
||||||
// Reset lastSkipped state
|
// Reset lastSkipped state
|
||||||
queue.lastSkipped = false
|
queue.lastSkipped = false
|
||||||
|
|
||||||
|
if (queue.playing.url.includes('soundcloud.com')) {
|
||||||
|
this._playSouncloudStream(queue, false).then(() => {
|
||||||
|
// Emit trackChanged event
|
||||||
|
if (!firstPlay) {
|
||||||
|
queue.emit('trackChanged', nowPlaying, wasPlaying, queue.lastSkipped, queue.repeatMode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
this._playYTDLStream(queue, false).then(() => {
|
this._playYTDLStream(queue, false).then(() => {
|
||||||
// Emit trackChanged event
|
// Emit trackChanged event
|
||||||
if (!firstPlay) {
|
if (!firstPlay) {
|
||||||
|
|
Loading…
Reference in a new issue