reddit-to-telegram 0.8.1 → 0.10.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/.rubocop.yml +3 -0
- data/Gemfile.lock +6 -7
- data/README.md +34 -45
- data/lib/reddit-to-telegram.rb +1 -0
- data/lib/reddit_to_telegram/configuration.rb +20 -8
- data/lib/reddit_to_telegram/errors.rb +33 -2
- data/lib/reddit_to_telegram/post.rb +20 -17
- data/lib/reddit_to_telegram/reddit/fetch.rb +17 -2
- data/lib/reddit_to_telegram/reddit/output.rb +3 -2
- data/lib/reddit_to_telegram/store/aws_dynamo_db.rb +132 -0
- data/lib/reddit_to_telegram/store/memory.rb +16 -7
- data/lib/reddit_to_telegram/store/temp_file.rb +22 -10
- data/lib/reddit_to_telegram/store.rb +24 -8
- data/lib/reddit_to_telegram/telegram/post/gallery.rb +9 -9
- data/lib/reddit_to_telegram/telegram/post.rb +12 -25
- data/lib/reddit_to_telegram/telegram/prepare_request.rb +30 -20
- data/lib/reddit_to_telegram/version.rb +1 -1
- data/reddit-to-telegram.gemspec +1 -1
- metadata +8 -8
- data/lib/reddit_to_telegram/store/aws_simple_db.rb +0 -123
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 00436ff5f5d09c81d76f4d49f3cc3996e983857f1fbff2ad2db006ea014c0e96
         | 
| 4 | 
            +
              data.tar.gz: ca6e585387a1165a9dacdee453d4853e531b727f9498918c97675d9484275b6c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e2ff22eb616b95a99f3046b0c63677f24f7ca0ee1327bb7a51e97a68190b9c39639562024efaca73afa292b24b05188d9abaedba74de491bf708606526895519
         | 
| 7 | 
            +
              data.tar.gz: 8658836ee6bb761ff2c75f9cd7c11ea2c2f526604982933d48eced8edf31ac515b8ca3ed97ac34bb515dca7baa21cb3d5de10463e13268519d3b73f8293be8f0
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,8 +1,8 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                reddit-to-telegram (0. | 
| 5 | 
            -
                  aws-sdk- | 
| 4 | 
            +
                reddit-to-telegram (0.10.0)
         | 
| 5 | 
            +
                  aws-sdk-dynamodb (~> 1.106)
         | 
| 6 6 | 
             
                  httparty
         | 
| 7 7 |  | 
| 8 8 | 
             
            GEM
         | 
| @@ -11,15 +11,14 @@ GEM | |
| 11 11 | 
             
                ast (2.4.2)
         | 
| 12 12 | 
             
                aws-eventstream (1.3.0)
         | 
| 13 13 | 
             
                aws-partitions (1.883.0)
         | 
| 14 | 
            -
                aws-sdk-core (3. | 
| 14 | 
            +
                aws-sdk-core (3.192.1)
         | 
| 15 15 | 
             
                  aws-eventstream (~> 1, >= 1.3.0)
         | 
| 16 16 | 
             
                  aws-partitions (~> 1, >= 1.651.0)
         | 
| 17 17 | 
             
                  aws-sigv4 (~> 1.8)
         | 
| 18 18 | 
             
                  jmespath (~> 1, >= 1.6.1)
         | 
| 19 | 
            -
                aws-sdk- | 
| 20 | 
            -
                  aws-sdk-core (~> 3, >= 3. | 
| 21 | 
            -
                  aws- | 
| 22 | 
            -
                aws-sigv2 (1.2.0)
         | 
| 19 | 
            +
                aws-sdk-dynamodb (1.106.0)
         | 
| 20 | 
            +
                  aws-sdk-core (~> 3, >= 3.191.0)
         | 
| 21 | 
            +
                  aws-sigv4 (~> 1.1)
         | 
| 23 22 | 
             
                aws-sigv4 (1.8.0)
         | 
| 24 23 | 
             
                  aws-eventstream (~> 1, >= 1.0.2)
         | 
| 25 24 | 
             
                httparty (0.21.0)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -7,7 +7,7 @@ | |
| 7 7 | 
             
            Beware, this is remotely not production-ready, API will change, you'll see lots of bugs and it may break at any time.
         | 
| 8 8 | 
             
            Be sure to check for gem updates.
         | 
| 9 9 |  | 
| 10 | 
            -
            You can set this bot up absolutely for free [via AWS Lambda](https://gist.github.com/dersnek/851c32a6b45eab19f1c8748095b2a481#file-free-rtt-bot-in-aws-lambda).
         | 
| 10 | 
            +
            You can set this bot up absolutely for free [via AWS Lambda](https://gist.github.com/dersnek/851c32a6b45eab19f1c8748095b2a481#file-free-rtt-bot-in-aws-lambda), no ruby knowledge required.
         | 
| 11 11 |  | 
| 12 12 | 
             
            ## Installation
         | 
| 13 13 | 
             
            In your `Gemfile` add:
         | 
| @@ -19,33 +19,33 @@ Then run `bundle install`. | |
| 19 19 | 
             
            Or `gem install reddit-to-telegram`. Don't forget to `require` it.
         | 
| 20 20 |  | 
| 21 21 | 
             
            ## Prerequisites
         | 
| 22 | 
            -
            - (Optionally) You'll need an [AWS account](https://aws.amazon.com/) to host a free SimpleDB (best available storage type, also default one). I also recommend hosting the bot on AWS lambda, since it would be free.
         | 
| 23 | 
            -
            - (Optionally) [Create a Reddit app](https://www.reddit.com/prefs/apps), which would allow more requests to reddit
         | 
| 24 22 | 
             
            - [Obtain a telegram bot token](https://core.telegram.org/bots/tutorial#obtain-your-bot-token)
         | 
| 23 | 
            +
            - (Optionally) You'll need an [AWS account](https://aws.amazon.com/) to host a free DynamoDB (best available storage type, also default one). I also recommend hosting the bot on AWS lambda, since it would be free.
         | 
| 24 | 
            +
            - (Optionally) [Create a Reddit app](https://www.reddit.com/prefs/apps), which would allow more requests to reddit
         | 
| 25 25 |  | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
            | RTT_AWS_ACCESS_KEY_ID         | Your AWS access key ID. Needed for AWS SimpleDB storage                                                                                                                       | No       |
         | 
| 30 | 
            -
            | RTT_AWS_DOMAIN_NAME           | Domain name to use for SimpleDB                                                                                                                                               | No       |
         | 
| 31 | 
            -
            | RTT_AWS_REGION                | AWS region your SimpleDB will be hosted on. Beware, it's not available in all regions.                                                                                        | No       |
         | 
| 32 | 
            -
            | RTT_AWS_SECRET_ACCESS_KEY     | Your AWS access key ID. Needed for AWS SimpleDB storage.                                                                                                                      | No       |
         | 
| 33 | 
            -
            | RTT_GOOGLE_API_KEY            | Your Google API key to translate posts via Google Translate.                                                                                                                  | No       |
         | 
| 34 | 
            -
            | RTT_MAX_STORED_POSTS          | Number of posts to store in the database to avoid duplicates, default is 25.                                                                                                  | No       |
         | 
| 35 | 
            -
            | RTT_REDDIT_CLIENT_ID          | Reddit app credentials to access API. Reddit allows more authenticated requests.                                                                                              | No       |
         | 
| 36 | 
            -
            | RTT_REDDIT_CLIENT_SECRET      | Reddit app credentials to access API. Reddit allows more authenticated requests.                                                                                              | No       |
         | 
| 37 | 
            -
            | RTT_STORE_TYPE                | Choose between `aws_simple_db`, `memory` or `temp_file`. Default is `aws_simple_db`, so if you're not specifying your AWS credentials, you have to choose another store type. | No       |
         | 
| 38 | 
            -
            | RTT_TELEGRAM_BOT_TOKEN        | The token you've received when you've created a telegram bot.                                                                                                                 | Yes      |
         | 
| 39 | 
            -
            | RTT_TELEGRAM_ERROR_CHANNEL_ID | Telegram channel to send errors to (without `@`, only errors from Telegram API responses would be sent for now)                                                               | No       |
         | 
| 40 | 
            -
            | RTT_TEMP_DIR                  | Directory to write temp files to without trailing `/`                                                                                                                         | No       |
         | 
| 26 | 
            +
            It is pretty congifurable, either dynamically or via ENV variables.
         | 
| 27 | 
            +
            To assign variables dynamically, set them via `RedditToTelegram.config.variable_name= `, e.g. `RedditToTelegram.config.aws.access_key_id = ...`.
         | 
| 28 | 
            +
            You can also create an ENV variable with a corresponding name. Here is the full configuration explained. Required options have a * next to them.
         | 
| 41 29 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 30 | 
            +
            Config variable           | Corresponding ENV Variable    | Description                                                                                                                                                                  |
         | 
| 31 | 
            +
            | ----------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
         | 
| 32 | 
            +
            add_channel_handle        | -                             | Add channel handle to Telegram posts. Accepted values: true or false. Default is false                                                                                       |
         | 
| 33 | 
            +
            add_reddit_link           | -                             | Add reddit link to Telegram posts. Accepted values: true or false. Default is false.                                                                                         |
         | 
| 34 | 
            +
            logger                    | -                             | Which logger to use. You can pass your own ruby logger                                                                                                                       |
         | 
| 35 | 
            +
            on_error                  | -                             | What to do when an error happens. Default is :log, but you can also :raise or :ignore                                                                                        |
         | 
| 36 | 
            +
            send_errors_to_telegram   | -                             | Also log errors to telegram (besides regular logging). Accepted values: true or false, default is false                                                                      |
         | 
| 37 | 
            +
            translate                 | -                             | Translate posts via Google Translate. Leave empty for no translation. More details below                                                                                     |
         | 
| 38 | 
            +
            aws.access_key_id         | RTT_AWS_ACCESS_KEY_ID         | Your AWS access key ID. Needed for AWS DynamoDB storage                                                                                                                      |
         | 
| 39 | 
            +
            aws.region                | RTT_AWS_REGION                | AWS region your DynamoDB is hosted on                                                                                                                                        |
         | 
| 40 | 
            +
            aws.secret_access_key     | RTT_AWS_SECRET_ACCESS_KEY     | Your AWS access key ID. Needed for AWS DynamoDB storage.                                                                                                                     |
         | 
| 41 | 
            +
            google.api_key            | RTT_GOOGLE_API_KEY            | Your Google API key to translate posts via Google Translate                                                                                                                  |
         | 
| 42 | 
            +
            reddit.client_id          | RTT_REDDIT_CLIENT_ID          | Reddit app credentials to access API. Reddit allows more authenticated requests                                                                                              |
         | 
| 43 | 
            +
            reddit.client_secret      | RTT_REDDIT_CLIENT_SECRET      | Reddit app credentials to access API. Reddit allows more authenticated requests                                                                                              |
         | 
| 44 | 
            +
            store.max_stored_posts    | RTT_MAX_STORED_POSTS          | Number of posts to store in the database to avoid duplicates, default is 25                                                                                                  |
         | 
| 45 | 
            +
            store.tmp_dir             | RTT_TEMP_DIR                  | Directory to write temp files to without trailing `/`                                                                                                                        |
         | 
| 46 | 
            +
            store.type                | RTT_STORE_TYPE                | Choose between `aws_dynamo_db`, `memory` or `temp_file`. Default is `aws_dynamo_db`, so if you're not specifying your AWS credentials, you have to choose another store type |
         | 
| 47 | 
            +
            telegram.bot_token *      | RTT_TELEGRAM_BOT_TOKEN        | The token you've received when you've created a telegram bot                                                                                                                 |
         | 
| 48 | 
            +
            telegram.error_channel_id | RTT_TELEGRAM_ERROR_CHANNEL_ID | Telegram channel to send errors to (without `@`, only errors from Telegram API responses would be sent for now)                                                              |
         | 
| 49 49 |  | 
| 50 50 | 
             
            ## Usage
         | 
| 51 51 |  | 
| @@ -53,30 +53,19 @@ Check out `lib/configuration` for full configuration. | |
| 53 53 | 
             
            2. To fetch latest hot post which hasn't been pushed yet:
         | 
| 54 54 | 
             
            ```
         | 
| 55 55 | 
             
            RedditToTelegram.hot(
         | 
| 56 | 
            -
                 | 
| 57 | 
            -
                 | 
| 56 | 
            +
                telegram_channel_id_1: :subreddit_name_1,
         | 
| 57 | 
            +
                telegram_channel_id_2: :subreddit_name_2
         | 
| 58 58 | 
             
              )
         | 
| 59 59 | 
             
            ```
         | 
| 60 | 
            -
             | 
| 60 | 
            +
            You can push posts from one subreddit to one telegram channel, several-to-one, one-to-several, several-to-several, whatever you like.
         | 
| 61 | 
            +
            You can also push one specific post:
         | 
| 61 62 | 
             
            ```
         | 
| 62 | 
            -
            RedditToTelegram.from_link("regular_link_to_post" | 
| 63 | 
            +
            RedditToTelegram.from_link(telegram_channel_id: "regular_link_to_post")
         | 
| 63 64 | 
             
            ```
         | 
| 64 65 | 
             
            Use `:telegram_channel_id` without the `@`.
         | 
| 65 66 |  | 
| 66 | 
            -
            ###  | 
| 67 | 
            +
            ### Translation
         | 
| 67 68 |  | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
            RedditToTelegram. | 
| 71 | 
            -
                { subreddit_name_1: :telegram_channel_id_1 },
         | 
| 72 | 
            -
                translate: :ja
         | 
| 73 | 
            -
              )
         | 
| 74 | 
            -
            ```
         | 
| 75 | 
            -
            You can also specify if you want to add reddit link or telegram channel handle to the post text. By default they won't be added.
         | 
| 76 | 
            -
            ```
         | 
| 77 | 
            -
            RedditToTelegram.hot(
         | 
| 78 | 
            -
                { subreddit_name_1: :telegram_channel_id_1 },
         | 
| 79 | 
            -
                add_reddit_link: true,
         | 
| 80 | 
            -
                add_channel_handle: true
         | 
| 81 | 
            -
              )
         | 
| 82 | 
            -
            ```
         | 
| 69 | 
            +
            Translation option is supported.
         | 
| 70 | 
            +
            You will have to set `RedditToTelegram.config.translate` to the language key you want to translate to. You can find available languages in [Google Translate docs](https://cloud.google.com/translate/docs/languages).
         | 
| 71 | 
            +
            You will also have to set up Google Translate API key assign it to `RedditToTelegram.config.google.api_key`.
         | 
    
        data/lib/reddit-to-telegram.rb
    CHANGED
    
    
| @@ -5,7 +5,16 @@ require "logger" | |
| 5 5 | 
             
            module RedditToTelegram
         | 
| 6 6 | 
             
              module Configuration
         | 
| 7 7 | 
             
                class << self
         | 
| 8 | 
            -
                  attr_writer : | 
| 8 | 
            +
                  attr_writer :add_channel_handle, :add_reddit_link, :logger,
         | 
| 9 | 
            +
                              :on_error, :send_errors_to_telegram, :translate
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def add_channel_handle
         | 
| 12 | 
            +
                    @add_channel_handle ||= false
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def add_reddit_link
         | 
| 16 | 
            +
                    @add_reddit_link ||= false
         | 
| 17 | 
            +
                  end
         | 
| 9 18 |  | 
| 10 19 | 
             
                  def logger
         | 
| 11 20 | 
             
                    @logger ||= Logger.new($stdout).tap do |log|
         | 
| @@ -16,11 +25,19 @@ module RedditToTelegram | |
| 16 25 | 
             
                  def on_error
         | 
| 17 26 | 
             
                    @on_error ||= :log
         | 
| 18 27 | 
             
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def send_errors_to_telegram
         | 
| 30 | 
            +
                    @send_errors_to_telegram ||= false
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def translate
         | 
| 34 | 
            +
                    @translate ||= nil
         | 
| 35 | 
            +
                  end
         | 
| 19 36 | 
             
                end
         | 
| 20 37 |  | 
| 21 38 | 
             
                class Store
         | 
| 22 39 | 
             
                  DEFAULT_TMP_DIR = "#{Dir.pwd}/tmp".freeze
         | 
| 23 | 
            -
                  DEFAULT_TYPE = : | 
| 40 | 
            +
                  DEFAULT_TYPE = :aws_dynamo_db
         | 
| 24 41 |  | 
| 25 42 | 
             
                  class << self
         | 
| 26 43 | 
             
                    attr_writer :max_stored_posts, :tmp_dir, :type
         | 
| @@ -40,8 +57,7 @@ module RedditToTelegram | |
| 40 57 | 
             
                end
         | 
| 41 58 |  | 
| 42 59 | 
             
                class AWS
         | 
| 43 | 
            -
                  ATTRS = %i[access_key_id secret_access_key region | 
| 44 | 
            -
                  DEFAULT_DOMAIN_NAME = "reddit_to_telegram"
         | 
| 60 | 
            +
                  ATTRS = %i[access_key_id secret_access_key region].freeze
         | 
| 45 61 |  | 
| 46 62 | 
             
                  class << self
         | 
| 47 63 | 
             
                    attr_writer(*ATTRS)
         | 
| @@ -58,10 +74,6 @@ module RedditToTelegram | |
| 58 74 | 
             
                      @region ||= ENV["RTT_AWS_REGION"]
         | 
| 59 75 | 
             
                    end
         | 
| 60 76 |  | 
| 61 | 
            -
                    def domain_name
         | 
| 62 | 
            -
                      @domain_name ||= ENV["RTT_AWS_DOMAIN_NAME"] || DEFAULT_DOMAIN_NAME
         | 
| 63 | 
            -
                    end
         | 
| 64 | 
            -
             | 
| 65 77 | 
             
                    def set_up?
         | 
| 66 78 | 
             
                      ATTRS.all? { |a| !a.to_s.empty? }
         | 
| 67 79 | 
             
                    end
         | 
| @@ -3,19 +3,50 @@ | |
| 3 3 | 
             
            module RedditToTelegram
         | 
| 4 4 | 
             
              class RedditToTelegramError < StandardError; end
         | 
| 5 5 |  | 
| 6 | 
            +
              class BadResponseFromTelegram < RedditToTelegramError; end
         | 
| 7 | 
            +
              class FailedToCreateDatabaseTable < RedditToTelegramError; end
         | 
| 8 | 
            +
              class FailedToFetchFromReddit < RedditToTelegramError; end
         | 
| 9 | 
            +
              class FailedToPersistData < RedditToTelegramError; end
         | 
| 6 10 | 
             
              class InvalidStoreType < RedditToTelegramError; end
         | 
| 7 11 | 
             
              class MissingConfiguration < RedditToTelegramError; end
         | 
| 8 12 |  | 
| 9 13 | 
             
              class Errors
         | 
| 10 14 | 
             
                class << self
         | 
| 11 15 | 
             
                  def new(error, message = nil)
         | 
| 16 | 
            +
                    log_message = error.to_s
         | 
| 17 | 
            +
                    log_message += ": #{message}" unless message.nil?
         | 
| 18 | 
            +
             | 
| 12 19 | 
             
                    if Configuration.on_error == :raise
         | 
| 13 20 | 
             
                      raise(error.new(message))
         | 
| 14 21 | 
             
                    elsif Configuration.on_error == :log
         | 
| 15 | 
            -
                      log_message = error.to_s
         | 
| 16 | 
            -
                      log_message += ": #{message}" unless message.nil?
         | 
| 17 22 | 
             
                      Configuration.logger.error(log_message)
         | 
| 18 23 | 
             
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    return unless Configuration.send_errors_to_telegram
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    push_error_to_telegram(log_message)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    nil
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  private
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def push_error_to_telegram(message)
         | 
| 35 | 
            +
                    if Configuration.telegram.error_channel_id.to_s.empty?
         | 
| 36 | 
            +
                      Configuration.logger.warn("Telegram Error Channel ID is not set up, can't send errors there")
         | 
| 37 | 
            +
                      return
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    Telegram::Post.push(
         | 
| 41 | 
            +
                      {
         | 
| 42 | 
            +
                        type: :text,
         | 
| 43 | 
            +
                        text: message,
         | 
| 44 | 
            +
                        misc: { no_retry: true, disable_link_preview: true }
         | 
| 45 | 
            +
                      },
         | 
| 46 | 
            +
                      Configuration.telegram.error_channel_id
         | 
| 47 | 
            +
                    )
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    nil
         | 
| 19 50 | 
             
                  end
         | 
| 20 51 | 
             
                end
         | 
| 21 52 | 
             
              end
         | 
| @@ -3,29 +3,29 @@ | |
| 3 3 | 
             
            module RedditToTelegram
         | 
| 4 4 | 
             
              class Post
         | 
| 5 5 | 
             
                class << self
         | 
| 6 | 
            -
                  def hot(sources | 
| 6 | 
            +
                  def hot(sources)
         | 
| 7 7 | 
             
                    check_config
         | 
| 8 | 
            -
                    return if sources.empty?
         | 
| 9 | 
            -
             | 
| 10 8 | 
             
                    Store.setup
         | 
| 11 9 |  | 
| 12 | 
            -
                    sources.each do | | 
| 13 | 
            -
                       | 
| 14 | 
            -
             | 
| 10 | 
            +
                    sources.each do |telegram_chat_id, subreddits|
         | 
| 11 | 
            +
                      Array(subreddits).each do |subreddit|
         | 
| 12 | 
            +
                        res = Reddit::Fetch.hot(subreddit)
         | 
| 13 | 
            +
                        handle_res(res, subreddit, telegram_chat_id)
         | 
| 14 | 
            +
                      end
         | 
| 15 15 | 
             
                    end
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 |  | 
| 18 | 
            -
                  def from_link( | 
| 18 | 
            +
                  def from_link(sources)
         | 
| 19 19 | 
             
                    check_config
         | 
| 20 | 
            -
                    return  | 
| 20 | 
            +
                    return unless check_from_link_sources(sources)
         | 
| 21 21 |  | 
| 22 22 | 
             
                    Configuration.store.type = :memory
         | 
| 23 23 | 
             
                    Store.setup
         | 
| 24 24 |  | 
| 25 | 
            -
                    res = Reddit::Fetch.post( | 
| 25 | 
            +
                    res = Reddit::Fetch.post(sources.values.first)
         | 
| 26 26 | 
             
                    return unless res_ok?(res)
         | 
| 27 27 |  | 
| 28 | 
            -
                    Telegram::Post.push(res,  | 
| 28 | 
            +
                    Telegram::Post.push(res, sources.keys.first)
         | 
| 29 29 | 
             
                    res
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 |  | 
| @@ -35,19 +35,17 @@ module RedditToTelegram | |
| 35 35 | 
             
                    Errors.new(MissingConfiguration, "Missing Telegram bot token") if Configuration.telegram.bot_token.to_s.empty?
         | 
| 36 36 | 
             
                  end
         | 
| 37 37 |  | 
| 38 | 
            -
                  def handle_res(res, subreddit, telegram_chat_id | 
| 38 | 
            +
                  def handle_res(res, subreddit, telegram_chat_id)
         | 
| 39 39 | 
             
                    return unless res_ok?(res)
         | 
| 40 40 |  | 
| 41 | 
            -
                    post =  | 
| 41 | 
            +
                    post = Store.posts.next(telegram_chat_id, subreddit, res)
         | 
| 42 42 |  | 
| 43 43 | 
             
                    if post.nil?
         | 
| 44 44 | 
             
                      Configuration.logger.info("Could not find a new post to push")
         | 
| 45 45 | 
             
                      return
         | 
| 46 46 | 
             
                    end
         | 
| 47 47 |  | 
| 48 | 
            -
                     | 
| 49 | 
            -
                    Store::Posts.add(subreddit, post[:id])
         | 
| 50 | 
            -
                    res
         | 
| 48 | 
            +
                    Telegram::Post.push(post, telegram_chat_id)
         | 
| 51 49 | 
             
                  end
         | 
| 52 50 |  | 
| 53 51 | 
             
                  def res_ok?(res)
         | 
| @@ -62,8 +60,13 @@ module RedditToTelegram | |
| 62 60 | 
             
                    end
         | 
| 63 61 | 
             
                  end
         | 
| 64 62 |  | 
| 65 | 
            -
                  def  | 
| 66 | 
            -
                     | 
| 63 | 
            +
                  def check_from_link_sources(sources)
         | 
| 64 | 
            +
                    if !sources.is_a?(Hash) || sources.keys.count != 1 || sources.values.count != 1
         | 
| 65 | 
            +
                      Errors.new(ArgumentError, "Check documentation on usage")
         | 
| 66 | 
            +
                      return false
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    true
         | 
| 67 70 | 
             
                  end
         | 
| 68 71 | 
             
                end
         | 
| 69 72 | 
             
              end
         | 
| @@ -55,12 +55,22 @@ module RedditToTelegram | |
| 55 55 | 
             
                        handle_429(func_name, func_args)
         | 
| 56 56 | 
             
                      when 200
         | 
| 57 57 | 
             
                        Output.format_response(res)
         | 
| 58 | 
            +
                      else
         | 
| 59 | 
            +
                        Errors.new(FailedToFetchFromReddit, res.to_s)
         | 
| 58 60 | 
             
                      end
         | 
| 59 61 | 
             
                    end
         | 
| 60 62 |  | 
| 61 63 | 
             
                    def handle_401(func_name, func_args)
         | 
| 64 | 
            +
                      retries_left = func_args.last
         | 
| 65 | 
            +
                      func_args[func_args.length - 1] = retries_left - 1
         | 
| 66 | 
            +
             | 
| 62 67 | 
             
                      Store::Reddit.token = Auth.token
         | 
| 63 | 
            -
             | 
| 68 | 
            +
             | 
| 69 | 
            +
                      if retries_left > 0
         | 
| 70 | 
            +
                        send(func_name, *func_args)
         | 
| 71 | 
            +
                      else
         | 
| 72 | 
            +
                        Errors.new(FailedToFetchFromReddit, "Failed to authenticate")
         | 
| 73 | 
            +
                      end
         | 
| 64 74 | 
             
                    end
         | 
| 65 75 |  | 
| 66 76 | 
             
                    def handle_429(func_name, func_args)
         | 
| @@ -68,7 +78,12 @@ module RedditToTelegram | |
| 68 78 |  | 
| 69 79 | 
             
                      sleep(10 / retries_left) if retries_left > 0
         | 
| 70 80 | 
             
                      func_args[func_args.length - 1] = retries_left - 1
         | 
| 71 | 
            -
             | 
| 81 | 
            +
             | 
| 82 | 
            +
                      if retries_left > 0
         | 
| 83 | 
            +
                        send(func_name, *func_args)
         | 
| 84 | 
            +
                      else
         | 
| 85 | 
            +
                        Errors.new(FailedToFetchFromReddit, "Too many requests")
         | 
| 86 | 
            +
                      end
         | 
| 72 87 | 
             
                    end
         | 
| 73 88 | 
             
                  end
         | 
| 74 89 | 
             
                end
         | 
| @@ -96,8 +96,9 @@ module RedditToTelegram | |
| 96 96 | 
             
                    end
         | 
| 97 97 |  | 
| 98 98 | 
             
                    def base_post_format_attrs(data)
         | 
| 99 | 
            -
                      { id: data["name"],
         | 
| 100 | 
            -
                        text: CGI.unescapeHTML(data["title"]) | 
| 99 | 
            +
                      { id: data["name"].split("_")&.dig(1),
         | 
| 100 | 
            +
                        text: CGI.unescapeHTML(data["title"]),
         | 
| 101 | 
            +
                        misc: {} }
         | 
| 101 102 | 
             
                    end
         | 
| 102 103 |  | 
| 103 104 | 
             
                    def prepare_gallery_links(data)
         | 
| @@ -0,0 +1,132 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "aws-sdk-dynamodb"
         | 
| 4 | 
            +
            require "json"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module RedditToTelegram
         | 
| 7 | 
            +
              module Store
         | 
| 8 | 
            +
                class AWSDynamoDB
         | 
| 9 | 
            +
                  ITEM_NAME = "cached_data"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  class << self
         | 
| 12 | 
            +
                    def client
         | 
| 13 | 
            +
                      @client ||= Aws::DynamoDB::Client.new(
         | 
| 14 | 
            +
                        access_key_id: Configuration.aws.access_key_id,
         | 
| 15 | 
            +
                        secret_access_key: Configuration.aws.secret_access_key,
         | 
| 16 | 
            +
                        region: Configuration.aws.region
         | 
| 17 | 
            +
                      )
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    attr_reader :reddit_token
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    def setup
         | 
| 25 | 
            +
                      check_credentials
         | 
| 26 | 
            +
                      prepare_db
         | 
| 27 | 
            +
                      assign_default_values
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def check_credentials
         | 
| 31 | 
            +
                      return unless Configuration.store.type == :aws_dynamo_db
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      return if Configuration.aws.set_up?
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                      Errors.new(
         | 
| 36 | 
            +
                        MissingConfiguration,
         | 
| 37 | 
            +
                        "Missing AWS credentials. Set them up or change store type to anything other than aws_dynamo_db"
         | 
| 38 | 
            +
                      )
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    def add_post(telegram_chat_id, subreddit, id)
         | 
| 42 | 
            +
                      assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                      @posts[telegram_chat_id][subreddit] << id
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      if @posts[telegram_chat_id][subreddit].count > Store.max_stored_posts
         | 
| 47 | 
            +
                        @posts[telegram_chat_id][subreddit].shift
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                      persist_posts(telegram_chat_id)
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    def assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 54 | 
            +
                      @posts[telegram_chat_id] = {} if @posts[telegram_chat_id].nil?
         | 
| 55 | 
            +
                      @posts[telegram_chat_id][subreddit] = [] if @posts[telegram_chat_id][subreddit].nil?
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    def persist_posts(telegram_chat_id)
         | 
| 59 | 
            +
                      res = client.put_item(
         | 
| 60 | 
            +
                        {
         | 
| 61 | 
            +
                          item: {
         | 
| 62 | 
            +
                            "TelegramChannel" => telegram_chat_id.to_s,
         | 
| 63 | 
            +
                            "Posts" => @posts[telegram_chat_id].to_json
         | 
| 64 | 
            +
                          },
         | 
| 65 | 
            +
                          return_consumed_capacity: "TOTAL",
         | 
| 66 | 
            +
                          table_name: POSTS_TABLE_NAME
         | 
| 67 | 
            +
                        }
         | 
| 68 | 
            +
                      )
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                      Errors.new(FailedToPersistData, "Failed to persist data to DynamoDB") unless res.successful?
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    def dup_post?(telegram_chat_id, subreddit, id)
         | 
| 74 | 
            +
                      return false if @posts.dig(telegram_chat_id, subreddit).nil?
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                      @posts[telegram_chat_id][subreddit].include?(id)
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    def load_posts(telegram_chat_id)
         | 
| 80 | 
            +
                      res = client.get_item(
         | 
| 81 | 
            +
                        { key: { "TelegramChannel" => telegram_chat_id.to_s },
         | 
| 82 | 
            +
                          table_name: POSTS_TABLE_NAME }
         | 
| 83 | 
            +
                      )
         | 
| 84 | 
            +
                      @posts[telegram_chat_id] = JSON.parse(res.item["Posts"]).transform_keys(&:to_sym)
         | 
| 85 | 
            +
                    rescue StandardError
         | 
| 86 | 
            +
                      @posts[telegram_chat_id] = nil
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    def assign_default_values
         | 
| 90 | 
            +
                      @reddit_token = ""
         | 
| 91 | 
            +
                      @posts = {}
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    POSTS_TABLE_NAME = "Posts"
         | 
| 95 | 
            +
                    POSTS_TABLE_ATTRIBUTES = {
         | 
| 96 | 
            +
                      attribute_definitions: [
         | 
| 97 | 
            +
                        { attribute_name: "TelegramChannel",
         | 
| 98 | 
            +
                          attribute_type: "S" }
         | 
| 99 | 
            +
                      ],
         | 
| 100 | 
            +
                      key_schema: [
         | 
| 101 | 
            +
                        { attribute_name: "TelegramChannel",
         | 
| 102 | 
            +
                          key_type: "HASH" }
         | 
| 103 | 
            +
                      ],
         | 
| 104 | 
            +
                      provisioned_throughput: {
         | 
| 105 | 
            +
                        read_capacity_units: 1,
         | 
| 106 | 
            +
                        write_capacity_units: 1
         | 
| 107 | 
            +
                      },
         | 
| 108 | 
            +
                      table_name: POSTS_TABLE_NAME
         | 
| 109 | 
            +
                    }.freeze
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    def prepare_db
         | 
| 112 | 
            +
                      res = client.list_tables
         | 
| 113 | 
            +
                      return unless res.successful?
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                      return if res.table_names.include?(POSTS_TABLE_NAME)
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                      client.create_table(POSTS_TABLE_ATTRIBUTES)
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                      waited = 0
         | 
| 120 | 
            +
                      while client.describe_table(table_name: POSTS_TABLE_NAME).table.table_status != "ACTIVE"
         | 
| 121 | 
            +
                        if waited == 10
         | 
| 122 | 
            +
                          Errors.new(FailedToCreateDatabaseTable, "Failed to create #{POSTS_TABLE_NAME} table in DynamoDB")
         | 
| 123 | 
            +
                          break
         | 
| 124 | 
            +
                        end
         | 
| 125 | 
            +
                        sleep(1)
         | 
| 126 | 
            +
                        waited += 1
         | 
| 127 | 
            +
                      end
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
            end
         | 
| @@ -11,17 +11,26 @@ module RedditToTelegram | |
| 11 11 | 
             
                    @posts = {}
         | 
| 12 12 |  | 
| 13 13 | 
             
                    def setup; end
         | 
| 14 | 
            +
                    def load_posts(_); end
         | 
| 14 15 |  | 
| 15 | 
            -
                    def add_post(subreddit, id)
         | 
| 16 | 
            -
                       | 
| 17 | 
            -
             | 
| 18 | 
            -
                       | 
| 16 | 
            +
                    def add_post(telegram_chat_id, subreddit, id)
         | 
| 17 | 
            +
                      assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      posts[telegram_chat_id][subreddit] << id
         | 
| 20 | 
            +
                      return unless posts[telegram_chat_id][subreddit].count > Store.max_stored_posts
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      posts[telegram_chat_id][subreddit].shift
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 26 | 
            +
                      posts[telegram_chat_id] = {} if posts[telegram_chat_id].nil?
         | 
| 27 | 
            +
                      posts[telegram_chat_id][subreddit] = [] if posts[telegram_chat_id][subreddit].nil?
         | 
| 19 28 | 
             
                    end
         | 
| 20 29 |  | 
| 21 | 
            -
                    def dup_post?(subreddit, id)
         | 
| 22 | 
            -
                      return false if posts | 
| 30 | 
            +
                    def dup_post?(telegram_channel, subreddit, id)
         | 
| 31 | 
            +
                      return false if posts.dig(telegram_channel, subreddit).nil?
         | 
| 23 32 |  | 
| 24 | 
            -
                      posts[subreddit].include?(id)
         | 
| 33 | 
            +
                      posts[telegram_channel][subreddit].include?(id)
         | 
| 25 34 | 
             
                    end
         | 
| 26 35 |  | 
| 27 36 | 
             
                    def posts
         | 
| @@ -17,22 +17,34 @@ module RedditToTelegram | |
| 17 17 | 
             
                      read_file
         | 
| 18 18 | 
             
                    end
         | 
| 19 19 |  | 
| 20 | 
            +
                    def load_posts(_); end
         | 
| 21 | 
            +
             | 
| 20 22 | 
             
                    def reddit_token=(val)
         | 
| 21 23 | 
             
                      @reddit_token = val
         | 
| 22 24 | 
             
                      write_file
         | 
| 23 25 | 
             
                    end
         | 
| 24 26 |  | 
| 25 | 
            -
                    def add_post(subreddit, id)
         | 
| 26 | 
            -
                       | 
| 27 | 
            -
             | 
| 28 | 
            -
                      @posts[ | 
| 27 | 
            +
                    def add_post(telegram_chat_id, subreddit, id)
         | 
| 28 | 
            +
                      assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      @posts[telegram_chat_id][subreddit] << id
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      if @posts[telegram_chat_id][subreddit].count > Store.max_stored_posts
         | 
| 33 | 
            +
                        @posts[telegram_chat_id][subreddit].shift
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
             | 
| 29 36 | 
             
                      write_file
         | 
| 30 37 | 
             
                    end
         | 
| 31 38 |  | 
| 32 | 
            -
                    def  | 
| 33 | 
            -
                       | 
| 39 | 
            +
                    def assign_empty_values_to_posts(telegram_chat_id, subreddit)
         | 
| 40 | 
            +
                      @posts[telegram_chat_id] = {} if @posts[telegram_chat_id].nil?
         | 
| 41 | 
            +
                      @posts[telegram_chat_id][subreddit] = [] if @posts[telegram_chat_id][subreddit].nil?
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    def dup_post?(telegram_channel, subreddit, id)
         | 
| 45 | 
            +
                      return false if posts.dig(telegram_channel, subreddit).nil?
         | 
| 34 46 |  | 
| 35 | 
            -
                      posts[subreddit].include?(id)
         | 
| 47 | 
            +
                      posts[telegram_channel][subreddit].include?(id)
         | 
| 36 48 | 
             
                    end
         | 
| 37 49 |  | 
| 38 50 | 
             
                    def read_file
         | 
| @@ -43,14 +55,14 @@ module RedditToTelegram | |
| 43 55 | 
             
                      @reddit_token = data["reddit_token"]
         | 
| 44 56 | 
             
                      @posts = {}
         | 
| 45 57 | 
             
                      data.each do |key, value|
         | 
| 46 | 
            -
                        @posts[key.split("_").last.to_sym] = value if key.match?(/posts_.+/)
         | 
| 58 | 
            +
                        @posts[key.split("_").last.to_sym] = value.transform_keys(&:to_sym) if key.match?(/posts_.+/)
         | 
| 47 59 | 
             
                      end
         | 
| 48 60 | 
             
                    end
         | 
| 49 61 |  | 
| 50 62 | 
             
                    def write_file
         | 
| 51 63 | 
             
                      data = { reddit_token: @reddit_token }
         | 
| 52 | 
            -
                      @posts.each do | | 
| 53 | 
            -
                        data["posts_#{ | 
| 64 | 
            +
                      @posts.each do |telegram_chat_id, values|
         | 
| 65 | 
            +
                        data["posts_#{telegram_chat_id}"] = values
         | 
| 54 66 | 
             
                      end
         | 
| 55 67 | 
             
                      File.open(temp_file_path, "w") { |f| f.write(data.to_json) }
         | 
| 56 68 | 
             
                    end
         | 
| @@ -2,15 +2,12 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module RedditToTelegram
         | 
| 4 4 | 
             
              module Store
         | 
| 5 | 
            -
                MAX_STORED_POSTS = Configuration.store.max_stored_posts - 1
         | 
| 6 5 | 
             
                CLASS_MAP = {
         | 
| 7 | 
            -
                   | 
| 6 | 
            +
                  aws_dynamo_db: "RedditToTelegram::Store::AWSDynamoDB",
         | 
| 8 7 | 
             
                  memory: "RedditToTelegram::Store::Memory",
         | 
| 9 8 | 
             
                  temp_file: "RedditToTelegram::Store::TempFile"
         | 
| 10 9 | 
             
                }.freeze
         | 
| 11 10 |  | 
| 12 | 
            -
                STORE = Object.const_get("RedditToTelegram::Store::AWSSimpleDB")
         | 
| 13 | 
            -
             | 
| 14 11 | 
             
                class << self
         | 
| 15 12 | 
             
                  attr_accessor :active
         | 
| 16 13 |  | 
| @@ -20,6 +17,18 @@ module RedditToTelegram | |
| 20 17 | 
             
                    self.active = Object.const_get(CLASS_MAP[Configuration.store.type])
         | 
| 21 18 | 
             
                    active.send(:setup)
         | 
| 22 19 | 
             
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def max_stored_posts
         | 
| 22 | 
            +
                    Configuration.store.max_stored_posts - 1
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def reddit
         | 
| 26 | 
            +
                    Reddit
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def posts
         | 
| 30 | 
            +
                    Posts
         | 
| 31 | 
            +
                  end
         | 
| 23 32 | 
             
                end
         | 
| 24 33 |  | 
| 25 34 | 
             
                class Reddit
         | 
| @@ -36,12 +45,19 @@ module RedditToTelegram | |
| 36 45 |  | 
| 37 46 | 
             
                class Posts
         | 
| 38 47 | 
             
                  class << self
         | 
| 39 | 
            -
                    def add(subreddit, id)
         | 
| 40 | 
            -
                      Store.active.send(:add_post, subreddit, id)
         | 
| 48 | 
            +
                    def add(telegram_chat_id, subreddit, id)
         | 
| 49 | 
            +
                      Store.active.send(:add_post, telegram_chat_id, subreddit, id)
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    def dup?(telegram_chat_id, subreddit, id)
         | 
| 53 | 
            +
                      Store.active.send(:dup_post?, telegram_chat_id, subreddit, id)
         | 
| 41 54 | 
             
                    end
         | 
| 42 55 |  | 
| 43 | 
            -
                    def  | 
| 44 | 
            -
                      Store.active.send(: | 
| 56 | 
            +
                    def next(telegram_chat_id, subreddit, posts)
         | 
| 57 | 
            +
                      Store.active.send(:load_posts, telegram_chat_id)
         | 
| 58 | 
            +
                      new_post = posts.find { |post| !dup?(telegram_chat_id, subreddit, post[:id]) }
         | 
| 59 | 
            +
                      add(telegram_chat_id, subreddit, new_post[:id]) unless new_post.nil?
         | 
| 60 | 
            +
                      new_post
         | 
| 45 61 | 
             
                    end
         | 
| 46 62 | 
             
                  end
         | 
| 47 63 | 
             
                end
         | 
| @@ -5,30 +5,30 @@ module RedditToTelegram | |
| 5 5 | 
             
                class Post
         | 
| 6 6 | 
             
                  class Gallery
         | 
| 7 7 | 
             
                    class << self
         | 
| 8 | 
            -
                      def push_remaining_gallery_data(post, channel, res | 
| 8 | 
            +
                      def push_remaining_gallery_data(post, channel, res)
         | 
| 9 9 | 
             
                        if post[:additional_media]
         | 
| 10 | 
            -
                          push_remaining_gallery_images(post, channel | 
| 10 | 
            +
                          push_remaining_gallery_images(post, channel)
         | 
| 11 11 | 
             
                        else
         | 
| 12 | 
            -
                          push_gallery_caption(post, channel, res | 
| 12 | 
            +
                          push_gallery_caption(post, channel, res)
         | 
| 13 13 | 
             
                        end
         | 
| 14 14 | 
             
                      end
         | 
| 15 15 |  | 
| 16 16 | 
             
                      private
         | 
| 17 17 |  | 
| 18 | 
            -
                      def push_remaining_gallery_images(post, channel | 
| 18 | 
            +
                      def push_remaining_gallery_images(post, channel)
         | 
| 19 19 | 
             
                        post[:media] = post[:additional_media].first(10)
         | 
| 20 20 | 
             
                        remaining = post.delete(:additional_media).drop(10)
         | 
| 21 21 | 
             
                        post[:additional_media] = remaining unless remaining.empty?
         | 
| 22 | 
            -
                        Post.push(post, channel | 
| 22 | 
            +
                        Post.push(post, channel)
         | 
| 23 23 | 
             
                      end
         | 
| 24 24 |  | 
| 25 | 
            -
                      def push_gallery_caption(post, channel, res | 
| 25 | 
            +
                      def push_gallery_caption(post, channel, res)
         | 
| 26 26 | 
             
                        Telegram::Post.push(
         | 
| 27 27 | 
             
                          { type: :text,
         | 
| 28 28 | 
             
                            id: post[:id],
         | 
| 29 | 
            -
                            text: post[:text] | 
| 30 | 
            -
             | 
| 31 | 
            -
                           | 
| 29 | 
            +
                            text: post[:text],
         | 
| 30 | 
            +
                            misc: gallery_caption_opts(res) },
         | 
| 31 | 
            +
                          channel
         | 
| 32 32 | 
             
                        )
         | 
| 33 33 | 
             
                      end
         | 
| 34 34 |  | 
| @@ -19,20 +19,20 @@ module RedditToTelegram | |
| 19 19 | 
             
                  }.freeze
         | 
| 20 20 |  | 
| 21 21 | 
             
                  class << self
         | 
| 22 | 
            -
                    def push(post, channel | 
| 22 | 
            +
                    def push(post, channel)
         | 
| 23 23 | 
             
                      res = HTTParty.post(
         | 
| 24 24 | 
             
                        "#{BASE_URI}#{Configuration.telegram.bot_token}/send#{METHOD_MAP[post[:type]]}",
         | 
| 25 | 
            -
                        **params(post, channel | 
| 25 | 
            +
                        **params(post, channel)
         | 
| 26 26 | 
             
                      )
         | 
| 27 27 |  | 
| 28 | 
            -
                      handle_response(post, channel, res | 
| 28 | 
            +
                      handle_response(post, channel, res)
         | 
| 29 29 | 
             
                    end
         | 
| 30 30 |  | 
| 31 31 | 
             
                    private
         | 
| 32 32 |  | 
| 33 | 
            -
                    def params(post, channel | 
| 33 | 
            +
                    def params(post, channel)
         | 
| 34 34 | 
             
                      binary = post.dig(:misc)&.dig(:binary)
         | 
| 35 | 
            -
                      body = PrepareRequest.body(post, channel | 
| 35 | 
            +
                      body = PrepareRequest.body(post, channel)
         | 
| 36 36 |  | 
| 37 37 | 
             
                      pars = {
         | 
| 38 38 | 
             
                        body: binary ? body : body.to_json,
         | 
| @@ -42,29 +42,16 @@ module RedditToTelegram | |
| 42 42 | 
             
                      pars
         | 
| 43 43 | 
             
                    end
         | 
| 44 44 |  | 
| 45 | 
            -
                    def handle_response(post, channel, res | 
| 46 | 
            -
                       | 
| 47 | 
            -
                      Gallery.push_remaining_gallery_data(post, channel, res | 
| 48 | 
            -
                      Video.delete_file if post[:type] == :video && post.dig(:misc | 
| 45 | 
            +
                    def handle_response(post, channel, res)
         | 
| 46 | 
            +
                      log_error(post, channel, res) unless res["ok"]
         | 
| 47 | 
            +
                      Gallery.push_remaining_gallery_data(post, channel, res) if post[:type] == :gallery
         | 
| 48 | 
            +
                      Video.delete_file if post[:type] == :video && post.dig(:misc, :binary)
         | 
| 49 49 | 
             
                      res
         | 
| 50 50 | 
             
                    end
         | 
| 51 51 |  | 
| 52 | 
            -
                    def  | 
| 53 | 
            -
                       | 
| 54 | 
            -
             | 
| 55 | 
            -
                      push(
         | 
| 56 | 
            -
                        {
         | 
| 57 | 
            -
                          type: :text,
         | 
| 58 | 
            -
                          id: post[:id],
         | 
| 59 | 
            -
                          text: "Channel: @#{channel}\n\nResponse: #{res}"
         | 
| 60 | 
            -
                        },
         | 
| 61 | 
            -
                        Configuration.telegram.error_channel_id,
         | 
| 62 | 
            -
                        opts.merge(
         | 
| 63 | 
            -
                          add_reddit_link: true,
         | 
| 64 | 
            -
                          disable_link_preview: true,
         | 
| 65 | 
            -
                          no_retry: true
         | 
| 66 | 
            -
                        )
         | 
| 67 | 
            -
                      )
         | 
| 52 | 
            +
                    def log_error(post, channel, res)
         | 
| 53 | 
            +
                      message = "\n\nChannel: #{channel}\n\nPost data: #{post}\n\nResponse: #{res}"
         | 
| 54 | 
            +
                      Errors.new(BadResponseFromTelegram, message)
         | 
| 68 55 | 
             
                    end
         | 
| 69 56 | 
             
                  end
         | 
| 70 57 | 
             
                end
         | 
| @@ -4,54 +4,64 @@ module RedditToTelegram | |
| 4 4 | 
             
              module Telegram
         | 
| 5 5 | 
             
                class PrepareRequest
         | 
| 6 6 | 
             
                  class << self
         | 
| 7 | 
            -
                    def body(post, chat_id | 
| 8 | 
            -
                      body = prepare_body(post, chat_id | 
| 9 | 
            -
                      body[:link_preview_options] = { is_disabled: true } if  | 
| 10 | 
            -
                      body[:reply_parameters] = { message_id:  | 
| 7 | 
            +
                    def body(post, chat_id)
         | 
| 8 | 
            +
                      body = prepare_body(post, chat_id)
         | 
| 9 | 
            +
                      body[:link_preview_options] = { is_disabled: true } if post.dig(:misc, :disable_link_preview)
         | 
| 10 | 
            +
                      body[:reply_parameters] = { message_id: post[:misc][:reply_to] } if post.dig(:misc, :reply_to)
         | 
| 11 11 | 
             
                      body
         | 
| 12 12 | 
             
                    end
         | 
| 13 13 |  | 
| 14 14 | 
             
                    private
         | 
| 15 15 |  | 
| 16 | 
            -
                    def prepare_body(post, chat_id | 
| 16 | 
            +
                    def prepare_body(post, chat_id)
         | 
| 17 17 | 
             
                      case post[:type]
         | 
| 18 18 | 
             
                      when :image
         | 
| 19 | 
            -
                        { chat_id: "@#{chat_id}", photo: post[:media], caption: prepare_text(post, chat_id | 
| 19 | 
            +
                        { chat_id: "@#{chat_id}", photo: post[:media], caption: prepare_text(post, chat_id) }
         | 
| 20 20 | 
             
                      when :gallery
         | 
| 21 | 
            -
                        { chat_id: "@#{chat_id}", media: prepare_gallery_media(post), caption: prepare_text(post, chat_id | 
| 21 | 
            +
                        { chat_id: "@#{chat_id}", media: prepare_gallery_media(post), caption: prepare_text(post, chat_id) }
         | 
| 22 22 | 
             
                      when :gif
         | 
| 23 | 
            -
                        { chat_id: "@#{chat_id}", animation: post[:media], caption: prepare_text(post, chat_id | 
| 23 | 
            +
                        { chat_id: "@#{chat_id}", animation: post[:media], caption: prepare_text(post, chat_id) }
         | 
| 24 24 | 
             
                      when :text
         | 
| 25 | 
            -
                        { chat_id: "@#{chat_id}", text: prepare_text(post, chat_id | 
| 25 | 
            +
                        { chat_id: "@#{chat_id}", text: prepare_text(post, chat_id) }
         | 
| 26 26 | 
             
                      when :video
         | 
| 27 27 | 
             
                        {
         | 
| 28 28 | 
             
                          chat_id: "@#{chat_id}",
         | 
| 29 29 | 
             
                          video: prepare_video(post),
         | 
| 30 30 | 
             
                          height: post[:misc][:video_height],
         | 
| 31 31 | 
             
                          width: post[:misc][:video_width],
         | 
| 32 | 
            -
                          caption: prepare_text(post, chat_id | 
| 32 | 
            +
                          caption: prepare_text(post, chat_id)
         | 
| 33 33 | 
             
                        }
         | 
| 34 34 | 
             
                      end
         | 
| 35 35 | 
             
                    end
         | 
| 36 36 |  | 
| 37 | 
            -
                    def prepare_text(post, chat_id | 
| 37 | 
            +
                    def prepare_text(post, chat_id)
         | 
| 38 38 | 
             
                      text = post[:text]
         | 
| 39 39 |  | 
| 40 | 
            -
                      text =  | 
| 40 | 
            +
                      text = translate(text)
         | 
| 41 | 
            +
                      text = add_reddit_link(text, post)
         | 
| 42 | 
            +
                      add_channel_handle(text, chat_id)
         | 
| 43 | 
            +
                    end
         | 
| 41 44 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                        text += "\n\nhttps://redd.it/#{id}"
         | 
| 45 | 
            -
                      end
         | 
| 45 | 
            +
                    def translate(text)
         | 
| 46 | 
            +
                      return text unless Configuration.translate
         | 
| 46 47 |  | 
| 47 | 
            -
                       | 
| 48 | 
            -
             | 
| 49 | 
            -
                        text += "@#{chat_id}"
         | 
| 50 | 
            -
                      end
         | 
| 48 | 
            +
                      Services::Translate.text(text, Configuration.translate)
         | 
| 49 | 
            +
                    end
         | 
| 51 50 |  | 
| 51 | 
            +
                    def add_reddit_link(text, post)
         | 
| 52 | 
            +
                      return text unless Configuration.add_reddit_link
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                      text += "\n\nhttps://redd.it/#{post[:id]}"
         | 
| 52 55 | 
             
                      text
         | 
| 53 56 | 
             
                    end
         | 
| 54 57 |  | 
| 58 | 
            +
                    def add_channel_handle(text, chat_id)
         | 
| 59 | 
            +
                      return text unless Configuration.add_channel_handle
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                      text += Configuration.add_reddit_link ? "\n" : "\n\n"
         | 
| 62 | 
            +
                      text + "@#{chat_id}"
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 55 65 | 
             
                    def prepare_gallery_media(post)
         | 
| 56 66 | 
             
                      Array(post[:media]).map { |link| { type: "photo", media: link } }
         | 
| 57 67 | 
             
                    end
         | 
    
        data/reddit-to-telegram.gemspec
    CHANGED
    
    | @@ -14,7 +14,7 @@ Gem::Specification.new do |s| | |
| 14 14 | 
             
              s.homepage    = "https://github.com/dersnek/reddit-to-telegram"
         | 
| 15 15 | 
             
              s.license     = "MIT"
         | 
| 16 16 |  | 
| 17 | 
            -
              s.add_dependency "aws-sdk- | 
| 17 | 
            +
              s.add_dependency "aws-sdk-dynamodb", "~> 1.106"
         | 
| 18 18 | 
             
              s.add_dependency "httparty"
         | 
| 19 19 |  | 
| 20 20 | 
             
              s.add_development_dependency "rubocop"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,29 +1,29 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: reddit-to-telegram
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Mark Tityuk
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-04- | 
| 11 | 
            +
            date: 2024-04-22 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            -
              name: aws-sdk- | 
| 14 | 
            +
              name: aws-sdk-dynamodb
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - - " | 
| 17 | 
            +
                - - "~>"
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: ' | 
| 19 | 
            +
                    version: '1.106'
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - - " | 
| 24 | 
            +
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: ' | 
| 26 | 
            +
                    version: '1.106'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: httparty
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -75,7 +75,7 @@ files: | |
| 75 75 | 
             
            - lib/reddit_to_telegram/reddit/output/imgur.rb
         | 
| 76 76 | 
             
            - lib/reddit_to_telegram/services/translate.rb
         | 
| 77 77 | 
             
            - lib/reddit_to_telegram/store.rb
         | 
| 78 | 
            -
            - lib/reddit_to_telegram/store/ | 
| 78 | 
            +
            - lib/reddit_to_telegram/store/aws_dynamo_db.rb
         | 
| 79 79 | 
             
            - lib/reddit_to_telegram/store/memory.rb
         | 
| 80 80 | 
             
            - lib/reddit_to_telegram/store/temp_file.rb
         | 
| 81 81 | 
             
            - lib/reddit_to_telegram/telegram/post.rb
         | 
| @@ -1,123 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "aws-sdk-simpledb"
         | 
| 4 | 
            -
            require "json"
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            module RedditToTelegram
         | 
| 7 | 
            -
              module Store
         | 
| 8 | 
            -
                class AWSSimpleDB
         | 
| 9 | 
            -
                  ITEM_NAME = "cached_data"
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  class << self
         | 
| 12 | 
            -
                    def client
         | 
| 13 | 
            -
                      @client ||= Aws::SimpleDB::Client.new(
         | 
| 14 | 
            -
                        access_key_id: Configuration.aws.access_key_id,
         | 
| 15 | 
            -
                        secret_access_key: Configuration.aws.secret_access_key,
         | 
| 16 | 
            -
                        region: Configuration.aws.region
         | 
| 17 | 
            -
                      )
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                    private
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                    attr_reader :reddit_token
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                    def setup
         | 
| 25 | 
            -
                      check_credentials
         | 
| 26 | 
            -
                      create_domain unless client.list_domains.domain_names.include?(Configuration.aws.domain_name)
         | 
| 27 | 
            -
                      read_db
         | 
| 28 | 
            -
                    end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                    def check_credentials
         | 
| 31 | 
            -
                      return unless Configuration.store.type == :aws_simple_db
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                      return if Configuration.aws.set_up?
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                      Errors.new(
         | 
| 36 | 
            -
                        MissingConfiguration,
         | 
| 37 | 
            -
                        "Missing AWS credentials. Set them up or change store type to anything other than aws_simple_db"
         | 
| 38 | 
            -
                      )
         | 
| 39 | 
            -
                    end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                    def reddit_token=(val)
         | 
| 42 | 
            -
                      @reddit_token = val
         | 
| 43 | 
            -
                      write_db
         | 
| 44 | 
            -
                    end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                    def add_post(subreddit, id)
         | 
| 47 | 
            -
                      @posts[subreddit] = [] if @posts[subreddit].nil?
         | 
| 48 | 
            -
                      @posts[subreddit] << id
         | 
| 49 | 
            -
                      @posts[subreddit].shift if @posts[subreddit].count > Store::MAX_STORED_POSTS
         | 
| 50 | 
            -
                      write_db
         | 
| 51 | 
            -
                    end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                    def dup_post?(subreddit, id)
         | 
| 54 | 
            -
                      return false if @posts[subreddit].nil?
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                      @posts[subreddit].include?(id)
         | 
| 57 | 
            -
                    end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    def read_db
         | 
| 60 | 
            -
                      res = client.get_attributes(
         | 
| 61 | 
            -
                        {
         | 
| 62 | 
            -
                          domain_name: Configuration.aws.domain_name,
         | 
| 63 | 
            -
                          item_name: "cached_data",
         | 
| 64 | 
            -
                          consistent_read: true
         | 
| 65 | 
            -
                        }
         | 
| 66 | 
            -
                      )
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                      return assign_default_values if res.attributes.empty?
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                      assign_values_from_db(res)
         | 
| 71 | 
            -
                    end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    def assign_values_from_db(data)
         | 
| 74 | 
            -
                      @reddit_token = data.attributes.find { |a| a.name == "reddit_token" }.value || ""
         | 
| 75 | 
            -
                      @posts = {}
         | 
| 76 | 
            -
                      data.attributes.each do |attr|
         | 
| 77 | 
            -
                        @posts[attr.name.split("_").last.to_sym] = JSON.parse(attr.value) if attr.name.match?(/posts_.+/)
         | 
| 78 | 
            -
                      end
         | 
| 79 | 
            -
                    end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                    def write_db
         | 
| 82 | 
            -
                      client.put_attributes(
         | 
| 83 | 
            -
                        {
         | 
| 84 | 
            -
                          domain_name: Configuration.aws.domain_name,
         | 
| 85 | 
            -
                          item_name: ITEM_NAME,
         | 
| 86 | 
            -
                          attributes: prepare_db_attrs
         | 
| 87 | 
            -
                        }
         | 
| 88 | 
            -
                      )
         | 
| 89 | 
            -
                    end
         | 
| 90 | 
            -
             | 
| 91 | 
            -
                    def prepare_db_attrs
         | 
| 92 | 
            -
                      attrs = [
         | 
| 93 | 
            -
                        {
         | 
| 94 | 
            -
                          name: "reddit_token",
         | 
| 95 | 
            -
                          value: @reddit_token,
         | 
| 96 | 
            -
                          replace: true
         | 
| 97 | 
            -
                        }
         | 
| 98 | 
            -
                      ]
         | 
| 99 | 
            -
             | 
| 100 | 
            -
                      @posts.each do |subreddit, values|
         | 
| 101 | 
            -
                        attrs << { name: "posts_#{subreddit}", value: values.to_json, replace: true }
         | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                      attrs
         | 
| 105 | 
            -
                    end
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                    def assign_default_values
         | 
| 108 | 
            -
                      @reddit_token = ""
         | 
| 109 | 
            -
                      @posts = {}
         | 
| 110 | 
            -
                    end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                    def create_domain
         | 
| 113 | 
            -
                      res = client.list_domains
         | 
| 114 | 
            -
                      return unless res.successful?
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                      return if res.domain_names.include?(Configuration.aws.domain_name)
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                      client.create_domain({ domain_name: Configuration.aws.domain_name })
         | 
| 119 | 
            -
                    end
         | 
| 120 | 
            -
                  end
         | 
| 121 | 
            -
                end
         | 
| 122 | 
            -
              end
         | 
| 123 | 
            -
            end
         |