zetabot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +281 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +41 -0
  7. data/Rakefile +6 -0
  8. data/Zeta.gemspec +74 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +13 -0
  11. data/bin/zeta +9 -0
  12. data/bin/zeta-setup +13 -0
  13. data/lib/Zeta.rb +13 -0
  14. data/lib/Zeta/access.rb +84 -0
  15. data/lib/Zeta/admin.rb +10 -0
  16. data/lib/Zeta/admin/autojoin.rb +25 -0
  17. data/lib/Zeta/admin/bot.rb +43 -0
  18. data/lib/Zeta/admin/channels.rb +36 -0
  19. data/lib/Zeta/admin/eval.rb +43 -0
  20. data/lib/Zeta/admin/fifo.rb +45 -0
  21. data/lib/Zeta/admin/ignore.rb +112 -0
  22. data/lib/Zeta/admin/oper.rb +50 -0
  23. data/lib/Zeta/admin/plugins.rb +109 -0
  24. data/lib/Zeta/admin/users.rb +5 -0
  25. data/lib/Zeta/blacklist.rb +25 -0
  26. data/lib/Zeta/cache.rb +0 -0
  27. data/lib/Zeta/cinch.rb +35 -0
  28. data/lib/Zeta/config.rb +42 -0
  29. data/lib/Zeta/gems.rb +0 -0
  30. data/lib/Zeta/locale.rb +4 -0
  31. data/lib/Zeta/log.rb +2 -0
  32. data/lib/Zeta/models.rb +5 -0
  33. data/lib/Zeta/models/channel.rb +3 -0
  34. data/lib/Zeta/models/plugin.rb +3 -0
  35. data/lib/Zeta/models/user.rb +3 -0
  36. data/lib/Zeta/plugins.rb +27 -0
  37. data/lib/Zeta/plugins/attack.rb +61 -0
  38. data/lib/Zeta/plugins/botinfo.rb +83 -0
  39. data/lib/Zeta/plugins/darkscience.rb +215 -0
  40. data/lib/Zeta/plugins/dbz.rb +31 -0
  41. data/lib/Zeta/plugins/dcc.rb +25 -0
  42. data/lib/Zeta/plugins/dnsbl.rb +36 -0
  43. data/lib/Zeta/plugins/echo.rb +15 -0
  44. data/lib/Zeta/plugins/eightball.rb +53 -0
  45. data/lib/Zeta/plugins/fml.rb +35 -0
  46. data/lib/Zeta/plugins/fnord.rb +329 -0
  47. data/lib/Zeta/plugins/gem.rb +0 -0
  48. data/lib/Zeta/plugins/gif.rb +73 -0
  49. data/lib/Zeta/plugins/help.rb +32 -0
  50. data/lib/Zeta/plugins/libsecure.rb +34 -0
  51. data/lib/Zeta/plugins/macros.rb +124 -0
  52. data/lib/Zeta/plugins/movie.rb +67 -0
  53. data/lib/Zeta/plugins/pdfinfo.rb +69 -0
  54. data/lib/Zeta/plugins/rainbow.rb +65 -0
  55. data/lib/Zeta/plugins/russian_roulette.rb +90 -0
  56. data/lib/Zeta/plugins/seen.rb +77 -0
  57. data/lib/Zeta/plugins/silly.rb +183 -0
  58. data/lib/Zeta/plugins/snooper.rb +146 -0
  59. data/lib/Zeta/plugins/urban.rb +60 -0
  60. data/lib/Zeta/plugins/weather.rb +203 -0
  61. data/lib/Zeta/plugins/whois.rb +25 -0
  62. data/lib/Zeta/plugins/wiki.rb +75 -0
  63. data/lib/Zeta/plugins/wolfram.rb +46 -0
  64. data/lib/Zeta/tasks/db.rb +0 -0
  65. data/lib/Zeta/version.rb +3 -0
  66. data/lib/generators/config/config.rb +0 -0
  67. data/lib/generators/plugin/new_plugin.rb +0 -0
  68. data/locale/en/8ball.yml +0 -0
  69. data/locale/en/attack.yml +148 -0
  70. data/locale/en/dbz.yml +10 -0
  71. data/locale/en/ircop.yml +5 -0
  72. data/locale/en/macros.yml +98 -0
  73. data/locale/en/meme.yml +27 -0
  74. metadata +636 -0
@@ -0,0 +1,90 @@
1
+ module Plugins
2
+ class RussianRoulette
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+ enable_acl
6
+
7
+ set plugin_name: "Russian Roulette",
8
+ help: "In Soviet Russia, boolet shoots YOU!\nUsage: ?rr <nick>",
9
+ react_on: :channel
10
+
11
+ attr_reader :games
12
+
13
+ PHRASES = [
14
+ "\"BANG\" You're dead! ... Just kidding comrade... for now.",
15
+ "\"...BLAMMO!\" (hangfires are a bitch, aren't they?)",
16
+ "Are you scared yet, comrade?",
17
+ "Are you pissing your pants yet?",
18
+ "You are lucky, comrade. At least for now.",
19
+ "The chamber was as empty as your head.",
20
+ "Damn. And I thought that it had bullet too.",
21
+ "Lucky you, comrade.",
22
+ "Must be your lucky day, comrade.",
23
+ "\"BLAM!\" you can't play russian roulette with a tokarev, comrade.",
24
+ "... Looks like you get to live another day... or 5 second.",
25
+ "... Bad primer."
26
+ ]
27
+
28
+ def initialize(*args)
29
+ super
30
+ @games = []
31
+ end
32
+
33
+ match /rr(?: (.+))?/, method: :russian
34
+
35
+ def russian(m, nick)
36
+ #return m.reply "I am sorry comrade, but I do not have pistol on me." unless check_user(m.channel, @bot)
37
+ return m.user.notice "Sorry comrade, but there is already game going on." if @games.include?(m.channel.name)
38
+
39
+ # player setup
40
+ player = User(nick) || m.user
41
+ player = m.user if player == @bot
42
+ # be nice, don't force the game on the starter unless the user actually exists in the channel.
43
+ return m.reply "I am terribly sorry %s, but I don't know %s." % [m.user.nick, player.nick] unless m.channel.users.include?(player)
44
+
45
+ # start game
46
+ @games << m.channel.name
47
+
48
+ turns, round_location = Array.new(2) { |i| Random.new.rand(1..6) }
49
+ m.channel.action "starts a %d-turn game of Russian Roulette with %s." % [turns, player.nick]
50
+
51
+ phrases = PHRASES.dup.shuffle
52
+
53
+ sleep 5
54
+
55
+ turns.times do |chamber|
56
+ return end_game(m.channel, true) unless m.channel.users.include?(player)
57
+ if round_location == chamber.succ
58
+ m.reply "*click*"
59
+ sleep 5
60
+ m.channel.kick(player, "*BLAM*")
61
+ m.reply "*BLAM*"
62
+ m.channel.action "watches %s's brain splatter across the wall." % player.nick
63
+ break
64
+ else
65
+ phrase = phrases.pop
66
+ m.reply "*click* %s" % phrase
67
+ end
68
+ sleep 5
69
+ end
70
+
71
+ m.reply "Looks like you get to live another day." if turns < round_location
72
+ sleep 1 if turns < round_location
73
+ end_game(m.channel)
74
+ end
75
+
76
+ private
77
+
78
+ def end_game(channel, premature=false)
79
+ @games.delete channel.name
80
+ channel.msg "Oh vell, it vas fun vhile it lasted." if premature
81
+ sleep 1
82
+ channel.action "holsters the pistol."
83
+ end
84
+ end
85
+ end
86
+
87
+
88
+ # AutoLoad
89
+ Bot.config.plugins.plugins.push Plugins::RussianRoulette
90
+
@@ -0,0 +1,77 @@
1
+ require 'action_view'
2
+ module Plugins
3
+ class Seen
4
+ class SeenStruct < Struct.new(:who, :where, :what, :time)
5
+ include ActionView::Helpers::DateHelper
6
+ def to_s
7
+ # "[#{time.asctime}] #{who} was seen in #{where} last saying #{what}"
8
+ time_ago = time_ago_in_words(Time.at(time))
9
+ "[ \x1F#{where.to_s.upcase}\x0F ] \x0304#{who}\x0F: \"\x0303#{what[0..300]}\x0F\" \x02#{time_ago}\x0F ago"
10
+ end
11
+ end
12
+
13
+ include Cinch::Plugin
14
+ include Cinch::Helpers
15
+
16
+ enable_acl(:nobody)
17
+
18
+ listen_to :channel
19
+ match /seen (.+)/
20
+ match /sync/, method: :sync
21
+
22
+ def initialize(*args)
23
+ super
24
+ @users = load_seen
25
+ end
26
+
27
+ def finalize
28
+ save_seen()
29
+ end
30
+
31
+ def listen(m)
32
+ @users[m.user.nick] = SeenStruct.new(m.user, m.channel, m.message, Time.now)
33
+ end
34
+
35
+ def execute(m, nick)
36
+ nick.rstrip!
37
+ if nick == @bot.nick
38
+ m.reply 'You are a Stupid human!'
39
+ elsif nick == m.user.nick
40
+ m.reply "Unfortunately, I see an idiot by the name of #{m.user.nick}"
41
+ elsif @users.key?(nick)
42
+ m.reply @users[nick].to_s
43
+ else
44
+ m.reply "I haven't seen #{nick}"
45
+ end
46
+ end
47
+
48
+ def sync(m)
49
+ save_seen()
50
+ end
51
+
52
+ def save_seen
53
+ File.open(File.join(Dir.home, '.zeta', 'cache', 'seen.rb'), 'w+') do |file|
54
+ Marshal.dump(@users, file)
55
+ end
56
+
57
+ end
58
+
59
+ def load_seen
60
+ if File.exists?(File.join(Dir.home, '.zeta', 'cache', 'seen.rb'))
61
+ File.open(File.join(Dir.home, '.zeta', 'cache', 'seen.rb')) do |file|
62
+ return Marshal.load(file)
63
+ end
64
+ else
65
+ return Hash.new
66
+ end
67
+ end
68
+
69
+ def clear_seen
70
+ @users = {}
71
+ File.delete(File.join(Dir.home, '.zeta', 'cache', 'seen.rb'))
72
+ end
73
+ end
74
+ end
75
+
76
+ # AutoLoad
77
+ Bot.config.plugins.plugins.push Plugins::Seen
@@ -0,0 +1,183 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/time'
4
+ require 'active_support/core_ext/string'
5
+ require 'active_support/core_ext/object/blank'
6
+ require 'chronic_duration'
7
+ require 'date'
8
+
9
+
10
+ module Plugins
11
+ class Silly
12
+ include Cinch::Plugin
13
+ include Cinch::Helpers
14
+ enable_acl
15
+
16
+ set(
17
+ plugin_name: "Silly",
18
+ help: "You know, silly stuff.",
19
+ )
20
+
21
+ _seconds_in_a_day = 86400
22
+
23
+ attr_reader :pokers
24
+
25
+ def initialize *args
26
+ super
27
+ @pokers = {}
28
+ end
29
+
30
+ match /^pokes (.+)$/, react_on: :action, method: :listen_poke, use_prefix: false
31
+
32
+ def listen_poke(m, thebot)
33
+
34
+ if User(thebot) == @bot
35
+ @pokers[m.user] = 0 if !@pokers.include?(m.user)
36
+ @pokers[m.user] += 1
37
+ case @pokers[m.user]
38
+ when 1..3
39
+ m.reply "Do NOT poke the bot!"
40
+ when 4
41
+ m.reply "I said, do NOT poke the bot!"
42
+ when 5
43
+ msg = ["WHAT ARE YOU, AN IDIOT? I SAID DO NOT POKE ME!!", "THIS! IS! SPARTA!!"].sample
44
+ m.channel.kick m.user, ["WHAT ARE YOU, AN IDIOT? I SAID DO NOT POKE ME!!", "THIS! IS! SPARTA!!"].sample
45
+ @pokers.delete(m.user)
46
+ end
47
+ end
48
+ end
49
+
50
+ match /\b(dumb|stupid)\b.+\bbots*\b/i, method: :execute_botinsult, use_prefix: false
51
+
52
+ def execute_botinsult(m)
53
+
54
+ m.reply ["Stupid human!", "Dumb human!", "Stupid meatbag.", "Silly human, your insults cannot harm me!", "get rekt", "u fkn w0t m8"].sample
55
+ end
56
+
57
+ def tzparser(tz)
58
+ prefix = (tz[0] !~ /(\+|-)/ ? "+" : "")
59
+ suffix = (tz =~ /^(?:\+|-)?(\d{1,2})$/ ? ":00" : "")
60
+ regexp = /^(\+|-)?(\d{1,2})(?::(\d{1,2}))?$/
61
+ if tz =~ regexp
62
+ prefix + tz.gsub(regexp) { |match| (!!$1 ? $1 : "") + $2.rjust(2, "0") + (!!$3 ? ":"+$3.rjust(2, "0") : "") } + suffix
63
+ else
64
+ raise ArgumentError, "A valid timezone was not supplied."
65
+ end
66
+ end
67
+
68
+ match "halloween", method: :halloween
69
+ match "halloweve", method: :halloween
70
+ match /halloween (\S+)/, method: :halloween
71
+
72
+ def halloween(m, tz = nil)
73
+ tz ||= "-00:00"
74
+ tz = tzparser(tz)
75
+ begin
76
+ today = Time.now.localtime(tz)
77
+ hw = Time.new(today.year, 10, 31, 0, 0, 0, tz)
78
+ hw = hw.next_year if hw.to_date.past?
79
+ message = if hw.to_date == today.to_date
80
+ "THIS IS HALLOWEEN!"
81
+ else
82
+ "There's #{ChronicDuration.output(hw.to_i - today.to_i, format: :long)} until Hallow's Eve!"
83
+ end
84
+ rescue ArgumentError => ae
85
+ message = ae.message
86
+ ensure
87
+ m.reply message, true
88
+ end
89
+ end
90
+
91
+ match "xmas", method: :xmas
92
+ match /xmas (\S+)/, method: :xmas
93
+
94
+ def xmas(m, tz = nil)
95
+ tz ||= "-00:00"
96
+ tz = tzparser(tz)
97
+ begin
98
+ today = Time.now.localtime(tz)
99
+ xmas = Time.new(today.year, 12, 25, 0, 0, 0, tz)
100
+ xmas = xmas.next_year if xmas.to_date.past?
101
+ message = if xmas.to_date == today.to_date
102
+ "Merry Christmas!"
103
+ else
104
+ "There's #{ChronicDuration.output(xmas.to_i - today.to_i, format: :long)} until Christmas!"
105
+ end
106
+ rescue ArgumentError => ae
107
+ message = ae.message
108
+ ensure
109
+ m.reply message, true
110
+ end
111
+ end
112
+
113
+ match "newyear", method: :newyear
114
+ match /newyear (\S+)/, method: :newyear
115
+
116
+ def newyear(m, tz = nil)
117
+ tz ||= "-00:00"
118
+ tz = tzparser(tz)
119
+ begin
120
+ today = Time.now.localtime(tz)
121
+ nyear = Time.new(today.year.succ, 1, 1, 0, 0, 0, tz)
122
+ #nyear = nyear.next_year if nyear.to_date.past?
123
+ message = if nyear.to_date == today.to_date
124
+ "Happy New Year #{today.year}!"
125
+ else
126
+ "There's #{ChronicDuration.output(nyear.to_i - today.to_i, format: :long)} until #{nyear.year}!"
127
+ end
128
+ rescue ArgumentError => ae
129
+ message = ae.message
130
+ ensure
131
+ m.reply message, true
132
+ end
133
+ end
134
+
135
+ match "tz", method: :tz
136
+ match /tz (\S+)/, method: :tz
137
+
138
+ def tz(m, tz = nil)
139
+ tz ||= "-00:00"
140
+ tz = tzparser(tz)
141
+ begin
142
+ today = Time.now.localtime(tz)
143
+ message = today.to_s
144
+ rescue ArgumentError => ae
145
+ message = ae.message
146
+ ensure
147
+ m.reply message, true
148
+ end
149
+ end
150
+
151
+ match "mayan", method: :mayan
152
+
153
+ def mayan(m)
154
+ msd = (Date.today.jd - Date.new(1, 1, 1).jd) + 1137142
155
+ lc = {
156
+ baktun: (msd - (msd % 144000)) / 144000,
157
+ katun: ((msd - (msd % 7200)) / 7200) % 20,
158
+ tun: ((msd - (msd % 360)) / 360) % 20,
159
+ uinal: ((msd - (msd % 20)) / 20) % 18,
160
+ kin: (msd % 20)
161
+ }
162
+
163
+ m.reply '%<baktun>s.%<katun>s.%<tun>s.%<uinal>s.%<kin>s' % lc
164
+ end
165
+
166
+ match /heavymetalize (.+)/, method: :heavymetalize
167
+
168
+ def heavymetalize(m, s)
169
+ m.reply s.tr('AEIOUaeiouyYWwXx', 'ÄËÏÖÜäëïöüÿŸẄẅẌẍ')
170
+ end
171
+
172
+ match /\bfeature\b.+\brequest\b/i, method: :execute_userproblem, use_prefix: false
173
+
174
+ def execute_userproblem(m)
175
+ m.reply ["user error.", "working as intended", "Status: WONTFIX", "PEBKAC issue", "ID:10T Error"].sample
176
+ end
177
+
178
+ end
179
+ end
180
+
181
+
182
+ # AutoLoad
183
+ Bot.config.plugins.plugins.push Plugins::Silly
@@ -0,0 +1,146 @@
1
+ # -*- coding: utf-8 -*-
2
+ # == Author
3
+ # Marvin Gülker (Quintus)
4
+ #
5
+ # == Modification author
6
+ # Liothen
7
+ #
8
+ # == License
9
+ # A named-pipe plugin for Cinch.
10
+ # Copyright © 2012 Marvin Gülker
11
+ #
12
+ # This program is free software: you can redistribute it and/or modify
13
+ # it under the terms of the GNU Lesser General Public License as published by
14
+ # the Free Software Foundation, either version 3 of the License, or
15
+ # (at your option) any later version.
16
+ #
17
+ # This program is distributed in the hope that it will be useful,
18
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ # GNU Lesser General Public License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Lesser General Public License
23
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
+
25
+ # Plugin for inspecting links pasted into channels.
26
+ require 'video_info'
27
+ require 'mechanize'
28
+ require 'action_view'
29
+
30
+ module Plugins
31
+ class Snooper
32
+ include Cinch::Plugin
33
+ include Cinch::Helpers
34
+ include ActionView::Helpers::DateHelper
35
+
36
+ enable_acl(:nobody)
37
+
38
+ # Default list of URL regexps to ignore.
39
+ # DEFAULT_BLACKLIST = [/\.png$/i, /\.jpe?g$/i, /\.bmp$/i, /\.gif$/i, /\.pdf$/i].freeze
40
+
41
+ set :help, <<-HELP
42
+ http[s]://...
43
+ I’ll fire a GET request at any link I encounter, parse the HTML
44
+ meta tags, and paste the result back into the channel.
45
+ HELP
46
+
47
+ match %r{\b((https?:\/\/)?(([0-9a-zA-Z_!~*'().&=+$%-]+:)?[0-9a-zA-Z_!~*'().&=+$%-]+\@)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+\.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\.[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/[0-9a-zA-Z_!~*'().;?:\@&=+$,%#-]+)*\/?))}i,
48
+ use_prefix: false,
49
+ react_on: :channel
50
+
51
+ def execute(msg, url)
52
+ url = "http://#{url}" unless url=~/^https?:\/\//
53
+ url = URI.encode(url)
54
+
55
+ # Ignore items on blacklist
56
+ # blacklist = DEFAULT_BLACKLIST.dup
57
+ # blacklist.concat(config[:blacklist]) if config[:blacklist]
58
+ # return if blacklist.any?{|entry| url =~ entry}
59
+
60
+ # Log
61
+ # debug "URL matched: #{url}"
62
+
63
+ # Parse URI
64
+ p = URI(url)
65
+
66
+ # API key lookup
67
+ VideoInfo.provider_api_keys = { youtube: Config.secrets[:google] }
68
+
69
+ # Parse out specific websites
70
+ if p.host == 'youtube.com' || p.host == 'www.youtube.com' || p.host == 'youtu.be'
71
+ match_youtube(msg, url)
72
+ elsif p.host == 'i.imgur.com' || p.host == 'imgur.com'
73
+ match_imgur(msg, url)
74
+ else
75
+ match_other(msg,url)
76
+ end
77
+
78
+ rescue => e
79
+ error "#{e.class.name}: #{e.message}"
80
+ error "[404] #{msg.user} - #{url}"
81
+ end
82
+
83
+ private
84
+ def match_youtube(msg, url)
85
+ if Config.secrets[:google]
86
+ video = VideoInfo.new(url)
87
+ msg.reply "#{Format(:red, 'YouTube ')}∴ #{video.title} ( #{Format(:green, Time.at(video.duration).strftime("%H:%M:%S"))} )"
88
+ else
89
+ match_other(msg, url)
90
+ end
91
+
92
+ end
93
+
94
+ def match_github(msg, url)
95
+ # TODO parse github url
96
+ end
97
+
98
+ def match_imgur(msg, url)
99
+ id = url.to_s.match(%r{(?:https?://i?\.?imgur.com/)(?:.*\/)?([A-Za-z0-9]+)(?:\.jpg|png|gif|gifv)?}i)
100
+ return match_other(msg, url) unless id
101
+
102
+ # Query Data
103
+ data = JSON.parse(
104
+ RestClient.get("https://api.imgur.com/3/image/#{id[1]}", { Authorization: "Client-ID #{Config.secrets[:imgur_id]}" })
105
+ )
106
+ return 'Unable to query imgur' unless defined?(data)
107
+ i = Hashie::Mash.new(data)
108
+
109
+ # SET Not Safe For Work
110
+ if i.data.nsfw
111
+ nsf = "[#{Format(:red, 'NSFW')}]"
112
+ else
113
+ nsf = "[#{Format(:green, 'SAFE')}]"
114
+ end
115
+
116
+ # Trigger reply message
117
+ msg.reply("#{Format(:purple, 'IMGUR')} #{nsf} ∴ [#{Format(:yellow, i.data.type)}] #{i.data.width}x#{i.data.height} "\
118
+ "∴ Views: #{ i.data.views.to_s} ∴ #{i.data.title ? i.data.title[0..100] : 'No Title'} "\
119
+ "∴ Posted #{time_ago_in_words(Time.at(i.data.datetime))} ago")
120
+ end
121
+
122
+ def match_other(msg,url)
123
+ begin
124
+ html = Mechanize.start { |m| Nokogiri::HTML(m.get(url).content, nil, 'utf-8') }
125
+ if node = html.at_xpath("html/head/title")
126
+ msg.reply("‡ #{node.text.lstrip.gsub(/\r|\n|\n\r/, ' ')[0..300]}")
127
+ end
128
+
129
+ if node = html.at_xpath('html/head/meta[@name="description"]')
130
+ msg.reply("» #{node[:content].lines.first(3).join.gsub(/\r|\n|\n\r/, ' ')[0..300]}")
131
+ end
132
+
133
+ info "[200] #{msg.user} - #{url}"
134
+ rescue => e
135
+ error e
136
+ error "[404] #{msg.user} - #{url}"
137
+ end
138
+ end
139
+
140
+ end
141
+ end
142
+
143
+
144
+ # AutoLoad
145
+ Bot.config.plugins.plugins.push Plugins::Snooper
146
+