twterm 1.1.3 → 1.2.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/bin/twterm +4 -4
- data/lib/twterm/app.rb +19 -4
- data/lib/twterm/client.rb +8 -470
- data/lib/twterm/direct_message.rb +82 -0
- data/lib/twterm/direct_message_composer.rb +74 -0
- data/lib/twterm/direct_message_manager.rb +52 -0
- data/lib/twterm/event/base.rb +22 -0
- data/lib/twterm/event/direct_message/fetched.rb +10 -0
- data/lib/twterm/event/favorite.rb +18 -0
- data/lib/twterm/event/follow.rb +17 -0
- data/lib/twterm/event/notification.rb +33 -0
- data/lib/twterm/event/open_uri.rb +11 -0
- data/lib/twterm/event/screen/resize.rb +13 -0
- data/lib/twterm/event/status/base.rb +14 -0
- data/lib/twterm/event/status/delete.rb +13 -0
- data/lib/twterm/event/status/mention.rb +10 -0
- data/lib/twterm/event/status/timeline.rb +10 -0
- data/lib/twterm/event_dispatcher.rb +59 -0
- data/lib/twterm/filter_query_window.rb +11 -5
- data/lib/twterm/filterable_list.rb +6 -1
- data/lib/twterm/notifier.rb +39 -15
- data/lib/twterm/promise.rb +2 -2
- data/lib/twterm/publisher.rb +16 -0
- data/lib/twterm/rest_client.rb +401 -0
- data/lib/twterm/screen.rb +16 -13
- data/lib/twterm/status.rb +12 -1
- data/lib/twterm/streaming_client.rb +103 -0
- data/lib/twterm/subscriber.rb +33 -0
- data/lib/twterm/tab/base.rb +13 -6
- data/lib/twterm/tab/direct_message/conversation.rb +103 -0
- data/lib/twterm/tab/direct_message/conversation_list.rb +99 -0
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +3 -2
- data/lib/twterm/tab/new/list.rb +5 -3
- data/lib/twterm/tab/new/search.rb +3 -2
- data/lib/twterm/tab/new/start.rb +17 -2
- data/lib/twterm/tab/new/user.rb +6 -3
- data/lib/twterm/tab/statuses/base.rb +18 -11
- data/lib/twterm/tab/statuses/conversation.rb +3 -2
- data/lib/twterm/tab/statuses/favorites.rb +3 -2
- data/lib/twterm/tab/statuses/home.rb +10 -4
- data/lib/twterm/tab/statuses/list_timeline.rb +3 -2
- data/lib/twterm/tab/statuses/mentions.rb +6 -6
- data/lib/twterm/tab/statuses/search.rb +4 -3
- data/lib/twterm/tab/statuses/user_timeline.rb +3 -2
- data/lib/twterm/tab/user_tab.rb +26 -16
- data/lib/twterm/tab/users/base.rb +3 -2
- data/lib/twterm/tab/users/followers.rb +3 -2
- data/lib/twterm/tab/users/friends.rb +3 -2
- data/lib/twterm/tab_manager.rb +20 -8
- data/lib/twterm/tweetbox.rb +5 -2
- data/lib/twterm/uri_opener.rb +25 -0
- data/lib/twterm/user.rb +11 -1
- data/lib/twterm/utils.rb +13 -0
- data/lib/twterm/version.rb +1 -1
- data/lib/twterm.rb +0 -3
- data/spec/twterm/event/screen/resize_spec.rb +11 -0
- data/spec/twterm/event_dispatcher_spec.rb +19 -0
- data/twterm.gemspec +1 -1
- metadata +29 -7
- data/lib/twterm/notification/base.rb +0 -24
- data/lib/twterm/notification/error.rb +0 -19
- data/lib/twterm/notification/message.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b97eeb5e737a698dcfde20b7e1f9284fa9d60c7
|
4
|
+
data.tar.gz: 8cd8793ff080f41519449fac75e9a88cd9e84deb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 114e722d6092d263be12a5b1d4bd102011c47b8cf9ff0a1893fcd9f6b25b562735f19725b8958fbcdad5c5a29a64490c50fe71923357e17fed43764374b63551
|
7
|
+
data.tar.gz: f78c9f33143bf6a3b27f0adae41bb0983d187340fa021ce95a781948d1b3ec4dd4e81100b40619741974ed0e45d29a35e4a87340718b8895ff9ed9d9a0b7f73c
|
data/bin/twterm
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'twterm'
|
4
|
-
|
5
3
|
if ARGV.count == 1 && (%w(-v --version).include?(ARGV.first))
|
4
|
+
require 'twterm/version'
|
6
5
|
puts 'twterm version %s' % Twterm::VERSION
|
7
6
|
exit
|
7
|
+
else
|
8
|
+
require 'twterm'
|
9
|
+
Twterm::App.instance.run
|
8
10
|
end
|
9
|
-
|
10
|
-
Twterm::App.instance.run
|
data/lib/twterm/app.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'curses'
|
2
|
+
require 'twterm/event/screen/resize'
|
3
|
+
require 'twterm/uri_opener'
|
4
|
+
|
1
5
|
module Twterm
|
2
6
|
class App
|
7
|
+
include Publisher
|
3
8
|
include Singleton
|
4
9
|
|
5
|
-
DATA_DIR = "#{ENV['HOME']}/.twterm"
|
10
|
+
DATA_DIR = "#{ENV['HOME']}/.twterm".freeze
|
6
11
|
|
7
12
|
def initialize
|
8
13
|
Dir.mkdir(DATA_DIR, 0700) unless File.directory?(DATA_DIR)
|
@@ -16,18 +21,28 @@ module Twterm
|
|
16
21
|
TabManager.instance.add_and_show(timeline)
|
17
22
|
|
18
23
|
mentions_tab = Tab::Statuses::Mentions.new(client)
|
24
|
+
|
19
25
|
TabManager.instance.add(mentions_tab)
|
20
26
|
TabManager.instance.recover_tabs
|
21
27
|
|
22
28
|
Screen.instance.refresh
|
23
29
|
|
24
|
-
client.
|
30
|
+
client.connect_user_stream
|
25
31
|
|
26
32
|
reset_interruption_handler
|
27
33
|
|
28
|
-
|
34
|
+
URIOpener.instance
|
35
|
+
|
36
|
+
resize = proc do
|
37
|
+
next if Curses.closed?
|
38
|
+
|
39
|
+
lines = `tput lines`.to_i
|
40
|
+
cols = `tput cols`.to_i
|
41
|
+
publish(Event::Screen::Resize.new(lines, cols))
|
42
|
+
end
|
29
43
|
|
30
|
-
|
44
|
+
Signal.trap(:WINCH, &resize)
|
45
|
+
Scheduler.new(60, &resize)
|
31
46
|
end
|
32
47
|
|
33
48
|
def run
|
data/lib/twterm/client.rb
CHANGED
@@ -1,122 +1,15 @@
|
|
1
|
+
require 'twterm/rest_client'
|
2
|
+
require 'twterm/streaming_client'
|
3
|
+
|
1
4
|
module Twterm
|
2
5
|
class Client
|
3
|
-
|
6
|
+
include RESTClient
|
7
|
+
include StreamingClient
|
4
8
|
|
5
|
-
|
6
|
-
CONSUMER_KEY = 'vLNSVFgXclBJQJRZ7VLMxL9lA'.freeze
|
7
|
-
CONSUMER_SECRET = 'OFLKzrepRG2p1hq0nUB9j2S9ndFQoNTPheTpmOY0GYw55jGgS5'.freeze
|
9
|
+
attr_reader :user_id, :screen_name
|
8
10
|
|
9
11
|
@@instances = []
|
10
12
|
|
11
|
-
def block(*user_ids)
|
12
|
-
send_request do
|
13
|
-
rest_client.block(*user_ids)
|
14
|
-
end.then do |users|
|
15
|
-
users.each do |user|
|
16
|
-
Friendship.block(self.user_id, user.id)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def destroy_status(status)
|
22
|
-
send_request_without_catch do
|
23
|
-
rest_client.destroy_status(status.id)
|
24
|
-
Notifier.instance.show_message('Your tweet has been deleted')
|
25
|
-
end.catch do |reason|
|
26
|
-
case reason
|
27
|
-
when Twitter::Error::NotFound, Twitter::Error::Forbidden
|
28
|
-
Notifier.instance.show_error 'You cannot destroy that status'
|
29
|
-
else
|
30
|
-
raise reason
|
31
|
-
end
|
32
|
-
end.catch(&show_error)
|
33
|
-
end
|
34
|
-
|
35
|
-
def favorite(status)
|
36
|
-
return false unless status.is_a? Status
|
37
|
-
|
38
|
-
send_request do
|
39
|
-
rest_client.favorite(status.id)
|
40
|
-
end.then do
|
41
|
-
status.favorite!
|
42
|
-
Notifier.instance.show_message('Successfully liked: @%s "%s"' % [
|
43
|
-
status.user.screen_name, status.text
|
44
|
-
])
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def favorites(user_id = nil)
|
49
|
-
user_id ||= self.user_id
|
50
|
-
|
51
|
-
send_request do
|
52
|
-
rest_client.favorites(user_id, count: 200)
|
53
|
-
end.then do |tweets|
|
54
|
-
tweets.map(&CREATE_STATUS_PROC)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def fetch_muted_users
|
59
|
-
send_request do
|
60
|
-
@muted_user_ids = rest_client.muted_ids.to_a
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def follow(*user_ids)
|
65
|
-
send_request do
|
66
|
-
rest_client.follow(*user_ids)
|
67
|
-
end.then do |users|
|
68
|
-
users.each do |user|
|
69
|
-
if user.protected?
|
70
|
-
Friendship.following_requested(self.user_id, user.id)
|
71
|
-
else
|
72
|
-
Friendship.follow(self.user_id, user.id)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def followers(user_id = nil)
|
79
|
-
user_id ||= self.user_id
|
80
|
-
|
81
|
-
m = Mutex.new
|
82
|
-
|
83
|
-
send_request do
|
84
|
-
rest_client.follower_ids(user_id).each_slice(100) do |user_ids|
|
85
|
-
m.synchronize do
|
86
|
-
users = rest_client.users(*user_ids).map(& -> u { User.new(u) })
|
87
|
-
users.each do |user|
|
88
|
-
Friendship.follow(user.id, self.user_id)
|
89
|
-
end if user_id == self.user_id
|
90
|
-
yield users
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def friends(user_id = nil)
|
97
|
-
user_id ||= self.user_id
|
98
|
-
|
99
|
-
m = Mutex.new
|
100
|
-
|
101
|
-
send_request do
|
102
|
-
rest_client.friend_ids(user_id).each_slice(100) do |user_ids|
|
103
|
-
m.synchronize do
|
104
|
-
yield rest_client.users(*user_ids).map(& -> u { User.new(u) })
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def home_timeline
|
111
|
-
send_request do
|
112
|
-
rest_client.home_timeline(count: 200)
|
113
|
-
end.then do |statuses|
|
114
|
-
statuses
|
115
|
-
.select(&@mute_filter)
|
116
|
-
.map(&CREATE_STATUS_PROC)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
13
|
def initialize(user_id, screen_name, access_token, access_token_secret)
|
121
14
|
@user_id, @screen_name = user_id, screen_name
|
122
15
|
@access_token, @access_token_secret = access_token, access_token_secret
|
@@ -134,324 +27,9 @@ module Twterm
|
|
134
27
|
|
135
28
|
initialize_user_stream
|
136
29
|
|
137
|
-
|
138
|
-
end
|
139
|
-
|
140
|
-
def initialize_user_stream
|
141
|
-
return if user_stream_initialized?
|
142
|
-
|
143
|
-
streaming_client.on_friends do
|
144
|
-
user_stream_connected!
|
145
|
-
end
|
146
|
-
|
147
|
-
streaming_client.on_timeline_status do |tweet|
|
148
|
-
status = Status.new(tweet)
|
149
|
-
invoke_callbacks(:timeline_status, status)
|
150
|
-
invoke_callbacks(:mention, status) if status.text.include? "@#{@screen_name}"
|
151
|
-
end
|
152
|
-
|
153
|
-
streaming_client.on_delete do |status_id|
|
154
|
-
timeline.delete_status(status_id)
|
155
|
-
end
|
156
|
-
|
157
|
-
streaming_client.on_event(:favorite) do |event|
|
158
|
-
break if event[:source][:screen_name] == @screen_name
|
30
|
+
direct_message_manager
|
159
31
|
|
160
|
-
|
161
|
-
text = event[:target_object][:text]
|
162
|
-
message = "@#{user} has favorited your tweet: #{text}"
|
163
|
-
Notifier.instance.show_message(message)
|
164
|
-
end
|
165
|
-
|
166
|
-
streaming_client.on_event(:follow) do |event|
|
167
|
-
screen_name = event[:source][:screen_name]
|
168
|
-
break if screen_name == @screen_name
|
169
|
-
|
170
|
-
Notifier.instance.show_message('@%s has followed you' % screen_name)
|
171
|
-
end
|
172
|
-
|
173
|
-
streaming_client.on_no_data_received do
|
174
|
-
user_stream_disconnected!
|
175
|
-
user_stream
|
176
|
-
end
|
177
|
-
|
178
|
-
user_stream_initialized!
|
179
|
-
end
|
180
|
-
|
181
|
-
def list(list_id)
|
182
|
-
send_request do
|
183
|
-
rest_client.list(list_id)
|
184
|
-
end.then do |list|
|
185
|
-
List.new(list)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def list_timeline(list)
|
190
|
-
fail ArgumentError,
|
191
|
-
'argument must be an instance of List class' unless list.is_a? List
|
192
|
-
send_request do
|
193
|
-
rest_client.list_timeline(list.id, count: 200)
|
194
|
-
end.then do |statuses|
|
195
|
-
statuses
|
196
|
-
.select(&@mute_filter)
|
197
|
-
.map(&CREATE_STATUS_PROC)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def lists
|
202
|
-
send_request do
|
203
|
-
rest_client.lists
|
204
|
-
end.then do |lists|
|
205
|
-
lists.map { |list| List.new(list) }
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
def lookup_friendships
|
210
|
-
user_ids = User.ids.reject { |id| Friendship.already_looked_up?(id) }
|
211
|
-
send_request_without_catch do
|
212
|
-
user_ids.each_slice(100) do |chunked_user_ids|
|
213
|
-
friendships = rest_client.friendships(*chunked_user_ids)
|
214
|
-
friendships.each do |friendship|
|
215
|
-
id = friendship.id
|
216
|
-
client_id = user_id
|
217
|
-
|
218
|
-
conn = friendship.connections
|
219
|
-
conn.include?('blocking') ? Friendship.block(client_id, id) : Friendship.unblock(client_id, id)
|
220
|
-
conn.include?('following') ? Friendship.follow(client_id, id) : Friendship.unfollow(client_id, id)
|
221
|
-
conn.include?('following_requested') ? Friendship.following_requested(client_id, id) : Friendship.following_not_requested(client_id, id)
|
222
|
-
conn.include?('followed_by') ? Friendship.follow(id, client_id) : Friendship.unfollow(id, client_id)
|
223
|
-
conn.include?('muting') ? Friendship.mute(client_id, id) : Friendship.unmute(client_id, id)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end.catch do |e|
|
227
|
-
case e
|
228
|
-
when Twitter::Error::TooManyRequests
|
229
|
-
# do nothing
|
230
|
-
else
|
231
|
-
raise e
|
232
|
-
end
|
233
|
-
end.catch(&show_error)
|
234
|
-
end
|
235
|
-
|
236
|
-
def mentions
|
237
|
-
send_request do
|
238
|
-
rest_client.mentions(count: 200)
|
239
|
-
end.then do |statuses|
|
240
|
-
statuses
|
241
|
-
.select(&@mute_filter)
|
242
|
-
.map(&CREATE_STATUS_PROC)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def mute(user_ids)
|
247
|
-
send_request do
|
248
|
-
rest_client.mute(*user_ids)
|
249
|
-
end.then do |users|
|
250
|
-
users.each do |user|
|
251
|
-
Friendship.mute(self.user_id, user.id)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def on_mention(&block)
|
257
|
-
fail ArgumentError, 'no block given' unless block_given?
|
258
|
-
on(:mention, &block)
|
259
|
-
end
|
260
|
-
|
261
|
-
def on_timeline_status(&block)
|
262
|
-
fail ArgumentError, 'no block given' unless block_given?
|
263
|
-
on(:timeline_status, &block)
|
264
|
-
end
|
265
|
-
|
266
|
-
def post(text, in_reply_to = nil)
|
267
|
-
send_request do
|
268
|
-
if in_reply_to.is_a? Status
|
269
|
-
text = "@#{in_reply_to.user.screen_name} #{text}"
|
270
|
-
rest_client.update(text, in_reply_to_status_id: in_reply_to.id)
|
271
|
-
else
|
272
|
-
rest_client.update(text)
|
273
|
-
end
|
274
|
-
Notifier.instance.show_message('Your tweet has been posted')
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
def rest_client
|
279
|
-
@rest_client ||= Twitter::REST::Client.new do |config|
|
280
|
-
config.consumer_key = CONSUMER_KEY
|
281
|
-
config.consumer_secret = CONSUMER_SECRET
|
282
|
-
config.access_token = @access_token
|
283
|
-
config.access_token_secret = @access_token_secret
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def retweet(status)
|
288
|
-
fail ArgumentError,
|
289
|
-
'argument must be an instance of Status class' unless status.is_a? Status
|
290
|
-
|
291
|
-
send_request_without_catch do
|
292
|
-
rest_client.retweet!(status.id)
|
293
|
-
end.then do
|
294
|
-
status.retweet!
|
295
|
-
Notifier.instance.show_message('Successfully retweeted: @%s "%s"' % [
|
296
|
-
status.user.screen_name, status.text
|
297
|
-
])
|
298
|
-
end.catch do |reason|
|
299
|
-
message =
|
300
|
-
case reason
|
301
|
-
when Twitter::Error::AlreadyRetweeted
|
302
|
-
'The status is already retweeted'
|
303
|
-
when Twitter::Error::NotFound
|
304
|
-
'The status is not found'
|
305
|
-
when Twitter::Error::Forbidden
|
306
|
-
if status.user.id == user_id # when the status is mine
|
307
|
-
'You cannot retweet your own status'
|
308
|
-
else # when the status is not mine
|
309
|
-
'The status is protected'
|
310
|
-
end
|
311
|
-
else
|
312
|
-
raise e
|
313
|
-
end
|
314
|
-
Notifier.instance.show_error "Retweet attempt failed: #{message}"
|
315
|
-
end.catch(&show_error)
|
316
|
-
end
|
317
|
-
|
318
|
-
def saved_search
|
319
|
-
send_request do
|
320
|
-
rest_client.saved_searches
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def search(query)
|
325
|
-
send_request do
|
326
|
-
rest_client.search(query, count: 100).attrs[:statuses]
|
327
|
-
end.then do |statuses|
|
328
|
-
statuses
|
329
|
-
.map(&Twitter::Tweet.method(:new))
|
330
|
-
.map(&CREATE_STATUS_PROC)
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
def show_status(status_id)
|
335
|
-
send_request do
|
336
|
-
rest_client.status(status_id)
|
337
|
-
end.then do |status|
|
338
|
-
Status.new(status)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def show_user(query)
|
343
|
-
send_request_without_catch do
|
344
|
-
rest_client.user(query)
|
345
|
-
end.catch do |reason|
|
346
|
-
case reason
|
347
|
-
when Twitter::Error::NotFound
|
348
|
-
nil
|
349
|
-
else
|
350
|
-
raise reason
|
351
|
-
end
|
352
|
-
end.catch(&show_error).then do |user|
|
353
|
-
user.nil? ? nil : User.new(user)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
def streaming_client
|
358
|
-
@streaming_client ||= TweetStream::Client.new(
|
359
|
-
consumer_key: CONSUMER_KEY,
|
360
|
-
consumer_secret: CONSUMER_SECRET,
|
361
|
-
oauth_token: @access_token,
|
362
|
-
oauth_token_secret: @access_token_secret,
|
363
|
-
auth_method: :oauth
|
364
|
-
)
|
365
|
-
end
|
366
|
-
|
367
|
-
def unblock(*user_ids)
|
368
|
-
send_request do
|
369
|
-
rest_client.unblock(*user_ids)
|
370
|
-
end.then do |users|
|
371
|
-
users.each do |user|
|
372
|
-
Friendship.unblock(self.user_id, user.id)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
def unfavorite(status)
|
378
|
-
fail ArgumentError,
|
379
|
-
'argument must be an instance of Status class' unless status.is_a? Status
|
380
|
-
|
381
|
-
send_request do
|
382
|
-
rest_client.unfavorite(status.id)
|
383
|
-
end.then do
|
384
|
-
status.unfavorite!
|
385
|
-
Notifier.instance.show_message('Successfully unliked: @%s "%s"' % [
|
386
|
-
status.user.screen_name, status.text
|
387
|
-
])
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
def unfollow(*user_ids)
|
392
|
-
send_request do
|
393
|
-
rest_client.unfollow(*user_ids)
|
394
|
-
end.then do |users|
|
395
|
-
users.each do |user|
|
396
|
-
Friendship.unfollow(self.user_id, user.id)
|
397
|
-
end
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
def unmute(user_ids)
|
402
|
-
send_request do
|
403
|
-
rest_client.unmute(*user_ids)
|
404
|
-
end.then do |users|
|
405
|
-
users.each do |user|
|
406
|
-
Friendship.unmute(self.user_id, user.id)
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
def user_stream
|
412
|
-
streaming_client.stop_stream
|
413
|
-
|
414
|
-
@streaming_thread = Thread.new do
|
415
|
-
begin
|
416
|
-
Notifier.instance.show_message 'Trying to connect to Twitter...'
|
417
|
-
streaming_client.userstream
|
418
|
-
rescue EventMachine::ConnectionError
|
419
|
-
Notifier.instance.show_error 'Connection failed'
|
420
|
-
sleep 30
|
421
|
-
retry
|
422
|
-
end
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
def user_stream_connected?
|
427
|
-
@user_stream_connected || false
|
428
|
-
end
|
429
|
-
|
430
|
-
def user_stream_connected!
|
431
|
-
Notifier.instance.show_message 'Connection established' unless user_stream_connected?
|
432
|
-
@user_stream_connected = true
|
433
|
-
end
|
434
|
-
|
435
|
-
def user_stream_disconnected!
|
436
|
-
@user_stream_connected = false
|
437
|
-
end
|
438
|
-
|
439
|
-
def user_stream_initialized?
|
440
|
-
@user_stream_initialized || false
|
441
|
-
end
|
442
|
-
|
443
|
-
def user_stream_initialized!
|
444
|
-
@user_stream_initialized = true
|
445
|
-
end
|
446
|
-
|
447
|
-
def user_timeline(user_id)
|
448
|
-
send_request do
|
449
|
-
rest_client.user_timeline(user_id, count: 200)
|
450
|
-
end.then do |statuses|
|
451
|
-
statuses
|
452
|
-
.select(&@mute_filter)
|
453
|
-
.map(&CREATE_STATUS_PROC)
|
454
|
-
end
|
32
|
+
@@instances << self
|
455
33
|
end
|
456
34
|
|
457
35
|
def self.new(user_id, screen_name, token, secret)
|
@@ -463,45 +41,5 @@ module Twterm
|
|
463
41
|
def self.current
|
464
42
|
@@instances[0]
|
465
43
|
end
|
466
|
-
|
467
|
-
private
|
468
|
-
|
469
|
-
def show_error
|
470
|
-
proc do |e|
|
471
|
-
case e
|
472
|
-
when Twitter::Error
|
473
|
-
Notifier.instance.show_error "Failed to send request: #{e.message}"
|
474
|
-
else
|
475
|
-
raise e
|
476
|
-
end
|
477
|
-
end.freeze
|
478
|
-
end
|
479
|
-
|
480
|
-
def invoke_callbacks(event, data = nil)
|
481
|
-
return if @callbacks[event].nil?
|
482
|
-
|
483
|
-
@callbacks[event].each { |cb| cb.call(data) }
|
484
|
-
self
|
485
|
-
end
|
486
|
-
|
487
|
-
def on(event, &block)
|
488
|
-
@callbacks[event] ||= []
|
489
|
-
@callbacks[event] << block
|
490
|
-
self
|
491
|
-
end
|
492
|
-
|
493
|
-
def send_request(&block)
|
494
|
-
send_request_without_catch(&block).catch(&show_error)
|
495
|
-
end
|
496
|
-
|
497
|
-
def send_request_without_catch(&block)
|
498
|
-
Promise.new do |resolve, reject|
|
499
|
-
begin
|
500
|
-
resolve.(block.call)
|
501
|
-
rescue Twitter::Error => reason
|
502
|
-
reject.(reason)
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end
|
506
44
|
end
|
507
45
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'twterm/user'
|
2
|
+
require 'twterm/utils'
|
3
|
+
|
4
|
+
module Twterm
|
5
|
+
class DirectMessage
|
6
|
+
attr_reader :id, :created_at, :recipient, :sender, :text
|
7
|
+
|
8
|
+
@@instances = {}
|
9
|
+
|
10
|
+
def initialize(message)
|
11
|
+
@id = message.id
|
12
|
+
update!(message)
|
13
|
+
|
14
|
+
@@instances[id] = self
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
other.is_a?(self.class) && id == other.id
|
19
|
+
end
|
20
|
+
|
21
|
+
def date
|
22
|
+
format = Time.now - @created_at < 86_400 ? '%H:%M:%S' : '%Y-%m-%d %H:%M:%S'
|
23
|
+
@created_at.strftime(format)
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(q)
|
27
|
+
[
|
28
|
+
sender.name,
|
29
|
+
sender.screen_name,
|
30
|
+
text
|
31
|
+
].map(&:downcase).any? { |x| x.include?(q) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def update!(message)
|
35
|
+
@created_at = message.created_at.dup.localtime
|
36
|
+
@recipient = User.new(message.recipient)
|
37
|
+
@sender = User.new(message.sender)
|
38
|
+
@text = message.text
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
class Conversation
|
44
|
+
include Utils
|
45
|
+
|
46
|
+
attr_reader :collocutor, :messages
|
47
|
+
|
48
|
+
def initialize(collocutor)
|
49
|
+
check_type User, collocutor
|
50
|
+
|
51
|
+
@collocutor = collocutor
|
52
|
+
@messages = []
|
53
|
+
end
|
54
|
+
|
55
|
+
def <<(message)
|
56
|
+
@messages << message if messages.find { |m| m == message }.nil?
|
57
|
+
@messages.sort_by!(&:created_at).reverse!
|
58
|
+
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def matches?(q)
|
63
|
+
[
|
64
|
+
collocutor.screen_name,
|
65
|
+
collocutor.name,
|
66
|
+
preview
|
67
|
+
].map(&:downcase).any? { |x| x.include?(q.downcase) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def preview
|
71
|
+
messages.sort_by(&:created_at).last.text.gsub("\n", ' ')
|
72
|
+
end
|
73
|
+
|
74
|
+
def updated_at
|
75
|
+
updated_at = @messages.map(&:created_at).max
|
76
|
+
|
77
|
+
format = Time.now - updated_at < 86_400 ? '%H:%M:%S' : '%Y-%m-%d %H:%M:%S'
|
78
|
+
updated_at.strftime(format)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|