bash plugin: revamped and enhanced
[rbot] / data / rbot / plugins / bash.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: bash.org quote retrieval
5 #
6 # Author:: Robin Kearney <robin@riviera.org.uk>
7 # Author:: cs
8 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
9 #
10 # Copyright:: (C) 2005 Robin Kearney
11 # Copyright:: (C) 2007 cs, Giuseppe Bilotta
12 #
13 # License:: public domain
14 #
15 # TODO improve output of quote
16 # TODO show more than one quote
17 # TODO allow selection of only quotes with vote > 0
18
19 require 'rexml/document'
20 require 'uri/common'
21
22 class ::BashQuote
23   attr_accessor :num, :text, :vote
24
25   def initialize(num, text, vote)
26     @num = num.to_i
27     @text = text
28     @vote = vote
29   end
30
31   def url
32     "http://www.bash.org/?#{@num}"
33   end
34
35 end
36
37 class BashPlugin < Plugin
38
39   BotConfig.register BotConfigEnumValue.new('bash.access',
40     :values => ['xml', 'html'], :default => 'html',
41     :desc => "Which method the bot should use to access bash.org quotes: xml files or standard webpages")
42
43   include REXML
44   def help(plugin, topic="")
45     "bash => print a random quote from bash.org, bash quote_id => print that quote id from bash.org, bash latest => print the latest quote from bash.org (currently broken, need to get josh@bash.org to fix the xml)"
46   end
47
48   def bash(m, params)
49     id = params[:id]
50     case @bot.config['bash.access'].intern
51     when :xml
52       xml_bash(m, id)
53     else
54       html_bash(m, :id => id)
55     end
56   end
57
58   def search(m, params)
59     esc = URI.escape(params[:words].to_s)
60     html = @bot.httputil.get("http://bash.org/?search=#{esc}")
61     html_bash(m, :html => html)
62   end
63
64   def html_bash(m, opts={})
65     quotes = []
66
67     html = opts[:html]
68     if not html
69       id = opts[:id]
70       case id
71       when 'latest'
72         html = @bot.httputil.get("http://bash.org/?latest")
73       when nil
74         html = @bot.httputil.get("http://bash.org/?random", :cache => false)
75       else
76         html = @bot.httputil.get("http://bash.org/?" + id)
77       end
78     end
79
80     html_quotes = html.split(/<p class="quote">/)
81     html_quotes.each { |htqt|
82       # debug htqt.inspect
83       if htqt.match(/<a href="\?(\d+)"[^>]*>.*?\((-?\d+)\).*?<p class="qt">(.*)<\/p>\s+(?:<\/td>.*)?\z/m)
84         num = $1
85         vote = $2
86         text = $3
87         quotes << BashQuote.new(num, text, vote)
88       end
89     }
90
91     case quotes.length
92     when 0
93       m.reply "no quotes found"
94       return
95     when 1
96       quote = quotes.first
97     else
98       # For the time being, we only echo the first quote, but in the future we
99       # may want to echo more than one for latest/random
100       quote = quotes.first
101     end
102     # TODO: the gsub of br tags to | should be an ircify_html option
103     m.reply "#%d (%d): %s" % [quote.num, quote.vote, quote.text.gsub(/(?:<br \/>\s*)+/, ' | ').ircify_html]
104   end
105
106   def xml_bash(m, id=nil)
107     case id
108     when 'latest'
109       xml = @bot.httputil.get("http://bash.org/xml/?latest&num=1")
110     when nil
111       xml = @bot.httputil.get("http://bash.org/xml/?random&num=1", :cache => false)
112     else
113       xml = @bot.httputil.get("http://bash.org/xml/?" + id + "&num=1")
114     end 
115
116     unless xml
117       m.reply "bash.org rss parse failed"
118       return
119     end
120     doc = Document.new xml
121     unless doc
122       m.reply "bash.org rss parse failed"
123       return
124     end
125     doc.elements.each("*/item") {|e|
126       if(id != 0) 
127         reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
128         reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
129       else
130         reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
131         reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
132       end
133       m.reply reply
134     }
135   end
136 end
137
138 plugin = BashPlugin.new
139
140 plugin.map "bash search *words", :action => :search
141 plugin.map "bash [:id]"
142