feed2gram 1.2.2 → 1.2.4
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 +9 -0
- data/README.md +9 -4
- data/example/Gemfile.lock +1 -1
- data/lib/feed2gram/publishes_posts.rb +34 -11
- 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: 3cafa61ecf677b96b07c3d83aa855d165dcbeb95c34c550b335ae605e6103734
         | 
| 4 | 
            +
              data.tar.gz: 6bb6d2b824e81d738e28cdf143e4278a0979e1a40b03d064e04370478a12328a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 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,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 | 
            -
                       | 
| 13 | 
            -
                         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                         | 
| 17 | 
            -
             | 
| 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 | 
            -
                       | 
| 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  | 
| 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
         | 
    
        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.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- | 
| 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. | 
| 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
         |