covilbot
Version:
Slack bot which connects with Mopidy and Spotify
234 lines (200 loc) • 6.1 kB
JavaScript
var EventEmitter = require('events').EventEmitter
var util = require('util')
var Entities = require('html-entities').AllHtmlEntities
var entities = new Entities()
var Yargs = require('yargs/yargs')
var CLIENT_EVENTS = require('@slack/client').CLIENT_EVENTS
var RTM_EVENTS = require('@slack/client').RTM_EVENTS
'use strict'
module.exports = {
DopeBot: DopeBot
}
function DopeBot (logger, slack, mopidy, spotify, settings) {
this.logger = logger
this.slack = slack
this.mopidy = mopidy
this.spotify = spotify
this.settings = settings
this.channels = {}
this.params = this.settings.params
this.attachments = this.settings.attachments
this.state = {}
this.search = {results: {}, hits: 0}
this.commands = []
this.yargs = new Yargs()
.usage('Usage: <command> [options]')
.commandDir('commands', {
visit: function (command) {
this.commands.push(command)
return command
}.bind(this)
})
.help('help')
.alias('help', 'h')
.locale('en')
}
util.inherits(DopeBot, EventEmitter)
DopeBot.prototype.post = function (message, params) {
params = params || this.params
if (Array.isArray(message)) {
params = Object.assign({attachments: message}, params)
message = null
} else {
message = entities.decode(message)
}
this.slack.web.chat.postMessage(this.channel.id, message, params)
}
DopeBot.prototype.run = function () {
this.logger.info('Starting covilbot', this.settings)
this._init()
this.mopidy.connect()
this.slack.rtm.start()
}
DopeBot.prototype.getState = function (full) {
var self = this
if (full) {
this.mopidy.playback.getState()
.done(function (state) {
self.state.state = state
})
this.mopidy.playback.getCurrentTlTrack()
.done(function (tlTrack) {
self.state.tlTrack = tlTrack
})
this.mopidy.mixer.getVolume()
.done(function (volume) {
self.state.volume = volume
})
}
this.mopidy.tracklist.getConsume()
.done(function (value) {
self.state.consume = value
})
this.mopidy.tracklist.getRandom()
.done(function (value) {
self.state.random = value
})
this.mopidy.tracklist.getRepeat()
.done(function (value) {
self.state.repeat = value
})
this.mopidy.tracklist.getSingle()
.done(function (value) {
self.state.single = value
})
}
DopeBot.prototype.updateHistoryState = function () {
if (!this.state.tlTrack) {
return
}
this.state.history = this.getHistoryState(this.state.tlTrack.tlid)
}
DopeBot.prototype.getUserById = function (id) {
for (var u in this.info.users) {
if (this.info.users[u].id === id) {
return this.info.users[u]
}
}
return null
}
DopeBot.prototype.getHistoryState = function (tlid) {
for (var user in this.history) {
var tlTrack = this.history[user].tracks[tlid]
if (tlTrack) {
return {
user: this.getUserById(user)
}
}
}
return null
}
DopeBot.prototype._init = function () {
var self = this
if (this.settings.history === true) {
this.history = {}
this.on('tracklist:add', function (message, tlTracks) {
if (!self.history[message.user]) {
self.history[message.user] = {
tracks: {}
}
}
for (var i in tlTracks) {
var tlTrack = tlTracks[i]
self.history[message.user].tracks[tlTrack.tlid] = {
track: tlTrack,
timestamp: Date.now()
}
}
})
this.on('tracklist:clear', function () {
self.history = {}
})
}
this.mopidy.on('state:online', function () {
self.logger.info('Connected to Mopidy')
})
this.slack.rtm.on(CLIENT_EVENTS.RTM.AUTHENTICATED, function (rtmStartData) {
self.info = rtmStartData
self.baseRegEx = self.settings.dialog === true ? new RegExp('^@' + self.info.self.id + ':?[ ]+(.*)', 'g') : /^(.*)/g
self.channel = self.info.channels.find(function (channel) {
return channel.name === self.settings.channel
})
self.logger.info('Connected to Slack. I am %s', self.info.self.id)
self.post('Hi there, I\'m your DJ tonite! :notes: What can I do you for?')
self.getState(true)
})
this.mopidy.on('event:trackPlaybackStarted', function (event) {
self.logger.info('Track playback started: ' + event.tl_track.track.name)
self.state.tlTrack = event.tl_track
if (self.settings.history === true) {
self.updateHistoryState()
}
self.post(self.attachments.state(self.state))
})
this.mopidy.on('event:volumeChanged', function (event) {
self.logger.info('Volume changed')
self.state.volume = event.volume
})
this.mopidy.on('event:playbackStateChanged', function (event) {
self.logger.info('Playback state changed')
self.state.state = event.new_state
})
this.mopidy.on('event:optionsChanged', function () {
self.logger.info('Playback options changed')
self.getState()
})
this.slack.rtm.on(RTM_EVENTS.MESSAGE, function (message) {
self.logger.debug('Received message', message)
if (self.channel.id !== message.channel || message.type !== 'message' || !message.text || message.username === self.params.username) {
return
}
// remove slack URL formatting
message.text = message.text.replace(/[<>]/g, '').trim()
var matches = message.text.match(self.baseRegEx)
if (matches) {
message.text = matches[0]
} else {
return
}
self.yargs.parse(message.text, {
db: self,
message: message
}, function (exitError, parsed, output) {
if (parsed.help) {
var commands
if (parsed._.length > 0) {
const identifier = parsed._[0]
commands = self.commands.filter(command => {
if (command.command.split(' ')[0] === identifier) {
return true
}
return command.aliases ? command.aliases.some(alias => alias === identifier) : false
})
} else {
commands = self.commands
}
self.post(self.attachments.help(commands.length === 0 ? self.commands : commands))
}
})
})
}