diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..2150236 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "es6": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "no-console": "off", + "indent": [ + "error", + "tab" + ], + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "warn", + "single" + ], + "semi": [ + "warn", + "always" + ] + } +} diff --git a/.gitignore b/.gitignore index cd2946a..53689ba 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,9 @@ $RECYCLE.BIN/ Network Trash Folder Temporary Items .apdisk + +# Ignores +node_modules/* + +start.bat +tokens.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..59f56ce --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 BDISTIN + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/package.json b/package.json new file mode 100644 index 0000000..881aa53 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "ohgodmusicbot", + "version": "1.0.0", + "description": "A v9 Discord.JS music bot in 100 lines or less", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "dependencies": { + "discord.js" : "github:hydrabolt/discord.js#indev", + "ytdl-core" : "github:fent/node-ytdl-core#master", + }, + "author": "BDISTIN", + "license": "MIT" +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..2cc0c98 --- /dev/null +++ b/server.js @@ -0,0 +1,100 @@ +const Discord = require('discord.js'); +const yt = require('ytdl-core'); +const tokens = require('./tokens.json'); +const client = new Discord.Client(); +let queue = {}; +client.on('message', msg => { + if (msg.content.startsWith(tokens.prefix + 'play')) { + if (queue[msg.guild.id].playing) return msg.channel.sendMessage('Already Playing'); + if (queue[msg.guild.id] === undefined) return msg.channel.sendMessage('Add some songs to the queue first with ++add'); + if (!client.voiceConnections.exists('channel', msg.member.voiceChannel)) return msg.channel.sendMessage('Join me to a voice channel with ++join first'); + let myVoiceConnection = client.voiceConnections.find('channel', msg.member.voiceChannel); + let dispatcher; + console.log(queue); + (function play(song) { + queue[msg.guild.id].playing = true; + console.log(song); + if (song === undefined) { + msg.channel.sendMessage('Queue is empty'); + queue[msg.guild.id].playing = false; + msg.member.voiceChannel.leave(); + return; + } + msg.channel.sendMessage(`Playing: **${song.title}**`); + dispatcher = myVoiceConnection.playStream(yt(song.url, { audioonly: true })); + let collector = msg.channel.createCollector(m => m); + collector.on('message', m => { + if (m.content.startsWith(tokens.prefix + 'pause')) { + dispatcher.pause(); + msg.channel.sendMessage('paused'); + } else if (m.content.startsWith(tokens.prefix + 'resume')){ + dispatcher.resume(); + msg.channel.sendMessage('resumed'); + } else if (m.content.startsWith(tokens.prefix + 'skip')){ + dispatcher.end(); + msg.channel.sendMessage('skipped'); + } else if (m.content.startsWith('volume+')){ + if (Math.round(dispatcher.volume*100) >= 100) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*100)}%`); + const amount = m.content.split('+').length-1; + dispatcher.setVolume(Math.max((dispatcher.volume*100 + 4*amount)/100,1)); + msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`); + } else if (m.content.startsWith('volume-')){ + if (Math.round(dispatcher.volume*100) <= 0) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*100)}%`); + const amount = m.content.split('-').length-1; + dispatcher.setVolume(Math.min((dispatcher.volume*100 - 4*amount)/100,0)); + msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`); + } + }); + dispatcher.on('end', () => { + setTimeout(()=>{ + collector.stop(); + queue[msg.guild.id].songs.shift(); + play(queue[msg.guild.id].songs[0]); + }, 1000); + }); + dispatcher.on('error', (err) => { + collector.stop(); + queue[msg.guild.id].songs.shift(); + queue[msg.guild.id].playing = false; + msg.channel.sendMessage('error: ' + err); + msg.member.voiceChannel.leave(); + return; + }); + })(queue[msg.guild.id].songs[0]); + } else if (msg.content.startsWith(tokens.prefix + 'join')) { + const voiceChannel = msg.member.voiceChannel; + if (!voiceChannel || voiceChannel.type !== 'voice') return msg.reply('I couldn\'t connect to your voice channel...'); + voiceChannel.join(); + } else if (msg.content.startsWith(tokens.prefix + 'add')) { + let url = msg.content.slice(6); + yt.getInfo(url, (err, info) => { + if(err) return msg.channel.sendMessage('Invalid YouTube Link: ' + err); + if (!queue.hasOwnProperty(msg.guild.id)) { + queue[msg.guild.id] = {}; + queue[msg.guild.id].playing = false; + queue[msg.guild.id].songs = []; + } + queue[msg.guild.id].songs.push({url: url, title: info.title}); + msg.channel.sendMessage(`added **${info.title}** to the queue`); + }); + } else if (msg.content.startsWith(tokens.prefix + 'help')) { + let tosend = ['```xl', + '++join : "Join Voice channel of msg sender"', + '++add : "Add a valid youtube link to the queue"', + '++play : "Play the music queue if already joined to a voice channel', + '++pause : "pauses the music, only available while play command is running."', + '++resume : "resumes the music, only available while play command is running."', + '++skip : "skips the playing song, only available while play command is running."', + 'volume+(+++) : "increases volume by 2%/+, only available while play command is running."', + 'volume+(---) : "decreases volume by 2%/-, only available while play command is running."', + 'notes : "commands are case sensitive, because I want to be a lazy ass on this bot."', + '```']; + msg.channel.sendMessage(tosend.join('\n')); + } else if (msg.content.startsWith(tokens.prefix + 'reboot')) { + if (msg.author.id == tokens.adminID) process.exit(); + } +}); +client.login(tokens.d_token); +client.on('ready', () => { + console.log('ready!'); +}); diff --git a/tokens.json.example b/tokens.json.example new file mode 100644 index 0000000..a405ec8 --- /dev/null +++ b/tokens.json.example @@ -0,0 +1,3 @@ +{ + "d_token" : "YOUR DISCORD APP TOKEN", +}