]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/bash.rb
chucknorris: read gzip stream before passing it to YAML.load
[user/henk/code/ruby/rbot.git] / 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
21 class ::BashQuote
22   attr_accessor :num, :text, :irc_text, :vote
23
24   def initialize(num, text, vote)
25     @num = num.to_i
26     @text = text
27     @vote = vote
28     @irc_text = mk_irc_text
29   end
30
31   def url
32     "http://www.bash.org/?#{@num}"
33   end
34
35   def to_s
36     "#%d (%d): %s" % [self.num, self.vote, self.irc_text]
37   end
38
39   private
40   def mk_irc_text
41     cur_nick = nil
42     last_nick = nil
43     text = String.new
44     @text.each_line { |l|
45       debug "line: #{l.inspect}"
46       cur_nick = l.match(/^\s*(&lt;.*?&gt;|\(.*?\)|.*?:)\s/)[1] rescue nil
47       debug "nick: #{cur_nick.inspect}; last: #{last_nick.inspect}"
48       if cur_nick and cur_nick == last_nick
49         text << l.sub(cur_nick,"")
50       else
51         last_nick = cur_nick.dup if cur_nick
52         text << l
53       end
54     }
55     debug text
56     # TODO: the gsub of br tags to | should be an ircify_html option
57     text.gsub(/(?:<br \/>\s*)+/, ' | ').ircify_html
58   end
59
60 end
61
62 class BashPlugin < Plugin
63
64   Config.register Config::EnumValue.new('bash.access',
65     :values => ['xml', 'html'], :default => 'html',
66     :desc => "Which method the bot should use to access bash.org quotes: xml files or standard webpages")
67
68   include REXML
69   def help(plugin, topic="")
70     [
71       _("bash => print a random quote from bash.org"),
72       _("bash quote_id => print that quote id from bash.org"),
73       _("bash search <terms> => print the first bash.org quote matching <terms>"),
74       _("bash latest => print the latest quote from bash.org")
75     ].join(", ")
76   end
77
78   def bash_filter(s)
79     # check if we like the location of the page
80     loc = Utils.check_location(s, %r{http://(?:www\.)?bash\.org/\?})
81     return unless loc
82     # check if there are any quotes
83     quotes = get_html_quotes(s[:text])
84     return if quotes.empty?
85     title = s[:text].ircify_html_title
86     # return the first quote
87     return {
88           :title => title,
89           :content => quotes.first.to_s,
90           :bash_quotes => quotes
91     }
92   end
93
94   def initialize
95     super
96
97     @bot.register_filter(:bash, :htmlinfo) { |s| bash_filter(s) }
98   end
99
100   def bash(m, params)
101     id = params[:id]
102     case @bot.config['bash.access'].intern
103     when :xml
104       xml_bash(m, id)
105     else
106       html_bash(m, :id => id)
107     end
108   end
109
110   def search(m, params)
111     esc = CGI.escape(params[:words].to_s)
112     html = @bot.httputil.get("http://bash.org/?search=#{esc}")
113     html_bash(m, :html => html)
114   end
115
116   def get_html_quotes(html)
117     quotes = []
118
119     html_quotes = html.split(/<p class="quote">/)
120     html_quotes.each { |htqt|
121       # debug htqt.inspect
122       if htqt.match(/<a href="\?(\d+)"[^>]*>.*?\((-?\d+)\).*?<p class="qt">(.*)<\/p>\s+(?:<\/td>.*)?\z/m)
123         num = $1
124         vote = $2
125         text = $3
126         quotes << BashQuote.new(num, text, vote)
127       end
128     }
129     return quotes
130   end
131
132   def html_bash(m, opts={})
133     html = opts[:html]
134     if not html
135       id = opts[:id]
136       case id
137       when 'latest'
138         html = @bot.httputil.get("http://bash.org/?latest")
139       when nil
140         html = @bot.httputil.get("http://bash.org/?random", :cache => false)
141       else
142         html = @bot.httputil.get("http://bash.org/?" + id)
143       end
144     end
145
146     if not html
147       m.reply "unable to retrieve quotes"
148       return
149     end
150
151     quotes = get_html_quotes(html)
152
153     case quotes.length
154     when 0
155       m.reply "no quotes found"
156       return
157     when 1
158       quote = quotes.first
159     else
160       # For the time being, we only echo the first quote, but in the future we
161       # may want to echo more than one for latest/random
162       quote = quotes.first
163     end
164     m.reply quote.to_s, :split_at => /\s+\|\s+/
165   end
166
167   def xml_bash(m, id=nil)
168     case id
169     when 'latest'
170       xml = @bot.httputil.get("http://bash.org/xml/?latest&num=1")
171     when nil
172       xml = @bot.httputil.get("http://bash.org/xml/?random&num=1", :cache => false)
173     else
174       xml = @bot.httputil.get("http://bash.org/xml/?" + id + "&num=1")
175     end
176
177     unless xml
178       m.reply "bash.org rss parse failed"
179       return
180     end
181     doc = Document.new xml
182     unless doc
183       m.reply "bash.org rss parse failed"
184       return
185     end
186     doc.elements.each("*/item") {|e|
187       if(id != 0)
188         reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
189         reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
190       else
191         reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
192         reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
193       end
194       m.reply reply
195     }
196   end
197 end
198
199 plugin = BashPlugin.new
200
201 plugin.map "bash search *words", :action => :search
202 plugin.map "bash [:id]"
203