reddit_bot 1.7.2 → 1.7.7
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/.gitignore +5 -0
- data/Rakefile +2 -2
- data/examples/cptflairbot3/main.rb +1 -1
- data/examples/devflairbot/main.rb +1 -1
- data/examples/dut/Gemfile +4 -0
- data/examples/dut/Gemfile.lock +24 -0
- data/examples/dut/main.rb +41 -0
- data/examples/largeimages/Gemfile +1 -1
- data/examples/largeimages/Gemfile.lock +21 -28
- data/examples/largeimages/main.rb +31 -25
- data/examples/realtimeww2/main.rb +6 -6
- data/examples/unisa/Gemfile +4 -0
- data/examples/unisa/Gemfile.lock +24 -0
- data/examples/unisa/main.rb +41 -0
- data/examples/wallpaper/Gemfile +1 -1
- data/examples/wallpaper/Gemfile.lock +16 -15
- data/lib/reddit_bot.rb +60 -20
- data/reddit_bot.gemspec +2 -4
- metadata +12 -6
- data/lib/reddit_bot/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 678fcb0251bf04be23802b62ddea29f5ea338386
|
4
|
+
data.tar.gz: b65667dea035f15f24a40f2c26017374b959780d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 384b4e42c38453c2a3ceb90892e144824f078f81dcc91e2c2ba65c39e22ed5e95d4b7ebc8bcba080d7113a10c654295768c8c6fcf32f7089495cd4395fafd80c
|
7
|
+
data.tar.gz: 24b3318a50e0ad0b784a8b8b1689ab3eef7dbebc1461760bc42a8fa920d6a223e2414910d2dfc38e5b50f394a1c032632d2aca87c12ba50141c1f07d941188dd
|
data/.gitignore
ADDED
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ loop do
|
|
10
10
|
next logger.info "bad destination: #{msg["data"]["dest"]}" unless msg["data"]["dest"] == "CPTFlairBot3"
|
11
11
|
case msg["data"]["subject"]
|
12
12
|
when "casualpokemontrades"
|
13
|
-
unless /^(?<name>\S+( \S+)*) ?\n(?<id>\d\d\d\d-\d\d\d\d-\d\d\d\d)\n(?<css_class
|
13
|
+
unless /^(?<name>\S+( \S+)*) ?\n(?<id>\d\d\d\d-\d\d\d\d-\d\d\d\d)\n(?<css_class>[a-z2-]+)$/ =~ msg["data"]["body"]
|
14
14
|
logger.info "invalid message for #{msg["data"]["subject"]}: %p" % msg["data"]["body"] unless Google::Cloud.env.compute_engine?
|
15
15
|
# puts "marking invalid message as read: %p" % msg["data"]["body"]
|
16
16
|
# BOT.json :post, "/api/read_message", {id: msg["data"]["name"]} unless Gem::Platform.local.os == "darwin"
|
@@ -34,7 +34,7 @@ loop do
|
|
34
34
|
JSON.parse( begin
|
35
35
|
NetHTTPUtils.request_data "https://www.reddit.com/r/#{subreddit}/comments.json", header: ["User-Agent", "ajsdjasdasd"]
|
36
36
|
rescue NetHTTPUtils::Error => e
|
37
|
-
raise unless [503, 504
|
37
|
+
raise unless [500, 502, 503, 504].include? e.code
|
38
38
|
sleep 60
|
39
39
|
retry
|
40
40
|
end )["data"]["children"].each do |comment|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
json (2.3.1)
|
7
|
+
nethttputils (0.4.0.0)
|
8
|
+
addressable
|
9
|
+
public_suffix (4.0.5)
|
10
|
+
reddit_bot (1.7.6)
|
11
|
+
json
|
12
|
+
nethttputils (~> 0.4.0.0)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
reddit_bot
|
19
|
+
|
20
|
+
RUBY VERSION
|
21
|
+
ruby 2.3.8p459
|
22
|
+
|
23
|
+
BUNDLED WITH
|
24
|
+
2.0.2
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "reddit_bot"
|
2
|
+
subreddit = "dut".freeze
|
3
|
+
bot = RedditBot::Bot.new YAML.load(File.read "secrets.yaml"), subreddit: subreddit
|
4
|
+
RedditBot::Twitter.init_twitter "DUT_Tweets"
|
5
|
+
|
6
|
+
loop do
|
7
|
+
bot.json(:get, "/message/unread")["data"]["children"].each do |msg|
|
8
|
+
next unless %w{ nakilon technomod }.include? msg["data"]["author"]
|
9
|
+
abort "ordered to die" if %w{ die die } == msg["data"].values_at("subject", "body")
|
10
|
+
end
|
11
|
+
|
12
|
+
id = bot.new_posts.flat_map do |post|
|
13
|
+
post["selftext"].scan(/\(https:\/\/twitter\.com\/#{RedditBot::Twitter::TWITTER_ACCOUNT}\/status\/(\d{18,})\)/i).flatten.map(&:to_i).max
|
14
|
+
end.find(&:itself)
|
15
|
+
abort "no tweets found in subreddit" if id.zero? unless ENV["FIRST_RUN"]
|
16
|
+
abort "flair isn't available" unless flair = bot.json(:get, "/r/#{subreddit}/api/link_flair").find{ |flair| flair["text"] == "Twitter" }
|
17
|
+
|
18
|
+
timeline = RedditBot::Twitter.user_timeline
|
19
|
+
timeline.replace timeline.take 2 if ENV["FIRST_RUN"] # against 200 posts long flood
|
20
|
+
timeline.reverse_each do |tweet|
|
21
|
+
next if tweet["id"] <= id
|
22
|
+
title, text, _ = RedditBot::Twitter.tweet2titleNtext tweet
|
23
|
+
result = bot.json :post, "/api/submit", {
|
24
|
+
sr: subreddit,
|
25
|
+
kind: "self",
|
26
|
+
title: title,
|
27
|
+
text: text,
|
28
|
+
flair_id: flair["id"],
|
29
|
+
}
|
30
|
+
p result
|
31
|
+
if result["json"]["errors"].empty?
|
32
|
+
abort "OK" if ENV["ONCE"]
|
33
|
+
next
|
34
|
+
end
|
35
|
+
fail unless result["json"]["errors"].map(&:first) == ["ALREADY_SUB"]
|
36
|
+
puts "ALREADY_SUB error for #{tweet["id"]}"
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "END LOOP #{Time.now}"
|
40
|
+
sleep 300
|
41
|
+
end
|
@@ -7,5 +7,5 @@ gem "nokogiri"
|
|
7
7
|
gem "nethttputils", git: "git@github.com:nakilon/nethttputils.git"
|
8
8
|
gem "directlink", git: "git@github.com:nakilon/directlink.git"
|
9
9
|
|
10
|
-
gem "gcplogger", git: "git@github.com:nakilon/gcplogger.git"
|
10
|
+
gem "gcplogger", git: "git@github.com:nakilon/gcplogger.git"
|
11
11
|
gem "google-cloud-error_reporting"
|
@@ -1,15 +1,3 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git@github.com:nakilon/directlink.git
|
3
|
-
revision: a1645d3abca0182e6de80f1a7b37b6ad0513b672
|
4
|
-
specs:
|
5
|
-
directlink (0.0.6.0)
|
6
|
-
addressable
|
7
|
-
fastimage (~> 2.1.3)
|
8
|
-
kramdown
|
9
|
-
nethttputils (~> 0.3.2.3)
|
10
|
-
nokogiri
|
11
|
-
reddit_bot (~> 1.7.0)
|
12
|
-
|
13
1
|
GIT
|
14
2
|
remote: git@github.com:nakilon/gcplogger.git
|
15
3
|
revision: 7c1451fac49bd0d242c6de43315ae6e9a70d8f7f
|
@@ -19,20 +7,21 @@ GIT
|
|
19
7
|
google-cloud-logging (~> 1.4.0)
|
20
8
|
public_suffix (~> 2.0)
|
21
9
|
|
22
|
-
GIT
|
23
|
-
remote: git@github.com:nakilon/nethttputils.git
|
24
|
-
revision: 6450111a35803b474c2331d8e12da6546101c887
|
25
|
-
specs:
|
26
|
-
nethttputils (0.3.2.6)
|
27
|
-
|
28
10
|
GEM
|
29
11
|
remote: https://rubygems.org/
|
30
12
|
specs:
|
31
|
-
addressable (2.
|
32
|
-
public_suffix (>= 2.0.2, <
|
13
|
+
addressable (2.7.0)
|
14
|
+
public_suffix (>= 2.0.2, < 5.0)
|
15
|
+
directlink (0.0.9.0)
|
16
|
+
addressable
|
17
|
+
fastimage (~> 2.1.3)
|
18
|
+
kramdown
|
19
|
+
nethttputils (~> 0.4.0.0)
|
20
|
+
nokogiri
|
21
|
+
reddit_bot (~> 1.7.0)
|
33
22
|
faraday (0.14.0)
|
34
23
|
multipart-post (>= 1.2, < 3)
|
35
|
-
fastimage (2.1.
|
24
|
+
fastimage (2.1.7)
|
36
25
|
google-cloud-core (1.2.0)
|
37
26
|
google-cloud-env (~> 1.0)
|
38
27
|
google-cloud-env (1.0.1)
|
@@ -72,7 +61,8 @@ GEM
|
|
72
61
|
googleauth (>= 0.5.1, < 0.7)
|
73
62
|
json (2.2.0)
|
74
63
|
jwt (2.1.0)
|
75
|
-
kramdown (2.
|
64
|
+
kramdown (2.3.0)
|
65
|
+
rexml
|
76
66
|
little-plugger (1.1.4)
|
77
67
|
logging (2.2.2)
|
78
68
|
little-plugger (~> 1.1)
|
@@ -81,13 +71,16 @@ GEM
|
|
81
71
|
mini_portile2 (2.4.0)
|
82
72
|
multi_json (1.13.1)
|
83
73
|
multipart-post (2.0.0)
|
84
|
-
|
74
|
+
nethttputils (0.4.0.0)
|
75
|
+
addressable
|
76
|
+
nokogiri (1.10.8)
|
85
77
|
mini_portile2 (~> 2.4.0)
|
86
78
|
os (0.9.6)
|
87
79
|
public_suffix (2.0.5)
|
88
|
-
reddit_bot (1.7.
|
80
|
+
reddit_bot (1.7.6)
|
89
81
|
json
|
90
|
-
nethttputils (~> 0.
|
82
|
+
nethttputils (~> 0.4.0.0)
|
83
|
+
rexml (3.2.4)
|
91
84
|
rly (0.2.3)
|
92
85
|
signet (0.8.1)
|
93
86
|
addressable (~> 2.3)
|
@@ -101,12 +94,12 @@ PLATFORMS
|
|
101
94
|
ruby
|
102
95
|
|
103
96
|
DEPENDENCIES
|
104
|
-
directlink
|
97
|
+
directlink (~> 0.0.9.0)
|
105
98
|
gcplogger!
|
106
99
|
google-cloud-error_reporting
|
107
100
|
json
|
108
|
-
nethttputils
|
101
|
+
nethttputils
|
109
102
|
nokogiri
|
110
103
|
|
111
104
|
BUNDLED WITH
|
112
|
-
|
105
|
+
2.0.2
|
@@ -16,21 +16,21 @@ require "directlink"
|
|
16
16
|
require "nokogiri"
|
17
17
|
|
18
18
|
require "../boilerplate"
|
19
|
-
|
19
|
+
bot = RedditBot::Bot.new YAML.load_file "secrets.yaml"
|
20
20
|
|
21
21
|
INCLUDE = %w{
|
22
22
|
user/kjoneslol/m/sfwpornnetwork
|
23
23
|
|
24
24
|
r/woahdude
|
25
|
+
r/pic
|
25
26
|
|
26
27
|
r/highres
|
27
28
|
r/wallpapers
|
28
29
|
r/wallpaper
|
29
30
|
r/WQHD_Wallpaper
|
30
31
|
|
31
|
-
r/pic
|
32
|
-
|
33
32
|
r/oldmaps
|
33
|
+
r/telephotolandscapes
|
34
34
|
}
|
35
35
|
EXCLUDE = %w{ foodporn powerwashingporn }
|
36
36
|
|
@@ -40,7 +40,7 @@ search_url = lambda do |url|
|
|
40
40
|
JSON.load( begin
|
41
41
|
NetHTTPUtils.request_data "https://www.reddit.com/r/largeimages/search.json", form: {q: "url:#{url}", restrict_sr: "on"}, header: ["User-Agent", "ajsdjasdasd"]
|
42
42
|
rescue NetHTTPUtils::Error => e
|
43
|
-
raise unless [503].include? e.code
|
43
|
+
raise unless [500, 503].include? e.code
|
44
44
|
sleep 60
|
45
45
|
retry
|
46
46
|
end )["data"]["children"]
|
@@ -74,7 +74,7 @@ loop do
|
|
74
74
|
]
|
75
75
|
end ) ],
|
76
76
|
[:source_reddit, 30000000, ( INCLUDE.flat_map do |sortasub|
|
77
|
-
|
77
|
+
bot.new_posts(sortasub).take(100).map do |child|
|
78
78
|
next if child["is_self"]
|
79
79
|
next if EXCLUDE.include? child["subreddit"].downcase
|
80
80
|
child.values_at(
|
@@ -85,37 +85,43 @@ loop do
|
|
85
85
|
].each do |source, min_resolution, entries|
|
86
86
|
logger.warn "#{source}.size: #{entries.size}"
|
87
87
|
entries.each do |id, url, title, subreddit, author, permalink|
|
88
|
+
author.downcase!
|
88
89
|
next if checked.include? id
|
89
90
|
checked << id
|
90
91
|
# next if Gem::Platform.local.os == "darwin" # prevent concurrent posting
|
91
92
|
logger.debug "image url for #{id}: #{url}"
|
92
|
-
next logger.warn "skipped a post by /u/sjhill"
|
93
|
-
next logger.warn "skipped a post by /u/redisforever"
|
94
|
-
next logger.warn "skipped a post by /u/bekalaki"
|
93
|
+
next logger.warn "skipped a post by /u/sjhill" if author == "sjhill" # opt-out
|
94
|
+
next logger.warn "skipped a post by /u/redisforever" if author == "redisforever" # opt-out
|
95
|
+
next logger.warn "skipped a post by /u/bekalaki" if author == "bekalaki" # 9 ways to divide a karmawhore
|
96
|
+
next logger.warn "skipped a post by /u/cherryblackeyes" if author == "cherryblackeyes" # he's not nice
|
97
|
+
next logger.warn "skipped a post by /u/abel_a_kay" if author == "abel_a_kay" # posting very similar images of the same thing for the history
|
98
|
+
next logger.warn "skipped gifv" if ( begin
|
99
|
+
URI url
|
100
|
+
rescue URI::InvalidURIError
|
101
|
+
require "addressable"
|
102
|
+
URI Addressable::URI.escape url
|
103
|
+
end ).host.split(?.) == %w{ v redd it }
|
95
104
|
|
96
105
|
t = begin
|
97
106
|
DirectLink url, 60
|
98
|
-
rescue
|
99
|
-
Net::OpenTimeout,
|
100
|
-
Errno::ECONNRESET,
|
101
|
-
NetHTTPUtils::Error,
|
102
|
-
FastImage::UnknownImageType,
|
103
|
-
FastImage::ImageFetchFailure,
|
104
|
-
DirectLink::ErrorNotFound,
|
105
|
-
DirectLink::ErrorBadLink => e
|
107
|
+
rescue *DirectLink::NORMAL_EXCEPTIONS => e
|
106
108
|
next logger.error "skipped (#{e}) #{url} from http://redd.it/#{id}"
|
107
109
|
end
|
108
|
-
logger.
|
110
|
+
logger.debug "DirectLink: #{t.inspect}"
|
109
111
|
tt = t.is_a?(Array) ? t : [t]
|
110
112
|
next logger.error "probably crosspost of a self post: http://redd.it/#{id}" if tt.empty?
|
111
|
-
unless min_resolution <= tt.first.width * tt.first.height
|
112
|
-
next logger.debug "skipped low resolution #{source}"
|
113
|
-
end
|
113
|
+
next logger.info "skipped low resolution #{source}" unless min_resolution <= tt.first.width * tt.first.height
|
114
114
|
# puts "https://www.reddit.com/r/LargeImages/search.json?q=url%3A#{CGI.escape url}&restrict_sr=on"
|
115
115
|
resolution = "[#{tt.first.width}x#{tt.first.height}]"
|
116
|
-
next logger.warn "already submitted #{resolution} #{id}: '#{url}'" unless
|
117
|
-
|
118
|
-
|
116
|
+
next logger.warn "already submitted #{resolution} #{id}: '#{url}'" unless Gem::Platform.local.os == "darwin" || search_url[url].empty?
|
117
|
+
|
118
|
+
system "curl -s '#{tt.first.url}' -o temp --retry 5" or fail
|
119
|
+
next logger.warn "skipped <2mb id=#{id}" if 2000000 > File.size("temp")
|
120
|
+
if "mapporn" == subreddit.downcase
|
121
|
+
`vips pngsave temp temp.png`
|
122
|
+
next logger.warn "skipped /r/mapporn <10mb PNG id=#{id}" if 10000000 > File.size("temp.png")
|
123
|
+
end
|
124
|
+
|
119
125
|
title = "#{resolution}#{
|
120
126
|
" [#{tt.size} images]" if tt.size > 1
|
121
127
|
} #{
|
@@ -124,7 +130,7 @@ loop do
|
|
124
130
|
} /r/#{subreddit}".gsub(/\s+\(\s+\)\s+/, " ").sub(/(?<=.{297}).+/, "...")
|
125
131
|
logger.warn "new post #{source}: #{url} #{title.inspect}"
|
126
132
|
unless Gem::Platform.local.os == "darwin"
|
127
|
-
result =
|
133
|
+
result = bot.json :post,
|
128
134
|
"/api/submit",
|
129
135
|
{
|
130
136
|
kind: "link",
|
@@ -151,7 +157,7 @@ loop do
|
|
151
157
|
text = [line1, line2, line3].compact.join(" \n")
|
152
158
|
logger.info "new comment: #{text.inspect}"
|
153
159
|
unless Gem::Platform.local.os == "darwin"
|
154
|
-
result =
|
160
|
+
result = bot.leave_a_comment "#{result["json"]["data"]["name"]}", text.sub(/(?<=.{9000}).+/m, "...")
|
155
161
|
unless result["json"]["errors"].empty?
|
156
162
|
logger.error result.inspect
|
157
163
|
fail "failed to leave comment"
|
@@ -37,11 +37,11 @@ tweet2titleNtext = lambda do |tweet|
|
|
37
37
|
[CGI::unescapeHTML(tweet["full_text"]).sub(/( https:\/\/t\.co\/[0-9a-zA-Z]{10})*\z/, ""), text, contains_media]
|
38
38
|
end
|
39
39
|
[
|
40
|
-
[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 ^
|
41
|
-
[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 ^
|
42
|
-
[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 ^
|
43
|
-
[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 ^
|
44
|
-
[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 ^
|
40
|
+
[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 ^1942 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^""September ^7, ^2017](https://twitter.com/#{TWITTER}/status/905764294687633408)"],
|
41
|
+
[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 ^1942 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^4, ^2017](https://twitter.com/#{TWITTER}/status/915534673471733760)"],
|
42
|
+
[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 ^1942 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^3, ^2017](https://twitter.com/#{TWITTER}/status/915208866408824832)"],
|
43
|
+
[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 ^1942 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^1, ^2017](https://twitter.com/#{TWITTER}/status/914577848891006978)"],
|
44
|
+
[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 ^1942 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "November ^3, ^2017](https://twitter.com/#{TWITTER}/status/926581977372942336)"],
|
45
45
|
].each do |id, contains_media_, title_, text_|
|
46
46
|
title, text, contains_media = tweet2titleNtext[ JSON.load NetHTTPUtils.request_data(
|
47
47
|
"https://api.twitter.com/1.1/statuses/show.json",
|
@@ -101,7 +101,7 @@ loop do
|
|
101
101
|
sleep t
|
102
102
|
end
|
103
103
|
rescue NetHTTPUtils::Error => e
|
104
|
-
fail
|
104
|
+
fail unless [500, 503].include? e.code
|
105
105
|
sleep timeout
|
106
106
|
timeout *= 2
|
107
107
|
retry
|
@@ -0,0 +1,24 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
json (2.3.1)
|
7
|
+
nethttputils (0.4.0.0)
|
8
|
+
addressable
|
9
|
+
public_suffix (4.0.5)
|
10
|
+
reddit_bot (1.7.6)
|
11
|
+
json
|
12
|
+
nethttputils (~> 0.4.0.0)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
reddit_bot
|
19
|
+
|
20
|
+
RUBY VERSION
|
21
|
+
ruby 2.3.8p459
|
22
|
+
|
23
|
+
BUNDLED WITH
|
24
|
+
2.0.2
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "reddit_bot"
|
2
|
+
subreddit = "unisa".freeze
|
3
|
+
bot = RedditBot::Bot.new YAML.load(File.read "secrets.yaml"), subreddit: subreddit
|
4
|
+
RedditBot::Twitter.init_twitter "unisa"
|
5
|
+
|
6
|
+
loop do
|
7
|
+
bot.json(:get, "/message/unread")["data"]["children"].each do |msg|
|
8
|
+
next unless %w{ nakilon technomod }.include? msg["data"]["author"]
|
9
|
+
abort "ordered to die" if %w{ die die } == msg["data"].values_at("subject", "body")
|
10
|
+
end
|
11
|
+
|
12
|
+
id = bot.new_posts.flat_map do |post|
|
13
|
+
post["selftext"].scan(/\(https:\/\/twitter\.com\/#{RedditBot::Twitter::TWITTER_ACCOUNT}\/status\/(\d{18,})\)/i).flatten.map(&:to_i).max
|
14
|
+
end.find(&:itself)
|
15
|
+
abort "no tweets found in subreddit" if id.zero? unless ENV["FIRST_RUN"]
|
16
|
+
abort "flair isn't available" unless flair = bot.json(:get, "/r/#{subreddit}/api/link_flair").find{ |flair| flair["text"] == "Twitter" }
|
17
|
+
|
18
|
+
timeline = RedditBot::Twitter.user_timeline
|
19
|
+
timeline.replace timeline.take 2 if ENV["FIRST_RUN"] # against 200 posts long flood
|
20
|
+
timeline.reverse_each do |tweet|
|
21
|
+
next if tweet["id"] <= id
|
22
|
+
title, text, _ = RedditBot::Twitter.tweet2titleNtext tweet
|
23
|
+
result = bot.json :post, "/api/submit", {
|
24
|
+
sr: subreddit,
|
25
|
+
kind: "self",
|
26
|
+
title: title,
|
27
|
+
text: text,
|
28
|
+
flair_id: flair["id"],
|
29
|
+
}
|
30
|
+
p result
|
31
|
+
if result["json"]["errors"].empty?
|
32
|
+
abort "OK" if ENV["ONCE"]
|
33
|
+
next
|
34
|
+
end
|
35
|
+
fail unless result["json"]["errors"].map(&:first) == ["ALREADY_SUB"]
|
36
|
+
puts "ALREADY_SUB error for #{tweet["id"]}"
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "END LOOP #{Time.now}"
|
40
|
+
sleep 300
|
41
|
+
end
|
data/examples/wallpaper/Gemfile
CHANGED
@@ -1,33 +1,34 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
addressable (2.
|
5
|
-
public_suffix (>= 2.0.2, <
|
6
|
-
directlink (0.0.
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
directlink (0.0.8.7)
|
7
7
|
addressable
|
8
8
|
fastimage (~> 2.1.3)
|
9
9
|
kramdown
|
10
|
+
nethttputils (~> 0.3.3.0)
|
10
11
|
nokogiri
|
11
|
-
reddit_bot (~> 1.
|
12
|
-
fastimage (2.1.
|
13
|
-
json (2.
|
14
|
-
kramdown (1.
|
15
|
-
mini_portile2 (2.
|
16
|
-
nethttputils (0.
|
17
|
-
nokogiri (1.
|
18
|
-
mini_portile2 (~> 2.
|
12
|
+
reddit_bot (~> 1.7.0)
|
13
|
+
fastimage (2.1.7)
|
14
|
+
json (2.3.0)
|
15
|
+
kramdown (2.1.0)
|
16
|
+
mini_portile2 (2.4.0)
|
17
|
+
nethttputils (0.3.3.0)
|
18
|
+
nokogiri (1.10.4)
|
19
|
+
mini_portile2 (~> 2.4.0)
|
19
20
|
public_suffix (2.0.5)
|
20
|
-
reddit_bot (1.
|
21
|
+
reddit_bot (1.7.3)
|
21
22
|
json
|
22
|
-
nethttputils (~> 0.
|
23
|
+
nethttputils (~> 0.3.3.0)
|
23
24
|
|
24
25
|
PLATFORMS
|
25
26
|
ruby
|
26
27
|
|
27
28
|
DEPENDENCIES
|
28
29
|
directlink
|
29
|
-
nokogiri (~> 1.
|
30
|
+
nokogiri (~> 1.10.4)
|
30
31
|
public_suffix (< 3.0)
|
31
32
|
|
32
33
|
BUNDLED WITH
|
33
|
-
|
34
|
+
2.0.2
|
data/lib/reddit_bot.rb
CHANGED
@@ -3,11 +3,10 @@ STDOUT.sync = true
|
|
3
3
|
|
4
4
|
require "openssl"
|
5
5
|
require "json"
|
6
|
+
require "yaml"
|
6
7
|
|
7
8
|
require "nethttputils"
|
8
9
|
|
9
|
-
require_relative "reddit_bot/version" # TODO: deprecate this
|
10
|
-
|
11
10
|
module RedditBot
|
12
11
|
require "logger"
|
13
12
|
class << self
|
@@ -204,7 +203,7 @@ module RedditBot
|
|
204
203
|
username: @name,
|
205
204
|
password: @secret_password,
|
206
205
|
}, {
|
207
|
-
"User-Agent" => "bot/#{@user_agent || @name}/#{
|
206
|
+
"User-Agent" => "bot/#{@user_agent || @name}/#{Gem::Specification::load("#{__dir__}/../reddit_bot.gemspec").version} by /u/nakilon",
|
208
207
|
}, @secret_auth
|
209
208
|
unless @token_cached = response["access_token"]
|
210
209
|
fail "bot #{@name} isn't a 'developer' of app at https://www.reddit.com/prefs/apps/" if response == {"error"=>"invalid_grant"}
|
@@ -231,13 +230,13 @@ module RedditBot
|
|
231
230
|
begin
|
232
231
|
reddit_resp mtd, "https://oauth.reddit.com" + path, form, {
|
233
232
|
"Authorization" => "bearer #{token}",
|
234
|
-
"User-Agent" => "bot/#{@user_agent || @name}/#{
|
233
|
+
"User-Agent" => "bot/#{@user_agent || @name}/#{Gem::Specification::load("#{__dir__}/../reddit_bot.gemspec").version} by /u/nakilon",
|
235
234
|
}
|
236
235
|
rescue NetHTTPUtils::Error => e
|
236
|
+
raise unless e.code == 401
|
237
237
|
sleep timeout
|
238
238
|
Module.nesting[1].logger.info "sleeping #{timeout} seconds because of #{e.code}"
|
239
239
|
timeout *= 2
|
240
|
-
raise unless e.code == 401
|
241
240
|
@token_cached = nil
|
242
241
|
retry
|
243
242
|
end
|
@@ -247,21 +246,7 @@ module RedditBot
|
|
247
246
|
mtd, url, form, headers, basic_auth = *args
|
248
247
|
headers["Cookie:"] = "over18=1"
|
249
248
|
begin
|
250
|
-
NetHTTPUtils.request_data
|
251
|
-
next unless remaining = response.to_hash["x-ratelimit-remaining"]
|
252
|
-
if Gem::Platform.local.os == "darwin"
|
253
|
-
Module.nesting[1].logger.debug %w{
|
254
|
-
x-ratelimit-remaining
|
255
|
-
x-ratelimit-used
|
256
|
-
x-ratelimit-reset
|
257
|
-
}.map{ |key| "#{key}=#{response.to_hash[key]}" }.join ", "
|
258
|
-
end
|
259
|
-
fail remaining[0] if remaining[0].size < 4
|
260
|
-
next if remaining[0].size > 4
|
261
|
-
t = (response.to_hash["x-ratelimit-reset"][0].to_f + 1) / [remaining[0].to_f - 10, 1].max + 1
|
262
|
-
Module.nesting[1].logger.info "sleeping #{t} seconds because of x-ratelimit"
|
263
|
-
sleep t
|
264
|
-
end
|
249
|
+
NetHTTPUtils.request_data url, mtd, form: form, header: headers, auth: basic_auth
|
265
250
|
rescue NetHTTPUtils::Error => e
|
266
251
|
sleep 5
|
267
252
|
raise unless e.code.to_s.start_with? "50"
|
@@ -271,4 +256,59 @@ module RedditBot
|
|
271
256
|
end
|
272
257
|
|
273
258
|
end
|
259
|
+
|
260
|
+
module Twitter
|
261
|
+
require "json"
|
262
|
+
|
263
|
+
def self.init_twitter twitter
|
264
|
+
const_set :TWITTER_ACCOUNT, twitter
|
265
|
+
const_set :TWITTER_ACCESS_TOKEN, JSON.load(
|
266
|
+
NetHTTPUtils.request_data "https://api.twitter.com/oauth2/token", :post,
|
267
|
+
auth: File.read("twitter.token").split,
|
268
|
+
form: {grant_type: :client_credentials}
|
269
|
+
)["access_token"]
|
270
|
+
end
|
271
|
+
|
272
|
+
require "cgi"
|
273
|
+
def self.tweet2titleNtext tweet
|
274
|
+
text = ""
|
275
|
+
contains_media = false
|
276
|
+
up = ->s{ s.split.map{ |w| "^#{w}" }.join " " }
|
277
|
+
if tweet["extended_entities"] && !tweet["extended_entities"]["media"].empty?
|
278
|
+
contains_media = true
|
279
|
+
tweet["extended_entities"]["media"].each_with_index do |media, i|
|
280
|
+
text.concat "* [Image #{i + 1}](#{media["media_url_https"]})\n\n"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
if !tweet["entities"]["urls"].empty?
|
284
|
+
contains_media = true
|
285
|
+
tweet["entities"]["urls"].each_with_index do |url, i|
|
286
|
+
text.concat "* [Link #{i + 1}](#{url["expanded_url"]})\n\n"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
text.concat "^- #{
|
290
|
+
up[tweet["user"]["name"]]
|
291
|
+
} [^\\(@#{TWITTER_ACCOUNT}\\)](https://twitter.com/#{TWITTER_ACCOUNT}) ^| [#{
|
292
|
+
up[Date.parse(tweet["created_at"]).strftime "%B %-d, %Y"]
|
293
|
+
}](https://twitter.com/#{TWITTER_ACCOUNT}/status/#{tweet["id"]})"
|
294
|
+
[CGI::unescapeHTML(tweet["full_text"]).sub(/( https:\/\/t\.co\/[0-9a-zA-Z]{10})*\z/, ""), text, contains_media]
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.user_timeline
|
298
|
+
timeout = 1
|
299
|
+
JSON.load begin
|
300
|
+
NetHTTPUtils.request_data(
|
301
|
+
"https://api.twitter.com/1.1/statuses/user_timeline.json",
|
302
|
+
form: { screen_name: TWITTER_ACCOUNT, count: 200, tweet_mode: "extended" },
|
303
|
+
header: { Authorization: "Bearer #{TWITTER_ACCESS_TOKEN}" }
|
304
|
+
)
|
305
|
+
rescue NetHTTPUtils::Error => e
|
306
|
+
fail unless [500, 503].include? e.code
|
307
|
+
sleep timeout
|
308
|
+
timeout *= 2
|
309
|
+
retry
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
274
314
|
end
|
data/reddit_bot.gemspec
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require_relative "lib/reddit_bot/version"
|
2
|
-
|
3
1
|
Gem::Specification.new do |spec|
|
4
2
|
spec.name = "reddit_bot"
|
5
|
-
spec.version =
|
3
|
+
spec.version = "1.7.7"
|
6
4
|
spec.authors = ["Victor Maslov"]
|
7
5
|
spec.email = ["nakilon@gmail.com"]
|
8
6
|
|
@@ -15,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
15
13
|
# spec.require_paths = ["lib"]
|
16
14
|
|
17
15
|
spec.add_runtime_dependency "json"
|
18
|
-
spec.add_runtime_dependency "nethttputils", "~>0.
|
16
|
+
spec.add_runtime_dependency "nethttputils", "~>0.4.1.0"
|
19
17
|
# spec.add_development_dependency "bundler", "~> 1.11"
|
20
18
|
# spec.add_development_dependency "rake", "~> 10.0"
|
21
19
|
# spec.add_development_dependency "rspec", "~> 3.0"
|
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.7.
|
4
|
+
version: 1.7.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:
|
11
|
+
date: 2020-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.4.1.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.4.1.0
|
41
41
|
description: better than PRAW
|
42
42
|
email:
|
43
43
|
- nakilon@gmail.com
|
@@ -45,6 +45,7 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".gitignore"
|
48
49
|
- Gemfile
|
49
50
|
- LICENSE.txt
|
50
51
|
- README.md
|
@@ -72,6 +73,9 @@ files:
|
|
72
73
|
- examples/devflairbot/Gemfile
|
73
74
|
- examples/devflairbot/Gemfile.lock
|
74
75
|
- examples/devflairbot/main.rb
|
76
|
+
- examples/dut/Gemfile
|
77
|
+
- examples/dut/Gemfile.lock
|
78
|
+
- examples/dut/main.rb
|
75
79
|
- examples/get_dimensions.rb
|
76
80
|
- examples/iostroubleshooting/Gemfile
|
77
81
|
- examples/iostroubleshooting/Gemfile.lock
|
@@ -101,6 +105,9 @@ files:
|
|
101
105
|
- examples/sexypizza/Gemfile
|
102
106
|
- examples/sexypizza/Gemfile.lock
|
103
107
|
- examples/sexypizza/main.rb
|
108
|
+
- examples/unisa/Gemfile
|
109
|
+
- examples/unisa/Gemfile.lock
|
110
|
+
- examples/unisa/main.rb
|
104
111
|
- examples/wallpaper/Gemfile
|
105
112
|
- examples/wallpaper/Gemfile.lock
|
106
113
|
- examples/wallpaper/main.rb
|
@@ -108,7 +115,6 @@ files:
|
|
108
115
|
- examples/yayornay/Gemfile.lock
|
109
116
|
- examples/yayornay/main.rb
|
110
117
|
- lib/reddit_bot.rb
|
111
|
-
- lib/reddit_bot/version.rb
|
112
118
|
- reddit_bot.gemspec
|
113
119
|
homepage: https://github.com/Nakilon/reddit_bot
|
114
120
|
licenses:
|
@@ -130,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
136
|
version: '0'
|
131
137
|
requirements: []
|
132
138
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.5.2
|
139
|
+
rubygems_version: 2.5.2.3
|
134
140
|
signing_key:
|
135
141
|
specification_version: 4
|
136
142
|
summary: Library for Reddit bots
|
data/lib/reddit_bot/version.rb
DELETED