directlink 0.0.4.3 → 0.0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.bashrc +2 -1
- data/README.md +17 -2
- data/directlink.gemspec +2 -2
- data/lib/directlink.rb +61 -48
- data/test.rb +118 -16
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e252357f3a65696511a206fa8fdf8bebd65cc97
|
4
|
+
data.tar.gz: f4fddedf24809bed96c56a3e063b92d8feeb2cb9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c955776c59833e37194229370d7d26b17d1e6d48674b1cde952cc262eb9705e8681f8eb68d700b7de41abe31bb976a1fb297a18712a157dc0aec364b9d668377
|
7
|
+
data.tar.gz: cf7513d360fdfb6bad2108906398526ed18ee588dbd0a99e1961f5c8d593bd6061049376fad8936e0c835df0f4f6c1decc92952aa4040c4851a78dbb6bdc3d20
|
data/.bashrc
CHANGED
data/README.md
CHANGED
@@ -23,6 +23,13 @@ $ directlink //4.bp.blogspot.com/-5kP8ndL0kuM/Wpt82UCqvmI/AAAAAAAAEjI/ZbbZWs0-kg
|
|
23
23
|
=> https://4.bp.blogspot.com/-5kP8ndL0kuM/Wpt82UCqvmI/AAAAAAAAEjI/ZbbZWs0-kgwRXEJ9JEGioR0bm6U8MOkvQCKgBGAs/s0/IMG_20171223_093922.jpg
|
24
24
|
jpeg 4160x3120
|
25
25
|
```
|
26
|
+
Given the link to a page it tries to find the main image on it.
|
27
|
+
```
|
28
|
+
$ directlink https://plus.google.com/107956229381790410785/posts/Gu9apRHri41
|
29
|
+
<= https://plus.google.com/107956229381790410785/posts/Gu9apRHri41
|
30
|
+
=> https://lh3.googleusercontent.com/-mRDjiHoDA30/W0mndQaRXeI/AAAAAAAAfyA/NhZGMAoQsbAb8cUFDzNWh-NXQ9O-YQhuQCJoC/s0/001
|
31
|
+
jpeg 2000x1328
|
32
|
+
```
|
26
33
|
Retrieves all images from Imgur album or gallery, orders them by resolution from high to low:
|
27
34
|
```
|
28
35
|
$ directlink https://imgur.com/a/oacI3gl
|
@@ -91,7 +98,7 @@ $ export REDDIT_SECRETS=secrets.yaml
|
|
91
98
|
|
92
99
|
#### the "don't give up mode"
|
93
100
|
|
94
|
-
If the passed link is not the image link or a photo page of a known image hosting, the tool is still able to find the main images that the linked webpage contains
|
101
|
+
If the passed link is not the image link or a photo page of a known image hosting, the tool is still able to find the main images that the linked webpage contains. Like in the second example of this README or here -- it found three images in the markdown file:
|
95
102
|
```
|
96
103
|
$ directlink https://github.com/Nakilon/dhash-vips
|
97
104
|
<= https://github.com/Nakilon/dhash-vips
|
@@ -155,10 +162,17 @@ DirectLink "http://minus.com/", 0
|
|
155
162
|
SocketError: Failed to open TCP connection to minus.com:80 (getaddrinfo: nodename nor servname provided, or not known) to http://minus.com/
|
156
163
|
```
|
157
164
|
|
165
|
+
#### Ruby 2.0
|
166
|
+
|
167
|
+
The `addressable` dependency (for proper URI parsing) has a dependency that by default wants Ruby 2.1 or higher. You may fix it safely by adding this line to your `Gemfile`:
|
168
|
+
```
|
169
|
+
gem "jwt", "<2"
|
170
|
+
```
|
171
|
+
|
158
172
|
## Notes:
|
159
173
|
|
160
174
|
* `module DirectLink` public methods return different sets of properties -- `DirectLink()` unites them
|
161
|
-
* the `ErrorAssert` and `
|
175
|
+
* the `ErrorAssert`, `ErrorMissingEnvVar` and `URI::InvalidURIError` should never be raised and you might report it
|
162
176
|
* style: `@@` and lambdas are used to keep things private
|
163
177
|
* this gem is a historically 2 or 3 libraries merged -- this is why tests may look awkward
|
164
178
|
* 500px.com has discontinued API in June 2018 -- the tool now uses undocumented methods
|
@@ -166,3 +180,4 @@ SocketError: Failed to open TCP connection to minus.com:80 (getaddrinfo: nodenam
|
|
166
180
|
|
167
181
|
TODO: maybe make all these web service specific methods private and discourage to use them since they all return very different things and sometimes don't raise exceptions while the `DirectLink()` does
|
168
182
|
TODO: what should `--json` print if exception was thrown?
|
183
|
+
TODO: looped prompt mode
|
data/directlink.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "directlink"
|
3
|
-
spec.version = "0.0.4.
|
3
|
+
spec.version = "0.0.4.4"
|
4
4
|
spec.summary = "converts any kind of image hyperlink to direct link, type of image and its resolution"
|
5
5
|
|
6
6
|
spec.author = "Victor Maslov aka Nakilon"
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.add_dependency "fastimage", "~>2.1.3"
|
13
13
|
spec.add_dependency "nokogiri"
|
14
|
-
spec.add_dependency "reddit_bot", "~>1.6.
|
14
|
+
spec.add_dependency "reddit_bot", "~>1.6.8"
|
15
15
|
spec.add_dependency "kramdown"
|
16
16
|
spec.add_dependency "addressable"
|
17
17
|
spec.add_development_dependency "minitest"
|
data/lib/directlink.rb
CHANGED
@@ -46,25 +46,29 @@ module DirectLink
|
|
46
46
|
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9_-]{11}\/W[a-zA-Z0-9_-]{9}I\/AAAAAAAA[a-zA-Z0-9_]{3}\/[a-zA-Z0-9_-]{32}[gwAQ]CJoC\/)w4\d\d-h318-n(\/[^\/]+)\z/,
|
47
47
|
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9_]{11}\/W[a-zA-Z0-9]{9}I\/AAAAAAAA[a-zA-Z0-9]{3}\/[a-zA-Z0-9_-]{32}[gw]CJoC\/)w48\d-h8\d\d-n(\/[^\/]+)\z/,
|
48
48
|
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9_-]{11}\/W[a-zA-Z0-9_-]{9}I\/AAAAAAA[a-zA-Z0-9_-]{4}\/[a-zA-Z0-9_-]{33}(?:CJoC|CL0B(?:GAs)?)\/)w530(?:-d)?-h[1-9]\d\d-n(\/[^\/]+)\z/,
|
49
|
-
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-
|
50
|
-
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z-]{11}\/W[a-zA-Z-]{9}I\/AAAAAAAA[a-zA-Z]{3}\/[a-zA-Z0-9_-]{32}ACJoC\/)w179-h318-n(\/[^\/]+)\z/,
|
51
|
-
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9-]{11}\/W[a-zA-Z0-9]{9}I\/AAAAAAAAA[A-Z]{2}\/[a-zA-Z0-9]{32}QCJoC\/)w208-h318-n(\/[^\/]+)\z/
|
49
|
+
/\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z-]{11}\/W[a-zA-Z-]{9}I\/AAAAAAAA[a-zA-Z]{3}\/[a-zA-Z0-9_-]{32}ACJoC\/)w179-h318-n(\/[^\/]+)\z/
|
52
50
|
"#{$1}s#{width}#{$2}"
|
53
|
-
when /\A(\/\/lh3\.googleusercontent\.com\/proxy\/[a-zA-Z0-9_-]{66,523}=)(?:w(?:
|
51
|
+
when /\A(\/\/lh3\.googleusercontent\.com\/proxy\/[a-zA-Z0-9_-]{66,523}=)(?:w(?:[45]\d\d)-h\d\d\d-[np]|s530-p|s110-p-k)\z/
|
54
52
|
"https:#{$1}s#{width}"
|
55
53
|
when /\A(\/\/lh3\.googleusercontent\.com\/cOh2Nsv7EGo0QbuoKxoKZVZO_NcBzufuvPtzirMJfPmAzCzMtnEncfA7zGIDTJfkc1YZFX2MhgKnjA=)w530-h398-p\z/
|
56
54
|
"https:#{$1}s#{width}"
|
57
|
-
when /\A(\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9-]{11}\/
|
55
|
+
when /\A(\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9-]{11}\/[VW][a-zA-Z0-9_-]{9}I\/AAAAAAA[AC][a-zA-Z0-9]{3}\/[a-zA-Z0-9_-]{32}[gwAQ]CJoC\/)w530-h3\d\d-p(\/[^\/]+)\z/,
|
56
|
+
/\A(\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9]{11}\/W[a-zA-Z0-9]{9}I\/AAAAAAAA[a-zA-Z0-9]{3}\/[a-zA-Z0-9_]{32}ACJoC\/)w530-h298-p(\/[^\/]+)\z/,
|
58
57
|
/\A(\/\/[124]\.bp\.blogspot\.com\/-[a-zA-Z0-9_-]{11}\/W[npw][a-zA-Z0-9_-]{8}I\/AAAAAAAA[KDE][a-zA-Z0-9_-]{2}\/[a-zA-Z0-9_-]{33}C(?:Lc|Kg)BGAs\/)w530-h[23]\d\d-p(\/[^\/]+)\z/,
|
59
|
-
/\A(\/\/[2]\.bp\.blogspot\.com\/-[a-zA-Z-]{11}\/W[a-zA-Z0-9]{8}_I\/AAAAAAAAHDs\/[a-zA-Z0-9-]{33}CEwYBhgL\/)w530-h353-p(\/[^\/]+)\z
|
58
|
+
/\A(\/\/[2]\.bp\.blogspot\.com\/-[a-zA-Z-]{11}\/W[a-zA-Z0-9]{8}_I\/AAAAAAAAHDs\/[a-zA-Z0-9-]{33}CEwYBhgL\/)w530-h353-p(\/[^\/]+)\z/,
|
59
|
+
/\A(\/\/4\.bp\.blogspot\.com\/-[a-zA-Z0-9-]{11}\/W[a-zA-Z0-9]{9}I\/AAAAAAAAHHg\/[a-zA-Z0-9-]{33}CLcBGAs\/)w530-h353-p(\/[^\/]+)\z/
|
60
60
|
"https:#{$1}s#{width}#{$2}"
|
61
61
|
when /\A(https:\/\/lh3\.googleusercontent\.com\/-dUQsDY2vWuE\/AAAAAAAAAAI\/AAAAAAAAAAQ\/wVFZagieszU\/)w530-h176-n(\/photo\.jpg)\z/,
|
62
|
-
/\A(https:\/\/lh3\.googleusercontent\.com\/-t_ab__91ChA\/VeLaObkUlgI\/AAAAAAAAL4s\/VjO6KK_lkRw\/)w530-h351-n(\/[^\/]+)\z
|
62
|
+
/\A(https:\/\/lh3\.googleusercontent\.com\/-t_ab__91ChA\/VeLaObkUlgI\/AAAAAAAAL4s\/VjO6KK_lkRw\/)w530-h351-n(\/[^\/]+)\z/,
|
63
|
+
/\A(https:\/\/lh3\.googleusercontent\.com\/-s655sojwyvw\/VcNB4YMCz-I\/AAAAAAAALqo\/kW98MOcJJ0g\/)w530-h398-n\/06\.08\.15%2B-%2B1\z/,
|
64
|
+
/\A(https:\/\/lh3\.googleusercontent\.com\/-u3FhiUTmLCY\/Vk7dMQnxR2I\/AAAAAAAAMc0\/I76_52swA4s\/)w530-h322-n\/Harekosh_A%252520Concert_YkRqQg\.jpg\z/,
|
65
|
+
/\A(https:\/\/lh3\.googleusercontent\.com\/-t_ab__91ChA\/VeLaObkUlgI\/AAAAAAAAL4s\/VjO6KK_lkRw\/)w530-d-h351-n\/30\.08\.15%2B-%2B1\z/
|
63
66
|
"#{$1}s#{width}#{$2}"
|
64
67
|
# high res (s0) Google Plus post image
|
65
68
|
when /\Ahttps:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9_-]{11}\/W[a-zA-Z0-9_-]{9}I\/AAAAAAA[ABC][a-zA-Z0-9]{3}\/[a-zA-Z0-9_-]{33}CJoC\/s0\/[^\/]+\z/,
|
66
69
|
/\Ahttps:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9]{11}\/W[a-zA-Z0-9]{9}I\/AAAAAAAA[a-zA-Z_]{3}\/[a-zA-Z0-9]{32}gCJoC\/s0\/[^\/]+\z/,
|
67
|
-
/\Ahttps:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9]{11}\/[a-zA-Z0-9]{10}I\/AAAAAAA[a-zA-
|
70
|
+
/\Ahttps:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9]{11}\/[a-zA-Z0-9]{10}I\/AAAAAAA[a-zA-Z0-9]{4}\/[a-zA-Z0-9_-]{32}wCJoC\/s0\/[^\/]+\z/,
|
71
|
+
/\Ahttps:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9]{11}\/[a-zA-Z0-9]{10}I\/AAAAAAA[A-Z]{4}\/[a-zA-Z0-9-]{32}gCJoC\/s0\/[^\/]+\z/
|
68
72
|
src
|
69
73
|
# Google Plus userpic
|
70
74
|
when /\A(https:\/\/lh3\.googleusercontent\.com\/-[a-zA-Z0-9-]{11}\/AAAAAAAAAAI\/AAAAAAAA[a-zA-Z0-9]{3}\/[a-zA-Z0-9_-]{11}\/)s\d\d-p(?:-k)?-rw-no(\/photo\.jpg)\z/
|
@@ -90,24 +94,25 @@ module DirectLink
|
|
90
94
|
def self.imgur link, timeout = 1000
|
91
95
|
raise ErrorMissingEnvVar.new "define IMGUR_CLIENT_ID env var" unless ENV["IMGUR_CLIENT_ID"]
|
92
96
|
|
93
|
-
|
94
|
-
when /\Ahttps?:\/\/(?:(?:i|m|www)\.)?imgur\.com\/(a|gallery)\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\z/,
|
95
|
-
/\Ahttps?:\/\/imgur\.com\/(gallery)\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\/new\z/
|
97
|
+
request_data = lambda do |url|
|
96
98
|
t = 1
|
97
|
-
|
98
|
-
NetHTTPUtils.request_data "
|
99
|
-
$1 == "gallery" ? "gallery" : "album"
|
100
|
-
}/#{$2}/0.json", header: { Authorization: "Client-ID #{ENV["IMGUR_CLIENT_ID"]}" }
|
99
|
+
begin
|
100
|
+
NetHTTPUtils.request_data url, header: { Authorization: "Client-ID #{ENV["IMGUR_CLIENT_ID"]}" }
|
101
101
|
rescue NetHTTPUtils::Error => e
|
102
|
-
if
|
103
|
-
|
102
|
+
raise ErrorNotFound.new url.inspect if 404 == e.code
|
103
|
+
if t < timeout && [400, 500, 503].include?(e.code)
|
104
|
+
logger.error "retrying in #{t} seconds because of Imgur HTTP ERROR #{e.code}"
|
104
105
|
sleep t
|
105
106
|
t *= 2
|
106
107
|
retry
|
107
108
|
end
|
108
|
-
raise
|
109
|
-
raise ErrorAssert.new "unexpected http error for #{link}"
|
109
|
+
raise ErrorAssert.new "unexpected http error for #{url}"
|
110
110
|
end
|
111
|
+
end
|
112
|
+
case link
|
113
|
+
when /\Ahttps?:\/\/(?:(?:i|m|www)\.)?imgur\.com\/(a|gallery)\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\z/,
|
114
|
+
/\Ahttps?:\/\/imgur\.com\/(gallery)\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\/new\z/
|
115
|
+
json = request_data["https://api.imgur.com/3/#{$1 == "gallery" ? "gallery" : "album"}/#{$2}/0.json"]
|
111
116
|
data = JSON.load(json)["data"]
|
112
117
|
if data["error"]
|
113
118
|
raise ErrorAssert.new "unexpected error #{data.inspect} for #{link}"
|
@@ -128,19 +133,7 @@ module DirectLink
|
|
128
133
|
/\Ahttps?:\/\/imgur\.com\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\z/,
|
129
134
|
/\Ahttps?:\/\/imgur\.com\/([a-zA-Z0-9]{7})(?:\?\S+)?\z/,
|
130
135
|
/\Ahttps?:\/\/imgur\.com\/r\/[0-9_a-z]+\/([a-zA-Z0-9]{7})\z/
|
131
|
-
|
132
|
-
json = begin
|
133
|
-
NetHTTPUtils.request_data "https://api.imgur.com/3/image/#{$1}/0.json", header: { Authorization: "Client-ID #{ENV["IMGUR_CLIENT_ID"]}" }
|
134
|
-
rescue NetHTTPUtils::Error => e
|
135
|
-
raise ErrorNotFound.new link.inspect if e.code == 404
|
136
|
-
if t < timeout && [400, 500].include?(e.code)
|
137
|
-
logger.error "retrying in #{t} seconds because of Imgur HTTP ERROR #{e.code}"
|
138
|
-
sleep t
|
139
|
-
t *= 2
|
140
|
-
retry
|
141
|
-
end
|
142
|
-
raise ErrorAssert.new "unexpected http error for #{link}"
|
143
|
-
end
|
136
|
+
json = request_data["https://api.imgur.com/3/image/#{$1}/0.json"]
|
144
137
|
[ JSON.load(json)["data"] ]
|
145
138
|
else
|
146
139
|
raise ErrorBadLink.new link
|
@@ -202,29 +195,48 @@ module DirectLink
|
|
202
195
|
class << self
|
203
196
|
attr_accessor :reddit_bot
|
204
197
|
end
|
205
|
-
def self.reddit link
|
198
|
+
def self.reddit link, timeout = 1000
|
206
199
|
unless id = URI(link).path[/\A(?:\/r\/[0-9a-zA-Z_]+)?(?:\/comments)?\/([0-9a-z]{5,6})(?:\/|\z)/, 1]
|
207
200
|
raise DirectLink::ErrorBadLink.new link unless URI(link).host &&
|
208
201
|
URI(link).host.split(?.) == %w{ i redd it } &&
|
209
202
|
URI(link).path[/\A\/[a-z0-9]{12,13}\.(gif|jpg)\z/]
|
210
203
|
return [true, link]
|
211
204
|
end
|
212
|
-
|
205
|
+
retry_on_json_parseerror = lambda do |&b|
|
206
|
+
t = 1
|
207
|
+
begin
|
208
|
+
b.call
|
209
|
+
rescue JSON::ParserError => e
|
210
|
+
raise ErrorBadLink.new link if t > timeout
|
211
|
+
logger.error "#{e.message[0, 500].gsub(/\s+/, " ")}, retrying in #{t} seconds"
|
212
|
+
sleep t
|
213
|
+
t *= 2
|
214
|
+
retry
|
215
|
+
end
|
216
|
+
end
|
217
|
+
json = if ENV["REDDIT_SECRETS"]
|
213
218
|
require "reddit_bot"
|
214
219
|
RedditBot.logger.level = Logger::FATAL
|
215
220
|
require "yaml"
|
216
|
-
reddit_bot ||= RedditBot::Bot.new YAML.load_file ENV["REDDIT_SECRETS"]
|
217
|
-
|
221
|
+
self.reddit_bot ||= RedditBot::Bot.new YAML.load_file ENV["REDDIT_SECRETS"]
|
222
|
+
retry_on_json_parseerror.call{ self.reddit_bot.json :get, "/by_id/t3_#{id}" }
|
218
223
|
else
|
219
224
|
raise ErrorMissingEnvVar.new "defining REDDIT_SECRETS env var is highly recommended" rescue nil
|
220
|
-
json = JSON.load NetHTTPUtils.request_data "
|
225
|
+
json = retry_on_json_parseerror.call{ JSON.load NetHTTPUtils.request_data "https://www.reddit.com/#{id}.json", header: {"User-Agent" => "Mozilla"} }
|
221
226
|
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" unless json.size == 2
|
222
|
-
json
|
227
|
+
json.find{ |_| _["data"]["children"].first["kind"] == "t3" }
|
223
228
|
end
|
224
229
|
data = json["data"]["children"].first["data"]
|
225
|
-
|
226
|
-
|
227
|
-
|
230
|
+
if data["media"]["reddit_video"]
|
231
|
+
t = data["preview"]["images"]
|
232
|
+
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" unless t.size == 1
|
233
|
+
return [true, t.first["source"]["url"]]
|
234
|
+
else
|
235
|
+
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" unless data["media"].keys.sort == %w{ oembed type } && data["media"]["type"] == "youtube.com"
|
236
|
+
return [true, data["media"]["oembed"]["thumbnail_url"]]
|
237
|
+
end if data["media"]
|
238
|
+
return [true, data["url"]] unless data["is_self"]
|
239
|
+
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" if data["url"] != "https://www.reddit.com" + data["permalink"]
|
228
240
|
return [false, data["selftext"]]
|
229
241
|
end
|
230
242
|
|
@@ -312,16 +324,17 @@ def DirectLink link, max_redirect_resolving_retry_delay = nil, giveup = false
|
|
312
324
|
|
313
325
|
begin
|
314
326
|
s, u = DirectLink.reddit(link)
|
315
|
-
|
316
|
-
|
327
|
+
unless s
|
328
|
+
raise DirectLink::ErrorBadLink.new link if giveup # TODO: print original url in such cases if there was a recursion
|
329
|
+
f = ->_{ _.type == :a ? _.attr["href"] : _.children.flat_map(&f) }
|
330
|
+
require "kramdown"
|
331
|
+
return f[Kramdown::Document.new(u).root].map{ |_| DirectLink _, max_redirect_resolving_retry_delay, giveup }
|
317
332
|
end
|
318
|
-
|
319
|
-
|
320
|
-
require "kramdown"
|
321
|
-
return f[Kramdown::Document.new(u).root].map{ |_| DirectLink _, max_redirect_resolving_retry_delay, giveup }
|
333
|
+
return struct.new *u.values_at(*%w{ fallback_url width height }), "video" if u.is_a? Hash
|
334
|
+
link = u
|
322
335
|
rescue DirectLink::ErrorMissingEnvVar
|
323
336
|
end if %w{ reddit com } == URI(link).host.split(?.).last(2) ||
|
324
|
-
%w{ redd it } == URI(link).host.split(?.)
|
337
|
+
%w{ redd it } == URI(link).host.split(?.)
|
325
338
|
|
326
339
|
|
327
340
|
begin
|
data/test.rb
CHANGED
@@ -113,6 +113,18 @@ describe DirectLink do
|
|
113
113
|
assert DirectLink.google link
|
114
114
|
end
|
115
115
|
end
|
116
|
+
%w{
|
117
|
+
https://lh3.googleusercontent.com/-s655sojwyvw/VcNB4YMCz-I/AAAAAAAALqo/kW98MOcJJ0g/w530-h398-n/06.08.15%2B-%2B1
|
118
|
+
//4.bp.blogspot.com/-TuMlpg-Q1YY/W3PXkW1lkaI/AAAAAAAAHHg/Bh9IsuLV01kbctIu6lcRJHKkY-ej8oD5gCLcBGAs/w530-h353-p/_MG_2688-Edit.jpg
|
119
|
+
//lh3.googleusercontent.com/proxy/SEfB6tFuim6X0HdZfEBSxrXtumUdf4Q4y05rUW4wc_clWWVrowuWAGZghx71xwPUmf_8si2VQwnRivsM7PfD2gp3kA=w480-h360-n
|
120
|
+
https://lh3.googleusercontent.com/-u3FhiUTmLCY/Vk7dMQnxR2I/AAAAAAAAMc0/I76_52swA4s/w530-h322-n/Harekosh_A%252520Concert_YkRqQg.jpg
|
121
|
+
https://lh3.googleusercontent.com/-t_ab__91ChA/VeLaObkUlgI/AAAAAAAAL4s/VjO6KK_lkRw/w530-d-h351-n/30.08.15%2B-%2B1
|
122
|
+
//lh3.googleusercontent.com/-u2NzdIQfVyQ/Wy83AzoFT8I/AAAAAAAAh6M/fdpxOUkj5mUIfpvYol_R5dyupnF2nDIEACJoC/w530-h298-p/_DSC9134.jpg
|
123
|
+
}.each_with_index do |link, i| # July contenstants
|
124
|
+
it "another (July) Google Plus community post image ##{i + 1}" do
|
125
|
+
assert DirectLink.google link
|
126
|
+
end
|
127
|
+
end
|
116
128
|
%w{
|
117
129
|
https://lh3.googleusercontent.com/-f37xWyiyP8U/WvmxOxCd-0I/AAAAAAAACpw/3A2tRj02oY40MzJqZBJyWGImoSer0lwMgCJoC/s0/140809%2B029.jpg
|
118
130
|
https://lh3.googleusercontent.com/-1s_eiQB4x2k/WvXQEx59z2I/AAAAAAAAcI0/DvKYzWw3g6UNelqAQdOwrdtYdSEqKgkxwCJoC/s0/001
|
@@ -131,6 +143,8 @@ describe DirectLink do
|
|
131
143
|
https://lh3.googleusercontent.com/-aUVoiLNsmAg/WzcsUU2xfNI/AAAAAAAAODw/DOBual6E1rkVLHh3SKZSzbpNQzdEoZPOQCJoC/w530-h883-n-k-no/gplus-1797734754.mp4
|
132
144
|
//lh3.googleusercontent.com/proxy/hOIoIpMEmoVDSP40VRzM92Zw2AeLvEEhxfyKHCOxiNVPyiGvZik5rMvl3jYISLgDJla6mhZuk8pFEYJhX5BU2wy_dw=w530-h822-p
|
133
145
|
https://lh3.googleusercontent.com/-GP3BA3zGR5A/W0IwuVXlfmI/AAAAAAADROs/SH8rRlBDYTsHZiHpM45S3zpEipu5hJ2PwCJoC/s0/%25D1%2582%25D0%25B0%25D0%25B4%25D0%25B6%25D0%25B8%25D0%25BA%25D1%2581%25D0%25BA%25D0%25BE%25D0%25B5%2B%25D1%2580%25D0%25B0%25D0%25B7%25D0%25BD%25D0%25BE%25D1%2582%25D1%2580%25D0%25B0%25D0%25B2%25D1%258C%25D0%25B5.png
|
146
|
+
https://lh3.googleusercontent.com/-DLODAbD9W7E/W27ob5XGCOI/AAAAAAADV8g/J_6RYR6UkKsc2RJOWRx6Q-NBVx5RbMoxwCJoC/s0/1236080.jpg
|
147
|
+
https://lh3.googleusercontent.com/-cJajRreI87w/W4gW5uF4Q7I/AAAAAAADZKI/mw1YayYE-MY2-1OCCmjvgM3kbCK0lmIggCJoC/s0/2504855.jpg
|
134
148
|
}.each_with_index do |link, i|
|
135
149
|
it "gpluscomm_105636351696833883213_86400 ##{i + 1}" do
|
136
150
|
assert DirectLink.google link
|
@@ -187,21 +201,27 @@ describe DirectLink do
|
|
187
201
|
assert_nil e.cause if Exception.instance_methods.include? :cause # Ruby 2.1
|
188
202
|
end
|
189
203
|
|
190
|
-
|
204
|
+
valid_imgur_image_url_direct = "https://i.imgur.com/BLCesav.jpg"
|
191
205
|
it 200 do
|
192
206
|
assert_equal [["https://i.imgur.com/BLCesav.jpg", 1000, 1500, "image/jpeg"]],
|
193
|
-
DirectLink.imgur(
|
194
|
-
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
207
|
+
DirectLink.imgur(valid_imgur_image_url_direct)
|
208
|
+
end
|
209
|
+
valid_imgur_image_url_album = "https://imgur.com/a/wPi63mj"
|
210
|
+
[400, 500, 503].each do |error_code|
|
211
|
+
[
|
212
|
+
[valid_imgur_image_url_direct, :direct],
|
213
|
+
[valid_imgur_image_url_album, :album],
|
214
|
+
].each do |url, kind|
|
215
|
+
it "retries limited amout of times on error #{error_code} (#{kind})" do
|
216
|
+
tries = 0
|
217
|
+
e = assert_raises DirectLink::ErrorAssert do
|
218
|
+
NetHTTPUtils.stub :request_data, ->*{ tries += 1; raise NetHTTPUtils::Error.new "", error_code } do
|
219
|
+
DirectLink.imgur url, 4 # do not remove `4` or test will hang
|
220
|
+
end
|
201
221
|
end
|
222
|
+
assert_equal error_code, e.cause.code if Exception.instance_methods.include? :cause # Ruby 2.1
|
223
|
+
assert_equal 3, tries
|
202
224
|
end
|
203
|
-
assert_equal error_code, e.cause.code if Exception.instance_methods.include? :cause # Ruby 2.1
|
204
|
-
assert_equal 3, tries
|
205
225
|
end
|
206
226
|
end
|
207
227
|
it "does not throw 400 after a successfull retry" do
|
@@ -213,13 +233,13 @@ describe DirectLink do
|
|
213
233
|
m.call *args
|
214
234
|
} do
|
215
235
|
assert_equal [["https://i.imgur.com/BLCesav.jpg", 1000, 1500, "image/jpeg"]],
|
216
|
-
DirectLink.imgur(
|
236
|
+
DirectLink.imgur(valid_imgur_image_url_direct, 4) # do not remove `4` or test may hang
|
217
237
|
end
|
218
238
|
end
|
219
239
|
it 404 do
|
220
240
|
e = assert_raises DirectLink::ErrorNotFound do
|
221
241
|
NetHTTPUtils.stub :request_data, ->*{ raise NetHTTPUtils::Error.new "", 404 } do
|
222
|
-
DirectLink.imgur
|
242
|
+
DirectLink.imgur valid_imgur_image_url_direct
|
223
243
|
end
|
224
244
|
end
|
225
245
|
assert_equal 404, e.cause.code if Exception.instance_methods.include? :cause # Ruby 2.1
|
@@ -314,7 +334,7 @@ describe DirectLink do
|
|
314
334
|
["http://redd.it/32tq0i", [true, "http://i.imgur.com/vy6Ms4Z.jpg"]], # TODO maybe check that it calls #imgur recursively
|
315
335
|
["https://i.redd.it/c8rk0kjywhy01.jpg", [true, "https://i.redd.it/c8rk0kjywhy01.jpg"]],
|
316
336
|
["https://i.redd.it/si758zk7r5xz.jpg", [true, "https://i.redd.it/si758zk7r5xz.jpg"]], # it is 404 but `.reddit` does not care -- it just returns the url
|
317
|
-
["https://reddit.com/123456", [true, "
|
337
|
+
["https://reddit.com/123456", [true, "https://i.ytimg.com/vi/b9upM4RbIeU/hqdefault.jpg"]],
|
318
338
|
["https://www.reddit.com/r/travel/988889", [true, "https://i.redd.it/3h5xls6ehrg11.jpg"]],
|
319
339
|
["http://redd.it/988889", [true, "https://i.redd.it/3h5xls6ehrg11.jpg"]],
|
320
340
|
] ],
|
@@ -381,6 +401,46 @@ describe DirectLink do
|
|
381
401
|
end
|
382
402
|
end
|
383
403
|
|
404
|
+
# TODO: make a Reddit describe
|
405
|
+
it "retries limited amout of times on error JSON::ParserError" do
|
406
|
+
link = "https://www.reddit.com/r/gifs/comments/9ftc8f/low_pass_wake_vortices/?st=JM2JIKII&sh=c00fea4f"
|
407
|
+
tries = 0
|
408
|
+
m = NetHTTPUtils.method :request_data
|
409
|
+
e = assert_raises DirectLink::ErrorBadLink do
|
410
|
+
NetHTTPUtils.stub :request_data, lambda{ |*args|
|
411
|
+
if args.first == "https://www.reddit.com/9ftc8f.json"
|
412
|
+
tries += 1
|
413
|
+
raise JSON::ParserError
|
414
|
+
end
|
415
|
+
m.call *args
|
416
|
+
} do
|
417
|
+
t = ENV.delete "REDDIT_SECRETS"
|
418
|
+
begin
|
419
|
+
DirectLink.reddit link, 3 # do not remove `4` or test will hang
|
420
|
+
ensure
|
421
|
+
ENV["REDDIT_SECRETS"] = t
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
assert_instance_of JSON::ParserError, e.cause if Exception.instance_methods.include? :cause # Ruby 2.1
|
426
|
+
assert_equal 3, tries
|
427
|
+
end
|
428
|
+
it "Reddit correctly parses out id when no token provided" do
|
429
|
+
t = ENV.delete "REDDIT_SECRETS"
|
430
|
+
begin
|
431
|
+
assert_equal "https://i.redditmedia.com/-WnE-3o4RhKx6ImGD69vJYAo7UjMn5b4ClHHISJ0_Kk.png?s=fc3e2f2f9973c45daa759a45a75557bf",
|
432
|
+
DirectLink("https://www.reddit.com/r/gifs/comments/9ftc8f/low_pass_wake_vortices/?st=JM2JIKII&sh=c00fea4f").url
|
433
|
+
ensure
|
434
|
+
ENV["REDDIT_SECRETS"] = t
|
435
|
+
end
|
436
|
+
end
|
437
|
+
it "it is really impossible to get dimensions from the shitty Reddit media hosting" do
|
438
|
+
# TODO: why does it call the same Net::HTTP::Get twice?
|
439
|
+
assert_raises FastImage::UnknownImageType do
|
440
|
+
DirectLink "https://v.redd.it/2tyovczka8m11/DASH_4_8_M"
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
384
444
|
describe "throws ErrorBadLink if method does not match the link" do
|
385
445
|
%i{ google imgur flickr _500px wiki reddit }.each do |method|
|
386
446
|
["", "test", "http://example.com/"].each_with_index do |url, i|
|
@@ -393,10 +453,54 @@ describe DirectLink do
|
|
393
453
|
end
|
394
454
|
end
|
395
455
|
|
456
|
+
# TODO: test each webservice-specific method
|
457
|
+
# TODO: check not in OpenSSL but higher -- in Net::HTTP
|
458
|
+
it "does not cause the SystemStackError" do
|
459
|
+
OpenSSL::Buffering.module_eval do
|
460
|
+
old = instance_method :write
|
461
|
+
depths = []
|
462
|
+
define_method :write do |arg|
|
463
|
+
depths.push caller.size
|
464
|
+
raise "probable infinite recursion" if [1]*10 == depths.each_cons(2).map{ |i,j| j-i } if depths.size > 10
|
465
|
+
old.bind(self).(arg)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
DirectLink "https://i.redd.it/gdo0cnmeagx01.jpg"
|
469
|
+
end
|
470
|
+
|
396
471
|
end
|
397
472
|
|
398
473
|
describe "DirectLink()" do
|
399
474
|
|
475
|
+
it "does not raise JSON::ParserError -- Reddit sucks and may respond with wrong content type" do
|
476
|
+
DirectLink.reddit "https://www.reddit.com/123456" # just to initialize DirectLink.reddit_bot
|
477
|
+
# I don't remember for what though
|
478
|
+
# oh, maybe to avoid rasing in initializer
|
479
|
+
# but why not?
|
480
|
+
limit = 0
|
481
|
+
loop do
|
482
|
+
limit += 1
|
483
|
+
tries = 0
|
484
|
+
m = JSON.method :load
|
485
|
+
JSON.stub :load, ->*args{
|
486
|
+
if limit == tries += 1
|
487
|
+
raise JSON::ParserError
|
488
|
+
else
|
489
|
+
m.call *args
|
490
|
+
end
|
491
|
+
} do
|
492
|
+
t = ENV.delete "REDDIT_SECRETS"
|
493
|
+
begin
|
494
|
+
p DirectLink.reddit "https://www.reddit.com/123456"
|
495
|
+
ensure
|
496
|
+
ENV["REDDIT_SECRETS"] = t
|
497
|
+
end
|
498
|
+
end
|
499
|
+
break if 1 == tries
|
500
|
+
end
|
501
|
+
assert_equal 2, limit, "`JSON.load` was called only once?!"
|
502
|
+
end
|
503
|
+
|
400
504
|
# thanks to gem addressable
|
401
505
|
it "does not throw URI::InvalidURIError if there are brackets" do
|
402
506
|
assert_equal 404, (
|
@@ -480,8 +584,6 @@ describe DirectLink do
|
|
480
584
|
["https://github.com/Nakilon/dhash-vips", 3],
|
481
585
|
["http://imgur.com/HQHBBBD", FastImage::UnknownImageType, true],
|
482
586
|
["http://imgur.com/HQHBBBD", "https://i.imgur.com/HQHBBBD.jpg?fb"], # .at_css("meta[@property='og:image']")
|
483
|
-
["http://redd.it/123456", FastImage::UnknownImageType, true],
|
484
|
-
["http://redd.it/123456", 1],
|
485
587
|
["http://redd.it/997he7", DirectLink::ErrorBadLink, true],
|
486
588
|
["http://redd.it/997he7", 1], # currently only links are parsed
|
487
589
|
].each_with_index do |(input, expectation, giveup), i|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: directlink
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.4.
|
4
|
+
version: 0.0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Maslov aka Nakilon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastimage
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.6.
|
47
|
+
version: 1.6.8
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.6.
|
54
|
+
version: 1.6.8
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: kramdown
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|