zetabot 0.0.1

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.
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
File without changes
@@ -0,0 +1,73 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'json'
4
+
5
+ module Plugins
6
+ class Gif
7
+ include Cinch::Plugin
8
+ include Cinch::Helpers
9
+ enable_acl
10
+
11
+ # Author: blahed (https://github.com/blahed/gifbot)
12
+ self.plugin_name = 'GIF'
13
+ self.help = '?randomgif | ?rgif | ?gifme <query>'
14
+
15
+ def initialize(*args)
16
+ super
17
+ @imgurray = []
18
+ @last_update = Time
19
+ end
20
+
21
+ match 'randomgif', method: :imgif
22
+ match 'rgif', method: :imgif
23
+ match 'imgif', method: :imgif
24
+ def imgif(msg)
25
+ msg.reply "IMGUR↦ #{imgur}"
26
+ end
27
+
28
+ match /gifme (.+)/, method: :gifme
29
+ def gifme(msg,query)
30
+ msg.reply "GB↦ #{search(query)}"
31
+ end
32
+
33
+ private
34
+
35
+ def search(query)
36
+ url = URI.encode "http://www.gifbin.com/search/#{query}/"
37
+ doc = Nokogiri::HTML( open(url) )
38
+ e = doc.css('.thumbs li').length
39
+ return "No Results Found" if e == 0
40
+ result = doc.css('.thumbs li')[rand(e)].css('a img').attribute('src').text.gsub(/tn_/, '')
41
+ "http://www.gifbin.com#{result}"
42
+ end
43
+
44
+ def gifbin
45
+ url = URI.encode 'http://www.gifbin.com/random'
46
+ doc = Nokogiri.HTML(open url)
47
+ doc.css('div#gifcontainer a img').attribute('src').text
48
+ end
49
+
50
+ def imgur
51
+ # Cache results for 1 hour
52
+ if @imgurray.empty? || @last_update >= (Time.now + 3600)
53
+ url = URI.encode('http://reddit.com/r/gifs.json')
54
+ doc = JSON.load(open(url))
55
+
56
+ doc['data']['children'].each_with_index do |post, index|
57
+ if doc['data']['children'][index]['data']['url'].to_s =~ /imgur/
58
+ @imgurray << doc['data']['children'][index]['data']['url'].to_s
59
+ end
60
+ end
61
+ @last_update = Time.now
62
+ @imgurray.sample
63
+ else
64
+ @imgurray.sample
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+ # AutoLoad
73
+ Bot.config.plugins.plugins.push Plugins::Gif
@@ -0,0 +1,32 @@
1
+ module Plugins
2
+ class BotHelp
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+ enable_acl
6
+
7
+ set(
8
+ plugin_name: "BotHelp",
9
+ help: "Need help?.\nUsage: `?help`\nUsage: `?help [plugin]` `?help plugins`",
10
+ )
11
+ match /help (.+)$/i, method: :execute_help
12
+
13
+ def execute_help(m, name)
14
+ list = {}
15
+ @bot.plugins.each { |p| list[p.class.plugin_name.downcase] = {name: p.class.plugin_name, help: p.class.help} };
16
+ return m.user.notice("Help for \"#{name}\" could not be found.") unless list.has_key?(name.downcase)
17
+ m.user.notice("Help for #{Format(:bold, list[name.downcase][:name])}:\n#{list[name.downcase][:help]}")
18
+ end
19
+
20
+ match 'help', method: :execute_list
21
+ def execute_list(m)
22
+
23
+ list = []
24
+ @bot.plugins.each {|p| list << p.class.plugin_name };
25
+ m.user.notice("All #{list.size} currently loaded plugins for #{@bot.nick}:\n#{list.to_sentence}.\nTo view help for a plugin, use `!help <plugin name>`.")
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ # AutoLoad
32
+ Bot.config.plugins.plugins.push Plugins::BotHelp
@@ -0,0 +1,34 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'ostruct'
4
+ require 'discourse_api'
5
+ require 'action_view'
6
+
7
+ module Plugins
8
+ class Libsecure
9
+ include Cinch::Plugin
10
+ include Cinch::Helpers
11
+ include ActionView::Helpers::DateHelper
12
+
13
+ enable_acl(:nobody)
14
+
15
+ self.plugin_name = 'DarkScience #libsecure'
16
+ self.help = '?latest'
17
+
18
+ match 'latest', method: :fetch_latest
19
+
20
+ def fetch_latest(m)
21
+ return unless m.channel == '#libsecure' || m.channel == '#bots'
22
+
23
+ client = DiscourseApi::Client.new('https://libsecure.so', Config.secrets[:libsecure], Config.secrets[:libsecure_user] )
24
+ parser = client.latest_topics.sort_by { |hash| hash['last_posted_at'] }
25
+ data = parser.last
26
+
27
+ m.reply "Latest → #{data['title']} -- https://libsecure.so/t/#{data['id']}"
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ # AutoLoad
34
+ Bot.config.plugins.plugins.push Plugins::Libsecure
@@ -0,0 +1,124 @@
1
+ # coding: utf-8
2
+ require 'yaml'
3
+
4
+ module Plugins
5
+ class Macros
6
+ include Cinch::Plugin
7
+ include Cinch::Helpers
8
+
9
+ enable_acl(:nobody, false)
10
+
11
+ attr_reader :macros
12
+
13
+ set plugin_name: "Macros", help: "Macro's are prefixed by a <dot> example .dnf",
14
+ react_on: :channel
15
+
16
+ def initialize *args
17
+ super
18
+ # @macros = YAML::load_file($root_path + '/locales/macros.yml')
19
+ @macros = load_locale 'macros'
20
+ end
21
+
22
+ match /reload/, method: :execute_reloadmacros, react_on: :private
23
+ def execute_reloadmacros m
24
+ return unless check_user(m, :admin)
25
+ # return unless check_channel(m)
26
+ begin
27
+ # @macros = YAML::load_file($root_path + '/locales/macros.yml')
28
+ @macros = load_locale 'macros'
29
+ m.user.notice "Macros have been reloaded."
30
+ rescue
31
+ m.user.notice "Reloading macros has failed: #{$!}"
32
+ end
33
+ end
34
+
35
+ match /m (\w+)(?: (.+))?/, method: :execute_macro, group: :macro
36
+ def execute_macro m, macro, arguments
37
+ return unless @macros.has_key?(macro)
38
+ parse(arguments.to_s.rstrip, @macros[macro], m.channel, m.user)
39
+
40
+
41
+ # Guide to writing macros:
42
+ # - A macro can be a string, hash, or array
43
+ # - They can be embedded within each other (as lines, etc.)
44
+ # To have options for a macro (either globally or within embedded macros:)
45
+ # => macroname:
46
+ # => type: (string) ['random'] (optional)
47
+ # => sent_as: (string) ['reply','action'] (optional)
48
+ # => sleep: (numeric) a number that represents how many seconds the bot will wait for each line
49
+ # => lines: (array, string, hash) an object that represents the individual lines.
50
+
51
+ # Guide to writing macros v3 templates:
52
+ # transform/(default text)[template]
53
+ # transform/ (optional):
54
+ # cap (all uppercase)
55
+ # lc (all lowercase)
56
+ # (default text) (optional):
57
+ # Can be anything that you want. May want to watch usage of brackets &c.
58
+ # [template] (required):
59
+ # Can be one of these tags:
60
+ # * in (input/argument, will default to the default text if available, otherwise it will choose a random nick.)
61
+ # * channel (the current channel that the command is run in.)
62
+ # * bot (The bot's nick)
63
+ # * self (the originating user's nick)
64
+ end
65
+
66
+ private
67
+
68
+ # @param [String,NilClass] input The arguments for the command.
69
+ # @param [String,Hash,Array] macro The macro object.
70
+ # @param [Channel] channel The target channel.
71
+ # @param [Users] user The user that activated the macro.
72
+ # @param [Hash] params The (optional) parameters for controlling the macro as set in the external resource.
73
+ # @option params [String,NilClass] 'type' The type of output. Can be either nil, or "random"
74
+ # @option params [String] 'sent_as' The method of sending the line. Can be either 'reply' or 'action'
75
+ # @option params [Numeric,NilClass] 'sleep' How long does the bot wait to send the line?
76
+ def parse(input, macro, channel, user, params={})
77
+ params = { 'type' => nil, 'sent_as' => 'reply', 'sleep' => nil }.merge params
78
+
79
+ if macro.respond_to? :has_key?
80
+ lines = macro['lines']
81
+ params = params.merge macro.reject {|k,_| k.eql? 'lines' }
82
+ lines = lines.sample if params['type'].eql?('random') && lines.respond_to?(:each)
83
+ parse(input, lines, channel, user, params)
84
+ elsif macro.respond_to? :each
85
+ macro.each {|line| parse(input, line, channel, user, params) }
86
+ else
87
+ sleep params['sleep'] if params['sleep']
88
+ case params['sent_as']
89
+ when 'action' then channel.action replace_tokens(input, macro.to_s, channel, user)
90
+ else
91
+ channel.send replace_tokens(input, macro.to_s, channel, user)
92
+ end
93
+ end
94
+ end
95
+
96
+ # @see #parse (sans params)
97
+ def replace_tokens(input, macro, channel, user)
98
+ tokens = macro.scan(/((?:(\w+)\/)?(?:\((.+?)\))?(?:\[(\w+)\]))/)
99
+ tokens.each_with_object(macro.dup) {|(token,transform,default,template), memo|
100
+ result = case template
101
+ when 'in' then input || default || channel.users.keys.sample.nick
102
+ when 'bot' then @bot.nick
103
+ when 'channel' then channel.name
104
+ when 'self' then user.nick
105
+ else token
106
+ end
107
+
108
+ result = case transform
109
+ when 'cap' then result.upcase
110
+ when 'lc' then result.downcase
111
+ else result
112
+ end
113
+
114
+ memo.sub!(token, result)
115
+ }
116
+ end
117
+
118
+
119
+ end
120
+ end
121
+
122
+
123
+ # AutoLoad
124
+ Bot.config.plugins.plugins.push Plugins::Macros
@@ -0,0 +1,67 @@
1
+ module Plugins
2
+ class Movie
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+
6
+ enable_acl
7
+
8
+ set(
9
+ plugin_name: 'Movie',
10
+ help: 'Movie Plots \nUsage: `?movie <name of movie>`;',
11
+ react_on: :channel
12
+ )
13
+
14
+ match /movie (.*)/, method: :find_movie
15
+ def find_movie(m, movie)
16
+ data = query_movie(movie)
17
+ if data && data.response == 'True'
18
+ m.reply "Movie ⊥ #{data.title} (#{data.year}) <#{data.rated}> #{data.plot.to_s.strip[0..800]} [www.imdb.com/title/#{data.imdbid}/]"
19
+ elsif data && data.response == 'False'
20
+ m.reply data.error
21
+ else
22
+ m.reply 'Unable to find movie!'
23
+ end
24
+ end
25
+
26
+ private
27
+ def query_movie(m)
28
+ year = m[/:\d+/].gsub(/:/, '') if m[/:\d+/]
29
+ movie = URI.encode(m.gsub(/:\d+/, ''))
30
+ data = JSON.parse(
31
+ # RestClient.get("http://www.omdbapi.com/?t=#{movie}&y=#{year}")
32
+ open("http://www.omdbapi.com/?t=#{movie}&y=#{year}").read
33
+ )
34
+ OpenStruct.new(
35
+ title: data['Title'],
36
+ year: data['Year'],
37
+ rated: data['Rated'],
38
+ released: data['Released'],
39
+ runtime: data['Runtime'],
40
+ genre: data['Genre'],
41
+ director: data['Director'],
42
+ writer: data['Writer'],
43
+ actors: data['Actors'],
44
+ plot: data['Plot'],
45
+ language: data['Language'],
46
+ country: data['Country'],
47
+ awards: data['Awards'],
48
+ poster: data['Poster'],
49
+ metascore: data['Metascore'],
50
+ imdbrating: data['imdbRating'],
51
+ imdbvotes: data['imdbVotes'],
52
+ imdbid: data['imdbID'],
53
+ type: data['Type'],
54
+ response: data['Response'],
55
+ error: data['Error']
56
+ )
57
+ rescue
58
+ nil
59
+ end
60
+
61
+
62
+ end
63
+ end
64
+
65
+
66
+ # AutoLoad
67
+ Bot.config.plugins.plugins.push Plugins::Movie
@@ -0,0 +1,69 @@
1
+ require 'faraday'
2
+ require 'open-uri'
3
+ require 'action_view'
4
+ require 'pdf-reader'
5
+ require 'humanize-bytes'
6
+
7
+ module Plugins
8
+ class PDFinfo
9
+ include Cinch::Plugin
10
+ include Cinch::Helpers
11
+ include ActionView::Helpers::DateHelper
12
+
13
+ enable_acl(:nobody, false)
14
+
15
+ self.plugin_name = 'PDF Information'
16
+ self.help = 'This plugin will check a url for a pdf link and fetch metadata from it'
17
+
18
+
19
+ # Default list of URL regexps to ignore.
20
+ DEFAULT_ALLOWED = [/\.pdf$/i].freeze
21
+ FILE_SIZE_LIMIT = 4000000
22
+
23
+
24
+ match %r{(https?://.*?)(?:\s|$|,|\.\s|\.$)}, :use_prefix => false
25
+
26
+ def execute(msg, url)
27
+
28
+ allowedlist = DEFAULT_ALLOWED.dup
29
+ allowedlist.concat(config[:blacklist]) if config[:blacklist]
30
+
31
+ return unless allowedlist.any? { |entry| url =~ entry }
32
+ debug "URL matched: #{url}"
33
+
34
+ # Grab header and check filesize
35
+ # one line to make request
36
+ head = Faraday.head url
37
+
38
+ # example with headers
39
+ file_size = head.headers['Content-Length']
40
+ humanize_size = Humanize::Byte.new(file_size.to_i).to_k.to_s.to_i.round(2)
41
+ if file_size.to_i > FILE_SIZE_LIMIT
42
+ return msg.reply("PDF → Unable to parse. file too big #{humanize_size}kb")
43
+ end
44
+
45
+
46
+ # Get file and parse metadata
47
+ open(url, "rb") do |io|
48
+ reader = PDF::Reader.new(io)
49
+ creator = reader.info[:Creator] || 'Anon'
50
+ producer = reader.info[:Producer] || 'Anon'
51
+ creation = reader.info[:CreationDate] || 'now'
52
+ modification = reader.info[:ModDate] || 'now'
53
+ title = reader.info[:Title] || nil
54
+ display = title ? title : "Title: None <> Creator: #{creator} <> Producer: #{producer} <> Creation: #{creation}"
55
+ msg.reply "PDF (#{humanize_size}kb) → #{display}"
56
+ end
57
+
58
+
59
+ rescue => e
60
+ error "#{e.class.name}: #{e.message}"
61
+ end
62
+
63
+
64
+ end
65
+
66
+ end
67
+
68
+ # AutoLoad
69
+ Bot.config.plugins.plugins.push Plugins::PDFinfo
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class String # moved from lib\obj_ext\string.rb
4
+ def irc_colorize
5
+ self.gsub(/!\[(.*?)\]/) { $1.tr('boruic', 2.chr + 15.chr + 18.chr + 31.chr + 29.chr + 3.chr) }
6
+ #Note to self, tr and gsub is your friend!
7
+ #Thanks to j416 on #ruby@freenode!
8
+ end
9
+ end
10
+
11
+
12
+ module Plugins
13
+ class Rainbow
14
+ include Cinch::Plugin
15
+ include Cinch::Helpers
16
+ enable_acl
17
+
18
+ set plugin_name: "Rainbow", help: "Rainbowificates your text.\nUsage: `?rainbow [text]`.\nUsage: `?eyerape [text]`.", suffix: /$/
19
+
20
+ def rainbowification(s)
21
+ s.gsub(/\x03([0-9]{2}(,[0-9]{2})?)?/, "") # Because total function abuse.
22
+ colour = %w{04 07 08 09 10 06 13}
23
+ i = Random.new.rand(0..colour.size-1);
24
+ new_string = ""
25
+ s.each_char { |c|
26
+ new_string << "\x03#{colour[i]}#{c}";
27
+ i = i < colour.size-1 ? i.next : 0;
28
+ }
29
+ new_string
30
+ end
31
+
32
+ def eyerapeification(s)
33
+ sd = s.dup
34
+ sd.gsub(/\x03([0-9]{2}(,[0-9]{2})?)?/, "") # Because total function abuse.
35
+ colour = %w{04 07 08 09 10 06 13}
36
+ offset = Random.new.rand(0..colour.size-1)
37
+ sd = "\x02" + sd.upcase.split(" ").map { |c|
38
+ offset = (offset < colour.size-1 ? offset.next : 0)
39
+ "\x03#{colour[offset]},#{colour[offset-4]}#{c.each_char.each_with_index.map { |char, index| index % 2 == 0 ? char : char.downcase }.join}"
40
+ }.join(" ")
41
+ #sd
42
+ end
43
+
44
+ match /rainbow (.+)/, method: :execute_rainbow
45
+
46
+ def execute_rainbow(m, string)
47
+ m.reply(rainbowification(string), false)
48
+ end
49
+
50
+
51
+
52
+ match /eyerape (.+)/, method: :execute_eyerape
53
+
54
+ def execute_eyerape(m, string)
55
+ m.reply(eyerapeification(string), false)
56
+ end
57
+
58
+
59
+ end
60
+ end
61
+
62
+ # AutoLoad
63
+ Bot.config.plugins.plugins.push Plugins::Rainbow
64
+
65
+