Class: RedditBot::Bot
- Inherits:
-
Object
- Object
- RedditBot::Bot
- Defined in:
- lib/reddit_bot.rb
Constant Summary collapse
- @@skip_erroneous_descending_ids =
lambda do |array| array.reverse.each_with_object([]) do |item, result| unless result.empty? a, b = [item["id"], result.first["id"]] next if a == b || a.size < b.size || !(a.size > b.size) && a < b end result.unshift item end end
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
bot’s Reddit username; set via constructor parameter secrets.
Instance Method Summary collapse
-
#each_comment_of_the_post_thread(article) ⇒ Object
- article
-
String
ID36 of a post or self.post.
-
#each_new_post_with_top_level_comments ⇒ Object
:yields: JSON objects: [“data”] part of post or self.post, top level comment ([“children”] element).
-
#initialize(secrets, **kwargs) ⇒ Bot
constructor
- secrets
-
Hash
with keys :client_id, :client_secret, :password: and :login [kwargs] keyword params may include :subreddit for clever methods.
-
#json(mtd, path, _form = []) ⇒ Object
- mtd
-
Symbol
:get or :post [path]String
an API method [_form]Array
orHash
API method params.
-
#leave_a_comment(thing_id, text) ⇒ Object
- thing_id
-
String
fullname of a post (or self.post?), comment (and private message?) [text] :nodoc:.
-
#new_posts(subreddit = nil, caching = false) ⇒ Object
:yields: JSON objects: [“data”] part of post or self.post.
-
#report(reason, thing_id) ⇒ Object
- reason
-
:nodoc: [thing_id]
String
fullname of a “link, commenr or message”.
-
#set_post_flair(post, link_flair_css_class, link_flair_text) ⇒ Object
- post
-
JSON object of a post of self.post [link_flair_css_class] :nodoc: [link_flair_text] :nodoc:.
Constructor Details
#initialize(secrets, **kwargs) ⇒ Bot
- secrets
-
Hash
with keys :client_id, :client_secret, :password: and :login - kwargs
-
keyword params may include :subreddit for clever methods
26 27 28 29 30 31 |
# File 'lib/reddit_bot.rb', line 26 def initialize secrets, **kwargs @name, @secret_password, @user_agent, *@secret_auth = secrets.values_at *%i{ login password user_agent client_id client_secret } # @ignore_captcha = true # @ignore_captcha = kwargs[:ignore_captcha] if kwargs.has_key?(:ignore_captcha) @subreddit = kwargs[:subreddit] end |
Instance Attribute Details
#name ⇒ Object (readonly)
bot’s Reddit username; set via constructor parameter secrets
22 23 24 |
# File 'lib/reddit_bot.rb', line 22 def name @name end |
Instance Method Details
#each_comment_of_the_post_thread(article) ⇒ Object
- article
-
String
ID36 of a post or self.post
182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/reddit_bot.rb', line 182 def each_comment_of_the_post_thread article Enumerator.new do |e| f = lambda do |smth| smth["data"]["children"].each do |child| f[child["data"]["replies"]] if child["data"]["replies"].is_a? Hash fail "unknown type child['kind']: #{child["kind"]}" unless child["kind"] == "t1" e << [child["data"]["name"], child["data"]] end end f[ json(:get, "/comments/#{article}", depth: 100500, limit: 100500).tap do |t| fail "smth weird about /comments/<id> response" unless t.size == 2 end[1] ] end end |
#each_new_post_with_top_level_comments ⇒ Object
:yields: JSON objects: [“data”] part of post or self.post, top level comment ([“children”] element)
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/reddit_bot.rb', line 168 def each_new_post_with_top_level_comments # TODO add keys assertion like in method above? json(:get, "/r/#{@subreddit}/new")["data"]["children"].each do |post| fail "unknown type post['kind']: #{post["kind"]}" unless post["kind"] == "t3" t = json :get, "/comments/#{post["data"]["id"]}", depth: 1, limit: 100500#, sort: "top" fail "smth weird about /comments/<id> response" unless t.size == 2 yield post["data"], t[1]["data"]["children"].map{ |child| fail "unknown type child['kind']: #{child["kind"]}" unless child["kind"] == "t1" child["data"] }.to_enum end end |
#json(mtd, path, _form = []) ⇒ Object
- mtd
-
Symbol
:get or :post - path
-
String
an API method - _form
-
Array
orHash
API method params
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/reddit_bot.rb', line 36 def json mtd, path, _form = [] form = Hash[_form] response = JSON.load resp_with_token mtd, path, form.merge({api_type: "json"}) if response.is_a?(Hash) && response["json"] && # for example, flairlist.json and {"error": 403} do not have it !response["json"]["errors"].empty? Module.nesting[1].logger.error "ERROR OCCURED on #{[mtd, path]}" fail "unknown how to handle multiple errors" if 1 < response["json"]["errors"].size Module.nesting[1].logger.error "error: #{response["json"]["errors"]}" error, description = response["json"]["errors"].first case error when "ALREADY_SUB" ; Module.nesting[1].logger.warn "was rejected by moderator if you didn't see in dups" # when "BAD_CAPTCHA" ; update_captcha # json mtd, path, form.merger( { # iden: @iden_and_captcha[0], # captcha: @iden_and_captcha[1], # } ) unless @ignore_captcha when "RATELIMIT" fail error unless description[/\Ayou are doing that too much\. try again in (\d) minutes\.\z/] Module.nesting[1].logger.info "retrying in #{$1.to_i + 1} minutes" sleep ($1.to_i + 1) * 60 return json mtd, path, _form else ; fail error end end response end |
#leave_a_comment(thing_id, text) ⇒ Object
- thing_id
-
String
fullname of a post (or self.post?), comment (and private message?) - text
-
:nodoc:
104 105 106 107 108 109 110 111 112 |
# File 'lib/reddit_bot.rb', line 104 def leave_a_comment thing_id, text Module.nesting[1].logger.warn "leaving a comment on '#{thing_id}'" json(:post, "/api/comment", thing_id: thing_id, text: text, ).tap do |result| fail result["json"]["errors"].to_s unless result["json"]["errors"].empty? end end |
#new_posts(subreddit = nil, caching = false) ⇒ Object
:yields: JSON objects: [“data”] part of post or self.post
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/reddit_bot.rb', line 134 def new_posts subreddit = nil, caching = false cache = lambda do |id, &block| next block.call unless caching require "fileutils" FileUtils.mkdir_p "cache" filename = "cache/#{Digest::MD5.hexdigest id.inspect}" next YAML.load File.read filename if File.exist? filename block.call.tap do |data| File.write filename, YAML.dump(data) end end Enumerator.new do |e| after = {} loop do # TODO maybe force lib user to prepend "r/" to @subreddit constructor? args = [:get, "/#{subreddit || (@subreddit ? "r/#{@subreddit}" : fail)}/new", {limit: 100}.merge(after)] result = cache.call(args){ json *args } fail if result.keys != %w{ kind data } fail if result["kind"] != "Listing" fail result["data"].keys.inspect unless result["data"].keys == %w{ after dist modhash whitelist_status children before } || result["data"].keys == %w{ modhash dist children after before } @@skip_erroneous_descending_ids[ result["data"]["children"].map do |post| fail "unknown type post['kind']: #{post["kind"]}" unless post["kind"] == "t3" post["data"] end ].each do |data| e << data end break unless marker = result["data"]["after"] after = {after: marker} end end end |
#report(reason, thing_id) ⇒ Object
- reason
-
:nodoc:
- thing_id
-
String
fullname of a “link, commenr or message”
77 78 79 80 81 82 83 |
# File 'lib/reddit_bot.rb', line 77 def report reason, thing_id Module.nesting[1].logger.warn "reporting '#{thing_id}'" json :post, "/api/report", reason: "other", other_reason: reason, thing_id: thing_id end |
#set_post_flair(post, link_flair_css_class, link_flair_text) ⇒ Object
- post
-
JSON object of a post of self.post
- link_flair_css_class
-
:nodoc:
- link_flair_text
-
:nodoc:
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/reddit_bot.rb', line 88 def set_post_flair post, link_flair_css_class, link_flair_text Module.nesting[1].logger.warn "setting flair '#{link_flair_css_class}' with text '#{link_flair_text}' to post '#{post["name"]}'" if {"error"=>403} == @flairselector_choices ||= json(:post, "/r/#{@subreddit}/api/flairselector", link: post["name"]) Module.nesting[1].logger.error "possibly not enough permissions for /r/#{@subreddit}/api/flairselector" return end json :post, "/api/selectflair", link: post["name"], text: link_flair_text, flair_template_id: @flairselector_choices["choices"].find{ |i| i["flair_css_class"] == link_flair_css_class }.tap{ |flair| fail "can't find '#{link_flair_css_class}' flair class at https://www.reddit.com/r/#{@subreddit}/about/flair/#link_templates" unless flair }["flair_template_id"] end |