directlink 0.0.9.1 → 0.0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/directlink +1 -10
- data/directlink.gemspec +6 -7
- data/lib/directlink.rb +48 -32
- data/test.rb +81 -35
- metadata +8 -31
- data/.bashrc +0 -5
- data/.travis.yml +0 -39
- data/Gemfile +0 -3
- data/README.md +0 -198
- data/Rakefile +0 -1
- data/api_tokens_for_travis.sh +0 -8
- data/gplus.txt +0 -1454
- data/reddit_token_for_travis.yaml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f745bed3faf2b74dfe4532357fbb772fe32598b1
|
4
|
+
data.tar.gz: 203127452f8e51be364fff16a4c1eafa8a0a21df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75bd9d5351c48c4f1df45b76f4835abc52bd057eabd01f4615a2056c16f4f9cf57546c3ff7123f479836206d1bb3164a740bebd2d81b84899b5507ee74d0e178
|
7
|
+
data.tar.gz: 6e20c47d7270b6bf3b0920ea964337b5143e255eb789baac70823218c9b689b13a6b16abdc729a3c134a2b5cf48fccfa074ec64bebac6ed835a32764b8f5726c
|
data/bin/directlink
CHANGED
@@ -68,16 +68,7 @@ begin
|
|
68
68
|
(t.is_a?(Array) ? t : [t]).each{ |s| puts "=> #{s.url}\n #{s.type} #{s.width}x#{s.height}" }
|
69
69
|
end
|
70
70
|
end
|
71
|
-
rescue
|
72
|
-
Net::OpenTimeout,
|
73
|
-
Errno::ECONNRESET,
|
74
|
-
NetHTTPUtils::Error,
|
75
|
-
FastImage::UnknownImageType,
|
76
|
-
FastImage::ImageFetchFailure,
|
77
|
-
# DirectLink::ErrorMissingEnvVar,
|
78
|
-
# DirectLink::ErrorAssert,
|
79
|
-
DirectLink::ErrorNotFound,
|
80
|
-
DirectLink::ErrorBadLink => e
|
71
|
+
rescue *DirectLink::NORMAL_EXCEPTIONS => e
|
81
72
|
puts e.backtrace if debug
|
82
73
|
cause = e.cause if e.cause if e.respond_to? :cause
|
83
74
|
c = e.class.to_s
|
data/directlink.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "directlink"
|
3
|
-
spec.version = "0.0.9.
|
4
|
-
spec.summary = "
|
3
|
+
spec.version = "0.0.9.2"
|
4
|
+
spec.summary = "obtains from any kind of hyperlink a link to an image, its format and resolution"
|
5
5
|
|
6
6
|
spec.author = "Victor Maslov aka Nakilon"
|
7
7
|
spec.email = "nakilon@gmail.com"
|
@@ -11,19 +11,18 @@ 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 "nethttputils", "~>0.4.
|
15
|
-
spec.add_dependency "reddit_bot", "~>1.7.
|
14
|
+
spec.add_dependency "nethttputils", "~>0.4.1.0"
|
15
|
+
spec.add_dependency "reddit_bot", "~>1.7.8"
|
16
16
|
spec.add_dependency "kramdown"
|
17
17
|
spec.add_dependency "addressable"
|
18
18
|
spec.add_development_dependency "minitest"
|
19
|
-
spec.add_development_dependency "byebug"
|
20
19
|
|
21
20
|
spec.require_path = "lib"
|
22
21
|
spec.bindir = "bin"
|
23
22
|
spec.executable = "directlink"
|
24
23
|
spec.test_file = "test.rb"
|
25
|
-
spec.files =
|
24
|
+
spec.files = %w{ LICENSE directlink.gemspec lib/directlink.rb bin/directlink }
|
26
25
|
|
27
|
-
spec.requirements << "you may
|
26
|
+
spec.requirements << "you may want to create apps and provide API tokens:"
|
28
27
|
spec.requirements << "IMGUR_CLIENT_ID, FLICKR_API_KEY, REDDIT_SECRETS"
|
29
28
|
end
|
data/lib/directlink.rb
CHANGED
@@ -2,11 +2,10 @@ module DirectLink
|
|
2
2
|
|
3
3
|
class << self
|
4
4
|
attr_accessor :silent
|
5
|
-
end
|
6
|
-
self.silent = false
|
7
|
-
class << self
|
8
5
|
attr_accessor :logger
|
6
|
+
attr_accessor :timeout
|
9
7
|
end
|
8
|
+
self.silent = false
|
10
9
|
self.logger = Object.new
|
11
10
|
self.logger.define_singleton_method :error do |str|
|
12
11
|
puts str unless Module.nesting.first.silent
|
@@ -35,6 +34,20 @@ module DirectLink
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
37
|
+
require "nethttputils"
|
38
|
+
require "fastimage"
|
39
|
+
NORMAL_EXCEPTIONS = [
|
40
|
+
SocketError,
|
41
|
+
Net::OpenTimeout,
|
42
|
+
Errno::ECONNRESET,
|
43
|
+
NetHTTPUtils::Error,
|
44
|
+
NetHTTPUtils::EOFError_from_rbuf_fill,
|
45
|
+
FastImage::UnknownImageType,
|
46
|
+
FastImage::ImageFetchFailure,
|
47
|
+
DirectLink::ErrorNotFound,
|
48
|
+
DirectLink::ErrorBadLink,
|
49
|
+
] # the only exceptions gem user should expect and handle
|
50
|
+
|
38
51
|
|
39
52
|
def self.google src, width = 0
|
40
53
|
# this can handle links without schema because it's used for parsing community HTML pages
|
@@ -76,10 +89,9 @@ module DirectLink
|
|
76
89
|
end
|
77
90
|
|
78
91
|
require "json"
|
79
|
-
require "nethttputils"
|
80
92
|
|
81
93
|
# TODO make the timeout handling respect the way the Directlink method works with timeouts
|
82
|
-
def self.imgur link, timeout =
|
94
|
+
def self.imgur link, timeout = 2000
|
83
95
|
raise ErrorMissingEnvVar.new "define IMGUR_CLIENT_ID env var" unless ENV["IMGUR_CLIENT_ID"]
|
84
96
|
|
85
97
|
request_data = lambda do |url|
|
@@ -107,16 +119,16 @@ module DirectLink
|
|
107
119
|
elsif data["images"]
|
108
120
|
raise ErrorNotFound.new link.inspect if data["images"].empty?
|
109
121
|
data["images"]
|
110
|
-
elsif data["type"] && data["type"]
|
122
|
+
elsif data["type"] && %w{ image/jpeg image/png image/gif video/mp4 }.include?(data["type"])
|
111
123
|
# TODO check if this branch is possible at all
|
112
124
|
[ data ]
|
113
125
|
# elsif data["comment"]
|
114
126
|
# fi["https://imgur.com/" + data["image_id"]]
|
115
127
|
else
|
116
128
|
# one day single-video item should hit this but somehow it didn't yet
|
117
|
-
raise ErrorAssert.new "unknown data format #{
|
129
|
+
raise ErrorAssert.new "unknown data format #{json} for #{link}"
|
118
130
|
end
|
119
|
-
when /\Ahttps?:\/\/(?:(?:i|m|www)\.)?imgur\.com\/([a-zA-Z0-9]{7,8})(?:\.(?:gifv|
|
131
|
+
when /\Ahttps?:\/\/(?:(?:i|m|www)\.)?imgur\.com\/([a-zA-Z0-9]{7,8})(?:\.(?:gifv|jpe?g(?:\?fb)?|png))?\z/,
|
120
132
|
/\Ahttps?:\/\/(?:(?:i|m|www)\.)?imgur\.com\/([a-zA-Z0-9]{5})\.mp4\z/,
|
121
133
|
/\Ahttps?:\/\/imgur\.com\/([a-zA-Z0-9]{5}(?:[a-zA-Z0-9]{2})?)\z/,
|
122
134
|
/\Ahttps?:\/\/imgur\.com\/([a-zA-Z0-9]{7})(?:\?\S+)?\z/,
|
@@ -128,7 +140,7 @@ module DirectLink
|
|
128
140
|
raise ErrorBadLink.new link
|
129
141
|
end.map do |image|
|
130
142
|
case image["type"]
|
131
|
-
when
|
143
|
+
when *%w{ image/jpeg image/png image/gif video/mp4 }
|
132
144
|
image.values_at "link", "width", "height", "type"
|
133
145
|
else
|
134
146
|
raise ErrorAssert.new "unknown type of #{link}: #{image}"
|
@@ -191,11 +203,11 @@ module DirectLink
|
|
191
203
|
attr_accessor :reddit_bot
|
192
204
|
end
|
193
205
|
def self.reddit link, timeout = 1000
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
206
|
+
return [true, link] if URI(link).host &&
|
207
|
+
URI(link).host.split(?.) == %w{ i redd it } &&
|
208
|
+
URI(link).path[/\A\/[a-z0-9]{12,13}\.(gif|jpg)\z/]
|
209
|
+
unless id = link[/\Ahttps:\/\/www\.reddit\.com\/gallery\/([0-9a-z]{5,6})\z/, 1]
|
210
|
+
raise DirectLink::ErrorBadLink.new link unless id = URI(link).path[/\A(?:\/r\/[0-9a-zA-Z_]+)?(?:\/comments|\/duplicates)?\/([0-9a-z]{5,6})(?:\/|\z)/, 1]
|
199
211
|
end
|
200
212
|
retry_on_json_parseerror = lambda do |&b|
|
201
213
|
t = 1
|
@@ -223,16 +235,17 @@ module DirectLink
|
|
223
235
|
end
|
224
236
|
# TODO: do we handle linking Imgur albums?
|
225
237
|
data = json["data"]["children"].first["data"]
|
226
|
-
if data["media"]
|
227
|
-
return [true, data["media"]["reddit_video"]["fallback_url"]]
|
228
|
-
else
|
238
|
+
if data["media"]
|
239
|
+
return [true, data["media"]["reddit_video"]["fallback_url"]] if data["media"]["reddit_video"]
|
229
240
|
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" unless data["media"].keys.sort == %w{ oembed type } && %w{ youtube.com gfycat.com imgur.com }.include?(data["media"]["type"])
|
230
241
|
return [true, data["media"]["oembed"]["thumbnail_url"]]
|
231
|
-
end
|
242
|
+
end
|
232
243
|
return [true, data["media_metadata"].values.map do |media|
|
233
|
-
|
234
|
-
|
235
|
-
|
244
|
+
next if media == {"status"=>"failed"}
|
245
|
+
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" unless media["status"] == "valid"
|
246
|
+
[media["m"], *media["s"].values_at("x", "y"), CGI.unescapeHTML(media["s"]["u"])]
|
247
|
+
end.compact] if data["media_metadata"]
|
248
|
+
return [true, "#{"https://www.reddit.com" if /\A\/r\/[0-9a-zA-Z_]+\/comments\/[0-9a-z]{5,6}\// =~ data["url"]}#{data["url"]}"] if data["crosspost_parent"]
|
236
249
|
return [true, data["url"]] unless data["is_self"]
|
237
250
|
raise ErrorAssert.new "our knowledge about Reddit API seems to be outdated" if data["url"] != "https://www.reddit.com" + data["permalink"]
|
238
251
|
return [false, data["selftext"]]
|
@@ -242,7 +255,7 @@ module DirectLink
|
|
242
255
|
id, mtd, field, f = case link
|
243
256
|
when %r{\Ahttps://vk\.com/id(?<user_id>\d+)\?z=photo(?<id>\k<user_id>_\d+)(%2F(album\k<user_id>_0|photos\k<user_id>))?\z},
|
244
257
|
%r{\Ahttps://vk\.com/[a-z_]+\?z=photo(?<_>)(?<id>(?<user_id>\d+)_\d+)%2Fphotos\k<user_id>\z},
|
245
|
-
%r{\Ahttps://vk\.com/photo(?<_>)(?<id>-?\d+_\d+)(\?all=1)?\z},
|
258
|
+
%r{\Ahttps://vk\.com/photo(?<_>)(?<id>-?\d+_\d+)(\?(?:all|rev)=1)?\z},
|
246
259
|
%r{\Ahttps://vk\.com/feed\?section=likes&z=photo(?<_>)(?<id>-(?<user_id>\d+)_\d+)%2F(liked\d+|album\k<user_id>_0)\z},
|
247
260
|
%r{\Ahttps://vk\.com/[a-z_]+\?z=photo(?<_>)(?<id>(?<user_id>-\d+)_\d+)%2F(wall\k<user_id>_\d+|album\k<user_id>_0)\z},
|
248
261
|
%r{\Ahttps://vk\.com/wall(?<user_id>-\d+)_\d+\?z=photo(?<id>\k<user_id>_\d+)%2F(wall\k<user_id>_\d+|album\k<user_id>_00%2Frev|\d+)\z}
|
@@ -286,9 +299,8 @@ module DirectLink
|
|
286
299
|
end
|
287
300
|
|
288
301
|
|
289
|
-
|
290
|
-
|
291
|
-
def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
302
|
+
def DirectLink link, timeout = nil, proxy = nil, giveup: false, ignore_meta: false
|
303
|
+
timeout ||= DirectLink.timeout
|
292
304
|
ArgumentError.new("link should be a <String>, not <#{link.class}>") unless link.is_a? String
|
293
305
|
begin
|
294
306
|
URI link
|
@@ -326,7 +338,7 @@ def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
|
326
338
|
**( %w{ reddit com } == URI(link).host.split(?.).last(2) ||
|
327
339
|
%w{ redd it } == URI(link).host.split(?.) ? {Cookie: "over18=1"} : {} ),
|
328
340
|
}
|
329
|
-
head = NetHTTPUtils.request_data link, :
|
341
|
+
head = NetHTTPUtils.request_data link, :HEAD, header: header, **(proxy ? {proxy: proxy} : {}), **(timeout ? {
|
330
342
|
timeout: timeout,
|
331
343
|
max_start_http_retry_delay: timeout,
|
332
344
|
max_read_retry_delay: timeout
|
@@ -383,7 +395,7 @@ def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
|
383
395
|
f = ->_{ _.type == :a ? _.attr["href"] : _.children.flat_map(&f) }
|
384
396
|
require "kramdown"
|
385
397
|
return f[Kramdown::Document.new(u).root].flat_map do |sublink|
|
386
|
-
DirectLink URI.join(link, sublink).to_s, timeout, giveup: giveup
|
398
|
+
DirectLink URI.join(link, sublink).to_s, timeout, giveup: giveup # TODO: maybe subtract from timeout the time we've already wasted
|
387
399
|
end
|
388
400
|
end
|
389
401
|
if u.is_a? Hash
|
@@ -393,8 +405,8 @@ def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
|
393
405
|
struct.new u, x, y, t
|
394
406
|
end
|
395
407
|
end
|
396
|
-
|
397
|
-
|
408
|
+
raise DirectLink::ErrorNotFound.new link.inspect if link == u
|
409
|
+
return DirectLink u, timeout, giveup: giveup
|
398
410
|
rescue DirectLink::ErrorMissingEnvVar
|
399
411
|
end if %w{ reddit com } == URI(link).host.split(?.).last(2) ||
|
400
412
|
%w{ redd it } == URI(link).host.split(?.)
|
@@ -407,11 +419,15 @@ def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
|
407
419
|
end if %w{ vk com } == URI(link).host.split(?.)
|
408
420
|
|
409
421
|
begin
|
410
|
-
f = FastImage.new
|
422
|
+
f = FastImage.new link,
|
423
|
+
raise_on_failure: true,
|
424
|
+
timeout: timeout,
|
425
|
+
**(proxy ? {proxy: "http://#{proxy}"} : {}),
|
426
|
+
http_header: {"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"}
|
411
427
|
rescue FastImage::UnknownImageType
|
412
428
|
raise if giveup
|
413
429
|
require "nokogiri"
|
414
|
-
head = NetHTTPUtils.request_data link, :
|
430
|
+
head = NetHTTPUtils.request_data link, :HEAD, header: {"User-Agent" => "Mozilla"},
|
415
431
|
max_start_http_retry_delay: timeout,
|
416
432
|
timeout: timeout, # NetHTTPUtild passes this as read_timeout to Net::HTTP.start
|
417
433
|
max_read_retry_delay: timeout # and then compares accumulated delay to this
|
@@ -423,7 +439,7 @@ def DirectLink link, timeout = nil, giveup: false, ignore_meta: false
|
|
423
439
|
html = Nokogiri::HTML NetHTTPUtils.request_data link, header: {"User-Agent" => "Mozilla"}
|
424
440
|
if t = html.at_css("meta[@property='og:image']")
|
425
441
|
begin
|
426
|
-
return DirectLink URI.join(link, t[:content]).to_s, nil, giveup: true
|
442
|
+
return DirectLink URI.join(link, t[:content]).to_s, nil, *proxy, giveup: true
|
427
443
|
rescue URI::InvalidURIError
|
428
444
|
end
|
429
445
|
end unless ignore_meta
|
data/test.rb
CHANGED
@@ -13,6 +13,8 @@ fail unless ENV.include? "REDDIT_SECRETS"
|
|
13
13
|
|
14
14
|
require_relative "lib/directlink"
|
15
15
|
DirectLink.silent = true
|
16
|
+
DirectLink.timeout = 30 # TODO: tests about this attribute
|
17
|
+
|
16
18
|
describe DirectLink do
|
17
19
|
|
18
20
|
describe "./lib" do
|
@@ -329,9 +331,11 @@ describe DirectLink do
|
|
329
331
|
["https://imgur.com/9yaMdJq", "https://i.imgur.com/9yaMdJq.mp4", 720, 404, "video/mp4"],
|
330
332
|
["http://imgur.com/gallery/dCQprEq/new", "https://i.imgur.com/dCQprEq.jpg", 5760, 3840, "image/jpeg"],
|
331
333
|
["https://i.imgur.com/fFUTSJu.jpg?fb", "https://i.imgur.com/fFUTSJu.jpg", 1469, 2200, "image/jpeg"], # from reddit.com/93mtba
|
334
|
+
["https://i.imgur.com/IxUrhGX.jpeg", "https://i.imgur.com/IxUrhGX.jpg", 4384, 3012, "image/jpeg"], # jpEg
|
335
|
+
["https://imgur.com/gallery/9f2s9EE", "https://i.imgur.com/9f2s9EE.mp4", 960, 1438, "video/mp4"], # mp4
|
332
336
|
].each_with_index do |t, i|
|
333
337
|
url, n, first, last, type = t
|
334
|
-
it "##{i + 1}" do
|
338
|
+
it "kinds of post ##{i + 1}" do
|
335
339
|
case last
|
336
340
|
when NilClass
|
337
341
|
if n.is_a? Class
|
@@ -377,7 +381,7 @@ describe DirectLink do
|
|
377
381
|
["https://www.flickr.com/photos/130019700@N03/18848891351/in/dateposted-public/", [4621, 3081, "https://live.staticflickr.com/3796/18848891351_f751b35aeb_o.jpg"]], # userid in-public
|
378
382
|
["https://www.flickr.com/photos/frank3/3778768209/in/photolist-6KVb92-eCDTCr-ur8K-7qbL5z-c71afh-c6YvXW-7mHG2L-c71ak9-c71aTq-c71azf-c71aq5-ur8Q-6F6YkR-eCDZsD-eCEakg-eCE6DK-4ymYku-7ubEt-51rUuc-buujQE-ur8x-9fuNu7-6uVeiK-qrmcC6-ur8D-eCEbei-eCDY9P-eCEhCk-eCE5a2-eCH457-eCHrcq-eCEdZ4-eCH6Sd-c71b5o-c71auE-eCHa8m-eCDSbz-eCH1dC-eCEg3v-7JZ4rh-9KwxYL-6KV9yR-9tUSbU-p4UKp7-eCHfwS-6KVbAH-5FrdbP-eeQ39v-eeQ1UR-4jHAGN", [4096, 2723, "https://live.staticflickr.com/2499/3778768209_dfa75a41cc_4k.jpg"]],
|
379
383
|
["https://www.flickr.com/photos/patricksloan/18230541413/sizes/l", [2048, 491, "https://live.staticflickr.com/5572/18230541413_fec4783d79_k.jpg"]],
|
380
|
-
["https://flic.kr/p/vPvCWJ", [
|
384
|
+
["https://flic.kr/p/vPvCWJ", [5120, 3413, "https://live.staticflickr.com/507/19572004110_1bd49c5ebd_5k.jpg"]],
|
381
385
|
] ],
|
382
386
|
[ :wiki, [
|
383
387
|
["https://en.wikipedia.org/wiki/Prostitution_by_country#/media/File:Prostitution_laws_of_the_world.PNG", "https://upload.wikimedia.org/wikipedia/commons/e/e8/Prostitution_laws_of_the_world.PNG"],
|
@@ -396,26 +400,18 @@ describe DirectLink do
|
|
396
400
|
["http://redd.it/988889", [true, "https://i.redd.it/3h5xls6ehrg11.jpg"]],
|
397
401
|
["https://www.reddit.com/r/CatsStandingUp/duplicates/abn0ua/cat/", [true, "https://v.redd.it/s9b86afb6w721/DASH_2_4_M?source=fallback"]],
|
398
402
|
["https://www.reddit.com/r/hangers/comments/97you5/tara_radovic/", [true, "https://i.imgur.com/rbLqgOu.jpg"]], # "crossport" from Imgur
|
399
|
-
|
400
|
-
|
401
|
-
["https://
|
402
|
-
["https://
|
403
|
-
["https://
|
404
|
-
|
405
|
-
["https://vk.com/wall-185182611_454?z=photo-185182611_457239340%2Fwall-185182611_454", [[1280, 960, "https://sun9-46.userapi.com/c851028/v851028578/1a62f6/VB4SdR1O6Tg.jpg"]]],
|
406
|
-
["https://vk.com/wall-105984091_7946?z=photo-105984091_457243312%2Falbum-105984091_00%2Frev", [[1280, 875, "https://sun9-37.userapi.com/c852020/v852020134/1b6b36/0IsDFb-Hda4.jpg"]]],
|
407
|
-
["https://vk.com/photo533531776_456239427?all=1", [[750, 938, "https://sun9-25.userapi.com/c849416/v849416600/14b949/V01Ch1gYjhc.jpg"]]],
|
408
|
-
["https://vk.com/photo-155488973_456242404", [[1486, 1000, "https://sun9-7.userapi.com/c852132/v852132877/8578e/m6AJWiskiKE.jpg"]]],
|
409
|
-
["https://vk.com/id2272074?z=photo2272074_264578776%2Fphotos2272074", [[604, 484, "https://sun9-10.userapi.com/c10472/u2272074/-7/x_407b2ba2.jpg"]]],
|
410
|
-
["https://vk.com/feed?section=likes&z=photo-117564754_456261460%2Fliked3902406", [[1024, 1335, "https://sun9-72.userapi.com/c854028/v854028353/895b6/izQJresLdf0.jpg"]]],
|
411
|
-
["https://vk.com/likizimy?z=photo-42543351_456239941%2Fwall-42543351_1908", [[1179, 1731, "https://sun9-47.userapi.com/c855036/v855036571/60f7b/ryCPJIMyMkI.jpg"]]],
|
412
|
-
["https://vk.com/e_rod?z=photo298742340_457247118%2Fphotos298742340", [[1728, 2160, "https://sun9-53.userapi.com/c858320/v858320596/c7714/oImGe4o1ZJI.jpg"]]],
|
403
|
+
["https://www.reddit.com/gallery/i1u6rb", [true, [["image/jpg", 1440, 1440, "https://preview.redd.it/x31msdj6vee51.jpg?width=1440&format=pjpg&auto=webp&s=b79952f8364bb98692d978944347f19e28774d1b"], ["image/jpg", 2441, 2441, "https://preview.redd.it/mwkzq6j6vee51.jpg?width=2441&format=pjpg&auto=webp&s=455e669356550351e6b8768d8009de616c11142a"], ["image/jpg", 1440, 1440, "https://preview.redd.it/0ws1j8j6vee51.jpg?width=1440&format=pjpg&auto=webp&s=061582da8478e7601a7ce7a97fa1663852873726"], ["image/jpg", 1440, 1440, "https://preview.redd.it/2un68aj6vee51.jpg?width=1440&format=pjpg&auto=webp&s=a980f0e5814c2360f5d7a0fb12f391e304942c06"], ["image/jpg", 3024, 3780, "https://preview.redd.it/5bsfaej6vee51.jpg?width=3024&format=pjpg&auto=webp&s=9b96b4b7262eebacc7571a9f0ad902e2034bf990"], ["image/jpg", 1440, 1440, "https://preview.redd.it/0z010ej6vee51.jpg?width=1440&format=pjpg&auto=webp&s=f0c29be6ec98b835a482c7584cca43fd16217bc8"], ["image/jpg", 1440, 1440, "https://preview.redd.it/aylm2ej6vee51.jpg?width=1440&format=pjpg&auto=webp&s=39cf471b14020a1f137bc9bbb294bf5489cab3e7"]]]], # TODO: find smaller gallery
|
404
|
+
["https://www.reddit.com/i1u6rb", [true, [["image/jpg", 1440, 1440, "https://preview.redd.it/x31msdj6vee51.jpg?width=1440&format=pjpg&auto=webp&s=b79952f8364bb98692d978944347f19e28774d1b"], ["image/jpg", 2441, 2441, "https://preview.redd.it/mwkzq6j6vee51.jpg?width=2441&format=pjpg&auto=webp&s=455e669356550351e6b8768d8009de616c11142a"], ["image/jpg", 1440, 1440, "https://preview.redd.it/0ws1j8j6vee51.jpg?width=1440&format=pjpg&auto=webp&s=061582da8478e7601a7ce7a97fa1663852873726"], ["image/jpg", 1440, 1440, "https://preview.redd.it/2un68aj6vee51.jpg?width=1440&format=pjpg&auto=webp&s=a980f0e5814c2360f5d7a0fb12f391e304942c06"], ["image/jpg", 3024, 3780, "https://preview.redd.it/5bsfaej6vee51.jpg?width=3024&format=pjpg&auto=webp&s=9b96b4b7262eebacc7571a9f0ad902e2034bf990"], ["image/jpg", 1440, 1440, "https://preview.redd.it/0z010ej6vee51.jpg?width=1440&format=pjpg&auto=webp&s=f0c29be6ec98b835a482c7584cca43fd16217bc8"], ["image/jpg", 1440, 1440, "https://preview.redd.it/aylm2ej6vee51.jpg?width=1440&format=pjpg&auto=webp&s=39cf471b14020a1f137bc9bbb294bf5489cab3e7"]]]], # TODO: find smaller gallery
|
405
|
+
["https://www.reddit.com/gallery/i3y7pc", [true, "https://www.reddit.com/gallery/i3y7pc"]], # deleted gallery
|
406
|
+
["https://www.reddit.com/ik6c6a", [true, "https://www.reddit.com/r/Firewatch/comments/ik6brf/new_wallpaper_for_my_triple_monitor_setup/"]], # deleted gallery
|
407
|
+
["https://www.reddit.com/kbjdwc", [true, [["image/jpg", 500, 500, "https://preview.redd.it/71t8ljeexo461.jpg?width=500&format=pjpg&auto=webp&s=df211fe0699e3970681ffe493ed1af79725857e8"], ["image/jpg", 720, 446, "https://preview.redd.it/c11nt7hexo461.jpg?width=720&format=pjpg&auto=webp&s=5e34ab0e6d54c0acfdb47f1daaf283087c5ad6a6"], ["image/jpg", 713, 588, "https://preview.redd.it/67mqvllexo461.jpg?width=713&format=pjpg&auto=webp&s=969dfb52bedd6f0055249aa8b7454b23adaa946e"]]]], # failed media
|
408
|
+
# TODO: empty result? https://redd.it/9hhtsq
|
413
409
|
] ],
|
414
410
|
].each do |method, tests|
|
415
|
-
next if method == :vk && ENV.include?("
|
416
|
-
describe method do
|
411
|
+
next if method == :vk && ENV.include?("CI")
|
412
|
+
describe "kinds of links #{method}" do
|
417
413
|
tests.each_with_index do |(input, expectation), i|
|
418
|
-
it "
|
414
|
+
it "##{i + 1}" do
|
419
415
|
if expectation.is_a? Class
|
420
416
|
assert_raises expectation, input do
|
421
417
|
DirectLink.method(method).call input
|
@@ -429,6 +425,37 @@ describe DirectLink do
|
|
429
425
|
end
|
430
426
|
end
|
431
427
|
|
428
|
+
describe "kinds of links vk" do
|
429
|
+
next if ENV.include? "CI"
|
430
|
+
[
|
431
|
+
["https://vk.com/wall-105984091_7806", [960, 1280, "https://userapi.com/impf/c855224/v855224900/a72f1/7OZ8ux9Wcwo.jpg"]],
|
432
|
+
# ["https://vk.com/wall298742340_4715", [1080, 1080, "https://userapi.com/impf/c857136/v857136625/15e38b/CsCqsJD174A.jpg"]], # TODO: it's now 404
|
433
|
+
["https://vk.com/wall-185182611_454?z=photo-185182611_457239340%2Fwall-185182611_454", [1280, 960, "https://userapi.com/impf/c851028/v851028578/1a62f6/VB4SdR1O6Tg.jpg"]],
|
434
|
+
["https://vk.com/wall-105984091_7946?z=photo-105984091_457243312%2Falbum-105984091_00%2Frev", [1280, 875, "https://userapi.com/impf/c852020/v852020134/1b6b36/0IsDFb-Hda4.jpg"]],
|
435
|
+
["https://vk.com/id57030827?z=photo57030827_456241143%2Falbum57030827_0", [1920, 1440, "https://userapi.com/impf/c845322/v845322944/167836/bP9z41BybhI.jpg"]],
|
436
|
+
["https://vk.com/id57030827?z=photo57030827_456241143", [1920, 1440, "https://userapi.com/impf/c845322/v845322944/167836/bP9z41BybhI.jpg"]],
|
437
|
+
["https://vk.com/photo1_215187843?all=1", [2560, 1913, "https://userapi.com/impf/c210/v210001/6/53_VwoACy4I.jpg"]],
|
438
|
+
["https://vk.com/photo298742340_456243948?rev=1", [1583, 1080, "https://userapi.com/impf/c852224/v852224479/321be/9rZaJ2QTdz4.jpg"]],
|
439
|
+
["https://vk.com/photo-155488973_456242404", [1486, 1000, "https://userapi.com/impf/c852132/v852132877/8578e/m6AJWiskiKE.jpg"]],
|
440
|
+
# ["https://vk.com/id2272074?z=photo2272074_264578776%2Fphotos2272074", [604, 484, "https://userapi.com/impf/c10472/u2272074/-7/x_407b2ba2.jpg"]], # TODO: it's now 404
|
441
|
+
["https://vk.com/feed?section=likes&z=photo-117564754_456261460%2Fliked3902406", [1024, 1335, "https://userapi.com/impf/c854028/v854028353/895b6/izQJresLdf0.jpg"]],
|
442
|
+
["https://vk.com/likizimy?z=photo-42543351_456239941%2Fwall-42543351_1908", [1179, 1731, "https://userapi.com/impf/c855036/v855036571/60f7b/ryCPJIMyMkI.jpg"]],
|
443
|
+
["https://vk.com/e_rod?z=photo298742340_457247118%2Fphotos298742340", [1728, 2160, "https://userapi.com/impf/c858320/v858320596/c7714/oImGe4o1ZJI.jpg"]],
|
444
|
+
].each_with_index do |(input, expectation), i|
|
445
|
+
it "##{i + 1}" do
|
446
|
+
result = DirectLink.method(:vk).call input
|
447
|
+
assert_equal 1, result.size
|
448
|
+
result[0][-1].tap do |url|
|
449
|
+
url.replace( URI.parse(url).tap do |_|
|
450
|
+
_.host = _.host.split(?.).drop(1).join(?.)
|
451
|
+
_.query = nil
|
452
|
+
end.to_s )
|
453
|
+
end
|
454
|
+
assert_equal [expectation], result, "#{input} :: #{result.inspect} != #{expectation.inspect}"
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
432
459
|
{
|
433
460
|
google: [
|
434
461
|
"https://lh3.googleusercontent.com/-NVJgqmI_2Is/WqMM2OMYg-I/AAAAAAAALrk/5-p3JL3iZt0Ho9dOf_p3gpddzqwr3Wp0ACJoC/w424-h318-n/001",
|
@@ -461,13 +488,13 @@ describe DirectLink do
|
|
461
488
|
["http://redd.it/32tq0i", "https://www.reddit.com/comments/32tq0i"],
|
462
489
|
["https://reddit.com/123456", "https://www.reddit.com/r/funny/comments/123456/im_thinking_about_getting_a_dog_and_youtubed_ways/"],
|
463
490
|
# ["https://www.reddit.com/r/travel/988889", "https://www.reddit.com/r/travel/comments/988889/playa_miramar_in_guaymas_sonora/"],
|
464
|
-
"https://www.reddit.com/r/
|
491
|
+
"https://www.reddit.com/r/PareidoliaGoneWild/comments/hzrlq6/beard_trimmer_on_display_at_best_buy_they_knew/", # NSFW causes redirect to /over_18? if the special cookie not provided
|
465
492
|
],
|
466
493
|
vk: [
|
467
494
|
"https://vk.com/id57030827?z=photo57030827_456241143",
|
468
495
|
],
|
469
496
|
}.each do |method, tests|
|
470
|
-
describe "DirectLink() calls #{method}" do
|
497
|
+
describe "DirectLink() sees domain name and calls #{method}" do
|
471
498
|
tests.each_with_index do |(input, expected), i|
|
472
499
|
it "##{i + 1}" do
|
473
500
|
DirectLink.stub method, ->link{
|
@@ -603,6 +630,16 @@ describe DirectLink do
|
|
603
630
|
)
|
604
631
|
end
|
605
632
|
|
633
|
+
it "throws ErrorNotFound when Reddit gallery is removed" do
|
634
|
+
assert_raises DirectLink::ErrorNotFound do
|
635
|
+
DirectLink "https://www.reddit.com/gallery/i3y7pc"
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
it "follows Reddit crosspost" do
|
640
|
+
assert_equal %w{ image/png image/png }, DirectLink("https://www.reddit.com/ik6c6a").map(&:type)
|
641
|
+
end
|
642
|
+
|
606
643
|
it "throws ErrorBadLink if link is invalid" do
|
607
644
|
assert_equal "test".inspect, (
|
608
645
|
assert_raises DirectLink::ErrorBadLink do
|
@@ -655,7 +692,7 @@ describe DirectLink do
|
|
655
692
|
[
|
656
693
|
# ["http://www.aeronautica.difesa.it/organizzazione/REPARTI/divolo/PublishingImages/6%C2%B0%20Stormo/2013-decollo%20al%20tramonto%20REX%201280.jpg", ["http://www.aeronautica.difesa.it/organizzazione/REPARTI/divolo/PublishingImages/6%C2%B0%20Stormo/2013-decollo%20al%20tramonto%20REX%201280.jpg", 1280, 853, :jpeg], nil, 1], # website is dead?
|
657
694
|
# ["http://minus.com/lkP3hgRJd9npi", SocketError, /nodename nor servname provided, or not known|No address associated with hostname/, 0],
|
658
|
-
["http://www.cutehalloweencostumeideas.org/wp-content/uploads/2017/10/Niagara-Falls_04.jpg", SocketError, /nodename nor servname provided, or not known|Name or service not known/, 0],
|
695
|
+
["http://www.cutehalloweencostumeideas.org/wp-content/uploads/2017/10/Niagara-Falls_04.jpg", SocketError, /nodename nor servname provided, or not known|Name or service not known|getaddrinfo: Name does not resolve/, 0],
|
659
696
|
].each_with_index do |(input, expectation, message_string_or_regex, max_redirect_resolving_retry_delay), i|
|
660
697
|
it "##{i + 1}" do
|
661
698
|
if expectation.is_a? Class
|
@@ -696,19 +733,20 @@ describe DirectLink do
|
|
696
733
|
case expectation
|
697
734
|
when Class
|
698
735
|
e = assert_raises expectation, "for #{input} (giveup = #{giveup})" do
|
699
|
-
DirectLink input,
|
736
|
+
DirectLink input, 5, *ENV["PROXY"], giveup: giveup
|
700
737
|
end
|
701
738
|
assert_equal expectation.to_s, e.class.to_s, "for #{input} (giveup = #{giveup})"
|
702
739
|
when String
|
703
|
-
result = DirectLink input,
|
740
|
+
result = DirectLink input, 5, *ENV["PROXY"], giveup: giveup
|
704
741
|
assert_equal expectation, result.url, "for #{input} (giveup = #{giveup})"
|
705
742
|
else
|
706
|
-
result = DirectLink input,
|
743
|
+
result = DirectLink input, 5, *ENV["PROXY"], giveup: giveup
|
707
744
|
result = [result] unless result.is_a? Array # we can't do `Array(<Struct>)` because it splats by elements
|
708
745
|
assert_equal expectation, result.size, ->{
|
709
746
|
"for #{input} (giveup = #{giveup}): #{result.map &:url}"
|
710
747
|
}
|
711
748
|
end
|
749
|
+
# weird that this test may take longer than 5 sec
|
712
750
|
ensure
|
713
751
|
ENV["IMGUR_CLIENT_ID"] = ti if ti
|
714
752
|
ENV["REDDIT_SECRETS"] = tr if tr
|
@@ -751,21 +789,28 @@ describe DirectLink do
|
|
751
789
|
|
752
790
|
describe "fails" do
|
753
791
|
[
|
754
|
-
[1, "http://example.com/",
|
755
|
-
[1, "http://example.com/404",
|
792
|
+
[1, "http://example.com/", /\AFastImage::UnknownImageType\n\z/],
|
793
|
+
[1, "http://example.com/404", /\ANetHTTPUtils::Error: HTTP error #404 \n\z/],
|
756
794
|
|
757
795
|
# TODO: a test when the giveup=false fails and reraises the DirectLink::ErrorMissingEnvVar
|
758
796
|
# maybe put it to ./lib tests
|
759
797
|
|
760
798
|
# by design it should be impossible to write a test for DirectLink::ErrorAssert
|
761
|
-
[1, "https://flic.kr/p/DirectLinkErrorNotFound",
|
799
|
+
[1, "https://flic.kr/p/DirectLinkErrorNotFound", /\ANetHTTPUtils::Error: HTTP error #404 \n\z/],
|
762
800
|
|
763
|
-
[1, "https://imgur.com/a/badlinkpattern",
|
801
|
+
[1, "https://imgur.com/a/badlinkpattern", /\ANetHTTPUtils::Error: HTTP error #404 \n\z/],
|
764
802
|
# TODO: a test that it appends the `exception.cause`
|
803
|
+
|
804
|
+
[1, "https://groundingpositivity.com/2020/08/13/new-quantum-app-will-make-you-wonder-do-we-live-in-a-simulation/", (
|
805
|
+
Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.4.0") ?
|
806
|
+
/\ANetHTTPUtils::EOFError_from_rbuf_fill: probably the old Ruby empty backtrace EOFError exception from net\/protocol\.rb: end of file reached\n\z/ :
|
807
|
+
/\A\S+\/net\/protocol\.rb:\d+:in `rbuf_fill': end of file reached \(EOFError\)\n/
|
808
|
+
) ], # TODO: add also a test to nethttputils gem
|
765
809
|
].each_with_index do |(expected_exit_code, link, expected_output, unset), i| # TODO: unset is not used anymore or I have to go sleep?
|
766
810
|
it "##{i + 1}" do
|
767
811
|
string, status = Open3.capture2e "export #{(File.read("api_tokens_for_travis.sh") + File.read("vk.secret")).scan(/(?<=^export )\S+=\S+/).join(" ")}#{unset} && RUBYOPT='-rbundler/setup #{$-I.map{ |i| "-I #{i}" }.join " "}' ./bin/directlink #{link}"
|
768
|
-
assert_equal
|
812
|
+
assert_equal expected_exit_code, status.exitstatus, "for #{link}"
|
813
|
+
assert string[expected_output], "for #{link}"
|
769
814
|
end
|
770
815
|
end
|
771
816
|
end
|
@@ -820,12 +865,13 @@ describe DirectLink do
|
|
820
865
|
# TODO: test about --json
|
821
866
|
it "uses <meta> tag" do
|
822
867
|
string, status = Open3.capture2e "RUBYOPT='-rbundler/setup' ./bin/directlink --json https://www.kp.ru/daily/26342.7/3222103/"
|
823
|
-
assert_equal [0, "https://
|
824
|
-
end
|
825
|
-
it "ignores <meta> tag" do
|
826
|
-
string, status = Open3.capture2e "RUBYOPT='-rbundler/setup' ./bin/directlink --json --ignore-meta https://www.kp.ru/daily/26342.7/3222103/"
|
827
|
-
assert_equal [0, 21, "https://s11.stc.all.kpcdn.net/share/i/12/8024261/inx960x640.jpg"], [status.exitstatus, JSON.load(string).size, JSON.load(string).first.fetch("url")]
|
868
|
+
assert_equal [0, "https://s11.stc.all.kpcdn.net/share/i/12/8054352/cr-1200-630.wm-asnplfru-100-tr-0-0.t-13-3222103-ttps-54-14-0083CD-1010-l-85-b-42.t-13-3222103-ttps-54-14-FFF-1010-l-85-b-42.t-207-5-asb-37-10-FFF-788-l-370-t-68.m2018-03-14T02-10-20.jpg"], [status.exitstatus, JSON.load(string).fetch("url")]
|
828
869
|
end
|
870
|
+
# TODO: kp.ru broke the page -- images are gone
|
871
|
+
# it "ignores <meta> tag" do
|
872
|
+
# string, status = Open3.capture2e "RUBYOPT='-rbundler/setup' ./bin/directlink --json --ignore-meta https://www.kp.ru/daily/26342.7/3222103/"
|
873
|
+
# assert_equal [0, 21, "https://s11.stc.all.kpcdn.net/share/i/12/8024261/inx960x640.jpg"], [status.exitstatus, JSON.load(string).size, JSON.load(string).first.fetch("url")]
|
874
|
+
# end
|
829
875
|
|
830
876
|
end
|
831
877
|
|