rbot 0.9.9 → 0.9.10
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +8 -0
- data/ChangeLog +51 -0
- data/INSTALL +4 -0
- data/README +1 -0
- data/REQUIREMENTS +11 -0
- data/TODO +2 -0
- data/bin/rbot +21 -2
- data/data/rbot/languages/german.lang +4 -1
- data/data/rbot/languages/russian.lang +75 -0
- data/data/rbot/plugins/autoop.rb +42 -51
- data/data/rbot/plugins/bans.rb +205 -0
- data/data/rbot/plugins/bash.rb +56 -0
- data/data/rbot/plugins/chucknorris.rb +74 -0
- data/data/rbot/plugins/chucknorris.yml.gz +0 -0
- data/data/rbot/plugins/deepthoughts.rb +95 -0
- data/data/rbot/plugins/demauro.rb +95 -0
- data/data/rbot/plugins/digg.rb +51 -0
- data/data/rbot/plugins/figlet.rb +24 -0
- data/data/rbot/plugins/forecast.rb +133 -0
- data/data/rbot/plugins/freshmeat.rb +13 -7
- data/data/rbot/plugins/google.rb +2 -0
- data/data/rbot/plugins/grouphug.rb +36 -0
- data/data/rbot/plugins/imdb.rb +92 -0
- data/data/rbot/plugins/insult.rb +8 -1
- data/data/rbot/plugins/iplookup.rb +227 -0
- data/data/rbot/plugins/karma.rb +2 -2
- data/data/rbot/plugins/keywords.rb +470 -0
- data/data/rbot/plugins/lart.rb +132 -146
- data/data/rbot/plugins/lastfm.rb +25 -0
- data/data/rbot/plugins/markov.rb +204 -0
- data/data/rbot/plugins/math.rb +5 -1
- data/data/rbot/plugins/nickserv.rb +71 -11
- data/data/rbot/plugins/opme.rb +19 -19
- data/data/rbot/plugins/quakeauth.rb +2 -2
- data/data/rbot/plugins/quotes.rb +40 -25
- data/data/rbot/plugins/remind.rb +1 -1
- data/data/rbot/plugins/rot13.rb +2 -2
- data/data/rbot/plugins/roulette.rb +49 -15
- data/data/rbot/plugins/rss.rb +585 -0
- data/data/rbot/plugins/rubyurl.rb +39 -0
- data/data/rbot/plugins/seen.rb +2 -1
- data/data/rbot/plugins/slashdot.rb +5 -5
- data/data/rbot/plugins/spell.rb +5 -0
- data/data/rbot/plugins/theyfightcrime.rb +121 -0
- data/data/rbot/plugins/threat.rb +55 -0
- data/data/rbot/plugins/tinyurl.rb +39 -0
- data/data/rbot/plugins/topic.rb +204 -0
- data/data/rbot/plugins/urban.rb +71 -0
- data/data/rbot/plugins/url.rb +399 -4
- data/data/rbot/plugins/wow.rb +123 -0
- data/data/rbot/plugins/wserver.rb +1 -1
- data/data/rbot/templates/levels.rbot +2 -0
- data/lib/rbot/auth.rb +207 -96
- data/lib/rbot/channel.rb +5 -5
- data/lib/rbot/config.rb +125 -24
- data/lib/rbot/dbhash.rb +87 -21
- data/lib/rbot/httputil.rb +181 -13
- data/lib/rbot/ircbot.rb +525 -179
- data/lib/rbot/ircsocket.rb +330 -54
- data/lib/rbot/message.rb +66 -23
- data/lib/rbot/messagemapper.rb +25 -17
- data/lib/rbot/plugins.rb +244 -115
- data/lib/rbot/post-clean.rb +1 -0
- data/lib/rbot/{post-install.rb → post-config.rb} +1 -1
- data/lib/rbot/rbotconfig.rb +29 -14
- data/lib/rbot/registry.rb +111 -72
- data/lib/rbot/rfc2812.rb +208 -197
- data/lib/rbot/timer.rb +4 -0
- data/lib/rbot/utils.rb +2 -2
- metadata +127 -104
- data/data/rbot/plugins/rss.rb.disabled +0 -414
- data/lib/rbot/keywords.rb +0 -433
@@ -0,0 +1,585 @@
|
|
1
|
+
# RSS feed plugin for RubyBot
|
2
|
+
# (c) 2004 Stanislav Karchebny <berkus@madfire.net>
|
3
|
+
# (c) 2005 Ian Monroe <ian@monroe.nu>
|
4
|
+
# (c) 2005 Mark Kretschmann <markey@web.de>
|
5
|
+
# Licensed under MIT License.
|
6
|
+
|
7
|
+
require 'rss/parser'
|
8
|
+
require 'rss/1.0'
|
9
|
+
require 'rss/2.0'
|
10
|
+
require 'rss/dublincore'
|
11
|
+
# begin
|
12
|
+
# require 'rss/dublincore/2.0'
|
13
|
+
# rescue
|
14
|
+
# warning "Unable to load RSS libraries, RSS plugin functionality crippled"
|
15
|
+
# end
|
16
|
+
|
17
|
+
class ::String
|
18
|
+
def shorten(limit)
|
19
|
+
if self.length > limit
|
20
|
+
self+". " =~ /^(.{#{limit}}[^.!;?]*[.!;?])/mi
|
21
|
+
return $1
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def riphtml
|
27
|
+
self.gsub(/<[^>]+>/, '').gsub(/&/,'&').gsub(/"/,'"').gsub(/</,'<').gsub(/>/,'>').gsub(/&ellip;/,'...').gsub(/'/, "'").gsub("\n",'')
|
28
|
+
end
|
29
|
+
|
30
|
+
def mysqlize
|
31
|
+
self.gsub(/'/, "''")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ::RssBlob
|
36
|
+
attr :url
|
37
|
+
attr :handle
|
38
|
+
attr :type
|
39
|
+
attr :watchers
|
40
|
+
|
41
|
+
def initialize(url,handle=nil,type=nil,watchers=[])
|
42
|
+
@url = url
|
43
|
+
if handle
|
44
|
+
@handle = handle
|
45
|
+
else
|
46
|
+
@handle = url
|
47
|
+
end
|
48
|
+
@type = type
|
49
|
+
@watchers = watchers
|
50
|
+
end
|
51
|
+
|
52
|
+
def watched?
|
53
|
+
!@watchers.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def watched_by?(who)
|
57
|
+
@watchers.include?(who)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_watch(who)
|
61
|
+
if watched_by?(who)
|
62
|
+
return nil
|
63
|
+
end
|
64
|
+
@watchers << who unless watched_by?(who)
|
65
|
+
return who
|
66
|
+
end
|
67
|
+
|
68
|
+
def rm_watch(who)
|
69
|
+
@watchers.delete(who)
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_a
|
73
|
+
[@handle,@url,@type,@watchers]
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s(watchers=false)
|
77
|
+
if watchers
|
78
|
+
a = self.to_a.flatten
|
79
|
+
else
|
80
|
+
a = self.to_a[0,3]
|
81
|
+
end
|
82
|
+
a.join(" | ")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class RSSFeedsPlugin < Plugin
|
87
|
+
BotConfig.register BotConfigIntegerValue.new('rss.head_max',
|
88
|
+
:default => 30, :validate => Proc.new{|v| v > 0 && v < 200},
|
89
|
+
:desc => "How many characters to use of a RSS item header")
|
90
|
+
|
91
|
+
BotConfig.register BotConfigIntegerValue.new('rss.text_max',
|
92
|
+
:default => 90, :validate => Proc.new{|v| v > 0 && v < 400},
|
93
|
+
:desc => "How many characters to use of a RSS item text")
|
94
|
+
|
95
|
+
BotConfig.register BotConfigIntegerValue.new('rss.thread_sleep',
|
96
|
+
:default => 300, :validate => Proc.new{|v| v > 30},
|
97
|
+
:desc => "How many characters to use of a RSS item text")
|
98
|
+
|
99
|
+
@@watchThreads = Hash.new
|
100
|
+
@@mutex = Mutex.new
|
101
|
+
|
102
|
+
def initialize
|
103
|
+
super
|
104
|
+
kill_threads
|
105
|
+
if @registry.has_key?(:feeds)
|
106
|
+
@feeds = @registry[:feeds]
|
107
|
+
else
|
108
|
+
@feeds = Hash.new
|
109
|
+
end
|
110
|
+
rewatch_rss
|
111
|
+
end
|
112
|
+
|
113
|
+
def watchlist
|
114
|
+
@feeds.select { |h, f| f.watched? }
|
115
|
+
end
|
116
|
+
|
117
|
+
def cleanup
|
118
|
+
kill_threads
|
119
|
+
end
|
120
|
+
|
121
|
+
def save
|
122
|
+
@registry[:feeds] = @feeds
|
123
|
+
end
|
124
|
+
|
125
|
+
def kill_threads
|
126
|
+
@@mutex.synchronize {
|
127
|
+
# Abort all running threads.
|
128
|
+
@@watchThreads.each { |url, thread|
|
129
|
+
debug "Killing thread for #{url}"
|
130
|
+
thread.kill
|
131
|
+
}
|
132
|
+
@@watchThreads = Hash.new
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def help(plugin,topic="")
|
137
|
+
case topic
|
138
|
+
when "show"
|
139
|
+
"rss show #{Bold}handle#{Bold} [#{Bold}limit#{Bold}] : show #{Bold}limit#{Bold} (default: 5, max: 15) entries from rss #{Bold}handle#{Bold}; #{Bold}limit#{Bold} can also be in the form a..b, to display a specific range of items"
|
140
|
+
when "list"
|
141
|
+
"rss list [#{Bold}handle#{Bold}] : list all rss feeds (matching #{Bold}handle#{Bold})"
|
142
|
+
when "watched"
|
143
|
+
"rss watched [#{Bold}handle#{Bold}] : list all watched rss feeds (matching #{Bold}handle#{Bold})"
|
144
|
+
when "add"
|
145
|
+
"rss add #{Bold}handle#{Bold} #{Bold}url#{Bold} [#{Bold}type#{Bold}] : add a new rss called #{Bold}handle#{Bold} from url #{Bold}url#{Bold} (of type #{Bold}type#{Bold})"
|
146
|
+
when /^(del(ete)?|rm)$/
|
147
|
+
"rss del(ete)|rm #{Bold}handle#{Bold} : delete rss feed #{Bold}handle#{Bold}"
|
148
|
+
when "replace"
|
149
|
+
"rss replace #{Bold}handle#{Bold} #{Bold}url#{Bold} [#{Bold}type#{Bold}] : try to replace the url of rss called #{Bold}handle#{Bold} with #{Bold}url#{Bold} (of type #{Bold}type#{Bold}); only works if nobody else is watching it"
|
150
|
+
when "forcereplace"
|
151
|
+
"rss forcereplace #{Bold}handle#{Bold} #{Bold}url#{Bold} [#{Bold}type#{Bold}] : replace the url of rss called #{Bold}handle#{Bold} with #{Bold}url#{Bold} (of type #{Bold}type#{Bold})"
|
152
|
+
when "watch"
|
153
|
+
"rss watch #{Bold}handle#{Bold} [#{Bold}url#{Bold} [#{Bold}type#{Bold}]] : watch rss #{Bold}handle#{Bold} for changes; when the other parameters are present, it will be created if it doesn't exist yet"
|
154
|
+
when /(un|rm)watch/
|
155
|
+
"rss unwatch|rmwatch #{Bold}handle#{Bold} : stop watching rss #{Bold}handle#{Bold} for changes"
|
156
|
+
when "rewatch"
|
157
|
+
"rss rewatch : restart threads that watch for changes in watched rss"
|
158
|
+
else
|
159
|
+
"manage RSS feeds: rss show|list|watched|add|del(ete)|rm|(force)replace|watch|unwatch|rmwatch|rewatch"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def report_problem(report, e=nil, m=nil)
|
164
|
+
if m && m.respond_to?(:reply)
|
165
|
+
m.reply report
|
166
|
+
else
|
167
|
+
warning report
|
168
|
+
end
|
169
|
+
if e
|
170
|
+
debug e.inspect
|
171
|
+
debug e.backtrace.join("\n") if e.respond_to?(:backtrace)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def show_rss(m, params)
|
176
|
+
handle = params[:handle]
|
177
|
+
lims = params[:limit].to_s.match(/(\d+)(?:..(\d+))?/)
|
178
|
+
debug lims.to_a.inspect
|
179
|
+
if lims[2]
|
180
|
+
ll = [[lims[1].to_i-1,lims[2].to_i-1].min, 0].max
|
181
|
+
ul = [[lims[1].to_i-1,lims[2].to_i-1].max, 14].min
|
182
|
+
rev = lims[1].to_i > lims[2].to_i
|
183
|
+
else
|
184
|
+
ll = 0
|
185
|
+
ul = [[lims[1].to_i-1, 1].max, 14].min
|
186
|
+
rev = false
|
187
|
+
end
|
188
|
+
|
189
|
+
feed = @feeds.fetch(handle, nil)
|
190
|
+
unless feed
|
191
|
+
m.reply "I don't know any feeds named #{handle}"
|
192
|
+
return
|
193
|
+
end
|
194
|
+
|
195
|
+
m.reply "lemme fetch it..."
|
196
|
+
title = items = nil
|
197
|
+
@@mutex.synchronize {
|
198
|
+
title, items = fetchRss(feed, m)
|
199
|
+
}
|
200
|
+
return unless items
|
201
|
+
|
202
|
+
# We sort the feeds in freshness order (newer ones first)
|
203
|
+
items = freshness_sort(items)
|
204
|
+
disp = items[ll..ul]
|
205
|
+
disp.reverse! if rev
|
206
|
+
|
207
|
+
m.reply "Channel : #{title}"
|
208
|
+
disp.each do |item|
|
209
|
+
printFormattedRss(feed, item, {:places=>[m.replyto],:handle=>nil,:date=>true})
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def itemDate(item,ex=nil)
|
214
|
+
return item.pubDate if item.respond_to?(:pubDate)
|
215
|
+
return item.date if item.respond_to?(:date)
|
216
|
+
return ex
|
217
|
+
end
|
218
|
+
|
219
|
+
def freshness_sort(items)
|
220
|
+
notime = Time.at(0)
|
221
|
+
items.sort { |a, b|
|
222
|
+
itemDate(b, notime) <=> itemDate(a, notime)
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
def list_rss(m, params)
|
227
|
+
wanted = params[:handle]
|
228
|
+
reply = String.new
|
229
|
+
@@mutex.synchronize {
|
230
|
+
@feeds.each { |handle, feed|
|
231
|
+
next if wanted and !handle.match(wanted)
|
232
|
+
reply << "#{feed.handle}: #{feed.url} (in format: #{feed.type ? feed.type : 'default'})"
|
233
|
+
(reply << " (watched)") if feed.watched_by?(m.replyto)
|
234
|
+
reply << "\n"
|
235
|
+
}
|
236
|
+
}
|
237
|
+
if reply.empty?
|
238
|
+
reply = "no feeds found"
|
239
|
+
reply << " matching #{wanted}" if wanted
|
240
|
+
end
|
241
|
+
m.reply reply
|
242
|
+
end
|
243
|
+
|
244
|
+
def watched_rss(m, params)
|
245
|
+
wanted = params[:handle]
|
246
|
+
reply = String.new
|
247
|
+
@@mutex.synchronize {
|
248
|
+
watchlist.each { |handle, feed|
|
249
|
+
next if wanted and !handle.match(wanted)
|
250
|
+
next unless feed.watched_by?(m.replyto)
|
251
|
+
reply << "#{feed.handle}: #{feed.url} (in format: #{feed.type ? feed.type : 'default'})\n"
|
252
|
+
}
|
253
|
+
}
|
254
|
+
if reply.empty?
|
255
|
+
reply = "no watched feeds"
|
256
|
+
reply << " matching #{wanted}" if wanted
|
257
|
+
end
|
258
|
+
m.reply reply
|
259
|
+
end
|
260
|
+
|
261
|
+
def add_rss(m, params, force=false)
|
262
|
+
handle = params[:handle]
|
263
|
+
url = params[:url]
|
264
|
+
unless url.match(/https?/)
|
265
|
+
m.reply "I only deal with feeds from HTTP sources, so I can't use #{url} (maybe you forgot the handle?)"
|
266
|
+
return
|
267
|
+
end
|
268
|
+
type = params[:type]
|
269
|
+
if @feeds.fetch(handle, nil) && !force
|
270
|
+
m.reply "There is already a feed named #{handle} (URL: #{@feeds[handle].url})"
|
271
|
+
return
|
272
|
+
end
|
273
|
+
unless url
|
274
|
+
m.reply "You must specify both a handle and an url to add an RSS feed"
|
275
|
+
return
|
276
|
+
end
|
277
|
+
@@mutex.synchronize {
|
278
|
+
@feeds[handle] = RssBlob.new(url,handle,type)
|
279
|
+
}
|
280
|
+
reply = "Added RSS #{url} named #{handle}"
|
281
|
+
if type
|
282
|
+
reply << " (format: #{type})"
|
283
|
+
end
|
284
|
+
m.reply reply
|
285
|
+
return handle
|
286
|
+
end
|
287
|
+
|
288
|
+
def del_rss(m, params, pass=false)
|
289
|
+
feed = unwatch_rss(m, params, true)
|
290
|
+
if feed.watched?
|
291
|
+
m.reply "someone else is watching #{feed.handle}, I won't remove it from my list"
|
292
|
+
return
|
293
|
+
end
|
294
|
+
@@mutex.synchronize {
|
295
|
+
@feeds.delete(feed.handle)
|
296
|
+
}
|
297
|
+
m.okay unless pass
|
298
|
+
return
|
299
|
+
end
|
300
|
+
|
301
|
+
def replace_rss(m, params)
|
302
|
+
handle = params[:handle]
|
303
|
+
if @feeds.key?(handle)
|
304
|
+
del_rss(m, {:handle => handle}, true)
|
305
|
+
end
|
306
|
+
if @feeds.key?(handle)
|
307
|
+
m.reply "can't replace #{feed.handle}"
|
308
|
+
else
|
309
|
+
add_rss(m, params, true)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def forcereplace_rss(m, params)
|
314
|
+
add_rss(m, params, true)
|
315
|
+
end
|
316
|
+
|
317
|
+
def watch_rss(m, params)
|
318
|
+
handle = params[:handle]
|
319
|
+
url = params[:url]
|
320
|
+
type = params[:type]
|
321
|
+
if url
|
322
|
+
add_rss(m, params)
|
323
|
+
end
|
324
|
+
feed = nil
|
325
|
+
@@mutex.synchronize {
|
326
|
+
feed = @feeds.fetch(handle, nil)
|
327
|
+
}
|
328
|
+
if feed
|
329
|
+
@@mutex.synchronize {
|
330
|
+
if feed.add_watch(m.replyto)
|
331
|
+
watchRss(feed, m)
|
332
|
+
m.okay
|
333
|
+
else
|
334
|
+
m.reply "Already watching #{feed.handle}"
|
335
|
+
end
|
336
|
+
}
|
337
|
+
else
|
338
|
+
m.reply "Couldn't watch feed #{handle} (no such feed found)"
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def unwatch_rss(m, params, pass=false)
|
343
|
+
handle = params[:handle]
|
344
|
+
unless @feeds.has_key?(handle)
|
345
|
+
m.reply("dunno that feed")
|
346
|
+
return
|
347
|
+
end
|
348
|
+
feed = @feeds[handle]
|
349
|
+
if feed.rm_watch(m.replyto)
|
350
|
+
m.reply "#{m.replyto} has been removed from the watchlist for #{feed.handle}"
|
351
|
+
else
|
352
|
+
m.reply("#{m.replyto} wasn't watching #{feed.handle}") unless pass
|
353
|
+
end
|
354
|
+
if !feed.watched?
|
355
|
+
@@mutex.synchronize {
|
356
|
+
if @@watchThreads[handle].kind_of? Thread
|
357
|
+
@@watchThreads[handle].kill
|
358
|
+
debug "rmwatch: Killed thread for #{handle}"
|
359
|
+
@@watchThreads.delete(handle)
|
360
|
+
end
|
361
|
+
}
|
362
|
+
end
|
363
|
+
return feed
|
364
|
+
end
|
365
|
+
|
366
|
+
def rewatch_rss(m=nil)
|
367
|
+
kill_threads
|
368
|
+
|
369
|
+
# Read watches from list.
|
370
|
+
watchlist.each{ |handle, feed|
|
371
|
+
watchRss(feed, m)
|
372
|
+
}
|
373
|
+
m.okay if m
|
374
|
+
end
|
375
|
+
|
376
|
+
private
|
377
|
+
def watchRss(feed, m=nil)
|
378
|
+
if @@watchThreads.has_key?(feed.handle)
|
379
|
+
report_problem("watcher thread for #{feed.handle} is already running", nil, m)
|
380
|
+
return
|
381
|
+
end
|
382
|
+
@@watchThreads[feed.handle] = Thread.new do
|
383
|
+
debug "watcher for #{feed} started"
|
384
|
+
oldItems = []
|
385
|
+
firstRun = true
|
386
|
+
failures = 0
|
387
|
+
loop do
|
388
|
+
begin
|
389
|
+
debug "fetching #{feed}"
|
390
|
+
title = newItems = nil
|
391
|
+
@@mutex.synchronize {
|
392
|
+
title, newItems = fetchRss(feed)
|
393
|
+
}
|
394
|
+
unless newItems
|
395
|
+
debug "no items in feed #{feed}"
|
396
|
+
failures +=1
|
397
|
+
else
|
398
|
+
debug "Checking if new items are available for #{feed}"
|
399
|
+
if firstRun
|
400
|
+
debug "First run, we'll see next time"
|
401
|
+
firstRun = false
|
402
|
+
else
|
403
|
+
otxt = oldItems.map { |item| item.to_s }
|
404
|
+
dispItems = newItems.reject { |item|
|
405
|
+
otxt.include?(item.to_s)
|
406
|
+
}
|
407
|
+
if dispItems.length > 0
|
408
|
+
debug "Found #{dispItems.length} new items in #{feed}"
|
409
|
+
dispItems.each { |item|
|
410
|
+
@@mutex.synchronize {
|
411
|
+
printFormattedRss(feed, item)
|
412
|
+
}
|
413
|
+
}
|
414
|
+
else
|
415
|
+
debug "No new items found in #{feed}"
|
416
|
+
end
|
417
|
+
end
|
418
|
+
oldItems = newItems.dup
|
419
|
+
end
|
420
|
+
rescue Exception => e
|
421
|
+
error "Error watching #{feed}: #{e.inspect}"
|
422
|
+
debug e.backtrace.join("\n")
|
423
|
+
failures += 1
|
424
|
+
end
|
425
|
+
|
426
|
+
seconds = @bot.config['rss.thread_sleep'] * (failures + 1)
|
427
|
+
seconds += seconds * (rand(100)-50)/100
|
428
|
+
debug "watcher for #{feed} going to sleep #{seconds} seconds.."
|
429
|
+
sleep seconds
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def printFormattedRss(feed, item, opts=nil)
|
435
|
+
places = feed.watchers
|
436
|
+
handle = "::#{feed.handle}:: "
|
437
|
+
date = String.new
|
438
|
+
if opts
|
439
|
+
places = opts[:places] if opts.key?(:places)
|
440
|
+
handle = opts[:handle].to_s if opts.key?(:handle)
|
441
|
+
if opts.key?(:date) && opts[:date]
|
442
|
+
if item.respond_to?(:pubDate)
|
443
|
+
if item.pubDate.class <= Time
|
444
|
+
date = item.pubDate.strftime("%Y/%m/%d %H.%M.%S")
|
445
|
+
else
|
446
|
+
date = item.pubDate.to_s
|
447
|
+
end
|
448
|
+
elsif item.respond_to?(:date)
|
449
|
+
if item.date.class <= Time
|
450
|
+
date = item.date.strftime("%Y/%m/%d %H.%M.%S")
|
451
|
+
else
|
452
|
+
date = item.date.to_s
|
453
|
+
end
|
454
|
+
else
|
455
|
+
date = "(no date)"
|
456
|
+
end
|
457
|
+
date += " :: "
|
458
|
+
end
|
459
|
+
end
|
460
|
+
title = "#{Bold}#{item.title.chomp.riphtml}#{Bold}" if item.title
|
461
|
+
desc = item.description.gsub(/\s+/,' ').strip.riphtml.shorten(@bot.config['rss.text_max']) if item.description
|
462
|
+
link = item.link.chomp if item.link
|
463
|
+
places.each { |loc|
|
464
|
+
case feed.type
|
465
|
+
when 'blog'
|
466
|
+
@bot.say loc, "#{handle}#{date}#{item.category.content} blogged at #{link}"
|
467
|
+
@bot.say loc, "#{handle}#{title} - #{desc}"
|
468
|
+
when 'forum'
|
469
|
+
@bot.say loc, "#{handle}#{date}#{title}#{' @ ' if item.title && item.link}#{link}"
|
470
|
+
when 'wiki'
|
471
|
+
@bot.say loc, "#{handle}#{date}#{item.title} has been edited by #{item.dc_creator}. #{desc} #{link}"
|
472
|
+
when 'gmame'
|
473
|
+
@bot.say loc, "#{handle}#{date}Message #{title} sent by #{item.dc_creator}. #{desc}"
|
474
|
+
when 'trac'
|
475
|
+
@bot.say loc, "#{handle}#{date}#{title} @ #{link}"
|
476
|
+
unless item.title =~ /^Changeset \[(\d+)\]/
|
477
|
+
@bot.say loc, "#{handle}#{date}#{desc}"
|
478
|
+
end
|
479
|
+
else
|
480
|
+
@bot.say loc, "#{handle}#{date}#{title}#{' @ ' if item.title && item.link}#{link}"
|
481
|
+
end
|
482
|
+
}
|
483
|
+
end
|
484
|
+
|
485
|
+
def fetchRss(feed, m=nil)
|
486
|
+
begin
|
487
|
+
# Use 60 sec timeout, cause the default is too low
|
488
|
+
# Do not use get_cached for RSS until we have proper cache handling
|
489
|
+
# xml = @bot.httputil.get_cached(feed.url,60,60)
|
490
|
+
xml = @bot.httputil.get(feed.url,60,60)
|
491
|
+
rescue URI::InvalidURIError, URI::BadURIError => e
|
492
|
+
report_problem("invalid rss feed #{feed.url}", e, m)
|
493
|
+
return
|
494
|
+
rescue => e
|
495
|
+
report_problem("error getting #{feed.url}", e, m)
|
496
|
+
return
|
497
|
+
end
|
498
|
+
debug "fetched #{feed}"
|
499
|
+
unless xml
|
500
|
+
report_problem("reading feed #{feed} failed", nil, m)
|
501
|
+
return
|
502
|
+
end
|
503
|
+
|
504
|
+
begin
|
505
|
+
## do validate parse
|
506
|
+
rss = RSS::Parser.parse(xml)
|
507
|
+
debug "parsed #{feed}"
|
508
|
+
rescue RSS::InvalidRSSError
|
509
|
+
## do non validate parse for invalid RSS 1.0
|
510
|
+
begin
|
511
|
+
rss = RSS::Parser.parse(xml, false)
|
512
|
+
rescue RSS::Error => e
|
513
|
+
report_problem("parsing rss stream failed, whoops =(", e, m)
|
514
|
+
return
|
515
|
+
end
|
516
|
+
rescue RSS::Error => e
|
517
|
+
report_problem("parsing rss stream failed, oioi", e, m)
|
518
|
+
return
|
519
|
+
rescue => e
|
520
|
+
report_problem("processing error occured, sorry =(", e, m)
|
521
|
+
return
|
522
|
+
end
|
523
|
+
items = []
|
524
|
+
if rss.nil?
|
525
|
+
report_problem("#{feed} does not include RSS 1.0 or 0.9x/2.0", nil, m)
|
526
|
+
else
|
527
|
+
begin
|
528
|
+
rss.output_encoding = 'UTF-8'
|
529
|
+
rescue RSS::UnknownConvertMethod => e
|
530
|
+
report_problem("bah! something went wrong =(", e, m)
|
531
|
+
return
|
532
|
+
end
|
533
|
+
rss.channel.title ||= "Unknown"
|
534
|
+
title = rss.channel.title
|
535
|
+
rss.items.each do |item|
|
536
|
+
item.title ||= "Unknown"
|
537
|
+
items << item
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
if items.empty?
|
542
|
+
report_problem("no items found in the feed, maybe try weed?", e, m)
|
543
|
+
return
|
544
|
+
end
|
545
|
+
return [title, items]
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
plugin = RSSFeedsPlugin.new
|
550
|
+
|
551
|
+
plugin.map 'rss show :handle :limit',
|
552
|
+
:action => 'show_rss',
|
553
|
+
:requirements => {:limit => /^\d+(?:\.\.\d+)?$/},
|
554
|
+
:defaults => {:limit => 5}
|
555
|
+
plugin.map 'rss list :handle',
|
556
|
+
:action => 'list_rss',
|
557
|
+
:defaults => {:handle => nil}
|
558
|
+
plugin.map 'rss watched :handle',
|
559
|
+
:action => 'watched_rss',
|
560
|
+
:defaults => {:handle => nil}
|
561
|
+
plugin.map 'rss add :handle :url :type',
|
562
|
+
:action => 'add_rss',
|
563
|
+
:defaults => {:type => nil}
|
564
|
+
plugin.map 'rss del :handle',
|
565
|
+
:action => 'del_rss'
|
566
|
+
plugin.map 'rss delete :handle',
|
567
|
+
:action => 'del_rss'
|
568
|
+
plugin.map 'rss rm :handle',
|
569
|
+
:action => 'del_rss'
|
570
|
+
plugin.map 'rss replace :handle :url :type',
|
571
|
+
:action => 'replace_rss',
|
572
|
+
:defaults => {:type => nil}
|
573
|
+
plugin.map 'rss forcereplace :handle :url :type',
|
574
|
+
:action => 'forcereplace_rss',
|
575
|
+
:defaults => {:type => nil}
|
576
|
+
plugin.map 'rss watch :handle :url :type',
|
577
|
+
:action => 'watch_rss',
|
578
|
+
:defaults => {:url => nil, :type => nil}
|
579
|
+
plugin.map 'rss unwatch :handle',
|
580
|
+
:action => 'unwatch_rss'
|
581
|
+
plugin.map 'rss rmwatch :handle',
|
582
|
+
:action => 'unwatch_rss'
|
583
|
+
plugin.map 'rss rewatch :handle',
|
584
|
+
:action => 'rewatch_rss'
|
585
|
+
|