4 # :title: Dictionary lookup plugin for rbot
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7 # Copyright:: (C) 2006-2007 Giuseppe Bilotta
10 # Provides a link to the definition of a word in one of the supported
11 # dictionaries. Currently available are
12 # * the Oxford dictionary for (British) English
13 # * the De Mauro/Paravia dictionary for Italian
14 # * the Chambers dictionary for English (accepts both US and UK)
15 # * the Littré dictionary for French
17 # Other plugins can use this one to check if a given word is valid in italian
18 # or english or french by using the is_italian?, is_british?, is_english?,
21 # TODO: cache results and reuse them if get_cached returns a cache copy
23 DEMAURO_LEMMA = /<anchor>(.*?)(?: - (.*?))<go href="lemma.php\?ID=(\d+)"\/><\/anchor>/
24 CHAMBERS_LEMMA = /<p><span class="hwd">(.*?)<\/span> <span class="psa">(.*?)<\/span>(.*?)<\/p>/
26 class DictPlugin < Plugin
27 Config.register Config::IntegerValue.new('dict.hits',
29 :desc => "Number of hits to return from a dictionary lookup")
30 Config.register Config::IntegerValue.new('dict.first_par',
32 :desc => "When set to n > 0, the bot will return the first paragraph from the first n dictionary hits")
35 # check if it's a page we can handle
36 loc = Utils.check_location(s, @dmurlrx)
37 # the location might be not good, but we might still be able to handle the
39 if !loc and s[:text] !~ /<!-- Il dizionario della lingua italiana Paravia: /
40 debug "not our business"
43 # we want to grab the content from the WAP page, since it's in a much
44 # cleaner HTML, so first try to get the word ID
45 if s[:text] !~ %r{<li><a href="(\d+)" title="vai al lemma precedente" accesskey="p">lemma precedente</a></li>}
49 title = s[:text].ircify_html_title
50 content = @bot.filter(:htmlinfo, URI.parse(@dmwaplemma % id))[:content]
51 return {:title => title, :content => content.sub(/^\S+\s+-\s+/,'')}
56 @dmurl = "http://old.demauroparavia.it/"
57 @dmurlrx = %r{http://(?:www|old\.)?demauroparavia\.it/(\d+)}
58 @dmwapurl = "http://wap.demauroparavia.it/index.php?lemma=%s"
59 @dmwaplemma = "http://wap.demauroparavia.it/lemma.php?ID=%s"
60 @oxurl = "http://www.askoxford.com/concise_oed/%s"
61 @chambersurl = "http://www.chambersharrap.co.uk/chambers/features/chref/chref.py/main?query=%s&title=21st"
62 @littreurl = "http://francois.gannaz.free.fr/Littre/xmlittre.php?requete=%s"
64 @bot.register_filter(:demauro, :htmlinfo) { |s| demauro_filter(s) }
68 def help(plugin, topic="")
71 return "demauro <word> => provides a link to the definition of <word> from the De Mauro/Paravia dictionary"
73 return "oxford <word> => provides a link to the definition of <word> (it can also be an expression) from the Concise Oxford dictionary"
75 return "chambers <word> => provides a link to the definition of <word> (it can also be an expression) from the Chambers 21st Century Dictionary"
77 return "littre <word> => provides a link to the definition of <word> (it can also be an expression) from the Littré online dictionary"
79 return "<dictionary> <word>: check for <word> on <dictionary> where <dictionary> can be one of: demauro, oxford, chambers, littre"
82 def demauro(m, params)
83 justcheck = params[:justcheck]
85 word = params[:word].downcase
86 url = @dmwapurl % CGI.escape(word)
88 info = @bot.httputil.get_response(url) rescue nil
89 xml = info.body if info
91 info = info ? " (#{info.code} - #{info.message})" : ""
92 return false if justcheck
93 m.reply "An error occurred while looking for #{word}#{info}"
96 if xml=~ /Non ho trovato occorrenze per/
97 return false if justcheck
98 m.reply "Nothing found for #{word}"
101 entries = xml.scan(DEMAURO_LEMMA)
104 if not entries.transpose.first.grep(/\b#{word}\b/)
105 return false if justcheck
106 text += " not found. Similar words"
108 return true if justcheck
111 hits = @bot.config['dict.hits']
112 text += entries[0...hits].map { |ar|
114 urls << @dmwaplemma % ar[2]
115 key = ar[1].ircify_html
116 "#{n}. #{Bold}#{ar[0]}#{Bold} - #{key}: #{@dmurl}#{ar[2]}"
120 first_pars = @bot.config['dict.first_par']
122 return unless first_pars > 0
124 Utils.get_first_pars urls, first_pars, :message => m,
125 :strip => /^.+?\s+-\s+/
129 def is_italian?(word)
130 return demauro(nil, :word => word, :justcheck => true)
134 def oxford(m, params)
135 justcheck = params[:justcheck]
137 word = params[:word].join
138 [word, word + "_1"].each { |check|
139 url = @oxurl % CGI.escape(check)
143 h = @bot.httputil.get(url, :max_redir => 5)
144 if h and h.match(/<h2>#{word}<\/h2>(.*)Perform/m)
145 m.reply("#{word} : #{url}") unless justcheck
147 m.reply("#{Bold}%s#{Bold}: %s" % [word, defn.ircify_html(:nbsp => :space)], :overlong => :truncate)
151 return false if justcheck
152 m.reply "#{word} not found"
155 def is_british?(word)
156 return oxford(nil, :word => word, :justcheck => true, :british => true)
160 def chambers(m, params)
161 justcheck = params[:justcheck]
163 word = params[:word].to_s.downcase
164 url = @chambersurl % CGI.escape(word)
166 info = @bot.httputil.get_response(url) rescue nil
167 xml = info.body if info
170 info = info ? " (#{info.code} - #{info.message})" : ""
171 return false if justcheck
172 m.reply "An error occurred while looking for #{word}#{info}"
174 when /Sorry, no entries for <b>.*?<\/b> were found./
175 return false if justcheck
176 m.reply "Nothing found for #{word}"
178 when /No exact matches for <b>.*?<\/b>, but the following may be helpful./
179 return false if justcheck
180 m.reply "Nothing found for #{word}, but see #{url} for possible suggestions"
183 # Else, we have a hit
184 return true if justcheck
185 m.reply "#{word}: #{url}"
186 entries = xml.scan(CHAMBERS_LEMMA)
187 hits = @bot.config['dict.hits']
188 entries[0...hits].map { |ar|
189 m.reply(("#{Bold}%s#{Bold} #{Underline}%s#{Underline}%s" % ar).ircify_html, :overlong => :truncate)
193 def is_english?(word)
194 return chambers(nil, :word => word, :justcheck => true)
197 def littre(m, params)
198 justcheck = params[:justcheck]
200 word = params[:word].to_s.downcase
201 url = @littreurl % CGI.escape(word)
203 info = @bot.httputil.get_response(url) rescue nil
204 xml = info.body if info
205 head ||= xml.match(/<div class="entree">(.*?)<\/div>/)[1] rescue nil
208 info = info ? " (#{info.code} - #{info.message})" : ""
209 return false if justcheck
210 m.reply "An error occurred while looking for #{word}#{info}"
212 when /Erreur : le mot <STRONG>.*?<\/STRONG> n'a pas./
213 return false if justcheck
215 m.reply "Nothing found for #{word}, I'll assume you meant #{head}"
217 m.reply "Nothing found for #{word}"
221 return true if justcheck
222 entete = xml.match(/<div class="entete">(.*?)<\/div>/m)[1] rescue nil
223 m.reply "#{head}: #{url} : #{entete.ircify_html rescue nil}"
224 entries = xml.scan(/<span class="variante">(.*?)<\!--variante-->/m)
225 hits = @bot.config['dict.hits']
227 entries[0...hits].map { |ar|
229 m.reply(("#{Bold}#{n}#{Bold} %s" % ar).ircify_html, :overlong => :truncate)
234 return littre(nil, :word => word, :justcheck => true)
239 plugin = DictPlugin.new
240 plugin.map 'demauro :word', :action => 'demauro', :thread => true
241 plugin.map 'oxford *word', :action => 'oxford', :thread => true
242 plugin.map 'chambers *word', :action => 'chambers', :thread => true
243 plugin.map 'littre *word', :action => 'littre', :thread => true