mod_spox 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/CHANGELOG +31 -1
  2. data/LICENSE +674 -0
  3. data/README.rdoc +73 -0
  4. data/bin/mod_spox +28 -28
  5. data/data/mod_spox/extras/AOLSpeak.rb +2 -3
  6. data/data/mod_spox/extras/AutoKick.rb +10 -23
  7. data/data/mod_spox/extras/AutoMode.rb +12 -23
  8. data/data/mod_spox/extras/Bash.rb +55 -0
  9. data/data/mod_spox/extras/Bouncer.rb +85 -57
  10. data/data/mod_spox/extras/Bullshit.rb +1 -1
  11. data/data/mod_spox/extras/Bytes.rb +1 -2
  12. data/data/mod_spox/extras/Confess.rb +27 -29
  13. data/data/mod_spox/extras/DCC.rb +11 -20
  14. data/data/mod_spox/extras/DevWatch.rb +21 -23
  15. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  16. data/data/mod_spox/extras/EightBall.rb +1 -1
  17. data/data/mod_spox/extras/FML.rb +35 -0
  18. data/data/mod_spox/extras/Headers.rb +31 -50
  19. data/data/mod_spox/extras/Karma.rb +81 -29
  20. data/data/mod_spox/extras/Logger.rb +2 -2
  21. data/data/mod_spox/extras/LolSpeak.rb +1 -2
  22. data/data/mod_spox/extras/PhpCli.rb +138 -8
  23. data/data/mod_spox/extras/PhpFuncLookup.rb +20 -23
  24. data/data/mod_spox/extras/Pinger.rb +1 -1
  25. data/data/mod_spox/extras/Quotes.rb +8 -10
  26. data/data/mod_spox/extras/RegexTracker.rb +2 -4
  27. data/data/mod_spox/extras/Roulette.rb +20 -27
  28. data/data/mod_spox/extras/RubyCli.rb +93 -0
  29. data/data/mod_spox/extras/Search.rb +17 -3
  30. data/data/mod_spox/extras/Seen.rb +150 -0
  31. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  32. data/data/mod_spox/extras/Talk.rb +2 -4
  33. data/data/mod_spox/extras/Topten.rb +10 -12
  34. data/data/mod_spox/extras/TracTicket.rb +3 -5
  35. data/data/mod_spox/extras/Translate.rb +20 -22
  36. data/data/mod_spox/extras/Twitter.rb +118 -33
  37. data/data/mod_spox/extras/UrbanDictionary.rb +8 -17
  38. data/data/mod_spox/extras/Weather.rb +1 -2
  39. data/data/mod_spox/plugins/Authenticator.rb +93 -98
  40. data/data/mod_spox/plugins/Banner.rb +26 -56
  41. data/data/mod_spox/plugins/Helper.rb +5 -6
  42. data/data/mod_spox/plugins/Initializer.rb +4 -14
  43. data/data/mod_spox/plugins/Joiner.rb +1 -1
  44. data/data/mod_spox/plugins/Nicker.rb +13 -0
  45. data/data/mod_spox/plugins/Parter.rb +2 -2
  46. data/data/mod_spox/plugins/Permissions.rb +60 -0
  47. data/data/mod_spox/plugins/PluginLoader.rb +7 -12
  48. data/data/mod_spox/plugins/Ponger.rb +51 -0
  49. data/data/mod_spox/plugins/Quitter.rb +1 -2
  50. data/data/mod_spox/plugins/Servers.rb +57 -0
  51. data/data/mod_spox/plugins/Status.rb +3 -2
  52. data/data/mod_spox/plugins/Triggers.rb +9 -9
  53. data/lib/mod_spox/Bot.rb +109 -33
  54. data/lib/mod_spox/BotConfig.rb +2 -2
  55. data/lib/mod_spox/ConfigurationWizard.rb +12 -12
  56. data/lib/mod_spox/Database.rb +1 -4
  57. data/lib/mod_spox/Exceptions.rb +26 -0
  58. data/lib/mod_spox/Helpers.rb +29 -68
  59. data/lib/mod_spox/Loader.rb +23 -24
  60. data/lib/mod_spox/Logger.rb +19 -17
  61. data/lib/mod_spox/MessageFactory.rb +50 -24
  62. data/lib/mod_spox/Pipeline.rb +21 -7
  63. data/lib/mod_spox/Plugin.rb +27 -3
  64. data/lib/mod_spox/PluginManager.rb +28 -15
  65. data/lib/mod_spox/PriorityQueue.rb +69 -0
  66. data/lib/mod_spox/Socket.rb +93 -51
  67. data/lib/mod_spox/Sockets.rb +76 -63
  68. data/lib/mod_spox/Timer.rb +21 -141
  69. data/lib/mod_spox/Version.rb +14 -0
  70. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  71. data/lib/mod_spox/handlers/Bounce.rb +5 -5
  72. data/lib/mod_spox/handlers/Created.rb +13 -5
  73. data/lib/mod_spox/handlers/Handler.rb +12 -3
  74. data/lib/mod_spox/handlers/Invite.rb +14 -8
  75. data/lib/mod_spox/handlers/Join.rb +24 -20
  76. data/lib/mod_spox/handlers/Kick.rb +22 -13
  77. data/lib/mod_spox/handlers/Mode.rb +42 -36
  78. data/lib/mod_spox/handlers/Motd.rb +4 -0
  79. data/lib/mod_spox/handlers/Names.rb +66 -39
  80. data/lib/mod_spox/handlers/Nick.rb +20 -14
  81. data/lib/mod_spox/handlers/Part.rb +25 -8
  82. data/lib/mod_spox/handlers/Ping.rb +11 -5
  83. data/lib/mod_spox/handlers/Pong.rb +9 -5
  84. data/lib/mod_spox/handlers/Privmsg.rb +25 -17
  85. data/lib/mod_spox/handlers/Quit.rb +13 -8
  86. data/lib/mod_spox/handlers/Topic.rb +4 -0
  87. data/lib/mod_spox/handlers/Welcome.rb +16 -24
  88. data/lib/mod_spox/handlers/Who.rb +64 -48
  89. data/lib/mod_spox/handlers/Whois.rb +92 -60
  90. data/lib/mod_spox/messages/incoming/Nick.rb +2 -2
  91. data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -1
  92. data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
  93. data/lib/mod_spox/messages/internal/EstablishConnection.rb +1 -1
  94. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  95. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  96. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  97. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  98. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  99. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  100. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  101. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  102. data/lib/mod_spox/models/Auth.rb +16 -46
  103. data/lib/mod_spox/models/AuthMask.rb +13 -0
  104. data/lib/mod_spox/models/Channel.rb +46 -27
  105. data/lib/mod_spox/models/Config.rb +10 -19
  106. data/lib/mod_spox/models/Group.rb +20 -8
  107. data/lib/mod_spox/models/Models.rb +1 -1
  108. data/lib/mod_spox/models/Nick.rb +105 -113
  109. data/lib/mod_spox/models/NickMode.rb +23 -9
  110. data/lib/mod_spox/models/Server.rb +12 -1
  111. data/lib/mod_spox/models/Setting.rb +12 -16
  112. data/lib/mod_spox/models/Signature.rb +28 -8
  113. data/tests/BotHolder.rb +24 -0
  114. data/tests/handlers/tc_BadNick.rb +21 -0
  115. data/tests/handlers/tc_Created.rb +24 -0
  116. data/tests/handlers/tc_Invite.rb +50 -0
  117. data/tests/handlers/tc_Join.rb +33 -0
  118. data/tests/handlers/tc_Kick.rb +32 -0
  119. data/tests/handlers/tc_Mode.rb +85 -0
  120. data/tests/handlers/tc_Names.rb +35 -0
  121. data/tests/handlers/tc_Nick.rb +55 -0
  122. data/tests/handlers/tc_Part.rb +44 -0
  123. data/tests/handlers/tc_Ping.rb +40 -0
  124. data/tests/handlers/tc_Pong.rb +28 -0
  125. data/tests/handlers/tc_Privmsg.rb +85 -0
  126. data/tests/handlers/tc_Quit.rb +40 -0
  127. data/tests/handlers/tc_Who.rb +50 -0
  128. data/tests/handlers/tc_Whois.rb +61 -0
  129. data/tests/models/tc_Auth.rb +34 -0
  130. data/tests/models/tc_Channel.rb +52 -0
  131. data/tests/models/tc_Config.rb +19 -0
  132. data/tests/models/tc_Nick.rb +142 -0
  133. data/tests/models/tc_NickMode.rb +40 -0
  134. data/tests/models/tc_Setting.rb +21 -0
  135. data/tests/models/tc_Signature.rb +14 -0
  136. data/tests/run_tests.rb +4 -0
  137. metadata +284 -212
  138. data/README +0 -36
  139. data/lib/mod_spox/Cache.rb +0 -57
  140. data/lib/mod_spox/Monitors.rb +0 -84
  141. data/lib/mod_spox/Pool.rb +0 -164
  142. data/lib/mod_spox/models/AuthGroup.rb +0 -16
  143. data/lib/mod_spox/models/ChannelMode.rb +0 -14
  144. data/lib/mod_spox/models/NickChannel.rb +0 -45
  145. data/lib/mod_spox/models/NickGroup.rb +0 -16
@@ -5,10 +5,8 @@ class Talk < ModSpox::Plugin
5
5
  def initialize(pipeline)
6
6
  super
7
7
  group = Group.find_or_create(:name => 'talk')
8
- Signature.find_or_create(:signature => 'say (\S+) (.+)', :plugin => name, :method => 'talk', :group_id => group.pk,
9
- :description => 'Make bot speak given text to target', :requirement => 'private').params = [:target, :text]
10
- Signature.find_or_create(:signature => 'action (\S+) (.+)', :plugin => name, :method => 'action', :group_id => group.pk,
11
- :description => 'Make bot perform action for target', :requirement => 'private').params = [:target, :text]
8
+ add_sig(:sig => 'say (\S+) (.+)', :method => :talk, :group => group, :desc => 'Make bot speak given text to target', :req => 'private', :params => [:target, :text])
9
+ add_sig(:sig => 'action (\S+) (.+)', :method => :action, :group => group, :desc => 'Make bot perform action for target', :req => 'private', :params => [:target, :text])
12
10
  end
13
11
 
14
12
  def talk(message, params)
@@ -5,20 +5,16 @@ class Topten < ModSpox::Plugin
5
5
  def initialize(pipeline)
6
6
  super
7
7
  ChatStat.create_table unless ChatStat.table_exists?
8
- Signature.find_or_create(:signature => 'topten', :plugin => name, :method => 'topten',
9
- :requirement => 'public', :description => 'Show topten users since midnight')
10
- Signature.find_or_create(:signature => 'topten ([0-9]{4}\/[0-9]{2}\/[0-9]{2})', :plugin => name, :method => 'archive',
11
- :description => 'Show topten from given date', :requirement => 'public').params = [:date]
12
- Signature.find_or_create(:signature => 'stats ?(\S+)?', :plugin => name, :method => 'stats', :description => 'Show stats on nick',
13
- :requirement => 'public').params = [:nick]
14
- Signature.find_or_create(:signature => 'stats lifetime (\S+)?', :plugin => name, :method => 'life_stats',
15
- :description => 'Show stat totals for given nick', :requirement => 'public').params = [:nick]
8
+ add_sig(:sig => 'topten', :method => :topten, :req => 'public', :desc => 'Show topten users since midnight')
9
+ add_sig(:sig => 'topten ([0-9]{4}\/[0-9]{2}\/[0-9]{2})', :method => :archive, :desc => 'Show topten from given date', :req => 'public', :params => [:date])
10
+ add_sig(:sig => 'stats ?(\S+)?', :method => :stats, :desc => 'Show stats on nick', :req => 'public', :params => [:nick])
11
+ add_sig(:sig => 'stats lifetime (\S+)?', :method => :life_stats, :desc => 'Show stat totals for given nick', :req => 'public', :params => [:nick])
16
12
  @pipeline.hook(self, :log_stats, :Incoming_Privmsg)
17
13
  end
18
14
 
19
15
  def topten(m, p)
20
16
  stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => construct_daykey).reverse_order(:bytes).limit(10)
21
- if(stats.size > 0)
17
+ if(stats.count > 0)
22
18
  users = []
23
19
  stats.each do |stat|
24
20
  bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
@@ -32,7 +28,7 @@ class Topten < ModSpox::Plugin
32
28
 
33
29
  def archive(m, p)
34
30
  stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => p[:date]).reverse_order(:bytes).limit(10)
35
- if(stats.size > 0)
31
+ if(stats.count > 0)
36
32
  users = []
37
33
  stats.each do |stat|
38
34
  bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
@@ -62,8 +58,8 @@ class Topten < ModSpox::Plugin
62
58
  def life_stats(m, p)
63
59
  nick = p[:nick] ? Nick.locate(p[:nick], false) : m.source
64
60
  if(nick)
65
- result = ChatStat.group(:nick_id).select(:SUM[:bytes].as(:tbytes), :SUM[:words].as(:twords), :SUM[:questions].as(:tquestions)).filter(:nick_id => nick.pk).first
66
- bytes = (result[:tbytes] > 1023) ? "#{sprintf('%.2f', (result[:tbytes] / 1024.0))}kb" : "#{result[:tbytes]}b"
61
+ result = ChatStat.group(:nick_id).select('SUM(bytes) as tbytes'.lit, 'SUM(words) as twords'.lit, 'SUM(questions) as tquestions'.lit).filter(:nick_id => nick.pk).first
62
+ bytes = (result[:tbytes].to_i > 1023) ? "#{sprintf('%.2f', (result[:tbytes].to_i / 1024.0))}kb" : "#{result[:tbytes]}b"
67
63
  reply m.replyto, "#{nick.nick} (total): #{bytes} logged, #{result[:twords]} words spoken and #{result[:tquestions]} questions asked"
68
64
  else
69
65
  reply m.replyto, "\2Error:\2 Failed to find #{p[:nick]}"
@@ -100,6 +96,8 @@ class Topten < ModSpox::Plugin
100
96
  foreign_key :channel_id, :table => :channels
101
97
  foreign_key :nick_id, :table => :nicks
102
98
  end
99
+ many_to_one :channel, :class => ModSpox::Models::Channel
100
+ many_to_one :nick, :class => ModSpox::Models::Nick
103
101
  end
104
102
 
105
103
  end
@@ -10,14 +10,12 @@ class TracTicket < ModSpox::Plugin
10
10
  add_sig(:sig => 'ticket trac( (\S+))?', :method => :trac_location, :group => admin,
11
11
  :desc => 'Show/set trac site', :params => [:trash, :site])
12
12
  add_sig(:sig => 'ticket site', :method => :trac_location, :desc => 'Show trac site')
13
- @site = Config[:trac]
13
+ @site = Config.val(:trac)
14
14
  end
15
15
 
16
16
  def trac_location(message, params)
17
17
  if(params[:site])
18
- site = Config.find_or_create(:name => 'trac')
19
- site.value = params[:site]
20
- site.save
18
+ site = Config.set(:trac, params[:site])
21
19
  @site = params[:site]
22
20
  reply message.replyto, "\2Trac Update:\2 Location of trac system has been updated: #{params[:site]}"
23
21
  else
@@ -44,7 +42,7 @@ class TracTicket < ModSpox::Plugin
44
42
  'Referer' => @site,
45
43
  'Content-Type' => 'application/x-www-form-urlencoded'
46
44
  }
47
- data = "reporter=#{URI.escape(message.source.nick)}&summary=#{URI.escape(params[:short])}&description=#{URI.escape(long)}&type=#{URI.escape(params[:type])}&action=create&status=new&priority=minor&__FORM_TOKEN=#{URI.escape(fid)}"
45
+ data = "field_reporter=#{URI.escape(message.source.nick)}&field_summary=#{URI.escape(params[:short])}&field_description=#{URI.escape(long)}&field_type=#{URI.escape(params[:type])}&field_status=new&submit=Create%20ticket&field_priority=minor&__FORM_TOKEN=#{URI.escape(fid)}"
48
46
  resp, data = con.post(path, data, headers)
49
47
  reply message.replyto, 'Ticket was successfully added to tracker'
50
48
  rescue Object => boom
@@ -4,23 +4,13 @@ class Translate < ModSpox::Plugin
4
4
 
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
- begin
8
- require 'htmlentities'
9
- rescue Object => boom
10
- Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
11
- raise Exceptions::BotException.new("Missing required HTMLEntities library")
12
- end
13
- Signature.find_or_create(:signature => 'translate ([a-z]{2}\|[a-z]{2}) (.+)', :plugin => name, :method => 'translate',
14
- :description => 'Translate text').params = [:lang, :text]
15
- Signature.find_or_create(:signature => 'autotranslate add ([a-z]{2}) (\S+)', :plugin => name, :method => 'auto_add',
16
- :description => 'Add a nick to the autotranslate service').params = [:lang, :nick]
17
- Signature.find_or_create(:signature => 'autotranslate remove (\S+)', :plugin => name, :method => 'auto_remove',
18
- :description => 'Remove a nick from the autotranslate service').params = [:nick]
19
- add_sig(:sig => 'translate languages', :method => 'langs', :description => 'Show available languages')
7
+ add_sig(:sig => 'translate ([a-z]{2}\|[a-z]{2}) (.+)', :method => :translate, :desc => 'Translate text', :params => [:lang, :text])
8
+ add_sig(:sig => 'autotranslate add ([a-z]{2}) (\S+)', :method => :auto_add, :desc => 'Add a nick to the autotranslate service', :params => [:lang, :nick])
9
+ add_sig(:sig => 'autotranslate remove (\S+)', :method => :auto_remove, :desc => 'Remove a nick from the autotranslate service', :params => [:nick])
10
+ add_sig(:sig => 'translate languages', :method => :langs, :desc => 'Show available languages')
20
11
  @pipeline.hook(self, :listener, :Incoming_Privmsg)
21
12
  @watchers = {}
22
13
  @cache = {}
23
- @coder = HTMLEntities.new
24
14
  @allowed = {'zh'=>'Chinese-simplified','zt'=>'Chinese-traditional','en'=>'English','nl'=>'Dutch',
25
15
  'fr'=>'French','de'=>'German','el'=>'Greek','it'=>'Italian','ja'=>'Japanese',
26
16
  'ko'=>'Korean','pt'=>'Portuguese','ru'=>'Russian','es'=>'Spanish'}
@@ -82,12 +72,13 @@ class Translate < ModSpox::Plugin
82
72
  def listener(message)
83
73
  if(message.is_public? && @watchers.has_key?(message.target.pk))
84
74
  if(@watchers[message.target.pk].has_key?(message.source.pk))
85
- trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}en", message.message)
75
+ trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}|en", message.message)
86
76
  reply message.replyto, "\2Translation (#{message.source.nick}):\2 #{trans_message}" unless trans_message == message.message
87
- elsif(message.message =~ /^(\S+)[:,]/)
77
+ elsif(message.message =~ /^(\S+[:, ])/)
78
+ message.message.slice!(0..$1.size)
88
79
  Logger.info("Translate matched a followed nick: #{$1}")
89
80
  nick = Helpers.find_model($1, false)
90
- return unless nick
81
+ return unless nick.is_a?(Models::Nick)
91
82
  if(@watchers[message.target.pk].has_key?(nick.pk))
92
83
  reply message.replyto, "\2(#{do_translation("en|#{@watchers[message.target.pk][nick.pk]}", 'translation')})\2 #{do_translation("en|#{@watchers[message.target.pk][nick.pk]}", message.message)}"
93
84
  end
@@ -102,17 +93,24 @@ class Translate < ModSpox::Plugin
102
93
  if(@cache.has_key?(langs) && @cache[langs].has_key?(text))
103
94
  return @cache[langs][text]
104
95
  end
105
- content = Net::HTTP.post_form(URI.parse('http://babelfish.yahoo.com/translate_txt'), {
96
+ headers = {'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'}
97
+ url = URI.parse('http://babelfish.yahoo.com/translate_txt')
98
+ post = Net::HTTP::Post.new(url.path, headers)
99
+ post.set_form_data({
106
100
  'ei' => 'UTF-8',
107
101
  'doit' => 'done',
108
- 'fr' => 'bf-home',
102
+ 'fr' => 'bf-res',
109
103
  'intl' => '1',
110
104
  'tt' => 'urltext',
111
105
  'trtext' => text,
112
106
  'lp' => langs.gsub(/\|/, '_'),
113
107
  'btnTrTxt' => 'Translate'
114
- }).body
115
- if(content)
108
+ })
109
+ result = Net::HTTP.new(url.host, url.port).start do |http|
110
+ http.request(post)
111
+ end
112
+ if(result.is_a?(Net::HTTPSuccess))
113
+ content = result.body
116
114
  if(content =~ /<div id="result">(.+?)<input/im)
117
115
  tr = $1
118
116
  tr.gsub!(/<.+?>/, '')
@@ -122,7 +120,7 @@ class Translate < ModSpox::Plugin
122
120
  @cache[langs] = {} unless @cache.has_key?(langs)
123
121
  @cache[langs][text] = tr
124
122
  end
125
- return @coder.decode(tr).strip
123
+ return Helpers.convert_entities(tr).strip
126
124
  else
127
125
  raise 'Failed to locate translation'
128
126
  end
@@ -34,7 +34,7 @@ class Twitter < ModSpox::Plugin
34
34
  ModClient.configure do |conf|
35
35
  conf.user_agent = 'mod_spox twitter for twits'
36
36
  conf.application_name = 'mod_spox IRC bot'
37
- conf.application_version = "#{$BOTVERSION} (#{$BOTCODENAME})"
37
+ conf.application_version = "#{ModSpox.botversion} (#{ModSpox.botcodename})"
38
38
  conf.application_url = 'http://rubyforge.org/projects/mod_spox'
39
39
  conf.source = 'modspoxircbot'
40
40
  end
@@ -64,11 +64,19 @@ class Twitter < ModSpox::Plugin
64
64
  :group => admin, :req => 'public')
65
65
  add_sig(:sig => 'autotweets interval( \d+)?', :method => :auto_tweets_interval, :desc => 'Set/show interval for auto tweet checks',
66
66
  :group => admin, :params => [:interval])
67
+ add_sig(:sig => 'autotweets burst( \d+)?', :method => :auto_tweets_burst, :desc => 'Set/show maximum number of tweets to display at once',
68
+ :group => admin, :params => [:burst])
69
+ add_sig(:sig => 'twitter alias (\S+) (\S+)', :method => :alias_user, :desc => 'Set alias for twitter account', :group => twitter, :params => [:twit, :irc])
70
+ add_sig(:sig => 'twitter aliases (\S+)', :method => :show_aliases, :desc => 'Show alias for twit', :params => [:twit])
71
+ add_sig(:sig => 'twitter dealias (\S+)', :method => :remove_alias, :desc => 'Remove alias for twit', :params => [:twit], :group => twitter)
67
72
  @pipeline.hook(self, :get_timer, :Internal_TimerResponse)
68
73
  @auth_info = Models::Setting.find_or_create(:name => 'twitter').value
69
74
  @twitter = ModClient.new
70
- @coder = HTMLEntities.new
71
75
  @search_url = 'http://search.twitter.com/search.json'
76
+ @aliases = Models::Setting.find_or_create(:name => 'twitter_aliases').value
77
+ @aliases = {} if @aliases.nil?
78
+ @burst = Models::Setting.find_or_create(:name => 'twitter_burst').value
79
+ @burst = @burst.nil? ? 5 : @burst.to_i
72
80
  unless(@auth_info.is_a?(Hash))
73
81
  @auth_info = {:username => nil, :password => nil, :interval => 0, :channels => []}
74
82
  else
@@ -78,8 +86,64 @@ class Twitter < ModSpox::Plugin
78
86
  @lock = Mutex.new
79
87
  @running = false
80
88
  @timer = {:action => nil, :id => nil}
89
+ @friends = []
90
+ populate_friends
81
91
  start_auto
82
92
  end
93
+
94
+ def auto_tweets_burst(m, params)
95
+ if(params[:burst])
96
+ params[:burst] = params[:burst].to_i
97
+ if(params[:burst] == 0)
98
+ error m.replyto, 'Invalid value. Must supply a positive integer.'
99
+ else
100
+ @burst = params[:burst]
101
+ information m.replyto, "Updated maximum autotweet burst to: #{@burst}"
102
+ end
103
+ else
104
+ information m.replyto, "Maximum number of tweets to auto report: #{@burst}"
105
+ end
106
+ end
107
+
108
+ def alias_user(m, params)
109
+ begin
110
+ raise "twit #{params[:twit]} is not in my friends list" unless @friends.include?(params[:twit])
111
+ raise "twit is already aliased to #{Models::Nick[@aliases[params[:twit].to_sym]].nick}" if @aliases.has_key?(params[:twit].to_sym)
112
+ nick = Helpers.find_model(params[:irc])
113
+ raise "failed to find nick #{params[:irc]}. is this a new user?" if nick.nil?
114
+ @aliases[params[:twit].to_sym] = nick.pk
115
+ save_aliases
116
+ information m.replyto, "Nick #{params[:irc]} is now aliased to twit #{params[:twit]}"
117
+ rescue Object => boom
118
+ error m.replyto, "Failed to alias user: #{boom}"
119
+ end
120
+ end
121
+
122
+ def save_aliases
123
+ t = Models::Setting.find_or_create(:name => 'twitter_aliases')
124
+ t.value = @aliases
125
+ t.save
126
+ end
127
+
128
+ def show_aliases(m, params)
129
+ begin
130
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
131
+ information m.replyto, "Twit #{params[:twit]} is aliased to: #{Models::Nick[@aliases[params[:twit].to_sym]].nick}"
132
+ rescue Object => boom
133
+ error m.replyto, "Failed to find alias. Reason: #{boom}"
134
+ end
135
+ end
136
+
137
+ def remove_alias(m, params)
138
+ begin
139
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
140
+ @aliases.delete(params[:twit].to_sym)
141
+ save_aliases
142
+ information m.replyto, "Twit #{params[:twit]} is no longer aliased"
143
+ rescue Object => boom
144
+ error m.replyto, "Failed to remove alias: #{boom}"
145
+ end
146
+ end
83
147
 
84
148
  def search(m, params)
85
149
  url = URI.escape("#{@search_url}?rpp=1&q=#{params[:term]}")
@@ -109,7 +173,10 @@ class Twitter < ModSpox::Plugin
109
173
  output = ["Twitter match for: \2#{term}:\2"]
110
174
  result['results'].each do |item|
111
175
  t = Time.parse(item['created_at'])
112
- output << "[#{t.strftime("%Y/%m/%d-%H:%M:%S")}] <#{item['from_user']}> #{item['text']}"
176
+ output << "[#{t.strftime("%Y/%m/%d-%H:%M:%S")}] <#{item['from_user']}> #{Helpers.convert_entities(item['text'])}"
177
+ end
178
+ if(output.size < 2)
179
+ output = "\2Error:\2 No results found for term: #{term}"
113
180
  end
114
181
  return output
115
182
  rescue Object => boom
@@ -121,7 +188,7 @@ class Twitter < ModSpox::Plugin
121
188
  msgs = @twitter.messages(:received)
122
189
  reply m.replyto, "\2Twitter INBOX\2 Messages in inbox: #{msgs.size} (only last 5 displayed)"
123
190
  msgs.slice(0..5).each do | msg |
124
- reply m.replyto, "\2#{msg.sender.screen_name}:\2 [#{msg.id}] #{@coder.decode(msg.text)}"
191
+ reply m.replyto, "\2#{msg.sender.screen_name}:\2 [#{msg.id}] #{Helpers.convert_entities(msg.text)}"
125
192
  end
126
193
  end
127
194
 
@@ -239,15 +306,10 @@ class Twitter < ModSpox::Plugin
239
306
  end
240
307
 
241
308
  def friends(m, params)
242
- begin
243
- fs = @twitter.my(:friends)
244
- if(fs.size > 0)
245
- reply m.replyto, "\2Friends:\2 #{fs.map{|u| u.screen_name}.join(', ')}"
246
- else
247
- warning m.replyto, 'no friends found'
248
- end
249
- rescue Object => boom
250
- error m.replyto, "failed to locate friends list. (#{boom})"
309
+ if(@friends.size > 0)
310
+ reply m.replyto, "\2Friends:\2 #{@friends.join(', ')}"
311
+ else
312
+ warning m.replyto, 'no friends found'
251
313
  end
252
314
  end
253
315
 
@@ -257,6 +319,7 @@ class Twitter < ModSpox::Plugin
257
319
  unless(@twitter.my(:friends).include?(user))
258
320
  @twitter.friend(:add, user)
259
321
  information m.replyto, "added new friend: #{params[:twit]}"
322
+ @friends << params[:twit]
260
323
  else
261
324
  warning m.replyto, "#{params[:twit]} is already in friend list"
262
325
  end
@@ -271,6 +334,7 @@ class Twitter < ModSpox::Plugin
271
334
  if(@twitter.my(:friends).map{|u|u.screen_name}.include?(user.screen_name))
272
335
  @twitter.friend(:remove, user)
273
336
  information m.replyto, "removed user from friend list: #{params[:twit]}"
337
+ @friends.delete(params[:twit])
274
338
  else
275
339
  warning m.replyto, "#{params[:twit]} is not in friend list"
276
340
  end
@@ -283,7 +347,7 @@ class Twitter < ModSpox::Plugin
283
347
  begin
284
348
  msg = @twitter.status(:get, params[:m_id])
285
349
  if(msg)
286
- reply m.replyto, "\2Tweet:\2 [#{msg.created_at.strftime("%Y/%m/%d-%H:%M:%S")}}] <#{msg.user.screen_name}> #{@coder.decode(msg.text)}"
350
+ reply m.replyto, "\2Tweet:\2 [#{msg.created_at.strftime("%Y/%m/%d-%H:%M:%S")}] <#{screen_name(msg.user.screen_name)}> #{Helpers.convert_entities(msg.text)}"
287
351
  else
288
352
  warning m.replyto, "failed to find message with ID: #{params[:m_id].strip}"
289
353
  end
@@ -294,6 +358,34 @@ class Twitter < ModSpox::Plugin
294
358
 
295
359
  private
296
360
 
361
+ def populate_friends
362
+ return unless @lock.try_lock
363
+ begin
364
+ fs = @twitter.my(:friends)
365
+ @friends = []
366
+ if(fs.size > 0)
367
+ @friends = fs.map{|u| u.screen_name}
368
+ end
369
+ rescue Object => boom
370
+ Logger.info("Failed to populate friends: #{boom}")
371
+ @pipeline << Messages::Internal::TimerAdd.new(self, 200, nil, true){ populate_friends }
372
+ ensure
373
+ @lock.unlock
374
+ end
375
+ end
376
+
377
+ def screen_name(n)
378
+ return @aliases.has_key?(n.to_sym) ? Models::Nick[@aliases[n.to_sym]].nick : n
379
+ end
380
+
381
+ def replace_names(s)
382
+ s.scan(/@\S+/).each do |n|
383
+ n.slice!(0)
384
+ s.gsub!("@#{n}", "@#{screen_name(n)}")
385
+ end
386
+ return s
387
+ end
388
+
297
389
  def check_timeline
298
390
  if(@auth_info[:channels].size < 1 || @auth_info[:interval].to_i < 1)
299
391
  Logger.warn('Twitter has no channels to send information to')
@@ -302,19 +394,24 @@ class Twitter < ModSpox::Plugin
302
394
  things = []
303
395
  @twitter.my(:friends).each do |f|
304
396
  @twitter.timeline_for(:friend, :id => f.screen_name, :since => @last_check) do |status|
305
- if(@coder.decode(status.text) =~ /^@(\S+)/)
397
+ next if status.created_at < @last_check
398
+ if(Helpers.convert_entities(status.text) =~ /^@(\S+)/)
306
399
  next unless @twitter.my(:friends).map{|f|f.screen_name}.include?($1) || $1 == @twitter.login
307
400
  end
308
- things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{status.user.screen_name}> #{@coder.decode(status.text)}"
401
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
309
402
  end
310
403
  end
311
404
  @twitter.timeline_for(:me, :since => @last_check) do |status|
312
- things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{status.user.screen_name}> #{@coder.decode(status.text)}"
405
+ next if status.created_at < @last_check
406
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
313
407
  end
314
- things.uniq!
315
- things.sort!
316
- things.each do |status|
317
- @auth_info[:channels].each{|i| reply Models::Channel[i], "\2AutoTweet:\2 #{status}"}
408
+ unless(things.empty?)
409
+ things.uniq!
410
+ things.sort!
411
+ things = things[-@burst,@burst] if things.size > @burst
412
+ things.each do |status|
413
+ @auth_info[:channels].each{|i| reply Models::Channel[i], "\2AutoTweet:\2 #{status}"}
414
+ end
318
415
  end
319
416
  @last_check = Time.now
320
417
  rescue Object => boom
@@ -323,18 +420,6 @@ class Twitter < ModSpox::Plugin
323
420
  end
324
421
  end
325
422
 
326
- def information(to, message)
327
- reply to, "\2Twitter (info):\2 #{message}"
328
- end
329
-
330
- def warning(to, message)
331
- reply to, "\2Twitter (warn):\2 #{message}"
332
- end
333
-
334
- def error(to, message)
335
- reply to, "\2Twitter (error):\2 #{message}"
336
- end
337
-
338
423
  def save_info
339
424
  i = Models::Setting.find_or_create(:name => 'twitter')
340
425
  i.value = @auth_info
@@ -7,21 +7,12 @@ class UrbanDictionary < ModSpox::Plugin
7
7
 
8
8
  def initialize(pipeline)
9
9
  super(pipeline)
10
- begin
11
- require 'htmlentities'
12
- rescue Object => boom
13
- Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
14
- raise Exceptions::BotException.new("Missing required HTMLEntities library")
15
- end
16
- Signature.find_or_create(:signature => 'udefine (?!key)(\d+)? ?(.+)', :plugin => name, :method => 'define',
17
- :description => 'Find the definition of a word or phrase').params = [:number, :term]
18
- Signature.find_or_create(:signature => 'udefine key (.+)', :plugin => name, :method => 'key',
19
- :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Set API key').params = [:key]
20
- @coder = HTMLEntities.new
10
+ add_sig(:sig => 'udefine (?!key)((\d+ )?(.+))', :method => :define, :desc => 'Find the definition of a word or phrase', :params => [:fullmatch, :number, :term])
11
+ add_sig(:sig => 'udefine key (.+)', :method => :key, :group => Models::Group.filter(:name => 'admin').first, :desc => 'Set API key', :params => [:key])
21
12
  end
22
13
 
23
14
  def define(message, params)
24
- key = Config[:urban_key]
15
+ key = Config.val(:urban_key)
25
16
  if(key)
26
17
  site = 'http://api.urbandictionary.com/soap?wsdl'
27
18
  result = params[:number] ? params[:number].to_i - 1 : 0
@@ -35,11 +26,11 @@ class UrbanDictionary < ModSpox::Plugin
35
26
  if defs.size < result + 1
36
27
  @pipeline << Privmsg.new(message.replyto, "Error: Definition number #{result+1} for term: #{params[:term]} not found.")
37
28
  else
38
- defin = defs[result].definition.length > 500 ? defs[result].definition.slice(0..500) + " *[CUT]*" : defs[result].definition
39
- exp = defs[result].example.length > 500 ? defs[result].example.slice(0..500) + " *[CUT]*" : defs[result].example
29
+ defin = defs[result].definition.length > 390 ? defs[result].definition.slice(0..390) + " *[CUT]*" : defs[result].definition
30
+ exp = defs[result].example.length > 390 ? defs[result].example.slice(0..390) + " *[CUT]*" : defs[result].example
40
31
  output << "Definition for \2#{defs[result].word}:\2"
41
- output << @coder.decode(defin.gsub(/[\r\n\s]+/, ' '))
42
- output << "\2Example usage:\2 #{@coder.decode(exp.gsub(/[\r\n\s]+/, ' '))}" if exp.length > 0
32
+ output << Helpers.convert_entities(defin.gsub(/[\r\n\s]+/, ' '))
33
+ output << "\2Example usage:\2 #{Helpers.convert_entities(exp.gsub(/[\r\n\s]+/, ' '))}" if exp.length > 0
43
34
  reply message.replyto, output
44
35
  end
45
36
  rescue Timeout::Error
@@ -56,7 +47,7 @@ class UrbanDictionary < ModSpox::Plugin
56
47
  if(message.is_public?)
57
48
  @pipeline << Privmsg.new(message.replyto, 'I don\'t set keys in public')
58
49
  else
59
- Config[:urban_key] = params[:key]
50
+ Config.set(:urban_key, params[:key])
60
51
  @pipeline << Privmsg.new(message.replyto, 'Urban Dictionary API key has been set.')
61
52
  end
62
53
  end