reddit_bot 1.6.6 → 1.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/examples/boilerplate.rb +0 -2
- data/examples/devflairbot/Gemfile +4 -2
- data/examples/devflairbot/Gemfile.lock +61 -10
- data/examples/devflairbot/main.rb +34 -8
- data/examples/get_dimensions.rb +3 -1
- data/examples/johnnymarr/Gemfile +3 -0
- data/examples/johnnymarr/Gemfile.lock +22 -0
- data/examples/johnnymarr/main.rb +54 -0
- data/examples/johnnymarr/twitter.rb +80 -0
- data/examples/largeimages/Gemfile.lock +3 -3
- data/examples/largeimages/main.rb +13 -9
- data/examples/net_http_utils.rb +2 -0
- data/examples/realtimeww2/Gemfile +1 -2
- data/examples/realtimeww2/Gemfile.lock +7 -8
- data/lib/reddit_bot.rb +24 -14
- data/lib/reddit_bot/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 125c3fc98ca91c87bbfbf759229f01a04ab866f8
|
4
|
+
data.tar.gz: 49bef2ef0766f1926013bb735e772d9dcac4042f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0b083b817628c284c18ff17f5f13e7e5e8de2a35b335024412b34c866774643f5e12409650affb9ffc9db9773e943cb3412767409339783caf73a3068797bef
|
7
|
+
data.tar.gz: 1855665d51f7c148035bb64ccd3e928966c3c6aa0efea8a09e6e6078793acfc4e8ba40fb389e6bcd490c4579446fa8ee25c5813fc389807af1ae1e45ad20d356
|
data/README.md
CHANGED
@@ -27,6 +27,7 @@ The [examples folder](examples) includes:
|
|
27
27
|
* **oneplus** -- bot that removes and modmails about links to 1080x1920 images
|
28
28
|
* **yayornay** -- bot that flairs posts according to voting in top level comments
|
29
29
|
* **realtimeww2** -- bot that posts tweets to a subreddit from a Twitter user timeline
|
30
|
+
* **johnnymarr** -- another Twitter timeline streaming bot working in the similar way
|
30
31
|
* **largeimages** -- this was my first bot -- it uses two approaches to track the most high resolution photos posted anywhere on Reddit to x-post them to [subreddit /r/largeimages](https://www.reddit.com/r/largeimages)
|
31
32
|
* **largeimagesreview** -- script that was used /r/largeimages to calculates quality of x-posts from different subreddits based on mods activity (remove/approve) so it showed that /r/pics and /r/foodporn should better be excluded:
|
32
33
|
|
data/examples/boilerplate.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "reddit_bot", "~>1.
|
4
|
-
|
3
|
+
gem "reddit_bot", "~>1.6.6"
|
4
|
+
|
5
|
+
gem "public_suffix", "<3.0" # Ruby 2.0
|
6
|
+
gem "google-cloud-error_reporting", "~>0.27.0" # Ruby 2.0
|
@@ -1,23 +1,74 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git@github.com:Nakilon/nethttputils.git
|
3
|
-
revision: 6cb2b6a2422d82e266e08b16da4fa29e809fd260
|
4
|
-
tag: v0.1.0.4
|
5
|
-
specs:
|
6
|
-
nethttputils (0.1.0.4)
|
7
|
-
|
8
1
|
GEM
|
9
2
|
remote: https://rubygems.org/
|
10
3
|
specs:
|
4
|
+
addressable (2.5.2)
|
5
|
+
public_suffix (>= 2.0.2, < 4.0)
|
6
|
+
faraday (0.15.2)
|
7
|
+
multipart-post (>= 1.2, < 3)
|
8
|
+
google-cloud-core (1.2.1)
|
9
|
+
google-cloud-env (~> 1.0)
|
10
|
+
google-cloud-env (1.0.2)
|
11
|
+
faraday (~> 0.11)
|
12
|
+
google-cloud-error_reporting (0.27.0)
|
13
|
+
google-cloud-core (~> 1.0)
|
14
|
+
google-gax (~> 0.8.0)
|
15
|
+
stackdriver-core (~> 1.2)
|
16
|
+
google-gax (0.8.12)
|
17
|
+
google-protobuf (~> 3.2)
|
18
|
+
googleapis-common-protos (~> 1.3.5)
|
19
|
+
googleauth (~> 0.5.1)
|
20
|
+
grpc (~> 1.6.6)
|
21
|
+
rly (~> 0.2.3)
|
22
|
+
google-protobuf (3.6.0)
|
23
|
+
googleapis-common-protos (1.3.7)
|
24
|
+
google-protobuf (~> 3.0)
|
25
|
+
googleapis-common-protos-types (~> 1.0)
|
26
|
+
grpc (~> 1.0)
|
27
|
+
googleapis-common-protos-types (1.0.1)
|
28
|
+
google-protobuf (~> 3.0)
|
29
|
+
googleauth (0.5.3)
|
30
|
+
faraday (~> 0.12)
|
31
|
+
jwt (~> 1.4)
|
32
|
+
logging (~> 2.0)
|
33
|
+
memoist (~> 0.12)
|
34
|
+
multi_json (~> 1.11)
|
35
|
+
os (~> 0.9)
|
36
|
+
signet (~> 0.7)
|
37
|
+
grpc (1.6.7)
|
38
|
+
google-protobuf (~> 3.1)
|
39
|
+
googleapis-common-protos-types (~> 1.0.0)
|
40
|
+
googleauth (~> 0.5.1)
|
11
41
|
json (2.1.0)
|
12
|
-
|
42
|
+
jwt (1.5.6)
|
43
|
+
little-plugger (1.1.4)
|
44
|
+
logging (2.2.2)
|
45
|
+
little-plugger (~> 1.1)
|
46
|
+
multi_json (~> 1.10)
|
47
|
+
memoist (0.16.0)
|
48
|
+
multi_json (1.13.1)
|
49
|
+
multipart-post (2.0.0)
|
50
|
+
nethttputils (0.2.4.1)
|
51
|
+
os (0.9.6)
|
52
|
+
public_suffix (2.0.5)
|
53
|
+
reddit_bot (1.6.6)
|
13
54
|
json
|
55
|
+
nethttputils (~> 0.2.4.1)
|
56
|
+
rly (0.2.3)
|
57
|
+
signet (0.8.1)
|
58
|
+
addressable (~> 2.3)
|
59
|
+
faraday (~> 0.9)
|
60
|
+
jwt (>= 1.5, < 3.0)
|
61
|
+
multi_json (~> 1.10)
|
62
|
+
stackdriver-core (1.3.0)
|
63
|
+
google-cloud-core (~> 1.2)
|
14
64
|
|
15
65
|
PLATFORMS
|
16
66
|
ruby
|
17
67
|
|
18
68
|
DEPENDENCIES
|
19
|
-
|
20
|
-
|
69
|
+
google-cloud-error_reporting (~> 0.27.0)
|
70
|
+
public_suffix (< 3.0)
|
71
|
+
reddit_bot (~> 1.6.6)
|
21
72
|
|
22
73
|
BUNDLED WITH
|
23
74
|
1.16.1
|
@@ -1,14 +1,34 @@
|
|
1
|
-
|
1
|
+
# The bot changes the post flair class with one with "dev" prefix
|
2
|
+
# if there is response from someone with "developer" user flair in comments.
|
3
|
+
# Seems like in current implementation it reads 10 last comments per subreddit
|
4
|
+
# so it's possible to miss if bot is down for a while but in fact it's enough stable and does not go down.
|
2
5
|
|
6
|
+
require_relative "../boilerplate"
|
3
7
|
BOT = RedditBot::Bot.new YAML.load File.read "secrets.yaml"
|
4
8
|
|
9
|
+
fail("no ENV['ERROR_REPORTING_KEYFILE'] specified") unless ENV["ERROR_REPORTING_KEYFILE"]
|
10
|
+
require "google/cloud/error_reporting"
|
11
|
+
Google::Cloud::ErrorReporting.configure do |config|
|
12
|
+
config.project_id = (JSON.load File.read ENV["ERROR_REPORTING_KEYFILE"])["project_id"]
|
13
|
+
end
|
14
|
+
|
15
|
+
reported = []
|
5
16
|
loop do
|
6
17
|
puts "LOOP #{Time.now}"
|
7
18
|
|
19
|
+
moderated = BOT.json(:get, "/subreddits/mine/moderator")["data"]["children"].map do |child|
|
20
|
+
fail unless child["kind"] == "t5"
|
21
|
+
child["data"]["display_name"].downcase
|
22
|
+
end
|
8
23
|
[
|
9
|
-
["ion", "Developer"],
|
24
|
+
# ["ion", "Developer"],
|
10
25
|
# ["survivetheculling", "Developer"],
|
26
|
+
["vigorgame", "Developer"],
|
27
|
+
["insurgency", "Developer"],
|
28
|
+
["Battalion1944", "Developer"],
|
11
29
|
].each do |subreddit, developer_class|
|
30
|
+
subreddit.downcase!
|
31
|
+
next puts "!!! can't moderate #{subreddit} !!!" unless moderated.include? subreddit
|
12
32
|
puts "sub: #{subreddit}"
|
13
33
|
|
14
34
|
JSON.parse( begin
|
@@ -20,13 +40,13 @@ loop do
|
|
20
40
|
end )["data"]["children"].each do |comment|
|
21
41
|
id = comment["data"]["link_id"][3..-1]
|
22
42
|
commenter_flair = comment["data"]["author_flair_css_class"]
|
23
|
-
|
43
|
+
puts "flair: #{commenter_flair}" if commenter_flair
|
24
44
|
next unless developer_class == commenter_flair
|
25
45
|
puts "https://reddit.com/r/#{subreddit}/comments/#{id}/#{comment["data"]["id"]} '#{commenter_flair}'"
|
26
46
|
flairselector = BOT.json :post, "/api/flairselector", { link: comment["data"]["link_id"] }
|
27
|
-
|
28
|
-
puts "https://reddit.com/#{id}
|
29
|
-
next unless target = case
|
47
|
+
current_flair_class = flairselector["current"]["flair_css_class"]
|
48
|
+
puts "existing https://reddit.com/#{id} #{current_flair_class.inspect}"
|
49
|
+
next unless target = case current_flair_class
|
30
50
|
when nil then "untaggeddev"
|
31
51
|
when "news" then "newsdev"
|
32
52
|
when "discussion" then "discussiondev"
|
@@ -36,10 +56,16 @@ loop do
|
|
36
56
|
when "bug" then "bugdev"
|
37
57
|
when "announcement" then "announcementdev"
|
38
58
|
when "suggestion" then "suggestiondev"
|
39
|
-
else puts "ignored https://reddit.com/#{id}
|
59
|
+
else puts "ignored https://reddit.com/#{id} #{current_flair_class.inspect}"
|
60
|
+
end
|
61
|
+
unless choice = flairselector["choices"].find{ |choice| choice["flair_css_class"] == target }
|
62
|
+
next if reported.include? comment["data"]["link_id"]
|
63
|
+
Google::Cloud::ErrorReporting.report RuntimeError.new("no '#{target}' link flair in /r/#{subreddit}").tap{ |_| _.set_backtrace caller }
|
64
|
+
reported.push comment["data"]["link_id"]
|
65
|
+
next
|
40
66
|
end
|
41
|
-
choice = flairselector["choices"].find{ |choice| choice["flair_css_class"] == target }
|
42
67
|
puts "assigning '#{target}' (#{choice}) flair to post https://reddit.com/#{id}"
|
68
|
+
next if ENV["TEST"]
|
43
69
|
_ = BOT.json :post,
|
44
70
|
"/api/selectflair", {
|
45
71
|
flair_template_id: choice["flair_template_id"],
|
data/examples/get_dimensions.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git@github.com:nakilon/reddit_bot.git
|
3
|
+
revision: 0a0649b20ff0b1a28366a17ec7c037e481e850b3
|
4
|
+
specs:
|
5
|
+
reddit_bot (1.6.7)
|
6
|
+
json
|
7
|
+
nethttputils (~> 0.2.4.1)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
json (2.1.0)
|
13
|
+
nethttputils (0.2.4.2)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
reddit_bot!
|
20
|
+
|
21
|
+
BUNDLED WITH
|
22
|
+
1.16.1
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative "../boilerplate"
|
2
|
+
SUBREDDIT = "JohnnyMarr"
|
3
|
+
BOT = RedditBot::Bot.new YAML.load(File.read "secrets.yaml"), subreddit: SUBREDDIT
|
4
|
+
|
5
|
+
TWITTER = "Johnny_Marr"
|
6
|
+
require_relative "twitter"
|
7
|
+
|
8
|
+
loop do
|
9
|
+
id = BOT.new_posts.find do |post|
|
10
|
+
/\(https:\/\/twitter\.com\/#{TWITTER}\/status\/(\d{18,})\)/i =~ post["selftext"] and break $1
|
11
|
+
end.to_i
|
12
|
+
n = if id.zero?
|
13
|
+
fail "no tweets found in subreddit" unless [ "#{SUBREDDIT}_TEST" ].include?(SUBREDDIT) || ENV["START"]
|
14
|
+
10
|
15
|
+
else
|
16
|
+
200
|
17
|
+
end
|
18
|
+
|
19
|
+
fail unless flair = BOT.json(:get, "/r/#{SUBREDDIT}/api/link_flair").find do |flair|
|
20
|
+
flair["text"] == "Twitter"
|
21
|
+
end
|
22
|
+
|
23
|
+
timeout = 0
|
24
|
+
JSON.load( begin
|
25
|
+
NetHTTPUtils.request_data(
|
26
|
+
"https://api.twitter.com/1.1/statuses/user_timeline.json",
|
27
|
+
form: { screen_name: TWITTER, count: n, tweet_mode: "extended" },
|
28
|
+
header: { Authorization: "Bearer #{TWITTER_ACCESS_TOKEN}" }
|
29
|
+
)
|
30
|
+
rescue NetHTTPUtils::Error => e
|
31
|
+
fail if e.code != 503
|
32
|
+
sleep timeout += 1
|
33
|
+
retry
|
34
|
+
end ).sort_by{ |tweet| -tweet["id"] }.take_while do |tweet|
|
35
|
+
tweet["id"] > id && (!File.exist?("id") || tweet["id"] > File.read("id").to_i)
|
36
|
+
end.reverse_each do |tweet|
|
37
|
+
title, text, contains_media = Tweet2titleNtext[tweet]
|
38
|
+
result = BOT.json :post, "/api/submit", {
|
39
|
+
sr: SUBREDDIT,
|
40
|
+
kind: "self",
|
41
|
+
title: title,
|
42
|
+
text: text,
|
43
|
+
}.tap{ |h| h.merge!({ flair_id: flair["id"] }) }
|
44
|
+
unless result["json"]["errors"].empty?
|
45
|
+
fail unless result["json"]["errors"].map(&:first) == ["ALREADY_SUB"]
|
46
|
+
puts "ALREADY_SUB error for #{tweet["id"]}"
|
47
|
+
end
|
48
|
+
File.write "id", tweet["id"]
|
49
|
+
abort if ENV["ONCE"]
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "END LOOP #{Time.now}"
|
53
|
+
sleep 300
|
54
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "json"
|
2
|
+
require "nethttputils"
|
3
|
+
|
4
|
+
TWITTER_ACCESS_TOKEN = JSON.load(
|
5
|
+
NetHTTPUtils.request_data "https://api.twitter.com/oauth2/token", :post,
|
6
|
+
auth: File.read("twitter.token").split,
|
7
|
+
form: {grant_type: :client_credentials}
|
8
|
+
)["access_token"]
|
9
|
+
|
10
|
+
Tweet2titleNtext = lambda do |tweet|
|
11
|
+
pp tweet if ENV["TEST"]
|
12
|
+
text = ""
|
13
|
+
contains_media = false
|
14
|
+
up = ->s{ s.split.map{ |w| "^#{w}" }.join " " }
|
15
|
+
|
16
|
+
tweet_to_get_media_from = tweet["retweeted_status"] || tweet
|
17
|
+
if tweet_to_get_media_from["extended_entities"] && !tweet_to_get_media_from["extended_entities"]["media"].empty?
|
18
|
+
contains_media = true
|
19
|
+
tweet_to_get_media_from["extended_entities"]["media"].each_with_index do |media, i|
|
20
|
+
text.concat "* [Image #{i + 1}](#{media["media_url_https"]})\n\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
if !tweet_to_get_media_from["entities"]["urls"].empty?
|
24
|
+
contains_media = true
|
25
|
+
tweet_to_get_media_from["entities"]["urls"].each_with_index do |url, i|
|
26
|
+
text.concat "* [Link #{i + 1}](#{url["expanded_url"]})\n\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require "date"
|
31
|
+
text.concat "^- #{
|
32
|
+
up[tweet["user"]["name"]]
|
33
|
+
} [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [#{
|
34
|
+
up[Date.parse(tweet["created_at"]).strftime "%B %-d, %Y"]
|
35
|
+
}](https://twitter.com/#{TWITTER}/status/#{tweet["id"]})"
|
36
|
+
require "cgi"
|
37
|
+
# [CGI::unescapeHTML(tweet["full_text"]).sub(/( https:\/\/t\.co\/[0-9a-zA-Z]{10})*\z/, ""), text, contains_media]
|
38
|
+
[CGI::unescapeHTML(tweet["retweeted_status"] ? "RT: #{tweet["retweeted_status"]["full_text"]}" : tweet["full_text"]).sub(/(\s+https:\/\/t\.co\/[0-9a-zA-Z]{10})*\z/, ""), text, contains_media]
|
39
|
+
end
|
40
|
+
[
|
41
|
+
[905764294687633408, true, "The Polish government & military high command is now evacuating Warsaw for Brest, 120 miles east: German armies are too close to the capital", "* [Image 1](https://pbs.twimg.com/media/DJHq71BXYAA6KJ0.jpg)\n\n" "^- ^WW2 ^Tweets ^from ^1940 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^""September ^7, ^2017](https://twitter.com/#{TWITTER}/status/905764294687633408)"],
|
42
|
+
[915534673471733760, true, "In east Poland (now Soviet Ukraine) industry & farms to be collectivised, political parties banned, aristocrats & capitalists \"re-educated\".", "* [Image 1](https://pbs.twimg.com/media/DLSh2J9W4AACcOG.jpg)\n\n* [Image 2](https://pbs.twimg.com/media/DLSh4sKX0AEBaXq.jpg)\n\n^- ^WW2 ^Tweets ^from ^1940 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^4, ^2017](https://twitter.com/#{TWITTER}/status/915534673471733760)"],
|
43
|
+
[915208866408824832, true, "For 1st time, RAF planes dropping propaganda leaflets on Berlin itself, entitled \"Germans: these are your leaders!\"", "* [Image 1](https://pbs.twimg.com/media/DLN5jJ-XkAEUz9M.jpg)\n\n* [Link 1](https://www.psywar.org/product_1939EH158.php)\n\n" "^- ^WW2 ^Tweets ^from ^1940 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^3, ^2017](https://twitter.com/#{TWITTER}/status/915208866408824832)"],
|
44
|
+
[914577848891006978, true, "\"In Poland, Russia pursued a cold policy of selfinterest. But clearly necessary for Russia… against Nazi menace.\"", "* [Link 1](https://www.youtube.com/watch?v=ygmP5A3n2JA)\n\n" "^- ^WW2 ^Tweets ^from ^1940 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^1, ^2017](https://twitter.com/#{TWITTER}/status/914577848891006978)"],
|
45
|
+
[926581977372942336, false, "Finland rejects Soviet demand to surrender land near Leningrad & give Red Navy base in Hanko; Soviets now claim Finns' manner \"warlike\".", "^- ^WW2 ^Tweets ^from ^1940 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "November ^3, ^2017](https://twitter.com/#{TWITTER}/status/926581977372942336)"],
|
46
|
+
[1007650044441329664, true, "RT: SOLD OUT | Tonight’s @Johnny_Marr signing at Rough Trade East is now completely sold out! Catch you in a bit. ‘Call The Comet’ is out now:", "* [Image 1](https://pbs.twimg.com/media/DfvdN1_WsAE_a3r.jpg)\n\n* [Link 1](https://roughtrade.com/gb/music/johnny-marr-call-the-comet)\n\n^- ^Johnny ^Marr [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^June ^15, ^2018](https://twitter.com/#{TWITTER}/status/1007650044441329664)"],
|
47
|
+
[1007155648612581376, true, "Tomorrow. #CallTheComet", "* [Image 1](https://pbs.twimg.com/ext_tw_video_thumb/1007155601913204736/pu/img/IREVPkgUVHoQHfBB.jpg)\n\n" "^- ^Johnny ^Marr [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^June ^14, ^2018](https://twitter.com/#{TWITTER}/status/1007155648612581376)"],
|
48
|
+
].each do |id, contains_media_, title_, text_|
|
49
|
+
title, text, contains_media = Tweet2titleNtext[ JSON.load NetHTTPUtils.request_data(
|
50
|
+
"https://api.twitter.com/1.1/statuses/show.json",
|
51
|
+
form: { id: id, tweet_mode: "extended" },
|
52
|
+
header: { Authorization: "Bearer #{TWITTER_ACCESS_TOKEN}" },
|
53
|
+
) ]
|
54
|
+
unless contains_media_ == contains_media
|
55
|
+
puts "expected: #{contains_media_}"
|
56
|
+
puts "got: #{contains_media}"
|
57
|
+
abort "CONTAINS_MEDIA ERROR"
|
58
|
+
end
|
59
|
+
unless title_ == title
|
60
|
+
puts "expected:\n#{title_.inspect}"
|
61
|
+
puts "got:\n#{title.inspect}"
|
62
|
+
abort "TITLE FORMATTING ERROR"
|
63
|
+
end
|
64
|
+
unless text_ == text
|
65
|
+
puts "expected:\n#{text_.inspect}"
|
66
|
+
puts "got:\n#{text.inspect}"
|
67
|
+
abort "TEXT FORMATTING ERROR"
|
68
|
+
end
|
69
|
+
if ENV["TEST_POST"]
|
70
|
+
pp BOT.json :post, "/api/submit", {
|
71
|
+
sr: "#{SUBREDDIT}_TEST",
|
72
|
+
kind: "self",
|
73
|
+
title: title,
|
74
|
+
text: text,
|
75
|
+
}.tap{ |h| h.merge!({ flair_id: BOT.json(:get, "/r/#{SUBREDDIT}_TEST/api/link_flair").find{ |flair|
|
76
|
+
flair["text"] == "Contains Media"
|
77
|
+
}["id"] }) if contains_media }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
abort "OK" if ENV["TEST"]
|
@@ -1,8 +1,8 @@
|
|
1
1
|
GIT
|
2
2
|
remote: git@github.com:Nakilon/directlink.git
|
3
|
-
revision:
|
3
|
+
revision: b22cb9f103d474742f773b9434747f9cf5a09ed0
|
4
4
|
specs:
|
5
|
-
directlink (0.0.
|
5
|
+
directlink (0.0.3.0)
|
6
6
|
fastimage (~> 2.1.3)
|
7
7
|
nethttputils (~> 0.2.4.0)
|
8
8
|
|
@@ -83,7 +83,7 @@ GEM
|
|
83
83
|
mini_portile2 (2.1.0)
|
84
84
|
multi_json (1.13.1)
|
85
85
|
multipart-post (2.0.0)
|
86
|
-
nethttputils (0.2.4.
|
86
|
+
nethttputils (0.2.4.2)
|
87
87
|
nokogiri (1.6.8.1)
|
88
88
|
mini_portile2 (~> 2.1.0)
|
89
89
|
os (0.9.6)
|
@@ -37,7 +37,13 @@ EXCLUDE = %w{ foodporn powerwashingporn }
|
|
37
37
|
checked = []
|
38
38
|
|
39
39
|
search_url = lambda do |url|
|
40
|
-
JSON.load(
|
40
|
+
JSON.load( begin
|
41
|
+
NetHTTPUtils.request_data "https://www.reddit.com/r/largeimages/search.json", form: {q: "url:#{url}", restrict_sr: "on"}, header: ["User-Agent", "ajsdjasdasd"]
|
42
|
+
rescue NetHTTPUtils::Error => e
|
43
|
+
raise unless [503].include? e.code
|
44
|
+
sleep 60
|
45
|
+
retry
|
46
|
+
end )["data"]["children"]
|
41
47
|
end
|
42
48
|
fail unless 1 == search_url["https://i.imgur.com/9JTxtjW.jpg"].size
|
43
49
|
|
@@ -88,12 +94,12 @@ loop do
|
|
88
94
|
next logger.warn "skipped a post by /u/bekalaki" if author == "bekalaki" # 9 ways to divide a karmawhore
|
89
95
|
|
90
96
|
t = begin
|
91
|
-
DirectLink url
|
92
|
-
rescue
|
93
|
-
|
97
|
+
DirectLink url, 60
|
98
|
+
rescue SocketError,
|
99
|
+
Net::OpenTimeout,
|
100
|
+
NetHTTPUtils::Error,
|
94
101
|
FastImage::UnknownImageType,
|
95
102
|
FastImage::ImageFetchFailure,
|
96
|
-
# DirectLink::ErrorMissingEnvVar,
|
97
103
|
DirectLink::ErrorNotFound,
|
98
104
|
DirectLink::ErrorBadLink => e
|
99
105
|
next logger.error "skipped (#{e}) #{url} from http://redd.it/#{id}"
|
@@ -112,10 +118,8 @@ loop do
|
|
112
118
|
" [#{tt.size} images]" if tt.size > 1
|
113
119
|
} #{
|
114
120
|
title.sub(/\s*\[?#{tt.first.width}\s*[*x×]\s*#{tt.first.height}\]?\s*/i, " ").
|
115
|
-
sub("[OC]", " ").gsub(/\s+/, " ").strip
|
116
|
-
|
117
|
-
} /r/#{subreddit}".
|
118
|
-
gsub(/\s+\(\s+\)\s+/, " ")
|
121
|
+
sub("[OC]", " ").gsub(/\s+/, " ").strip
|
122
|
+
} /r/#{subreddit}".gsub(/\s+\(\s+\)\s+/, " ").sub(/(?<=.{297}).+/, "...")
|
119
123
|
logger.warn "new post #{source}: #{url} #{title.inspect}"
|
120
124
|
unless Gem::Platform.local.os == "darwin"
|
121
125
|
result = BOT.json :post,
|
data/examples/net_http_utils.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
GIT
|
2
|
-
remote: git@github.com:
|
3
|
-
revision:
|
4
|
-
tag: v0.1.0.4
|
2
|
+
remote: git@github.com:nakilon/reddit_bot.git
|
3
|
+
revision: 351c559e507289aa6385e769eb6d5c6de80ba629
|
5
4
|
specs:
|
6
|
-
|
5
|
+
reddit_bot (1.6.7)
|
6
|
+
json
|
7
|
+
nethttputils (~> 0.2.4.1)
|
7
8
|
|
8
9
|
GEM
|
9
10
|
remote: https://rubygems.org/
|
10
11
|
specs:
|
11
12
|
json (2.1.0)
|
12
|
-
|
13
|
-
json
|
13
|
+
nethttputils (0.2.4.2)
|
14
14
|
|
15
15
|
PLATFORMS
|
16
16
|
ruby
|
17
17
|
|
18
18
|
DEPENDENCIES
|
19
|
-
|
20
|
-
reddit_bot (~> 1.6.4)
|
19
|
+
reddit_bot!
|
21
20
|
|
22
21
|
BUNDLED WITH
|
23
22
|
1.16.1
|
data/lib/reddit_bot.rb
CHANGED
@@ -7,8 +7,15 @@ require "json"
|
|
7
7
|
|
8
8
|
require "nethttputils"
|
9
9
|
|
10
|
-
require_relative "reddit_bot/version"
|
10
|
+
require_relative "reddit_bot/version" # TODO: deprecate this
|
11
|
+
|
11
12
|
module RedditBot
|
13
|
+
require "logger"
|
14
|
+
class << self
|
15
|
+
attr_accessor :logger
|
16
|
+
end
|
17
|
+
self.logger = Logger.new STDOUT
|
18
|
+
|
12
19
|
class Bot
|
13
20
|
|
14
21
|
# bot's Reddit username; set via constructor parameter secrets[:login]
|
@@ -31,12 +38,12 @@ module RedditBot
|
|
31
38
|
response = JSON.parse resp_with_token mtd, path, form.merge({api_type: "json"})
|
32
39
|
if response.is_a?(Hash) && response["json"] && # for example, flairlist.json and {"error": 403} do not have it
|
33
40
|
!response["json"]["errors"].empty?
|
34
|
-
|
41
|
+
Module.nesting[1].logger.error "ERROR OCCURED on #{[mtd, path]}"
|
35
42
|
fail "unknown how to handle multiple errors" if 1 < response["json"]["errors"].size
|
36
|
-
|
43
|
+
Module.nesting[1].logger.error "error: #{response["json"]["errors"]}"
|
37
44
|
error, description = response["json"]["errors"].first
|
38
45
|
case error
|
39
|
-
when "ALREADY_SUB" ;
|
46
|
+
when "ALREADY_SUB" ; Module.nesting[1].logger.warn "was rejected by moderator if you didn't see in dups"
|
40
47
|
# when "BAD_CAPTCHA" ; update_captcha
|
41
48
|
# json mtd, path, form.merger( {
|
42
49
|
# iden: @iden_and_captcha[0],
|
@@ -44,7 +51,7 @@ module RedditBot
|
|
44
51
|
# } ) unless @ignore_captcha
|
45
52
|
when "RATELIMIT"
|
46
53
|
fail error unless description[/\Ayou are doing that too much\. try again in (\d) minutes\.\z/]
|
47
|
-
|
54
|
+
Module.nesting[1].logger.info "retrying in #{$1.to_i + 1} minutes"
|
48
55
|
sleep ($1.to_i + 1) * 60
|
49
56
|
return json mtd, path, _form
|
50
57
|
else ; fail error
|
@@ -68,7 +75,7 @@ module RedditBot
|
|
68
75
|
# [reason] :nodoc:
|
69
76
|
# [thing_id] +String+ fullname of a "link, commenr or message"
|
70
77
|
def report reason, thing_id
|
71
|
-
|
78
|
+
Module.nesting[1].logger.warn "reporting '#{thing_id}'"
|
72
79
|
json :post, "/api/report",
|
73
80
|
reason: "other",
|
74
81
|
other_reason: reason,
|
@@ -79,8 +86,11 @@ module RedditBot
|
|
79
86
|
# [link_flair_css_class] :nodoc:
|
80
87
|
# [link_flair_text] :nodoc:
|
81
88
|
def set_post_flair post, link_flair_css_class, link_flair_text
|
82
|
-
|
83
|
-
|
89
|
+
Module.nesting[1].logger.warn "setting flair '#{link_flair_css_class}' with text '#{link_flair_text}' to post '#{post["name"]}'"
|
90
|
+
if {"error"=>403} == @flairselector_choices ||= json(:post, "/r/#{@subreddit}/api/flairselector", link: post["name"])
|
91
|
+
Module.nesting[1].logger.error "possibly not enough permissions for /r/#{@subreddit}/api/flairselector"
|
92
|
+
return
|
93
|
+
end
|
84
94
|
json :post, "/api/selectflair",
|
85
95
|
link: post["name"],
|
86
96
|
text: link_flair_text,
|
@@ -92,7 +102,7 @@ module RedditBot
|
|
92
102
|
# [thing_id] +String+ fullname of a post (or self.post?), comment (and private message?)
|
93
103
|
# [text] :nodoc:
|
94
104
|
def leave_a_comment thing_id, text
|
95
|
-
|
105
|
+
Module.nesting[1].logger.warn "leaving a comment on '#{thing_id}'"
|
96
106
|
json(:post, "/api/comment",
|
97
107
|
thing_id: thing_id,
|
98
108
|
text: text,
|
@@ -180,7 +190,7 @@ module RedditBot
|
|
180
190
|
fail "bot #{@name} isn't a 'developer' of app at https://www.reddit.com/prefs/apps/" if response == {"error"=>"invalid_grant"}
|
181
191
|
fail response.inspect
|
182
192
|
end
|
183
|
-
|
193
|
+
Module.nesting[1].logger.info "new token is: #{@token_cached}"
|
184
194
|
# update_captcha if "true" == resp_with_token(:get, "/api/needs_captcha", {})
|
185
195
|
@token_cached
|
186
196
|
end
|
@@ -216,7 +226,7 @@ module RedditBot
|
|
216
226
|
NetHTTPUtils.request_data(url, mtd, form: form, header: headers, auth: basic_auth) do |response|
|
217
227
|
next unless remaining = response.to_hash["x-ratelimit-remaining"]
|
218
228
|
if Gem::Platform.local.os == "darwin"
|
219
|
-
|
229
|
+
Module.nesting[1].logger.debug %w{
|
220
230
|
x-ratelimit-remaining
|
221
231
|
x-ratelimit-used
|
222
232
|
x-ratelimit-reset
|
@@ -225,13 +235,13 @@ module RedditBot
|
|
225
235
|
fail remaining[0] if remaining[0].size < 4
|
226
236
|
next if remaining[0].size > 4
|
227
237
|
t = (response.to_hash["x-ratelimit-reset"][0].to_f + 1) / [remaining[0].to_f - 10, 1].max + 1
|
228
|
-
|
238
|
+
Module.nesting[1].logger.info "sleeping #{t} seconds because of x-ratelimit"
|
229
239
|
sleep t
|
230
240
|
end
|
231
241
|
rescue NetHTTPUtils::Error => e
|
232
242
|
sleep 5
|
233
|
-
raise unless e.code
|
234
|
-
|
243
|
+
raise unless e.code.to_s.start_with? "50"
|
244
|
+
Module.nesting[1].logger.error "API ERROR 50*"
|
235
245
|
retry
|
236
246
|
end
|
237
247
|
end
|
data/lib/reddit_bot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reddit_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Maslov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -77,6 +77,10 @@ files:
|
|
77
77
|
- examples/iostroubleshooting/Gemfile
|
78
78
|
- examples/iostroubleshooting/Gemfile.lock
|
79
79
|
- examples/iostroubleshooting/main.rb
|
80
|
+
- examples/johnnymarr/Gemfile
|
81
|
+
- examples/johnnymarr/Gemfile.lock
|
82
|
+
- examples/johnnymarr/main.rb
|
83
|
+
- examples/johnnymarr/twitter.rb
|
80
84
|
- examples/largeimages/Gemfile
|
81
85
|
- examples/largeimages/Gemfile.lock
|
82
86
|
- examples/largeimages/main.rb
|