feed2gram 1.2.2 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f1c5ede06c494a4b45e77b7ba717c408f72ce9c2ae272c97550b6f0e687fae2
4
- data.tar.gz: df2a2f0ff2ac9ec4663c5fb4c7f48fb2e1cd9aa3f31c4b9ff7cfc0dde5308946
3
+ metadata.gz: 3cafa61ecf677b96b07c3d83aa855d165dcbeb95c34c550b335ae605e6103734
4
+ data.tar.gz: 6bb6d2b824e81d738e28cdf143e4278a0979e1a40b03d064e04370478a12328a
5
5
  SHA512:
6
- metadata.gz: 8c0e76000c8a937c57d082e0a20c2e8d05bdb193476584a873bd034eed858fdca7702dbd37a3889d3338e4e79ad05c605a2f61ee4d80e8245a479fdf1e90d878
7
- data.tar.gz: e377a974a2aa8c51e8cf8e2eff23feb30b88b5da9c3a63979de1c05ce5a3e7ede6f0e764f65ff7b9f01266c4bb581dfe63a548ad67e4b25c6aac8968a9288a2e
6
+ metadata.gz: 47f0207f0c8da0e90ef63b176f5a1c9bbff08d9da467028b58a1bb4a54177d2b72ce9a8419d0b00372e53b0ae4180051cd95cb69de0f2373b5b029db55581359
7
+ data.tar.gz: 98af19289a16b92af530000d32275aa5a471a70024c0fa88b7749bcb4e07046f2eafed9f041f9f35b3072af2e130c81ee403f7468a6400ea04926afc48be983b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [1.2.4]
2
+
3
+ * When uploads fail, output a message that includes the error code
4
+ (and the URL to look them up)
5
+
6
+ ## [1.2.3]
7
+
8
+ * Add a retry option after IG continues to fail to download videos correctly. See `RETRIES_AFTER_UPLOAD_TIMEOUT` (default 5 retries)
9
+
1
10
  ## [1.2.2]
2
11
 
3
12
  * Fix integer/string conversion error when env vars from 1.2.1 are set
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # feed2gram
1
+ # feed2gram - Syndicate your site's photos, videos, and carousels to Instagram
2
+
3
+ **feed2gram is for automating Instagram posts, for posting to Threads, see
4
+ [feed2thread](https://github.com/searls/feed2thread)**
2
5
 
3
6
  I've joined the [POSSE](https://indieweb.org/POSSE) and publish as much as I can
4
7
  to [justin.searls.co](https://justin.searls.co) and syndicate it elsewhere. I'm
@@ -101,8 +104,10 @@ Usage: feed2gram [options]
101
104
  These environment variables can be set to augment the gem's behavior:
102
105
 
103
106
  * `SECONDS_PER_UPLOAD_CHECK` - when uploading video, feed2gram must wait until
104
- the [status code](https://tiagogrosso.github.io/instagram-graph-api-lib/enums/CONTAINER_STATUS_CODE.html) on the media indicates it is published. This variable determines how many seconds to wait between each check (defaults to 30 seconds). Shortening this value can lead to hitting one's hourly rate limit
105
- * `MAX_UPLOAD_STATUS_CHECKS` - how many status checks to perform before giving up on a piece of media and calling the post failed. Unfortunately, Facebook's servers can take anywhere from 15 seconds to 15 hours to download and process even trivially small videos, so GLHF
107
+ the [status code](https://tiagogrosso.github.io/instagram-graph-api-lib/enums/CONTAINER_STATUS_CODE.html) on the media indicates it is published. This variable determines how many seconds to wait between each check (defaults to `30` seconds). Shortening this value can lead to hitting one's hourly rate limit
108
+ * `MAX_UPLOAD_STATUS_CHECKS` - how many status checks to perform before giving up on a piece of media and calling the post failed. Unfortunately, Facebook's servers can take anywhere from 15 seconds to 15 hours to download and process even trivially small videos, so GLHF (defaults to `100` attempts)
109
+ * `RETRIES_AFTER_UPLOAD_TIMEOUT` - because Facebook's servers will so often hang and fail to download videos (even when you
110
+ set the timeout to absurd lengths like 20 hours, it'll still report `IN_PROGRESS`), it may be necessary to retry after timeout. (defaults to `5` retries)
106
111
 
107
112
  ## Formatting your Atom feed's HTML
108
113
 
@@ -167,7 +172,7 @@ We publish a Docker image [using GitHub
167
172
  actions](https://github.com/searls/feed2gram/blob/main/.github/workflows/main.yml)
168
173
  tagged as `latest` for every new commit to the `main` branch, as well as with a
169
174
  release tag tracking every release of the gem on
170
- [rubygems.org](https://rubygems.org). The images are hosted [here on GitHub's
175
+ [rubygems.org](https://rubygems.org/gems/feed2gram). The images are hosted [here on GitHub's
171
176
  container
172
177
  registry](https://github.com/searls/feed2gram/pkgs/container/feed2gram)
173
178
 
data/example/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- feed2gram (1.2.2)
4
+ feed2gram (1.2.3)
5
5
  nokogiri (~> 1.15)
6
6
 
7
7
  GEM
@@ -1,7 +1,12 @@
1
1
  module Feed2Gram
2
2
  Result = Struct.new(:post, :status, keyword_init: true)
3
+ class FacebookSucksAtDownloadingFilesError < StandardError; end
3
4
 
4
5
  class PublishesPosts
6
+ SECONDS_PER_UPLOAD_CHECK = ENV.fetch("SECONDS_PER_UPLOAD_CHECK") { 30 }.to_i
7
+ MAX_UPLOAD_STATUS_CHECKS = ENV.fetch("MAX_UPLOAD_STATUS_CHECKS") { 100 }.to_i
8
+ RETRIES_AFTER_UPLOAD_TIMEOUT = ENV.fetch("RETRIES_AFTER_UPLOAD_TIMEOUT") { 5 }.to_i
9
+
5
10
  def publish(posts, config, options)
6
11
  post_limit = options.limit || posts.size
7
12
  puts "Publishing #{post_limit} posts to Instagram" if options.verbose
@@ -9,12 +14,14 @@ module Feed2Gram
9
14
  # reverse to post oldest first (most Atom feeds are reverse-chronological)
10
15
  posts.reverse.take(post_limit).map { |post|
11
16
  begin
12
- if post.medias.size == 1
13
- puts "Publishing #{post.media_type.downcase} for: #{post.url}" if options.verbose
14
- publish_single_media(post, config, options)
15
- else
16
- puts "Publishing carousel for: #{post.url}" if options.verbose
17
- publish_carousel(post, config, options)
17
+ retry_if_upload_times_out(RETRIES_AFTER_UPLOAD_TIMEOUT, post, options) do
18
+ if post.medias.size == 1
19
+ puts "Publishing #{post.media_type.downcase} for: #{post.url}" if options.verbose
20
+ publish_single_media(post, config, options)
21
+ else
22
+ puts "Publishing carousel for: #{post.url}" if options.verbose
23
+ publish_carousel(post, config, options)
24
+ end
18
25
  end
19
26
  rescue => e
20
27
  warn "Failed to post #{post.url}: #{e.message}"
@@ -26,6 +33,18 @@ module Feed2Gram
26
33
 
27
34
  private
28
35
 
36
+ def retry_if_upload_times_out(times_remaining, post, options, &blk)
37
+ blk.call
38
+ rescue FacebookSucksAtDownloadingFilesError
39
+ if times_remaining > 0
40
+ puts "Will retry with attempt ##{RETRIES_AFTER_UPLOAD_TIMEOUT - times_remaining + 2} after Facebook failed to download a video without timing out for: #{post.url}" if options.verbose
41
+ retry_if_upload_times_out(times_remaining - 1, post, options, &blk)
42
+ else
43
+ warn "Failed to post #{post.url} after #{RETRIES_AFTER_UPLOAD_TIMEOUT} retries due to Facebook timing out on video downloads"
44
+ Result.new(post: post, status: :failed)
45
+ end
46
+ end
47
+
29
48
  def publish_single_media(post, config, options)
30
49
  media = post.medias.first
31
50
 
@@ -82,19 +101,17 @@ module Feed2Gram
82
101
  Result.new(post: post, status: :posted)
83
102
  end
84
103
 
85
- SECONDS_PER_UPLOAD_CHECK = ENV.fetch("SECONDS_PER_UPLOAD_CHECK") { 30 }.to_i
86
- MAX_UPLOAD_STATUS_CHECKS = ENV.fetch("MAX_UPLOAD_STATUS_CHECKS") { 100 }.to_i
87
104
  # Good ol' loop-and-sleep. Haven't loop do'd in a while
88
105
  def wait_for_media_to_upload!(url, container_id, config, options)
89
106
  wait_attempts = 0
90
107
  loop do
91
108
  if wait_attempts > MAX_UPLOAD_STATUS_CHECKS
92
109
  warn "Giving up waiting for media to upload after waiting #{SECONDS_PER_UPLOAD_CHECK * MAX_UPLOAD_STATUS_CHECKS} seconds: #{url}"
93
- break
110
+ raise FacebookSucksAtDownloadingFilesError
94
111
  end
95
112
 
96
113
  res = Http.get("/#{container_id}", {
97
- fields: "status_code",
114
+ fields: "status_code,status",
98
115
  access_token: config.access_token
99
116
  })
100
117
  puts "Upload status #{res[:status_code]} after waiting #{wait_attempts * SECONDS_PER_UPLOAD_CHECK} seconds for IG to download #{url}" if options.verbose
@@ -104,7 +121,13 @@ module Feed2Gram
104
121
  wait_attempts += 1
105
122
  sleep SECONDS_PER_UPLOAD_CHECK
106
123
  else
107
- warn "Unexpected status code (#{res[:status_code]}) uploading: #{url}"
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
108
131
  break
109
132
  end
110
133
  end
@@ -1,3 +1,3 @@
1
1
  module Feed2Gram
2
- VERSION = "1.2.2"
2
+ VERSION = "1.2.4"
3
3
  end
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.2.2
4
+ version: 1.2.4
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-02-13 00:00:00.000000000 Z
11
+ date: 2024-08-14 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.4
80
+ rubygems_version: 3.5.14
81
81
  signing_key:
82
82
  specification_version: 4
83
83
  summary: Reads an Atom feed and posts its entries to Instagram