rbot 0.9.14 → 0.9.15
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +6 -2
- data/REQUIREMENTS +7 -1
- data/Rakefile +10 -32
- data/bin/rbot +6 -1
- data/bin/svnwatch-postcommit-hook +68 -0
- data/data/rbot/contrib/plugins/stats.rb +3 -3
- data/data/rbot/contrib/plugins/vandale.rb +1 -1
- data/data/rbot/filters/rss.rb +72 -0
- data/data/rbot/languages/finnish.lang +50 -0
- data/data/rbot/plugins/alias.rb +6 -6
- data/data/rbot/plugins/autorejoin.rb +41 -2
- data/data/rbot/plugins/bans.rb +100 -6
- data/data/rbot/plugins/bash.rb +9 -4
- data/data/rbot/plugins/cal.rb +1 -1
- data/data/rbot/plugins/chucknorris.rb +6 -6
- data/data/rbot/plugins/debugger.rb +7 -3
- data/data/rbot/plugins/deepthoughts.rb +1 -1
- data/data/rbot/plugins/delicious.rb +6 -2
- data/data/rbot/plugins/dice.rb +7 -7
- data/data/rbot/plugins/dict.rb +4 -3
- data/data/rbot/plugins/dictclient.rb +17 -13
- data/data/rbot/plugins/digg.rb +3 -3
- data/data/rbot/plugins/eightball.rb +1 -1
- data/data/rbot/plugins/factoids.rb +13 -4
- data/data/rbot/plugins/figlet.rb +4 -4
- data/data/rbot/plugins/forecast.rb +3 -3
- data/data/rbot/plugins/fortune.rb +14 -8
- data/data/rbot/plugins/freshmeat.rb +2 -2
- data/data/rbot/plugins/games/azgame.rb +72 -19
- data/data/rbot/plugins/games/hangman.rb +499 -0
- data/data/rbot/plugins/games/quiz.rb +15 -13
- data/data/rbot/plugins/games/roshambo.rb +1 -1
- data/data/rbot/plugins/games/roulette.rb +4 -4
- data/data/rbot/plugins/games/shiritori.rb +31 -31
- data/data/rbot/plugins/games/uno.rb +28 -6
- data/data/rbot/plugins/games/wheelfortune.rb +1 -3
- data/data/rbot/plugins/geoip.rb +83 -28
- data/data/rbot/plugins/googlefight.rb +64 -0
- data/data/rbot/plugins/greet.rb +45 -0
- data/data/rbot/plugins/grouphug.rb +40 -12
- data/data/rbot/plugins/imdb.rb +4 -4
- data/data/rbot/plugins/insult.rb +2 -2
- data/data/rbot/plugins/karma.rb +6 -5
- data/data/rbot/plugins/keywords.rb +26 -22
- data/data/rbot/plugins/lart.rb +5 -6
- data/data/rbot/plugins/lastfm.rb +488 -125
- data/data/rbot/plugins/lib_spotify.rb +84 -0
- data/data/rbot/plugins/linkbot.rb +1 -1
- data/data/rbot/plugins/markov.rb +567 -78
- data/data/rbot/plugins/math.rb +3 -3
- data/data/rbot/plugins/modes.rb +1 -1
- data/data/rbot/plugins/nickrecover.rb +1 -1
- data/data/rbot/plugins/nickserv.rb +7 -7
- data/data/rbot/plugins/note.rb +55 -0
- data/data/rbot/plugins/nslookup.rb +2 -2
- data/data/rbot/plugins/quakeauth.rb +4 -4
- data/data/rbot/plugins/quotes.rb +53 -19
- data/data/rbot/plugins/reaction.rb +76 -19
- data/data/rbot/plugins/remind.rb +3 -96
- data/data/rbot/plugins/ri.rb +1 -1
- data/data/rbot/plugins/rot13.rb +1 -1
- data/data/rbot/plugins/rss.rb +296 -190
- data/data/rbot/plugins/salut.rb +8 -8
- data/data/rbot/plugins/script.rb +48 -11
- data/data/rbot/plugins/search.rb +124 -28
- data/data/rbot/plugins/seen.rb +162 -31
- data/data/rbot/plugins/shortenurls.rb +1 -1
- data/data/rbot/plugins/slashdot.rb +19 -6
- data/data/rbot/plugins/spotify.rb +78 -0
- data/data/rbot/plugins/theyfightcrime.rb +10 -10
- data/data/rbot/plugins/time.rb +2 -2
- data/data/rbot/plugins/translator.rb +161 -85
- data/data/rbot/plugins/tube.rb +2 -2
- data/data/rbot/plugins/tumblr.rb +143 -0
- data/data/rbot/plugins/twitter.rb +25 -6
- data/data/rbot/plugins/urban.rb +6 -4
- data/data/rbot/plugins/url.rb +49 -10
- data/data/rbot/plugins/weather.rb +6 -6
- data/data/rbot/plugins/wserver.rb +5 -5
- data/data/rbot/plugins/youtube.rb +12 -12
- data/data/rbot/templates/lart/larts-italian +1 -1
- data/launch_here.rb +68 -0
- data/lib/rbot/botuser.rb +1 -1
- data/lib/rbot/compat19.rb +70 -0
- data/lib/rbot/config.rb +8 -6
- data/lib/rbot/core/auth.rb +37 -21
- data/lib/rbot/core/basics.rb +33 -2
- data/lib/rbot/core/config.rb +24 -17
- data/lib/rbot/core/filters_ui.rb +2 -2
- data/lib/rbot/core/irclog.rb +20 -11
- data/lib/rbot/core/remote.rb +9 -9
- data/lib/rbot/core/unicode.rb +4 -0
- data/lib/rbot/core/userdata.rb +16 -1
- data/lib/rbot/core/utils/extends.rb +76 -0
- data/lib/rbot/core/utils/filters.rb +47 -0
- data/lib/rbot/core/utils/httputil.rb +36 -26
- data/lib/rbot/core/utils/parse_time.rb +193 -0
- data/lib/rbot/core/utils/utils.rb +81 -56
- data/lib/rbot/core/utils/wordlist.rb +66 -0
- data/lib/rbot/core/wordlist_ui.rb +27 -0
- data/lib/rbot/irc.rb +59 -19
- data/lib/rbot/ircbot.rb +190 -58
- data/lib/rbot/ircsocket.rb +14 -8
- data/lib/rbot/language.rb +4 -3
- data/lib/rbot/load-gettext.rb +22 -9
- data/lib/rbot/message.rb +89 -18
- data/lib/rbot/messagemapper.rb +71 -19
- data/lib/rbot/plugins.rb +112 -44
- data/lib/rbot/{registry.rb → registry/bdb.rb} +226 -22
- data/lib/rbot/registry/tc.rb +531 -0
- data/lib/rbot/rfc2812.rb +33 -8
- data/lib/rbot/timer.rb +12 -20
- data/po/en_US/rbot-autorejoin.po +3 -0
- data/po/en_US/rbot-azgame.po +51 -43
- data/po/en_US/rbot-bash.po +15 -0
- data/po/en_US/rbot-dictclient.po +20 -20
- data/po/en_US/rbot-factoids.po +9 -9
- data/po/en_US/rbot-geoip.po +0 -0
- data/po/en_US/rbot-googlefight.po +24 -0
- data/po/en_US/rbot-grouphug.po +4 -4
- data/po/en_US/rbot-hangman.po +114 -0
- data/po/en_US/rbot-keywords.po +3 -3
- data/po/en_US/rbot-lastfm.po +268 -70
- data/po/en_US/rbot-markov.po +73 -2
- data/po/en_US/rbot-quotes.po +21 -21
- data/po/en_US/rbot-rss.po +6 -2
- data/po/en_US/rbot-script.po +3 -0
- data/po/en_US/rbot-seen.po +72 -0
- data/po/en_US/rbot-spell.po +2 -2
- data/po/en_US/rbot-translator.po +13 -13
- data/po/en_US/rbot-twitter.po +3 -3
- data/po/en_US/rbot-uno.po +131 -114
- data/po/en_US/rbot-wall.po +12 -13
- data/po/en_US/rbot-wheelfortune.po +41 -41
- data/po/en_US/rbot.po +254 -194
- data/po/fi/rbot-alias.po +82 -0
- data/po/fi/rbot-autoop.po +0 -0
- data/po/fi/rbot-autorejoin.po +20 -0
- data/po/fi/rbot-azgame.po +194 -0
- data/po/fi/rbot-bans.po +0 -0
- data/po/fi/rbot-bash.po +32 -0
- data/po/fi/rbot-botsnack.po +0 -0
- data/po/fi/rbot-cal.po +20 -0
- data/po/fi/rbot-chanserv.po +0 -0
- data/po/fi/rbot-chucknorris.po +0 -0
- data/po/fi/rbot-debugger.po +0 -0
- data/po/fi/rbot-deepthoughts.po +0 -0
- data/po/fi/rbot-delicious.po +0 -0
- data/po/fi/rbot-dice.po +0 -0
- data/po/fi/rbot-dict.po +0 -0
- data/po/fi/rbot-dictclient.po +111 -0
- data/po/fi/rbot-digg.po +0 -0
- data/po/fi/rbot-eightball.po +0 -0
- data/po/fi/rbot-excuse.po +0 -0
- data/po/fi/rbot-factoids.po +107 -0
- data/po/fi/rbot-figlet.po +36 -0
- data/po/fi/rbot-fish.po +0 -0
- data/po/fi/rbot-forecast.po +0 -0
- data/po/fi/rbot-fortune.po +0 -0
- data/po/fi/rbot-freshmeat.po +0 -0
- data/po/fi/rbot-geoip.po +0 -0
- data/po/fi/rbot-googlefight.po +24 -0
- data/po/fi/rbot-grouphug.po +35 -0
- data/po/fi/rbot-hangman.po +121 -0
- data/po/fi/rbot-hl2.po +0 -0
- data/po/fi/rbot-host.po +20 -0
- data/po/fi/rbot-imdb.po +0 -0
- data/po/fi/rbot-insult.po +0 -0
- data/po/fi/rbot-iplookup.po +0 -0
- data/po/fi/rbot-karma.po +0 -0
- data/po/fi/rbot-keywords.po +24 -0
- data/po/fi/rbot-lart.po +0 -0
- data/po/fi/rbot-lastfm.po +377 -0
- data/po/fi/rbot-linkbot.po +0 -0
- data/po/fi/rbot-markov.po +91 -0
- data/po/fi/rbot-math.po +0 -0
- data/po/fi/rbot-modes.po +0 -0
- data/po/fi/rbot-nickrecover.po +36 -0
- data/po/fi/rbot-nickserv.po +104 -0
- data/po/fi/rbot-nslookup.po +0 -0
- data/po/fi/rbot-quakeauth.po +0 -0
- data/po/fi/rbot-quiz.po +0 -0
- data/po/fi/rbot-quotes.po +108 -0
- data/po/fi/rbot-reaction.po +0 -0
- data/po/fi/rbot-remind.po +0 -0
- data/po/fi/rbot-remotectl.po +0 -0
- data/po/fi/rbot-ri.po +0 -0
- data/po/fi/rbot-roshambo.po +0 -0
- data/po/fi/rbot-rot13.po +0 -0
- data/po/fi/rbot-roulette.po +0 -0
- data/po/fi/rbot-rss.po +24 -0
- data/po/fi/rbot-salut.po +0 -0
- data/po/fi/rbot-script.po +20 -0
- data/po/fi/rbot-search.po +0 -0
- data/po/fi/rbot-seen.po +92 -0
- data/po/fi/rbot-shiritori.po +102 -0
- data/po/fi/rbot-shortenurls.po +0 -0
- data/po/fi/rbot-slashdot.po +0 -0
- data/po/fi/rbot-spell.po +54 -0
- data/po/fi/rbot-theyfightcrime.po +0 -0
- data/po/fi/rbot-threat.po +0 -0
- data/po/fi/rbot-time.po +0 -0
- data/po/fi/rbot-topic.po +0 -0
- data/po/fi/rbot-translator.po +77 -0
- data/po/fi/rbot-tube.po +0 -0
- data/po/fi/rbot-twitter.po +24 -0
- data/po/fi/rbot-uno.po +529 -0
- data/po/fi/rbot-urban.po +0 -0
- data/po/fi/rbot-url.po +0 -0
- data/po/fi/rbot-usermodes.po +0 -0
- data/po/fi/rbot-wall.po +32 -0
- data/po/fi/rbot-weather.po +0 -0
- data/po/fi/rbot-wheelfortune.po +205 -0
- data/po/fi/rbot-wow.po +0 -0
- data/po/fi/rbot-wserver.po +0 -0
- data/po/fi/rbot-youtube.po +58 -0
- data/po/fi/rbot.po +1152 -0
- data/po/fr/rbot-autorejoin.po +3 -0
- data/po/fr/rbot-azgame.po +51 -43
- data/po/fr/rbot-bash.po +15 -0
- data/po/fr/rbot-dictclient.po +20 -20
- data/po/fr/rbot-factoids.po +9 -9
- data/po/fr/rbot-geoip.po +0 -0
- data/po/fr/rbot-googlefight.po +24 -0
- data/po/fr/rbot-grouphug.po +4 -4
- data/po/fr/rbot-hangman.po +114 -0
- data/po/fr/rbot-keywords.po +3 -3
- data/po/fr/rbot-lastfm.po +268 -70
- data/po/fr/rbot-markov.po +74 -2
- data/po/fr/rbot-quotes.po +21 -21
- data/po/fr/rbot-rss.po +6 -2
- data/po/fr/rbot-script.po +3 -0
- data/po/fr/rbot-seen.po +72 -0
- data/po/fr/rbot-spell.po +2 -2
- data/po/fr/rbot-translator.po +13 -13
- data/po/fr/rbot-twitter.po +3 -3
- data/po/fr/rbot-uno.po +132 -114
- data/po/fr/rbot-wall.po +8 -9
- data/po/fr/rbot-wheelfortune.po +41 -41
- data/po/fr/rbot.po +268 -197
- data/po/it/rbot-autorejoin.po +3 -0
- data/po/it/rbot-azgame.po +50 -42
- data/po/it/rbot-bash.po +15 -0
- data/po/it/rbot-dictclient.po +20 -20
- data/po/it/rbot-factoids.po +9 -9
- data/po/it/rbot-geoip.po +0 -0
- data/po/it/rbot-googlefight.po +24 -0
- data/po/it/rbot-grouphug.po +4 -4
- data/po/it/rbot-hangman.po +114 -0
- data/po/it/rbot-keywords.po +3 -3
- data/po/it/rbot-lastfm.po +268 -70
- data/po/it/rbot-markov.po +75 -3
- data/po/it/rbot-quotes.po +21 -21
- data/po/it/rbot-rss.po +7 -3
- data/po/it/rbot-script.po +19 -0
- data/po/it/rbot-seen.po +72 -0
- data/po/it/rbot-spell.po +2 -2
- data/po/it/rbot-translator.po +13 -13
- data/po/it/rbot-twitter.po +3 -3
- data/po/it/rbot-uno.po +137 -116
- data/po/it/rbot-wall.po +8 -9
- data/po/it/rbot-wheelfortune.po +41 -41
- data/po/it/rbot.po +265 -208
- data/po/ja/rbot-autorejoin.po +3 -0
- data/po/ja/rbot-azgame.po +51 -43
- data/po/ja/rbot-bash.po +15 -0
- data/po/ja/rbot-dictclient.po +20 -20
- data/po/ja/rbot-factoids.po +9 -9
- data/po/ja/rbot-geoip.po +0 -0
- data/po/ja/rbot-googlefight.po +24 -0
- data/po/ja/rbot-grouphug.po +4 -4
- data/po/ja/rbot-hangman.po +114 -0
- data/po/ja/rbot-keywords.po +3 -3
- data/po/ja/rbot-lastfm.po +268 -70
- data/po/ja/rbot-markov.po +73 -2
- data/po/ja/rbot-quotes.po +21 -21
- data/po/ja/rbot-rss.po +6 -2
- data/po/ja/rbot-script.po +3 -0
- data/po/ja/rbot-seen.po +72 -0
- data/po/ja/rbot-spell.po +2 -2
- data/po/ja/rbot-translator.po +13 -13
- data/po/ja/rbot-twitter.po +3 -3
- data/po/ja/rbot-uno.po +131 -114
- data/po/ja/rbot-wall.po +8 -9
- data/po/ja/rbot-wheelfortune.po +41 -41
- data/po/ja/rbot.po +248 -192
- data/po/rbot-alias.pot +2 -2
- data/po/rbot-autorejoin.pot +21 -0
- data/po/rbot-azgame.pot +51 -43
- data/po/rbot-bash.pot +33 -0
- data/po/rbot-cal.pot +2 -2
- data/po/rbot-dictclient.pot +21 -21
- data/po/rbot-factoids.pot +10 -10
- data/po/rbot-figlet.pot +2 -2
- data/po/rbot-geoip.pot +0 -0
- data/po/rbot-googlefight.pot +25 -0
- data/po/rbot-grouphug.pot +6 -6
- data/po/rbot-hangman.pot +115 -0
- data/po/rbot-host.pot +2 -2
- data/po/rbot-keywords.pot +4 -4
- data/po/rbot-lastfm.pot +270 -72
- data/po/rbot-markov.pot +74 -3
- data/po/rbot-nickrecover.pot +2 -2
- data/po/rbot-nickserv.pot +2 -2
- data/po/rbot-quotes.pot +22 -22
- data/po/rbot-rss.pot +7 -3
- data/po/rbot-script.pot +21 -0
- data/po/rbot-seen.pot +90 -0
- data/po/rbot-shiritori.pot +2 -2
- data/po/rbot-spell.pot +3 -3
- data/po/rbot-translator.pot +14 -14
- data/po/rbot-twitter.pot +4 -4
- data/po/rbot-uno.pot +132 -115
- data/po/rbot-wall.pot +2 -2
- data/po/rbot-wheelfortune.pot +42 -42
- data/po/rbot-youtube.pot +2 -2
- data/po/rbot.pot +249 -193
- data/po/zh_CN/rbot-autorejoin.po +3 -0
- data/po/zh_CN/rbot-azgame.po +50 -42
- data/po/zh_CN/rbot-bash.po +15 -0
- data/po/zh_CN/rbot-dictclient.po +20 -20
- data/po/zh_CN/rbot-factoids.po +9 -9
- data/po/zh_CN/rbot-geoip.po +0 -0
- data/po/zh_CN/rbot-googlefight.po +24 -0
- data/po/zh_CN/rbot-grouphug.po +4 -4
- data/po/zh_CN/rbot-hangman.po +114 -0
- data/po/zh_CN/rbot-keywords.po +3 -3
- data/po/zh_CN/rbot-lastfm.po +268 -70
- data/po/zh_CN/rbot-markov.po +73 -2
- data/po/zh_CN/rbot-quotes.po +21 -21
- data/po/zh_CN/rbot-rss.po +6 -2
- data/po/zh_CN/rbot-script.po +3 -0
- data/po/zh_CN/rbot-seen.po +72 -0
- data/po/zh_CN/rbot-spell.po +2 -2
- data/po/zh_CN/rbot-translator.po +13 -13
- data/po/zh_CN/rbot-twitter.po +3 -3
- data/po/zh_CN/rbot-uno.po +131 -114
- data/po/zh_CN/rbot-wall.po +7 -8
- data/po/zh_CN/rbot-wheelfortune.po +41 -41
- data/po/zh_CN/rbot.po +248 -192
- data/po/zh_TW/rbot-autorejoin.po +3 -0
- data/po/zh_TW/rbot-azgame.po +50 -42
- data/po/zh_TW/rbot-bash.po +15 -0
- data/po/zh_TW/rbot-dictclient.po +20 -20
- data/po/zh_TW/rbot-factoids.po +9 -9
- data/po/zh_TW/rbot-geoip.po +0 -0
- data/po/zh_TW/rbot-googlefight.po +24 -0
- data/po/zh_TW/rbot-grouphug.po +4 -4
- data/po/zh_TW/rbot-hangman.po +114 -0
- data/po/zh_TW/rbot-keywords.po +3 -3
- data/po/zh_TW/rbot-lastfm.po +268 -70
- data/po/zh_TW/rbot-markov.po +73 -2
- data/po/zh_TW/rbot-quotes.po +21 -21
- data/po/zh_TW/rbot-rss.po +6 -2
- data/po/zh_TW/rbot-script.po +3 -0
- data/po/zh_TW/rbot-seen.po +72 -0
- data/po/zh_TW/rbot-spell.po +2 -2
- data/po/zh_TW/rbot-translator.po +13 -13
- data/po/zh_TW/rbot-twitter.po +3 -3
- data/po/zh_TW/rbot-uno.po +131 -114
- data/po/zh_TW/rbot-wall.po +7 -8
- data/po/zh_TW/rbot-wheelfortune.po +41 -41
- data/po/zh_TW/rbot.po +253 -194
- data/setup.rb +4 -4
- metadata +127 -18
- data/README +0 -43
- data/data/rbot/plugins/fish.rb +0 -121
- data/lib/rbot/dbhash.rb +0 -199
data/data/rbot/plugins/remind.rb
CHANGED
@@ -5,100 +5,7 @@ class RemindPlugin < Plugin
|
|
5
5
|
#
|
6
6
|
# Throws:: RunTimeError "invalid time string" on parse failure
|
7
7
|
def timestr_offset(timestr)
|
8
|
-
|
9
|
-
when (/^(\S+)\s+(\S+)$/)
|
10
|
-
mult = $1
|
11
|
-
unit = $2
|
12
|
-
if(mult =~ /^([\d.]+)$/)
|
13
|
-
num = $1.to_f
|
14
|
-
raise "invalid time string" unless num
|
15
|
-
else
|
16
|
-
case mult
|
17
|
-
when(/^(one|an|a)$/)
|
18
|
-
num = 1
|
19
|
-
when(/^two$/)
|
20
|
-
num = 2
|
21
|
-
when(/^three$/)
|
22
|
-
num = 3
|
23
|
-
when(/^four$/)
|
24
|
-
num = 4
|
25
|
-
when(/^five$/)
|
26
|
-
num = 5
|
27
|
-
when(/^six$/)
|
28
|
-
num = 6
|
29
|
-
when(/^seven$/)
|
30
|
-
num = 7
|
31
|
-
when(/^eight$/)
|
32
|
-
num = 8
|
33
|
-
when(/^nine$/)
|
34
|
-
num = 9
|
35
|
-
when(/^ten$/)
|
36
|
-
num = 10
|
37
|
-
when(/^fifteen$/)
|
38
|
-
num = 15
|
39
|
-
when(/^twenty$/)
|
40
|
-
num = 20
|
41
|
-
when(/^thirty$/)
|
42
|
-
num = 30
|
43
|
-
when(/^sixty$/)
|
44
|
-
num = 60
|
45
|
-
else
|
46
|
-
raise "invalid time string"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
case unit
|
50
|
-
when (/^(s|sec(ond)?s?)$/)
|
51
|
-
return num
|
52
|
-
when (/^(m|min(ute)?s?)$/)
|
53
|
-
return num * 60
|
54
|
-
when (/^(h|h(ou)?rs?)$/)
|
55
|
-
return num * 60 * 60
|
56
|
-
when (/^(d|days?)$/)
|
57
|
-
return num * 60 * 60 * 24
|
58
|
-
else
|
59
|
-
raise "invalid time string"
|
60
|
-
end
|
61
|
-
when (/^(\d+):(\d+):(\d+)$/)
|
62
|
-
hour = $1.to_i
|
63
|
-
min = $2.to_i
|
64
|
-
sec = $3.to_i
|
65
|
-
now = Time.now
|
66
|
-
later = Time.mktime(now.year, now.month, now.day, hour, min, sec)
|
67
|
-
return later - now
|
68
|
-
when (/^(\d+):(\d+)$/)
|
69
|
-
hour = $1.to_i
|
70
|
-
min = $2.to_i
|
71
|
-
now = Time.now
|
72
|
-
later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
|
73
|
-
return later - now
|
74
|
-
when (/^(\d+):(\d+)(am|pm)$/)
|
75
|
-
hour = $1.to_i
|
76
|
-
min = $2.to_i
|
77
|
-
ampm = $3
|
78
|
-
if ampm == "pm"
|
79
|
-
hour += 12
|
80
|
-
end
|
81
|
-
now = Time.now
|
82
|
-
later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
|
83
|
-
return later - now
|
84
|
-
when (/^(\S+)$/)
|
85
|
-
num = 1
|
86
|
-
unit = $1
|
87
|
-
case unit
|
88
|
-
when (/^(s|sec(ond)?s?)$/)
|
89
|
-
return num
|
90
|
-
when (/^(m|min(ute)?s?)$/)
|
91
|
-
return num * 60
|
92
|
-
when (/^(h|h(ou)?rs?)$/)
|
93
|
-
return num * 60 * 60
|
94
|
-
when (/^(d|days?)$/)
|
95
|
-
return num * 60 * 60 * 24
|
96
|
-
else
|
97
|
-
raise "invalid time string"
|
98
|
-
end
|
99
|
-
else
|
100
|
-
raise "invalid time string"
|
101
|
-
end
|
8
|
+
Utils.parse_time_offset(timestr)
|
102
9
|
end
|
103
10
|
|
104
11
|
def initialize
|
@@ -202,11 +109,11 @@ class RemindPlugin < Plugin
|
|
202
109
|
end
|
203
110
|
def no_more(m, params)
|
204
111
|
who = params.has_key?(:who) ? params[:who] : m.sourcenick
|
205
|
-
deleted = params.has_key?(:string) ?
|
112
|
+
deleted = params.has_key?(:string) ?
|
206
113
|
del_reminder(who, params[:string].to_s) : del_reminder(who)
|
207
114
|
if deleted
|
208
115
|
m.okay
|
209
|
-
else
|
116
|
+
else
|
210
117
|
m.reply "but I wasn't going to :/"
|
211
118
|
end
|
212
119
|
end
|
data/data/rbot/plugins/ri.rb
CHANGED
@@ -52,7 +52,7 @@ class RiPlugin < Plugin
|
|
52
52
|
return m.reply("failed to execute ri")
|
53
53
|
end
|
54
54
|
ret = ret.gsub(/\t/, " ").split(/\n/).join(" ").gsub(/\s\s+/, ' ')
|
55
|
-
|
55
|
+
|
56
56
|
if ret.length > @bot.config['ri.max_length']
|
57
57
|
if !m.private? && tgt.to_s != m.sourcenick
|
58
58
|
return m.reply('entry is too long to send to the channel or to some other user, use /msg to ask me about it')
|
data/data/rbot/plugins/rot13.rb
CHANGED
data/data/rbot/plugins/rss.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'rss'
|
18
18
|
|
19
|
-
# Try to load rss/content/2.0 so we can access the data in <content:encoded>
|
19
|
+
# Try to load rss/content/2.0 so we can access the data in <content:encoded>
|
20
20
|
# tags.
|
21
21
|
begin
|
22
22
|
require 'rss/content/2.0'
|
@@ -150,12 +150,50 @@ module ::RSS
|
|
150
150
|
|
151
151
|
SlashModel::ELEMENTS.collect! {|name| "#{SLASH_PREFIX}_#{name}"}
|
152
152
|
end
|
153
|
+
|
154
|
+
class Element
|
155
|
+
class << self
|
156
|
+
def def_bang(name, chain)
|
157
|
+
class_eval %<
|
158
|
+
def #{name}!
|
159
|
+
blank2nil { #{chain.join(' rescue ')} rescue nil }
|
160
|
+
end
|
161
|
+
>, *get_file_and_line_from_caller(0)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
{
|
166
|
+
:link => %w{link.href link},
|
167
|
+
:guid => %w{guid.content guid},
|
168
|
+
:content => %w{content.content content},
|
169
|
+
:description => %w{description.content description},
|
170
|
+
:title => %w{title.content title},
|
171
|
+
:category => %w{category.content category},
|
172
|
+
:dc_subject => %w{dc_subject},
|
173
|
+
:author => %w{author.name.content author.name author},
|
174
|
+
:dc_creator => %w{dc_creator}
|
175
|
+
}.each { |name, chain| def_bang name, chain }
|
176
|
+
|
177
|
+
def categories!
|
178
|
+
return nil unless self.respond_to? :categories
|
179
|
+
cats = categories.map do |c|
|
180
|
+
blank2nil { c.content rescue c rescue nil }
|
181
|
+
end.compact
|
182
|
+
cats.empty? ? nil : cats
|
183
|
+
end
|
184
|
+
|
185
|
+
protected
|
186
|
+
def blank2nil(&block)
|
187
|
+
x = yield
|
188
|
+
(x && !x.empty?) ? x : nil
|
189
|
+
end
|
190
|
+
end
|
153
191
|
end
|
154
192
|
|
155
193
|
|
156
194
|
class ::RssBlob
|
157
195
|
attr_accessor :url, :handle, :type, :refresh_rate, :xml, :title, :items,
|
158
|
-
:mutex, :watchers, :last_fetched
|
196
|
+
:mutex, :watchers, :last_fetched, :http_cache, :last_success
|
159
197
|
|
160
198
|
def initialize(url,handle=nil,type=nil,watchers=[], xml=nil, lf = nil)
|
161
199
|
@url = url
|
@@ -167,11 +205,13 @@ class ::RssBlob
|
|
167
205
|
@type = type
|
168
206
|
@watchers=[]
|
169
207
|
@refresh_rate = nil
|
208
|
+
@http_cache = false
|
170
209
|
@xml = xml
|
171
210
|
@title = nil
|
172
211
|
@items = nil
|
173
212
|
@mutex = Mutex.new
|
174
213
|
@last_fetched = lf
|
214
|
+
@last_success = nil
|
175
215
|
sanitize_watchers(watchers)
|
176
216
|
end
|
177
217
|
|
@@ -246,6 +286,14 @@ class RSSFeedsPlugin < Plugin
|
|
246
286
|
:default => 300, :validate => Proc.new{|v| v > 30},
|
247
287
|
:desc => "How many seconds to sleep before checking RSS feeds again")
|
248
288
|
|
289
|
+
Config.register Config::IntegerValue.new('rss.announce_timeout',
|
290
|
+
:default => 0,
|
291
|
+
:desc => "Don't announce watched feed if these many seconds elapsed since the last successful update")
|
292
|
+
|
293
|
+
Config.register Config::IntegerValue.new('rss.announce_max',
|
294
|
+
:default => 3,
|
295
|
+
:desc => "Maximum number of new items to announce when a watched feed is updated")
|
296
|
+
|
249
297
|
Config.register Config::BooleanValue.new('rss.show_updated',
|
250
298
|
:default => true,
|
251
299
|
:desc => "Whether feed items for which the description was changed should be shown as new")
|
@@ -254,32 +302,20 @@ class RSSFeedsPlugin < Plugin
|
|
254
302
|
:default => true,
|
255
303
|
:desc => "Whether to display links from the text of a feed item.")
|
256
304
|
|
305
|
+
Config.register Config::EnumValue.new('rss.announce_method',
|
306
|
+
:values => ['say', 'notice'],
|
307
|
+
:default => 'say',
|
308
|
+
:desc => "Whether to display links from the text of a feed item.")
|
309
|
+
|
257
310
|
# Make an 'unique' ID for a given item, based on appropriate bot options
|
258
311
|
# Currently only suppored is bot.config['rss.show_updated']: when false,
|
259
312
|
# only the guid/link is accounted for.
|
260
|
-
|
261
|
-
def block_rescue(df = nil, &block)
|
262
|
-
v = block.call rescue nil
|
263
|
-
(String === v && '' != v) ? v : nil
|
264
|
-
end
|
265
313
|
|
266
314
|
def make_uid(item)
|
267
|
-
uid = [
|
268
|
-
(block_rescue do item.guid.content end ||
|
269
|
-
block_rescue do item.guid end ||
|
270
|
-
block_rescue do item.link.href end ||
|
271
|
-
block_rescue do item.link end
|
272
|
-
)
|
273
|
-
]
|
315
|
+
uid = [item.guid! || item.link!]
|
274
316
|
if @bot.config['rss.show_updated']
|
275
|
-
uid.push(
|
276
|
-
|
277
|
-
block_rescue do item.description end
|
278
|
-
)
|
279
|
-
uid.unshift(
|
280
|
-
block_rescue do item.title.content end ||
|
281
|
-
block_rescue do item.title end
|
282
|
-
)
|
317
|
+
uid.push(item.content! || item.description!)
|
318
|
+
uid.unshift item.title!
|
283
319
|
end
|
284
320
|
# debug "taking hash of #{uid.inspect}"
|
285
321
|
uid.hash
|
@@ -287,7 +323,7 @@ class RSSFeedsPlugin < Plugin
|
|
287
323
|
|
288
324
|
|
289
325
|
# We used to save the Mutex with the RssBlob, which was idiotic. And
|
290
|
-
# since Mutexes dumped in one version might not be
|
326
|
+
# since Mutexes dumped in one version might not be restorable in another,
|
291
327
|
# we need a few tricks to be able to restore data from other versions of Ruby
|
292
328
|
#
|
293
329
|
# When migrating 1.8.6 => 1.8.5, all we need to do is define an empty
|
@@ -303,88 +339,98 @@ class RSSFeedsPlugin < Plugin
|
|
303
339
|
|
304
340
|
# Auxiliary method used to collect two lines for rss output filters,
|
305
341
|
# running substitutions against DataStream _s_ optionally joined
|
306
|
-
# with hash _h_
|
342
|
+
# with hash _h_.
|
343
|
+
#
|
344
|
+
# For substitutions, *_wrap keys can be used to alter the content of
|
345
|
+
# other nonempty keys. If the value of *_wrap is a String, it will be
|
346
|
+
# put before and after the corresponding key; if it's an Array, the first
|
347
|
+
# and second elements will be used for wrapping; if it's nil, no wrapping
|
348
|
+
# will be done (useful to override a default wrapping).
|
349
|
+
#
|
350
|
+
# For example:
|
351
|
+
# :handle_wrap => '::'::
|
352
|
+
# will wrap s[:handle] by prefixing and postfixing it with '::'
|
353
|
+
# :date_wrap => [nil, ' :: ']::
|
354
|
+
# will put ' :: ' after s[:date]
|
307
355
|
def make_stream(line1, line2, s, h={})
|
308
356
|
ss = s.merge(h)
|
309
|
-
|
357
|
+
subs = {}
|
358
|
+
wraps = {}
|
359
|
+
ss.each do |k, v|
|
360
|
+
kk = k.to_s.chomp!('_wrap')
|
361
|
+
if kk
|
362
|
+
nk = kk.intern
|
363
|
+
case v
|
364
|
+
when String
|
365
|
+
wraps[nk] = ss[nk].wrap_nonempty(v, v)
|
366
|
+
when Array
|
367
|
+
wraps[nk] = ss[nk].wrap_nonempty(*v)
|
368
|
+
when nil
|
369
|
+
# do nothing
|
370
|
+
else
|
371
|
+
warning "ignoring #{v.inspect} wrapping of unknown class"
|
372
|
+
end
|
373
|
+
else
|
374
|
+
subs[k] = v
|
375
|
+
end
|
376
|
+
end
|
377
|
+
subs.merge! wraps
|
378
|
+
DataStream.new([line1, line2].compact.join("\n") % subs, ss)
|
379
|
+
end
|
380
|
+
|
381
|
+
# Auxiliary method used to define rss output filters
|
382
|
+
def rss_type(key, &block)
|
383
|
+
@bot.register_filter(key, @outkey, &block)
|
310
384
|
end
|
311
385
|
|
312
|
-
# Define default
|
386
|
+
# Define default output filters (rss types), and load custom ones.
|
387
|
+
# Custom filters are looked for in the plugin's default filter locations
|
388
|
+
# and in rss/types.rb under botclass.
|
389
|
+
# Preferably, the rss_type method should be used in these files, e.g.:
|
390
|
+
# rss_type :my_type do |s|
|
391
|
+
# line1 = "%{handle} and some %{author} info"
|
392
|
+
# make_stream(line1, nil, s)
|
393
|
+
# end
|
394
|
+
# to define the new type 'my_type'. The keys available in the DataStream
|
395
|
+
# are:
|
396
|
+
# item::
|
397
|
+
# the actual rss item
|
398
|
+
# handle::
|
399
|
+
# the item handle
|
400
|
+
# date::
|
401
|
+
# the item date
|
402
|
+
# title::
|
403
|
+
# the item title
|
404
|
+
# desc, link, category, author::
|
405
|
+
# the item description, link, category, author
|
406
|
+
# at::
|
407
|
+
# the string ' @ ' if the item has both an title and a link
|
408
|
+
# handle_wrap, date_wrap, title_wrap, ...::
|
409
|
+
# these keys can be defined to wrap the corresponding elements if they
|
410
|
+
# are nonempty. By default handle is wrapped with '::', date has a ' ::'
|
411
|
+
# appended and title is enbolden
|
313
412
|
#
|
314
|
-
# TODO: load personal ones
|
315
413
|
def define_filters
|
316
|
-
@outkey
|
317
|
-
@bot.register_filter(:headlines, @outkey) { |s|
|
318
|
-
line1 = (s[:handle].empty? ? "%{date}" : "%{handle}") << "%{title}"
|
319
|
-
make_stream(line1, nil, s)
|
320
|
-
}
|
321
|
-
@bot.register_filter(:blog, @outkey) { |s|
|
322
|
-
author = s[:author] ? (s[:author] + " ") : ""
|
323
|
-
abt = s[:category] ? "about #{s[:category]} " : ""
|
324
|
-
line1 = "%{handle}%{date}%{author}blogged %{abt}at %{link}"
|
325
|
-
line2 = "%{handle}%{title} - %{desc}"
|
326
|
-
make_stream(line1, line2, s, :author => author, :abt => abt)
|
327
|
-
}
|
328
|
-
@bot.register_filter(:photoblog, @outkey) { |s|
|
329
|
-
author = s[:author] ? (s[:author] + " ") : ""
|
330
|
-
abt = s[:category] ? "under #{s[:category]} " : ""
|
331
|
-
line1 = "%{handle}%{date}%{author}added an image %{abt}at %{link}"
|
332
|
-
line2 = "%{handle}%{title} - %{desc}"
|
333
|
-
make_stream(line1, line2, s, :author => author, :abt => abt)
|
334
|
-
}
|
335
|
-
@bot.register_filter(:news, @outkey) { |s|
|
336
|
-
line1 = "%{handle}%{date}%{title}%{at}%{link}" % s
|
337
|
-
line2 = "%{handle}%{date}%{desc}" % s
|
338
|
-
make_stream(line1, line2, s)
|
339
|
-
}
|
340
|
-
@bot.register_filter(:git, @outkey) { |s|
|
341
|
-
author = s[:author] ? (s[:author] + " ") : ""
|
342
|
-
line1 = "%{handle}%{date}%{author}committed %{title}%{at}%{link}"
|
343
|
-
make_stream(line1, nil, s, :author => author)
|
344
|
-
}
|
345
|
-
@bot.register_filter(:forum, @outkey) { |s|
|
346
|
-
line1 = "%{handle}%{date}%{title}%{at}%{link}"
|
347
|
-
make_stream(line1, nil, s)
|
348
|
-
}
|
349
|
-
@bot.register_filter(:wiki, @outkey) { |s|
|
350
|
-
line1 = "%{handle}%{date}%{title}%{at}%{link}"
|
351
|
-
line1 << "has been edited by %{author}. %{desc}"
|
352
|
-
make_stream(line1, nil, s)
|
353
|
-
}
|
354
|
-
@bot.register_filter(:gmane, @outkey) { |s|
|
355
|
-
line1 = "%{handle}%{date}Message %{title} sent by %{author}. %{desc}"
|
356
|
-
make_stream(line1, nil, s)
|
357
|
-
}
|
358
|
-
@bot.register_filter(:trac, @outkey) { |s|
|
359
|
-
author = s[:author].sub(/@\S+?\s*>/, "@...>") + ": " if s[:author]
|
360
|
-
line1 = "%{handle}%{date}%{author}%{title}%{at}%{link}"
|
361
|
-
line2 = nil
|
362
|
-
unless s[:item].title =~ /^(?:Changeset \[(?:[\da-f]+)\]|\(git commit\))/
|
363
|
-
line2 = "%{handle}%{date}%{desc}"
|
364
|
-
end
|
365
|
-
make_stream(line1, line2, s, :author => author)
|
366
|
-
}
|
367
|
-
@bot.register_filter(:"/.", @outkey) { |s|
|
368
|
-
dept = "(from the #{s[:item].slash_department} dept) " rescue nil
|
369
|
-
sec = " in section #{s[:item].slash_section}" rescue nil
|
370
|
-
line1 = "%{handle}%{date}%{dept}%{title}%{at}%{link} "
|
371
|
-
line1 << "(posted by %{author}%{sec})"
|
372
|
-
make_stream(line1, nil, s, :dept => dept, :sec => sec)
|
373
|
-
}
|
374
|
-
@bot.register_filter(:default, @outkey) { |s|
|
375
|
-
line1 = "%{handle}%{date}%{title}%{at}%{link}"
|
376
|
-
line1 << " (by %{author})" if s[:author]
|
377
|
-
make_stream(line1, nil, s)
|
378
|
-
}
|
414
|
+
@outkey ||= :"rss.out"
|
379
415
|
|
380
|
-
# Define an HTML info filter
|
416
|
+
# Define an HTML info filter
|
381
417
|
@bot.register_filter(:rss, :htmlinfo) { |s| htmlinfo_filter(s) }
|
382
|
-
|
383
418
|
# This is the output format used by the input filter
|
384
|
-
|
419
|
+
rss_type :htmlinfo do |s|
|
385
420
|
line1 = "%{title}%{at}%{link}"
|
386
421
|
make_stream(line1, nil, s)
|
387
|
-
|
422
|
+
end
|
423
|
+
|
424
|
+
# the default filter
|
425
|
+
rss_type :default do |s|
|
426
|
+
line1 = "%{handle}%{date}%{title}%{at}%{link}"
|
427
|
+
line1 << " (by %{author})" if s[:author]
|
428
|
+
make_stream(line1, nil, s)
|
429
|
+
end
|
430
|
+
|
431
|
+
@user_types ||= datafile 'types.rb'
|
432
|
+
load_filters
|
433
|
+
load_filters :path => @user_types
|
388
434
|
end
|
389
435
|
|
390
436
|
FEED_NS = %r{xmlns.*http://(purl\.org/rss|www.w3c.org/1999/02/22-rdf)}
|
@@ -445,7 +491,7 @@ class RSSFeedsPlugin < Plugin
|
|
445
491
|
}
|
446
492
|
|
447
493
|
@feeds = @registry[:feeds]
|
448
|
-
raise unless @feeds
|
494
|
+
raise LoadError, "corrupted feed database" unless @feeds
|
449
495
|
|
450
496
|
@registry.recovery = nil
|
451
497
|
|
@@ -535,7 +581,7 @@ class RSSFeedsPlugin < Plugin
|
|
535
581
|
when "rewatch"
|
536
582
|
"rss rewatch : restart threads that watch for changes in watched rss"
|
537
583
|
when "types"
|
538
|
-
"rss types : show the rss types for which an output format
|
584
|
+
"rss types : show the rss types for which an output format exist (all other types will use the default one)"
|
539
585
|
else
|
540
586
|
"manage RSS feeds: rss types|show|list|watched|add|change|del(ete)|rm|(force)replace|watch|unwatch|rmwatch|rewatch|who watches"
|
541
587
|
end
|
@@ -599,7 +645,7 @@ class RSSFeedsPlugin < Plugin
|
|
599
645
|
parsed = parseRss(feed, m)
|
600
646
|
end
|
601
647
|
return unless feed.items
|
602
|
-
m.reply "using old data" unless fetched and parsed
|
648
|
+
m.reply "using old data" unless fetched and parsed and parsed > 0
|
603
649
|
|
604
650
|
title = feed.title
|
605
651
|
items = feed.items
|
@@ -611,7 +657,12 @@ class RSSFeedsPlugin < Plugin
|
|
611
657
|
|
612
658
|
m.reply "Channel : #{title}"
|
613
659
|
disp.each do |item|
|
614
|
-
printFormattedRss(feed, item, {
|
660
|
+
printFormattedRss(feed, item, {
|
661
|
+
:places => [m.replyto],
|
662
|
+
:handle => nil,
|
663
|
+
:date => true,
|
664
|
+
:announce_method => :say
|
665
|
+
})
|
615
666
|
end
|
616
667
|
end
|
617
668
|
|
@@ -630,19 +681,34 @@ class RSSFeedsPlugin < Plugin
|
|
630
681
|
|
631
682
|
def list_rss(m, params)
|
632
683
|
wanted = params[:handle]
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
684
|
+
listed = @feeds.keys
|
685
|
+
if wanted
|
686
|
+
wanted_rx = Regexp.new(wanted, true)
|
687
|
+
listed.reject! { |handle| !handle.match(wanted_rx) }
|
688
|
+
end
|
689
|
+
listed.sort!
|
690
|
+
debug listed
|
691
|
+
if @bot.config['send.max_lines'] > 0 and listed.size > @bot.config['send.max_lines']
|
692
|
+
reply = listed.inject([]) do |ar, handle|
|
693
|
+
feed = @feeds[handle]
|
694
|
+
string = handle.dup
|
695
|
+
(string << " (#{feed.type})") if feed.type
|
696
|
+
(string << " (watched)") if feed.watched_by?(m.replyto)
|
697
|
+
ar << string
|
698
|
+
end.join(', ')
|
699
|
+
elsif listed.size > 0
|
700
|
+
reply = listed.inject([]) do |ar, handle|
|
701
|
+
feed = @feeds[handle]
|
702
|
+
string = "#{feed.handle}: #{feed.url} (in format: #{feed.type ? feed.type : 'default'})"
|
703
|
+
(string << " refreshing every #{Utils.secs_to_string(feed.refresh_rate)}") if feed.refresh_rate
|
704
|
+
(string << " (watched)") if feed.watched_by?(m.replyto)
|
705
|
+
ar << string
|
706
|
+
end.join("\n")
|
707
|
+
else
|
642
708
|
reply = "no feeds found"
|
643
709
|
reply << " matching #{wanted}" if wanted
|
644
710
|
end
|
645
|
-
m.reply reply, :max_lines =>
|
711
|
+
m.reply reply, :max_lines => 0
|
646
712
|
end
|
647
713
|
|
648
714
|
def watched_rss(m, params)
|
@@ -823,6 +889,7 @@ class RSSFeedsPlugin < Plugin
|
|
823
889
|
if params and handle = params[:handle]
|
824
890
|
feed = @feeds.fetch(handle.downcase, nil)
|
825
891
|
if feed
|
892
|
+
feed.http_cache = false
|
826
893
|
@bot.timer.reschedule(@watch[feed.handle], (params[:delay] || 0).to_f)
|
827
894
|
m.okay if m
|
828
895
|
else
|
@@ -842,7 +909,7 @@ class RSSFeedsPlugin < Plugin
|
|
842
909
|
private
|
843
910
|
def watchRss(feed, m=nil)
|
844
911
|
if @watch.has_key?(feed.handle)
|
845
|
-
report_problem("watcher thread for #{feed.handle} is already running", nil, m)
|
912
|
+
# report_problem("watcher thread for #{feed.handle} is already running", nil, m)
|
846
913
|
return
|
847
914
|
end
|
848
915
|
status = Hash.new
|
@@ -858,11 +925,18 @@ class RSSFeedsPlugin < Plugin
|
|
858
925
|
failures = status[:failures]
|
859
926
|
begin
|
860
927
|
debug "fetching #{feed}"
|
861
|
-
|
928
|
+
|
929
|
+
first_run = !feed.last_success
|
930
|
+
if (@bot.config['rss.announce_timeout'] > 0 &&
|
931
|
+
(Time.now - feed.last_success > @bot.config['rss.announce_timeout']))
|
932
|
+
debug "#{feed} wasn't polled for too long, supressing output"
|
933
|
+
first_run = true
|
934
|
+
end
|
862
935
|
oldxml = feed.xml ? feed.xml.dup : nil
|
863
|
-
unless fetchRss(feed)
|
936
|
+
unless fetchRss(feed, nil, feed.http_cache)
|
864
937
|
failures += 1
|
865
938
|
else
|
939
|
+
feed.http_cache = true
|
866
940
|
if first_run
|
867
941
|
debug "first run for #{feed}, getting items"
|
868
942
|
parseRss(feed)
|
@@ -870,14 +944,12 @@ class RSSFeedsPlugin < Plugin
|
|
870
944
|
debug "xml for #{feed} didn't change"
|
871
945
|
failures -= 1 if failures > 0
|
872
946
|
else
|
873
|
-
|
874
|
-
|
875
|
-
parseRss(feed)
|
876
|
-
failures -= 1 if failures > 0
|
877
|
-
else
|
878
|
-
# This one is used for debugging
|
879
|
-
otxt = []
|
947
|
+
# This one is used for debugging
|
948
|
+
otxt = []
|
880
949
|
|
950
|
+
if feed.items.nil?
|
951
|
+
oids = []
|
952
|
+
else
|
881
953
|
# These are used for checking new items vs old ones
|
882
954
|
oids = Set.new feed.items.map { |item|
|
883
955
|
uid = make_uid item
|
@@ -886,10 +958,13 @@ class RSSFeedsPlugin < Plugin
|
|
886
958
|
debug [uid, otxt.last].inspect
|
887
959
|
uid
|
888
960
|
}
|
961
|
+
end
|
889
962
|
|
890
|
-
|
891
|
-
|
963
|
+
nitems = parseRss(feed)
|
964
|
+
if nitems.nil?
|
892
965
|
failures += 1
|
966
|
+
elsif nitems == 0
|
967
|
+
debug "no items in feed #{feed}"
|
893
968
|
else
|
894
969
|
debug "Checking if new items are available for #{feed}"
|
895
970
|
failures -= 1 if failures > 0
|
@@ -914,7 +989,19 @@ class RSSFeedsPlugin < Plugin
|
|
914
989
|
}
|
915
990
|
|
916
991
|
if dispItems.length > 0
|
992
|
+
max = @bot.config['rss.announce_max']
|
917
993
|
debug "Found #{dispItems.length} new items in #{feed}"
|
994
|
+
if max > 0 and dispItems.length > max
|
995
|
+
debug "showing only the latest #{dispItems.length}"
|
996
|
+
feed.watchers.each do |loc|
|
997
|
+
@bot.say loc, (_("feed %{feed} had %{num} updates, showing the latest %{max}") % {
|
998
|
+
:feed => feed.handle,
|
999
|
+
:num => dispItems.length,
|
1000
|
+
:max => max
|
1001
|
+
})
|
1002
|
+
end
|
1003
|
+
dispItems.slice!(max..-1)
|
1004
|
+
end
|
918
1005
|
# When displaying watched feeds, publish them from older to newer
|
919
1006
|
dispItems.reverse.each { |item|
|
920
1007
|
printFormattedRss(feed, item)
|
@@ -923,7 +1010,6 @@ class RSSFeedsPlugin < Plugin
|
|
923
1010
|
debug "No new items found in #{feed}"
|
924
1011
|
end
|
925
1012
|
end
|
926
|
-
end
|
927
1013
|
end
|
928
1014
|
end
|
929
1015
|
rescue Exception => e
|
@@ -955,50 +1041,43 @@ class RSSFeedsPlugin < Plugin
|
|
955
1041
|
return seconds
|
956
1042
|
end
|
957
1043
|
|
958
|
-
def
|
959
|
-
|
960
|
-
|
961
|
-
|
1044
|
+
def make_date(obj)
|
1045
|
+
if obj.kind_of? Time
|
1046
|
+
obj.strftime("%Y/%m/%d %H:%M")
|
1047
|
+
else
|
1048
|
+
obj.to_s
|
1049
|
+
end
|
962
1050
|
end
|
963
1051
|
|
964
|
-
def printFormattedRss(feed, item,
|
1052
|
+
def printFormattedRss(feed, item, options={})
|
965
1053
|
# debug item
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
end
|
991
|
-
elsif item.respond_to?(:date)
|
992
|
-
if item.date.class <= Time
|
993
|
-
date = item.date.strftime("%Y/%m/%d %H:%M")
|
994
|
-
else
|
995
|
-
date = item.date.to_s
|
996
|
-
end
|
997
|
-
else
|
998
|
-
date = "(no date)"
|
999
|
-
end
|
1000
|
-
date += " :: "
|
1054
|
+
opts = {
|
1055
|
+
:places => feed.watchers,
|
1056
|
+
:handle => feed.handle,
|
1057
|
+
:date => false,
|
1058
|
+
:announce_method => @bot.config['rss.announce_method']
|
1059
|
+
}.merge options
|
1060
|
+
|
1061
|
+
places = opts[:places]
|
1062
|
+
announce_method = opts[:announce_method]
|
1063
|
+
|
1064
|
+
handle = opts[:handle].to_s
|
1065
|
+
|
1066
|
+
date = \
|
1067
|
+
if opts[:date]
|
1068
|
+
if item.respond_to?(:updated)
|
1069
|
+
make_date(item.updated.content)
|
1070
|
+
elsif item.respond_to?(:source) and item.source.respond_to?(:updated)
|
1071
|
+
make_date(item.source.updated.content)
|
1072
|
+
elsif item.respond_to?(:pubDate)
|
1073
|
+
make_date(item.pubDate)
|
1074
|
+
elsif item.respond_to?(:date)
|
1075
|
+
make_date(item.date)
|
1076
|
+
else
|
1077
|
+
"(no date)"
|
1001
1078
|
end
|
1079
|
+
else
|
1080
|
+
String.new
|
1002
1081
|
end
|
1003
1082
|
|
1004
1083
|
tit_opt = {}
|
@@ -1012,14 +1091,14 @@ class RSSFeedsPlugin < Plugin
|
|
1012
1091
|
# visible in the URL anyway
|
1013
1092
|
# TODO make this optional?
|
1014
1093
|
base_title.sub!(/^Changeset \[([\da-f]{40})\]:/) { |c| "(git commit)"} if feed.type == 'trac'
|
1015
|
-
title =
|
1094
|
+
title = base_title.ircify_html(tit_opt)
|
1016
1095
|
end
|
1017
1096
|
|
1018
1097
|
desc_opt = {}
|
1019
1098
|
desc_opt[:limit] = @bot.config['rss.text_max']
|
1020
1099
|
desc_opt[:a_href] = :link_out if @bot.config['rss.show_links']
|
1021
1100
|
|
1022
|
-
# We prefer content_encoded here as it tends to provide more html formatting
|
1101
|
+
# We prefer content_encoded here as it tends to provide more html formatting
|
1023
1102
|
# for use with ircify_html.
|
1024
1103
|
if item.respond_to?(:content_encoded) && item.content_encoded
|
1025
1104
|
desc = item.content_encoded.ircify_html(desc_opt)
|
@@ -1038,12 +1117,13 @@ class RSSFeedsPlugin < Plugin
|
|
1038
1117
|
desc = "(?)"
|
1039
1118
|
end
|
1040
1119
|
|
1041
|
-
link = item.link
|
1120
|
+
link = item.link!
|
1042
1121
|
link.strip! if link
|
1043
1122
|
|
1044
|
-
|
1123
|
+
categories = item.categories!
|
1124
|
+
category = item.category! || item.dc_subject!
|
1045
1125
|
category.strip! if category
|
1046
|
-
author =
|
1126
|
+
author = item.dc_creator! || item.author!
|
1047
1127
|
author.strip! if author
|
1048
1128
|
|
1049
1129
|
line1 = nil
|
@@ -1054,15 +1134,25 @@ class RSSFeedsPlugin < Plugin
|
|
1054
1134
|
key = @bot.global_filter_name(feed.type, @outkey)
|
1055
1135
|
key = @bot.global_filter_name(:default, @outkey) unless @bot.has_filter?(key)
|
1056
1136
|
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1137
|
+
stream_hash = {
|
1138
|
+
:item => item,
|
1139
|
+
:handle => handle,
|
1140
|
+
:handle_wrap => ['::', ':: '],
|
1141
|
+
:date => date,
|
1142
|
+
:date_wrap => [nil, ' :: '],
|
1143
|
+
:title => title,
|
1144
|
+
:title_wrap => Bold,
|
1145
|
+
:desc => desc, :link => link,
|
1146
|
+
:categories => categories,
|
1147
|
+
:category => category, :author => author, :at => at
|
1148
|
+
}
|
1149
|
+
output = @bot.filter(key, stream_hash)
|
1060
1150
|
|
1061
1151
|
return output if places.empty?
|
1062
1152
|
|
1063
1153
|
places.each { |loc|
|
1064
1154
|
output.to_s.each_line { |line|
|
1065
|
-
@bot.
|
1155
|
+
@bot.__send__(announce_method, loc, line, :overlong => :truncate)
|
1066
1156
|
}
|
1067
1157
|
}
|
1068
1158
|
end
|
@@ -1092,8 +1182,16 @@ class RSSFeedsPlugin < Plugin
|
|
1092
1182
|
# reassign the 0.9 RDFs to 1.0, and hope it goes right.
|
1093
1183
|
xml.gsub!("xmlns=\"http://my.netscape.com/rdf/simple/0.9/\"",
|
1094
1184
|
"xmlns=\"http://purl.org/rss/1.0/\"")
|
1185
|
+
# make sure the parser doesn't double-convert in case the feed is not UTF-8
|
1186
|
+
xml.sub!(/<\?xml (.*?)\?>/) do |match|
|
1187
|
+
if /\bencoding=(['"])(.*?)\1/.match(match)
|
1188
|
+
match.sub!(/\bencoding=(['"])(?:.*?)\1/,'encoding="UTF-8"')
|
1189
|
+
end
|
1190
|
+
match
|
1191
|
+
end
|
1095
1192
|
feed.mutex.synchronize do
|
1096
1193
|
feed.xml = xml
|
1194
|
+
feed.last_success = Time.now
|
1097
1195
|
end
|
1098
1196
|
return true
|
1099
1197
|
end
|
@@ -1102,25 +1200,33 @@ class RSSFeedsPlugin < Plugin
|
|
1102
1200
|
return nil unless feed.xml
|
1103
1201
|
feed.mutex.synchronize do
|
1104
1202
|
xml = feed.xml
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
debug "parsed and validated #{feed}"
|
1109
|
-
rescue RSS::InvalidRSSError
|
1110
|
-
## do non validate parse for invalid RSS 1.0
|
1203
|
+
rss = nil
|
1204
|
+
errors = []
|
1205
|
+
RSS::AVAILABLE_PARSERS.each do |parser|
|
1111
1206
|
begin
|
1112
|
-
|
1113
|
-
|
1207
|
+
## do validate parse
|
1208
|
+
rss = RSS::Parser.parse(xml, true, true, parser)
|
1209
|
+
debug "parsed and validated #{feed} with #{parser}"
|
1210
|
+
break
|
1211
|
+
rescue RSS::InvalidRSSError
|
1212
|
+
begin
|
1213
|
+
## do non validate parse for invalid RSS 1.0
|
1214
|
+
rss = RSS::Parser.parse(xml, false, true, parser)
|
1215
|
+
debug "parsed but not validated #{feed} with #{parser}"
|
1216
|
+
break
|
1217
|
+
rescue RSS::Error => e
|
1218
|
+
errors << [parser, e, "parsing rss stream failed, whoops =("]
|
1219
|
+
end
|
1114
1220
|
rescue RSS::Error => e
|
1115
|
-
|
1116
|
-
|
1221
|
+
errors << [parser, e, "parsing rss stream failed, oioi"]
|
1222
|
+
rescue => e
|
1223
|
+
errors << [parser, e, "processing error occured, sorry =("]
|
1117
1224
|
end
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
return nil
|
1225
|
+
end
|
1226
|
+
unless errors.empty?
|
1227
|
+
debug errors
|
1228
|
+
self.send(:report_problem, errors.last[2], errors.last[1], m)
|
1229
|
+
return nil unless rss
|
1124
1230
|
end
|
1125
1231
|
items = []
|
1126
1232
|
if rss.nil?
|
@@ -1151,11 +1257,11 @@ class RSSFeedsPlugin < Plugin
|
|
1151
1257
|
|
1152
1258
|
if items.empty?
|
1153
1259
|
report_problem("no items found in the feed, maybe try weed?", e, m)
|
1154
|
-
|
1260
|
+
else
|
1261
|
+
feed.title = title.strip
|
1262
|
+
feed.items = items
|
1155
1263
|
end
|
1156
|
-
|
1157
|
-
feed.items = items
|
1158
|
-
return true
|
1264
|
+
return items.length
|
1159
1265
|
end
|
1160
1266
|
end
|
1161
1267
|
end
|