facy 1.2.9.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +1 -0
- data/bin/facy +18 -0
- data/config.yml +4 -0
- data/facy.gemspec +27 -0
- data/lib/facy.rb +32 -0
- data/lib/facy/command.rb +180 -0
- data/lib/facy/converter.rb +91 -0
- data/lib/facy/core.rb +104 -0
- data/lib/facy/core_ext.rb +9 -0
- data/lib/facy/exception.rb +3 -0
- data/lib/facy/facebook.rb +108 -0
- data/lib/facy/get_token.rb +112 -0
- data/lib/facy/help.rb +28 -0
- data/lib/facy/image_viewer.rb +82 -0
- data/lib/facy/input_queue.rb +35 -0
- data/lib/facy/logger.rb +26 -0
- data/lib/facy/option_parser.rb +23 -0
- data/lib/facy/output.rb +183 -0
- data/lib/facy/version.rb +3 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8dea1a2158dbc7708ea9c5ea389cd691a7b3a7e8
|
4
|
+
data.tar.gz: b5b33c9358d8e6afb39eb5fa52dfef9a0b68949f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 59f1a7c30b3c0ef84edeedb55d69867ac9aff3c211f68a2c83fe89b7235e1abcd1bc499c823d1cd31e6ed29d605b162b3cb4985e50e41659406161ba12c4a48d
|
7
|
+
data.tar.gz: a6571b1d6a67012fdd217b19dbe853bcf9cf0fa9df7ae9b4a88a5028ed996bb1a1bce42b4c06d3caa14679b790592688b2fae0d41adb117908c34158d9f17fc4
|
data/.gitignore
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 dxhuy1988
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Facy
|
2
|
+
Facy is a terminal client for facebook, which support streaming-like feature.
|
3
|
+
Only supports Ruby 1.9 and later.
|
4
|
+
To install facy, we need ruby pre-installed, please refer to https://www.ruby-lang.org/en/installation/ to know how to install ruby.
|
5
|
+
I recommend rvm to control the version of installed ruby.
|
6
|
+
|
7
|
+
|
8
|
+
- **Homepage**: http://huydx.com/facy
|
9
|
+
- **Installation guide**: https://github.com/huydx/facy/wiki/Installation-Guide
|
10
|
+
- **Usage guide**: https://github.com/huydx/facy/wiki/Usage-guide
|
11
|
+
|
12
|
+
![](http://i.gyazo.com/01de9c8da6191b79bcec201048361f58.png)
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
Install it yourself as:
|
16
|
+
```
|
17
|
+
$ gem install facy
|
18
|
+
```
|
19
|
+
and then refer to the [wiki page](https://github.com/huydx/facy/wiki/Installation-Guide) to complete the initial setup process. To setup facy, you need to register facebook developer account, and create your own facebook app.
|
20
|
+
- To register facebook developer account, go to: https://developers.facebook.com/docs/create-developer-account
|
21
|
+
- After registerd, you can go to https://developers.facebook.com/apps to create your new app
|
22
|
+
- And then you'are able to setup facy follow https://github.com/huydx/facy/wiki/Installation-Guide
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
## Contributing
|
27
|
+
|
28
|
+
1. Fork it ( http://github.com/huydx/facy/fork )
|
29
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
30
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
31
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
32
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/facy
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
#
|
4
|
+
print "\e[31m"
|
5
|
+
puts %q{
|
6
|
+
_/ ____\____ ____ ___.__.
|
7
|
+
\ __\\__ \ _/ ___< | |
|
8
|
+
| | / __ \\ \___\___ |
|
9
|
+
|__| (____ /\___ > ____|
|
10
|
+
\/ \/\/
|
11
|
+
}
|
12
|
+
print "\e[0m"
|
13
|
+
require 'facy'
|
14
|
+
Facy.parse(ARGV)
|
15
|
+
puts "Fetching facebook stream at first time may takes a while ♩ ♪ ♫ ♬"
|
16
|
+
puts ""
|
17
|
+
|
18
|
+
Facy.start({})
|
data/config.yml
ADDED
data/facy.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'facy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "facy"
|
8
|
+
spec.version = Facy::VERSION
|
9
|
+
spec.authors = ["dxhuy1988"]
|
10
|
+
spec.email = ["doxuanhuy@gmail.com"]
|
11
|
+
spec.summary = %q{facy: terminal client for facebook}
|
12
|
+
spec.description = %q{facy: first colorful terminal client for facebook}
|
13
|
+
spec.homepage = "https://github.com/huydx/facy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n") + ['config.yml']
|
17
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_runtime_dependency "koala", "~>1.10"
|
23
|
+
spec.add_runtime_dependency "activesupport", "~>4.0"
|
24
|
+
spec.add_runtime_dependency "launchy", "~>2.4"
|
25
|
+
spec.add_runtime_dependency "eventmachine", "~>1.0"
|
26
|
+
spec.add_runtime_dependency "rmagick", "~>2.13"
|
27
|
+
end
|
data/lib/facy.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
%w(
|
2
|
+
rmagick
|
3
|
+
koala
|
4
|
+
readline
|
5
|
+
yaml
|
6
|
+
thread
|
7
|
+
launchy
|
8
|
+
eventmachine
|
9
|
+
active_support
|
10
|
+
active_support/core_ext
|
11
|
+
active_support/dependencies
|
12
|
+
).each { |lib| require lib }
|
13
|
+
|
14
|
+
Thread.abort_on_exception = true
|
15
|
+
Encoding.default_external = Encoding.find('UTF-8')
|
16
|
+
|
17
|
+
%w(
|
18
|
+
core_ext
|
19
|
+
core
|
20
|
+
logger
|
21
|
+
get_token
|
22
|
+
output
|
23
|
+
command
|
24
|
+
help
|
25
|
+
facebook
|
26
|
+
input_queue
|
27
|
+
command
|
28
|
+
converter
|
29
|
+
exception
|
30
|
+
option_parser
|
31
|
+
image_viewer
|
32
|
+
).each { |file| require_dependency File.expand_path("../facy/#{file}", __FILE__) }
|
data/lib/facy/command.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
module Facy
|
2
|
+
module Command
|
3
|
+
def commands
|
4
|
+
@commands ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def command(pattern, options={}, &block)
|
8
|
+
commands << {pattern: pattern, block: block}
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(text)
|
12
|
+
text.strip!
|
13
|
+
rule, target = match_single_command(text) || match_target_command(text)
|
14
|
+
commands.each do |c|
|
15
|
+
if rule.to_s == c[:pattern].to_s.split(":").first
|
16
|
+
c[:block].call(target)
|
17
|
+
return
|
18
|
+
end
|
19
|
+
end
|
20
|
+
rescue Exception => e
|
21
|
+
error e
|
22
|
+
log(:error, e.message)
|
23
|
+
log(:error, e.backtrace)
|
24
|
+
end
|
25
|
+
|
26
|
+
def match_target_command(text)
|
27
|
+
text =~ /^:(\S*) (.+)$/
|
28
|
+
return [$1, $2] if $1 && $2
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def match_single_command(text)
|
33
|
+
text =~ /^:(\S*)$/
|
34
|
+
return $1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
extend Command
|
39
|
+
|
40
|
+
init do
|
41
|
+
commands.clear
|
42
|
+
command :post do |text|
|
43
|
+
async {
|
44
|
+
ret = facebook_post(text)
|
45
|
+
instant_output(Item.new(
|
46
|
+
info: :info,
|
47
|
+
content: "post '#{text}' has been posted to your wall")
|
48
|
+
) if ret["id"]
|
49
|
+
}
|
50
|
+
end
|
51
|
+
help :post, 'post to your own wall', ':post [content]'
|
52
|
+
|
53
|
+
command :like do |post_code|
|
54
|
+
post_code = "$#{post_code}"
|
55
|
+
item = post_code_reverse_map[post_code]
|
56
|
+
post_id = item.id if item.is_a?(Item)
|
57
|
+
async {
|
58
|
+
ret = facebook_like(post_id)
|
59
|
+
instant_output(Item.new(info: :info, content: "like success")) if ret
|
60
|
+
}
|
61
|
+
end
|
62
|
+
help :like, 'like a post', ':like [code]'
|
63
|
+
|
64
|
+
command :exit do
|
65
|
+
stop_process
|
66
|
+
end
|
67
|
+
help :exit, 'quit facy', ":exit"
|
68
|
+
|
69
|
+
command :open do |post_code|
|
70
|
+
post_code = "$#{post_code}"
|
71
|
+
item = post_code_reverse_map[post_code]
|
72
|
+
link = item.data.link if item.is_a?(Item)
|
73
|
+
p link
|
74
|
+
if link
|
75
|
+
browse(link)
|
76
|
+
else
|
77
|
+
async { instant_output(Item.new(info: :error, content: "sorry this post can not be openned")) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
help :open, 'open a post in browser', ':open [code]'
|
81
|
+
|
82
|
+
command :comment do |content|
|
83
|
+
content = content.split(" ")
|
84
|
+
post_code = "$#{content.first}"
|
85
|
+
comment = content.tap{|c|c.shift}.join(' ')
|
86
|
+
|
87
|
+
item = post_code_reverse_map[post_code]
|
88
|
+
post_id = item.id if item.is_a?(Item)
|
89
|
+
|
90
|
+
async {
|
91
|
+
ret = facebook_comment(post_id, comment)
|
92
|
+
instant_output(Item.new(info: :info, content: 'comment success')) if ret
|
93
|
+
}
|
94
|
+
end
|
95
|
+
help :comment, 'comment to a post,', ':comment [code] [content]'
|
96
|
+
|
97
|
+
command :seen do |notif_code|
|
98
|
+
async {
|
99
|
+
ret = facebook_set_seen(notif_code)
|
100
|
+
instant_output(Item.new(info: :info, content: 'unseen success')) if ret
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
command :view_raw do |post_code|
|
105
|
+
post_code = "$#{post_code}"
|
106
|
+
item = post_code_reverse_map[post_code]
|
107
|
+
|
108
|
+
print JSON.pretty_generate(item.raw)
|
109
|
+
puts ""
|
110
|
+
end
|
111
|
+
help :view_raw, "view raw json output of a post", ":view_raw [post_code]"
|
112
|
+
|
113
|
+
command :view_img do |post_code|
|
114
|
+
if config[:enable_img_view]
|
115
|
+
post_code = "$#{post_code}"
|
116
|
+
item = post_code_reverse_map[post_code]
|
117
|
+
|
118
|
+
if item.data.picture
|
119
|
+
view_img(item.data.picture)
|
120
|
+
else
|
121
|
+
instant_output(Item.new(info: :error, content: "this post has no image link"))
|
122
|
+
end
|
123
|
+
else
|
124
|
+
instant_output(Item.new(info: :error, content: "use facy -enable_img_view to enable image viewer"))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
command :view_comments do |post_code|
|
129
|
+
post_code = "$#{post_code}"
|
130
|
+
item = post_code_reverse_map[post_code]
|
131
|
+
comments = item.data.comments
|
132
|
+
|
133
|
+
unless comments.empty?
|
134
|
+
comments.each do |cm|
|
135
|
+
instant_output(Item.new(info: :comment, from: cm["from"]["name"], message: cm["message"]))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
help :view_comments, "view a comment from a post", ":view_comments [code]"
|
140
|
+
|
141
|
+
command :view_likes do |post_code|
|
142
|
+
post_code = "$#{post_code}"
|
143
|
+
item = post_code_reverse_map[post_code]
|
144
|
+
likes = item.data.likes
|
145
|
+
unless likes.empty?
|
146
|
+
likes.each do |lk|
|
147
|
+
instant_output(Item.new(info: :like, from: lk["name"]))
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
command :dump_log do
|
153
|
+
if config[:debug_log]
|
154
|
+
dump_log
|
155
|
+
instant_output(Item.new(info: :info, content: "dump log success to #{log_file}"))
|
156
|
+
else
|
157
|
+
instant_output(Item.new(
|
158
|
+
info: :info,
|
159
|
+
content: "you need to start $facy -debug option to enable log"
|
160
|
+
))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
help :dump_log, "dump debug log to file", ":dump_log"
|
164
|
+
|
165
|
+
command :commands do
|
166
|
+
helps.each do |help|
|
167
|
+
puts ":#{help[:target].to_s.colorize(38,5,8)} #{help[:usage]}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
help :commands, "list all available commands", ":commands"
|
171
|
+
|
172
|
+
completion_proc = proc {|s|
|
173
|
+
commands
|
174
|
+
.map{|c|c[:pattern]}
|
175
|
+
.map{|c|":#{c.to_s}"}
|
176
|
+
.grep(/^#{Regexp.escape(s)}/)
|
177
|
+
}
|
178
|
+
Readline.completion_proc = completion_proc
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Facy
|
4
|
+
module Converter
|
5
|
+
#convert facebook graph return to Item#class
|
6
|
+
def graph2item(graph_item)
|
7
|
+
id = graph_item["id"]
|
8
|
+
if id =~ /^notif_(.+)$/
|
9
|
+
item = Item.new({
|
10
|
+
id: id,
|
11
|
+
info: :notification,
|
12
|
+
data: {
|
13
|
+
user: graph_item["from"]["name"],
|
14
|
+
content: graph_item["title"],
|
15
|
+
},
|
16
|
+
date: graph_item["created_time"],
|
17
|
+
})
|
18
|
+
else
|
19
|
+
content =
|
20
|
+
case graph_item["type"]
|
21
|
+
when "status"
|
22
|
+
if graph_item["message"].nil?
|
23
|
+
graph_item["story"]
|
24
|
+
else
|
25
|
+
graph_item["message"]
|
26
|
+
end
|
27
|
+
when "photo"
|
28
|
+
"share a photo: #{graph_item['message'] || graph_item['link']}"
|
29
|
+
when "checkin"
|
30
|
+
"checkin"
|
31
|
+
when "video"
|
32
|
+
"share a video: #{graph_item['message']}"
|
33
|
+
when "link"
|
34
|
+
"#{graph_item["message"]} #{graph_item["link"]}"
|
35
|
+
end
|
36
|
+
|
37
|
+
link =
|
38
|
+
(graph_item["actions"] && graph_item["actions"].first["link"]) ||
|
39
|
+
graph_item["link"]
|
40
|
+
|
41
|
+
likes = graph_item["likes"] && graph_item["likes"]["data"] || []
|
42
|
+
comments = graph_item["comments"] && graph_item["comments"]["data"] || []
|
43
|
+
|
44
|
+
like_count = likes.size
|
45
|
+
comment_count = comments.size
|
46
|
+
|
47
|
+
item = Item.new({
|
48
|
+
id: graph_item["id"],
|
49
|
+
info: :feed,
|
50
|
+
data: {
|
51
|
+
type: graph_item["type"],
|
52
|
+
user: graph_item["from"]["name"],
|
53
|
+
content: content,
|
54
|
+
picture: graph_item["picture"],
|
55
|
+
link: link,
|
56
|
+
like_count: like_count,
|
57
|
+
likes: likes,
|
58
|
+
comment_count: comment_count,
|
59
|
+
comments: comments,
|
60
|
+
date: DateTime.parse(graph_item["created_time"]),
|
61
|
+
},
|
62
|
+
date: graph_item["created_time"],
|
63
|
+
})
|
64
|
+
end
|
65
|
+
item.raw = graph_item
|
66
|
+
return item
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
extend Converter
|
71
|
+
|
72
|
+
class DeepStruct < OpenStruct
|
73
|
+
def initialize(hash=nil)
|
74
|
+
@table = {}
|
75
|
+
@hash_table = {}
|
76
|
+
|
77
|
+
if hash
|
78
|
+
hash.each do |k,v|
|
79
|
+
@table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
|
80
|
+
@hash_table[k.to_sym] = v
|
81
|
+
new_ostruct_member(k)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_h
|
87
|
+
@hash_table
|
88
|
+
end
|
89
|
+
end
|
90
|
+
class Item < DeepStruct; end
|
91
|
+
end
|