ayadn 0.6.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +14 -0
  6. data/Guardfile +26 -0
  7. data/LICENSE.txt +22 -0
  8. data/MANUAL.md +946 -0
  9. data/README.md +26 -411
  10. data/Rakefile +6 -0
  11. data/ayadn.gemspec +39 -0
  12. data/bin/ayadn +3 -3
  13. data/lib/ayadn.rb +12 -25
  14. data/lib/ayadn/action.rb +1121 -0
  15. data/lib/ayadn/alias.rb +106 -0
  16. data/lib/ayadn/api.rb +312 -301
  17. data/lib/ayadn/app.rb +429 -365
  18. data/lib/ayadn/authorize.rb +127 -28
  19. data/lib/ayadn/blacklist.rb +116 -0
  20. data/lib/ayadn/cnx.rb +105 -0
  21. data/lib/ayadn/databases.rb +110 -0
  22. data/lib/ayadn/descriptions.rb +1043 -0
  23. data/lib/ayadn/endpoints.rb +220 -153
  24. data/lib/ayadn/errors.rb +37 -0
  25. data/lib/ayadn/extend.rb +4 -10
  26. data/lib/ayadn/fileops.rb +48 -0
  27. data/lib/ayadn/logs.rb +32 -0
  28. data/lib/ayadn/pinboard.rb +46 -35
  29. data/lib/ayadn/post.rb +229 -212
  30. data/lib/ayadn/scroll.rb +251 -0
  31. data/lib/ayadn/set.rb +377 -0
  32. data/lib/ayadn/settings.rb +195 -0
  33. data/lib/ayadn/status.rb +226 -165
  34. data/lib/ayadn/switch.rb +72 -0
  35. data/lib/ayadn/version.rb +4 -0
  36. data/lib/ayadn/view.rb +506 -269
  37. data/lib/ayadn/workers.rb +362 -0
  38. data/spec/helpers.rb +19 -0
  39. data/spec/mock/@ericd.json +160 -0
  40. data/spec/mock/@m.json +45 -0
  41. data/spec/mock/checkins.json +1856 -0
  42. data/spec/mock/fwr_@ayadn.json +1077 -0
  43. data/spec/mock/posted.json +1 -0
  44. data/spec/mock/stream.json +1 -0
  45. data/spec/spec_helper.rb +14 -0
  46. data/spec/unit/api_spec.rb +61 -0
  47. data/spec/unit/databases_spec.rb +5 -0
  48. data/spec/unit/descriptions_spec.rb +9 -0
  49. data/spec/unit/endpoints_spec.rb +35 -0
  50. data/spec/unit/post_spec.rb +136 -0
  51. data/spec/unit/status_spec.rb +9 -0
  52. data/spec/unit/view_spec.rb +119 -0
  53. data/spec/unit/workers_spec.rb +147 -0
  54. metadata +216 -40
  55. data/CHANGELOG.md +0 -250
  56. data/CONTRIBUTORS.md +0 -5
  57. data/LICENSE.md +0 -14
  58. data/lib/ayadn/adn_files.rb +0 -84
  59. data/lib/ayadn/client-http.rb +0 -226
  60. data/lib/ayadn/colors.rb +0 -62
  61. data/lib/ayadn/config.yml +0 -35
  62. data/lib/ayadn/debug.rb +0 -36
  63. data/lib/ayadn/files.rb +0 -184
  64. data/lib/ayadn/get-api.rb +0 -43
  65. data/lib/ayadn/help.rb +0 -152
  66. data/lib/ayadn/list.rb +0 -89
  67. data/lib/ayadn/main.rb +0 -542
  68. data/lib/ayadn/requires.rb +0 -12
  69. data/lib/ayadn/skip.rb +0 -27
  70. data/lib/ayadn/tools.rb +0 -208
  71. data/lib/ayadn/user-stream.rb +0 -91
  72. data/lib/ayadn/view-channels.rb +0 -120
  73. data/lib/ayadn/view-interactions.rb +0 -57
  74. data/lib/ayadn/view-object.rb +0 -195
  75. data/lib/experiments.rb +0 -109
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/ayadn.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ayadn/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ayadn"
8
+ spec.version = Ayadn::VERSION
9
+ spec.author = "Eric Dejonckheere"
10
+ spec.email = "eric@aya.io"
11
+ spec.summary = %q{App.net command-line client.}
12
+ spec.description = %q{App.net command-line client: toolbox to access and manage your ADN data, show your streams, post, manage conversations, star/follow/repost... and many, many more.}
13
+ spec.homepage = "http://ayadn-app.net"
14
+ spec.license = "MIT"
15
+
16
+ spec.bindir = 'bin'
17
+ spec.files = `git ls-files`.split("\n")
18
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ spec.executables = %w{ayadn}
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.required_ruby_version = '>= 1.9.3'
23
+
24
+ spec.add_dependency "thor", ">= 0.18"
25
+ spec.add_dependency "rest-client", ">= 1.6"
26
+ spec.add_dependency "rainbow", ">= 2.0"
27
+ spec.add_dependency "terminal-table", ">= 1.4"
28
+ spec.add_dependency "daybreak", ">= 0.3"
29
+ spec.add_dependency "pinboard"
30
+
31
+ spec.add_development_dependency "bundler", ">= 1.5"
32
+ spec.add_development_dependency "rake", ">= 10.1"
33
+ spec.add_development_dependency "rspec", ">= 2.14"
34
+ spec.add_development_dependency "rb-fsevent", ">= 0.9"
35
+ spec.add_development_dependency "guard-rspec", ">= 4.2"
36
+ spec.add_development_dependency "fakefs", ">= 0.5"
37
+
38
+ spec.post_install_message = "Thank you for installing Ayadn!"
39
+ end
data/bin/ayadn CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
  # App.net command-line client
4
- # by Eric Dejonckheere
5
- # http://alpha.app.net/ericd
6
- # © 2013
4
+ # Author: Eric DEJONCKHEERE (http://app.net/ericd)
7
5
 
6
+ $PROGRAM_NAME = 'ayadn'
8
7
  require_relative '../lib/ayadn'
9
8
 
9
+ Ayadn::App.start ARGV
data/lib/ayadn.rb CHANGED
@@ -1,25 +1,12 @@
1
- require_relative 'ayadn/requires.rb'
2
- require_relative 'ayadn/adn_files.rb'
3
- require_relative 'ayadn/api.rb'
4
- require_relative 'ayadn/authorize.rb'
5
- require_relative 'ayadn/client-http.rb'
6
- require_relative 'ayadn/colors.rb'
7
- require_relative 'ayadn/debug.rb'
8
- require_relative 'ayadn/endpoints.rb'
9
- require_relative 'ayadn/extend.rb'
10
- require_relative 'ayadn/files.rb'
11
- require_relative 'ayadn/get-api.rb'
12
- require_relative 'ayadn/help.rb'
13
- require_relative 'ayadn/list.rb'
14
- require_relative 'ayadn/main.rb'
15
- require_relative 'ayadn/pinboard.rb'
16
- require_relative 'ayadn/post.rb'
17
- require_relative 'ayadn/skip.rb'
18
- require_relative 'ayadn/status.rb'
19
- require_relative 'ayadn/tools.rb'
20
- require_relative 'ayadn/user-stream.rb'
21
- require_relative 'ayadn/view-channels.rb'
22
- require_relative 'ayadn/view-interactions.rb'
23
- require_relative 'ayadn/view-object.rb'
24
- require_relative 'ayadn/view.rb'
25
- require_relative 'ayadn/app.rb'
1
+ # encoding: utf-8
2
+ require_relative 'ayadn/version'
3
+
4
+ %w{rest_client json thor rainbow/ext/string terminal-table yaml logger daybreak fileutils io/console}.each { |r| require "#{r}" }
5
+
6
+ winPlatforms = ['mswin', 'mingw', 'mingw_18', 'mingw_19', 'mingw_20', 'mingw32']
7
+ case Gem::Platform.local.os
8
+ when *winPlatforms
9
+ require 'win32console'
10
+ end
11
+
12
+ require_relative 'ayadn/app'
@@ -0,0 +1,1121 @@
1
+ # encoding: utf-8
2
+ module Ayadn
3
+ class Action
4
+
5
+ def initialize
6
+ @api = API.new
7
+ @view = View.new
8
+ Settings.load_config
9
+ Settings.get_token
10
+ Settings.init_config
11
+ Logs.create_logger
12
+ Databases.open_databases
13
+ end
14
+
15
+ def unified(options)
16
+ begin
17
+ doing(options)
18
+ stream = @api.get_unified(options)
19
+ (no_new_posts unless Databases.has_new?(stream, 'unified')) if options[:new]
20
+ Databases.save_max_id(stream)
21
+ render_view(stream, options)
22
+ Scroll.new(@api, @view).unified(options) if options[:scroll]
23
+ rescue => e
24
+ Errors.global_error("action/unified", options, e)
25
+ ensure
26
+ Databases.close_all
27
+ end
28
+ end
29
+
30
+ def checkins(options)
31
+ begin
32
+ doing(options)
33
+ stream = @api.get_checkins(options)
34
+ (no_new_posts unless Databases.has_new?(stream, 'explore:checkins')) if options[:new]
35
+ Databases.save_max_id(stream)
36
+ render_view(stream, options)
37
+ Scroll.new(@api, @view).checkins(options) if options[:scroll]
38
+ rescue => e
39
+ Errors.global_error("action/checkins", options, e)
40
+ ensure
41
+ Databases.close_all
42
+ end
43
+ end
44
+
45
+ def global(options)
46
+ begin
47
+ doing(options)
48
+ stream = @api.get_global(options)
49
+ (no_new_posts unless Databases.has_new?(stream, 'global')) if options[:new]
50
+ Databases.save_max_id(stream)
51
+ render_view(stream, options)
52
+ Scroll.new(@api, @view).global(options) if options[:scroll]
53
+ rescue => e
54
+ Errors.global_error("action/global", options, e)
55
+ ensure
56
+ Databases.close_all
57
+ end
58
+ end
59
+
60
+ def trending(options)
61
+ begin
62
+ doing(options)
63
+ stream = @api.get_trending(options)
64
+ (no_new_posts unless Databases.has_new?(stream, 'explore:trending')) if options[:new]
65
+ Databases.save_max_id(stream)
66
+ render_view(stream, options)
67
+ Scroll.new(@api, @view).trending(options) if options[:scroll]
68
+ rescue => e
69
+ Errors.global_error("action/trending", options, e)
70
+ ensure
71
+ Databases.close_all
72
+ end
73
+ end
74
+
75
+ def photos(options)
76
+ begin
77
+ doing(options)
78
+ stream = @api.get_photos(options)
79
+ (no_new_posts unless Databases.has_new?(stream, 'explore:photos')) if options[:new]
80
+ Databases.save_max_id(stream)
81
+ render_view(stream, options)
82
+ Scroll.new(@api, @view).photos(options) if options[:scroll]
83
+ rescue => e
84
+ Errors.global_error("action/photos", options, e)
85
+ ensure
86
+ Databases.close_all
87
+ end
88
+ end
89
+
90
+ def conversations(options)
91
+ begin
92
+ doing(options)
93
+ stream = @api.get_conversations(options)
94
+ (no_new_posts unless Databases.has_new?(stream, 'explore:replies')) if options[:new]
95
+ Databases.save_max_id(stream)
96
+ render_view(stream, options)
97
+ Scroll.new(@api, @view).conversations(options) if options[:scroll]
98
+ rescue => e
99
+ Errors.global_error("action/conversations", options, e)
100
+ ensure
101
+ Databases.close_all
102
+ end
103
+ end
104
+
105
+ def mentions(username, options)
106
+ begin
107
+ missing_username if username.empty?
108
+ username = Workers.add_arobase_if_missing(username)
109
+ doing(options)
110
+ stream = @api.get_mentions(username, options)
111
+ user_404(username) if meta_404(stream)
112
+ Databases.save_max_id(stream)
113
+ options = options.dup
114
+ options[:in_mentions] = true
115
+ no_data('mentions') if stream['data'].empty?
116
+ render_view(stream, options)
117
+ Scroll.new(@api, @view).mentions(username, options) if options[:scroll]
118
+ rescue => e
119
+ Errors.global_error("action/mentions", [username, options], e)
120
+ ensure
121
+ Databases.close_all
122
+ end
123
+ end
124
+
125
+ def posts(username, options)
126
+ begin
127
+ missing_username if username.empty?
128
+ username = Workers.add_arobase_if_missing(username)
129
+ doing(options)
130
+ stream = @api.get_posts(username, options)
131
+ user_404(username) if meta_404(stream)
132
+ Databases.save_max_id(stream)
133
+ no_data('posts') if stream['data'].empty?
134
+ render_view(stream, options)
135
+ Scroll.new(@api, @view).posts(username, options) if options[:scroll]
136
+ rescue => e
137
+ Errors.global_error("action/posts", [username, options], e)
138
+ ensure
139
+ Databases.close_all
140
+ end
141
+ end
142
+
143
+ def interactions(options)
144
+ begin
145
+ doing(options)
146
+ stream = @api.get_interactions
147
+ unless options[:raw]
148
+ @view.clear_screen
149
+ @view.show_interactions(stream['data'])
150
+ else
151
+ @view.show_raw(stream)
152
+ end
153
+ rescue => e
154
+ Errors.global_error("action/interactions", options, e)
155
+ ensure
156
+ Databases.close_all
157
+ end
158
+ end
159
+
160
+ def whatstarred(username, options)
161
+ begin
162
+ missing_username if username.empty?
163
+ username = Workers.add_arobase_if_missing(username)
164
+ doing(options)
165
+ stream = @api.get_whatstarred(username, options)
166
+ user_404(username) if meta_404(stream)
167
+ stream['data'].empty? ? no_data('whatstarred') : render_view(stream, options)
168
+ rescue => e
169
+ Errors.global_error("action/whatstarred", [username, options], e)
170
+ ensure
171
+ Databases.close_all
172
+ end
173
+ end
174
+
175
+ def whoreposted(post_id, options)
176
+ begin
177
+ missing_post_id unless post_id.is_integer?
178
+ doing(options)
179
+ id = get_original_id(post_id, @api.get_details(post_id, options))
180
+ list = @api.get_whoreposted(id)
181
+ unless options[:raw]
182
+ unless list['data'].empty?
183
+ get_list(:whoreposted, list['data'], post_id)
184
+ else
185
+ puts Status.nobody_reposted
186
+ end
187
+ else
188
+ @view.show_raw(list)
189
+ end
190
+ rescue => e
191
+ Errors.global_error("action/whoreposted", post_id, e)
192
+ ensure
193
+ Databases.close_all
194
+ end
195
+ end
196
+
197
+ def whostarred(post_id, options)
198
+ begin
199
+ missing_post_id unless post_id.is_integer?
200
+ doing(options)
201
+ id = get_original_id(post_id, @api.get_details(post_id, options))
202
+ list = @api.get_whostarred(id)
203
+ unless options[:raw]
204
+ unless list['data'].empty?
205
+ get_list(:whostarred, list['data'], id)
206
+ else
207
+ puts Status.nobody_starred
208
+ end
209
+ else
210
+ @view.show_raw(list)
211
+ end
212
+ rescue => e
213
+ Errors.global_error("action/whostarred", [post_id, id], e)
214
+ ensure
215
+ Databases.close_all
216
+ end
217
+ end
218
+
219
+ def convo(post_id, options)
220
+ begin
221
+ missing_post_id unless post_id.is_integer?
222
+ doing(options)
223
+ id = get_original_id(post_id, @api.get_details(post_id, options))
224
+ stream = @api.get_convo(id, options)
225
+ post_404(id) if meta_404(stream)
226
+ Databases.pagination["replies:#{id}"] = stream['meta']['max_id']
227
+ render_view(stream, options)
228
+ Scroll.new(@api, @view).convo(id, options) if options[:scroll]
229
+ rescue => e
230
+ Errors.global_error("action/convo", [post_id, id, options], e)
231
+ ensure
232
+ Databases.close_all
233
+ end
234
+ end
235
+
236
+ def delete(post_id)
237
+ begin
238
+ missing_post_id unless post_id.is_integer?
239
+ print Status.deleting_post(post_id)
240
+ check_has_been_deleted(post_id, @api.delete_post(post_id))
241
+ rescue => e
242
+ Errors.global_error("action/delete", post_id, e)
243
+ ensure
244
+ Databases.close_all
245
+ end
246
+ end
247
+
248
+ def unfollow(username)
249
+ begin
250
+ missing_username if username.empty?
251
+ username = Workers.add_arobase_if_missing(username)
252
+ puts Status.unfollowing(username)
253
+ check_has_been_unfollowed(username, @api.unfollow(username))
254
+ rescue => e
255
+ Errors.global_error("action/unfollow", username, e)
256
+ ensure
257
+ Databases.close_all
258
+ end
259
+ end
260
+
261
+ def follow(username)
262
+ begin
263
+ missing_username if username.empty?
264
+ username = Workers.add_arobase_if_missing(username)
265
+ puts Status.following(username)
266
+ check_has_been_followed(username, @api.follow(username))
267
+ rescue => e
268
+ Errors.global_error("action/follow", username, e)
269
+ ensure
270
+ Databases.close_all
271
+ end
272
+ end
273
+
274
+ def unmute(username)
275
+ begin
276
+ missing_username if username.empty?
277
+ username = Workers.add_arobase_if_missing(username)
278
+ puts Status.unmuting(username)
279
+ check_has_been_unmuted(username, @api.unmute(username))
280
+ rescue => e
281
+ Errors.global_error("action/unmute", username, e)
282
+ ensure
283
+ Databases.close_all
284
+ end
285
+ end
286
+
287
+ def mute(username)
288
+ begin
289
+ missing_username if username.empty?
290
+ username = Workers.add_arobase_if_missing(username)
291
+ puts Status.muting(username)
292
+ check_has_been_muted(username, @api.mute(username))
293
+ rescue => e
294
+ Errors.global_error("action/mute", username, e)
295
+ ensure
296
+ Databases.close_all
297
+ end
298
+ end
299
+
300
+ def unblock(username)
301
+ begin
302
+ missing_username if username.empty?
303
+ username = Workers.add_arobase_if_missing(username)
304
+ puts Status.unblocking(username)
305
+ check_has_been_unblocked(username, @api.unblock(username))
306
+ rescue => e
307
+ Errors.global_error("action/unblock", username, e)
308
+ ensure
309
+ Databases.close_all
310
+ end
311
+ end
312
+
313
+ def block(username)
314
+ begin
315
+ missing_username if username.empty?
316
+ username = Workers.add_arobase_if_missing(username)
317
+ puts Status.blocking(username)
318
+ check_has_been_blocked(username, @api.block(username))
319
+ rescue => e
320
+ Errors.global_error("action/block", username, e)
321
+ ensure
322
+ Databases.close_all
323
+ end
324
+ end
325
+
326
+ def repost(post_id)
327
+ begin
328
+ missing_post_id unless post_id.is_integer?
329
+ puts Status.reposting(post_id)
330
+ resp = @api.get_details(post_id)
331
+ check_if_already_reposted(resp)
332
+ id = get_original_id(post_id, resp)
333
+ check_has_been_reposted(id, @api.repost(id))
334
+ rescue => e
335
+ Errors.global_error("action/repost", [post_id, id], e)
336
+ ensure
337
+ Databases.close_all
338
+ end
339
+ end
340
+
341
+ def unrepost(post_id)
342
+ begin
343
+ missing_post_id unless post_id.is_integer?
344
+ puts Status.unreposting(post_id)
345
+ if @api.get_details(post_id)['data']['you_reposted']
346
+ check_has_been_unreposted(post_id, @api.unrepost(post_id))
347
+ else
348
+ puts Status.not_your_repost
349
+ end
350
+ rescue => e
351
+ Errors.global_error("action/unrepost", post_id, e)
352
+ ensure
353
+ Databases.close_all
354
+ end
355
+ end
356
+
357
+ def unstar(post_id)
358
+ begin
359
+ missing_post_id unless post_id.is_integer?
360
+ puts Status.unstarring(post_id)
361
+ if @api.get_details(post_id)['data']['you_starred']
362
+ check_has_been_unstarred(post_id, @api.unstar(post_id))
363
+ else
364
+ puts Status.not_your_starred
365
+ end
366
+ rescue => e
367
+ Errors.global_error("action/unstar", post_id, e)
368
+ ensure
369
+ Databases.close_all
370
+ end
371
+ end
372
+
373
+ def star(post_id)
374
+ begin
375
+ missing_post_id unless post_id.is_integer?
376
+ puts Status.starring(post_id)
377
+ check_if_already_starred(@api.get_details(post_id))
378
+ check_has_been_starred(post_id, @api.star(post_id))
379
+ rescue => e
380
+ Errors.global_error("action/star", post_id, e)
381
+ ensure
382
+ Databases.close_all
383
+ end
384
+ end
385
+
386
+ def hashtag(hashtag, options)
387
+ begin
388
+ doing(options)
389
+ stream = @api.get_hashtag(hashtag)
390
+ no_data('hashtag') if stream['data'].empty?
391
+ render_view(stream, options)
392
+ rescue => e
393
+ Errors.global_error("action/hashtag", [hashtag, options], e)
394
+ ensure
395
+ Databases.close_all
396
+ end
397
+ end
398
+
399
+ def search(words, options)
400
+ begin
401
+ doing(options)
402
+ stream = @api.get_search(words, options)
403
+ no_data('search') if stream['data'].empty?
404
+ render_view(stream, options)
405
+ rescue => e
406
+ Errors.global_error("action/search", [words, options], e)
407
+ ensure
408
+ Databases.close_all
409
+ end
410
+ end
411
+
412
+ def followings(username, options)
413
+ begin
414
+ missing_username if username.empty?
415
+ username = Workers.add_arobase_if_missing(username)
416
+ doing(options)
417
+ unless options[:raw]
418
+ list = @api.get_followings(username)
419
+ auto_save_followings(list)
420
+ no_data('followings') if list.empty?
421
+ get_list(:followings, list, username)
422
+ Databases.add_to_users_db_from_list(list)
423
+ else
424
+ @view.show_raw(@api.get_raw_list(username, :followings))
425
+ end
426
+ rescue => e
427
+ Errors.global_error("action/followings", [username, options], e)
428
+ ensure
429
+ Databases.close_all
430
+ end
431
+ end
432
+
433
+ def followers(username, options)
434
+ begin
435
+ missing_username if username.empty?
436
+ username = Workers.add_arobase_if_missing(username)
437
+ doing(options)
438
+ unless options[:raw]
439
+ list = @api.get_followers(username)
440
+ auto_save_followers(list)
441
+ no_data('followers') if list.empty?
442
+ get_list(:followers, list, username)
443
+ Databases.add_to_users_db_from_list(list)
444
+ else
445
+ @view.show_raw(@api.get_raw_list(username, :followers))
446
+ end
447
+ rescue => e
448
+ Errors.global_error("action/followers", [username, options], e)
449
+ ensure
450
+ Databases.close_all
451
+ end
452
+ end
453
+
454
+ def muted(options)
455
+ begin
456
+ doing(options)
457
+ unless options[:raw]
458
+ list = @api.get_muted
459
+ auto_save_muted(list)
460
+ no_data('muted') if list.empty?
461
+ get_list(:muted, list, nil)
462
+ Databases.add_to_users_db_from_list(list)
463
+ else
464
+ @view.show_raw(@api.get_raw_list(nil, :muted))
465
+ end
466
+ rescue => e
467
+ Errors.global_error("action/muted", options, e)
468
+ ensure
469
+ Databases.close_all
470
+ end
471
+ end
472
+
473
+ def blocked(options)
474
+ begin
475
+ doing(options)
476
+ unless options[:raw]
477
+ list = @api.get_blocked
478
+ no_data('blocked') if list.empty?
479
+ get_list(:blocked, list, nil)
480
+ Databases.add_to_users_db_from_list(list)
481
+ else
482
+ @view.show_raw(@api.get_raw_list(nil, :blocked))
483
+ end
484
+ rescue => e
485
+ Errors.global_error("action/blocked", options, e)
486
+ ensure
487
+ Databases.close_all
488
+ end
489
+ end
490
+
491
+ def view_settings
492
+ begin
493
+ @view.clear_screen
494
+ @view.show_settings
495
+ rescue => e
496
+ Errors.global_error("action/settings", nil, e)
497
+ ensure
498
+ Databases.close_all
499
+ end
500
+ end
501
+
502
+ def userinfo(username, options)
503
+ begin
504
+ missing_username if username.empty?
505
+ username = Workers.add_arobase_if_missing(username)
506
+ doing(options)
507
+ unless options[:raw]
508
+ stream = @api.get_user(username)
509
+ user_404(username) if meta_404(stream)
510
+ if same_username?(stream)
511
+ token = @api.get_token_info
512
+ get_infos(stream['data'], token['data'])
513
+ else
514
+ get_infos(stream['data'], nil)
515
+ end
516
+ else
517
+ @view.show_raw(@api.get_user(username))
518
+ end
519
+ rescue => e
520
+ Errors.global_error("action/userinfo", [username, options], e)
521
+ ensure
522
+ Databases.close_all
523
+ end
524
+ end
525
+
526
+ def postinfo(post_id, options)
527
+ begin
528
+ missing_post_id unless post_id.is_integer?
529
+ doing(options)
530
+ unless options[:raw]
531
+ @view.clear_screen
532
+ response = @api.get_details(post_id, options)
533
+ post_404(post_id) if meta_404(response)
534
+ resp = response['data']
535
+ response = @api.get_user("@#{resp['user']['username']}")
536
+ user_404(username) if meta_404(response)
537
+ if same_username?(response)
538
+ token = @api.get_token_info
539
+ end
540
+ stream = response['data']
541
+ puts "POST:\n".inverse
542
+ @view.show_simple_post([resp], options)
543
+ if resp['repost_of']
544
+ puts "REPOST OF:\n".inverse
545
+ Errors.repost(post_id, resp['repost_of']['id'])
546
+ @view.show_simple_post([resp['repost_of']], options)
547
+ end
548
+ puts "AUTHOR:\n".inverse
549
+ if response['data']['username'] == Settings.config[:identity][:username]
550
+ @view.show_userinfos(stream, token['data'])
551
+ else
552
+ @view.show_userinfos(stream, nil)
553
+ end
554
+ else
555
+ @view.show_raw(@api.get_details(post_id, options))
556
+ end
557
+ rescue => e
558
+ Errors.global_error("action/postinfo", [post_id, options], e)
559
+ ensure
560
+ Databases.close_all
561
+ end
562
+ end
563
+
564
+ def files(options)
565
+ begin
566
+ doing(options)
567
+ unless options[:raw]
568
+ list = @api.get_files_list(options)
569
+ @view.clear_screen
570
+ list.empty? ? no_data('files') : @view.show_files_list(list)
571
+ else
572
+ @view.show_raw(@api.get_files_list(options))
573
+ end
574
+ rescue => e
575
+ Errors.global_error("action/files", options, e)
576
+ ensure
577
+ Databases.close_all
578
+ end
579
+ end
580
+
581
+ def download(file_id)
582
+ begin
583
+ resp = @api.get_file(file_id)
584
+ file = resp['data']
585
+ FileOps.download_url(file['name'], file['url'])
586
+ puts Status.downloaded(file['name'])
587
+ rescue => e
588
+ Errors.global_error("action/download", [file_id, file['url']], e)
589
+ ensure
590
+ Databases.close_all
591
+ end
592
+ end
593
+
594
+ def channels
595
+ begin
596
+ doing
597
+ resp = @api.get_channels
598
+ @view.clear_screen
599
+ @view.show_channels(resp)
600
+ rescue => e
601
+ Errors.global_error("action/channels", resp['meta'], e)
602
+ ensure
603
+ Databases.close_all
604
+ end
605
+ end
606
+
607
+ def messages(channel_id, options)
608
+ begin
609
+ channel_id = get_channel_id_from_alias(channel_id)
610
+ doing
611
+ resp = @api.get_messages(channel_id, options)
612
+ (no_new_posts unless Databases.has_new?(resp, "channel:#{channel_id}")) if options[:new]
613
+ Databases.save_max_id(resp)
614
+ no_data('messages') if resp['data'].empty?
615
+ render_view(resp, options)
616
+ Scroll.new(@api, @view).messages(channel_id, options) if options[:scroll]
617
+ rescue => e
618
+ Errors.global_error("action/messages", [channel_id, options], e)
619
+ ensure
620
+ Databases.close_all
621
+ end
622
+ end
623
+
624
+ def pin(post_id, usertags)
625
+ require 'pinboard'
626
+ require 'base64'
627
+ begin
628
+ missing_post_id unless post_id.is_integer?
629
+ doing
630
+ resp = get_data_from_response(@api.get_details(post_id, {}))
631
+ @view.clear_screen
632
+ links = Workers.new.extract_links(resp)
633
+ resp['text'].nil? ? text = "" : text = resp['text']
634
+ usertags << "ADN"
635
+ post_url = resp['canonical_url']
636
+ handle = "@" + resp['user']['username']
637
+ post_text = "From: #{handle} -- Text: #{text} -- Links: #{links.join(" ")}"
638
+ pinner = Ayadn::PinBoard.new
639
+ unless pinner.has_credentials_file?
640
+ puts Status.no_pin_creds
641
+ pinner.ask_credentials
642
+ puts Status.pin_creds_saved
643
+ end
644
+ credentials = pinner.load_credentials
645
+ maker = Struct.new(:username, :password, :url, :tags, :text, :description)
646
+ bookmark = maker.new(credentials[0], credentials[1], post_url, usertags.join(","), post_text, links[0])
647
+ puts Status.saving_pin
648
+ pinner.pin(bookmark)
649
+ puts Status.done
650
+ rescue => e
651
+ Errors.global_error("action/pin", [post_id, usertags], e)
652
+ ensure
653
+ Databases.close_all
654
+ end
655
+ end
656
+
657
+ def post(args)
658
+ begin
659
+ @view.clear_screen
660
+ puts Status.posting
661
+ resp = Post.new.post(args)
662
+ FileOps.save_post(resp) if Settings.options[:backup][:auto_save_sent_posts]
663
+ @view.clear_screen
664
+ puts Status.yourpost
665
+ @view.show_posted(resp)
666
+ rescue => e
667
+ Errors.global_error("action/post", args, e)
668
+ ensure
669
+ Databases.close_all
670
+ end
671
+ end
672
+
673
+ def auto(options)
674
+ begin
675
+ @view.clear_screen
676
+ puts Status.auto
677
+ poster = Post.new
678
+ platform = Settings.config[:platform]
679
+ case platform
680
+ when /mswin|mingw|cygwin/
681
+ poster.auto_classic
682
+ else
683
+ require "readline"
684
+ poster.auto_readline
685
+ end
686
+ rescue => e
687
+ Errors.global_error("action/auto post", [options, platform], e)
688
+ ensure
689
+ Databases.close_all
690
+ end
691
+ end
692
+
693
+ def write
694
+ begin
695
+ writer = Post.new
696
+ puts Status.post
697
+ lines_array = writer.compose
698
+ writer.check_post_length(lines_array)
699
+ @view.clear_screen
700
+ puts Status.posting
701
+ resp = writer.send_post(lines_array.join("\n"))
702
+ FileOps.save_post(resp) if Settings.options[:backup][:auto_save_sent_posts]
703
+ @view.clear_screen
704
+ puts Status.yourpost
705
+ @view.show_posted(resp)
706
+ rescue => e
707
+ Errors.global_error("action/write", lines_array.join(" "), e)
708
+ ensure
709
+ Databases.close_all
710
+ end
711
+ end
712
+
713
+ def pmess(username)
714
+ begin
715
+ missing_username if username.empty?
716
+ messenger = Post.new
717
+ puts Status.post
718
+ lines_array = messenger.compose
719
+ messenger.check_message_length(lines_array)
720
+ @view.clear_screen
721
+ puts Status.posting
722
+ resp = messenger.send_pm(username, lines_array.join("\n"))
723
+ FileOps.save_message(resp) if Settings.options[:backup][:auto_save_sent_messages]
724
+ @view.clear_screen
725
+ puts Status.yourpost
726
+ @view.show_posted(resp)
727
+ rescue => e
728
+ Errors.global_error("action/pmess", username, e)
729
+ ensure
730
+ Databases.close_all
731
+ end
732
+ end
733
+
734
+ def send_to_channel(channel_id)
735
+ begin
736
+ channel_id = get_channel_id_from_alias(channel_id)
737
+ messenger = Post.new
738
+ puts Status.post
739
+ lines_array = messenger.compose
740
+ messenger.check_message_length(lines_array)
741
+ @view.clear_screen
742
+ puts Status.posting
743
+ resp = messenger.send_message(channel_id, lines_array.join("\n"))
744
+ FileOps.save_message(resp) if Settings.options[:backup][:auto_save_sent_messages]
745
+ @view.clear_screen
746
+ puts Status.yourpost
747
+ @view.show_posted(resp)
748
+ rescue => e
749
+ Errors.global_error("action/send_to_channel", channel_id, e)
750
+ ensure
751
+ Databases.close_all
752
+ end
753
+ end
754
+
755
+ def reply(post_id)
756
+ begin
757
+ post_id = get_real_post_id(post_id)
758
+ puts Status.replying_to(post_id)
759
+ replied_to = @api.get_details(post_id)
760
+ post_404(post_id) if meta_404(replied_to)
761
+ poster = Post.new
762
+ puts Status.reply
763
+ lines_array = poster.compose
764
+ poster.check_post_length(lines_array)
765
+ @view.clear_screen
766
+ reply = poster.reply(lines_array.join("\n"), Workers.new.build_posts([replied_to['data']]))
767
+ puts Status.posting
768
+ resp = poster.send_reply(reply, post_id)
769
+ FileOps.save_post(resp) if Settings.options[:backup][:auto_save_sent_posts]
770
+ @view.clear_screen
771
+ puts Status.done
772
+ render_view(@api.get_convo(post_id, {}), {})
773
+ rescue => e
774
+ Errors.global_error("action/reply", post_id, e)
775
+ ensure
776
+ Databases.close_all
777
+ end
778
+ end
779
+
780
+ def nowplaying
781
+ begin
782
+ abort(Status.error_only_osx) unless Settings.config[:platform] =~ /darwin/
783
+ itunes = get_track_infos
784
+ itunes.each do |el|
785
+ abort(Status.empty_fields) if el.length == 0
786
+ end
787
+ @view.clear_screen
788
+ text_to_post = "#nowplaying '#{itunes.track}' from '#{itunes.album}' by #{itunes.artist}"
789
+ show_nowplaying(text_to_post)
790
+ abort("\nCanceled.\n\n".color(:red)) unless STDIN.getch == ("y" || "Y")
791
+ puts "\n"
792
+ post([text_to_post])
793
+ rescue => e
794
+ puts Status.wtf
795
+ Errors.global_error("action/nowplaying", itunes, e)
796
+ end
797
+ end
798
+
799
+ def random_posts(options)
800
+ begin
801
+ _, cols = winsize
802
+ max_posts = cols / 12
803
+ @view.clear_screen
804
+ puts "Fetching random posts, please wait...".color(:cyan)
805
+ @max_id = @api.get_global({count: 1})['meta']['max_id'].to_i
806
+ @view.clear_screen
807
+ counter = 1
808
+ wait = options[:wait] || 5
809
+ loop do
810
+ begin
811
+ @random_post_id = rand(@max_id)
812
+ @resp = @api.get_details(@random_post_id, {})
813
+ next if @resp['data']['is_deleted']
814
+ @view.show_simple_post([@resp['data']], {})
815
+ counter += 1
816
+ if counter == max_posts
817
+ countdown(wait)
818
+ @view.clear_screen
819
+ counter = 1
820
+ end
821
+ rescue Interrupt
822
+ abort(Status.canceled)
823
+ end
824
+ end
825
+ rescue => e
826
+ Errors.global_error("action/random_posts", [@max_id, @random_post_id, @resp], e)
827
+ ensure
828
+ Databases.close_all
829
+ end
830
+ end
831
+
832
+ private
833
+
834
+ def get_original_id(post_id, resp)
835
+ if resp['data']['repost_of']
836
+ puts Status.redirecting
837
+ id = resp['data']['repost_of']['id']
838
+ Errors.repost(post_id, id)
839
+ return id
840
+ else
841
+ return post_id
842
+ end
843
+ end
844
+
845
+ def check_if_already_starred(resp)
846
+ if resp['data']['you_starred']
847
+ puts "\nYou already starred this post.\n".color(:red)
848
+ exit
849
+ end
850
+ end
851
+
852
+ def check_if_already_reposted(resp)
853
+ if resp['data']['you_reposted']
854
+ puts "\nYou already reposted this post.\n".color(:red)
855
+ exit
856
+ end
857
+ end
858
+
859
+ def check_has_been_starred(post_id, resp)
860
+ if resp['meta']['code'] == 200
861
+ puts Status.starred(post_id)
862
+ Logs.rec.info "Starred #{post_id}."
863
+ else
864
+ whine(Status.not_starred(post_id), resp)
865
+ end
866
+ end
867
+
868
+ def check_has_been_reposted(post_id, resp)
869
+ if resp['meta']['code'] == 200
870
+ puts Status.reposted(post_id)
871
+ Logs.rec.info "Reposted #{post_id}."
872
+ else
873
+ whine(Status.not_reposted(post_id), resp)
874
+ end
875
+ end
876
+
877
+ def check_has_been_blocked(username, resp)
878
+ if resp['meta']['code'] == 200
879
+ puts Status.blocked(username)
880
+ Logs.rec.info "Blocked #{username}."
881
+ else
882
+ whine(Status.not_blocked(username), resp)
883
+ end
884
+ end
885
+
886
+ def check_has_been_muted(username, resp)
887
+ if resp['meta']['code'] == 200
888
+ puts Status.muted(username)
889
+ Logs.rec.info "Muted #{username}."
890
+ else
891
+ whine(Status.not_muted(username), resp)
892
+ end
893
+ end
894
+
895
+ def check_has_been_followed(username, resp)
896
+ if resp['meta']['code'] == 200
897
+ puts Status.followed(username)
898
+ Logs.rec.info "Followed #{username}."
899
+ else
900
+ whine(Status.not_followed(username), resp)
901
+ end
902
+ end
903
+
904
+ def check_has_been_deleted(post_id, resp)
905
+ if resp['meta']['code'] == 200
906
+ puts Status.deleted(post_id)
907
+ Logs.rec.info "Deleted post #{post_id}."
908
+ else
909
+ whine(Status.not_deleted(post_id), resp)
910
+ end
911
+ end
912
+
913
+ def check_has_been_unblocked(username, resp)
914
+ if resp['meta']['code'] == 200
915
+ puts Status.unblocked(username)
916
+ Logs.rec.info "Unblocked #{username}."
917
+ else
918
+ whine(Status.not_unblocked(username), resp)
919
+ end
920
+ end
921
+
922
+ def check_has_been_unstarred(post_id, resp)
923
+ if resp['meta']['code'] == 200
924
+ puts Status.unstarred(post_id)
925
+ Logs.rec.info "Unstarred #{post_id}."
926
+ else
927
+ whine(Status.not_unstarred(post_id), resp)
928
+ end
929
+ end
930
+
931
+ def check_has_been_unreposted(post_id, resp)
932
+ if resp['meta']['code'] == 200
933
+ puts Status.unreposted(post_id)
934
+ Logs.rec.info "Unreposted #{post_id}."
935
+ else
936
+ whine(Status.not_unreposted(post_id), resp)
937
+ end
938
+ end
939
+
940
+ def check_has_been_unmuted(username, resp)
941
+ if resp['meta']['code'] == 200
942
+ puts Status.unmuted(username)
943
+ Logs.rec.info "Unmuted #{username}."
944
+ else
945
+ whine(Status.not_unmuted(username), resp)
946
+ end
947
+ end
948
+
949
+ def check_has_been_unfollowed(username, resp)
950
+ if resp['meta']['code'] == 200
951
+ puts Status.unfollowed(username)
952
+ Logs.rec.info "Unfollowed #{username}."
953
+ else
954
+ whine(Status.not_unfollowed(username), resp)
955
+ end
956
+ end
957
+
958
+ def whine(status, resp)
959
+ puts status
960
+ Errors.error("#{status} => #{resp['meta']}")
961
+ end
962
+
963
+ def no_data(where)
964
+ Errors.warn "In action/#{where}: no data"
965
+ abort(Status.empty_list)
966
+ end
967
+
968
+ def meta_404(stream)
969
+ stream['meta']['code'] == 404
970
+ end
971
+
972
+ def user_404(username)
973
+ puts "\nUser #{username} doesn't exist. It could be a deleted account.\n".color(:red)
974
+ Errors.info("User #{username} doesn't exist")
975
+ exit
976
+ end
977
+
978
+ def post_404(post_id)
979
+ puts "\nImpossible to find #{post_id}. This post may have been deleted.\n".color(:red)
980
+ Errors.info("Impossible to find #{post_id}")
981
+ exit
982
+ end
983
+
984
+ def length_of_index
985
+ Databases.get_index_length
986
+ end
987
+
988
+ def get_post_from_index(id)
989
+ Databases.get_post_from_index(id)
990
+ end
991
+
992
+ def get_real_post_id(post_id)
993
+ id = post_id.to_i
994
+ if id > 0 && id <= length_of_index
995
+ resp = get_post_from_index(id)
996
+ post_id = resp[:id]
997
+ end
998
+ post_id
999
+ end
1000
+
1001
+ def render_view(data, options = {})
1002
+ unless options[:raw]
1003
+ #@view.clear_screen
1004
+ get_view(data['data'], options)
1005
+ else
1006
+ @view.show_raw(data)
1007
+ end
1008
+ end
1009
+
1010
+ def doing(options = {})
1011
+ unless options[:raw]
1012
+ @view.clear_screen
1013
+ print Status.downloading
1014
+ end
1015
+ end
1016
+
1017
+ def get_data_from_response(response)
1018
+ response['data']
1019
+ end
1020
+
1021
+ def get_view(stream, options = {})
1022
+ @view.clear_screen
1023
+ if options[:index]
1024
+ @view.show_posts_with_index(stream, options)
1025
+ else
1026
+ @view.show_posts(stream, options)
1027
+ end
1028
+ end
1029
+
1030
+ def get_simple_view(stream)
1031
+ @view.clear_screen
1032
+ @view.show_simple_stream(stream)
1033
+ end
1034
+
1035
+ def get_infos(stream, token)
1036
+ @view.clear_screen
1037
+ @view.show_userinfos(stream, token)
1038
+ end
1039
+
1040
+ def get_list(what, list, target)
1041
+ @view.clear_screen
1042
+ case what
1043
+ when :whoreposted
1044
+ @view.show_list_reposted(list, target)
1045
+ when :whostarred
1046
+ @view.show_list_starred(list, target)
1047
+ when :followings
1048
+ @view.show_list_followings(list, target)
1049
+ when :followers
1050
+ @view.show_list_followers(list, target)
1051
+ when :muted
1052
+ @view.show_list_muted(list)
1053
+ when :blocked
1054
+ @view.show_list_blocked(list)
1055
+ end
1056
+ end
1057
+
1058
+ def get_channel_id_from_alias(channel_id)
1059
+ unless channel_id.is_integer?
1060
+ channel_id = Databases.get_channel_id(channel_id)
1061
+ end
1062
+ channel_id
1063
+ end
1064
+
1065
+ def winsize
1066
+ IO.console.winsize
1067
+ end
1068
+
1069
+ def no_new_posts
1070
+ @view.clear_screen
1071
+ puts Status.no_new_posts
1072
+ exit
1073
+ end
1074
+
1075
+ def missing_username
1076
+ puts Status.error_missing_username
1077
+ exit
1078
+ end
1079
+
1080
+ def missing_post_id
1081
+ puts Status.error_missing_post_id
1082
+ exit
1083
+ end
1084
+
1085
+ def auto_save_followings(list)
1086
+ FileOps.save_followings_list(list) if Settings.options[:backup][:auto_save_lists]
1087
+ end
1088
+ def auto_save_followers(list)
1089
+ FileOps.save_followers_list(list) if Settings.options[:backup][:auto_save_lists]
1090
+ end
1091
+ def auto_save_muted(list)
1092
+ FileOps.save_muted_list(list) if Settings.options[:backup][:auto_save_lists]
1093
+ end
1094
+
1095
+ def same_username?(stream)
1096
+ stream['data']['username'] == Settings.config[:identity][:username]
1097
+ end
1098
+
1099
+ def get_track_infos
1100
+ track = `osascript -e 'tell application "iTunes"' -e 'set trackName to name of current track' -e 'return trackName' -e 'end tell'`
1101
+ album = `osascript -e 'tell application "iTunes"' -e 'set trackAlbum to album of current track' -e 'return trackAlbum' -e 'end tell'`
1102
+ artist = `osascript -e 'tell application "iTunes"' -e 'set trackArtist to artist of current track' -e 'return trackArtist' -e 'end tell'`
1103
+ maker = Struct.new(:artist, :album, :track)
1104
+ maker.new(artist.chomp!, album.chomp!, track.chomp!)
1105
+ end
1106
+
1107
+ def show_nowplaying(text)
1108
+ puts "\nThis is what will be posted:\n".color(:cyan)
1109
+ puts text + "\n\n"
1110
+ puts "Do you confirm? (y/N) ".color(:yellow)
1111
+ end
1112
+
1113
+ def countdown(wait)
1114
+ wait.downto(1) do |i|
1115
+ print "\r#{sprintf("%02d", i)} sec... QUIT WITH [CTRL+C]".color(:cyan)
1116
+ sleep 1
1117
+ end
1118
+ end
1119
+
1120
+ end
1121
+ end