ayadn 3.0 → 4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -4
- data/CHANGELOG.md +12 -4
- data/README.md +2 -5
- data/ayadn.gemspec +0 -2
- data/doc/01-index.md +0 -3
- data/doc/02-install.md +0 -4
- data/doc/06-post.md +0 -16
- data/doc/{18-contact.md → 16-contact.md} +0 -0
- data/doc/{19-examples.md → 17-examples.md} +0 -0
- data/doc/18-develop.md +165 -0
- data/lib/ayadn/action.rb +206 -396
- data/lib/ayadn/alias.rb +1 -1
- data/lib/ayadn/annotations.rb +15 -27
- data/lib/ayadn/api.rb +39 -28
- data/lib/ayadn/app.rb +19 -29
- data/lib/ayadn/authorize.rb +22 -13
- data/lib/ayadn/blacklist.rb +6 -19
- data/lib/ayadn/channel_object.rb +75 -0
- data/lib/ayadn/check.rb +19 -11
- data/lib/ayadn/cnx.rb +9 -15
- data/lib/ayadn/databases.rb +15 -27
- data/lib/ayadn/debug.rb +9 -9
- data/lib/ayadn/descriptions.rb +1 -99
- data/lib/ayadn/diagnostics.rb +16 -15
- data/lib/ayadn/endpoints.rb +18 -22
- data/lib/ayadn/errors.rb +1 -1
- data/lib/ayadn/fileops.rb +12 -12
- data/lib/ayadn/filtered_post_object.rb +11 -0
- data/lib/ayadn/ids.rb +0 -3
- data/lib/ayadn/logs.rb +4 -4
- data/lib/ayadn/mark.rb +34 -30
- data/lib/ayadn/nicerank.rb +7 -7
- data/lib/ayadn/nowplaying.rb +8 -22
- data/lib/ayadn/pinboard.rb +8 -12
- data/lib/ayadn/post.rb +18 -18
- data/lib/ayadn/post_object.rb +118 -0
- data/lib/ayadn/preferences_object.rb +290 -0
- data/lib/ayadn/profile.rb +2 -2
- data/lib/ayadn/scroll.rb +58 -67
- data/lib/ayadn/search.rb +22 -15
- data/lib/ayadn/set.rb +93 -83
- data/lib/ayadn/settings.rb +25 -33
- data/lib/ayadn/status.rb +24 -26
- data/lib/ayadn/stream.rb +68 -66
- data/lib/ayadn/stream_object.rb +56 -0
- data/lib/ayadn/switch.rb +2 -2
- data/lib/ayadn/user_object.rb +116 -0
- data/lib/ayadn/version.rb +1 -1
- data/lib/ayadn/view.rb +255 -278
- data/lib/ayadn/workers.rb +172 -174
- data/spec/integration/action_spec.rb +55 -34
- data/spec/mock/ayadn.sqlite +0 -0
- data/spec/unit/annotations_spec.rb +54 -41
- data/spec/unit/api_spec.rb +78 -7
- data/spec/unit/blacklistworkers_spec.rb +92 -20
- data/spec/unit/databases_spec.rb +117 -36
- data/spec/unit/endpoints_spec.rb +82 -10
- data/spec/unit/nicerank_spec.rb +56 -27
- data/spec/unit/post_spec.rb +94 -21
- data/spec/unit/set_spec.rb +141 -210
- data/spec/unit/view_spec.rb +105 -32
- data/spec/unit/workers_spec.rb +143 -52
- metadata +12 -37
- data/doc/16-movie.md +0 -39
- data/doc/17-tvshow.md +0 -46
- data/lib/ayadn/nowwatching.rb +0 -118
- data/lib/ayadn/tvshow.rb +0 -162
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6ebd67992a3895ceefe25d38e32281b3f40a340
|
4
|
+
data.tar.gz: 79aa8fc478f5610abc5295c8b54fc80d24becb4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bb3f4b17dcb074d1ed73a080e54c125f5c9640db70c71bf719e0a3bd189298f8f84cca6dc0df626436526467ebb722c1c53444e8de6c3f7a853252112fdc4b8
|
7
|
+
data.tar.gz: a1b6c4e8d91571e74088b0ce64eaf6b1a009e1ec6356df0a1dc8411eeaf61fdc5d833a1df151bf004d74d1b6bc1a9cd7db22466a82d0cfe30d133d8af53addb4
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 4.0- 2016-05-01 - 'Mr. Robot'
|
2
|
+
|
3
|
+
- Fixed: when possible, unauthorizing a user keeps the current user logged
|
4
|
+
- Fixed: inconsistencies in the 'set' command
|
5
|
+
- Fixed: malformed address for checkins in some cases
|
6
|
+
- Fixed: a case where changing the root URL was ignored
|
7
|
+
- Fixed: typos in descriptions
|
8
|
+
- Fixed: occasional crash in the 'random' stream
|
9
|
+
- New: documentation for developing with the Ayadn codebase
|
10
|
+
- Deprecated: 'movie' and 'tvshow' commands (we don't have access to imdb anymore)
|
11
|
+
- Code cleanup
|
12
|
+
|
1
13
|
## 3.0 - 2015-11-07 - 'Edge Of Tomorrow'
|
2
14
|
|
3
15
|
- New: option to set an alternative base URL for the API calls
|
@@ -36,10 +48,6 @@
|
|
36
48
|
|
37
49
|
- Fix: bug in add/remove user/mention to the blacklist
|
38
50
|
|
39
|
-
## 2.0.8 - 2015-02-11
|
40
|
-
|
41
|
-
*ignored*
|
42
|
-
|
43
51
|
## 2.0.7 - 2015-02-04 - 'Diacritics'
|
44
52
|
|
45
53
|
- Fix: users list if an element isn't in UTF8
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
[![Gem Version](https://badge.fury.io/rb/ayadn.svg)](http://badge.fury.io/rb/ayadn)
|
2
|
-
[![Build Status](https://travis-ci.org/ericdke/na.svg?branch=master)](https://travis-ci.org/ericdke/na)
|
3
|
-
[![Flattr this](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ericdejonckheere&url=https://github.com/ericdke/na&title=Ayadn&language=&tags=github&category=software)
|
2
|
+
[![Build Status](https://travis-ci.org/ericdke/na.svg?branch=master)](https://travis-ci.org/ericdke/na)
|
3
|
+
[![Flattr this](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ericdejonckheere&url=https://github.com/ericdke/na&title=Ayadn&language=&tags=github&category=software)
|
4
4
|
|
5
5
|
AYADN
|
6
6
|
=====
|
@@ -15,7 +15,6 @@ With Ayadn, you can use all the features of App.net from the console without any
|
|
15
15
|
- write fast single-line or complex multi-line posts
|
16
16
|
- embed pictures in posts
|
17
17
|
- embed online video in posts
|
18
|
-
- embed movie poster in posts
|
19
18
|
- view/scroll the Global stream with spammers filtered out
|
20
19
|
- view/scroll posts from specific users or posts mentioning a user
|
21
20
|
- follow/unfollow users, star/repost/mute/block/unstar/etc
|
@@ -26,8 +25,6 @@ With Ayadn, you can use all the features of App.net from the console without any
|
|
26
25
|
- list and download your files
|
27
26
|
- view (and write to) all your channels including Broadcasts, Patter, Ohai, etc
|
28
27
|
- 'nowplaying' from iTunes, Deezer or Last.fm, with album art and store link
|
29
|
-
- 'movie' creates a post from a movie title with poster, plot, and link
|
30
|
-
- 'tvshow' creates a post from a TV show title with poster, plot, and link
|
31
28
|
- view/send private messages
|
32
29
|
- view geolocation data in streams
|
33
30
|
- create silent black lists of users, mentions, clients or hashtags
|
data/ayadn.gemspec
CHANGED
@@ -28,8 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency "terminal-table", "~> 1.4"
|
29
29
|
spec.add_dependency "pinboard", "~> 0.1"
|
30
30
|
spec.add_dependency "unicode_utils", "~> 1.4"
|
31
|
-
spec.add_dependency "spotlite", "~> 0.8"
|
32
|
-
spec.add_dependency "tvdb_party", "~> 0.7"
|
33
31
|
spec.add_dependency "amalgalite", "~> 1.3"
|
34
32
|
spec.add_dependency "fast_cache", "~> 1.0"
|
35
33
|
|
data/doc/01-index.md
CHANGED
@@ -11,7 +11,6 @@ With Ayadn, you can use all the features of App.net from the console without any
|
|
11
11
|
- write fast single-line or complex multi-line posts
|
12
12
|
- embed pictures in posts
|
13
13
|
- embed online video in posts
|
14
|
-
- embed movie poster in posts
|
15
14
|
- view/scroll the Global stream with spammers filtered out
|
16
15
|
- view/scroll posts from specific users or posts mentioning a user
|
17
16
|
- follow/unfollow users, star/repost/mute/block/unstar/etc
|
@@ -22,8 +21,6 @@ With Ayadn, you can use all the features of App.net from the console without any
|
|
22
21
|
- list and download your files
|
23
22
|
- view (and write to) all your channels including Broadcasts, Patter, Ohai, etc
|
24
23
|
- 'nowplaying' from iTunes, Deezer or Last.fm, with album art and store link
|
25
|
-
- 'movie' creates a post from a movie title with poster, plot, and link
|
26
|
-
- 'tvshow' creates a post from a TV show title with poster, plot, and link
|
27
24
|
- view/send private messages
|
28
25
|
- view geolocation data in streams
|
29
26
|
- create silent black lists of users, mentions, clients or hashtags
|
data/doc/02-install.md
CHANGED
@@ -49,11 +49,7 @@ Ayadn depends upon these Gems:
|
|
49
49
|
pinboard (export to Pinboard)
|
50
50
|
rainbow (text UI utilities)
|
51
51
|
rest-client (networking)
|
52
|
-
spotlite (IMDb access)
|
53
52
|
terminal-table (text UI utilities)
|
54
53
|
thor (commands and options parsing)
|
55
|
-
tvdb_party (TVDb access)
|
56
54
|
unicode_utils (text utilities)
|
57
|
-
daybreak (Ruby data store)
|
58
55
|
|
59
|
-
*Note: the "daybreak" dependency is only needed for 1.x to 2.x migrations. Deprecated since Ayadn 3.0.*
|
data/doc/06-post.md
CHANGED
@@ -164,19 +164,3 @@ ayadn pm @ericd -Y https://www.youtube.com/watch?v=Ei8CFin00PY
|
|
164
164
|
```
|
165
165
|
|
166
166
|
*Note: unfortunately, very few App.net clients treat video embedding properly. So I would advise to include the video URL in the text body anyway, for better compatibility.*
|
167
|
-
|
168
|
-
# EMBED MOVIE POSTER
|
169
|
-
|
170
|
-
You can embed a movie poster in a normal post with option `-M`.
|
171
|
-
|
172
|
-
This is compatible with other options, eg embedding other images.
|
173
|
-
|
174
|
-
*Warning: contrary to the `movie` command, this option doesn't check with the user if the movie is valid. The poster is retrieved from IMDb and is automatically embedded in the post.*
|
175
|
-
|
176
|
-
Examples:
|
177
|
-
|
178
|
-
```
|
179
|
-
ayadn -P "I'll be back" -M terminator
|
180
|
-
ayadn -W -M truman show -E ~/Pics/my_face.jpg
|
181
|
-
ayadn -R 23362460 -M the dark knight
|
182
|
-
```
|
File without changes
|
File without changes
|
data/doc/18-develop.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# DEVELOP
|
2
|
+
|
3
|
+
Ayadn is an Open Source project under the MIT license.
|
4
|
+
|
5
|
+
You can develop with Ayadn in several ways: build your own Ayadn-based client, add features to the official one, fix bugs, etc.
|
6
|
+
|
7
|
+
## First step
|
8
|
+
|
9
|
+
The [repository](https://github.com/ericdke/na) doesn't always have a development branch. If it has one, use it - otherwise it means the previous one has been merged or dismissed and you have to fork the master branch.
|
10
|
+
|
11
|
+
The first step in any case is to [fork](https://help.github.com/articles/fork-a-repo/) then clone the repository:
|
12
|
+
|
13
|
+
$ git clone git@github.com:you/na.git && cd na
|
14
|
+
|
15
|
+
Run Bundler to ensure you have the proper dependencies installed:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
If you have the Ayadn Gem already installed, the currently logged in user will be used:
|
20
|
+
|
21
|
+
$ ./bin/ayadn -tl
|
22
|
+
|
23
|
+
Otherwise you will have to authorize first:
|
24
|
+
|
25
|
+
$ ./bin/ayadn -auth
|
26
|
+
|
27
|
+
Then for the Ayadn credentials itself, they're not included in the repository, so you will have to make a new `lib/ids.rb` file following this template:
|
28
|
+
|
29
|
+
<pre>
|
30
|
+
<code class="ruby">
|
31
|
+
# encoding: utf-8
|
32
|
+
module Ayadn
|
33
|
+
class Settings
|
34
|
+
# Mandatory
|
35
|
+
CLIENT_ID = "xxx"
|
36
|
+
end
|
37
|
+
class Endpoints
|
38
|
+
# Mandatory
|
39
|
+
CALLBACK_URL = "http://yourdomain.com/appname.html"
|
40
|
+
end
|
41
|
+
class NowPlaying
|
42
|
+
# Optional
|
43
|
+
AFFILIATE_SUFFIX = "&at=xxx&ct=appname"
|
44
|
+
DEEZER_APP_ID = "xxx"
|
45
|
+
DEEZER_AUTH_URL = "http://yourdomain.com/deezer.html"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
</code>
|
49
|
+
</pre>
|
50
|
+
|
51
|
+
*Be careful to not modify your `.gitignore` file, these credentials should always be ignored and its contents never be accessible from any public location.*
|
52
|
+
|
53
|
+
## Tests
|
54
|
+
|
55
|
+
### RSPEC
|
56
|
+
|
57
|
+
Ayadn has a set of *rspec* unit tests.
|
58
|
+
|
59
|
+
They're convenient but far from perfect, so you're welcome to improve them or add new ones (some classes like `FileOps` or `CNX` notably lack testing at the moment).
|
60
|
+
|
61
|
+
Ayadn tests include mock data (adapted from real data) like stream and user JSON responses, and also a dedicated SQLite mock file.
|
62
|
+
|
63
|
+
Just launch `rspec` to run the battery of tests:
|
64
|
+
|
65
|
+
$ rspec
|
66
|
+
|
67
|
+
### Debug
|
68
|
+
|
69
|
+
For live simulations and debug sessions, launch *irb* or *pry* then require `ayadn`:
|
70
|
+
|
71
|
+
$ pry
|
72
|
+
pry(main)> require_relative "lib/ayadn"
|
73
|
+
|
74
|
+
Then, to be "live", initialize the `Action` class:
|
75
|
+
|
76
|
+
pry(main)> action = Ayadn::Action.new
|
77
|
+
|
78
|
+
You can now issue commands to Ayadn, for example:
|
79
|
+
|
80
|
+
pry(main)> action.userinfo ["me"], {"raw"=>true}
|
81
|
+
|
82
|
+
*Be careful to use a test account when using Ayadn live like this...*
|
83
|
+
|
84
|
+
## Pull requests
|
85
|
+
|
86
|
+
You've added a feature or fixed a bug? Awesome! You're a hero!
|
87
|
+
|
88
|
+
Now you just have to open a Pull Request and wait until I examine your proposition and give you feedback.
|
89
|
+
|
90
|
+
## Make your own version
|
91
|
+
|
92
|
+
If you want to use (parts of) this codebase to create your own version of Ayadn, you will have to fill in several identifiers before release:
|
93
|
+
|
94
|
+
- Ayadn's client id
|
95
|
+
- Ayadn's callback URL for authentication
|
96
|
+
|
97
|
+
Optionally, if you keep those features:
|
98
|
+
|
99
|
+
- NowPlaying's iTunes affiliate suffix
|
100
|
+
- Deezer App id
|
101
|
+
- Deezer callback URL for authentication
|
102
|
+
|
103
|
+
**You will also have to create a new application in your App.net dashboard.**
|
104
|
+
|
105
|
+
*Don't forget to follow the License's rules before release. And although not mandatory, I'll be glad if you send me a message about your work. :)*
|
106
|
+
|
107
|
+
## Dive In
|
108
|
+
|
109
|
+
It's always hard to dive in an unknown codebase.
|
110
|
+
|
111
|
+
It's even more difficult when this codebase has a lot of legacy code and most of it is mediocre.
|
112
|
+
|
113
|
+
Unfortunately Ayadn is like that. ¯\(ツ)/¯
|
114
|
+
|
115
|
+
It was my first "big" app when I started developing in Ruby, so the code reflects that and suffers from the "lasagna syndrome": layers of new code upon layers of old code during years of development.
|
116
|
+
|
117
|
+
The biggest issue with the current codebase is not the code quality but its architecture, which is, to be polite, far from ideal, and not even really based on OOP principles - there's a lot of purely imperative code and other atrocities.
|
118
|
+
|
119
|
+
That being said, I believe my nomenclature for most methods and properties is self-explanatory enough, and there's comments where the code is a bit hairy or unclear.
|
120
|
+
|
121
|
+
As for the architecture, here's a brief overview.
|
122
|
+
|
123
|
+
### CLI
|
124
|
+
|
125
|
+
The first important step of the control flow is the `app.rb` class which intercepts the commands from the CLI.
|
126
|
+
|
127
|
+
This class inherits from `Thor` and only serves the purpose of being an interface for the CLI. Thor handles the IO of arguments and options, and also generates descriptions and help for the CLI commands.
|
128
|
+
|
129
|
+
From there, most commands will pass options and commands to the main dispatcher, the `Action` class (`action.rb`).
|
130
|
+
|
131
|
+
It initializes the user account credentials from the SQLite database and creates the main objects.
|
132
|
+
|
133
|
+
This is why you have to initialize `Action` yourself to use a live account if you're not using the CLI via `App`.
|
134
|
+
|
135
|
+
Follow what `Action`'s `initialize` does to understand the init process - it's scattered but easy to grasp.
|
136
|
+
|
137
|
+
### Action
|
138
|
+
|
139
|
+
The `Action` class launches the commands themselves (all commands that needed to have the credentials initialized).
|
140
|
+
|
141
|
+
Most of the commands in `Action` actually launch instances of the `Stream` class - other commands are implemented in `Action` itself or in topical classes like `Set` or `BlackList`.
|
142
|
+
|
143
|
+
### API
|
144
|
+
|
145
|
+
The `Endpoints` class holds all necessary endpoints and URLs.
|
146
|
+
|
147
|
+
The `API` class uses them to get the JSON responses from the ADN servers (using the `CNX` class for networking) and return a parsed version as a Ruby Hash. This class also handles the generation of query URLs from passed arguments.
|
148
|
+
|
149
|
+
Most commands will create custom Ayadn objects from these hashes, like `StreamObject` or `UserObject`, but for legacy reasons this is not how the global architecture works, and there's still places where the Hashes are used directly instead of handling custom objects.
|
150
|
+
|
151
|
+
### Main classes
|
152
|
+
|
153
|
+
The most used classes are the "God" classes `Workers`, `View` and `Status`.
|
154
|
+
|
155
|
+
`Workers` holds all utilities and workforce operations.
|
156
|
+
|
157
|
+
`View` creates colored and formatted text outputs.
|
158
|
+
|
159
|
+
`Status` holds all text messages: interface, errors, statuses, help, etc.
|
160
|
+
|
161
|
+
The `Workers` and `View` classes could really appreciate a rework and some DRY refactoring... but they currently work pretty well without known bugs so it's already something I suppose. ;)
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
|
data/lib/ayadn/action.rb
CHANGED
@@ -10,10 +10,10 @@ module Ayadn
|
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@api = API.new
|
13
|
-
@
|
14
|
-
@workers = Workers.new
|
15
|
-
@
|
16
|
-
@check = Check.new
|
13
|
+
@status = Status.new
|
14
|
+
@workers = Workers.new(@status)
|
15
|
+
@view = View.new(@status, @workers)
|
16
|
+
@check = Check.new(@status)
|
17
17
|
Settings.load_config
|
18
18
|
Settings.get_token
|
19
19
|
Settings.init_config
|
@@ -21,93 +21,32 @@ module Ayadn
|
|
21
21
|
Databases.open_databases
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
when 'unified', 'checkins', 'global', 'trending', 'photos', 'conversations', 'interactions'
|
27
|
-
begin
|
28
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
29
|
-
stream = Stream.new(@api, @view, @workers)
|
30
|
-
stream.send(meth.to_sym, options)
|
31
|
-
rescue => e
|
32
|
-
Errors.global_error({error: e, caller: caller, data: [meth, options]})
|
33
|
-
end
|
34
|
-
else
|
35
|
-
super
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def mentions(username, options)
|
40
|
-
begin
|
41
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
42
|
-
stream = Stream.new(@api, @view, @workers)
|
43
|
-
stream.mentions(username, options)
|
44
|
-
rescue => e
|
45
|
-
Errors.global_error({error: e, caller: caller, data: [username, options]})
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def posts(username, options)
|
50
|
-
begin
|
51
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
52
|
-
stream = Stream.new(@api, @view, @workers)
|
53
|
-
stream.posts(username, options)
|
54
|
-
rescue => e
|
55
|
-
Errors.global_error({error: e, caller: caller, data: [username, options]})
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def whatstarred(username, options)
|
24
|
+
# Uses method_missing to template a single method for several streams
|
25
|
+
def method_missing(meth, *args)
|
60
26
|
begin
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
Errors.global_error({error: e, caller: caller, data: [post_id, options]})
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def whostarred(post_id, options)
|
80
|
-
begin
|
81
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
82
|
-
stream = Stream.new(@api, @view, @workers)
|
83
|
-
stream.whostarred(post_id, options)
|
84
|
-
rescue => e
|
85
|
-
Errors.global_error({error: e, caller: caller, data: [post_id, options]})
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def convo(post_id, options)
|
90
|
-
begin
|
91
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
92
|
-
stream = Stream.new(@api, @view, @workers)
|
93
|
-
stream.convo(post_id, options)
|
27
|
+
options = if args.size > 1
|
28
|
+
args[1]
|
29
|
+
else
|
30
|
+
args[0]
|
31
|
+
end
|
32
|
+
Settings.options.timeline.compact = true if options[:compact]
|
33
|
+
Settings.global.force = true if options[:force]
|
34
|
+
stream = Stream.new(@api, @view, @workers, @check, @status)
|
35
|
+
case meth
|
36
|
+
when :mentions, :posts, :whatstarred, :whoreposted, :whostarred, :convo, :followings, :followers, :messages
|
37
|
+
stream.send(meth, args[0], options)
|
38
|
+
when :unified, :checkins, :global, :trending, :photos, :conversations, :interactions, :muted, :blocked, :random_posts
|
39
|
+
stream.send(meth, options)
|
40
|
+
end
|
94
41
|
rescue => e
|
95
|
-
Errors.global_error({error: e, caller: caller, data: [
|
42
|
+
Errors.global_error({error: e, caller: caller, data: [meth, options]})
|
96
43
|
end
|
97
44
|
end
|
98
45
|
|
99
46
|
def delete(post_ids, options = {})
|
100
47
|
begin
|
101
|
-
ids = post_ids
|
102
|
-
|
103
|
-
@status.error_missing_post_id
|
104
|
-
exit
|
105
|
-
end
|
106
|
-
if options[:force]
|
107
|
-
Settings.global[:force] = true
|
108
|
-
else
|
109
|
-
ids.map! { |post_id| @workers.get_real_post_id(post_id) }
|
110
|
-
end
|
48
|
+
ids = get_posts_ids_or_exit(post_ids) { @status.error_missing_post_id }
|
49
|
+
ids = get_real_posts_ids_or_force(options, ids)
|
111
50
|
puts "\n"
|
112
51
|
ids.each do |post_id|
|
113
52
|
@status.deleting_post(post_id)
|
@@ -127,11 +66,7 @@ module Ayadn
|
|
127
66
|
end
|
128
67
|
channel = args[0]
|
129
68
|
args.shift
|
130
|
-
ids = args
|
131
|
-
if ids.empty?
|
132
|
-
@status.error_missing_message_id
|
133
|
-
exit
|
134
|
-
end
|
69
|
+
ids = get_posts_ids_or_exit(args) { @status.error_missing_message_id }
|
135
70
|
channel_id = @workers.get_channel_id_from_alias(channel)
|
136
71
|
puts "\n"
|
137
72
|
ids.each do |message_id|
|
@@ -146,8 +81,8 @@ module Ayadn
|
|
146
81
|
|
147
82
|
def unfollow(usernames)
|
148
83
|
begin
|
149
|
-
|
150
|
-
users =
|
84
|
+
# Verify CLI input, remove current user from list (you never know) to avoid API error
|
85
|
+
users = get_all_usernames_but_me(usernames)
|
151
86
|
puts "\n"
|
152
87
|
@status.unfollowing(users.join(','))
|
153
88
|
users.each do |user|
|
@@ -161,8 +96,7 @@ module Ayadn
|
|
161
96
|
|
162
97
|
def follow(usernames)
|
163
98
|
begin
|
164
|
-
|
165
|
-
users = @workers.all_but_me(usernames)
|
99
|
+
users = get_all_usernames_but_me(usernames)
|
166
100
|
puts "\n"
|
167
101
|
@status.following(users.join(','))
|
168
102
|
users.each do |user|
|
@@ -176,8 +110,7 @@ module Ayadn
|
|
176
110
|
|
177
111
|
def unmute(usernames)
|
178
112
|
begin
|
179
|
-
|
180
|
-
users = @workers.all_but_me(usernames)
|
113
|
+
users = get_all_usernames_but_me(usernames)
|
181
114
|
puts "\n"
|
182
115
|
@status.unmuting(users.join(','))
|
183
116
|
users.each do |user|
|
@@ -191,8 +124,7 @@ module Ayadn
|
|
191
124
|
|
192
125
|
def mute(usernames)
|
193
126
|
begin
|
194
|
-
|
195
|
-
users = @workers.all_but_me(usernames)
|
127
|
+
users = get_all_usernames_but_me(usernames)
|
196
128
|
puts "\n"
|
197
129
|
@status.muting(users.join(','))
|
198
130
|
users.each do |user|
|
@@ -206,8 +138,7 @@ module Ayadn
|
|
206
138
|
|
207
139
|
def unblock(usernames)
|
208
140
|
begin
|
209
|
-
|
210
|
-
users = @workers.all_but_me(usernames)
|
141
|
+
users = get_all_usernames_but_me(usernames)
|
211
142
|
puts "\n"
|
212
143
|
@status.unblocking(users.join(','))
|
213
144
|
users.each do |user|
|
@@ -221,8 +152,7 @@ module Ayadn
|
|
221
152
|
|
222
153
|
def block(usernames)
|
223
154
|
begin
|
224
|
-
|
225
|
-
users = @workers.all_but_me(usernames)
|
155
|
+
users = get_all_usernames_but_me(usernames)
|
226
156
|
puts "\n"
|
227
157
|
@status.blocking(users.join(','))
|
228
158
|
users.each do |user|
|
@@ -236,22 +166,18 @@ module Ayadn
|
|
236
166
|
|
237
167
|
def repost(post_ids, options = {})
|
238
168
|
begin
|
239
|
-
ids = post_ids
|
240
|
-
|
241
|
-
@status.error_missing_post_id
|
242
|
-
exit
|
243
|
-
end
|
244
|
-
if options[:force]
|
245
|
-
Settings.global[:force] = true
|
246
|
-
else
|
247
|
-
ids.map! { |post_id| @workers.get_real_post_id(post_id) }
|
248
|
-
end
|
169
|
+
ids = get_posts_ids_or_exit(post_ids) { @status.error_missing_post_id }
|
170
|
+
ids = get_real_posts_ids_or_force(options, ids)
|
249
171
|
puts "\n"
|
250
172
|
ids.each do |post_id|
|
251
173
|
@status.reposting(post_id)
|
174
|
+
# Retrieve the post we want to repost
|
252
175
|
resp = @api.get_details(post_id)
|
176
|
+
# Verify it hasn't been already reposted by us
|
253
177
|
@check.already_reposted(resp)
|
178
|
+
# Maybe the post is already a repost by someone else?
|
254
179
|
id = @workers.get_original_id(post_id, resp)
|
180
|
+
# Repost then verify it has been done
|
255
181
|
@check.has_been_reposted(id, @api.repost(id))
|
256
182
|
end
|
257
183
|
rescue => e
|
@@ -261,16 +187,8 @@ module Ayadn
|
|
261
187
|
|
262
188
|
def unrepost(post_ids, options = {})
|
263
189
|
begin
|
264
|
-
ids = post_ids
|
265
|
-
|
266
|
-
@status.error_missing_post_id
|
267
|
-
exit
|
268
|
-
end
|
269
|
-
if options[:force]
|
270
|
-
Settings.global[:force] = true
|
271
|
-
else
|
272
|
-
ids.map! { |post_id| @workers.get_real_post_id(post_id) }
|
273
|
-
end
|
190
|
+
ids = get_posts_ids_or_exit(post_ids) { @status.error_missing_post_id }
|
191
|
+
ids = get_real_posts_ids_or_force(options, ids)
|
274
192
|
puts "\n"
|
275
193
|
ids.each do |post_id|
|
276
194
|
@status.unreposting(post_id)
|
@@ -287,16 +205,8 @@ module Ayadn
|
|
287
205
|
|
288
206
|
def unstar(post_ids, options = {})
|
289
207
|
begin
|
290
|
-
ids = post_ids
|
291
|
-
|
292
|
-
@status.error_missing_post_id
|
293
|
-
exit
|
294
|
-
end
|
295
|
-
if options[:force]
|
296
|
-
Settings.global[:force] = true
|
297
|
-
else
|
298
|
-
ids.map! { |post_id| @workers.get_real_post_id(post_id) }
|
299
|
-
end
|
208
|
+
ids = get_posts_ids_or_exit(post_ids) { @status.error_missing_post_id }
|
209
|
+
ids = get_real_posts_ids_or_force(options, ids)
|
300
210
|
puts "\n"
|
301
211
|
ids.each do |post_id|
|
302
212
|
@status.unstarring(post_id)
|
@@ -316,16 +226,8 @@ module Ayadn
|
|
316
226
|
|
317
227
|
def star(post_ids, options = {})
|
318
228
|
begin
|
319
|
-
ids = post_ids
|
320
|
-
|
321
|
-
@status.error_missing_post_id
|
322
|
-
exit
|
323
|
-
end
|
324
|
-
if options[:force]
|
325
|
-
Settings.global[:force] = true
|
326
|
-
else
|
327
|
-
ids.map! { |post_id| @workers.get_real_post_id(post_id) }
|
328
|
-
end
|
229
|
+
ids = get_posts_ids_or_exit(post_ids) { @status.error_missing_post_id }
|
230
|
+
ids = get_real_posts_ids_or_force(options, ids)
|
329
231
|
puts "\n"
|
330
232
|
ids.each do |post_id|
|
331
233
|
@status.starring(post_id)
|
@@ -341,7 +243,6 @@ module Ayadn
|
|
341
243
|
|
342
244
|
def hashtag(hashtag, options)
|
343
245
|
begin
|
344
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
345
246
|
search = Search.new(@api, @view, @workers)
|
346
247
|
search.hashtag(hashtag, options)
|
347
248
|
rescue => e
|
@@ -351,7 +252,6 @@ module Ayadn
|
|
351
252
|
|
352
253
|
def search(words, options)
|
353
254
|
begin
|
354
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
355
255
|
search = Search.new(@api, @view, @workers)
|
356
256
|
search.find(words, options)
|
357
257
|
rescue => e
|
@@ -359,53 +259,12 @@ module Ayadn
|
|
359
259
|
end
|
360
260
|
end
|
361
261
|
|
362
|
-
def followings(username, options)
|
363
|
-
begin
|
364
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
365
|
-
stream = Stream.new(@api, @view, @workers)
|
366
|
-
stream.followings(username, options)
|
367
|
-
rescue => e
|
368
|
-
Errors.global_error({error: e, caller: caller, data: [username, options]})
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
def followers(username, options)
|
373
|
-
begin
|
374
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
375
|
-
stream = Stream.new(@api, @view, @workers)
|
376
|
-
stream.followers(username, options)
|
377
|
-
rescue => e
|
378
|
-
Errors.global_error({error: e, caller: caller, data: [username, options]})
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
def muted(options)
|
383
|
-
begin
|
384
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
385
|
-
stream = Stream.new(@api, @view, @workers)
|
386
|
-
stream.muted(options)
|
387
|
-
rescue => e
|
388
|
-
Errors.global_error({error: e, caller: caller, data: [options]})
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
def blocked(options)
|
393
|
-
begin
|
394
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
395
|
-
stream = Stream.new(@api, @view, @workers)
|
396
|
-
stream.blocked(options)
|
397
|
-
rescue => e
|
398
|
-
Errors.global_error({error: e, caller: caller, data: [options]})
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
262
|
def view_settings(options)
|
403
263
|
begin
|
404
264
|
if options[:raw]
|
405
|
-
jj JSON.parse(Settings.
|
406
|
-
jj JSON.parse(Settings.options.to_json)
|
265
|
+
jj JSON.parse(Settings.options.to_h.to_json)
|
407
266
|
else
|
408
|
-
Settings.options
|
267
|
+
Settings.options.timeline.compact = true if options[:compact]
|
409
268
|
@view.show_settings
|
410
269
|
end
|
411
270
|
rescue => e
|
@@ -429,7 +288,7 @@ module Ayadn
|
|
429
288
|
|
430
289
|
def userinfo(username, options = {})
|
431
290
|
begin
|
432
|
-
Settings.options
|
291
|
+
Settings.options.timeline.compact = true if options[:compact]
|
433
292
|
@check.no_username(username)
|
434
293
|
usernames = @workers.add_arobases_to_usernames(username)
|
435
294
|
usernames.each.with_index do |username, index|
|
@@ -437,11 +296,11 @@ module Ayadn
|
|
437
296
|
@view.show_raw(@api.get_user(username), options)
|
438
297
|
else
|
439
298
|
@view.downloading if index == 0
|
440
|
-
|
441
|
-
|
442
|
-
@check.same_username(
|
299
|
+
user_object = UserObject.new(@api.get_user(username), username)
|
300
|
+
# Is it us? If yes, get *our* info
|
301
|
+
@check.same_username(user_object) ? token = @api.get_token_info['data'] : token = nil
|
443
302
|
@view.clear_screen if index == 0
|
444
|
-
@view.infos(
|
303
|
+
@view.infos(user_object, token)
|
445
304
|
end
|
446
305
|
end
|
447
306
|
rescue => e
|
@@ -452,12 +311,8 @@ module Ayadn
|
|
452
311
|
def postinfo(post_id, options)
|
453
312
|
begin
|
454
313
|
@check.bad_post_id(post_id)
|
455
|
-
Settings.options
|
456
|
-
|
457
|
-
Settings.global[:force] = true
|
458
|
-
else
|
459
|
-
post_id = @workers.get_real_post_id(post_id)
|
460
|
-
end
|
314
|
+
Settings.options.timeline.compact = true if options[:compact]
|
315
|
+
post_id = get_real_post_id_or_force(options, post_id)
|
461
316
|
details = lambda { @api.get_details(post_id, options) }
|
462
317
|
if options[:raw]
|
463
318
|
@view.show_raw(details.call, options)
|
@@ -465,32 +320,36 @@ module Ayadn
|
|
465
320
|
end
|
466
321
|
@view.clear_screen
|
467
322
|
response = details.call
|
468
|
-
@check.
|
469
|
-
|
323
|
+
@check.no_details(response, post_id)
|
324
|
+
|
325
|
+
post_object = PostObject.new(response["data"])
|
470
326
|
|
471
|
-
if
|
472
|
-
@status.user_404(
|
327
|
+
if post_object.is_deleted
|
328
|
+
@status.user_404(post_object.id)
|
473
329
|
Errors.global_error({error: "user 404", caller: caller, data: [post_id, options]})
|
474
330
|
end
|
475
331
|
|
476
|
-
response = @api.get_user("@#{
|
477
|
-
|
478
|
-
|
332
|
+
response = @api.get_user("@#{post_object.user.username}")
|
333
|
+
user_object = UserObject.new(response, post_object.user.username)
|
334
|
+
|
479
335
|
@status.post_info
|
480
|
-
@view.show_simple_post([
|
481
|
-
puts "\n" if Settings.options
|
336
|
+
@view.show_simple_post([post_object], options)
|
337
|
+
puts "\n" if Settings.options.timeline.compact
|
482
338
|
@status.say_info "author"
|
483
|
-
puts "\n" unless Settings.options
|
484
|
-
|
485
|
-
|
339
|
+
puts "\n" unless Settings.options.timeline.compact
|
340
|
+
# Is it us? ...
|
341
|
+
if user_object.username == Settings.config.identity.username
|
342
|
+
@view.show_userinfos(post_object.user, @api.get_token_info['data'], true)
|
486
343
|
else
|
487
|
-
@view.show_userinfos(
|
344
|
+
@view.show_userinfos(post_object.user, nil, true)
|
488
345
|
end
|
489
|
-
|
346
|
+
|
347
|
+
if !post_object.repost_of.nil?
|
490
348
|
@status.repost_info
|
491
|
-
|
492
|
-
|
493
|
-
|
349
|
+
# If we ask infos for a reposted post, fetch the original instead
|
350
|
+
Errors.repost(post_id, post_object.repost_of.id)
|
351
|
+
@view.show_simple_post([post_object.repost_of], options)
|
352
|
+
puts "\n" if Settings.options.timeline.compact
|
494
353
|
end
|
495
354
|
rescue => e
|
496
355
|
Errors.global_error({error: e, caller: caller, data: [post_id, options]})
|
@@ -526,6 +385,7 @@ module Ayadn
|
|
526
385
|
|
527
386
|
def channels options
|
528
387
|
begin
|
388
|
+
# Input could be channel IDs or channel aliases
|
529
389
|
channels = if options[:id]
|
530
390
|
channel_id = options[:id].map {|id| @workers.get_channel_id_from_alias(id)}
|
531
391
|
lambda { @api.get_channel(channel_id, options) }
|
@@ -533,42 +393,32 @@ module Ayadn
|
|
533
393
|
lambda { @api.get_channels }
|
534
394
|
end
|
535
395
|
if options[:raw]
|
536
|
-
@view.
|
396
|
+
@view.show_direct_raw(channels.call)
|
537
397
|
exit
|
538
398
|
else
|
539
399
|
@view.downloading
|
540
400
|
resp = channels.call
|
541
401
|
@view.clear_screen
|
542
|
-
|
402
|
+
channels = resp["data"].map { |ch| ChannelObject.new(ch) }
|
403
|
+
@view.show_channels(channels, options)
|
543
404
|
end
|
544
405
|
rescue => e
|
545
406
|
Errors.global_error({error: e, caller: caller, data: [options]})
|
546
407
|
end
|
547
408
|
end
|
548
409
|
|
549
|
-
def messages(channel_id, options)
|
550
|
-
begin
|
551
|
-
Settings.options[:timeline][:compact] = true if options[:compact] == true
|
552
|
-
stream = Stream.new(@api, @view, @workers)
|
553
|
-
stream.messages(channel_id, options)
|
554
|
-
rescue => e
|
555
|
-
Errors.global_error({error: e, caller: caller, data: [channel_id, options]})
|
556
|
-
end
|
557
|
-
end
|
558
|
-
|
559
410
|
def messages_unread(options)
|
560
411
|
begin
|
561
|
-
Settings.options
|
562
|
-
if options[:silent]
|
563
|
-
Settings.options[:marker][:messages] = false
|
564
|
-
end
|
412
|
+
Settings.options.timeline.compact = true if options[:compact]
|
413
|
+
Settings.options.marker.messages = false if options[:silent] # Option to not mark the messages as read
|
565
414
|
puts "\n"
|
566
415
|
@status.say_nocolor :searching, "channels with unread PMs"
|
567
|
-
|
416
|
+
channels_objects = @api.get_channels['data'].map { |obj| ChannelObject.new(obj) }
|
568
417
|
unread_channels = []
|
569
|
-
|
570
|
-
|
571
|
-
|
418
|
+
channels_objects.each do |ch|
|
419
|
+
# Channels can be of many types, PMs are only one type
|
420
|
+
if ch.type == "net.app.core.pm" && ch.has_unread
|
421
|
+
unread_channels << ch.id
|
572
422
|
end
|
573
423
|
end
|
574
424
|
if unread_channels.empty?
|
@@ -578,6 +428,7 @@ module Ayadn
|
|
578
428
|
unread_messages = {}
|
579
429
|
unread_channels.reverse.each do |id|
|
580
430
|
@status.say_nocolor :downloading, "messages from channel #{id}"
|
431
|
+
# Find the last time we've done this
|
581
432
|
since = Databases.find_last_id_from("channel:#{id}")
|
582
433
|
unless since.nil?
|
583
434
|
api_options = {count: 20, since_id: since}
|
@@ -585,18 +436,19 @@ module Ayadn
|
|
585
436
|
api_options = {count: 20}
|
586
437
|
end
|
587
438
|
ch = @api.get_messages(id, api_options)
|
439
|
+
# Find the last message seen and the last message in the channel
|
588
440
|
last_read_id = ch['meta']['marker']['last_read_id'].to_i
|
589
441
|
last_message_id = ch['meta']['max_id']
|
590
|
-
messages = []
|
591
|
-
ch['data'].each do |msg|
|
592
|
-
messages << msg if msg['id'].to_i > last_read_id
|
593
|
-
end
|
442
|
+
messages = ch['data'].map { |msg| msg if msg['id'].to_i > last_read_id }
|
594
443
|
unread_messages[id] = [messages, last_message_id]
|
595
444
|
end
|
596
|
-
|
445
|
+
# If we want to mark the messages as read
|
446
|
+
if Settings.options.marker.messages
|
597
447
|
unread_messages.each do |k,v|
|
598
448
|
name = "channel:#{k}"
|
449
|
+
# Save the reading position locally
|
599
450
|
Databases.pagination_insert(name, v[1])
|
451
|
+
# Mark as read
|
600
452
|
resp = @api.update_marker(name, v[1])
|
601
453
|
res = JSON.parse(resp)
|
602
454
|
if res['meta']['code'] != 200
|
@@ -609,9 +461,10 @@ module Ayadn
|
|
609
461
|
@view.clear_screen
|
610
462
|
unread_messages.each do |k,v|
|
611
463
|
@status.unread_from_channel(k)
|
612
|
-
|
464
|
+
messages_objects = v[0].map { |post_hash| PostObject.new(post_hash) }
|
465
|
+
@view.show_messages(messages_objects)
|
613
466
|
end
|
614
|
-
puts "\n" if Settings.options
|
467
|
+
puts "\n" if Settings.options.timeline.compact
|
615
468
|
rescue => e
|
616
469
|
Errors.global_error({error: e, caller: caller, data: [options]})
|
617
470
|
end
|
@@ -628,29 +481,32 @@ module Ayadn
|
|
628
481
|
end
|
629
482
|
begin
|
630
483
|
@check.bad_post_id(post_id)
|
631
|
-
Settings.options
|
632
|
-
|
633
|
-
Settings.global[:force] = true
|
634
|
-
else
|
635
|
-
post_id = @workers.get_real_post_id(post_id)
|
636
|
-
end
|
484
|
+
Settings.options.timeline.compact = true if options[:compact]
|
485
|
+
post_id = get_real_post_id_or_force(options, post_id)
|
637
486
|
@view.downloading
|
638
|
-
|
487
|
+
# Get the details from the post we want to send to Pinboard
|
488
|
+
# resp = @api.get_details(post_id)['data']
|
639
489
|
@view.clear_screen
|
640
|
-
links
|
641
|
-
|
490
|
+
# Extract links from the post
|
491
|
+
post_object = PostObject.new(@api.get_details(post_id)['data'])
|
492
|
+
links = @workers.extract_links(post_object)
|
493
|
+
# In case the post has no text, to prevent an error
|
494
|
+
post_object.text.nil? ? text = "" : text = post_object.text
|
495
|
+
# The first tag is always "ADN"
|
642
496
|
usertags << "ADN"
|
643
|
-
handle = "@" +
|
497
|
+
handle = "@" + post_object.user.username
|
644
498
|
post_text = "From: #{handle} -- Text: #{text} -- Links: #{links.join(" ")}"
|
645
499
|
pinner = Ayadn::PinBoard.new
|
646
500
|
unless pinner.has_credentials_file?
|
501
|
+
# No Pinboard account registered? Ask for one.
|
647
502
|
@status.no_pin_creds
|
648
|
-
pinner.ask_credentials
|
503
|
+
pinner.ask_credentials(@status)
|
649
504
|
@status.pin_creds_saved
|
650
505
|
end
|
506
|
+
# Get stored credentials
|
651
507
|
credentials = pinner.load_credentials
|
652
508
|
maker = Struct.new(:username, :password, :url, :tags, :text, :description)
|
653
|
-
bookmark = maker.new(credentials[0], credentials[1],
|
509
|
+
bookmark = maker.new(credentials[0], credentials[1], post_object.canonical_url, usertags.join(","), post_text, post_object.canonical_url)
|
654
510
|
@status.saving_pin
|
655
511
|
pinner.pin(bookmark)
|
656
512
|
@status.done
|
@@ -663,7 +519,7 @@ module Ayadn
|
|
663
519
|
begin
|
664
520
|
@view.clear_screen
|
665
521
|
@status.auto
|
666
|
-
Post.new.auto_readline
|
522
|
+
Post.new(@status).auto_readline
|
667
523
|
rescue => e
|
668
524
|
Errors.global_error({error: e, caller: caller, data: [options]})
|
669
525
|
end
|
@@ -671,18 +527,8 @@ module Ayadn
|
|
671
527
|
|
672
528
|
def post(args, options)
|
673
529
|
begin
|
674
|
-
Settings.options
|
675
|
-
|
676
|
-
if options[:poster] # Returns the same options hash + poster embed
|
677
|
-
settings = options.dup
|
678
|
-
options = NowWatching.new.get_poster(settings[:poster], settings)
|
679
|
-
end
|
680
|
-
text = args.join(" ")
|
681
|
-
writer.post_size_error(text) if writer.post_size_ok?(text) == false
|
682
|
-
@view.clear_screen
|
683
|
-
@status.posting
|
684
|
-
resp = writer.post({options: options, text: text})
|
685
|
-
save_and_view(resp)
|
530
|
+
Settings.options.timeline.compact = true if options[:compact]
|
531
|
+
post_and_show(Post.new(@status), args.join(" "), options)
|
686
532
|
rescue => e
|
687
533
|
Errors.global_error({error: e, caller: caller, data: [args, options]})
|
688
534
|
end
|
@@ -690,112 +536,91 @@ module Ayadn
|
|
690
536
|
|
691
537
|
def write(options)
|
692
538
|
begin
|
693
|
-
Settings.options
|
694
|
-
writer = Post.new
|
539
|
+
Settings.options.timeline.compact = true if options[:compact]
|
540
|
+
writer = Post.new(@status)
|
695
541
|
@status.writing
|
696
542
|
@status.post
|
697
|
-
|
698
|
-
text
|
699
|
-
writer.post_size_error(text) if writer.post_size_ok?(text) == false
|
700
|
-
@view.clear_screen
|
701
|
-
@status.posting
|
702
|
-
if options[:poster]
|
703
|
-
settings = options.dup
|
704
|
-
options = NowWatching.new.get_poster(settings[:poster], settings)
|
705
|
-
end
|
706
|
-
resp = writer.post({options: options, text: text})
|
707
|
-
save_and_view(resp)
|
543
|
+
text = writer.compose.join("\n")
|
544
|
+
post_and_show(writer, text, options)
|
708
545
|
rescue => e
|
709
546
|
Errors.global_error({error: e, caller: caller, data: [text, options]})
|
710
547
|
end
|
711
548
|
end
|
712
549
|
|
713
550
|
def pmess(username, options = {})
|
714
|
-
|
715
|
-
Settings.options
|
716
|
-
if options[:silent]
|
717
|
-
Settings.options[:marker][:messages] = false
|
718
|
-
end
|
551
|
+
begin
|
552
|
+
Settings.options.timeline.compact = true if options[:compact]
|
553
|
+
Settings.options.marker.messages = false if options[:silent]
|
719
554
|
@check.no_username(username)
|
720
555
|
username = [@workers.add_arobase(username)]
|
721
|
-
|
556
|
+
writer = Post.new(@status)
|
722
557
|
@status.message_from(username)
|
723
|
-
|
724
|
-
|
725
|
-
text
|
726
|
-
|
727
|
-
@view.clear_screen
|
558
|
+
@status.message
|
559
|
+
text = writer.compose.join("\n")
|
560
|
+
writer.message_size_error(text) if !writer.message_size_ok?(text)
|
561
|
+
@view.clear_screen
|
728
562
|
@status.posting
|
729
|
-
if options[:poster]
|
730
|
-
settings = options.dup
|
731
|
-
options = NowWatching.new.get_poster(settings[:poster], settings)
|
732
|
-
end
|
733
563
|
resp = writer.pm({options: options, text: text, username: username})
|
734
|
-
|
564
|
+
post_object = PostObject.new(resp["data"])
|
565
|
+
if Settings.options.marker.messages
|
735
566
|
if resp['meta']['code'] == 200
|
736
|
-
|
737
|
-
name
|
738
|
-
|
739
|
-
marked = @api.update_marker(name, data['id'])
|
567
|
+
name = "channel:#{post_object.channel_id}"
|
568
|
+
Databases.pagination_insert(name, post_object.id)
|
569
|
+
marked = @api.update_marker(name, post_object.id)
|
740
570
|
updated = JSON.parse(marked)
|
741
571
|
if updated['meta']['code'] != 200
|
742
|
-
raise "couldn't update channel #{
|
572
|
+
raise "couldn't update channel #{post_object.channel_id} as read"
|
743
573
|
end
|
744
574
|
end
|
745
575
|
end
|
746
|
-
FileOps.save_message(resp) if Settings.options
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
576
|
+
FileOps.save_message(resp) if Settings.options.backup.messages
|
577
|
+
@view.clear_screen
|
578
|
+
@status.yourmessage(username[0])
|
579
|
+
@view.show_simple_post([post_object])
|
580
|
+
rescue => e
|
751
581
|
Errors.global_error({error: e, caller: caller, data: [username, options]})
|
752
|
-
|
582
|
+
end
|
753
583
|
end
|
754
584
|
|
755
585
|
def reply(post_id, options = {})
|
756
586
|
begin
|
757
|
-
Settings.options
|
587
|
+
Settings.options.timeline.compact = true if options[:compact]
|
758
588
|
@check.bad_post_id(post_id)
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
@status.replying_to(post_id)
|
765
|
-
replied_to = @api.get_details(post_id)
|
766
|
-
@check.no_post(replied_to, post_id)
|
589
|
+
post_id = get_real_post_id_or_force(options, post_id)
|
590
|
+
@status.replying_to(post_id)
|
591
|
+
replied_to = @api.get_details(post_id)
|
592
|
+
@check.no_details(replied_to, post_id)
|
593
|
+
# API specifies to always reply to the original post of a reposted post. We offer the user an option to not.
|
767
594
|
unless options[:noredirect]
|
768
595
|
post_id = @workers.get_original_id(post_id, replied_to)
|
769
596
|
end
|
770
597
|
if replied_to['data']['repost_of']
|
771
598
|
if post_id == replied_to['data']['repost_of']['id']
|
772
599
|
replied_to = @api.get_details(post_id)
|
773
|
-
@check.
|
600
|
+
@check.no_details(replied_to, post_id)
|
774
601
|
end
|
775
602
|
end
|
776
603
|
# ----
|
777
|
-
writer = Post.new
|
604
|
+
writer = Post.new(@status)
|
778
605
|
@status.writing
|
779
606
|
@status.reply
|
780
|
-
|
781
|
-
|
782
|
-
# text length is tested in Post class for the reply command
|
607
|
+
text = writer.compose.join("\n")
|
608
|
+
# Text length is tested in Post class for the reply command
|
783
609
|
@view.clear_screen
|
784
|
-
replied_to = @workers.build_posts([replied_to['data']])
|
785
|
-
if options[:poster]
|
786
|
-
settings = options.dup
|
787
|
-
options = NowWatching.new.get_poster(settings[:poster], settings)
|
788
|
-
end
|
610
|
+
replied_to = @workers.build_posts([PostObject.new(replied_to['data'])])[0]
|
789
611
|
resp = writer.reply({options: options, text: text, id: post_id, reply_to: replied_to})
|
790
|
-
FileOps.save_post(resp) if Settings.options
|
612
|
+
FileOps.save_post(resp) if Settings.options.backup.posts
|
791
613
|
# ----
|
614
|
+
# "options" from CLI is immutable, we have to make a copy to add items
|
792
615
|
options = options.dup
|
793
616
|
unless resp['data']['reply_to'].nil?
|
794
617
|
options[:reply_to] = resp['data']['reply_to'].to_i
|
795
618
|
end
|
796
619
|
options[:post_id] = resp['data']['id'].to_i
|
797
|
-
@
|
798
|
-
|
620
|
+
stream = @api.get_convo(post_id)
|
621
|
+
stream_object = StreamObject.new(stream)
|
622
|
+
@view.render(stream_object, options)
|
623
|
+
puts "\n" if Settings.options.timeline.compact && !options[:raw]
|
799
624
|
rescue => e
|
800
625
|
Errors.global_error({error: e, caller: caller, data: [post_id, options]})
|
801
626
|
end
|
@@ -803,48 +628,41 @@ module Ayadn
|
|
803
628
|
|
804
629
|
def send_to_channel(channel_id, options = {})
|
805
630
|
begin
|
806
|
-
Settings.options
|
807
|
-
if options[:silent]
|
808
|
-
Settings.options[:marker][:messages] = false
|
809
|
-
end
|
631
|
+
Settings.options.timeline.compact = true if options[:compact]
|
632
|
+
Settings.options.marker.messages = false if options[:silent]
|
810
633
|
channel_id = @workers.get_channel_id_from_alias(channel_id)
|
811
|
-
writer = Post.new
|
634
|
+
writer = Post.new(@status)
|
812
635
|
@status.writing
|
813
636
|
@status.message
|
814
|
-
|
815
|
-
text
|
816
|
-
writer.message_size_error(text) if writer.message_size_ok?(text) == false
|
637
|
+
text = writer.compose.join("\n")
|
638
|
+
writer.message_size_error(text) if !writer.message_size_ok?(text)
|
817
639
|
@view.clear_screen
|
818
640
|
@status.posting
|
819
|
-
if options[:poster]
|
820
|
-
settings = options.dup
|
821
|
-
options = NowWatching.new.get_poster(settings[:poster], settings)
|
822
|
-
end
|
823
641
|
resp = writer.message({options: options, id: channel_id, text: text})
|
824
|
-
|
642
|
+
post_object = PostObject.new(resp["data"])
|
643
|
+
if Settings.options.marker.messages
|
825
644
|
if resp['meta']['code'] == 200
|
826
|
-
|
827
|
-
name
|
828
|
-
|
829
|
-
marked = @api.update_marker(name, data['id'])
|
645
|
+
name = "channel:#{post_object.channel_id}"
|
646
|
+
Databases.pagination_insert(name, post_object.id)
|
647
|
+
marked = @api.update_marker(name, post_object.id)
|
830
648
|
updated = JSON.parse(marked)
|
831
649
|
if updated['meta']['code'] != 200
|
832
|
-
raise "couldn't update channel #{
|
650
|
+
raise "couldn't update channel #{post_object.channel_id} as read"
|
833
651
|
end
|
834
652
|
end
|
835
653
|
end
|
836
|
-
FileOps.save_message(resp) if Settings.options
|
654
|
+
FileOps.save_message(resp) if Settings.options.backup.messages
|
837
655
|
@view.clear_screen
|
838
656
|
@status.yourpost
|
839
|
-
@view.
|
657
|
+
@view.show_simple_post([post_object])
|
840
658
|
rescue => e
|
841
659
|
Errors.global_error({error: e, caller: caller, data: [channel_id, options]})
|
842
660
|
end
|
843
661
|
end
|
844
662
|
|
845
663
|
def nowplaying(options = {})
|
846
|
-
Settings.options
|
847
|
-
np = NowPlaying.new(@api, @view, @workers, options)
|
664
|
+
Settings.options.timeline.compact = true if options[:compact]
|
665
|
+
np = NowPlaying.new(@api, @view, @workers, @status, options)
|
848
666
|
if options[:lastfm]
|
849
667
|
np.lastfm(options)
|
850
668
|
elsif options[:deezer]
|
@@ -854,62 +672,54 @@ module Ayadn
|
|
854
672
|
end
|
855
673
|
end
|
856
674
|
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
nw.post(args, options)
|
866
|
-
rescue ArgumentError => e
|
867
|
-
@status.no_movie
|
868
|
-
rescue => e
|
869
|
-
@status.wtf
|
870
|
-
Errors.global_error({error: e, caller: caller, data: [args, options]})
|
871
|
-
end
|
675
|
+
private
|
676
|
+
|
677
|
+
def save_and_view(resp)
|
678
|
+
FileOps.save_post(resp) if Settings.options.backup.posts
|
679
|
+
@view.clear_screen
|
680
|
+
@status.yourpost
|
681
|
+
puts "\n\n"
|
682
|
+
@view.show_posted(resp)
|
872
683
|
end
|
873
684
|
|
874
|
-
def
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
exit
|
880
|
-
end
|
881
|
-
client = TvShow.new
|
882
|
-
show_obj = if options[:alt]
|
883
|
-
client.find_alt(args.join(' '))
|
884
|
-
else
|
885
|
-
client.find(args.join(' '))
|
886
|
-
end
|
887
|
-
candidate = client.create_details(show_obj)
|
888
|
-
candidate.ok ? candidate.post(options) : candidate.cancel
|
889
|
-
rescue => e
|
890
|
-
@status.wtf
|
891
|
-
Errors.global_error({error: e, caller: caller, data: [args, options]})
|
685
|
+
def get_posts_ids_or_exit ids
|
686
|
+
int_ids = ids.select { |post_id| post_id.is_integer? }
|
687
|
+
if int_ids.empty?
|
688
|
+
yield
|
689
|
+
exit
|
892
690
|
end
|
691
|
+
int_ids
|
893
692
|
end
|
894
693
|
|
895
|
-
def
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
694
|
+
def get_all_usernames_but_me usernames
|
695
|
+
@check.no_username(usernames)
|
696
|
+
@workers.all_but_me(usernames)
|
697
|
+
end
|
698
|
+
|
699
|
+
def get_real_posts_ids_or_force options, posts_ids
|
700
|
+
if options[:force]
|
701
|
+
Settings.global.force = true
|
702
|
+
posts_ids
|
703
|
+
else
|
704
|
+
posts_ids.map { |post_id| @workers.get_real_post_id(post_id) }
|
902
705
|
end
|
903
706
|
end
|
904
707
|
|
905
|
-
|
708
|
+
def get_real_post_id_or_force options, post_id
|
709
|
+
if options[:force]
|
710
|
+
Settings.global.force = true
|
711
|
+
post_id
|
712
|
+
else
|
713
|
+
@workers.get_real_post_id(post_id)
|
714
|
+
end
|
715
|
+
end
|
906
716
|
|
907
|
-
def
|
908
|
-
|
717
|
+
def post_and_show writer, text, options
|
718
|
+
writer.post_size_error(text) if !writer.post_size_ok?(text)
|
909
719
|
@view.clear_screen
|
910
|
-
@status.
|
911
|
-
|
912
|
-
|
720
|
+
@status.posting
|
721
|
+
resp = writer.post({options: options, text: text})
|
722
|
+
save_and_view(resp)
|
913
723
|
end
|
914
724
|
|
915
725
|
end
|