rbot 0.9.9
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 +16 -0
- data/COPYING +21 -0
- data/ChangeLog +418 -0
- data/INSTALL +8 -0
- data/README +44 -0
- data/REQUIREMENTS +34 -0
- data/TODO +5 -0
- data/Usage_en.txt +129 -0
- data/bin/rbot +81 -0
- data/data/rbot/contrib/plugins/figlet.rb +20 -0
- data/data/rbot/contrib/plugins/ri.rb +83 -0
- data/data/rbot/contrib/plugins/stats.rb +232 -0
- data/data/rbot/contrib/plugins/vandale.rb +49 -0
- data/data/rbot/languages/dutch.lang +73 -0
- data/data/rbot/languages/english.lang +75 -0
- data/data/rbot/languages/french.lang +39 -0
- data/data/rbot/languages/german.lang +67 -0
- data/data/rbot/plugins/autoop.rb +68 -0
- data/data/rbot/plugins/autorejoin.rb +16 -0
- data/data/rbot/plugins/cal.rb +15 -0
- data/data/rbot/plugins/dice.rb +81 -0
- data/data/rbot/plugins/eightball.rb +19 -0
- data/data/rbot/plugins/excuse.rb +470 -0
- data/data/rbot/plugins/fish.rb +61 -0
- data/data/rbot/plugins/fortune.rb +22 -0
- data/data/rbot/plugins/freshmeat.rb +98 -0
- data/data/rbot/plugins/google.rb +51 -0
- data/data/rbot/plugins/host.rb +14 -0
- data/data/rbot/plugins/httpd.rb.disabled +35 -0
- data/data/rbot/plugins/insult.rb +258 -0
- data/data/rbot/plugins/karma.rb +85 -0
- data/data/rbot/plugins/lart.rb +181 -0
- data/data/rbot/plugins/math.rb +122 -0
- data/data/rbot/plugins/nickserv.rb +89 -0
- data/data/rbot/plugins/nslookup.rb +43 -0
- data/data/rbot/plugins/opme.rb +19 -0
- data/data/rbot/plugins/quakeauth.rb +51 -0
- data/data/rbot/plugins/quotes.rb +321 -0
- data/data/rbot/plugins/remind.rb +228 -0
- data/data/rbot/plugins/roshambo.rb +54 -0
- data/data/rbot/plugins/rot13.rb +10 -0
- data/data/rbot/plugins/roulette.rb +147 -0
- data/data/rbot/plugins/rss.rb.disabled +414 -0
- data/data/rbot/plugins/seen.rb +89 -0
- data/data/rbot/plugins/slashdot.rb +94 -0
- data/data/rbot/plugins/spell.rb +36 -0
- data/data/rbot/plugins/tube.rb +71 -0
- data/data/rbot/plugins/url.rb +88 -0
- data/data/rbot/plugins/weather.rb +649 -0
- data/data/rbot/plugins/wserver.rb +71 -0
- data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
- data/data/rbot/templates/keywords.rbot +4 -0
- data/data/rbot/templates/lart/larts +98 -0
- data/data/rbot/templates/lart/praises +5 -0
- data/data/rbot/templates/levels.rbot +30 -0
- data/data/rbot/templates/users.rbot +1 -0
- data/lib/rbot/auth.rb +203 -0
- data/lib/rbot/channel.rb +54 -0
- data/lib/rbot/config.rb +363 -0
- data/lib/rbot/dbhash.rb +112 -0
- data/lib/rbot/httputil.rb +141 -0
- data/lib/rbot/ircbot.rb +808 -0
- data/lib/rbot/ircsocket.rb +185 -0
- data/lib/rbot/keywords.rb +433 -0
- data/lib/rbot/language.rb +69 -0
- data/lib/rbot/message.rb +256 -0
- data/lib/rbot/messagemapper.rb +262 -0
- data/lib/rbot/plugins.rb +291 -0
- data/lib/rbot/post-install.rb +8 -0
- data/lib/rbot/rbotconfig.rb +36 -0
- data/lib/rbot/registry.rb +271 -0
- data/lib/rbot/rfc2812.rb +1104 -0
- data/lib/rbot/timer.rb +201 -0
- data/lib/rbot/utils.rb +83 -0
- data/setup.rb +1360 -0
- metadata +129 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
# Play the game of roshambo (rock-paper-scissors)
|
2
|
+
# Copyright (C) 2004 Hans Fugal
|
3
|
+
# Distributed under the same license as rbot itself
|
4
|
+
require 'time'
|
5
|
+
class RoshamboPlugin < Plugin
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
@scoreboard = {}
|
9
|
+
end
|
10
|
+
def help(plugin, topic="")
|
11
|
+
"roshambo <rock|paper|scissors> => play roshambo"
|
12
|
+
end
|
13
|
+
def privmsg(m)
|
14
|
+
# simultaneity
|
15
|
+
choice = choose
|
16
|
+
|
17
|
+
# init scoreboard
|
18
|
+
if (not @scoreboard.has_key?(m.sourcenick) or (Time.now - @scoreboard[m.sourcenick]['timestamp']) > 3600)
|
19
|
+
@scoreboard[m.sourcenick] = {'me'=>0,'you'=>0,'timestamp'=>Time.now}
|
20
|
+
end
|
21
|
+
case m.params
|
22
|
+
when 'rock','paper','scissors'
|
23
|
+
s = score(choice,m.params)
|
24
|
+
@scoreboard[m.sourcenick]['timestamp'] = Time.now
|
25
|
+
myscore=@scoreboard[m.sourcenick]['me']
|
26
|
+
yourscore=@scoreboard[m.sourcenick]['you']
|
27
|
+
case s
|
28
|
+
when 1
|
29
|
+
yourscore=@scoreboard[m.sourcenick]['you'] += 1
|
30
|
+
m.reply "#{choice}. You win. Score: me #{myscore} you #{yourscore}"
|
31
|
+
when 0
|
32
|
+
m.reply "#{choice}. We tie. Score: me #{myscore} you #{yourscore}"
|
33
|
+
when -1
|
34
|
+
myscore=@scoreboard[m.sourcenick]['me'] += 1
|
35
|
+
m.reply "#{choice}! I win! Score: me #{myscore} you #{yourscore}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
m.reply "incorrect usage: " + help(m.plugin)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def choose
|
43
|
+
['rock','paper','scissors'][rand(3)]
|
44
|
+
end
|
45
|
+
def score(a,b)
|
46
|
+
beats = {'rock'=>'scissors', 'paper'=>'rock', 'scissors'=>'paper'}
|
47
|
+
return -1 if beats[a] == b
|
48
|
+
return 1 if beats[b] == a
|
49
|
+
return 0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
plugin = RoshamboPlugin.new
|
53
|
+
plugin.register("roshambo")
|
54
|
+
plugin.register("rps")
|
@@ -0,0 +1,147 @@
|
|
1
|
+
RouletteHistory = Struct.new("RouletteHistory", :games, :shots, :deaths, :misses, :wins)
|
2
|
+
|
3
|
+
class RoulettePlugin < Plugin
|
4
|
+
def initialize
|
5
|
+
super
|
6
|
+
reset_chambers
|
7
|
+
@players = Array.new
|
8
|
+
end
|
9
|
+
def help(plugin, topic="")
|
10
|
+
"roulette => play russian roulette - starts a new game if one isn't already running. One round in a six chambered gun. Take turns to say roulette to the bot, until somebody dies. roulette reload => force the gun to reload, roulette stats => show stats from all games, roulette stats <player> => show stats for <player>, roulette clearstats => clear stats (config level auth required)"
|
11
|
+
end
|
12
|
+
def clearstats(m, params)
|
13
|
+
@registry.clear
|
14
|
+
m.okay
|
15
|
+
end
|
16
|
+
|
17
|
+
def roulette(m, params)
|
18
|
+
if m.private?
|
19
|
+
m.reply "you gotta play roulette in channel dude"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
playerdata = nil
|
24
|
+
if @registry.has_key?(m.sourcenick)
|
25
|
+
playerdata = @registry[m.sourcenick]
|
26
|
+
else
|
27
|
+
playerdata = RouletteHistory.new(0,0,0,0,0)
|
28
|
+
end
|
29
|
+
|
30
|
+
unless @players.include?(m.sourcenick)
|
31
|
+
@players << m.sourcenick
|
32
|
+
playerdata.games += 1
|
33
|
+
end
|
34
|
+
playerdata.shots += 1
|
35
|
+
|
36
|
+
shot = @chambers.pop
|
37
|
+
if shot
|
38
|
+
m.reply "#{m.sourcenick}: chamber #{6 - @chambers.length} of 6 => *BANG*"
|
39
|
+
playerdata.deaths += 1
|
40
|
+
@players.each {|plyr|
|
41
|
+
next if plyr == m.sourcenick
|
42
|
+
pdata = @registry[plyr]
|
43
|
+
next if pdata == nil
|
44
|
+
pdata.wins += 1
|
45
|
+
@registry[plyr] = pdata
|
46
|
+
}
|
47
|
+
else
|
48
|
+
m.reply "#{m.sourcenick}: chamber #{6 - @chambers.length} of 6 => +click+"
|
49
|
+
playerdata.misses += 1
|
50
|
+
end
|
51
|
+
|
52
|
+
@registry[m.sourcenick] = playerdata
|
53
|
+
|
54
|
+
if shot || @chambers.empty?
|
55
|
+
reload(m)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
def reload(m, params = {})
|
59
|
+
@bot.action m.replyto, "reloads"
|
60
|
+
reset_chambers
|
61
|
+
# all players win on a reload
|
62
|
+
# (allows you to play 3-shot matches etc)
|
63
|
+
@players.each {|plyr|
|
64
|
+
pdata = @registry[plyr]
|
65
|
+
next if pdata == nil
|
66
|
+
pdata.wins += 1
|
67
|
+
@registry[plyr] = pdata
|
68
|
+
}
|
69
|
+
@players = Array.new
|
70
|
+
end
|
71
|
+
def reset_chambers
|
72
|
+
@chambers = [false, false, false, false, false, false]
|
73
|
+
@chambers[rand(@chambers.length)] = true
|
74
|
+
end
|
75
|
+
def playerstats(m, params)
|
76
|
+
player = params[:player]
|
77
|
+
pstats = @registry[player]
|
78
|
+
if pstats.nil?
|
79
|
+
m.reply "#{player} hasn't played enough games yet"
|
80
|
+
else
|
81
|
+
m.reply "#{player} has played #{pstats.games} games, won #{pstats.wins} and lost #{pstats.deaths}. #{player} pulled the trigger #{pstats.shots} times and found the chamber empty on #{pstats.misses} occasions."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def stats(m, params)
|
85
|
+
total_players = 0
|
86
|
+
total_games = 0
|
87
|
+
total_shots = 0
|
88
|
+
|
89
|
+
died_most = [nil,0]
|
90
|
+
won_most = [nil,0]
|
91
|
+
h_win_percent = [nil,0]
|
92
|
+
l_win_percent = [nil,0]
|
93
|
+
h_luck_percent = [nil,0]
|
94
|
+
l_luck_percent = [nil,0]
|
95
|
+
@registry.each {|k,v|
|
96
|
+
total_players += 1
|
97
|
+
total_games += v.deaths
|
98
|
+
total_shots += v.shots
|
99
|
+
|
100
|
+
win_rate = v.wins.to_f / v.games * 100
|
101
|
+
if h_win_percent[0].nil? || win_rate > h_win_percent[1] && v.games > 2
|
102
|
+
h_win_percent = [[k], win_rate]
|
103
|
+
elsif win_rate == h_win_percent[1] && v.games > 2
|
104
|
+
h_win_percent[0] << k
|
105
|
+
end
|
106
|
+
if l_win_percent[0].nil? || win_rate < l_win_percent[1] && v.games > 2
|
107
|
+
l_win_percent = [[k], win_rate]
|
108
|
+
elsif win_rate == l_win_percent[1] && v.games > 2
|
109
|
+
l_win_percent[0] << k
|
110
|
+
end
|
111
|
+
|
112
|
+
luck = v.misses.to_f / v.shots * 100
|
113
|
+
if h_luck_percent[0].nil? || luck > h_luck_percent[1] && v.games > 2
|
114
|
+
h_luck_percent = [[k], luck]
|
115
|
+
elsif luck == h_luck_percent[1] && v.games > 2
|
116
|
+
h_luck_percent[0] << k
|
117
|
+
end
|
118
|
+
if l_luck_percent[0].nil? || luck < l_luck_percent[1] && v.games > 2
|
119
|
+
l_luck_percent = [[k], luck]
|
120
|
+
elsif luck == l_luck_percent[1] && v.games > 2
|
121
|
+
l_luck_percent[0] << k
|
122
|
+
end
|
123
|
+
|
124
|
+
if died_most[0].nil? || v.deaths > died_most[1]
|
125
|
+
died_most = [[k], v.deaths]
|
126
|
+
elsif v.deaths == died_most[1]
|
127
|
+
died_most[0] << k
|
128
|
+
end
|
129
|
+
if won_most[0].nil? || v.wins > won_most[1]
|
130
|
+
won_most = [[k], v.wins]
|
131
|
+
elsif v.wins == won_most[1]
|
132
|
+
won_most[0] << k
|
133
|
+
end
|
134
|
+
}
|
135
|
+
if total_games < 1
|
136
|
+
m.reply "roulette stats: no games played yet"
|
137
|
+
else
|
138
|
+
m.reply "roulette stats: #{total_games} games completed, #{total_shots} shots fired at #{total_players} players. Luckiest: #{h_luck_percent[0].join(',')} (#{sprintf '%.1f', h_luck_percent[1]}% clicks). Unluckiest: #{l_luck_percent[0].join(',')} (#{sprintf '%.1f', l_luck_percent[1]}% clicks). Highest survival rate: #{h_win_percent[0].join(',')} (#{sprintf '%.1f', h_win_percent[1]}%). Lowest survival rate: #{l_win_percent[0].join(',')} (#{sprintf '%.1f', l_win_percent[1]}%). Most wins: #{won_most[0].join(',')} (#{won_most[1]}). Most deaths: #{died_most[0].join(',')} (#{died_most[1]})."
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
plugin = RoulettePlugin.new
|
143
|
+
plugin.map 'roulette reload', :action => 'reload'
|
144
|
+
plugin.map 'roulette stats :player', :action => 'playerstats'
|
145
|
+
plugin.map 'roulette stats', :action => 'stats'
|
146
|
+
plugin.map 'roulette clearstats', :action => 'clearstats', :auth => 'config'
|
147
|
+
plugin.map 'roulette'
|
@@ -0,0 +1,414 @@
|
|
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
|
+
# TODO
|
8
|
+
# checks feeds very often - does it use HEAD to check it needs to d/l?
|
9
|
+
# some usage issues
|
10
|
+
# why can't I do this here? :
|
11
|
+
# Class String
|
12
|
+
# def foo
|
13
|
+
# foo
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
|
17
|
+
require 'rss/parser'
|
18
|
+
require 'rss/1.0'
|
19
|
+
require 'rss/2.0'
|
20
|
+
require 'rss/dublincore'
|
21
|
+
begin
|
22
|
+
require 'rss/dublincore/2.0'
|
23
|
+
rescue LoadError => e
|
24
|
+
puts "rss plugin: no dublincore 2.0 found, should be okay tho"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class RSSFeedsPlugin < Plugin
|
29
|
+
@@watchThreads = Hash.new
|
30
|
+
|
31
|
+
# Keep a 1:1 relation between commands and handlers
|
32
|
+
@@handlers = {
|
33
|
+
"rss" => "handle_rss",
|
34
|
+
"addrss" => "handle_addrss",
|
35
|
+
"rmrss" => "handle_rmrss",
|
36
|
+
"listrss" => "handle_listrss",
|
37
|
+
"listwatches" => "handle_listrsswatch",
|
38
|
+
"rewatch" => "handle_rewatch",
|
39
|
+
"watchrss" => "handle_watchrss",
|
40
|
+
"rmwatch" => "handle_rmwatch"
|
41
|
+
}
|
42
|
+
|
43
|
+
def name
|
44
|
+
'rss'
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
super
|
49
|
+
@feeds = Hash.new
|
50
|
+
@watchList = Hash.new
|
51
|
+
|
52
|
+
if FileTest.exists?("#{@bot.botclass}/rss/feeds")
|
53
|
+
IO.foreach("#{@bot.botclass}/rss/feeds") { |line|
|
54
|
+
s = line.chomp.split("|", 2)
|
55
|
+
@feeds[s[0]] = s[1]
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
if FileTest.exists?("#{@bot.botclass}/rss/watchlist")
|
60
|
+
IO.foreach("#{@bot.botclass}/rss/watchlist") { |line|
|
61
|
+
s = line.chomp.split("|", 3)
|
62
|
+
@watchList[s[0]] = [s[1], s[2]]
|
63
|
+
watchRss( s[2], s[0], s[1] )
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def cleanup
|
69
|
+
kill_threads
|
70
|
+
end
|
71
|
+
|
72
|
+
def save
|
73
|
+
Dir.mkdir("#{@bot.botclass}/rss") if not FileTest.directory?("#{@bot.botclass}/rss")
|
74
|
+
File.open("#{@bot.botclass}/rss/feeds", "w") { |file|
|
75
|
+
@feeds.each { |k,v|
|
76
|
+
file.puts(k + "|" + v)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
File.open("#{@bot.botclass}/rss/watchlist", "w") { |file|
|
80
|
+
@watchList.each { |url, d|
|
81
|
+
feedFormat = d[0] || ''
|
82
|
+
whichChan = d[1] || 'markey'
|
83
|
+
file.puts(url + '|' + feedFormat + '|' + whichChan)
|
84
|
+
}
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def kill_threads
|
89
|
+
Thread.critical=true
|
90
|
+
# Abort all running threads.
|
91
|
+
@@watchThreads.each { |url, thread|
|
92
|
+
puts "Killing thread for #{url}"
|
93
|
+
thread.kill
|
94
|
+
}
|
95
|
+
# @@watchThreads.each { |url, thread|
|
96
|
+
# puts "Joining on killed thread for #{url}"
|
97
|
+
# thread.join
|
98
|
+
# }
|
99
|
+
@@watchThreads = Hash.new
|
100
|
+
Thread.critical=false
|
101
|
+
end
|
102
|
+
|
103
|
+
def help(plugin,topic="")
|
104
|
+
"RSS Reader: rss name [limit] => read a named feed [limit maximum posts, default 5], addrss [force] name url => add a feed, listrss => list all available feeds, rmrss name => remove the named feed, watchrss url [type] => watch a rss feed for changes (type may be 'amarokblog', 'amarokforum', 'mediawiki', 'gmame' or empty - it defines special formatting of feed items), rewatch => restart all rss watches, rmwatch url => stop watching for changes in url"
|
105
|
+
end
|
106
|
+
|
107
|
+
def privmsg(m)
|
108
|
+
meth = self.method(@@handlers[m.plugin])
|
109
|
+
meth.call(m)
|
110
|
+
end
|
111
|
+
|
112
|
+
def handle_rss(m)
|
113
|
+
unless m.params
|
114
|
+
m.reply("incorrect usage: " + help(m.plugin))
|
115
|
+
return
|
116
|
+
end
|
117
|
+
limit = 5
|
118
|
+
if m.params =~ /\s+(\d+)$/
|
119
|
+
limit = $1.to_i
|
120
|
+
if limit < 1 || limit > 15
|
121
|
+
m.reply("weird, limit not in [1..15], reverting to default")
|
122
|
+
limit = 5
|
123
|
+
end
|
124
|
+
m.params.gsub!(/\s+\d+$/, '')
|
125
|
+
end
|
126
|
+
unless @feeds.has_key?(m.params)
|
127
|
+
m.reply(m.params + "? what is that feed about?")
|
128
|
+
return
|
129
|
+
end
|
130
|
+
|
131
|
+
m.reply("Please wait, querying...")
|
132
|
+
title = ''
|
133
|
+
items = fetchRSS(m.replyto, @feeds[m.params], title)
|
134
|
+
if(items == nil)
|
135
|
+
return
|
136
|
+
end
|
137
|
+
m.reply("Channel : #{title}")
|
138
|
+
# FIXME: optional by-date sorting if dates present
|
139
|
+
items[0...limit].each do |item|
|
140
|
+
printRSSItem(m.replyto,item)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def handle_addrss(m)
|
145
|
+
unless m.params
|
146
|
+
m.reply "incorrect usage: " + help(m.plugin)
|
147
|
+
return
|
148
|
+
end
|
149
|
+
if m.params =~ /^force /
|
150
|
+
forced = true
|
151
|
+
m.params.gsub!(/^force /, '')
|
152
|
+
end
|
153
|
+
feed = m.params.scan(/^(\S+)\s+(\S+)$/)
|
154
|
+
unless feed.length == 1 && feed[0].length == 2
|
155
|
+
m.reply("incorrect usage: " + help(m.plugin))
|
156
|
+
return
|
157
|
+
end
|
158
|
+
if @feeds.has_key?(feed[0][0]) && !forced
|
159
|
+
m.reply("But there is already a feed named #{feed[0][0]} with url #{@feeds[feed[0][0]]}")
|
160
|
+
return
|
161
|
+
end
|
162
|
+
feed[0][0].gsub!("|", '_')
|
163
|
+
@feeds[feed[0][0]] = feed[0][1]
|
164
|
+
m.reply("RSS: Added #{feed[0][1]} with name #{feed[0][0]}")
|
165
|
+
end
|
166
|
+
|
167
|
+
def handle_rmrss(m)
|
168
|
+
unless m.params
|
169
|
+
m.reply "incorrect usage: " + help(m.plugin)
|
170
|
+
return
|
171
|
+
end
|
172
|
+
unless @feeds.has_key?(m.params)
|
173
|
+
m.reply("dunno that feed")
|
174
|
+
return
|
175
|
+
end
|
176
|
+
@feeds.delete(m.params)
|
177
|
+
m.okay
|
178
|
+
end
|
179
|
+
|
180
|
+
def handle_rmwatch(m)
|
181
|
+
unless m.params
|
182
|
+
m.reply "incorrect usage: " + help(m.plugin)
|
183
|
+
return
|
184
|
+
end
|
185
|
+
unless @watchList.has_key?(m.params)
|
186
|
+
m.reply("no such watch")
|
187
|
+
return
|
188
|
+
end
|
189
|
+
unless @watchList[m.params][1] == m.replyto
|
190
|
+
m.reply("no such watch for this channel/nick")
|
191
|
+
return
|
192
|
+
end
|
193
|
+
@watchList.delete(m.params)
|
194
|
+
Thread.critical=true
|
195
|
+
if @@watchThreads[m.params].kind_of? Thread
|
196
|
+
@@watchThreads[m.params].kill
|
197
|
+
puts "rmwatch: Killed thread for #{m.params}"
|
198
|
+
# @@watchThreads[m.params].join
|
199
|
+
# puts "rmwatch: Joined killed thread for #{m.params}"
|
200
|
+
@@watchThreads.delete(m.params)
|
201
|
+
end
|
202
|
+
Thread.critical=false
|
203
|
+
m.okay
|
204
|
+
end
|
205
|
+
|
206
|
+
def handle_listrss(m)
|
207
|
+
reply = ''
|
208
|
+
if @feeds.length == 0
|
209
|
+
reply = "No feeds yet."
|
210
|
+
else
|
211
|
+
@feeds.each { |k,v|
|
212
|
+
reply << k + ": " + v + "\n"
|
213
|
+
}
|
214
|
+
end
|
215
|
+
m.reply(reply)
|
216
|
+
end
|
217
|
+
|
218
|
+
def handle_listrsswatch(m)
|
219
|
+
reply = ''
|
220
|
+
if @watchList.length == 0
|
221
|
+
reply = "No watched feeds yet."
|
222
|
+
else
|
223
|
+
@watchList.each { |url,v|
|
224
|
+
reply << url + " for " + v[1] + " (in format: " + (v[0]?v[0]:"default") + ")\n"
|
225
|
+
}
|
226
|
+
end
|
227
|
+
m.reply(reply)
|
228
|
+
end
|
229
|
+
|
230
|
+
def handle_rewatch(m)
|
231
|
+
kill_threads
|
232
|
+
|
233
|
+
# Read watches from list.
|
234
|
+
@watchList.each{ |url, d|
|
235
|
+
feedFormat = d[0]
|
236
|
+
whichChan = d[1]
|
237
|
+
watchRss(whichChan, url,feedFormat)
|
238
|
+
}
|
239
|
+
m.okay
|
240
|
+
end
|
241
|
+
|
242
|
+
def handle_watchrss(m)
|
243
|
+
unless m.params
|
244
|
+
m.reply "incorrect usage: " + help(m.plugin)
|
245
|
+
return
|
246
|
+
end
|
247
|
+
feed = m.params.scan(/^(\S+)\s+(\S+)$/)
|
248
|
+
url = feed[0][0]
|
249
|
+
feedFormat = feed[0][1]
|
250
|
+
if @watchList.has_key?(url)
|
251
|
+
m.reply("But there is already a watch for feed #{url} on chan #{@watchList[url][1]}")
|
252
|
+
return
|
253
|
+
end
|
254
|
+
@watchList[url] = [feedFormat, m.replyto]
|
255
|
+
watchRss(m.replyto, url,feedFormat)
|
256
|
+
m.okay
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
def watchRss(whichChan, url, feedFormat)
|
261
|
+
if @@watchThreads.has_key?(url)
|
262
|
+
@bot.say whichChan, "ERROR: watcher thread for #{url} is already running! #{@@watchThreads[url]}"
|
263
|
+
return
|
264
|
+
end
|
265
|
+
@@watchThreads[url] = Thread.new do
|
266
|
+
puts 'watchRss thread started.'
|
267
|
+
oldItems = []
|
268
|
+
firstRun = true
|
269
|
+
loop do
|
270
|
+
begin # exception
|
271
|
+
title = ''
|
272
|
+
puts 'Fetching rss feed..'
|
273
|
+
newItems = fetchRSS(whichChan, url, title)
|
274
|
+
if( newItems.empty? )
|
275
|
+
@bot.say whichChan, "Oops - Item is empty"
|
276
|
+
break
|
277
|
+
end
|
278
|
+
puts "Checking if new items are available"
|
279
|
+
if (firstRun)
|
280
|
+
firstRun = false
|
281
|
+
else
|
282
|
+
newItems.each do |nItem|
|
283
|
+
showItem = true;
|
284
|
+
oldItems.each do |oItem|
|
285
|
+
if (nItem.to_s == oItem.to_s)
|
286
|
+
showItem = false
|
287
|
+
end
|
288
|
+
end
|
289
|
+
if showItem
|
290
|
+
puts "showing #{nItem.title}"
|
291
|
+
printFormatedRSS(whichChan, nItem,feedFormat)
|
292
|
+
else
|
293
|
+
puts "not showing #{nItem.title}"
|
294
|
+
break
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
oldItems = newItems
|
299
|
+
rescue Exception
|
300
|
+
$stderr.print "IO failed: " + $! + "\n"
|
301
|
+
end
|
302
|
+
|
303
|
+
seconds = 150 + rand(100)
|
304
|
+
puts "Thread going to sleep #{seconds} seconds.."
|
305
|
+
sleep seconds
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def printRSSItem(whichChan,item)
|
311
|
+
if item.kind_of?(RSS::RDF::Item)
|
312
|
+
@bot.say whichChan, shorten(riphtml(item.title.chomp), 20) + " @ " + item.link
|
313
|
+
else
|
314
|
+
@bot.say whichChan, "#{item.pubDate.to_s.chomp+": " if item.pubDate}#{shorten(riphtml(item.title.chomp), 20)+" :: " if item.title}#{" @ "+item.link.chomp if item.link}"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def printFormatedRSS(whichChan,item, type)
|
319
|
+
case type
|
320
|
+
when 'amarokblog'
|
321
|
+
@bot.say whichChan, "::#{item.category.content} just blogged at #{item.link}::"
|
322
|
+
@bot.say whichChan, "::#{shorten(riphtml(item.title.chomp), 20)} - #{shorten(riphtml(item.description.chomp),60)}::"
|
323
|
+
when 'amarokforum'
|
324
|
+
@bot.say whichChan, "::Forum:: #{item.pubDate.to_s.chomp+": " if item.pubDate}#{shorten(riphtml(item.title.chomp), 20)+" :: " if item.title}#{" @ "+item.link.chomp if item.link}"
|
325
|
+
when 'mediawiki'
|
326
|
+
@bot.say whichChan, "::Wiki:: #{item.title} has been edited by #{item.dc_creator}. #{shorten(riphtml(item.description.split("\n")[0].chomp),60)} #{item.link} ::"
|
327
|
+
puts "mediawiki #{item.title}"
|
328
|
+
when "gmame"
|
329
|
+
@bot.say whichChan, "::amarok-devel:: Message #{item.title} sent by #{item.dc_creator}. #{shorten(riphtml(item.description.split("\n")[0].chomp),60)}::"
|
330
|
+
else
|
331
|
+
printRSSItem(whichChan,item)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def fetchRSS(whichChan, url, title)
|
336
|
+
begin
|
337
|
+
# Use 60 sec timeout, cause the default is too low
|
338
|
+
xml = Utils.http_get(url,60,60)
|
339
|
+
rescue URI::InvalidURIError, URI::BadURIError => e
|
340
|
+
@bot.say whichChan, "invalid rss feed #{url}"
|
341
|
+
return
|
342
|
+
end
|
343
|
+
puts 'fetched'
|
344
|
+
unless xml
|
345
|
+
@bot.say whichChan, "reading feed #{url} failed"
|
346
|
+
return
|
347
|
+
end
|
348
|
+
|
349
|
+
begin
|
350
|
+
## do validate parse
|
351
|
+
rss = RSS::Parser.parse(xml)
|
352
|
+
puts 'parsed'
|
353
|
+
rescue RSS::InvalidRSSError
|
354
|
+
## do non validate parse for invalid RSS 1.0
|
355
|
+
begin
|
356
|
+
rss = RSS::Parser.parse(xml, false)
|
357
|
+
rescue RSS::Error
|
358
|
+
@bot.say whichChan, "parsing rss stream failed, whoops =("
|
359
|
+
return
|
360
|
+
end
|
361
|
+
rescue RSS::Error
|
362
|
+
@bot.say whichChan, "parsing rss stream failed, oioi"
|
363
|
+
return
|
364
|
+
rescue
|
365
|
+
@bot.say whichChan, "processing error occured, sorry =("
|
366
|
+
return
|
367
|
+
end
|
368
|
+
items = []
|
369
|
+
if rss.nil?
|
370
|
+
@bot.say whichChan, "#{m.params} does not include RSS 1.0 or 0.9x/2.0"
|
371
|
+
else
|
372
|
+
begin
|
373
|
+
rss.output_encoding = "euc-jp"
|
374
|
+
rescue RSS::UnknownConvertMethod
|
375
|
+
@bot.say whichChan, "bah! something went wrong =("
|
376
|
+
return
|
377
|
+
end
|
378
|
+
rss.channel.title ||= "Unknown"
|
379
|
+
title.replace(rss.channel.title)
|
380
|
+
rss.items.each do |item|
|
381
|
+
item.title ||= "Unknown"
|
382
|
+
items << item
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
if items.empty?
|
387
|
+
@bot.say whichChan, "no items found in the feed, maybe try weed?"
|
388
|
+
return
|
389
|
+
end
|
390
|
+
return items
|
391
|
+
end
|
392
|
+
|
393
|
+
def riphtml(str)
|
394
|
+
str.gsub(/<[^>]+>/, '').gsub(/&/,'&').gsub(/"/,'"').gsub(/</,'<').gsub(/>/,'>').gsub(/&ellip;/,'...').gsub(/'/, "'").gsub("\n",'')
|
395
|
+
end
|
396
|
+
|
397
|
+
def shorten(str, limit)
|
398
|
+
if str.length > limit
|
399
|
+
str+". " =~ /^(.{#{limit}}[^.!;?]*[.!;?])/mi
|
400
|
+
return $1
|
401
|
+
end
|
402
|
+
str
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
plugin = RSSFeedsPlugin.new
|
407
|
+
plugin.register("rss")
|
408
|
+
plugin.register("addrss")
|
409
|
+
plugin.register("rmrss")
|
410
|
+
plugin.register("listrss")
|
411
|
+
plugin.register("rewatch")
|
412
|
+
plugin.register("watchrss")
|
413
|
+
plugin.register("listwatches")
|
414
|
+
plugin.register("rmwatch")
|