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,26 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def delete(obj, twitter)
|
4
|
+
if obj.user.id == twitter.account.id
|
5
|
+
begin
|
6
|
+
twitter.rest.destroy_status(obj.id)
|
7
|
+
rescue Twitter::Error::NotFound => e
|
8
|
+
raise ExecutedError, e.message
|
9
|
+
end
|
10
|
+
else
|
11
|
+
raise ExecutedError, "You may not delete another user's status."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Keyboard.add("k", "Delete") do |m,twitter|
|
16
|
+
error_handler do
|
17
|
+
obj, _ = index_with_dialog(m[1], "Delete Screen", <<~EOF)
|
18
|
+
Please input target index.
|
19
|
+
EOF
|
20
|
+
if_tweet(obj, twitter) do |tweet|
|
21
|
+
delete(tweet, twitter)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def directmessage(user, text, twitter)
|
4
|
+
case user
|
5
|
+
when Twitter::User
|
6
|
+
twitter.rest.create_direct_message(user.id, text)
|
7
|
+
else
|
8
|
+
twitter.rest.create_direct_message(user, text)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Keyboard.add("d", "Direct Message") do |m, twitter|
|
13
|
+
error_handler do
|
14
|
+
obj, m2 = index_with_dialog(m[1], "DirectMessage Screen", <<~EOF, true)
|
15
|
+
Please input target (index or screen_name) and DM content.
|
16
|
+
Syntax: '\#{index} \#{content}'
|
17
|
+
EOF
|
18
|
+
raise NoContentError if m2.empty?
|
19
|
+
|
20
|
+
case obj
|
21
|
+
when Twitter::Tweet, Twitter::Streaming::Event
|
22
|
+
if_tweet(obj, twitter) do |tweet|
|
23
|
+
directmessage(tweet.user, m2, twitter)
|
24
|
+
end
|
25
|
+
when Twitter::DirectMessage
|
26
|
+
directmessage(obj.sender, m2, twitter)
|
27
|
+
when String
|
28
|
+
directmessage(obj, m2, twitter)
|
29
|
+
else
|
30
|
+
raise UnSupportError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
class self::Buf < Window::Buf::Buf
|
4
|
+
Options = {count: 50}
|
5
|
+
|
6
|
+
def initialize(twitter)
|
7
|
+
@twitter = twitter
|
8
|
+
super(Window::DMBase)
|
9
|
+
end
|
10
|
+
|
11
|
+
def prefetch
|
12
|
+
adds(
|
13
|
+
@twitter.rest.direct_messages(
|
14
|
+
@buf.last.nil? ? Options : Options.merge(max_id: @buf.last.id-1)
|
15
|
+
)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class self::DirectMessage < Window::Buf::Screen
|
21
|
+
include Command::DM
|
22
|
+
|
23
|
+
def initialize(twitter)
|
24
|
+
super(Plugins::Directmessages::Buf.new(twitter), "#{twitter.account.screen_name}'s DirectMessages")
|
25
|
+
add_command(twitter)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Keyboard.add("b", "DirectMessages") do |m, twitter|
|
30
|
+
self::DirectMessage.new(twitter).show
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def favorite(obj, twitter)
|
4
|
+
if obj.favorited?
|
5
|
+
raise ExecutedError, "already favorited"
|
6
|
+
else
|
7
|
+
twitter.rest.favorite(obj.id)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Keyboard.add("f", "Favorite") do |m,twitter|
|
12
|
+
error_handler do
|
13
|
+
obj, _ = index_with_dialog(m[1], "Favorite Screen", <<~EOF)
|
14
|
+
Please input target index.
|
15
|
+
EOF
|
16
|
+
if_tweet(obj, twitter) do |tweet|
|
17
|
+
favorite(tweet, twitter)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
Keyboard.add("n", "New Tweet") do |m, twitter|
|
4
|
+
if m[1].empty?
|
5
|
+
dialog = Window::Dialog.new("Tweet Screen", <<~EOF)
|
6
|
+
Please input tweet content.
|
7
|
+
EOF
|
8
|
+
dialog.command(/(.+)/) do |m|
|
9
|
+
twitter.rest.update(m[1])
|
10
|
+
end
|
11
|
+
dialog.show(true, false)
|
12
|
+
else
|
13
|
+
twitter.rest.update(m[1])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def update(obj,text,twitter)
|
4
|
+
twitter.rest.update("@#{obj.user.screen_name} #{text}", :in_reply_to_status_id => obj.id)
|
5
|
+
end
|
6
|
+
|
7
|
+
Keyboard.add("r", "Reply") do |m, twitter|
|
8
|
+
error_handler do
|
9
|
+
obj, m2 = index_with_dialog(m[1], "Reply Screen", <<~EOF)
|
10
|
+
Please input target index and tweet content.
|
11
|
+
Syntax: '\#{index} \#{content}'
|
12
|
+
EOF
|
13
|
+
case obj
|
14
|
+
when Twitter::Tweet, Twitter::Streaming::Event
|
15
|
+
if_tweet(obj, twitter) do |tweet|
|
16
|
+
update(tweet, m2, twitter)
|
17
|
+
end
|
18
|
+
when Twitter::DirectMessage
|
19
|
+
twitter.rest.create_direct_message(obj.sender.id, m2)
|
20
|
+
else
|
21
|
+
raise UnSupportError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def retweet(obj, twitter)
|
4
|
+
if obj.retweeted?
|
5
|
+
raise ExecutedError, "already retweeted"
|
6
|
+
else
|
7
|
+
begin
|
8
|
+
twitter.rest.retweet(obj.id)
|
9
|
+
rescue Twitter::Error::Forbidden => e
|
10
|
+
if e.message == "You have already retweeted this tweet."
|
11
|
+
raise ExecutedError, "already retweeted"
|
12
|
+
else
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Keyboard.add("t", "Retweet") do |m, twitter|
|
20
|
+
error_handler do
|
21
|
+
obj, _ = index_with_dialog(m[1], "Retweet Screen", <<~EOF)
|
22
|
+
Please input target index.
|
23
|
+
EOF
|
24
|
+
if_tweet(obj, twitter) do |tweet|
|
25
|
+
retweet(tweet, twitter)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
def unfavorite(obj, twitter)
|
4
|
+
begin
|
5
|
+
twitter.rest.unfavorite(obj.id)
|
6
|
+
rescue Twitter::Error::NotFound => e
|
7
|
+
if e.message == "No status found with that ID."
|
8
|
+
raise ExecutedError, "not favorited"
|
9
|
+
else
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Keyboard.add("l", "UnFavorite") do |m,twitter|
|
16
|
+
error_handler do
|
17
|
+
obj, _ = index_with_dialog(m[1], "UnFavorite Screen", <<~EOF)
|
18
|
+
Please input target index.
|
19
|
+
EOF
|
20
|
+
if_tweet(obj, twitter) do |tweet|
|
21
|
+
unfavorite(tweet, twitter)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
class self::Profile < Window::DynamicView
|
4
|
+
include Command::User
|
5
|
+
|
6
|
+
def initialize(object, twitter)
|
7
|
+
@twitter = twitter
|
8
|
+
parse(object)
|
9
|
+
super("#{@user.screen_name}'s profile", "")
|
10
|
+
@width = 60
|
11
|
+
dynamic_view do
|
12
|
+
user = twitter.rest.user(@user)
|
13
|
+
<<~EOF
|
14
|
+
#{mutual.rjust(@width - 3)}
|
15
|
+
#{profile(user)}
|
16
|
+
|
17
|
+
#{statistics(user)}
|
18
|
+
EOF
|
19
|
+
end
|
20
|
+
add_command(@user, twitter)
|
21
|
+
show(true)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def mutual
|
26
|
+
friendship = @twitter.rest.friendship(@twitter.account.id, @user)
|
27
|
+
following = friendship.source.following? ? ">" : "/"
|
28
|
+
follower = friendship.source.followed_by? ? "<": "/"
|
29
|
+
"@#{@twitter.account.screen_name} #{following}=#{follower} @#{@user.screen_name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def profile(user)
|
33
|
+
{
|
34
|
+
name: user.name,
|
35
|
+
description: user.description.split_num(44),
|
36
|
+
location: user.location,
|
37
|
+
url: user.website.to_s
|
38
|
+
}.indent
|
39
|
+
end
|
40
|
+
|
41
|
+
def statistics(user)
|
42
|
+
{
|
43
|
+
tweets: user.tweets_count,
|
44
|
+
follow: user.friends_count,
|
45
|
+
follower: user.followers_count,
|
46
|
+
favorite: user.favorites_count
|
47
|
+
}.indent
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse(obj)
|
51
|
+
@user = case obj
|
52
|
+
when Twitter::Tweet
|
53
|
+
obj.user
|
54
|
+
when Twitter::DirectMessage
|
55
|
+
ob.sender
|
56
|
+
when Twitter::Streaming::Event
|
57
|
+
ob.source
|
58
|
+
when Twitter::Streaming::DeletedTweet
|
59
|
+
obj.user
|
60
|
+
when String
|
61
|
+
@twitter.rest.user(obj)
|
62
|
+
else
|
63
|
+
raise UnSupportError
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Keyboard.add("p", "User Profile") do |m, twitter|
|
69
|
+
error_handler do
|
70
|
+
obj, _ = index_with_dialog(m[1], "Select User Screen", <<~EOF, true)
|
71
|
+
Please input target (index or screen_name) and DM content.
|
72
|
+
EOF
|
73
|
+
self::Profile.new(obj, twitter)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
Keyboard.add("e", "Exit") do
|
4
|
+
puts "終了します".color
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
Keyboard.add("q", "Clear Terminal Screen") do
|
9
|
+
print "\e[2J\e[f"
|
10
|
+
end
|
11
|
+
|
12
|
+
Keyboard.add("^", "Reconnection") do |m, twitter|
|
13
|
+
twitter.kill
|
14
|
+
twitter.start
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Flumtter
|
2
|
+
plugin do
|
3
|
+
add_opt do |opt, options|
|
4
|
+
opt.on('--timeline_load VALUE', 'load timeline num'){|v|options[:timeline_load] = v.to_i}
|
5
|
+
opt.on('--[no-]timeline_load?', 'load timeline on init'){|v|options[:timeline_load?] = v}
|
6
|
+
end
|
7
|
+
|
8
|
+
on_event(:init) do |twitter|
|
9
|
+
if Setting[:timeline_load?]
|
10
|
+
twitter.rest.home_timeline(count: Setting[:timeline_load] || 20).reverse_each do |object|
|
11
|
+
puts TimeLine::Tweet.new(object, twitter).to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Flumtter
|
2
|
+
sarastire 'plugins/timeline'
|
3
|
+
|
4
|
+
plugin do
|
5
|
+
Client.on_event(:tweet) do |object, twitter|
|
6
|
+
type = object.type(twitter.account)
|
7
|
+
cls = if type.include?(:quote)
|
8
|
+
TimeLine::Quote
|
9
|
+
elsif type.include?(:retweet)
|
10
|
+
TimeLine::Retweet
|
11
|
+
elsif type.include?(:self_tweet)
|
12
|
+
TimeLine::SelfTweet
|
13
|
+
elsif type.include?(:reply_to_me)
|
14
|
+
TimeLine::ReplyTweet
|
15
|
+
else
|
16
|
+
TimeLine::Tweet
|
17
|
+
end
|
18
|
+
puts cls.new(object, twitter).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
Client.on_event(:event) do |object, twitter|
|
22
|
+
type = object.type(twitter.account)
|
23
|
+
cls = if type.include?(:favorite)
|
24
|
+
TimeLine::Favorite
|
25
|
+
elsif type.include?(:unfavorite)
|
26
|
+
TimeLine::UnFavorite
|
27
|
+
end
|
28
|
+
puts cls.new(object, twitter).to_s if cls
|
29
|
+
end
|
30
|
+
|
31
|
+
Client.on_event(:directmessage) do |object, twitter|
|
32
|
+
puts TimeLine::DirectMessage.new(object, twitter).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
Client.on_event(:deletedtweet) do |object, twitter|
|
36
|
+
begin
|
37
|
+
puts TimeLine::DeletedTweet.new(object, twitter).to_s
|
38
|
+
rescue TimeLine::DeletedTweet::TweetNotFound
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module TimeLine
|
3
|
+
class Base
|
4
|
+
@@elements = []
|
5
|
+
|
6
|
+
def self.[](key)
|
7
|
+
@@elements[key]
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(object, twitter)
|
11
|
+
@object = object
|
12
|
+
@twitter = twitter
|
13
|
+
@@elements << object
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
text = <<~EOF.color(fg_color)
|
18
|
+
#{header}
|
19
|
+
#{user}
|
20
|
+
#{body}
|
21
|
+
#{footer}
|
22
|
+
EOF
|
23
|
+
bg_color.nil? ? text : text.background_color(bg_color)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def user
|
28
|
+
"#{@object.user.name} (@#{@object.user.screen_name})"
|
29
|
+
end
|
30
|
+
|
31
|
+
def color
|
32
|
+
:white
|
33
|
+
end
|
34
|
+
|
35
|
+
def fg_color
|
36
|
+
case color
|
37
|
+
when Symbol
|
38
|
+
color
|
39
|
+
when Array
|
40
|
+
color[0]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def bg_color
|
45
|
+
case color
|
46
|
+
when Symbol
|
47
|
+
nil
|
48
|
+
when Array
|
49
|
+
color[1]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def created_at
|
54
|
+
@object.created_at.strftime("%Y/%m/%d %H:%M:%S")
|
55
|
+
end
|
56
|
+
|
57
|
+
def index
|
58
|
+
@@elements.rindex(@object)
|
59
|
+
end
|
60
|
+
|
61
|
+
def header
|
62
|
+
"#{index} ".ljust(Terminal.x, ?-)
|
63
|
+
end
|
64
|
+
|
65
|
+
def body
|
66
|
+
@object.text.nl
|
67
|
+
end
|
68
|
+
|
69
|
+
def footer
|
70
|
+
"#{created_at}".ljust(Terminal.x, nil, @object.via)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|