]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/url.rb
286e8c4a38c8a4d449b5c15321fae3008428e163
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / url.rb
1 require 'open-uri'
2
3 Url = Struct.new("Url", :channel, :nick, :time, :url)
4 TITLE_RE = /<\s*title\s*>(.+)<\s*\/title\s*>/im
5
6 class UrlPlugin < Plugin
7   BotConfig.register BotConfigIntegerValue.new('url.max_urls',
8     :default => 100, :validate => Proc.new{|v| v > 0},
9     :desc => "Maximum number of urls to store. New urls replace oldest ones.")
10   BotConfig.register BotConfigBooleanValue.new('url.say_titles',
11     :default => true, 
12     :desc => "Get the title of any links pasted to the channel and display it (Also, tells if the link is broken)")
13   
14   def initialize
15     super
16     @registry.set_default(Array.new)
17   end
18
19   def help(plugin, topic="")
20     "urls [<max>=4] => list <max> last urls mentioned in current channel, urls search [<max>=4] <regexp> => search for matching urls. In a private message, you must specify the channel to query, eg. urls <channel> [max], urls search <channel> [max] <regexp>"
21   end
22
23   def get_title_for_url(url)
24     begin
25       pagedata = open(url).read
26       return unless TITLE_RE.match(pagedata)
27       title = $1.strip.gsub(/\s*\n\s*/, " ")
28       title = title[0..255] if title.length > 255 
29       "Title: #{title}"
30
31     rescue SocketError => e
32       "Title: ^- Error connecting to site (#{e.message})"
33     rescue OpenURI::HTTPError => e
34       "Title: ^- Error getting page (#{e.message})"
35     rescue Exception => e
36       "Title: ^- Error: #{e.inspect}"
37     end
38   end
39
40   def listen(m)
41     return unless m.kind_of?(PrivMessage)
42     return if m.address?
43     # TODO support multiple urls in one line
44     if m.message =~ /(f|ht)tps?:\/\//
45       if m.message =~ /((f|ht)tps?:\/\/.*?)(?:\s+|$)/
46         urlstr = $1
47         list = @registry[m.target]
48
49         if @bot.config['url.say_titles']
50           debug "Getting title for #{urlstr}..."
51           title = get_title_for_url urlstr
52           if title
53             m.reply title
54             debug "Title found!"
55           else
56             debug "Title not found!"
57           end        
58         end
59     
60         # check to see if this url is already listed
61         return if list.find {|u| u.url == urlstr }
62         
63         url = Url.new(m.target, m.sourcenick, Time.new, urlstr)
64         debug "#{list.length} urls so far"
65         if list.length > @bot.config['url.max_urls']
66           list.pop
67         end
68         debug "storing url #{url.url}"
69         list.unshift url
70         debug "#{list.length} urls now"
71         @registry[m.target] = list
72       end
73     end
74   end
75
76   def urls(m, params)
77     channel = params[:channel] ? params[:channel] : m.target
78     max = params[:limit].to_i
79     max = 10 if max > 10
80     max = 1 if max < 1
81     list = @registry[channel]
82     if list.empty?
83       m.reply "no urls seen yet for channel #{channel}"
84     else
85       list[0..(max-1)].each do |url|
86         m.reply "[#{url.time.strftime('%Y/%m/%d %H:%M:%S')}] <#{url.nick}> #{url.url}"
87       end
88     end
89   end
90
91   def search(m, params)
92     channel = params[:channel] ? params[:channel] : m.target
93     max = params[:limit].to_i
94     string = params[:string]
95     max = 10 if max > 10
96     max = 1 if max < 1
97     regex = Regexp.new(string)
98     list = @registry[channel].find_all {|url|
99       regex.match(url.url) || regex.match(url.nick)
100     }
101     if list.empty?
102       m.reply "no matches for channel #{channel}"
103     else
104       list[0..(max-1)].each do |url|
105         m.reply "[#{url.time.strftime('%Y/%m/%d %H:%M:%S')}] <#{url.nick}> #{url.url}"
106       end
107     end
108   end
109 end
110 plugin = UrlPlugin.new
111 plugin.map 'urls search :channel :limit :string', :action => 'search',
112                           :defaults => {:limit => 4},
113                           :requirements => {:limit => /^\d+$/},
114                           :public => false
115 plugin.map 'urls search :limit :string', :action => 'search',
116                           :defaults => {:limit => 4},
117                           :requirements => {:limit => /^\d+$/},
118                           :private => false
119 plugin.map 'urls :channel :limit', :defaults => {:limit => 4},
120                           :requirements => {:limit => /^\d+$/},
121                           :public => false
122 plugin.map 'urls :limit', :defaults => {:limit => 4},
123                           :requirements => {:limit => /^\d+$/},
124                           :private => false