Created
August 20, 2015 11:45
-
-
Save NickHu/7d82d1316d62b7d11950 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'mumble-ruby' | |
require 'ruby-mpd' | |
require 'sqlite3' | |
class Bot | |
attr_reader :queue | |
def initialize(client, mpd, quickmpd, karma_db) | |
@client = client | |
@mpd = mpd | |
@mpd_interrupt = false | |
@quickmpd = quickmpd | |
@queue = [] | |
@mpd.clear | |
@mpd.on :playlistlength do |playlistlength| | |
if playlistlength < @queue.length | |
@queue.pop | |
end | |
end | |
@quickmpd.clear | |
@quickmpd.on :playlistlength do |pll| | |
if pll > 0 and @mpd.playing? == true | |
@mpd_interrupt=true | |
@mpd.pause=true | |
@quickmpd.play | |
elsif pll > 0 | |
@quickmpd.play | |
else | |
if @mpd_interrupt | |
@mpd.play | |
end | |
end | |
end | |
@karma = karma_db | |
@soundbytes = populate_soundbytes("quickplay") | |
end | |
def command_handler(input) | |
input.gsub!(/(<[^>]*>)|\n|\t/s) {" "} | |
if (md = (/(\w+)\+\+(?:$|\s+)(.*)/).match(input)) | |
#puts "Increment" | |
#puts md.inspect | |
if (md[2].empty? != true) | |
karma_modify(md[1], md[2], 1) | |
else | |
karma_modify(md[1], nil, 1) | |
end | |
return nil | |
elsif (md = (/(\w+)--(?:$|\s+)(.*)/).match(input)) | |
#puts "Decrement" | |
#puts md.inspect | |
if (md[2].empty? != true) | |
karma_modify(md[1], md[2], 0) | |
else | |
karma_modify(md[1], nil, 0) | |
end | |
return nil | |
end | |
if @soundbytes.key?(input.downcase) | |
quickplay @soundbytes[input.downcase].sample | |
end | |
if (input.start_with?("!") != true) | |
return nil | |
end | |
input[0] = '' | |
argv = input.split | |
#puts "Argv #{argv}" | |
if (argv[0].eql? "help") | |
helptext = <<-EOF | |
<br /> | |
!help - List commands <br /> | |
!play - Play music <br /> | |
!pause - Pause music <br /> | |
!queue - List play queue <br /> | |
!next - Next track <br /> | |
!clear - Clear playlist <br /> | |
!volume [up|down|0-100] - Set volume <br /> | |
!youtube - Queue YouTube by URL or ID <br /> | |
!soundcloud - Queue SoundCloud by URL or ID <br /> | |
!url - Queue audio file by URL <br /> | |
!8ball - Ask the Magic 8 Ball <br /> | |
!coin - Flip a coin <br /> | |
!dice - Roll the dice <br /> | |
!karma - Show karma for something <br /> | |
<WORD>++ <REASON> - Increment karma for something <br /> | |
<WORD>-- <REASON> - Decrement karma for something <br /> | |
!reload - Reload config | |
EOF | |
@client.text_channel(0, helptext) | |
elsif (argv[0].eql? "play") | |
while @quickmpd.status[:playlistlength] > 0 | |
sleep 1 | |
end | |
@mpd.play | |
@client.text_channel(0, "Playing...") | |
elsif (argv[0].eql? "pause") | |
@mpd.pause=true | |
@client.text_channel(0, "Pausing...") | |
elsif (argv[0].eql? "queue") | |
if @queue.empty? | |
@client.text_channel(0, "Queue empty") | |
else | |
@client.text_channel(0, "<br />* " + @queue.join("<br />")) | |
end | |
elsif (argv[0].eql? "next") | |
@mpd.next | |
@client.text_channel(0, "Skipping...") | |
elsif (argv[0].eql? "clear") | |
@mpd.clear | |
@client.text_channel(0, "Clearing...") | |
elsif (argv[0].eql? "volume" or argv[0].eql? "vol") | |
if argv[1].eql? "up" | |
if argv[2] | |
@mpd.volume=(@mpd.volume + argv[2]) | |
@client.text_channel(0, "Increasing volume by #{argv[2]}") | |
else | |
@mpd.volume=(@mpd.volume + 5) | |
@client.text_channel(0, "Increasing volume by 5") | |
end | |
elsif argv[1].eql? "down" | |
if argv[2] | |
@mpd.volume=(@mpd.volume - argv[2]) | |
@client.text_channel(0, "Decreasing volume by #{argv[2]}") | |
else | |
@mpd.volume=(@mpd.volume - 5) | |
@client.text_channel(0, "Decreasing volume by 5") | |
end | |
else | |
if argv[1].to_i.integer? and argv[1].to_i >= 0 and argv[1].to_i <= 100 | |
@mpd.volume=argv[1] | |
@client.text_channel(0, "Set volume to #{argv[1]}") | |
end | |
end | |
elsif (argv[0].eql? "youtube" or argv[0].eql? "yt") | |
begin | |
youtube(argv[1]) | |
rescue | |
@client.text_channel(0, "BEEP BEEP ERROR") | |
end | |
elsif (argv[0].eql? "soundcloud" or argv[0].eql? "sc") | |
queue(argv[1]) | |
elsif (argv[0].eql? "url") | |
queue(argv[1], :url) | |
elsif (argv[0].eql? "8ball") | |
@client.text_channel(0, magic8ball) | |
elsif (argv[0].eql? "coin") | |
@client.text_channel(0, "It's " + coin) | |
elsif (argv[0].eql? "dice" or argv[0].eql? "rtd") | |
roll = 1 | |
if argv[1] | |
roll = dice(argv[1].to_i) | |
else | |
roll = dice | |
end | |
@client.text_channel(0, "Rolled a #{roll}") | |
elsif (argv[0].eql? "karma") | |
karma_print(argv[1]) | |
elsif (argv[0].eql? "reload") | |
@quickmpd.update | |
@soundbytes = populate_soundbytes("quickplay") | |
@client.text_channel(0, "Reloaded config") | |
end | |
end | |
def quickplay(file) | |
@quickmpd.add(file) unless @quickmpd.playing? | |
end | |
def populate_soundbytes(directory) | |
items = Dir.entries(directory) | |
items.delete(".") | |
items.delete("..") | |
soundbytes = Hash.new | |
items.each { |item| root = item.match(/([^\-]+)(-\d+)?\.ogg/); (soundbytes[root[1]] ||= []) << item } | |
return soundbytes | |
end | |
def karma_print(thing) | |
karma_str = "" | |
stm = @karma.prepare("SELECT Karma FROM Karma WHERE Item = ?") | |
stm.bind_params(thing.downcase) | |
rs = stm.execute | |
row = rs.next | |
if row | |
karma_str << "Karma of #{thing} is #{row[0]} <br />" | |
rstm = @karma.prepare("SELECT Reason, Quantity, Positive FROM Reason WHERE Item = ?") | |
rstm.bind_params(thing.downcase) | |
rrs = rstm.execute | |
while (rrow = rrs.next) do | |
if rrow[2] == 0 | |
karma_str << "-#{rrow[1]} ~ #{rrow[0]} <br />" | |
elsif rrow[2] == 1 | |
karma_str << "+#{rrow[1]} ~ #{rrow[0]} <br />" | |
end | |
end | |
rstm.close if rstm | |
else | |
karma_str = "No karma for #{thing} <br />" | |
end | |
stm.close if stm | |
@client.text_channel(0, karma_str) | |
end | |
def karma_modify(thing, reason, positive) | |
if reason | |
rstm = nil | |
if karma_reason_exists(thing, reason, positive) | |
rstm = @karma.prepare("UPDATE Reason SET Quantity = Quantity + 1 WHERE Reason = ?") | |
rstm.bind_params(reason.downcase) | |
else | |
rstm = @karma.prepare("INSERT INTO Reason VALUES(?, ?, 1, ?)") | |
rstm.bind_params(reason.downcase, thing.downcase, positive) | |
end | |
rstm.execute | |
rstm.close if rstm | |
end | |
stm = nil | |
feedback = "" | |
if karma_item_exists(thing) | |
if positive == 1 | |
stm = @karma.prepare("UPDATE Karma SET Karma = Karma + 1 WHERE Item = ?") | |
feedback << "Karma gained for #{thing}" | |
elsif positive == 0 | |
stm = @karma.prepare("UPDATE Karma SET Karma = Karma - 1 WHERE Item = ?") | |
feedback << "Karma lost for #{thing}" | |
end | |
else | |
if positive == 1 | |
stm = @karma.prepare("INSERT INTO Karma VALUES(?, 1)") | |
feedback << "Karma gained for #{thing}" | |
elsif positive == 0 | |
stm = @karma.prepare("INSERT INTO Karma VALUES(?, -1)") | |
feedback << "Karma lost for #{thing}" | |
end | |
end | |
feedback << " ~ #{reason}" if reason | |
stm.bind_params(thing.downcase) | |
stm.execute | |
@client.text_channel(0, feedback) | |
stm.close if stm | |
end | |
def karma_item_exists(item) | |
stm = @karma.prepare "SELECT * FROM Karma WHERE Item = ?" | |
stm.bind_params(item.downcase) | |
rs = stm.execute | |
if rs.next | |
stm.close if stm | |
return true | |
else | |
stm.close if stm | |
return false | |
end | |
end | |
def karma_reason_exists(thing, reason, positive) | |
stm = @karma.prepare "SELECT * FROM Reason WHERE Item = ? AND Reason = ? AND Positive = ?" | |
stm.bind_params(thing.downcase, reason.downcase, positive) | |
rs = stm.execute | |
if rs.next | |
stm.close if stm | |
return true | |
else | |
stm.close if stm | |
return false | |
end | |
end | |
def youtube(input) | |
matchdata = input.match(/watch\?v=(\w{11})/) | |
if matchdata | |
id = matchdata[1] | |
elsif input =~ /[\w\-]{11}/ | |
id = input | |
end | |
if id.empty? | |
raise RuntimeError, "Failed to parse valid YouTube identifier" | |
end | |
queue(id, :youtube) | |
end | |
def get_title(id) | |
title = `./youtube-dl -e "#{id}"` or raise RuntimeError, "Failed to get Title" | |
return title | |
end | |
def get_url_generic(id) | |
url = `./youtube-dl -g "#{id}"` | |
return url.gsub(/https:\/\//, "http://") | |
end | |
def get_youtube(id) | |
system("./youtube-dl -f141 #{id} -o \"/var/lib/mpd/music/%\(id\)s.%\(ext\)s\"") or raise RuntimeError, "Failed to get URL" | |
return "#{id}.m4a" | |
end | |
def queue(id, source = :generic) | |
url = "" | |
if source == :youtube | |
title = get_title id | |
url = get_youtube(id) | |
elsif source == :url | |
title = id | |
url = id.gsub(/https:\/\//, "http://") | |
else | |
title = get_title id | |
url = get_url_generic(id) | |
end | |
begin | |
@mpd.update | |
@mpd.add(url.chomp) | |
@queue.push(title) | |
@client.text_channel(0, "Queued #{@queue.last}") | |
rescue | |
@client.text_channel(0, "BEEP BEEP ERROR") | |
end | |
end | |
def magic8ball | |
outcome = rand(21) | |
case outcome | |
when 0 | |
return "It is certain" | |
when 1 | |
return "It is decidedly so" | |
when 2 | |
return "Without a doubt" | |
when 3 | |
return "Yes definitely" | |
when 4 | |
return "You may rely on it" | |
when 5 | |
return "As I see it, yes" | |
when 6 | |
return "Most likely" | |
when 7 | |
return "Outlook good" | |
when 8 | |
return "Yes" | |
when 9 | |
return "Signs point to yes" | |
when 10 | |
return "Reply hazy try again" | |
when 11 | |
return "Ask again later" | |
when 12 | |
return "Better not tell you now" | |
when 13 | |
return "Cannot predict now" | |
when 14 | |
return "Concentrate and ask again" | |
when 15 | |
return "Don't count on it" | |
when 16 | |
return "My reply is no" | |
when 17 | |
return "My sources say no" | |
when 18 | |
return "Outlook not so good" | |
when 19 | |
return "Very doubtful" | |
end | |
end | |
def coin | |
flip = rand(2) | |
case flip | |
when 0 | |
return "heads" | |
when 1 | |
return "tails" | |
end | |
end | |
def dice(faces = 6) | |
return 1 + rand(faces) | |
end | |
end | |
######################### | |
#Mumble code starts here# | |
######################### | |
cli = Mumble::Client.new('localhost', 64738, 'phrik') | |
cli.connect | |
sleep(1) | |
mpd = MPD.new("localhost", 6600, {callbacks: true}) | |
mpd.connect | |
quickmpd = MPD.new("/home/nick/mumble-client/quickmpd", 0, {callbacks: true}) | |
quickmpd.connect | |
quickmpd.update | |
karma_db = SQLite3::Database.open "karma.db" | |
karma_db.execute "CREATE TABLE IF NOT EXISTS Karma(Item VARCHAR PRIMARY KEY, Karma INTEGER NOT NULL)" | |
karma_db.execute "CREATE TABLE IF NOT EXISTS Reason(Reason VARCHAR NOT NULL, Item VARCHAR NOT NULL, Quantity INTEGER NOT NULL, Positive BOOLEAN NOT NULL, PRIMARY KEY(Reason, Item, Positive), FOREIGN KEY(Item) REFERENCES Karma(Item))" | |
phrik = Bot.new(cli, mpd, quickmpd, karma_db) | |
cli.on_text_message do |msg| | |
phrik.command_handler(msg.message) | |
end | |
#cli.on_connected do | |
# cli.me.mute | |
# cli.me.deafen | |
#end | |
cli.player.stream_named_pipe('/tmp/mumble.fifo') | |
gets | |
karma_db.close if karma_db | |
mpd.disconnect | |
quickmpd.disconnect | |
cli.disconnect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment