getvideo 0.0.4
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 +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/Gemfile +15 -0
- data/Guardfile +24 -0
- data/LICENSE +22 -0
- data/README.md +56 -0
- data/Rakefile +2 -0
- data/getvideo.gemspec +21 -0
- data/lib/getvideo.rb +38 -0
- data/lib/getvideo/56.rb +60 -0
- data/lib/getvideo/iask.rb +173 -0
- data/lib/getvideo/iqiyi.rb +80 -0
- data/lib/getvideo/ku6.rb +56 -0
- data/lib/getvideo/sohu.rb +77 -0
- data/lib/getvideo/tudou.rb +163 -0
- data/lib/getvideo/version.rb +3 -0
- data/lib/getvideo/video.rb +126 -0
- data/lib/getvideo/youku.rb +82 -0
- data/lib/getvideo/youtube.rb +65 -0
- data/spec/56_spec.rb +50 -0
- data/spec/getvideo_spec.rb +13 -0
- data/spec/iask_spec.rb +128 -0
- data/spec/iqiyi_spec.rb +42 -0
- data/spec/ku6_spec.rb +39 -0
- data/spec/sohu_spec.rb +62 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/tudou_spec.rb +155 -0
- data/spec/youku_spec.rb +47 -0
- data/spec/youtube_spec.rb +49 -0
- metadata +126 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
|
3
|
+
module Getvideo
|
4
|
+
class Iqiyi < Video
|
5
|
+
set_api_uri { "http://cache.video.qiyi.com/v/#{id}" }
|
6
|
+
attr_reader :ipad_response
|
7
|
+
|
8
|
+
def initialize(url)
|
9
|
+
super
|
10
|
+
ipad_connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def html_url
|
14
|
+
response.css("videoUrl").text
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
if url =~ /\.html/
|
19
|
+
parse_vid[1]
|
20
|
+
elsif url =~ /swf/
|
21
|
+
url.scan(/com\/([^\/]+)/)[0][0]
|
22
|
+
else
|
23
|
+
url
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def title
|
28
|
+
response.css("title").text
|
29
|
+
end
|
30
|
+
|
31
|
+
def cover
|
32
|
+
response.css("albumImage").text
|
33
|
+
end
|
34
|
+
|
35
|
+
def m3u8
|
36
|
+
ipad_response["data"]["mtl"][1]["m3u"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def flash
|
40
|
+
position = response.css("logoPosition").text
|
41
|
+
duration = response.css("totalDuration").text
|
42
|
+
video_url = response.css("videoUrl").text.gsub("http://www.iqiyi.com/","")
|
43
|
+
"http://player.video.qiyi.com/#{id}/#{position}/#{duration}/#{video_url}"[0..-5]+"swf"
|
44
|
+
end
|
45
|
+
|
46
|
+
def media
|
47
|
+
video_list = {}
|
48
|
+
video_list["mp4"] = []
|
49
|
+
video_list["mp4"] << parse_mp4
|
50
|
+
video_list["ts"] = []
|
51
|
+
file = response.css("file")
|
52
|
+
size = response.css("size")
|
53
|
+
file.zip(size).each do |f|
|
54
|
+
video_list["ts"] << f[0].content[0..-4] + "ts?start=0&end=99999999&hsize=" + f[1].text
|
55
|
+
end
|
56
|
+
return video_list
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def ipad_connection
|
62
|
+
conn = Faraday.new
|
63
|
+
response= conn.get "http://cache.video.qiyi.com/m/#{id}/"
|
64
|
+
@ipad_response = MultiJson.load response.body.scan(/ipadUrl=([^*]+)/)[0][0]
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_mp4(url=nil)
|
68
|
+
site = ipad_response["data"]["mp4Url"]
|
69
|
+
conn = Faraday.new
|
70
|
+
res = conn.get(site)
|
71
|
+
res.body.scan(/"l":"([^,]+)"/)[0][0]
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_vid
|
75
|
+
conn = Faraday.new
|
76
|
+
page_res = conn.get(url)
|
77
|
+
return page_res.body.match(/data-player-videoid\s*[:=]\s*["']([^"']+)["']/)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/getvideo/ku6.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
|
3
|
+
module Getvideo
|
4
|
+
class Ku6 < Video
|
5
|
+
def html_url
|
6
|
+
if url =~ /\.html/
|
7
|
+
url
|
8
|
+
else
|
9
|
+
"http://v.ku6.com/show/#{id}.html"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def title
|
14
|
+
response["data"]["t"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
if url =~ /\.html/
|
19
|
+
url.split("/").last.split(".html")[0]
|
20
|
+
elsif url =~ /\.swf/
|
21
|
+
url.split("/")[-2]
|
22
|
+
else
|
23
|
+
url
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cover
|
28
|
+
response["data"]["bigpicpath"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def flash
|
32
|
+
"http://player.ku6.com/refer/#{id}/v.swf"
|
33
|
+
end
|
34
|
+
|
35
|
+
def m3u8
|
36
|
+
"http://v.ku6.com/fetchwebm/#{id}.m3u8"
|
37
|
+
end
|
38
|
+
|
39
|
+
def media
|
40
|
+
video_list = {}
|
41
|
+
video_list["f4v"] = []
|
42
|
+
response["data"]["f"].split(",").each do |f|
|
43
|
+
video_list["f4v"] << f
|
44
|
+
end
|
45
|
+
return video_list
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def connection
|
51
|
+
conn = Faraday.new
|
52
|
+
response= conn.post "http://v.ku6.com/fetch.htm", {"t" => "getVideo4Player", "vid" => id}
|
53
|
+
@response = Response.new(response).parsed
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
|
3
|
+
module Getvideo
|
4
|
+
class Sohu < Video
|
5
|
+
set_api_uri do
|
6
|
+
if url =~ /(my\.tv|my\/v\.swf|\|my)/
|
7
|
+
"http://my.tv.sohu.com/videinfo.jhtml?m=viewnew&vid=#{id}"
|
8
|
+
else
|
9
|
+
"http://hot.vrs.sohu.com/vrs_flash.action?vid=#{id}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def html_url
|
14
|
+
response["url"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
if url =~ /my\.tv.+\/(?:pl|us)\/(?:[^\D]+)\/([^\D]+)/
|
19
|
+
u = url.scan(/my\.tv.+\/(?:pl|us)\/(?:[^\D]+)\/([^\D]+)/)[0][0]
|
20
|
+
elsif url =~ /(\.shtml|my\.tv.+\/user\/detail)/
|
21
|
+
parse_vid[1]
|
22
|
+
elsif url =~ /v\.swf/
|
23
|
+
url.scan(/(sohu\.com\/([^\D]+)\/v.swf|id=([^\D]+))/)[0].compact[1]
|
24
|
+
elsif url =~ /\|my/
|
25
|
+
url.split("|")[0]
|
26
|
+
else
|
27
|
+
url
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def title
|
32
|
+
response["data"]["tvName"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def cover
|
36
|
+
response["data"]["coverImg"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def flash
|
40
|
+
if url =~ /(my\.tv)/
|
41
|
+
"http://share.vrs.sohu.com/my/v.swf&topBar=1&id=#{id}&autoplay=false"
|
42
|
+
else
|
43
|
+
"http://share.vrs.sohu.com/#{id}/v.swf&autoplay=false"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def m3u8
|
48
|
+
if url =~ /(my\.tv)/
|
49
|
+
"http://my.tv.sohu.com/ipad/#{id}.m3u8"
|
50
|
+
else
|
51
|
+
"http://hot.vrs.sohu.com/ipad#{id}.m3u8"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def media
|
56
|
+
host = response["allot"]
|
57
|
+
prot = response["prot"]
|
58
|
+
clips = response["data"]["clipsURL"]
|
59
|
+
new = response["data"]["su"]
|
60
|
+
clips_len = clips.length
|
61
|
+
new_len = new.length
|
62
|
+
video_list = {}
|
63
|
+
video_list["mp4"] = []
|
64
|
+
clips.zip(new).each do | c, n |
|
65
|
+
h, _, _, key = Net::HTTP.get(URI.parse("http://#{host}?prot=#{prot}&file=#{c}&new=#{n}")).split("|")
|
66
|
+
video_list["mp4"] << "#{h}#{n}?key=#{key}"
|
67
|
+
end
|
68
|
+
return video_list
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_vid
|
72
|
+
conn = Faraday.new
|
73
|
+
page_res = conn.get(url)
|
74
|
+
page_res.body.match(/vid[\s]*=[\s]*["|']?(\d+)["|']?/)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
|
3
|
+
module Getvideo
|
4
|
+
class Tudou < Video
|
5
|
+
attr_reader :info
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
9
|
+
parse_html
|
10
|
+
tudou_connect
|
11
|
+
@body = Nokogiri::XML(response)
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
iid
|
16
|
+
end
|
17
|
+
|
18
|
+
def html_url
|
19
|
+
if url =~ /\/(a|o|l)\/.*.\.swf/
|
20
|
+
type = url.scan(/\/(a|o|l)\/.*.\.swf/)[0][0]
|
21
|
+
case type
|
22
|
+
when "a"
|
23
|
+
"http://www.tudou.com/albumplay/#{acode}#{"/" + lcode if lcode }.html"
|
24
|
+
when "o"
|
25
|
+
"http://www.tudou.com/oplay/#{acode}#{"/" + lcode if lcode}.html"
|
26
|
+
when "l"
|
27
|
+
"http://www.tudou.com/listplay/#{acode}#{"/" + lcode if lcode}.html"
|
28
|
+
end
|
29
|
+
elsif url =~ /dp\.tudou.com\/(a|o|l|v|albumplay|oplay|listplay)\//
|
30
|
+
type = url.scan(/dp\.tudou.com\/(a|o|l|v|albumplay|oplay|listplay)\/.*.\.html/)[0][0]
|
31
|
+
case type
|
32
|
+
when "a", "albumplay"
|
33
|
+
"http://www.tudou.com/albumplay/#{acode}#{"/" + lcode if lcode}.html"
|
34
|
+
when "o", "oplay"
|
35
|
+
"http://www.tudou.com/oplay/#{acode}#{"/" + lcode if lcode}.html"
|
36
|
+
when "l", "listplay"
|
37
|
+
"http://www.tudou.com/listplay/#{acode}#{"/" + lcode if lcode}.html"
|
38
|
+
when "v"
|
39
|
+
"http://www.tudou.com/programs/view/#{lcode}/"
|
40
|
+
end
|
41
|
+
elsif url =~ /www\.tudou.com\/(programs|albumplay|listplay|oplay)/
|
42
|
+
url
|
43
|
+
else
|
44
|
+
"http://www.tudou.com/programs/view/#{lcode}/"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def title
|
49
|
+
@body.children()[0].attr("title")
|
50
|
+
end
|
51
|
+
|
52
|
+
def cover
|
53
|
+
@info.match(/pic\s*:\s*(\S+)/)[1].delete("\"").gsub(/["|']/,"")
|
54
|
+
end
|
55
|
+
|
56
|
+
def flash
|
57
|
+
if url =~ /\/(v|a|o|l)\/.*.\.swf/
|
58
|
+
url
|
59
|
+
elsif url =~ /\/(albumplay|listplay|oplay)/
|
60
|
+
url_type = url.scan(/\/((a)lbumplay|(l)istplay|(o)play)/)[0].compact()[1]
|
61
|
+
"http://www.tudou.com/#{url_type}/#{acode}/&rpid=116105338&resourceId=116105338_04_05_99&iid=#{iid}/v.swf"
|
62
|
+
elsif url =~ /dp\.tudou\.com\/(l|a|o)/
|
63
|
+
url_type = url.scan(/dp\.tudou.com\/(a|l|o)/)[0][0]
|
64
|
+
"http://www.tudou.com/#{url_type}/#{acode}/&rpid=116105338&resourceId=116105338_04_05_99&iid=#{iid}/v.swf"
|
65
|
+
elsif url =~ /dp\.tudou\.com\/v/
|
66
|
+
"http://www.tudou.com/v/#{lcode}/&rpid=116105338&resourceId=116105338_04_05_99/v.swf"
|
67
|
+
else
|
68
|
+
"http://www.tudou.com/v/#{lcode}/&rpid=116105338&resourceId=116105338_04_05_99/v.swf"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def m3u8
|
73
|
+
"http://vr.tudou.com/v2proxy/v2.m3u8?it=#{iid}&st=2&pw="
|
74
|
+
end
|
75
|
+
|
76
|
+
def media
|
77
|
+
video_list = {}
|
78
|
+
video_list["f4v"] = []
|
79
|
+
video_list["flv"] = []
|
80
|
+
old_brt = ""
|
81
|
+
@body.css("f").each do | file |
|
82
|
+
brt = file.attr("brt")
|
83
|
+
if brt != old_brt
|
84
|
+
if file.content =~ /f4v/
|
85
|
+
video_list["f4v"] << file.content
|
86
|
+
elsif file.content =~ /flv/
|
87
|
+
video_list["flv"] << file.content
|
88
|
+
end
|
89
|
+
old_brt = brt
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return video_list
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def tudou_connect
|
98
|
+
uri = URI.parse "http://v2.tudou.com/v?it=#{iid}"
|
99
|
+
http = Net::HTTP.new uri.host, uri.port
|
100
|
+
req = Net::HTTP::Get.new(uri.request_uri,{"User-Agent"=> ""})
|
101
|
+
res = http.request req
|
102
|
+
@response = res.body
|
103
|
+
end
|
104
|
+
|
105
|
+
def lcode
|
106
|
+
if url =~ /\/v\/.*.\.swf/
|
107
|
+
url.scan(/\/v\/([^\/]+)\//)[0][0]
|
108
|
+
elsif url =~ /dp\.tudou\.com\/(l|a|o|listplay|albumplay|oplay)\/([^.]+)\/([^.]+)\.html/
|
109
|
+
url.scan(/dp\.tudou\.com\/(?:l|a|o|listplay|albumplay|oplay)\/([^.]+)\/([^.]+)\.html/)[0][1]
|
110
|
+
elsif url =~ /dp\.tudou\.com\/(l|a|o|listplay|albumplay|oplay)\/([^.]+)\.html/
|
111
|
+
nil
|
112
|
+
elsif url =~ /dp\.tudou\.com\/v\/([^.]+)\.html/
|
113
|
+
url.scan(/dp\.tudou\.com\/v\/([^.]+)\.html/)[0][0]
|
114
|
+
else
|
115
|
+
tudou_connect
|
116
|
+
Nokogiri::XML(response).children()[0].attr("code")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def acode
|
121
|
+
if url =~ /\/(a|o|l)\/.*.\.swf/
|
122
|
+
url.scan(/\/[a|o|l]\/([^\/]+)\//)[0][0]
|
123
|
+
elsif url =~ /\/(listplay|albumplay|oplay)\/([^.]+)\/([^.]+)\.html/
|
124
|
+
url.scan(/\/(?:listplay|albumplay|oplay)\/([^.]+)\/([^.]+)\.html/)[0][0]
|
125
|
+
elsif url =~ /dp\.tudou\.com\/(l|a|o)\/([^.]+)\/([^.]+)\.html/
|
126
|
+
url.scan(/dp\.tudou\.com\/(?:l|a|o)\/([^.]+)\/([^.]+)\.html/)[0][0]
|
127
|
+
elsif url =~ /dp\.tudou\.com\/(l|a|o)\/([^.]+)\.html/
|
128
|
+
url.scan(/dp\.tudou\.com\/(?:l|a|o)\/([^.]+)\.html/)[0][0]
|
129
|
+
|
130
|
+
elsif url =~ /\/(listplay|albumplay|oplay)\/([^.]+)\.html/
|
131
|
+
url.scan(/\/(?:listplay|albumplay|oplay)\/([^.]+)\.html/)[0][0]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def iid
|
136
|
+
if url =~ /\/(programs|albumplay|listplay|oplay)/
|
137
|
+
get_iid[0][0]
|
138
|
+
elsif url =~ /\/v\/.*.\.swf/
|
139
|
+
get_iid[0][0]
|
140
|
+
elsif url =~ /\/(a|o|l)\/.*.\.swf/
|
141
|
+
url.scan(/iid=([^\/]+)/)[0][0]
|
142
|
+
elsif url =~ /dp\.tudou\.com\/(a|o|l|v)\//
|
143
|
+
get_iid[0][0]
|
144
|
+
elsif url =~ /dp\.tudou\.com\/player\.php/
|
145
|
+
url.scan(/player\.php\?id=([^&]+)/)[0][0]
|
146
|
+
elsif url =~ /dp.tudou.com\/nplayer\.swf/
|
147
|
+
url.scan(/nplayer\.swf\?([^&]+)/)[0][0]
|
148
|
+
else
|
149
|
+
url
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_iid
|
154
|
+
@info.scan(/iid\s*:\s*(\S+)/)
|
155
|
+
end
|
156
|
+
|
157
|
+
def parse_html
|
158
|
+
conn = Faraday.new
|
159
|
+
res = conn.get html_url
|
160
|
+
@info = res.body
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
begin
|
3
|
+
require 'faraday'
|
4
|
+
rescue LoadError
|
5
|
+
raise "You don't have the 'faraday' gem installed"
|
6
|
+
end
|
7
|
+
|
8
|
+
module Getvideo
|
9
|
+
class Video
|
10
|
+
attr_reader :url, :response
|
11
|
+
|
12
|
+
def initialize(url)
|
13
|
+
@url = url
|
14
|
+
connection
|
15
|
+
end
|
16
|
+
|
17
|
+
def connection
|
18
|
+
api_url = self.class.get_api_uri(self)
|
19
|
+
conn = Faraday.new
|
20
|
+
response= conn.get api_url
|
21
|
+
@response = Response.new(response).parsed
|
22
|
+
end
|
23
|
+
|
24
|
+
def id; end
|
25
|
+
def html_url; end
|
26
|
+
def cover; end
|
27
|
+
def title; end
|
28
|
+
def flash; end
|
29
|
+
def m3u8; end
|
30
|
+
def media; end
|
31
|
+
|
32
|
+
def play_media
|
33
|
+
media["mp4"][0] if media["mp4"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def json
|
37
|
+
{id: id,
|
38
|
+
url: html_url,
|
39
|
+
cover: cover,
|
40
|
+
title: title,
|
41
|
+
m3u8: m3u8,
|
42
|
+
flash: flash,
|
43
|
+
media: play_media}.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def set_api_uri(&block)
|
48
|
+
return @api_uri unless block_given?
|
49
|
+
@api_uri = block
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_api_uri(klass)
|
53
|
+
klass.instance_eval(&set_api_uri)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Response
|
59
|
+
attr_reader :response
|
60
|
+
|
61
|
+
CONTENT_TYPE = {
|
62
|
+
'application/json' => :json,
|
63
|
+
'application/x-www-form-urlencoded' => :html,
|
64
|
+
'text/html' => :html,
|
65
|
+
'text/javascript' => :json,
|
66
|
+
'text/xml' => :xml
|
67
|
+
}
|
68
|
+
|
69
|
+
PARSERS = {
|
70
|
+
:json => lambda{ |body| MultiJson.respond_to?(:adapter) ? MultiJson.load(body) : MultiJson.decode(body) rescue body },
|
71
|
+
:html => lambda{ |body| Nokogiri::HTML(body) },
|
72
|
+
:xml => lambda{ |body| Nokogiri::XML(body) }
|
73
|
+
}
|
74
|
+
|
75
|
+
def initialize(response)
|
76
|
+
@response = response
|
77
|
+
end
|
78
|
+
|
79
|
+
def headers
|
80
|
+
response.headers
|
81
|
+
end
|
82
|
+
|
83
|
+
def body
|
84
|
+
decode(response.body)
|
85
|
+
end
|
86
|
+
|
87
|
+
def decode(body)
|
88
|
+
return '' if !body
|
89
|
+
return body if json?
|
90
|
+
charset = body.match(/charset\s*=[\s|\W]*([\w-]+)/)
|
91
|
+
if charset[1].downcase != "utf-8"
|
92
|
+
begin
|
93
|
+
body.encode! "utf-8", charset[1], {:invalid => :replace}
|
94
|
+
rescue
|
95
|
+
body
|
96
|
+
end
|
97
|
+
else
|
98
|
+
body
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def status
|
103
|
+
response.status
|
104
|
+
end
|
105
|
+
|
106
|
+
def content_type
|
107
|
+
((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip
|
108
|
+
end
|
109
|
+
|
110
|
+
def json?
|
111
|
+
CONTENT_TYPE[content_type] == :json || !response.body.match(/\<html/)
|
112
|
+
end
|
113
|
+
|
114
|
+
def parser
|
115
|
+
type = CONTENT_TYPE[content_type]
|
116
|
+
type = :json if type == :html && !response.body.match(/\<html/)
|
117
|
+
return type
|
118
|
+
end
|
119
|
+
|
120
|
+
def parsed
|
121
|
+
return nil unless CONTENT_TYPE.key?(content_type)
|
122
|
+
return nil unless PARSERS.key?(parser)
|
123
|
+
@parsed ||= PARSERS[parser].call(body)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|