mirror of https://github.com/icedream/ts3bot.git
287 lines
9.0 KiB
CoffeeScript
287 lines
9.0 KiB
CoffeeScript
Sync = require "sync"
|
|
|
|
config = require("./config")
|
|
getLogger = require("./logger")
|
|
services = require("./services")
|
|
sync = require "sync"
|
|
request = require "request"
|
|
fs = require("fs")
|
|
path = require("path")
|
|
qs = require "querystring"
|
|
youtubedl = require "youtube-dl"
|
|
isValidUrl = (require "valid-url").isWebUri
|
|
|
|
log = getLogger "Main"
|
|
|
|
# http://stackoverflow.com/a/7117336
|
|
removeBB = (str) -> str.replace /\[(\w+)[^\]]*](.*?)\[\/\1]/g, "$2"
|
|
|
|
module.exports =
|
|
shutdown: (cb) =>
|
|
apiService = services.find("api")
|
|
if apiService and apiService.state == "started"
|
|
await apiService.stop defer(err)
|
|
if err
|
|
cb? new Error "Could not stop API"
|
|
return
|
|
|
|
ts3clientService = services.find("ts3client")
|
|
if ts3clientService and ts3clientService.state == "started"
|
|
await ts3clientService.stop defer(err)
|
|
if err
|
|
cb? new Error "Could not stop TeamSpeak3"
|
|
return
|
|
|
|
log.debug "Shutting down services..."
|
|
await services.shutdown defer(err)
|
|
if err
|
|
cb? new Error "Error while shutting down rest of services."
|
|
log.debug "Services shut down."
|
|
|
|
cb?()
|
|
shutdownSync: => Sync @shutdown
|
|
|
|
# PulseAudio daemon
|
|
await services.find("pulseaudio").start defer err
|
|
if err
|
|
log.warn "PulseAudio could not start up, audio may not act as expected!"
|
|
|
|
# VLC HTTP API
|
|
await services.find("vlc").start defer err
|
|
if err
|
|
log.warn "VLC could not start up!"
|
|
await module.exports.shutdown defer()
|
|
process.exit 1
|
|
vlc = services.find("vlc").instance
|
|
vlc.status.volume 127 # that's 50% (about half of 0xFF)
|
|
|
|
# TeamSpeak3
|
|
ts3clientService = services.find("ts3client")
|
|
|
|
ts3clientService.on "started", (ts3proc) =>
|
|
ts3query = ts3clientService.query
|
|
|
|
ts3query.currentScHandlerID = 1
|
|
ts3query.mydata = {}
|
|
|
|
ts3query.on "open", =>
|
|
log.info "TS3 query now ready."
|
|
|
|
attempts = 0
|
|
err = null
|
|
init = true
|
|
while init or err != null
|
|
init = false
|
|
if err
|
|
attempts++
|
|
if attempts == 10
|
|
log.error "Could not register to TeamSpeak3 client events, giving up!"
|
|
break
|
|
else
|
|
log.warn "Could not register to TeamSpeak3 client events!", err
|
|
for eventName in [
|
|
"notifytalkstatuschange"
|
|
"notifyconnectstatuschange"
|
|
"notifytextmessage"
|
|
"notifyclientupdated"
|
|
"notifycliententerview"
|
|
"notifyclientleftview"
|
|
"notifyclientchatclosed"
|
|
"notifyclientchatcomposing"
|
|
"notifyclientchannelgroupchanged"
|
|
"notifyclientmoved"
|
|
]
|
|
await ts3query.clientnotifyregister ts3query.currentScHandlerID, eventName, defer(err)
|
|
if err
|
|
break
|
|
|
|
ts3query.on "message.selected", (args) =>
|
|
if args["schandlerid"]
|
|
ts3query.currentScHandlerID = parseInt args["schandlerid"]
|
|
|
|
ts3query.on "message.notifytalkstatuschange", (args) =>
|
|
await ts3query.use args.schandlerid, defer(err, data)
|
|
|
|
ts3query.on "message.notifyconnectstatuschange", (args) =>
|
|
await ts3query.use args.schandlerid, defer(err, data)
|
|
|
|
if args.status == "disconnected" and ts3clientService.state != "stopping"
|
|
log.warn "Disconnected from TeamSpeak server, reconnecting in a few seconds..."
|
|
ts3clientService.stopSync()
|
|
setTimeout (() => ts3clientService.restartSync()), 8000
|
|
|
|
if args.status == "connecting"
|
|
log.info "Connecting to TeamSpeak server..."
|
|
|
|
if args.status == "connection_established"
|
|
log.info "Connected to TeamSpeak server."
|
|
|
|
ts3query.on "message.notifyclientupdated", (args) =>
|
|
await ts3query.use args.schandlerid, defer(err, data)
|
|
await ts3query.whoami defer(err, data)
|
|
if not err
|
|
ts3query.mydata = data
|
|
|
|
ts3query.on "message.notifytextmessage", (args) =>
|
|
await ts3query.use args.schandlerid, defer(err, data)
|
|
|
|
msg = args.msg
|
|
invoker = { name: args.invokername, uid: args.invokeruid, id: args.invokerid }
|
|
targetmode = args.targetmode # 1 = private, 2 = channel
|
|
|
|
log.info "<#{invoker.name}> #{msg}"
|
|
|
|
# cheap argument parsing here
|
|
firstSpacePos = msg.indexOf " "
|
|
if firstSpacePos == 0
|
|
return
|
|
if firstSpacePos > 0
|
|
name = msg.substring 0, firstSpacePos
|
|
paramline = msg.substring firstSpacePos + 1
|
|
params = paramline.match(/'[^']*'|"[^"]*"|[^ ]+/g) || [];
|
|
else
|
|
name = msg
|
|
paramline = ""
|
|
params = []
|
|
|
|
switch name.toLowerCase()
|
|
when "play"
|
|
inputBB = paramline.trim()
|
|
|
|
# we gonna interpret play without a url as an attempt to unpause the current song
|
|
if inputBB.length <= 0
|
|
vlc.status.resume()
|
|
return
|
|
|
|
input = removeBB inputBB
|
|
|
|
# only allow playback from file if it's a preconfigured alias
|
|
if isValidUrl input
|
|
log.debug "Got input URL:", input
|
|
else
|
|
input = config.get "aliases:#{input}"
|
|
if not(isValidUrl input) and not(fs.existsSync input)
|
|
log.debug "Got neither valid URL nor valid alias:", input
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot."
|
|
return
|
|
|
|
# TODO: permission system to check if uid is allowed to play this url or alias
|
|
|
|
await vlc.status.empty defer(err)
|
|
if err
|
|
log.warn "Couldn't empty VLC playlist", err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, an error occurred. Try again later."
|
|
return
|
|
|
|
# let's give youtube-dl a shot!
|
|
await youtubedl.getInfo input, [
|
|
"--format=bestaudio"
|
|
], defer(err, info)
|
|
if err or not info?
|
|
log.debug "There is no audio-only download for #{inputBB}, downloading full video instead."
|
|
await youtubedl.getInfo input, [
|
|
"--format=best"
|
|
], defer(err, info)
|
|
if err or not info?
|
|
info =
|
|
url: input
|
|
if not info.url?
|
|
info.url = input
|
|
info.title = input # URL as title
|
|
|
|
await vlc.status.play info.url, defer(err)
|
|
if err
|
|
vlc.status.empty()
|
|
log.warn "VLC API returned an error when trying to play", err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Something seems to be wrong with that media. Maybe check the URL/sound name you provided?"
|
|
return
|
|
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Now playing [URL=#{input}]#{info.title}[/URL]."
|
|
when "next"
|
|
await vlc.status.next defer(err)
|
|
if err
|
|
vlc.status.empty()
|
|
log.warn "VLC API returned an error when trying to skip current song", err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "This unfortunately didn't work out, I'm sorry."
|
|
return
|
|
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Going to the next playlist entry."
|
|
when "enqueue"
|
|
inputBB = paramline
|
|
input = removeBB paramline
|
|
|
|
# only allow playback from file if it's a preconfigured alias
|
|
if isValidUrl input
|
|
log.debug "Got input URL:", input
|
|
else
|
|
input = config.get "aliases:#{input}"
|
|
if not(isValidUrl input) and not(fs.existsSync input)
|
|
log.debug "Got neither valid URL nor valid alias:", input
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot."
|
|
return
|
|
|
|
# TODO: permission system to check if uid is allowed to play this url or alias
|
|
|
|
# let's give youtube-dl a shot!
|
|
await youtubedl.getInfo input, [
|
|
"--format=bestaudio"
|
|
], defer(err, info)
|
|
if err or not info?
|
|
log.debug "There is no audio-only download for #{inputBB}, downloading full video instead."
|
|
await youtubedl.getInfo input, [
|
|
"--format=best"
|
|
], defer(err, info)
|
|
if err or not info?
|
|
info =
|
|
url: input
|
|
if not info.url?
|
|
info.url = input
|
|
info.title = input # URL as title
|
|
|
|
await vlc.status.enqueue info.url, defer(err)
|
|
if err
|
|
vlc.status.empty()
|
|
log.warn "VLC API returned an error when trying to play", err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Something seems to be wrong with that media. Maybe check the URL/sound name you provided?"
|
|
return
|
|
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Now playing [URL=#{input}]#{info.title}[/URL]."
|
|
when "stop"
|
|
await vlc.status.stop defer(err)
|
|
|
|
vlc.status.empty()
|
|
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Stopped playback."
|
|
when "vol"
|
|
vol = parseInt paramline
|
|
|
|
if paramline.trim().length <= 0 or vol > 511 or vol < 0
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "The [b]vol[/b] command takes a number between 0 (0%) and 511 (200%) to set the volume. 100% is 127."
|
|
return
|
|
|
|
await vlc.status.volume paramline, defer(err)
|
|
|
|
if err
|
|
log.warn "Failed to set volume", err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "That unfortunately didn't work out."
|
|
return
|
|
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Volume set."
|
|
when "changenick"
|
|
nick = if paramline.length > params[0].length then paramline else params[0]
|
|
if nick.length < 1 or nick.length > 32
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "Invalid nickname."
|
|
return
|
|
Sync () =>
|
|
try
|
|
ts3query.clientupdate.sync ts3query, { client_nickname: nick }
|
|
catch err
|
|
ts3query.sendtextmessage args.targetmode, invoker.id, "That unfortunately didn't work out."
|
|
log.warn "ChangeNick failed, error information:", err
|
|
|
|
await ts3clientService.start [ config.get("ts3-server") ], defer(err, ts3proc)
|
|
if err
|
|
log.error "TeamSpeak3 could not start, shutting down."
|
|
await module.exports.shutdown defer()
|
|
process.exit 1
|