rbot 0.9.9 → 0.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|