ayadn 0.6.4 → 1.0.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.
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