feed2gram 1.2.4 → 1.3.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/example/Gemfile +1 -0
- data/lib/feed2gram/publishes_posts.rb +93 -48
- data/lib/feed2gram/refreshes_token.rb +14 -6
- data/lib/feed2gram/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73e7d2df466144a3e956cc38742d783cce241a65894beaa90e7b332ee1b99ea6
|
4
|
+
data.tar.gz: 9b58a6e07f42adcae0b86969f01d84df77480e2db7831a6b98dd48ab67159ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a46c7e7ca41c516c88ed3f12fee71506a5b24f280dd784d53c787cc910027bebb3b37fda1f364ad6b8dd84e9d5460ee569c4e7ff3a2eb480195b3ce6a6ddb8a4
|
7
|
+
data.tar.gz: 4a1c63c08f0ddf6693e587f2a2bd78c94e1638cd68471f54a50cd1d1df4c67ac8fbb876a402ac9b8d63e018f20ad5c415ce90b0d487bfc26b1950524c3f07054
|
data/CHANGELOG.md
CHANGED
data/example/Gemfile
CHANGED
@@ -31,6 +31,79 @@ module Feed2Gram
|
|
31
31
|
}
|
32
32
|
end
|
33
33
|
|
34
|
+
# Pseudo-public "API mode"
|
35
|
+
def create_single_media_container(post, config)
|
36
|
+
media = post.medias.first
|
37
|
+
Http.post("/#{config.instagram_id}/media", {
|
38
|
+
:media_type => post.media_type,
|
39
|
+
:caption => post.caption,
|
40
|
+
:access_token => config.access_token,
|
41
|
+
:cover_url => media.cover_url,
|
42
|
+
media.video? ? :video_url : :image_url => media.url
|
43
|
+
}.compact)[:id]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Pseudo-public "API mode"
|
47
|
+
def create_carousel_media_container(media, config)
|
48
|
+
res = Http.post("/#{config.instagram_id}/media", {
|
49
|
+
:media_type => media.media_type,
|
50
|
+
:is_carousel_item => true,
|
51
|
+
:access_token => config.access_token,
|
52
|
+
media.video? ? :video_url : :image_url => media.url
|
53
|
+
}.compact)
|
54
|
+
res[:id]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Pseudo-public "API mode"
|
58
|
+
def create_carousel_container(post, media_containers, config)
|
59
|
+
Http.post("/#{config.instagram_id}/media", {
|
60
|
+
caption: post.caption,
|
61
|
+
media_type: post.media_type,
|
62
|
+
children: media_containers.join(","),
|
63
|
+
access_token: config.access_token
|
64
|
+
})[:id]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pseudo-public "API mode"
|
68
|
+
def upload_finished?(container_id, config)
|
69
|
+
res = Http.get("/#{container_id}", {
|
70
|
+
fields: "status_code,status",
|
71
|
+
access_token: config.access_token
|
72
|
+
})
|
73
|
+
|
74
|
+
if res[:status_code] == "FINISHED"
|
75
|
+
true
|
76
|
+
elsif res[:status_code] == "IN_PROGRESS"
|
77
|
+
false
|
78
|
+
else
|
79
|
+
raise <<~MSG
|
80
|
+
Unexpected status code (#{res[:status_code]}) uploading container: #{container_id}"
|
81
|
+
|
82
|
+
API sent back this: #{res[:status]}
|
83
|
+
|
84
|
+
Error codes can be looked up here: https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/error-codes/
|
85
|
+
MSG
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Pseudo-public "API mode"
|
90
|
+
def publish_container(container_id, config)
|
91
|
+
res = Http.post("/#{config.instagram_id}/media_publish", {
|
92
|
+
creation_id: container_id,
|
93
|
+
access_token: config.access_token
|
94
|
+
})
|
95
|
+
res[:id]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Pseudo-public "API mode"
|
99
|
+
def get_media_permalink(media_id, config)
|
100
|
+
res = Http.get("/#{media_id}", {
|
101
|
+
fields: "permalink",
|
102
|
+
access_token: config.access_token
|
103
|
+
})
|
104
|
+
res[:permalink]
|
105
|
+
end
|
106
|
+
|
34
107
|
private
|
35
108
|
|
36
109
|
def retry_if_upload_times_out(times_remaining, post, options, &blk)
|
@@ -49,55 +122,35 @@ module Feed2Gram
|
|
49
122
|
media = post.medias.first
|
50
123
|
|
51
124
|
puts "Creating media resource for URL - #{media.url}" if options.verbose
|
52
|
-
container_id =
|
53
|
-
:media_type => post.media_type,
|
54
|
-
:caption => post.caption,
|
55
|
-
:access_token => config.access_token,
|
56
|
-
:cover_url => media.cover_url,
|
57
|
-
media.video? ? :video_url : :image_url => media.url
|
58
|
-
}.compact)[:id]
|
125
|
+
container_id = create_single_media_container(post, config)
|
59
126
|
|
60
127
|
if media.video?
|
61
128
|
wait_for_media_to_upload!(media.url, container_id, config, options)
|
62
129
|
end
|
63
130
|
|
64
131
|
puts "Publishing media for URL - #{media.url}" if options.verbose
|
65
|
-
|
66
|
-
creation_id: container_id,
|
67
|
-
access_token: config.access_token
|
68
|
-
})
|
132
|
+
publish_container(container_id, config)
|
69
133
|
Result.new(post: post, status: :posted)
|
70
134
|
end
|
71
135
|
|
72
136
|
def publish_carousel(post, config, options)
|
73
137
|
media_containers = post.medias.take(10).map { |media|
|
74
138
|
puts "Creating media resource for URL - #{media.url}" if options.verbose
|
75
|
-
|
76
|
-
:media_type => media.media_type,
|
77
|
-
:is_carousel_item => true,
|
78
|
-
:access_token => config.access_token,
|
79
|
-
media.video? ? :video_url : :image_url => media.url
|
80
|
-
}.compact)
|
81
|
-
res[:id]
|
139
|
+
create_carousel_media_container(media, config)
|
82
140
|
}
|
83
|
-
post.medias.
|
84
|
-
|
141
|
+
post.medias.zip(media_containers).each { |media, container_id|
|
142
|
+
if media.video?
|
143
|
+
wait_for_media_to_upload!(media.url, container_id, config, options)
|
144
|
+
end
|
85
145
|
}
|
86
146
|
|
87
147
|
puts "Creating carousel media resource for post - #{post.url}" if options.verbose
|
88
|
-
carousel_id =
|
89
|
-
|
90
|
-
media_type: post.media_type,
|
91
|
-
children: media_containers.join(","),
|
92
|
-
access_token: config.access_token
|
93
|
-
})[:id]
|
148
|
+
carousel_id = create_carousel_container(post, media_containers, config)
|
149
|
+
|
94
150
|
wait_for_media_to_upload!(post.url, carousel_id, config, options)
|
95
151
|
|
96
152
|
puts "Publishing carousel media for post - #{post.url}" if options.verbose
|
97
|
-
|
98
|
-
creation_id: carousel_id,
|
99
|
-
access_token: config.access_token
|
100
|
-
})
|
153
|
+
publish_container(carousel_id, config)
|
101
154
|
Result.new(post: post, status: :posted)
|
102
155
|
end
|
103
156
|
|
@@ -110,24 +163,16 @@ module Feed2Gram
|
|
110
163
|
raise FacebookSucksAtDownloadingFilesError
|
111
164
|
end
|
112
165
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
else
|
124
|
-
warn <<~MSG
|
125
|
-
Unexpected status code (#{res[:status_code]}) uploading: #{url}"
|
126
|
-
|
127
|
-
API sent back this: #{res[:status]}
|
128
|
-
|
129
|
-
Error codes can be looked up here: https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/error-codes/
|
130
|
-
MSG
|
166
|
+
begin
|
167
|
+
puts "Uploading after waiting #{wait_attempts * SECONDS_PER_UPLOAD_CHECK} seconds for IG to download #{url}" if options.verbose
|
168
|
+
if upload_finished?(container_id, config)
|
169
|
+
break
|
170
|
+
else
|
171
|
+
wait_attempts += 1
|
172
|
+
sleep SECONDS_PER_UPLOAD_CHECK
|
173
|
+
end
|
174
|
+
rescue => e
|
175
|
+
warn e.message
|
131
176
|
break
|
132
177
|
end
|
133
178
|
end
|
@@ -1,10 +1,22 @@
|
|
1
1
|
module Feed2Gram
|
2
2
|
class RefreshesToken
|
3
3
|
def refresh!(config, options)
|
4
|
+
puts "Refreshing Facebook OAuth token" if options.verbose
|
5
|
+
new_access_token = call(config)
|
6
|
+
return unless new_access_token
|
7
|
+
|
8
|
+
config.access_token = new_access_token
|
9
|
+
config.access_token_refreshed_at = Time.now.utc
|
10
|
+
|
11
|
+
puts "Updating Facebook OAuth token in: #{options.config_path}" if options.verbose
|
12
|
+
File.write(options.config_path, config.as_yaml)
|
13
|
+
end
|
14
|
+
|
15
|
+
# "API mode"
|
16
|
+
def call(config)
|
4
17
|
return unless config.access_token_refreshed_at.nil? ||
|
5
18
|
config.access_token_refreshed_at < Time.now - (60 * 60)
|
6
19
|
|
7
|
-
puts "Refreshing Facebook OAuth token" if options.verbose
|
8
20
|
data = Http.get("/oauth/access_token", {
|
9
21
|
grant_type: "fb_exchange_token",
|
10
22
|
client_id: config.facebook_app_id,
|
@@ -12,11 +24,7 @@ module Feed2Gram
|
|
12
24
|
fb_exchange_token: config.access_token
|
13
25
|
})
|
14
26
|
|
15
|
-
|
16
|
-
config.access_token_refreshed_at = Time.now.utc
|
17
|
-
|
18
|
-
puts "Updating Facebook OAuth token in: #{options.config_path}" if options.verbose
|
19
|
-
File.write(options.config_path, config.as_yaml)
|
27
|
+
data[:access_token]
|
20
28
|
end
|
21
29
|
end
|
22
30
|
end
|
data/lib/feed2gram/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feed2gram
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
|
-
rubygems_version: 3.5.
|
80
|
+
rubygems_version: 3.5.11
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
83
|
summary: Reads an Atom feed and posts its entries to Instagram
|