flumtter 5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/flumtter +5 -0
- data/flumtter.gemspec +31 -0
- data/lib/flumtter.rb +2 -0
- data/lib/flumtter/app/core/account_selector.rb +88 -0
- data/lib/flumtter/app/core/client.rb +148 -0
- data/lib/flumtter/app/core/command.rb +24 -0
- data/lib/flumtter/app/core/command/dm.rb +12 -0
- data/lib/flumtter/app/core/command/tweet.rb +24 -0
- data/lib/flumtter/app/core/command/user.rb +52 -0
- data/lib/flumtter/app/core/command/userlist.rb +8 -0
- data/lib/flumtter/app/core/core.rb +58 -0
- data/lib/flumtter/app/core/curses.rb +90 -0
- data/lib/flumtter/app/core/hash.rb +29 -0
- data/lib/flumtter/app/core/initializer.rb +28 -0
- data/lib/flumtter/app/core/keyboard.rb +54 -0
- data/lib/flumtter/app/core/plugins.rb +27 -0
- data/lib/flumtter/app/core/string.rb +148 -0
- data/lib/flumtter/app/core/terminal.rb +13 -0
- data/lib/flumtter/app/core/thread.rb +29 -0
- data/lib/flumtter/app/core/toast.rb +26 -0
- data/lib/flumtter/app/core/util.rb +107 -0
- data/lib/flumtter/app/core/windows/base.rb +16 -0
- data/lib/flumtter/app/core/windows/buf_window.rb +194 -0
- data/lib/flumtter/app/core/windows/dialog.rb +62 -0
- data/lib/flumtter/app/core/windows/dmbase.rb +28 -0
- data/lib/flumtter/app/core/windows/dynamic_view.rb +43 -0
- data/lib/flumtter/app/core/windows/favorite.rb +31 -0
- data/lib/flumtter/app/core/windows/follower.rb +20 -0
- data/lib/flumtter/app/core/windows/following.rb +20 -0
- data/lib/flumtter/app/core/windows/mention.rb +29 -0
- data/lib/flumtter/app/core/windows/popup.rb +35 -0
- data/lib/flumtter/app/core/windows/tweet.rb +31 -0
- data/lib/flumtter/app/core/windows/tweetbase.rb +24 -0
- data/lib/flumtter/app/core/windows/userbase.rb +43 -0
- data/lib/flumtter/app/main.rb +3 -0
- data/lib/flumtter/app/plugins/commands.rb +15 -0
- data/lib/flumtter/app/plugins/commands/account_changer.rb +9 -0
- data/lib/flumtter/app/plugins/commands/change_profile.rb +69 -0
- data/lib/flumtter/app/plugins/commands/conversation.rb +39 -0
- data/lib/flumtter/app/plugins/commands/delete.rb +26 -0
- data/lib/flumtter/app/plugins/commands/directmessage.rb +35 -0
- data/lib/flumtter/app/plugins/commands/directmessages.rb +33 -0
- data/lib/flumtter/app/plugins/commands/favorite.rb +22 -0
- data/lib/flumtter/app/plugins/commands/mention.rb +7 -0
- data/lib/flumtter/app/plugins/commands/new_tweet.rb +17 -0
- data/lib/flumtter/app/plugins/commands/reply.rb +26 -0
- data/lib/flumtter/app/plugins/commands/retweet.rb +30 -0
- data/lib/flumtter/app/plugins/commands/unfavorite.rb +26 -0
- data/lib/flumtter/app/plugins/commands/user.rb +77 -0
- data/lib/flumtter/app/plugins/commands/utility.rb +17 -0
- data/lib/flumtter/app/plugins/load.rb +16 -0
- data/lib/flumtter/app/plugins/pry.rb +12 -0
- data/lib/flumtter/app/plugins/timeline.rb +42 -0
- data/lib/flumtter/app/plugins/timeline/base.rb +74 -0
- data/lib/flumtter/app/plugins/timeline/deleted_tweet.rb +23 -0
- data/lib/flumtter/app/plugins/timeline/dm.rb +23 -0
- data/lib/flumtter/app/plugins/timeline/event.rb +11 -0
- data/lib/flumtter/app/plugins/timeline/fav.rb +43 -0
- data/lib/flumtter/app/plugins/timeline/tweet.rb +51 -0
- data/lib/flumtter/app/plugins/toast.rb +45 -0
- data/lib/flumtter/version.rb +3 -0
- metadata +213 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module Flumtter
|
2
|
+
class Window::DMBase < Window::Buf::Element
|
3
|
+
def id
|
4
|
+
@object.id
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def user
|
9
|
+
"#{@object.sender.name} (@#{@object.sender.screen_name})"
|
10
|
+
end
|
11
|
+
|
12
|
+
def created_at
|
13
|
+
@object.created_at.strftime("%Y/%m/%d %H:%M:%S")
|
14
|
+
end
|
15
|
+
|
16
|
+
def header
|
17
|
+
"#{@index} ".ljust(width, ?-, "@#{@object.sender.screen_name} => @#{@object.recipient.screen_name}")
|
18
|
+
end
|
19
|
+
|
20
|
+
def body
|
21
|
+
@object.text.nl
|
22
|
+
end
|
23
|
+
|
24
|
+
def footer
|
25
|
+
created_at
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
class DynamicView < Dialog
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
@hight += 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def dynamic_view(&blk)
|
12
|
+
@view = blk
|
13
|
+
end
|
14
|
+
|
15
|
+
def show(recall=false)
|
16
|
+
Dispel::Screen.open do |screen|
|
17
|
+
view = @view.nil? ? "" : @view.call
|
18
|
+
Dispel::Window.open(@hight + (view.nil? ? 0 : view.size_of_lines), @width, 0, 0) do |win|
|
19
|
+
win.box(?|,?-,?*)
|
20
|
+
win.setpos(win.cury+2, win.curx+1)
|
21
|
+
win.addstr @title.title
|
22
|
+
win.setpos(win.cury+1, 1)
|
23
|
+
win.addstr "¯"*(@title.title.size+2)
|
24
|
+
|
25
|
+
add_multiline_str(win, @body)
|
26
|
+
win.setpos(win.cury+1, 1)
|
27
|
+
add_multiline_str(win, view)
|
28
|
+
|
29
|
+
win.setpos(win.cury+2, 1)
|
30
|
+
win.addstr "help: ?".rjust(win.maxx - 2)
|
31
|
+
win.setpos(win.cury+1, 1)
|
32
|
+
call getstr(win)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue Dispel::Recall
|
36
|
+
show(recall)
|
37
|
+
rescue Dispel::NoCommandError => e
|
38
|
+
Window::Popup::Error.new(e.class.to_s).show
|
39
|
+
show(recall) if recall
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module Window
|
3
|
+
class FavoriteBuf < Buf::Buf
|
4
|
+
Options = {count: 50}
|
5
|
+
|
6
|
+
def initialize(user, twitter)
|
7
|
+
@twitter = twitter
|
8
|
+
@user = user
|
9
|
+
super(TweetBase)
|
10
|
+
end
|
11
|
+
|
12
|
+
def prefetch
|
13
|
+
adds(
|
14
|
+
@twitter.rest.favorites(
|
15
|
+
@user.id,
|
16
|
+
@buf.last.nil? ? Options : Options.merge(max_id: @buf.last.id-1)
|
17
|
+
)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Favorite < Buf::Screen
|
23
|
+
include Command::Tweet
|
24
|
+
|
25
|
+
def initialize(user, twitter)
|
26
|
+
super(FavoriteBuf.new(user, twitter), "#{user.screen_name}'s Favorites")
|
27
|
+
add_command(twitter)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'userbase'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
class FollowerBuf < UserBuf
|
6
|
+
def prefetch
|
7
|
+
@ids ||= @twitter.rest.follower_ids(@user.id).to_a
|
8
|
+
adds(
|
9
|
+
@twitter.rest.users @ids.pop(100)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Follower < User
|
15
|
+
def initialize(user, twitter)
|
16
|
+
super(FollowerBuf.new(user, twitter), "#{user.screen_name}'s Follower", twitter)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'userbase'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
class FollowingBuf < UserBuf
|
6
|
+
def prefetch
|
7
|
+
@ids ||= @twitter.rest.friend_ids(@user.id).to_a
|
8
|
+
adds(
|
9
|
+
@twitter.rest.users @ids.pop(100)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Following < User
|
15
|
+
def initialize(user, twitter)
|
16
|
+
super(FollowingBuf.new(user, twitter), "#{user.screen_name}'s Following", twitter)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module Window
|
3
|
+
class MentionBuf < Buf::Buf
|
4
|
+
Options = {count: 50}
|
5
|
+
|
6
|
+
def initialize(twitter)
|
7
|
+
@twitter = twitter
|
8
|
+
super(TweetBase)
|
9
|
+
end
|
10
|
+
|
11
|
+
def prefetch
|
12
|
+
adds(
|
13
|
+
@twitter.rest.mentions(
|
14
|
+
@buf.last.nil? ? Options : Options.merge(max_id: @buf.last.id-1)
|
15
|
+
)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Mention < Buf::Screen
|
21
|
+
include Command::Tweet
|
22
|
+
|
23
|
+
def initialize(twitter)
|
24
|
+
super(MentionBuf.new(twitter), "#{twitter.account.screen_name}'s Mentions")
|
25
|
+
add_command(twitter)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
class Popup < Base
|
6
|
+
def show
|
7
|
+
Dispel::Screen.open do |screen|
|
8
|
+
Dispel::Window.open(@hight, @width, 0, 0) do |win|
|
9
|
+
win.box(?|,?-,?*)
|
10
|
+
win.setpos(win.cury+2, win.curx+1)
|
11
|
+
win.addstr @title.title
|
12
|
+
win.setpos(win.cury+1, 1)
|
13
|
+
win.addstr "¯"*(@title.title.size+2)
|
14
|
+
|
15
|
+
add_multiline_str(win, @body)
|
16
|
+
|
17
|
+
win.getch
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Popup::Error < Popup
|
24
|
+
def initialize(body)
|
25
|
+
super("Error", body)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Popup::Success < Popup
|
30
|
+
def initialize(body)
|
31
|
+
super("Success", body)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module Window
|
3
|
+
class TweetBuf < Buf::Buf
|
4
|
+
Options = {count: 50}
|
5
|
+
|
6
|
+
def initialize(user, twitter)
|
7
|
+
@twitter = twitter
|
8
|
+
@user = user
|
9
|
+
super(TweetBase)
|
10
|
+
end
|
11
|
+
|
12
|
+
def prefetch
|
13
|
+
adds(
|
14
|
+
@twitter.rest.user_timeline(
|
15
|
+
@user.id,
|
16
|
+
@buf.last.nil? ? Options : Options.merge(max_id: @buf.last.id-1)
|
17
|
+
)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Tweet < Buf::Screen
|
23
|
+
include Command::Tweet
|
24
|
+
|
25
|
+
def initialize(user, twitter)
|
26
|
+
super(TweetBuf.new(user, twitter), "#{user.screen_name}'s Tweets")
|
27
|
+
add_command(twitter)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Flumtter
|
2
|
+
class Window::TweetBase < Window::Buf::Element
|
3
|
+
def id
|
4
|
+
@object.id
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def user
|
9
|
+
"#{@object.user.name} (@#{@object.user.screen_name})"
|
10
|
+
end
|
11
|
+
|
12
|
+
def created_at
|
13
|
+
@object.created_at.strftime("%Y/%m/%d %H:%M:%S")
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
@object.text.nl
|
18
|
+
end
|
19
|
+
|
20
|
+
def footer
|
21
|
+
"#{created_at}".ljust(width, nil, @object.via)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module Window
|
3
|
+
class UserBase < Buf::Element
|
4
|
+
def id
|
5
|
+
@object.id
|
6
|
+
end
|
7
|
+
|
8
|
+
def element
|
9
|
+
@text ||= <<~EOF
|
10
|
+
#{header}
|
11
|
+
#{
|
12
|
+
{
|
13
|
+
"#{@object.name} (@#{@object.screen_name})": {
|
14
|
+
description: @object.description.split_num(Terminal.x - 20),
|
15
|
+
location: @object.location,
|
16
|
+
url: @object.website.to_s
|
17
|
+
}
|
18
|
+
}.indent
|
19
|
+
}
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class UserBuf < Buf::Buf
|
25
|
+
Options = {count: 50}
|
26
|
+
|
27
|
+
def initialize(user, twitter)
|
28
|
+
@twitter = twitter
|
29
|
+
@user = user
|
30
|
+
super(UserBase)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class User < Buf::Screen
|
35
|
+
include Command::UserList
|
36
|
+
|
37
|
+
def initialize(buf, title, twitter)
|
38
|
+
super(buf, title)
|
39
|
+
add_command(twitter)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
class self::Profile
|
4
|
+
include Util
|
5
|
+
alias_method :cvr, :command_value_regexp
|
6
|
+
|
7
|
+
def initialize(twitter)
|
8
|
+
@twitter = twitter
|
9
|
+
setting = Window::DynamicView.new("Change Profile", <<~EOF)
|
10
|
+
Please select item you want to change with new profile.
|
11
|
+
Syntax: '\#{item} \#{new profile}'
|
12
|
+
EOF
|
13
|
+
setting.dynamic_view do
|
14
|
+
user = twitter.rest.user
|
15
|
+
{
|
16
|
+
"Current value": {
|
17
|
+
name: user.name,
|
18
|
+
description: user.description.split_num(40),
|
19
|
+
location: user.location,
|
20
|
+
url: user.website.to_s
|
21
|
+
},
|
22
|
+
}.indent
|
23
|
+
end
|
24
|
+
%w(name description url location).each do |meth|
|
25
|
+
setting.command(cvr(meth)) do |m|
|
26
|
+
begin
|
27
|
+
send(meth, m)
|
28
|
+
rescue RangeError
|
29
|
+
Window::Popup::Error.new("Too short or Too long.").show
|
30
|
+
end
|
31
|
+
raise Dispel::Recall
|
32
|
+
end
|
33
|
+
end
|
34
|
+
setting.show(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
def name(m)
|
38
|
+
m[1].range?(20)
|
39
|
+
update_profile(name: m[1])
|
40
|
+
end
|
41
|
+
|
42
|
+
def description(m)
|
43
|
+
m[1].range?(160)
|
44
|
+
update_profile(description: m[1])
|
45
|
+
end
|
46
|
+
|
47
|
+
def url(m)
|
48
|
+
m[1].range?(30)
|
49
|
+
update_profile(url: m[1])
|
50
|
+
end
|
51
|
+
|
52
|
+
def location(m)
|
53
|
+
m[1].range?(100)
|
54
|
+
update_profile(location: m[1])
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def update_profile(hash)
|
59
|
+
@twitter.rest.update_profile(hash)
|
60
|
+
rescue Twitter::Error::Forbidden => e
|
61
|
+
Window::Popup::Error.new(e.message).show
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Keyboard.add("c", "Change Profile") do |m, twitter|
|
66
|
+
self::Profile.new(twitter)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
class self::Buf < Window::Buf::Buf
|
4
|
+
def initialize(twitter)
|
5
|
+
@twitter = twitter
|
6
|
+
super(Window::TweetBase)
|
7
|
+
end
|
8
|
+
|
9
|
+
def prefetch
|
10
|
+
id = @buf.last&.object&.in_reply_to_status_id
|
11
|
+
add(
|
12
|
+
@twitter.rest.status(id)
|
13
|
+
) unless id.nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class self::Conversation < Window::Buf::Screen
|
18
|
+
include Command::Tweet
|
19
|
+
|
20
|
+
def initialize(obj, twitter)
|
21
|
+
buf = Plugins::Conversation::Buf.new(twitter)
|
22
|
+
buf.add(obj)
|
23
|
+
super(buf, "Conversation")
|
24
|
+
add_command(twitter)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Keyboard.add("g", "Conversation") do |m, twitter|
|
29
|
+
error_handler do
|
30
|
+
obj, _ = index_with_dialog(m[1], "Conversation Screen", <<~EOF)
|
31
|
+
Please input target index.
|
32
|
+
EOF
|
33
|
+
if_tweet(obj, twitter) do |tweet|
|
34
|
+
self::Conversation.new(tweet, twitter).show
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|