facebook-cli 1.0.0
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/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: []
|