facebook-cli 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/facebook-cli +5 -0
- data/lib/fbcli.rb +161 -0
- data/lib/fbcli/auth.rb +70 -0
- data/lib/fbcli/facebook.rb +42 -0
- data/lib/fbcli/format.rb +27 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bf355c2240f7b7be619e73de13c23b91bc464b12
|
4
|
+
data.tar.gz: 8fac877170cfebfadd4bc0b9c4ae66d59c5e9138
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2687e272aed37d79b35eb51126977aa1047b1751fdac8483c6b80c84d325b49dea3c814d990b065e8abf24c88697758a61095d717f301ddbb996b371506ecae0
|
7
|
+
data.tar.gz: 0fe2391fd1f630b93ebdb23370449ebef5742798d897564292b5199d4f8b1664e4915167896cecd86cb843ae5a4fd6b7bfe3efffe18bb4a67dd7a0955208e549
|
data/bin/facebook-cli
ADDED
data/lib/fbcli.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'gli'
|
2
|
+
require 'yaml'
|
3
|
+
require 'fbcli/auth'
|
4
|
+
require 'fbcli/format'
|
5
|
+
require 'fbcli/facebook'
|
6
|
+
|
7
|
+
CONFIG_FILE = "config.yml"
|
8
|
+
|
9
|
+
include GLI::App
|
10
|
+
|
11
|
+
program_desc "Facebook command line interface"
|
12
|
+
|
13
|
+
version '1.0.0'
|
14
|
+
|
15
|
+
flag [:token], :desc => 'Provide Facebook access token', :required => false
|
16
|
+
flag [:format], :desc => 'Output format (values: text, html)', :default_value => "text"
|
17
|
+
|
18
|
+
pre do |global_options,command|
|
19
|
+
$config = YAML.load_file(CONFIG_FILE)
|
20
|
+
|
21
|
+
if $config['app_id'].nil? or $config['app_secret'].nil?
|
22
|
+
exit_now! <<~EOM
|
23
|
+
It looks like you are running #{$0} for the first time.
|
24
|
+
|
25
|
+
The following steps are necessary to use the Facebook API:
|
26
|
+
|
27
|
+
- Create a new application at: https://developers.facebook.com/apps
|
28
|
+
- In the Settings tab, add "localhost" to the App Domains
|
29
|
+
- Save the App ID and App Secret in "config.yml"
|
30
|
+
|
31
|
+
After that, run: #{$0} login
|
32
|
+
EOM
|
33
|
+
end
|
34
|
+
|
35
|
+
$format = global_options[:format]
|
36
|
+
|
37
|
+
if $format == "html" and command.name != :login
|
38
|
+
puts <<~EOM
|
39
|
+
<!doctype html>
|
40
|
+
<html lang=en>
|
41
|
+
<head>
|
42
|
+
<meta charset=utf-8>
|
43
|
+
</head>
|
44
|
+
<body>
|
45
|
+
EOM
|
46
|
+
end
|
47
|
+
|
48
|
+
# Success
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
post do |global_options,command|
|
53
|
+
if $format == "html" and command.name != :login
|
54
|
+
puts <<~EOM
|
55
|
+
</body>
|
56
|
+
</html>
|
57
|
+
EOM
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
on_error do |exception|
|
62
|
+
puts exception.message
|
63
|
+
|
64
|
+
# Suppress GLI's built-in error handling
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Log into Facebook and receive an access token"
|
69
|
+
command :login do |c|
|
70
|
+
c.flag [:port], :desc => 'Local TCP port to serve Facebook login redirect page', :default_value => '3333'
|
71
|
+
c.action do |global_options,options,args|
|
72
|
+
token, expiration = FBCLI::listen_for_auth_code(options['port'], $config['app_id'], $config['app_secret'])
|
73
|
+
|
74
|
+
if not token.nil?
|
75
|
+
$config['access_token'] = token
|
76
|
+
|
77
|
+
File.open(CONFIG_FILE,'w') do |f|
|
78
|
+
f.write $config.to_yaml
|
79
|
+
end
|
80
|
+
|
81
|
+
puts "Your access token: #{token}"
|
82
|
+
puts
|
83
|
+
puts "Expires in: #{FBCLI::expiration_str(expiration.to_i)}"
|
84
|
+
puts
|
85
|
+
puts "Have fun!"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "Show your name and profile ID"
|
91
|
+
command :me do |c|
|
92
|
+
c.action do |global_options,options,args|
|
93
|
+
data = FBCLI::request_data global_options, ""
|
94
|
+
FBCLI::write "Name: #{data["name"]}"
|
95
|
+
FBCLI::write "Your profile ID: #{data["id"]}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
desc "List the pages you have 'Liked'"
|
100
|
+
command :likes do |c|
|
101
|
+
c.action do |global_options,options,args|
|
102
|
+
FBCLI::page_items global_options, "likes" do |item|
|
103
|
+
FBCLI::write item["name"]
|
104
|
+
FBCLI::write FBCLI::link item["id"]
|
105
|
+
FBCLI::write
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
desc "List the people you are friends with (some limitations)"
|
111
|
+
long_desc <<~EOM
|
112
|
+
As of Graph API v2.0 Facebook no longer provides access to your full friends list.
|
113
|
+
As an alternative, we now request 'invitable_friends' which only includes friends
|
114
|
+
you are allowed to invite to use your app.
|
115
|
+
|
116
|
+
See: https://developers.facebook.com/docs/apps/faq#faq_1694316010830088
|
117
|
+
EOM
|
118
|
+
command :friends do |c|
|
119
|
+
c.action do |global_options,options,args|
|
120
|
+
FBCLI::page_items global_options, "invitable_friends" do |item|
|
121
|
+
FBCLI::write item["name"]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
desc "List the posts on your profile"
|
127
|
+
command :feed do |c|
|
128
|
+
c.action do |global_options,options,args|
|
129
|
+
FBCLI::page_items global_options, "feed" do |item|
|
130
|
+
profile_id, post_id = item["id"].split '_', 2
|
131
|
+
|
132
|
+
FBCLI::write item["message"] if item.has_key?("message")
|
133
|
+
FBCLI::write FBCLI::link "#{profile_id}/posts/#{post_id}"
|
134
|
+
FBCLI::write "Created: #{FBCLI::date(item["created_time"])}"
|
135
|
+
FBCLI::write "--"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
consumePhoto = Proc.new do |item|
|
141
|
+
FBCLI::write item["name"] unless not item.key?("name")
|
142
|
+
FBCLI::write FBCLI::link "#{item["id"]}"
|
143
|
+
FBCLI::write "Created: #{FBCLI::date(item["created_time"])}"
|
144
|
+
FBCLI::write "--"
|
145
|
+
end
|
146
|
+
|
147
|
+
desc "List photos you have uploaded"
|
148
|
+
command :photos do |c|
|
149
|
+
c.action do |global_options,options,args|
|
150
|
+
FBCLI::page_items global_options, "photos?type=uploaded", &consumePhoto
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
desc "List photos you are tagged in"
|
155
|
+
command :photosof do |c|
|
156
|
+
c.action do |global_options,options,args|
|
157
|
+
FBCLI::page_items global_options, "photos", &consumePhoto
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
exit run(ARGV)
|
data/lib/fbcli/auth.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'webrick'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module FBCLI
|
7
|
+
API_VERSION = "2.7"
|
8
|
+
|
9
|
+
def self.listen_for_auth_code(port, app_id, app_secret)
|
10
|
+
uri = "https://www.facebook.com/dialog/oauth?client_id=#{app_id}" +
|
11
|
+
"&redirect_uri=http://localhost:#{port}/" +
|
12
|
+
"&scope=user_likes,user_friends,user_photos,user_posts"
|
13
|
+
|
14
|
+
puts "Please open: #{uri}"
|
15
|
+
puts
|
16
|
+
puts "Waiting for authorization code on port #{port}..."
|
17
|
+
puts
|
18
|
+
|
19
|
+
server = WEBrick::HTTPServer.new(
|
20
|
+
:Port => port,
|
21
|
+
:SSLEnable => false,
|
22
|
+
:Logger => WEBrick::Log.new(File.open(File::NULL, 'w')),
|
23
|
+
:AccessLog => []
|
24
|
+
)
|
25
|
+
|
26
|
+
access_token = nil
|
27
|
+
|
28
|
+
server.mount_proc '/' do |req, res|
|
29
|
+
key, value = req.query_string.split '=', 2
|
30
|
+
|
31
|
+
if key == "code"
|
32
|
+
access_token = get_access_token(port, app_id, value, app_secret)
|
33
|
+
else
|
34
|
+
puts "Received unexpected request: #{req.query_string}"
|
35
|
+
# TODO: Handle forseeable cases
|
36
|
+
end
|
37
|
+
|
38
|
+
res.body = 'You may now close this window.'
|
39
|
+
server.shutdown
|
40
|
+
end
|
41
|
+
|
42
|
+
# Allow CTRL+C intervention
|
43
|
+
trap 'INT' do server.shutdown end
|
44
|
+
|
45
|
+
# This thread will block execution until server shuts down
|
46
|
+
server.start
|
47
|
+
|
48
|
+
# Return access token
|
49
|
+
access_token
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.get_access_token(port, app_id, auth_code, app_secret)
|
53
|
+
auth_uri = "https://graph.facebook.com/v#{API_VERSION}/oauth/access_token?" +
|
54
|
+
"client_id=#{app_id}" +
|
55
|
+
"&redirect_uri=http://localhost:#{port}/" +
|
56
|
+
"&client_secret=#{app_secret}" +
|
57
|
+
"&code=#{auth_code}"
|
58
|
+
|
59
|
+
res = Net::HTTP.get_response(URI.parse(auth_uri))
|
60
|
+
res = JSON.parse(res.body)
|
61
|
+
|
62
|
+
[res["access_token"], res["expires_in"]]
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.expiration_str(seconds)
|
66
|
+
h, m = seconds.divmod(60 * 3600)
|
67
|
+
|
68
|
+
"#{h} hours and #{m.div 3600} minutes"
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'koala'
|
2
|
+
|
3
|
+
module FBCLI
|
4
|
+
def self.init_api(global_options)
|
5
|
+
if not global_options[:token].nil?
|
6
|
+
$config['access_token'] = global_options[:token]
|
7
|
+
end
|
8
|
+
|
9
|
+
if $config['access_token'].nil? or $config['access_token'].empty?
|
10
|
+
exit_now! "You must first acquire an access token; run: #{$0} login"
|
11
|
+
end
|
12
|
+
|
13
|
+
Koala::Facebook::API.new($config['access_token'])
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.request_data(global_options, cmd)
|
17
|
+
api = init_api(global_options)
|
18
|
+
|
19
|
+
begin
|
20
|
+
data = api.get_connections("me", cmd)
|
21
|
+
rescue Koala::Facebook::APIError => e
|
22
|
+
exit_now! \
|
23
|
+
"Koala #{e.fb_error_type} (code #{e.fb_error_code})" +
|
24
|
+
if not e.http_status.nil? then " HTTP status: #{e.http_status}" else "" end +
|
25
|
+
"\n #{e.fb_error_message}"
|
26
|
+
end
|
27
|
+
|
28
|
+
data
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.page_items(global_options, cmd)
|
32
|
+
items = request_data(global_options, cmd)
|
33
|
+
|
34
|
+
while not items.nil? do
|
35
|
+
items.each { |item|
|
36
|
+
yield item
|
37
|
+
}
|
38
|
+
|
39
|
+
items = items.next_page
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/fbcli/format.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module FBCLI
|
2
|
+
# Facebook returns dates in ISO 8601 format
|
3
|
+
def self.date(fb_date)
|
4
|
+
Time.parse(fb_date).httpdate
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.link(path, format = $format)
|
8
|
+
url = "https://www.facebook.com/#{path}"
|
9
|
+
|
10
|
+
case format
|
11
|
+
when "html"
|
12
|
+
"<a href=\"#{url}\">#{url}</a>"
|
13
|
+
else
|
14
|
+
url
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.write(str = "", format = $format)
|
19
|
+
str = "" if str.nil?
|
20
|
+
|
21
|
+
if format == "html"
|
22
|
+
str = " " + str + "<br>"
|
23
|
+
end
|
24
|
+
|
25
|
+
puts str.encode('utf-8')
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facebook-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ildar Sagdejev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A limited command line interface to the Facebook Graph API
|
14
|
+
email: specious@gmail.com
|
15
|
+
executables:
|
16
|
+
- facebook-cli
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/facebook-cli
|
21
|
+
- lib/fbcli.rb
|
22
|
+
- lib/fbcli/auth.rb
|
23
|
+
- lib/fbcli/facebook.rb
|
24
|
+
- lib/fbcli/format.rb
|
25
|
+
homepage: https://github.com/specious/facebook-cli
|
26
|
+
licenses:
|
27
|
+
- MIT
|
28
|
+
metadata: {}
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.3'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 2.5.1
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: Facebook command line utility
|
49
|
+
test_files: []
|