Skip to content

Instantly share code, notes, and snippets.

@meh
Created July 14, 2010 07:23
Show Gist options
  • Save meh/475141 to your computer and use it in GitHub Desktop.
Save meh/475141 to your computer and use it in GitHub Desktop.
lol a bot
#! /usr/bin/env ruby
require 'failirc/client'
require 'getoptlong'
require 'uri'
require 'net/http'
require 'timeout'
require 'sqlite3'
VERSION = '0.2'
args = GetoptLong.new(
['--version', '-v', GetoptLong::NO_ARGUMENT],
['--verbose', '-V', GetoptLong::NO_ARGUMENT],
['--config', '-f', GetoptLong::REQUIRED_ARGUMENT],
['--database', '-d', GetoptLong::REQUIRED_ARGUMENT],
)
options = {
:verbose => false,
:config => '/etc/failbot.conf',
}
args.each {|option, value|
case option
when '--version'
puts "Fail IRC #{IRC::VERSION}"
exit 0
when '--verbose'
options[:verbose] = true
when '--config'
options[:config] = value
when '--database'
options[:database] = value
end
}
class Database
def initialize (path)
if !path
raise 'No database.'
end
@db = SQLite3::Database.new(path)
@db.results_as_hash = true
self.url :init
self.quotes :init
self.karma :init
end
def close
@db.close
end
def url (what, *args)
self.send "url_#{what}", *args
end
def url_init
@db.execute(%{
CREATE TABLE IF NOT EXISTS urls (
url TEXT UNIQUE,
date INTEGER,
user TEXT,
channel TEXT,
server TEXT
);
})
end
def url_insert (url, date, user, channel, server)
@db.execute('INSERT OR IGNORE INTO urls VALUES(?, ?, ?, ?, ?)', [url, date, user, channel, server])
end
def url_get (channel, query, *objects)
if objects.last.is_a?(Range)
range = objects.pop
end
if query.is_a?(Range)
@db.execute("SELECT * FROM urls WHERE server = ? AND channel = ? LIMIT #{query.end - query.begin} OFFSET #{query.begin}", [channel.server.to_s, channel.to_s])
elsif query.is_a?(Fixnum)
@db.execute('SELECT WHERE server = ? AND channel = ?', [channel.server.to_s, channel.to_s])
else
@db.execute("SELECT * FROM urls WHERE #{query} AND server = ? AND channel = ?", objects.concat([channel.server.to_s, channel.to_s]))
end
end
def url_all
@db.execute('SELECT * FROM urls')
end
def url_length
@db.execute('SELECT COUNT(*) AS length FROM urls').shift['length']
end
def quotes (what, *args)
self.send "quotes_#{what}", *args
end
def quotes_init
@db.execute(%{
CREATE TABLE IF NOT EXISTS quotes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quote TEXT,
date INTEGER,
user TEXT,
channel TEXT,
server TEXT
);
})
end
def quotes_insert (quote, date, user, channel, server)
@db.execute('INSERT INTO quotes VALUES(NULL, ?, ?, ?, ?, ?)', [quote, date, user, channel, server])
end
def quotes_get (what, *stuff)
if what.is_a?(Symbol)
case what
when :random
@db.execute('SELECT * FROM quotes ORDER BY RANDOM() LIMIT 1').shift
end
else
query = ''
objects = []
stuff.each {|string|
query << "quote LIKE ?"
objects << "%#{string}%"
}
@db.execute("SELECT * FROM quotes WHERE #{query}", objects)
end
end
def karma (what, *args)
self.send "karma_#{what}", *args
end
def karma_init
@db.execute(%{
CREATE TABLE IF NOT EXISTS karma (
name TEXT PRIMARY KEY UNIQUE,
value INTEGER DEFAULT 0
);
})
end
def karma_set (name, what)
name.strip!
@db.execute('INSERT OR IGNORE INTO karma VALUES(?, 0)', name)
if what.is_a?(String)
if what == '++'
@db.execute('UPDATE karma SET value = value + 1 WHERE name LIKE ?', name)
elsif what == '--'
@db.execute('UPDATE karma SET value = value - 1 WHERE name LIKE ?', name)
end
else
@db.execute('UPDATE karma SET value = ? WHERE name LIKE ?', [what, name])
end
end
def karma_get (name)
@db.execute('SELECT * FROM karma WHERE name LIKE ?', name).shift
end
end
$client = IRC::Client.new(File.new(options[:config]), options[:verbose])
if tmp = $client.config.elements['config/informations/database']
options[:database] = tmp.text
end
$db = Database.new(options[:database])
$authorized = Hash.new
def stop (client)
client.stop
$db.close
Process.exit!(0)
end
trap('INT') { stop $client }
trap('KILL') { stop $client }
module Commands
def self.version (server, from, to, string)
version = "lulzBot-\x02#{VERSION}\x02 [failirc-#{IRC::VERSION}]"
if to.is_a?(IRC::Client::Channel)
$client.fire :message, server, :output, $client, to, version
else
$client.fire :message, server, :output, $client, from, version
end
end
def self.auth (server, from, to, string)
if string == $client.config.elements['config/informations/password'].text
$authorized[from] = true
end
end
def self.quit (server, from, to, string)
if !$authorized[from]
return
end
$client.servers.each_value {|server|
$client.fire :quit, server, string
}
self.debug 'Quitting...'
while true
if $client.servers.empty?
Process.exit!(0)
end
sleep 0.1
end
end
def self.raw (server, from, to, string)
if !$authorized[from]
return
end
server.send :raw, string
end
def self.urls (server, from, to, string)
if !to.is_a?(IRC::Client::Channel)
to = from
end
if string.empty?
if string.empty?
$client.fire :message, server, :output, $client, to, "I've got \x02#{$db.url :length}\x02 URLs."
else
end
else
end
# $urls.each_value {|url|
# $client.fire :message, server, :output, $client, to, "[#{url[:at]}] #{url[:uri]} { #{url[:from]} }"
# }
end
def self.quotes (server, from, to, string)
matches = string.match(/^([^ ]+)(\s+(.+))?$/)
if !matches
quote = $db.quotes :get, :random
$client.fire :message, server, :output, $client, to, "\002#{quote['id']}\002. #{quote['quote']}"
return
end
command = matches[1].to_sym
value = matches[3]
case command
when :add
$db.quotes :insert, value, Time.new.to_i, from.mask.to_s, to.to_s, server.to_s
end
end
def self.karma (server, from, to, string)
matches = string.match(/^([^ ]+)(\s+(.+))?$/)
if !matches
return
end
command = matches[1].to_sym
value = matches[3]
case command
when :get
karma = $db.karma :get, value
$client.fire :message, server, :output, $client, to, "\x02#{karma['name']}\x02 == \x1F#{karma['value']}\x1F"
end
end
def self.regexp (server, from, to, string)
matches = string.match(%r{"(([^"\\]|\\.)*?)"\s+(((m)?/(([^/\\]|\\.)*?)/(.*?))|((s)/(([^/\\]|\\.)*?)/(([^/\\]|\\.)*?)/(.*)))$})
if !matches
$client.fire :message, server, :output, $client, to, "#{from.nick}, wat"
return
end
string = matches[1]
type = matches[5] || matches[10] || 'm'
regexp = matches[6] || matches[11]
mode = matches[8] || matches[15]
into = matches[13] || ''
regexp = Regexp.new(regexp, mode)
if mode.include?('g')
if type == 'm'
result = string.scan(regexp)
else
result = string.gsub(regexp, into)
end
else
if type == 'm'
result = string.match(regexp)
else
result = string.sub(regexp, into)
end
end
if type == 's'
$client.fire :message, server, :output, $client, to, result
else
do_shit = lambda {|result|
if !result.is_a?(Array)
result = result.to_a
end
text = "\x1F#{result.shift}\x1F: "
result.each {|match|
text << "\x1F#{match}\x1F, "
}
$client.fire :message, server, :output, $client, to, text[0, text.length - 2]
}
if mode.include?('g')
result.each {|result|
do_shit.call result
}
else
do_shit.call result
end
end
end
end
def add_urls (message, from, to, server)
URI.extract(message).each {|uri|
if !uri.match(%r{\w+://})
next
end
if match = uri.match('http://tinyurl.com/(.+)$')
uri = timeout 5 do
Net::HTTP.get(URI.parse("http://preview.tinyurl.com/#{match[1]}"))
end rescue next
if match = uri.match(/redirecturl" href="(.+?)"/)
uri = URI.decode(match[1])
else
next
end
end
if to.is_a?(IRC::Client::Channel)
$db.url :insert, uri, Time.new.to_i, from.to_s, to.to_s, server.to_s
end
}
end
# check for connection
$client.observe :connected, lambda {|server|
$client.config.elements.each('config/misc/channels/channel') {|channel|
$client.fire :join, server, channel.text
}
}
# fetch URLs
$client.observe :message, lambda {|server, chain, from, to, message|
if chain != :input
return
end
add_urls(message, from, to, server)
}
$client.observe :topic_change, lambda {|server, old, topic|
add_urls(topic.text, topic.setBy, topic.channel, server)
}
# get karma
$client.observe :message, lambda {|server, chain, from, to, message|
if chain != :input
return
end
if !to.is_a?(IRC::Client::Channel)
return
end
if matches = message.match(/^([^\+\-]+)(\+\+|\-\-)$/)
if matches[1] == from.nick && matches[2] == '++'
$client.fire :message, server, :output, $client, to, "#{from.nick}, do you think I don't see what you did there?"
else
$db.karma :set, matches[1], matches[2]
end
end
}
# fix shit
$client.observe :message, lambda {|server, chain, from, to, message|
if chain != :input
return
end
if $__last && matches = message.match(%r{^(s|tr)/(([^/\\]|\\.)*?)/(([^/\\]|\\.)*?)/(.*)$})
type = matches[1]
regexp = matches[2]
into = matches[4]
mode = matches[6]
if type == 's'
regexp = Regexp.new(regexp, mode)
if mode.include?('g')
result = $__last[1].gsub(regexp, into)
else
result = $__last[1].sub(regexp, into)
end
else
result = $__last[1].tr(regexp, into)
end
$client.fire :message, server, :output, $client, to, "<#{$__last[0].nick}> #{result} <-- fix'd"
else
$__last = [from, message]
end
}
# dispatch commands
$client.observe :message, lambda {|server, chain, from, to, message|
if chain != :input
return
end
if match = message.match(/^~([^ ]+)(\s+(.*))?$/)
begin
if command = Commands.method(match[1].to_sym)
command.call(server, from, to, match[3] || '')
end
rescue Exception => e
self.debug e
end
end
}
$client.observe :parted, lambda {|server, user, channel|
$authorized.delete(user)
}
$client.start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment