reddit_bot 1.7.2 → 1.7.7
Sign up to get free protection for your applications and to get access to all the features.
- 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