facy 1.2.9.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|