]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/imdb.rb
imdb plugin: show popular movies acted/directed when finding people
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / imdb.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: IMDB plugin for rbot
5 #
6 # Author:: Arnaud Cornet <arnaud.cornet@gmail.com>
7 # Copyright:: (C) 2005 Arnaud Cornet
8 # License:: MIT license
9 #
10 # Notes by Giuseppe Bilotta:
11 # TODO return more than one match (configurable)
12
13 require 'uri/common'
14
15 class Imdb
16   def initialize(bot)
17     @bot = bot
18   end
19
20   def search(rawstr)
21     str = URI.escape(rawstr) << ";site=aka"
22     return do_search(str)
23   end
24
25   def do_search(str)
26     resp = nil
27     begin
28       resp = @bot.httputil.get_response("http://us.imdb.com/find?q=#{str}",
29                                         :max_redir => -1)
30     rescue Exception => e
31       error e.message
32       warning e.backtrace.join("\n")
33       return nil
34     end
35
36     if resp.code == "200"
37       m = /<a href="(\/(?:title|name)\/(?:tt|nm)[0-9]+\/?)[^"]*"(?:[^>]*)>(?:[^<]*)<\/a>/.match(resp.body)
38       if m
39         url = m[1]
40         return url
41       end
42     elsif resp.code == "302"
43       new_loc = resp['location'].gsub(/http:\/\/us.imdb.com/, "")
44       if new_loc.match(/\/find\?q=(.*)/)
45         return do_search($1)
46       else
47         return new_loc.gsub(/\?.*/, "")
48       end
49     end
50     return nil
51   end
52
53   def info(rawstr)
54     sr = search(rawstr)
55     if !sr
56       debug "IMDB: search returned NIL"
57       return nil
58     end
59     type = sr.match(/^\/([^\/]+)\//)[1].downcase.intern rescue nil
60     case type
61     when :title
62       return info_title(sr)
63     when :name
64       return info_name(sr)
65     else
66       return "#{sr}"
67     end
68   end
69
70   def grab_info(info, body)
71     /<div class="info">\s+<h5>#{info}:<\/h5>\s+(.*?)<\/div>/mi.match(body)[1] rescue nil
72   end
73
74   def info_title(sr)
75     resp = nil
76     begin
77       resp = @bot.httputil.get_response('http://us.imdb.com' + sr,
78                                         :max_redir => -1)
79     rescue Exception => e
80       error e.message
81       warning e.backtrace.join("\n")
82       return nil
83     end
84
85     if resp.code == "200"
86       m = /<title>([^<]*)<\/title>/.match(resp.body)
87       return nil if !m
88       title = Utils.decode_html_entities(m[1])
89
90       m = /<b>([0-9.]+)\/10<\/b>\n?\r?\s+<small>\(<a href="ratings">([0-9,]+) votes?<\/a>\)<\/small>/.match(resp.body)
91       return nil if !m
92       score = m[1]
93       votes = m[2]
94
95       plot = nil
96       data = grab_info(/Plot (?:Outline|Summary)/, resp.body)
97       if data
98         plot = "Plot: #{data.ircify_html.gsub(/\s+more$/,'')}"
99       end
100
101       genre = Array.new
102       resp.body.scan(/<a href="\/Sections\/Genres\/[^\/]+\/">([^<]+)<\/a>/) do |gnr|
103         genre << gnr
104       end
105       info = "#{title} : http://us.imdb.com#{sr}\n"
106       info << "Ratings: #{score}/10 (#{votes} voters). Genre: #{genre.join('/')}\n"
107       info << plot if plot
108       return info
109     end
110     return nil
111   end
112
113   def info_name(sr)
114     resp = nil
115     begin
116       resp = @bot.httputil.get_response('http://us.imdb.com' + sr,
117                                         :max_redir => -1)
118     rescue Exception => e
119       error e.message
120       warning e.backtrace.join("\n")
121       return nil
122     end
123
124     if resp.code == "200"
125       m = /<title>([^<]*)<\/title>/.match(resp.body)
126       return nil if !m
127       name = Utils.decode_html_entities(m[1])
128
129       birth = nil
130       data = grab_info("Date of Birth", resp.body)
131       if data
132         birth = "Birth: #{data.ircify_html.gsub(/\s+more$/,'')}"
133       end
134
135       death = nil
136       data = grab_info("Date of Death", resp.body)
137       if data
138         death = "Death: #{data.ircify_html.gsub(/\s+more$/,'')}"
139       end
140
141       movies = {}
142
143       filmorate = nil
144       begin
145         filmorate = @bot.httputil.get("http://us.imdb.com" + sr + "filmorate")
146       rescue Exception
147       end
148
149       if filmorate
150         filmorate.scan(/<div class="filmo">.*?<a href="\/title.*?<\/div>/m) { |str|
151           what = str.match(/<a name="[^"]+">([^<]+)<\/a>/)[1] rescue nil
152           # next unless what
153           next unless ['Actor', 'Director'].include?(what)
154           movies[what] = str.scan(/<a href="\/title\/[^"]+">([^<]+)<\/a>/)[0..2].map { |tit|
155             Utils.decode_html_entities(tit)
156           }
157         }
158       end
159       debug movies.inspect
160
161       info = "#{name} : http://us.imdb.com#{sr}\n"
162       info << [birth, death].compact.join('. ') << "\n"
163       unless movies.empty?
164         info << "Top Movies:: "
165         ar = []
166         movies.keys.sort.each { |key|
167           ar << key.dup
168           ar.last << ": " + movies[key].join(', ')
169         }
170         info << ar.join('. ')
171       end
172       return info
173
174     end
175     return nil
176   end
177 end
178
179 class ImdbPlugin < Plugin
180   def help(plugin, topic="")
181     "imdb <string> => search http://www.imdb.org for <string>"
182   end
183
184   def imdb(m, params)
185     what = params[:what].to_s
186     i = Imdb.new(@bot)
187     info = i.info(what)
188     if !info
189       m.reply "Nothing found for #{what}"
190       return nil
191     end
192     m.reply info
193   end
194 end
195
196 plugin = ImdbPlugin.new
197 plugin.map "imdb *what"
198