twittbot 0.0.1 → 0.1.0
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.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/lib/twittbot/bot.rb +66 -16
- data/lib/twittbot/botpart.rb +36 -3
- data/lib/twittbot/cli.rb +14 -0
- data/lib/twittbot/defaults.rb +4 -2
- data/lib/twittbot/gem_ext/twitter.rb +2 -0
- data/lib/twittbot/gem_ext/twitter/direct_message.rb +13 -0
- data/lib/twittbot/gem_ext/twitter/tweet.rb +1 -1
- data/lib/twittbot/gem_ext/twitter/user.rb +9 -0
- data/lib/twittbot/generators/templates/basic_dm/basic_dm.rb +51 -0
- data/lib/twittbot/generators/templates/random_tweet/random_tweet.rb +16 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1ccc06698d66c5f816c4021a4f629b2bb7a388f
|
4
|
+
data.tar.gz: 809da09ae7ae3724f1c14080eef51dcdefe33c3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23668bb8a4caeb9d7bae00775498ff5fe4dc3a17893b5190a105683af2931cf624d36a2e6d2c989a7a51fe071e42f673ee1dbbaa76d8a843832bf3f0f75a6775
|
7
|
+
data.tar.gz: 8a9aef2318375d165b3af9eeeebfc219664998df13e4581fb3fdf24f836dc472cd8b4b275eb38932138bbb003e6cd2cfebd1973e02d1b757575d42e68ff4d1d5
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Twittbot
|
1
|
+
# Twittbot [](http://badge.fury.io/rb/twittbot) [](http://inch-ci.org/github/nilsding/twittbot)
|
2
2
|
|
3
3
|
Twittbot is the next generation of my old Twitter bot, `twittbot-nd`.
|
4
4
|
|
@@ -19,6 +19,10 @@ Authorize with Twitter:
|
|
19
19
|
|
20
20
|
$ twittbot auth
|
21
21
|
|
22
|
+
Add yourself as a botadmin:
|
23
|
+
|
24
|
+
$ twittbot add-admin nilsding
|
25
|
+
|
22
26
|
Add a template, such as for a simple reply bot:
|
23
27
|
|
24
28
|
$ twittbot generate random-reply
|
data/lib/twittbot/bot.rb
CHANGED
@@ -18,12 +18,21 @@ module Twittbot
|
|
18
18
|
}
|
19
19
|
|
20
20
|
$bot = {
|
21
|
+
botparts: [],
|
21
22
|
callbacks: {},
|
22
|
-
|
23
|
+
commands: {},
|
24
|
+
config: Twittbot::DEFAULT_BOT_CONFIG.merge(
|
25
|
+
YAML.load_file(File.expand_path("./#{Twittbot::CONFIG_FILE_NAME}", @options[:current_dir]))
|
26
|
+
),
|
23
27
|
periodic: []
|
24
28
|
}.merge!(options)
|
25
29
|
|
26
30
|
load_bot_code
|
31
|
+
|
32
|
+
at_exit do
|
33
|
+
save_config
|
34
|
+
$bot[:botparts].each { |b| b.save_config }
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
# Authenticates an account with Twitter.
|
@@ -54,26 +63,12 @@ module Twittbot
|
|
54
63
|
# get the bot's user name (screen_name) and print it to the console
|
55
64
|
$bot[:config][:screen_name] = get_screen_name access_token
|
56
65
|
puts "Hello, #{$bot[:config][:screen_name]}!"
|
57
|
-
|
58
|
-
save_config
|
59
66
|
end
|
60
67
|
|
61
68
|
# Starts the bot.
|
62
69
|
def start
|
63
70
|
check_config
|
64
|
-
|
65
|
-
cfg.consumer_key = $bot[:config][:consumer_key]
|
66
|
-
cfg.consumer_secret = $bot[:config][:consumer_secret]
|
67
|
-
cfg.access_token = $bot[:config][:access_token]
|
68
|
-
cfg.access_token_secret = $bot[:config][:access_token_secret]
|
69
|
-
end
|
70
|
-
|
71
|
-
@streamer ||= Twitter::Streaming::Client.new do |cfg|
|
72
|
-
cfg.consumer_key = $bot[:config][:consumer_key]
|
73
|
-
cfg.consumer_secret = $bot[:config][:consumer_secret]
|
74
|
-
cfg.access_token = $bot[:config][:access_token]
|
75
|
-
cfg.access_token_secret = $bot[:config][:access_token_secret]
|
76
|
-
end
|
71
|
+
init_clients
|
77
72
|
|
78
73
|
@userstream_thread ||= Thread.new do
|
79
74
|
puts "connected to user stream"
|
@@ -103,6 +98,23 @@ module Twittbot
|
|
103
98
|
@periodic_thread.join
|
104
99
|
end
|
105
100
|
|
101
|
+
# @param screen_name [String] the user's screen name
|
102
|
+
# @param action [Symbol] :add or :delete
|
103
|
+
def modify_admin(screen_name, action = :add)
|
104
|
+
init_clients
|
105
|
+
user = $bot[:client].user screen_name
|
106
|
+
case action
|
107
|
+
when :add
|
108
|
+
$bot[:config][:admins] << user.id unless $bot[:config][:admins].include? user.id
|
109
|
+
when :del, :delete
|
110
|
+
$bot[:config][:admins].delete user.id if $bot[:config][:admins].include? user.id
|
111
|
+
else
|
112
|
+
say "Unknown action " + action.to_s, :red
|
113
|
+
end
|
114
|
+
rescue Twitter::Error::NotFound
|
115
|
+
say "User not found.", :red
|
116
|
+
end
|
117
|
+
|
106
118
|
# Loads the bot's actual code which is stored in the bot's +lib+
|
107
119
|
# subdirectory.
|
108
120
|
def load_bot_code
|
@@ -158,6 +170,8 @@ module Twittbot
|
|
158
170
|
pp object
|
159
171
|
do_callbacks object.name, object, opts
|
160
172
|
end
|
173
|
+
when Twitter::DirectMessage
|
174
|
+
do_direct_message object, opts
|
161
175
|
else
|
162
176
|
puts "no handler for #{object.class.to_s}\n -- object data:"
|
163
177
|
require 'pp'
|
@@ -184,6 +198,26 @@ module Twittbot
|
|
184
198
|
end
|
185
199
|
end
|
186
200
|
|
201
|
+
# Processes a direct message.
|
202
|
+
# @param dm [Twitter::DirectMessage] received direct message
|
203
|
+
def do_direct_message(dm, opts = {})
|
204
|
+
return if dm.sender.screen_name == $bot[:config][:screen_name]
|
205
|
+
return do_callbacks(:direct_message, dm, opts) unless dm.text.start_with? $bot[:config][:dm_command_prefix]
|
206
|
+
dm_text = dm.text.sub($bot[:config][:dm_command_prefix], '').strip
|
207
|
+
return if dm_text.empty?
|
208
|
+
|
209
|
+
return unless /(?<command>[A-Za-z0-9]+)(?:\s*)(?<args>.*)/m =~ dm_text
|
210
|
+
command = Regexp.last_match(:command).to_sym
|
211
|
+
args = Regexp.last_match :args
|
212
|
+
|
213
|
+
cmd = $bot[:commands][command]
|
214
|
+
return say_status :dm, "#{dm.sender.screen_name} tried to issue non-existent command :#{command}, ignoring", :cyan if cmd.nil?
|
215
|
+
return say_status :dm, "#{dm.sender.screen_name} tried to issue admin command :#{command}, ignoring", :cyan if cmd[:admin] and !dm.sender.admin?
|
216
|
+
|
217
|
+
say_status :dm, "#{dm.sender.screen_name} issued command :#{command}", :cyan
|
218
|
+
cmd[:block].call(args, dm.sender)
|
219
|
+
end
|
220
|
+
|
187
221
|
# @return [Boolean] whether the bot is already authenticated or not.
|
188
222
|
def already_authed?
|
189
223
|
!($bot[:config][:access_token].empty? or $bot[:config][:access_token_secret].empty?)
|
@@ -191,6 +225,22 @@ module Twittbot
|
|
191
225
|
|
192
226
|
private
|
193
227
|
|
228
|
+
def init_clients
|
229
|
+
$bot[:client] ||= Twitter::REST::Client.new do |cfg|
|
230
|
+
cfg.consumer_key = $bot[:config][:consumer_key]
|
231
|
+
cfg.consumer_secret = $bot[:config][:consumer_secret]
|
232
|
+
cfg.access_token = $bot[:config][:access_token]
|
233
|
+
cfg.access_token_secret = $bot[:config][:access_token_secret]
|
234
|
+
end
|
235
|
+
|
236
|
+
@streamer ||= Twitter::Streaming::Client.new do |cfg|
|
237
|
+
cfg.consumer_key = $bot[:config][:consumer_key]
|
238
|
+
cfg.consumer_secret = $bot[:config][:consumer_secret]
|
239
|
+
cfg.access_token = $bot[:config][:access_token]
|
240
|
+
cfg.access_token_secret = $bot[:config][:access_token_secret]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
194
244
|
def get_screen_name(access_token)
|
195
245
|
oauth_response = access_token.get('/1.1/account/verify_credentials.json?skip_status=true')
|
196
246
|
oauth_response.body.match(/"screen_name"\s*:\s*"(.*?)"/).captures.first
|
data/lib/twittbot/botpart.rb
CHANGED
@@ -5,13 +5,14 @@ module Twittbot
|
|
5
5
|
class BotPart
|
6
6
|
# @param name [Symbol] The name of the botpart. Should be the same as the file name without the extension.
|
7
7
|
def initialize(name, &block)
|
8
|
-
botpart_config_path = File.expand_path("./etc/#{name}.yml")
|
9
|
-
@config = $bot[:config].merge(if File.exist? botpart_config_path
|
10
|
-
YAML.load_file botpart_config_path
|
8
|
+
@botpart_config_path = File.expand_path("./etc/#{name}.yml")
|
9
|
+
@config = $bot[:config].merge(if File.exist? @botpart_config_path
|
10
|
+
YAML.load_file @botpart_config_path
|
11
11
|
else
|
12
12
|
{}
|
13
13
|
end)
|
14
14
|
instance_eval &block
|
15
|
+
$bot[:botparts] << self
|
15
16
|
end
|
16
17
|
|
17
18
|
# Adds a new callback to +name+.
|
@@ -23,6 +24,7 @@ module Twittbot
|
|
23
24
|
# * :retweet
|
24
25
|
# * :favorite
|
25
26
|
# * :friend_list
|
27
|
+
# * :direct_message (i.e. not command DMs, see {cmd} for that)
|
26
28
|
def on(name, *args, &block)
|
27
29
|
$bot[:callbacks][name] ||= {
|
28
30
|
args: args,
|
@@ -66,5 +68,36 @@ module Twittbot
|
|
66
68
|
$bot[:client]
|
67
69
|
end
|
68
70
|
alias bot client
|
71
|
+
|
72
|
+
# Defines a new direct message command.
|
73
|
+
# @param name [Symbol] The name of the command. Can only contain alphanumerical characters.
|
74
|
+
# The recommended maximum length is 4 characters.
|
75
|
+
# @param options [Hash] A customizable set of options.
|
76
|
+
# @option options [Boolean] :admin (true) Require admin status for this command.
|
77
|
+
def cmd(name, options = {}, &block)
|
78
|
+
raise "Command already exists: #{name}" if $bot[:commands].include? name
|
79
|
+
raise "Command name does not contain only alphanumerical characters" unless name.to_s.match /\A[A-Za-z0-9]+\z/
|
80
|
+
|
81
|
+
opts = {
|
82
|
+
admin: true
|
83
|
+
}.merge(options)
|
84
|
+
|
85
|
+
$bot[:commands][name] ||= {
|
86
|
+
admin: opts[:admin],
|
87
|
+
block: block
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
# Saves the botpart's configuration. This is automatically called when
|
92
|
+
# Twittbot exits.
|
93
|
+
def save_config
|
94
|
+
botpart_config = Hash[@config.to_a - $bot[:config].to_a]
|
95
|
+
|
96
|
+
unless botpart_config.empty?
|
97
|
+
File.open @botpart_config_path, 'w' do |f|
|
98
|
+
f.write botpart_config.to_yaml
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
69
102
|
end
|
70
103
|
end
|
data/lib/twittbot/cli.rb
CHANGED
@@ -39,5 +39,19 @@ module Twittbot
|
|
39
39
|
lister = Twittbot::TemplateLister.new options
|
40
40
|
lister.list
|
41
41
|
end
|
42
|
+
|
43
|
+
desc 'add-admin USER_NAME', 'Adds an user to the botadmin list'
|
44
|
+
def add_admin(user_name)
|
45
|
+
require 'twittbot/bot'
|
46
|
+
bot = Twittbot::Bot.new
|
47
|
+
bot.modify_admin(user_name, :add)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'del-admin USER_NAME', 'Removes an user from the botadmin list'
|
51
|
+
def del_admin(user_name)
|
52
|
+
require 'twittbot/bot'
|
53
|
+
bot = Twittbot::Bot.new
|
54
|
+
bot.modify_admin(user_name, :delete)
|
55
|
+
end
|
42
56
|
end
|
43
57
|
end
|
data/lib/twittbot/defaults.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Twittbot
|
2
2
|
# The version of Twittbot.
|
3
|
-
VERSION = "0.0
|
3
|
+
VERSION = "0.1.0"
|
4
4
|
|
5
5
|
CONSUMER_KEY = 'FYRuQcDbPAXAyVjuPZMuw' # :nodoc:
|
6
6
|
CONSUMER_SECRET = 'KiLCYTftPdxNebl5DNcj7Ey2Y8YVZu7hfqiFRYkcg' # :nodoc:
|
@@ -16,6 +16,8 @@ module Twittbot
|
|
16
16
|
consumer_secret: Twittbot::CONSUMER_SECRET,
|
17
17
|
access_token: '',
|
18
18
|
access_token_secret: '',
|
19
|
-
track: []
|
19
|
+
track: [],
|
20
|
+
admins: [],
|
21
|
+
dm_command_prefix: '!'
|
20
22
|
}
|
21
23
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Twitter
|
2
|
+
class DirectMessage
|
3
|
+
# Replies to this direct message.
|
4
|
+
# @param direct_message_text [:String] direct message text
|
5
|
+
def reply(direct_message_text)
|
6
|
+
return if $bot.nil? or $bot[:client].nil?
|
7
|
+
|
8
|
+
$bot[:client].create_direct_message self.sender.id, direct_message_text
|
9
|
+
rescue Twitter::Error => e
|
10
|
+
puts "caught Twitter error while replying via DM: #{e.message}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -16,7 +16,7 @@ module Twitter
|
|
16
16
|
|
17
17
|
$bot[:client].update result, in_reply_to_status_id: self.id
|
18
18
|
rescue Twitter::Error => e
|
19
|
-
puts "caught Twitter error while
|
19
|
+
puts "caught Twitter error while replying: #{e.message}"
|
20
20
|
end
|
21
21
|
|
22
22
|
# Retweets this tweet.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%
|
2
|
+
# This is the config for this botpart.
|
3
|
+
# It is a hash and will be serialized to YAML and saved to 'etc/template_name.yml'.
|
4
|
+
botpart_config = {
|
5
|
+
magic_word: "Supercalifragilisticexpialidocious" # (I'll buy you a beer if you can spell this correctly while drunk)
|
6
|
+
}
|
7
|
+
|
8
|
+
# Display a message after installation template installation
|
9
|
+
post_install_message <<-MSG
|
10
|
+
In order to make some commands work, you need to be a BotAdmin. You can add
|
11
|
+
yourself to the BotAdmin list by starting
|
12
|
+
|
13
|
+
twittbot add-admin your_user_name
|
14
|
+
MSG
|
15
|
+
%>
|
16
|
+
Twittbot::BotPart.new :<%= @template_name %> do
|
17
|
+
# This command gives a BotAdmin the ability to tweet via the bot.
|
18
|
+
#
|
19
|
+
# Example usage (via direct message):
|
20
|
+
# !twet This is a tweet
|
21
|
+
cmd :twet do |args, _user|
|
22
|
+
bot.tweet args
|
23
|
+
end
|
24
|
+
|
25
|
+
# This command gives anyone who is followed by the bot the ability to echo
|
26
|
+
# back their direct message.
|
27
|
+
#
|
28
|
+
# Example usage:
|
29
|
+
# !echo Hello, world!
|
30
|
+
cmd :echo, admin: false do |args, user|
|
31
|
+
bot.dm user, args
|
32
|
+
end
|
33
|
+
|
34
|
+
## Uncomment this if you want to remotely stop the bot.
|
35
|
+
##
|
36
|
+
## Example usage:
|
37
|
+
## !stop Supercalifragilisticexpialidocious
|
38
|
+
#cmd :stop do |args, user|
|
39
|
+
# exit 0 if args.downcase == @config[:magic_word].downcase
|
40
|
+
#end
|
41
|
+
|
42
|
+
# Of course, there's a :direct_message callback too. This applies to
|
43
|
+
# everything that is not a command.
|
44
|
+
on :direct_message do |dm|
|
45
|
+
if dm.sender.admin? # You can check if an user is an admin by using the .admin? method.
|
46
|
+
dm.reply "You're an admin! You can use !twet to tweet nice things."
|
47
|
+
else
|
48
|
+
dm.reply "You're an ordinary user! Try using !echo on me."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -17,4 +17,20 @@ Twittbot::BotPart.new :<%= @template_name %> do
|
|
17
17
|
# ... tweet a random entry of the :tweets list that you configured
|
18
18
|
bot.tweet @config[:tweets].sample
|
19
19
|
end
|
20
|
+
|
21
|
+
## Uncomment the next few lines if you want to add new tweets to the tweet
|
22
|
+
## list on the fly using direct messages.
|
23
|
+
##
|
24
|
+
## Example usage:
|
25
|
+
## !atwt Tweet text
|
26
|
+
#cmd :atwt do |args|
|
27
|
+
# # adds args (usually the tweet text) to the list of random tweets unless
|
28
|
+
# # args already is in the list
|
29
|
+
# @config[:tweets] << args unless @config[:tweets].include? args
|
30
|
+
#end
|
31
|
+
#
|
32
|
+
## Auto-save! \o/
|
33
|
+
#every 1, :hour do
|
34
|
+
# save_config
|
35
|
+
#end
|
20
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twittbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nilsding
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02
|
11
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -135,8 +135,11 @@ files:
|
|
135
135
|
- lib/twittbot/cli.rb
|
136
136
|
- lib/twittbot/defaults.rb
|
137
137
|
- lib/twittbot/gem_ext/twitter.rb
|
138
|
+
- lib/twittbot/gem_ext/twitter/direct_message.rb
|
138
139
|
- lib/twittbot/gem_ext/twitter/rest/tweets.rb
|
139
140
|
- lib/twittbot/gem_ext/twitter/tweet.rb
|
141
|
+
- lib/twittbot/gem_ext/twitter/user.rb
|
142
|
+
- lib/twittbot/generators/templates/basic_dm/basic_dm.rb
|
140
143
|
- lib/twittbot/generators/templates/followback/followback.rb
|
141
144
|
- lib/twittbot/generators/templates/random_reply/random_reply.rb
|
142
145
|
- lib/twittbot/generators/templates/random_tweet/random_tweet.rb
|