parent
a984f43458
commit
3c4071b245
@ -0,0 +1 @@
|
|||||||
|
*~
|
||||||
@ -1,2 +1,28 @@
|
|||||||
# MPD_Jabber_bot
|
# MPD Jabber bot
|
||||||
|
|
||||||
|
Jabber/XMPP bot that controls streaming MPD instance.
|
||||||
|
|
||||||
|
This software is written in Ruby and allows you to control mpd server with simple commands written in MUC chat.
|
||||||
|
|
||||||
|
It can skip to prev/next song, play/pause/stop playback, control outputs, return info about current song and song which will be played next.
|
||||||
|
|
||||||
|
This software is still in alpha stage. It works for me so I can't promise updates in near future. Feel free to send me a patch if you want. I'll consider merging them.
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
* Create persistent config file
|
||||||
|
* Code cleanup
|
||||||
|
* Possibly add some more features
|
||||||
|
* Make it work in all versions of private messages
|
||||||
|
|
||||||
|
Do:
|
||||||
|
|
||||||
|
<botnick>: help
|
||||||
|
|
||||||
|
to get basic usage help.
|
||||||
|
|
||||||
|
This bot depends on following ruby modules:
|
||||||
|
|
||||||
|
* rubygems
|
||||||
|
* jabbot
|
||||||
|
* ruby-mpd
|
||||||
@ -0,0 +1,294 @@
|
|||||||
|
#!/usr/bin/ruby
|
||||||
|
$VERBOSE = nil
|
||||||
|
$BOTVERSION = "beta 0.0.1"
|
||||||
|
scriptname = "botik.rb" # When its changed, bot will switch to dev mode
|
||||||
|
|
||||||
|
botnick = "StreamCtl"
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
require 'jabbot'
|
||||||
|
require 'ruby-mpd'
|
||||||
|
|
||||||
|
mpd = MPD.new 'localhost', 6600
|
||||||
|
mpd.connect
|
||||||
|
|
||||||
|
class MPD
|
||||||
|
def outputs
|
||||||
|
send_command 'outputs'
|
||||||
|
end
|
||||||
|
|
||||||
|
def pause
|
||||||
|
send_command 'pause'
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputstatus(list)
|
||||||
|
outputs = outputrefresh()
|
||||||
|
if list.kind_of?(Array) then
|
||||||
|
conout = Hash.new
|
||||||
|
list.each {
|
||||||
|
|out|
|
||||||
|
conout[out.to_i] = outputs[out]
|
||||||
|
}
|
||||||
|
return conout
|
||||||
|
else
|
||||||
|
return outputs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputtoggle(out)
|
||||||
|
out = out.to_i
|
||||||
|
outputs = outputrefresh()
|
||||||
|
if outputs[out].status == 0 then
|
||||||
|
send_command "enableoutput #{out}"
|
||||||
|
else
|
||||||
|
send_command "disableoutput #{out}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputrefresh
|
||||||
|
outarray = send_command 'outputs'
|
||||||
|
i = 0
|
||||||
|
outputs = Hash.new
|
||||||
|
Struct.new("Output", :name, :status)
|
||||||
|
until(outarray.length < 1)
|
||||||
|
line = outarray[0]
|
||||||
|
outid = line[:outputid].to_i
|
||||||
|
outname = line[:outputname]
|
||||||
|
outstatus = (line[:outputenabled] ? 1 : 0) # Conversion to int
|
||||||
|
outputs[outid] = Struct::Output.new(outname, outstatus)
|
||||||
|
outarray.shift
|
||||||
|
end
|
||||||
|
return outputs
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputstatus(list)
|
||||||
|
outputs = outputrefresh()
|
||||||
|
if list.kind_of?(Array) then
|
||||||
|
conout = Hash.new
|
||||||
|
list.each {
|
||||||
|
|out|
|
||||||
|
conout[out.to_i] = outputs[out]
|
||||||
|
}
|
||||||
|
return conout
|
||||||
|
else
|
||||||
|
return outputs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputtoggle(out)
|
||||||
|
out = out.to_i
|
||||||
|
outputs = outputrefresh()
|
||||||
|
if outputs[out].status == 0 then
|
||||||
|
send_command "enableoutput #{out}"
|
||||||
|
else
|
||||||
|
send_command "disableoutput #{out}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def nextsong
|
||||||
|
stat = send_command "status"
|
||||||
|
nsid = stat[:nextsongid]
|
||||||
|
return send_command "playlistid #{nsid}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mpdcontrol(mpd,request, mess, type)
|
||||||
|
arr = mess.text.split(/\W+/)
|
||||||
|
if arr[2].nil? == false then
|
||||||
|
if arr[2].chomp.strip != "" then
|
||||||
|
param = arr[2].chomp.strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def outputsctl (outputs,sitelink)
|
||||||
|
reply = ""
|
||||||
|
def site_state_translate (input)
|
||||||
|
if input == 0 then
|
||||||
|
return "off"
|
||||||
|
else
|
||||||
|
return "on"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
outputs.each {
|
||||||
|
|key,var|
|
||||||
|
outfile = var[:name].split.last
|
||||||
|
weblink = ""
|
||||||
|
case outfile
|
||||||
|
when "HQ"
|
||||||
|
file = "hi.ogg"
|
||||||
|
when "LQ"
|
||||||
|
file = "lo.ogg"
|
||||||
|
when "MP3"
|
||||||
|
file = "stream.mp3"
|
||||||
|
end
|
||||||
|
reply = reply+"#{key} - #{sitelink}/#{file} - #{site_state_translate(var.status)}\n"
|
||||||
|
}
|
||||||
|
return reply
|
||||||
|
end
|
||||||
|
|
||||||
|
status = mpd.status[:state].to_s.downcase
|
||||||
|
case request
|
||||||
|
when "status"
|
||||||
|
if status == "stop" then
|
||||||
|
sticon = "◼"
|
||||||
|
else
|
||||||
|
status == "play" ? sticon = "▶" : sticon = "▮▮"
|
||||||
|
end
|
||||||
|
song = mpd.current_song
|
||||||
|
if song.name != nil then
|
||||||
|
answer = "Stream: #{song.name} .:. #{song.title} @ #{song.file}"
|
||||||
|
else
|
||||||
|
answer = "#{song.artist} - #{song.title} [album #{song.album}]"
|
||||||
|
end
|
||||||
|
|
||||||
|
song = mpd.current_song
|
||||||
|
if song.name != nil then
|
||||||
|
# do nothing
|
||||||
|
else
|
||||||
|
ns = mpd.nextsong
|
||||||
|
answer = "#{answer}\nNext song in queue: #{ns[:artist]} - #{ns[:title]} [album #{ns[:album]}]"
|
||||||
|
end
|
||||||
|
if type == "0" then
|
||||||
|
post "#{sticon} #{answer}"
|
||||||
|
else
|
||||||
|
post "#{sticon} #{answer}" => mess.user
|
||||||
|
end
|
||||||
|
when "play"
|
||||||
|
mpd.play
|
||||||
|
when "pause"
|
||||||
|
mpd.pause
|
||||||
|
when "stop"
|
||||||
|
mpd.stop
|
||||||
|
when "prev"
|
||||||
|
mpd.previous
|
||||||
|
when "next"
|
||||||
|
mpd.next
|
||||||
|
when "nextsong"
|
||||||
|
song = mpd.current_song
|
||||||
|
if song.name != nil then
|
||||||
|
answer = "MPD is playing external stream. I can't get next song info."
|
||||||
|
else
|
||||||
|
ns = mpd.nextsong
|
||||||
|
answer = "Next song in queue: #{ns[:artist]} - #{ns[:title]} [album #{ns[:album]}]"
|
||||||
|
end
|
||||||
|
if type == "0" then
|
||||||
|
post answer
|
||||||
|
else
|
||||||
|
post answer => mess.user
|
||||||
|
end
|
||||||
|
|
||||||
|
when "toggle"
|
||||||
|
if param.nil? == false then
|
||||||
|
if param.to_i >= 0 and param.to_i <= 2 then
|
||||||
|
mpd.outputtoggle param.to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
when "info"
|
||||||
|
if status == "stop" then
|
||||||
|
sticon = "◼"
|
||||||
|
else
|
||||||
|
status == "play" ? sticon = "▶" : sticon = "▮▮"
|
||||||
|
end
|
||||||
|
song = mpd.current_song
|
||||||
|
if song.name != nil then
|
||||||
|
answer = "Stream: #{song.name} .:. #{song.title} @ #{song.file}"
|
||||||
|
else
|
||||||
|
answer = "#{song.artist} - #{song.title} [album #{song.album}]"
|
||||||
|
end
|
||||||
|
if song.name != nil then
|
||||||
|
nsanswer = "MPD is playing external stream. I can't get next song info."
|
||||||
|
else
|
||||||
|
ns = mpd.nextsong
|
||||||
|
nsanswer = "Next song in queue: #{ns[:artist]} - #{ns[:title]} [album #{ns[:album]}]"
|
||||||
|
end
|
||||||
|
sitelink = "https://stream.example.com"
|
||||||
|
outputs = mpd.outputstatus([0, 1, 2])
|
||||||
|
outs = outputsctl(outputs,sitelink)
|
||||||
|
|
||||||
|
if type == "0" then
|
||||||
|
post "#{sticon} #{answer}\n#{nsanswer}\nOutputs:\n#{outs}"
|
||||||
|
else
|
||||||
|
post "#{sticon} #{answer}\n#{nsanswer}\nOutputs:\n#{outs}" => mess.user
|
||||||
|
end
|
||||||
|
when "outputs"
|
||||||
|
sitelink = "https://stream.example.com"
|
||||||
|
outputs = mpd.outputstatus([0, 1, 2])
|
||||||
|
if type == "0" then
|
||||||
|
post outputsctl(outputs,sitelink)
|
||||||
|
else
|
||||||
|
post outputsctl(outputs,sitelink) => mess.user
|
||||||
|
end
|
||||||
|
when "version"
|
||||||
|
if type == "0" then
|
||||||
|
post "Pitriss MPD stream control bot, version #{$BOTVERSION}"
|
||||||
|
else
|
||||||
|
post "Pitriss MPD stream control bot, version #{$BOTVERSION}" => mess.user
|
||||||
|
end
|
||||||
|
when "help"
|
||||||
|
answer = "Stream is located at https://stream.example.com/xyz.ext (see outputs)\n
|
||||||
|
Commands:\n
|
||||||
|
status - Info about played track
|
||||||
|
nestsong - Info about next song in queue
|
||||||
|
info - Verbose info about most relevant aspects
|
||||||
|
outputs - list all outputs available and its status
|
||||||
|
toggle <output number> - toggle state of output
|
||||||
|
play - start MPD
|
||||||
|
pause - pause MPD
|
||||||
|
stop - stops MPD
|
||||||
|
next - next song
|
||||||
|
prev - previous song\n\n
|
||||||
|
For more info ask in room. (eg howto access playlist control)"
|
||||||
|
if type == "0" then
|
||||||
|
post answer
|
||||||
|
else
|
||||||
|
post answer => mess.user
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if type == "0" then
|
||||||
|
post "Are you kiddin' me? That's complete bullshit! I don't believe single word you told me! Maybe you can try again with \"help\"?"
|
||||||
|
else
|
||||||
|
post "Are you kiddin' me? That's complete bullshit! I don't believe single word you told me! Maybe you can try again with \"help\"?" => mess.user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
configure do |conf|
|
||||||
|
conf.login = "bot@example.com"
|
||||||
|
conf.password = "ChangeMe"
|
||||||
|
# conf.nick = "StreamCtl"
|
||||||
|
conf.nick = botnick
|
||||||
|
conf.resource = "StreamCtl"
|
||||||
|
if scriptname == File.basename($0) then
|
||||||
|
conf.channel = "some-room"
|
||||||
|
else
|
||||||
|
conf.channel = "botdev"
|
||||||
|
end
|
||||||
|
conf.server = "conf.example.com"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
message(/^#{botnick}[,|:| ].*$/i) do |message, params|
|
||||||
|
arr = message.text.split(/\W+/)
|
||||||
|
if arr[1].nil? == false then
|
||||||
|
if arr[1].chomp.strip != "" then
|
||||||
|
mpdcontrol(mpd,arr[1].chomp.strip,message,"0")
|
||||||
|
else
|
||||||
|
mpdcontrol(mpd,"status",message,"0")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mpdcontrol(mpd,"status",message,"0")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
query do |message, params|
|
||||||
|
arr = message.text.split(/\W+/)
|
||||||
|
if arr[0].nil? == false then
|
||||||
|
if arr[0].chomp.strip != "" then
|
||||||
|
mpdcontrol(mpd,arr[0].chomp.strip,message, "1")
|
||||||
|
else
|
||||||
|
mpdcontrol(mpd,"status",message,"1")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mpdcontrol(mpd,"status",message,"1")
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in new issue