opendmm 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Rakefile +35 -27
- data/bin/opendmm +7 -7
- data/lib/opendmm.rb +35 -26
- data/lib/opendmm/maker.rb +18 -59
- data/lib/opendmm/makers/aknr.rb +18 -34
- data/lib/opendmm/makers/ako3.rb +18 -34
- data/lib/opendmm/makers/anna_and_hanako.rb +20 -36
- data/lib/opendmm/makers/apa.rb +19 -35
- data/lib/opendmm/makers/aroma.rb +40 -54
- data/lib/opendmm/makers/attackers.rb +30 -48
- data/lib/opendmm/makers/aurora.rb +24 -40
- data/lib/opendmm/makers/baltan.rb +20 -36
- data/lib/opendmm/makers/befree.rb +22 -38
- data/lib/opendmm/makers/bi.rb +24 -40
- data/lib/opendmm/makers/bijin_majo.rb +19 -35
- data/lib/opendmm/makers/candy.rb +27 -43
- data/lib/opendmm/makers/caribbean.rb +21 -36
- data/lib/opendmm/makers/cross.rb +22 -39
- data/lib/opendmm/makers/dip.rb +22 -38
- data/lib/opendmm/makers/dmm_collection.rb +19 -35
- data/lib/opendmm/makers/ebody.rb +22 -38
- data/lib/opendmm/makers/ideapocket.rb +42 -60
- data/lib/opendmm/makers/kawaii.rb +21 -37
- data/lib/opendmm/makers/kira_kira.rb +21 -37
- data/lib/opendmm/makers/madonna.rb +21 -37
- data/lib/opendmm/makers/moodyz.rb +41 -44
- data/lib/opendmm/makers/munekyunkissa.rb +21 -37
- data/lib/opendmm/makers/opera.rb +27 -43
- data/lib/opendmm/makers/oppai.rb +33 -51
- data/lib/opendmm/makers/premium.rb +23 -39
- data/lib/opendmm/makers/prestige.rb +40 -58
- data/lib/opendmm/makers/ran_maru.rb +29 -46
- data/lib/opendmm/makers/s1.rb +21 -37
- data/lib/opendmm/makers/s_cute.rb +41 -55
- data/lib/opendmm/makers/sod.rb +23 -39
- data/lib/opendmm/makers/tameikegoro.rb +22 -38
- data/lib/opendmm/makers/to_satsu.rb +20 -36
- data/lib/opendmm/makers/waap.rb +24 -41
- data/lib/opendmm/search_engine.rb +20 -0
- data/lib/opendmm/search_engines/dmm.rb +38 -58
- data/lib/opendmm/search_engines/jav_library.rb +32 -63
- data/lib/opendmm/site.rb +73 -0
- data/lib/opendmm/utils.rb +22 -2
- data/lib/opendmm/version.rb +1 -1
- data/test/{fixtures → dmm_fixtures}/DMYJ-001.json +1 -1
- data/test/fixture_test.rb +17 -13
- data/test/{fixtures → jav_library_fixtures}/XV-100.json +0 -0
- data/test/{fixtures → jav_library_fixtures}/XV-1000.json +0 -0
- data/test/{fixtures → maker_fixtures}/ABP-013.json +0 -0
- data/test/{fixtures → maker_fixtures}/ABS-014.json +0 -0
- data/test/{fixtures → maker_fixtures}/ABY-003.json +0 -0
- data/test/{fixtures → maker_fixtures}/ADN-019.json +0 -0
- data/test/{fixtures → maker_fixtures}/AIR-017.json +1 -1
- data/test/{fixtures → maker_fixtures}/AKO-011.json +1 -1
- data/test/{fixtures → maker_fixtures}/ALB-182.json +0 -0
- data/test/{fixtures → maker_fixtures}/ANND-066.json +0 -0
- data/test/{fixtures → maker_fixtures}/AP-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/APAA-182.json +0 -0
- data/test/{fixtures → maker_fixtures}/APAK-051.json +0 -0
- data/test/{fixtures → maker_fixtures}/ARM-191.json +0 -0
- data/test/{fixtures → maker_fixtures}/ARMG-223.json +0 -0
- data/test/{fixtures → maker_fixtures}/ATID-183.json +0 -0
- data/test/{fixtures → maker_fixtures}/BBI-104.json +0 -0
- data/test/{fixtures → maker_fixtures}/BEB-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/BF-175.json +0 -0
- data/test/{fixtures → maker_fixtures}/BID-017.json +0 -0
- data/test/{fixtures → maker_fixtures}/BIJN-006.json +0 -0
- data/test/{fixtures → maker_fixtures}/BLK-049.json +0 -0
- data/test/{fixtures → maker_fixtures}/BRA-002.json +0 -0
- data/test/{fixtures → maker_fixtures}/BWB-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/CHN-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/CHS-015.json +0 -0
- data/test/{fixtures → maker_fixtures}/CLUB-003.json +0 -0
- data/test/{fixtures → maker_fixtures}/CND-012.json +0 -0
- data/test/{fixtures → maker_fixtures}/CND-062.json +0 -0
- data/test/{fixtures → maker_fixtures}/CRAD-099.json +0 -0
- data/test/{fixtures → maker_fixtures}/CRPD-451.json +0 -0
- data/test/{fixtures → maker_fixtures}/CRSS-013.json +0 -0
- data/test/{fixtures → maker_fixtures}/CWM-156.json +1 -1
- data/test/fixtures/Carib 021511-620.json b/data/test/maker_fixtures/Carib → 021511-620.json +0 -0
- data/test/{fixtures → maker_fixtures}/DCOL-017.json +1 -1
- data/test/{fixtures → maker_fixtures}/DGL-007.json +1 -1
- data/test/{fixtures → maker_fixtures}/DOM-045.json +0 -0
- data/test/{fixtures → maker_fixtures}/EBOD-109.json +0 -0
- data/test/{fixtures → maker_fixtures}/ECB-078.json +1 -1
- data/test/{fixtures → maker_fixtures}/EDD-189.json +0 -0
- data/test/{fixtures → maker_fixtures}/ESK-232.json +0 -0
- data/test/{fixtures → maker_fixtures}/EZD-369.json +0 -0
- data/test/{fixtures → maker_fixtures}/FSET-399.json +0 -0
- data/test/{fixtures → maker_fixtures}/HAZ-009.json +0 -0
- data/test/{fixtures → maker_fixtures}/HON-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/IDBD-447.json +0 -0
- data/test/{fixtures → maker_fixtures}/INU-013.json +0 -0
- data/test/{fixtures → maker_fixtures}/IPSD-041.json +0 -0
- data/test/{fixtures → maker_fixtures}/IPTD-464.json +0 -0
- data/test/{fixtures → maker_fixtures}/IPTD-629.json +0 -0
- data/test/{fixtures → maker_fixtures}/IPZ-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/JBD-153.json +0 -0
- data/test/{fixtures → maker_fixtures}/JBS-004.json +0 -0
- data/test/{fixtures → maker_fixtures}/JOB-010.json +0 -0
- data/test/{fixtures → maker_fixtures}/JUC-285.json +0 -0
- data/test/{fixtures → maker_fixtures}/JUFD-137.json +0 -0
- data/test/{fixtures → maker_fixtures}/JUX-007.json +0 -0
- data/test/{fixtures → maker_fixtures}/JUX-119.json +0 -0
- data/test/{fixtures → maker_fixtures}/KAWD-249.json +1 -1
- data/test/{fixtures → maker_fixtures}/KIRD-147.json +0 -0
- data/test/{fixtures → maker_fixtures}/KISD-042.json +0 -0
- data/test/{fixtures → maker_fixtures}/LLR-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/MAS-042.json +0 -0
- data/test/{fixtures → maker_fixtures}/MBD-148.json +0 -0
- data/test/{fixtures → maker_fixtures}/MDC-002.json +0 -0
- data/test/{fixtures → maker_fixtures}/MDYD-544.json +0 -0
- data/test/{fixtures → maker_fixtures}/MEK-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIAD-490.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIDD-599.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIDD-643.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIDD-644.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIDE-004.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIGD-284.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIGD-336.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIGD-337.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIMK-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/MINT-004.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIQD-010.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIRD-071.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIRD-072.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIRD-073.json +0 -0
- data/test/{fixtures → maker_fixtures}/MIXS-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/MMY-010.json +0 -0
- data/test/{fixtures → maker_fixtures}/NAGE-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/NDR-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/NOF-003.json +0 -0
- data/test/{fixtures → maker_fixtures}/NPS-130.json +0 -0
- data/test/{fixtures → maker_fixtures}/OBA-045.json +1 -1
- data/test/{fixtures → maker_fixtures}/ONSD-570.json +0 -0
- data/test/{fixtures → maker_fixtures}/OPUD-125.json +1 -1
- data/test/{fixtures → maker_fixtures}/OSR-003.json +0 -0
- data/test/{fixtures → maker_fixtures}/PARM-028.json +0 -0
- data/test/{fixtures → maker_fixtures}/PBD-134.json +0 -0
- data/test/{fixtures → maker_fixtures}/PGD-306.json +0 -0
- data/test/{fixtures → maker_fixtures}/PJD-085.json +0 -0
- data/test/{fixtures → maker_fixtures}/PPB-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/PPP-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/PPPD-102.json +1 -1
- data/test/{fixtures → maker_fixtures}/PPSD-028.json +1 -1
- data/test/{fixtures → maker_fixtures}/PPT-004.json +0 -0
- data/test/{fixtures → maker_fixtures}/PTS-230.json +0 -0
- data/test/{fixtures → maker_fixtures}/PTV-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/PXD-027.json +0 -0
- data/test/{fixtures → maker_fixtures}/RAW-005.json +0 -0
- data/test/{fixtures → maker_fixtures}/RBD-183.json +0 -0
- data/test/fixtures/S-Cute 248_hibiki_07.json b/data/test/maker_fixtures/S-Cute → 248_hibiki_07.json +0 -0
- data/test/fixtures/S-Cute 353_rena_01.json b/data/test/maker_fixtures/S-Cute → 353_rena_01.json +0 -0
- data/test/fixtures/S-Cute ps5_07_rimu.json b/data/test/maker_fixtures/S-Cute → ps5_07_rimu.json +0 -0
- data/test/fixtures/S-Cute ps6_99_reona.json b/data/test/maker_fixtures/S-Cute → ps6_99_reona.json +0 -0
- data/test/fixtures/S-Cute ps7_83_akari2.json b/data/test/maker_fixtures/S-Cute → ps7_83_akari2.json +0 -0
- data/test/fixtures/S-Cute swm_05_risa2.json b/data/test/maker_fixtures/S-Cute → swm_05_risa2.json +0 -0
- data/test/{fixtures → maker_fixtures}/SAD-031.json +0 -0
- data/test/{fixtures → maker_fixtures}/SDDE-312.json +0 -0
- data/test/{fixtures → maker_fixtures}/SDMT-802.json +0 -0
- data/test/{fixtures → maker_fixtures}/SDMU-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/SDNM-011.json +0 -0
- data/test/{fixtures → maker_fixtures}/SET-007.json +0 -0
- data/test/{fixtures → maker_fixtures}/SGA-001.json +1 -0
- data/test/{fixtures → maker_fixtures}/SHKD-415.json +3 -3
- data/test/{fixtures → maker_fixtures}/SNIS-041.json +0 -0
- data/test/{fixtures → maker_fixtures}/SOE-259.json +0 -0
- data/test/{fixtures → maker_fixtures}/SPC-001.json +0 -0
- data/test/{fixtures → maker_fixtures}/SPS-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/SRS-015.json +0 -0
- data/test/{fixtures → maker_fixtures}/SSPD-077.json +0 -0
- data/test/{fixtures → maker_fixtures}/STAR-359.json +0 -0
- data/test/{fixtures → maker_fixtures}/SUPD-065.json +0 -0
- data/test/{fixtures → maker_fixtures}/TDT-018.json +0 -0
- data/test/{fixtures → maker_fixtures}/TMAM-034.json +0 -0
- data/test/{fixtures → maker_fixtures}/TMCY-039.json +0 -0
- data/test/{fixtures → maker_fixtures}/TMDI-040.json +0 -0
- data/test/{fixtures → maker_fixtures}/TMEM-044.json +0 -0
- data/test/{fixtures → maker_fixtures}/TMVI-042.json +0 -0
- data/test/{fixtures → maker_fixtures}/TRD-062.json +0 -0
- data/test/{fixtures → maker_fixtures}/TYOD-232.json +1 -1
- data/test/{fixtures → maker_fixtures}/URE-011.json +0 -0
- data/test/{fixtures → maker_fixtures}/WA-201.json +0 -0
- data/test/{fixtures → maker_fixtures}/WAT-003.json +0 -0
- data/test/{fixtures → maker_fixtures}/WPC-002.json +0 -0
- data/test/{fixtures → maker_fixtures}/WSS-231.json +1 -1
- data/test/{fixtures → maker_fixtures}/XND-023.json +0 -0
- data/test/{fixtures → maker_fixtures}/YRH-008.json +0 -0
- data/test/{fixtures → maker_fixtures}/YRZ-009.json +0 -0
- data/test/{fixtures → maker_fixtures}/ZEX-068.json +0 -0
- metadata +294 -292
@@ -1,66 +1,35 @@
|
|
1
|
-
|
1
|
+
base_uri 'www.javlibrary.com'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
module Site
|
7
|
-
include HTTParty
|
8
|
-
base_uri 'www.javlibrary.com'
|
9
|
-
follow_redirects false
|
3
|
+
def self.search_url(name)
|
4
|
+
"/ja/vl_searchbyid.php?keyword=#{CGI::escape(name)}"
|
5
|
+
end
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
rescue Errno::ETIMEDOUT => e
|
22
|
-
tries ||= 0
|
23
|
-
tries++
|
24
|
-
tries <= 5 ? retry : raise
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
module Parser
|
29
|
-
def self.parse_search_result(content)
|
30
|
-
html = Nokogiri::HTML(content)
|
31
|
-
first_result = html.css('#rightcolumn > div.videothumblist > div.videos > div.video > a').first
|
32
|
-
first_result['href'].remove('./?v=') if first_result
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.parse_item(content)
|
36
|
-
page_uri = content.request.last_uri
|
37
|
-
html = Nokogiri::HTML(content)
|
38
|
-
return {
|
39
|
-
actresses: html.css('#video_cast .text span.cast').map(&:text),
|
40
|
-
code: html.css('#video_id .text').text,
|
41
|
-
cover_image: html.at_css('#video_jacket > a')['href'],
|
42
|
-
directors: html.css('#video_director .text span.director').map(&:text),
|
43
|
-
genres: html.css('#video_genres .text span.genre').map(&:text),
|
44
|
-
label: html.css('#video_label .text').text,
|
45
|
-
maker: html.css('#video_maker .text').text,
|
46
|
-
movie_length: html.css('#video_length .text').text + ' minutes',
|
47
|
-
page: page_uri.to_s,
|
48
|
-
release_date: html.css('#video_date .text').text,
|
49
|
-
thumbnail_image: html.at_css('#video_jacket_img')['src'],
|
50
|
-
title: html.css('#video_title > h3').text.remove(html.css('#video_id .text').text),
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.search(name)
|
56
|
-
search_result = Site.search(name)
|
57
|
-
if search_result.code == 302
|
58
|
-
jav_id = search_result.headers['location'].remove('./?v=')
|
59
|
-
else
|
60
|
-
jav_id = Parser.parse_search_result(search_result)
|
61
|
-
end
|
62
|
-
Parser.parse_item(Site.item(jav_id)) if jav_id
|
63
|
-
end
|
64
|
-
end
|
7
|
+
def self.product_url(name)
|
8
|
+
search_page = get_with_retry search_url(name)
|
9
|
+
return nil unless search_page
|
10
|
+
if search_page.code == 302
|
11
|
+
url = search_page.headers['location']
|
12
|
+
else
|
13
|
+
search_html = Utils.html_in_utf8 search_page
|
14
|
+
first_result = search_html.at_css('#rightcolumn > div.videothumblist > div.videos > div.video > a')
|
15
|
+
return nil unless first_result
|
16
|
+
url = first_result['href']
|
65
17
|
end
|
66
|
-
|
18
|
+
URI.join(search_page.request.last_uri, url).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse_product_html(html)
|
22
|
+
{
|
23
|
+
actresses: html.css('#video_cast .text span.cast').map(&:text),
|
24
|
+
code: html.css('#video_id .text').text,
|
25
|
+
cover_image: html.at_css('#video_jacket > a')['href'],
|
26
|
+
directors: html.css('#video_director .text span.director').map(&:text),
|
27
|
+
genres: html.css('#video_genres .text span.genre').map(&:text),
|
28
|
+
label: html.css('#video_label .text').text,
|
29
|
+
maker: html.css('#video_maker .text').text,
|
30
|
+
movie_length: html.css('#video_length .text').text + ' minutes',
|
31
|
+
release_date: html.css('#video_date .text').text,
|
32
|
+
thumbnail_image: html.at_css('#video_jacket_img')['src'],
|
33
|
+
title: html.css('#video_title > h3').text.remove(html.css('#video_id .text').text),
|
34
|
+
}
|
35
|
+
end
|
data/lib/opendmm/site.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
require 'httparty'
|
3
|
+
require 'opendmm/utils'
|
4
|
+
|
5
|
+
module OpenDMM
|
6
|
+
module Site
|
7
|
+
|
8
|
+
def self.included(klass)
|
9
|
+
klass.mattr_accessor :url_generators
|
10
|
+
klass.mattr_accessor :code_generators
|
11
|
+
klass.url_generators = Hash.new
|
12
|
+
klass.code_generators = Hash.new
|
13
|
+
|
14
|
+
klass.include HTTParty
|
15
|
+
klass.follow_redirects false
|
16
|
+
|
17
|
+
klass.extend ClassMethods
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def get_with_retry(url, limit = 5)
|
22
|
+
return nil unless url
|
23
|
+
get url
|
24
|
+
rescue Errno::ETIMEDOUT => e
|
25
|
+
tries ||= 0
|
26
|
+
tries++
|
27
|
+
tries <= 5 ? retry : raise
|
28
|
+
end
|
29
|
+
|
30
|
+
def register_product(matcher, url_generator, code_generator = '#{$1.upcase}-#{$2}')
|
31
|
+
url_generators[matcher] = '"' + url_generator + '"'
|
32
|
+
code_generators[matcher] = '"' + code_generator + '"'
|
33
|
+
end
|
34
|
+
|
35
|
+
def product_url(name)
|
36
|
+
url_generators.each do |matcher, url_generator|
|
37
|
+
if name =~ matcher
|
38
|
+
return eval url_generator
|
39
|
+
end
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def product_code(name)
|
45
|
+
code_generators.each do |matcher, code_generator|
|
46
|
+
if name =~ matcher
|
47
|
+
return eval code_generator
|
48
|
+
end
|
49
|
+
end
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def product_extra_info(name, url, page, html)
|
54
|
+
Hash.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def product(name)
|
58
|
+
url = product_url name
|
59
|
+
page = get_with_retry url
|
60
|
+
return nil unless page
|
61
|
+
html = Utils.html_in_utf8 page
|
62
|
+
details = parse_product_html html
|
63
|
+
details[:code] ||= product_code name
|
64
|
+
details[:page] ||= page.request.last_uri.to_s
|
65
|
+
extra_info = product_extra_info(name, url, page, html)
|
66
|
+
extra_info.each do |k, v|
|
67
|
+
details[k] ||= v
|
68
|
+
end
|
69
|
+
Utils.finalize_details_hash details
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/opendmm/utils.rb
CHANGED
@@ -2,8 +2,10 @@ require 'active_support/core_ext/array/access'
|
|
2
2
|
require 'active_support/core_ext/array/grouping'
|
3
3
|
require 'active_support/core_ext/module/aliasing'
|
4
4
|
require 'active_support/core_ext/numeric/time'
|
5
|
+
require 'active_support/core_ext/string/filters'
|
5
6
|
require 'active_support/core_ext/string/starts_ends_with'
|
6
7
|
require 'chronic_duration'
|
8
|
+
require 'nokogiri'
|
7
9
|
|
8
10
|
class << Date
|
9
11
|
def parse_with_chinese_support(str)
|
@@ -61,13 +63,31 @@ module OpenDMM
|
|
61
63
|
end.to_h
|
62
64
|
end
|
63
65
|
|
64
|
-
def self.
|
66
|
+
def self.html_in_utf8(content)
|
65
67
|
# This is to get rid of the annoying error message:
|
66
68
|
# 'encoding error : input conversion failed due to input error'
|
67
69
|
$stderr.reopen('/dev/null', 'w')
|
68
|
-
encoding = Nokogiri
|
70
|
+
encoding = Nokogiri.HTML(content).encoding
|
69
71
|
$stderr = STDERR
|
70
72
|
content = content.encode('UTF-8', encoding, invalid: :replace, undef: :replace, replace: '')
|
73
|
+
Nokogiri.HTML content
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.finalize_details_hash(details)
|
77
|
+
details = details.squish_hard
|
78
|
+
details[:cover_image] = join_url_if_relative(details[:page], details[:cover_image])
|
79
|
+
details[:thumbnail_image] = join_url_if_relative(details[:page], details[:thumbnail_image])
|
80
|
+
details[:sample_images] = details[:sample_images].map do |uri|
|
81
|
+
join_url_if_relative(details[:page], uri)
|
82
|
+
end if details[:sample_images]
|
83
|
+
details[:movie_length] = ChronicDuration.parse(details[:movie_length]) if details[:movie_length]
|
84
|
+
details[:release_date] = Date.parse(details[:release_date]) if details[:release_date]
|
85
|
+
details.sort.to_h
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.join_url_if_relative(page_url, image_url)
|
89
|
+
return nil unless image_url
|
90
|
+
image_url.start_with?('http') ? image_url : URI.join(page_url, image_url).to_s
|
71
91
|
end
|
72
92
|
end
|
73
93
|
end
|
data/lib/opendmm/version.rb
CHANGED
data/test/fixture_test.rb
CHANGED
@@ -56,19 +56,23 @@ class FixtureTest < Minitest::Test
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
{ 'dmm' => 'OpenDMM::SearchEngine::Dmm',
|
60
|
+
'jav_library' => 'OpenDMM::SearchEngine::JavLibrary',
|
61
|
+
'maker' => 'OpenDMM::Maker' }.each do |category, klass|
|
62
|
+
Dir[File.dirname(__FILE__) + "/#{category}_fixtures/*.json"].each do |file|
|
63
|
+
name = File.basename(file, '.json')
|
64
|
+
eval <<-TESTCASE
|
62
65
|
|
63
|
-
class FixtureTest
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
class FixtureTest
|
67
|
+
def test_#{category}_#{name.parameterize.underscore}
|
68
|
+
expected = load_product('#{file}')
|
69
|
+
actual = #{klass}.search('#{name}')
|
70
|
+
assert_has_basic_keys(actual)
|
71
|
+
assert_no_unknown_keys(actual)
|
72
|
+
assert_equal expected, actual, HashDiff.diff(expected, actual)
|
73
|
+
end
|
70
74
|
end
|
71
|
-
end
|
72
75
|
|
73
|
-
TESTCASE
|
74
|
-
end
|
76
|
+
TESTCASE
|
77
|
+
end
|
78
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -3,7 +3,7 @@
|
|
3
3
|
"大槻ひびき"
|
4
4
|
],
|
5
5
|
"brand": "AIR*WAAP",
|
6
|
-
"code": "
|
6
|
+
"code": "AIR-017",
|
7
7
|
"cover_image": "http://www.waap.co.jp/hskhsk/itsub/AIR017.jpg",
|
8
8
|
"description": "肉厚で長いベロを持つガーリーなひびき嬢が、目隠しされて悦んでるドMのオッサンを、全身リップでゾクゾクさせちゃう。特にチクビを重点的に責め尽くし、チ●コをギン勃ちさせると、敏感な裏スジを丹念に舐めあげ吸引し、アナル舐めまでヤリタイ放題した後、ちくび責めと手コキで「ダメダメ」と罵られ、何度も寸止めされてヘロヘロのM男の顔面に、アソコを押しつけ強制クンニさせてアクメる。インサートは騎乗位からで、この腰使いはエロスネーク。半狂乱でイキまくって汗まみれで、フィニッシュ!",
|
9
9
|
"genres": [
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"actresses": [
|
3
3
|
"MARI[まり]"
|
4
4
|
],
|
5
|
-
"code": "
|
5
|
+
"code": "AKO-011",
|
6
6
|
"cover_image": "http://www.ako-3.com/img/jacket/AKO011.jpg",
|
7
7
|
"description": "コスプレしてみたりソフトSMをしてみたいというMARIちゃんは、爽やかイケメンがタイプで男に関しては色々うるさそう。そんな彼女のお餅みたく白くて柔らかい上物パイオツをぺろぺろナメナメしたり、アソコをぐっちょぐっちょ掻き回すと、カワイイ声で喘ぐスケベちゃんに豹変。で、ズッポリ挿入、フィニッシュは舌上、で、ごっくんしてくれたよ。で、おまけに、セックス後のシャワー室に侵入し、俺の乳首をイジらせ、フェラに持ち込み「ぐえっ」っと咽る彼女を尻目に精子を舐めさせちゃったぜ!",
|
8
8
|
"maker": "A子さん",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -3,7 +3,7 @@
|
|
3
3
|
"愛沢有紗"
|
4
4
|
],
|
5
5
|
"brand": "CLUB WAAP",
|
6
|
-
"code": "
|
6
|
+
"code": "CWM-156",
|
7
7
|
"cover_image": "http://www.waap.co.jp/hskhsk/itsub/CWM156.jpg",
|
8
8
|
"description": "日焼け跡を、ワシヅカミ☆ 真っ黒にこんがり灼けたボディに残るセクシーな水着の日焼け跡が、褐色の肢体にくっきりと卑猥に浮かぶことで自らを常に欲情的に燃え上がらせ、自然とオトコを挑発する情熱的なフェロモンを撒き散らす。金麦色の肌にくっきりと浮かぶ乳房に性交というカタチで吐き出される、全編・巨乳&日焼け跡フェチ要素100%の灼熱セックス130分!! 全5編。",
|
9
9
|
"directors": [
|
File without changes
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"actresses": [
|
3
3
|
"鈴木心春"
|
4
4
|
],
|
5
|
-
"code": "
|
5
|
+
"code": "DCOL-017",
|
6
6
|
"cover_image": "http://dmm-collection.com/images/works/dcol017/dcol017pl.jpg",
|
7
7
|
"description": "鈴木心春がレイプ作品解禁!白く美しい肌と完璧な巨乳を持つ人妻は知らず知らずのうちに周囲の男性達を誘惑してしまい、夫の留守中に水道局員が訪れた時、悲劇は始まった。夫に言えない秘密を背負ってしまった心春を襲うレイプの連鎖。抵抗できない人妻に男達が容赦なく肉棒を突き刺します!",
|
8
8
|
"maker": "D★Collection",
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"actresses": [
|
3
3
|
"宮崎ちひろ"
|
4
4
|
],
|
5
|
-
"code": "
|
5
|
+
"code": "DGL-007",
|
6
6
|
"cover_image": "http://dmm-collection.com/images/works/dgl007/dgl007pl.jpg",
|
7
7
|
"description": "衝撃のデビュー作から1年、たった1作のみの出演でAV界から姿を消した伝説の美女優が復活!男を誘惑する視線とパーフェクトなカラダは更に妖艶さを増し、激しいイキっぷりももちろん健在!芸能人美●うらんDコレ専属復活作です!",
|
8
8
|
"maker": "D★Collection",
|
File without changes
|
File without changes
|
@@ -3,7 +3,7 @@
|
|
3
3
|
"向井恋"
|
4
4
|
],
|
5
5
|
"brand": "est WAAP",
|
6
|
-
"code": "
|
6
|
+
"code": "ECB-078",
|
7
7
|
"cover_image": "http://www.waap.co.jp/hskhsk/itsub/ECB078.jpg",
|
8
8
|
"description": "このオンナ、下品なクセしてキレイ好き。 ドスケベフェロモン出っ放しのお姉さん・向井恋が、卑猥な口唇からヨダレをダラダラ垂らしながら、M男チ●ポにむしゃぶりついて精子を頂戴する。汁まみれになった射精後の敏感チ●ポにも、容赦ないお掃除フェラで徹底バキュームして、汁という汁が干からびるまでエンドレスに求め続ける、超肉食系淫女のアドリブごっくん&お掃除痴女ライブ!! 全4編。",
|
9
9
|
"directors": [
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"actresses": [
|
3
3
|
"横山美雪"
|
4
4
|
],
|
5
|
-
"code": "
|
5
|
+
"code": "KAWD-249",
|
6
6
|
"cover_image": "http://kawaiikawaii.jp/images/works/kawd249/kawd249pl.jpg",
|
7
7
|
"description": "オナニー快感に憑りつかれてしまった看護師・美雪☆夜勤がある日も無い日も毎日オナニー。少しずつ寝る時間が短くなりオナニーする時間のほうが長くなっちゃった!チンポも精子もズリネタ同然♪盗撮させてエッチ!クリ激擦り3P!見せ付けオナセックchu!全6コーナー収録!",
|
8
8
|
"genres": [
|