feed2gram 1.1.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +9 -0
- data/example/Gemfile +6 -0
- data/example/Gemfile.lock +59 -0
- data/example/sample.xml +38 -0
- data/example/server.rb +9 -0
- data/lib/feed2gram/parses_entries.rb +3 -2
- data/lib/feed2gram/publishes_posts.rb +7 -4
- data/lib/feed2gram/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6be6dddfdc2c228de285536b0fbefd7a5f1d34d864fd625e21c996307cc439f1
|
4
|
+
data.tar.gz: 35509d9f7bfacf70bce7ce37fdba2ddae9bb783171a561aad80b27b5ba9b0546
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf84920a3113a0bbe9c73790171e8216846aa4f7d66edeabd4ae9f58b71857a65c81630f1cc5eab094b1fe246ae5069a6086e2a798d39f9a925e3c4c2e3951cb
|
7
|
+
data.tar.gz: 3176d62ca5a41b2de36cf695771579de800fb3346ae83aa31d51d0716b780afb29dc1a49a268d2c32caf14d351120fcf7fad533e828ce38566089d446bcec63f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [1.2.1]
|
2
|
+
|
3
|
+
* Add `SECONDS_PER_UPLOAD_CHECK` and `MAX_UPLOAD_STATUS_CHECKS` env vars
|
4
|
+
|
5
|
+
## [1.2.0]
|
6
|
+
|
7
|
+
* Add support for the `cover_url` property for reel posts by way of a
|
8
|
+
`data-cover-url` attribute on the `<img>` tag of single-video posts..
|
9
|
+
|
1
10
|
## [1.1.0]
|
2
11
|
|
3
12
|
* Add support for videos and stories, including:
|
data/README.md
CHANGED
@@ -96,6 +96,14 @@ Usage: feed2gram [options]
|
|
96
96
|
--populate-cache Populate the cache file with any posts found in the feed WITHOUT posting them to Instagram
|
97
97
|
```
|
98
98
|
|
99
|
+
## Environment variables
|
100
|
+
|
101
|
+
These environment variables can be set to augment the gem's behavior:
|
102
|
+
|
103
|
+
* `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
|
106
|
+
|
99
107
|
## Formatting your Atom feed's HTML
|
100
108
|
|
101
109
|
feed2gram uses the first `<figure>` element to generate each Instagram post. That `<figure>` can contain one or more `<img>` tags and one `<figcaption>` tag, which will be used as the post's image(s) and caption, respectively.
|
@@ -108,6 +116,7 @@ Some things to keep in mind:
|
|
108
116
|
* If one `<img>` tag is present, a single photo post will be created. If there are more, a [carousel post](https://developers.facebook.com/docs/instagram-api/guides/content-publishing/#carousel-posts) will be created
|
109
117
|
* Because Facebook's servers actually _download your image_ as opposed to receiving them as uploads via the API, every `<img>` tag's `src` attribute must be set to a publicly-reachable, fully-qualified URL
|
110
118
|
* To post videos, stories, or reels, set the `data-media-type` attribute on the `<img>` tag to `video` or `image` (a media type of `image` will be assumed by default if left unspecified). Note that while `image` and `video` media may be interspersed throughout a carousel
|
119
|
+
* For video (reel) posts containing a single video, you can set `data-cover-url` on the `<img>` tag to a publicly-available URL and the Instagram API will use it as a custom thumbnail for the reel
|
111
120
|
* For carousel posts, the aspect ratio of the first image determines the aspect ratio of the rest, so be mindful of how you order the images based on how you want them to appear in the app
|
112
121
|
* Only one caption will be published, regardless of whether it's a single photo post or a carousel
|
113
122
|
* The caption limit is 2200 characters, so feed2gram will truncate it if necessary
|
data/example/Gemfile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
feed2gram (1.2.1)
|
5
|
+
nokogiri (~> 1.15)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
base64 (0.2.0)
|
11
|
+
mustermann (3.0.0)
|
12
|
+
ruby2_keywords (~> 0.0.1)
|
13
|
+
nokogiri (1.16.2-aarch64-linux)
|
14
|
+
racc (~> 1.4)
|
15
|
+
nokogiri (1.16.2-arm-linux)
|
16
|
+
racc (~> 1.4)
|
17
|
+
nokogiri (1.16.2-arm64-darwin)
|
18
|
+
racc (~> 1.4)
|
19
|
+
nokogiri (1.16.2-x86-linux)
|
20
|
+
racc (~> 1.4)
|
21
|
+
nokogiri (1.16.2-x86_64-darwin)
|
22
|
+
racc (~> 1.4)
|
23
|
+
nokogiri (1.16.2-x86_64-linux)
|
24
|
+
racc (~> 1.4)
|
25
|
+
racc (1.7.3)
|
26
|
+
rack (3.0.9)
|
27
|
+
rack-protection (4.0.0)
|
28
|
+
base64 (>= 0.1.0)
|
29
|
+
rack (>= 3.0.0, < 4)
|
30
|
+
rack-session (2.0.0)
|
31
|
+
rack (>= 3.0.0)
|
32
|
+
rackup (2.1.0)
|
33
|
+
rack (>= 3)
|
34
|
+
webrick (~> 1.8)
|
35
|
+
ruby2_keywords (0.0.5)
|
36
|
+
sinatra (4.0.0)
|
37
|
+
mustermann (~> 3.0)
|
38
|
+
rack (>= 3.0.0, < 4)
|
39
|
+
rack-protection (= 4.0.0)
|
40
|
+
rack-session (>= 2.0.0, < 3)
|
41
|
+
tilt (~> 2.0)
|
42
|
+
tilt (2.3.0)
|
43
|
+
webrick (1.8.1)
|
44
|
+
|
45
|
+
PLATFORMS
|
46
|
+
aarch64-linux
|
47
|
+
arm-linux
|
48
|
+
arm64-darwin
|
49
|
+
x86-linux
|
50
|
+
x86_64-darwin
|
51
|
+
x86_64-linux
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
feed2gram!
|
55
|
+
rackup
|
56
|
+
sinatra
|
57
|
+
|
58
|
+
BUNDLED WITH
|
59
|
+
2.5.4
|
data/example/sample.xml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us">
|
3
|
+
<id>https://gram.betterwithbecky.com/syndications/grams</id>
|
4
|
+
<title>Beckygram</title>
|
5
|
+
<updated>2024-02-09T12:41:16Z</updated>
|
6
|
+
<author>
|
7
|
+
<name>Becky Searls</name>
|
8
|
+
<email>becky@betterwithbecky.com</email>
|
9
|
+
</author>
|
10
|
+
<link href="https://gram.betterwithbecky.com/" rel="alternate" type="text/html" title="HTML"/>
|
11
|
+
<link href="https://gram.betterwithbecky.com/syndications/grams" rel="self" type="application/atom+xml" title="Grams"/>
|
12
|
+
<category term="Fitness"/>
|
13
|
+
<generator uri="https://rubyonrails.org/" version="0.119.0">
|
14
|
+
Ruby on Rails </generator>
|
15
|
+
<icon>https://gram.betterwithbecky.com/favicon.ico</icon>
|
16
|
+
<logo>https://static-cdn.betterwithbecky.com/assets/logo-fa728624cb9c92f3e052ee6b58a653d8e64fda32.png</logo>
|
17
|
+
<rights>Copyright Build with Becky LLC. All rights reserved.</rights>
|
18
|
+
<subtitle>What you're getting when you get Better with Becky.</subtitle>
|
19
|
+
<entry>
|
20
|
+
<id>https://gram.betterwithbecky.com/posts/1/whatever</id>
|
21
|
+
<title type="text">Test Title</title>
|
22
|
+
<link href="https://gram.betterwithbecky.com/posts/1/whatever" rel="alternate" type="text/html"/>
|
23
|
+
<author>
|
24
|
+
<name>Becky Searls</name>
|
25
|
+
<email>becky@example.com</email>
|
26
|
+
</author>
|
27
|
+
<published>2024-02-04T14:59:00Z</published>
|
28
|
+
<updated>2024-02-09T12:41:16Z</updated>
|
29
|
+
<content type="html"><![CDATA[
|
30
|
+
<figure data-post-type="post">
|
31
|
+
<img data-media-type="video" data-cover-url="https://upload.wikimedia.org/wikipedia/commons/7/7c/Aspect_ratio_16_9_example.jpg" src="https://static.videezy.com/system/resources/previews/000/032/359/original/MM008645___BOUNCING_FRUIT_009___1080p___phantom.mp4"/>"
|
32
|
+
<figcaption>
|
33
|
+
Nothing to see here. Just a test post.
|
34
|
+
</figcaption>
|
35
|
+
</figure>
|
36
|
+
]]></content>
|
37
|
+
</entry>
|
38
|
+
</feed>
|
data/example/server.rb
ADDED
@@ -2,7 +2,7 @@ require "nokogiri"
|
|
2
2
|
require "open-uri"
|
3
3
|
|
4
4
|
module Feed2Gram
|
5
|
-
Media = Struct.new(:media_type, :url, keyword_init: true) do
|
5
|
+
Media = Struct.new(:media_type, :url, :cover_url, keyword_init: true) do
|
6
6
|
def video?
|
7
7
|
media_type == "VIDEO"
|
8
8
|
end
|
@@ -17,7 +17,8 @@ module Feed2Gram
|
|
17
17
|
medias = html.xpath("//figure[1]/img").map { |img|
|
18
18
|
Media.new(
|
19
19
|
media_type: (img["data-media-type"] || "image").upcase,
|
20
|
-
url: img["src"]
|
20
|
+
url: img["src"],
|
21
|
+
cover_url: img["data-cover-url"]
|
21
22
|
)
|
22
23
|
}
|
23
24
|
|
@@ -33,6 +33,7 @@ module Feed2Gram
|
|
33
33
|
:media_type => post.media_type,
|
34
34
|
:caption => post.caption,
|
35
35
|
:access_token => config.access_token,
|
36
|
+
:cover_url => media.cover_url,
|
36
37
|
media.video? ? :video_url : :image_url => media.url
|
37
38
|
}.compact)[:id]
|
38
39
|
|
@@ -80,12 +81,14 @@ module Feed2Gram
|
|
80
81
|
Result.new(post: post, status: :posted)
|
81
82
|
end
|
82
83
|
|
84
|
+
SECONDS_PER_UPLOAD_CHECK = ENV.fetch("SECONDS_PER_UPLOAD_CHECK") { 30 }
|
85
|
+
MAX_UPLOAD_STATUS_CHECKS = ENV.fetch("MAX_UPLOAD_STATUS_CHECKS") { 100 }
|
83
86
|
# Good ol' loop-and-sleep. Haven't loop do'd in a while
|
84
87
|
def wait_for_media_to_upload!(url, container_id, config, options)
|
85
88
|
wait_attempts = 0
|
86
89
|
loop do
|
87
|
-
if wait_attempts >
|
88
|
-
warn "Giving up waiting for media to upload after waiting
|
90
|
+
if wait_attempts > MAX_UPLOAD_STATUS_CHECKS
|
91
|
+
warn "Giving up waiting for media to upload after waiting #{SECONDS_PER_UPLOAD_CHECK * MAX_UPLOAD_STATUS_CHECKS} seconds: #{url}"
|
89
92
|
break
|
90
93
|
end
|
91
94
|
|
@@ -93,12 +96,12 @@ module Feed2Gram
|
|
93
96
|
fields: "status_code",
|
94
97
|
access_token: config.access_token
|
95
98
|
})
|
96
|
-
puts "Upload status #{res[:status_code]} after #{wait_attempts
|
99
|
+
puts "Upload status #{res[:status_code]} after waiting #{wait_attempts * SECONDS_PER_UPLOAD_CHECK} seconds for IG to download #{url}" if options.verbose
|
97
100
|
if res[:status_code] == "FINISHED"
|
98
101
|
break
|
99
102
|
elsif res[:status_code] == "IN_PROGRESS"
|
100
103
|
wait_attempts += 1
|
101
|
-
sleep
|
104
|
+
sleep SECONDS_PER_UPLOAD_CHECK
|
102
105
|
else
|
103
106
|
warn "Unexpected status code (#{res[:status_code]}) uploading: #{url}"
|
104
107
|
break
|
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.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -38,6 +38,10 @@ files:
|
|
38
38
|
- LICENSE.txt
|
39
39
|
- README.md
|
40
40
|
- Rakefile
|
41
|
+
- example/Gemfile
|
42
|
+
- example/Gemfile.lock
|
43
|
+
- example/sample.xml
|
44
|
+
- example/server.rb
|
41
45
|
- exe/feed2gram
|
42
46
|
- lib/feed2gram.rb
|
43
47
|
- lib/feed2gram/filters_posts.rb
|
@@ -73,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
77
|
- !ruby/object:Gem::Version
|
74
78
|
version: '0'
|
75
79
|
requirements: []
|
76
|
-
rubygems_version: 3.
|
80
|
+
rubygems_version: 3.5.3
|
77
81
|
signing_key:
|
78
82
|
specification_version: 4
|
79
83
|
summary: Reads an Atom feed and posts its entries to Instagram
|