Skip to content

Instantly share code, notes, and snippets.

@acrylic-style
Last active May 4, 2020 13:22
Show Gist options
  • Save acrylic-style/c8d50d3ccf0c5124e6fabb22f549678e to your computer and use it in GitHub Desktop.
Save acrylic-style/c8d50d3ccf0c5124e6fabb22f549678e to your computer and use it in GitHub Desktop.
const ytdl = require('ytdl-core-discord')
const logger = require('logger.js').LoggerFactory.getLogger('commands:music')
const isNumber = (n) => !isNaN(parseFloat(n)) && isFinite(n)
const f = require('string-format')
const { Command } = require('bot-framework')
const YouTube = require('youtube-node')
const youtube = new YouTube()
const util = require('util')
const queue = {}
const playing = {}
const loop = {}
const play = async (connection, url, msg) => {
if (!loop[msg.guild.id]) loop[msg.guild.id] = {}
playing[msg.guild.id] = url
return connection.play(await ytdl(url, { filter: 'audioonly' }), { type: 'opus', seek: 0, volume: 0.1 }) // oldvalue: 0.1
//return play2(connection, url)
}
module.exports = class extends Command {
constructor() {
const opts = {
args: [
'play|start <URL or Search>',
'stop',
'pause',
'unpause|resume',
'volume',
'loop [disable|every [clear]]',
'queue',
'status',
],
alias: [
'play',
],
}
super('music', opts)
}
async run(msg, lang, args, sendDeletable, prefix) {
if (!msg.member.voice) return await msg.channel.send(lang.COMMAND_MUSIC_NOT_JOINED_VC)
if (!loop[msg.guild.id]) loop[msg.guild.id] = {} // need initialize!
if (args[1] === 'join') {
msg.member.voice.channel.join().then(vc => msg.channel.send(f(lang.COMMAND_MUSIC_JOINED_VC, vc.channel.name))).catch(e => logger.error(e))
} else if (args[1] === 'play' || args[1] === 'start') {
let keyword
if (!args[2] || !args[2].includes('youtube.com/watch?v=')) {
youtube.setKey(process.env.YOUTUBE_APIKEY)
const search = util.promisify(youtube.search)
const { items } = await search(args.slice(2).join(' '), 1).catch(e => logger.error(e))
keyword = args.slice(2).join(' ')
args[2] = 'https://youtube.com/watch?v=' + items[0].id.videoId // ugly hack :(
}
msg.member.voice.channel.join()
.then(async connection => {
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed) {
if (loop[msg.guild.id].enabled) return msg.channel.send(lang.COMMAND_MUSIC_CANTADD_LOOP_ENABLED)
if (!queue[msg.guild.id]) queue[msg.guild.id] = []
queue[msg.guild.id].push(args[2])
msg.channel.send(f(lang.COMMAND_MUSIC_QUEUE_ADDED, args[2]))
if (keyword) msg.channel.send('検索キーワード: ' + keyword)
} else {
await play(connection, args[2], msg)
msg.channel.send(f(lang.COMMAND_MUSIC_PLAYING, args[2]))
if (keyword) msg.channel.send('検索キーワード: ' + keyword)
}
if (msg.deletable) msg.delete()
const endHandler = async () => {
const q = queue[msg.guild.id]
if (q && (q ? q.length : false) && !loop[msg.guild.id].enabled) { // if queue is *not* empty and not enabled loop
await play(connection, q[0], msg)
msg.channel.send(f(lang.COMMAND_MUSIC_PLAYING_QUEUE, q[0]))
queue[msg.guild.id] = queue[msg.guild.id].slice(1)
} else { // if queue is empty or enabled looping
if (!loop[msg.guild.id].enabled && !loop[msg.guild.id].every) { // loop is disabled
msg.channel.send(lang.COMMAND_MUSIC_ENDED)
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher)
msg.guild.voice.connection.dispatcher.removeListener('end', endHandler)
} else { // loop is enabled
if (loop[msg.guild.id].every) {
const seconds = parseInt(loop[msg.guild.id].every.replace(/\D{1,}/gm, '')) * 60
setTimeout(() => {
play(connection, args[2], msg)
}, seconds * 1000)
} else {
await play(connection, args[2], msg)
}
}
}
}
msg.guild.voice.connection.dispatcher.on('end', endHandler)
})
} else if (args[1] === 'volume') {
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed) {
const before = msg.guild.voice.connection.dispatcher.volume
if (!isNumber(args[2])) return msg.channel.send(`:loud_sound: 現在の音量は${msg.guild.voice.connection.dispatcher.volume}です。`)
msg.guild.voice.connection.dispatcher.setVolume(parseInt(args[2]) / 100)
const emoji = before * 100 <= parseInt(args[2]) ? ':loud_sound:' : ':sound:'
msg.channel.send(f(emoji + lang.COMMAND_MUSIC_CHANGED_VOLUME, before * 100, parseInt(args[2]))) // oldvalue: 100
} else return msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING)
} else if (args[1] === 'skip') {
if (!loop[msg.guild.id].enabled && msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed) {
msg.guild.voice.connection.dispatcher.end() // Just stop the music and send end event, and play queue.
} else return msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING + ' ...or enabled loop.')
} else if (args[1] === 'stop') {
queue[msg.guild.id] = []
if (msg.guild.voice.connection && !msg.guild.voice.connection.dispatcher) {
msg.guild.voice.connection.dispatcher.destroy() // destroy.
if (msg.guild.me.voice && msg.guild.me.voice.channel && msg.guild.me.voice.channel.connection) msg.guild.me.voice.channel.connection.disconnect()
msg.channel.send(':wave:')
} else return msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING)
} else if (args[1] === 'loop') {
Object.assign({[msg.guild.id]: []}, queue)
//queue.push({[msg.guild.id]: []})
if (args[2] === 'disable') {
loop[msg.guild.id].every = null
loop[msg.guild.id].enabled = false
msg.channel.send(lang.COMMAND_MUSIC_DISABLED_LOOPING)
} else {
if (args[2] === 'every') {
if (args[3] === 'clear') return loop[msg.guild.id].every = null
if (!/\d{1,}m/gm.test(args[3])) return msg.channel.send(lang._invalid_args)
loop[msg.guild.id].enabled = true
loop[msg.guild.id].every = args[3]
msg.channel.send(f(lang.COMMAND_MUSIC_LOOP_EVERY, args[3]))
} else {
loop[msg.guild.id].enabled = loop[msg.guild.id].enabled ? false : true
msg.channel.send(f(lang.COMMAND_MUSIC_ONE_MUSIC_LOOP, loop[msg.guild.id].enabled ? lang.COMMAND_MUSIC_ENABLED : lang.COMMAND_MUSIC_DISABLED))
}
}
} else if (args[1] === 'pause') {
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed) {
msg.guild.voice.connection.dispatcher.pause()
msg.channel.send(lang.COMMAND_MUSIC_PAUSED)
} else msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING)
} else if (args[1] === 'unpause' || args[1] === 'resume') {
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed) {
msg.guild.voice.connection.dispatcher.resume()
msg.channel.send(lang.COMMAND_MUSIC_UNPAUSED)
} else msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING)
} else if (args[1] === 'queue') {
msg.channel.send(f(lang.COMMAND_MUSIC_QUEUE_COUNT, queue.length))
if (args[2] === 'clear') {
queue[msg.guild.id] = []
return msg.channel.send(lang.COMMAND_MUSIC_CLEARED_QUEUE)
} else if (args[2] === 'reactivate') {
return msg.channel.send(f('```\n{0}music stop\n{0}music play https://www.youtube.com/watch?v=jhFDyDgMVUI\n```', prefix))
}
const queues = queue[msg.guild.id] ? queue[msg.guild.id].map((e, i) => `${i}: ${e}`) : []
if (queues.length) msg.channel.send(queues.join('\n'))
} else if (args[1] === 'status') {
if (msg.guild.voice.connection && msg.guild.voice.connection.dispatcher && !msg.guild.voice.connection.dispatcher.destroyed && playing[msg.guild.id]) msg.channel.send(f(lang.COMMAND_MUSIC_NOW_PLAYING, playing[msg.guild.id]))
else msg.channel.send(lang.COMMAND_MUSIC_NOT_PLAYING)
} else msg.channel.send(lang._invalid_args)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment