opendmm 0.0.2

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.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +3 -0
  5. data/README.md +9 -0
  6. data/Rakefile +77 -0
  7. data/bin/opendmm +24 -0
  8. data/lib/opendmm.rb +9 -0
  9. data/lib/opendmm/maker.rb +60 -0
  10. data/lib/opendmm/makers/aknr.rb +38 -0
  11. data/lib/opendmm/makers/ako3.rb +39 -0
  12. data/lib/opendmm/makers/anna_and_hanako.rb +40 -0
  13. data/lib/opendmm/makers/apa.rb +40 -0
  14. data/lib/opendmm/makers/aroma.rb +63 -0
  15. data/lib/opendmm/makers/attackers.rb +55 -0
  16. data/lib/opendmm/makers/aurora.rb +45 -0
  17. data/lib/opendmm/makers/baltan.rb +40 -0
  18. data/lib/opendmm/makers/befree.rb +42 -0
  19. data/lib/opendmm/makers/bi.rb +44 -0
  20. data/lib/opendmm/makers/bijin_majo.rb +39 -0
  21. data/lib/opendmm/makers/candy.rb +41 -0
  22. data/lib/opendmm/makers/caribbean.rb +40 -0
  23. data/lib/opendmm/makers/dip.rb +43 -0
  24. data/lib/opendmm/makers/dmm_collection.rb +39 -0
  25. data/lib/opendmm/makers/ebody.rb +42 -0
  26. data/lib/opendmm/makers/ideapocket.rb +68 -0
  27. data/lib/opendmm/makers/kawaii.rb +41 -0
  28. data/lib/opendmm/makers/kira_kira.rb +41 -0
  29. data/lib/opendmm/makers/madonna.rb +41 -0
  30. data/lib/opendmm/makers/moodyz.rb +48 -0
  31. data/lib/opendmm/makers/munekyunkissa.rb +42 -0
  32. data/lib/opendmm/makers/opera.rb +47 -0
  33. data/lib/opendmm/makers/oppai.rb +57 -0
  34. data/lib/opendmm/makers/premium.rb +43 -0
  35. data/lib/opendmm/makers/prestige.rb +66 -0
  36. data/lib/opendmm/makers/s1.rb +41 -0
  37. data/lib/opendmm/makers/sod.rb +44 -0
  38. data/lib/opendmm/makers/tameikegoro.rb +42 -0
  39. data/lib/opendmm/makers/to_satsu.rb +40 -0
  40. data/lib/opendmm/makers/waap.rb +46 -0
  41. data/lib/opendmm/search_engines/jav_library.rb +58 -0
  42. data/lib/opendmm/utils.rb +119 -0
  43. data/lib/opendmm/version.rb +3 -0
  44. data/opendmm.gemspec +25 -0
  45. data/test/fixtures/ABP-013.json +33 -0
  46. data/test/fixtures/ABS-014.json +31 -0
  47. data/test/fixtures/ABY-003.json +32 -0
  48. data/test/fixtures/ADN-019.json +37 -0
  49. data/test/fixtures/AIR-017.json +34 -0
  50. data/test/fixtures/AKO-011.json +20 -0
  51. data/test/fixtures/ALB-182.json +31 -0
  52. data/test/fixtures/ANND-066.json +29 -0
  53. data/test/fixtures/AP-001.json +24 -0
  54. data/test/fixtures/APAA-182.json +38 -0
  55. data/test/fixtures/APAK-051.json +42 -0
  56. data/test/fixtures/ARM-191.json +28 -0
  57. data/test/fixtures/ARMG-223.json +27 -0
  58. data/test/fixtures/ATID-183.json +41 -0
  59. data/test/fixtures/BBI-104.json +33 -0
  60. data/test/fixtures/BEB-001.json +35 -0
  61. data/test/fixtures/BF-175.json +31 -0
  62. data/test/fixtures/BID-017.json +40 -0
  63. data/test/fixtures/BIJN-006.json +25 -0
  64. data/test/fixtures/BLK-049.json +27 -0
  65. data/test/fixtures/BRA-002.json +34 -0
  66. data/test/fixtures/BWB-005.json +31 -0
  67. data/test/fixtures/CHN-008.json +31 -0
  68. data/test/fixtures/CHS-015.json +32 -0
  69. data/test/fixtures/CLUB-003.json +22 -0
  70. data/test/fixtures/CND-012.json +29 -0
  71. data/test/fixtures/CWM-156.json +34 -0
  72. data/test/fixtures/Carib 021511-620.json +27 -0
  73. data/test/fixtures/DCOL-017.json +25 -0
  74. data/test/fixtures/DGL-007.json +24 -0
  75. data/test/fixtures/DOM-045.json +36 -0
  76. data/test/fixtures/EBOD-109.json +30 -0
  77. data/test/fixtures/ECB-078.json +33 -0
  78. data/test/fixtures/EDD-189.json +33 -0
  79. data/test/fixtures/ESK-232.json +31 -0
  80. data/test/fixtures/EZD-369.json +32 -0
  81. data/test/fixtures/FSET-399.json +40 -0
  82. data/test/fixtures/HAZ-009.json +33 -0
  83. data/test/fixtures/HON-001.json +31 -0
  84. data/test/fixtures/IDBD-447.json +32 -0
  85. data/test/fixtures/INU-013.json +34 -0
  86. data/test/fixtures/IPSD-041.json +40 -0
  87. data/test/fixtures/IPTD-464.json +35 -0
  88. data/test/fixtures/IPTD-629.json +32 -0
  89. data/test/fixtures/IPZ-005.json +35 -0
  90. data/test/fixtures/JBD-153.json +42 -0
  91. data/test/fixtures/JBS-004.json +32 -0
  92. data/test/fixtures/JOB-010.json +33 -0
  93. data/test/fixtures/JUC-285.json +36 -0
  94. data/test/fixtures/JUFD-137.json +33 -0
  95. data/test/fixtures/JUX-007.json +35 -0
  96. data/test/fixtures/JUX-119.json +35 -0
  97. data/test/fixtures/KAWD-249.json +30 -0
  98. data/test/fixtures/KIRD-147.json +28 -0
  99. data/test/fixtures/KISD-042.json +32 -0
  100. data/test/fixtures/LLR-005.json +35 -0
  101. data/test/fixtures/MAS-042.json +36 -0
  102. data/test/fixtures/MBD-148.json +32 -0
  103. data/test/fixtures/MDC-002.json +33 -0
  104. data/test/fixtures/MDYD-544.json +34 -0
  105. data/test/fixtures/MEK-008.json +32 -0
  106. data/test/fixtures/MIAD-490.json +34 -0
  107. data/test/fixtures/MIDD-599.json +36 -0
  108. data/test/fixtures/MIDD-643.json +32 -0
  109. data/test/fixtures/MIDD-644.json +30 -0
  110. data/test/fixtures/MIDE-004.json +34 -0
  111. data/test/fixtures/MIGD-284.json +34 -0
  112. data/test/fixtures/MIGD-336.json +33 -0
  113. data/test/fixtures/MIGD-337.json +35 -0
  114. data/test/fixtures/MIMK-005.json +36 -0
  115. data/test/fixtures/MINT-004.json +35 -0
  116. data/test/fixtures/MIQD-010.json +27 -0
  117. data/test/fixtures/MIRD-071.json +41 -0
  118. data/test/fixtures/MIRD-072.json +47 -0
  119. data/test/fixtures/MIRD-073.json +38 -0
  120. data/test/fixtures/MIXS-005.json +34 -0
  121. data/test/fixtures/MMY-010.json +32 -0
  122. data/test/fixtures/NAGE-001.json +33 -0
  123. data/test/fixtures/NDR-001.json +32 -0
  124. data/test/fixtures/NOF-003.json +36 -0
  125. data/test/fixtures/NPS-130.json +18 -0
  126. data/test/fixtures/OBA-045.json +35 -0
  127. data/test/fixtures/ONSD-570.json +29 -0
  128. data/test/fixtures/OPUD-125.json +46 -0
  129. data/test/fixtures/OSR-003.json +32 -0
  130. data/test/fixtures/PARM-028.json +21 -0
  131. data/test/fixtures/PBD-134.json +29 -0
  132. data/test/fixtures/PGD-306.json +34 -0
  133. data/test/fixtures/PJD-085.json +31 -0
  134. data/test/fixtures/PPB-008.json +31 -0
  135. data/test/fixtures/PPP-001.json +45 -0
  136. data/test/fixtures/PPPD-102.json +33 -0
  137. data/test/fixtures/PPSD-028.json +40 -0
  138. data/test/fixtures/PPT-004.json +31 -0
  139. data/test/fixtures/PTS-230.json +17 -0
  140. data/test/fixtures/PTV-001.json +28 -0
  141. data/test/fixtures/PXD-027.json +37 -0
  142. data/test/fixtures/RAW-005.json +32 -0
  143. data/test/fixtures/RBD-183.json +40 -0
  144. data/test/fixtures/SAD-031.json +35 -0
  145. data/test/fixtures/SDDE-312.json +34 -0
  146. data/test/fixtures/SDMT-802.json +32 -0
  147. data/test/fixtures/SDMU-008.json +38 -0
  148. data/test/fixtures/SDNM-011.json +37 -0
  149. data/test/fixtures/SET-007.json +32 -0
  150. data/test/fixtures/SGA-001.json +31 -0
  151. data/test/fixtures/SHKD-415.json +38 -0
  152. data/test/fixtures/SNIS-041.json +34 -0
  153. data/test/fixtures/SOE-259.json +31 -0
  154. data/test/fixtures/SPC-001.json +31 -0
  155. data/test/fixtures/SPS-008.json +32 -0
  156. data/test/fixtures/SRS-015.json +32 -0
  157. data/test/fixtures/SSPD-077.json +44 -0
  158. data/test/fixtures/STAR-359.json +33 -0
  159. data/test/fixtures/SUPD-065.json +41 -0
  160. data/test/fixtures/TDT-018.json +31 -0
  161. data/test/fixtures/TMAM-034.json +14 -0
  162. data/test/fixtures/TMCY-039.json +14 -0
  163. data/test/fixtures/TMDI-040.json +14 -0
  164. data/test/fixtures/TMEM-044.json +14 -0
  165. data/test/fixtures/TMVI-042.json +14 -0
  166. data/test/fixtures/TRD-062.json +31 -0
  167. data/test/fixtures/URE-011.json +38 -0
  168. data/test/fixtures/WA-201.json +17 -0
  169. data/test/fixtures/WAT-003.json +33 -0
  170. data/test/fixtures/WPC-002.json +35 -0
  171. data/test/fixtures/WSS-231.json +33 -0
  172. data/test/fixtures/XND-023.json +32 -0
  173. data/test/fixtures/XV-100.json +18 -0
  174. data/test/fixtures/XV-1000.json +24 -0
  175. data/test/fixtures/YRH-008.json +35 -0
  176. data/test/fixtures/YRZ-009.json +32 -0
  177. data/test/fixtures/ZEX-068.json +18 -0
  178. data/test/fixtures_test.rb +76 -0
  179. metadata +454 -0
@@ -0,0 +1,44 @@
1
+ module OpenDMM
2
+ module Maker
3
+ module Sod
4
+ include Maker
5
+
6
+ module Site
7
+ include HTTParty
8
+ base_uri 'ec.sod.co.jp'
9
+
10
+ def self.item(name)
11
+ case name
12
+ when /^(NAGE|SDDE|SDMT|SDMU|SDNM|STAR)-?(\d{3})$/i
13
+ get("/detail/index/-_-/iid/#{$1.upcase}-#{$2}")
14
+ end
15
+ end
16
+ end
17
+
18
+ module Parser
19
+ def self.parse(content)
20
+ page_uri = content.request.last_uri
21
+ html = Nokogiri::HTML(content)
22
+ specs = Utils.hash_by_split(html.xpath('//*[@id="main"]/tr/td[2]/table/tr[1]/td[1]/table/tr[1]/td/table/tr/td[2]/table/tr').map(&:text))
23
+ return {
24
+ actresses: specs['出演'].split,
25
+ code: specs['品番'],
26
+ cover_image: html.at_xpath('//*[@id="main"]/tr/td[2]/table/tr[1]/td[1]/table/tr[1]/td/table/tr/td[1]/a[1]')['href'],
27
+ description: html.css('div.detail-datacomment').text,
28
+ directors: specs['監督'].split,
29
+ genres: specs['ジャンル'].split,
30
+ label: specs['レーベル'],
31
+ maker: specs['メーカー'],
32
+ movie_length: specs['収録時間'],
33
+ page: page_uri.to_s,
34
+ release_date: specs['発売日'],
35
+ sample_images: html.css('div.detail-thumb-sample-box > a').map { |a| a['href'] },
36
+ series: specs['シリーズ'],
37
+ thumbnail_image: html.at_xpath('//*[@id="main"]/tr/td[2]/table/tr[1]/td[1]/table/tr[1]/td/table/tr/td[1]/a[1]/img')['src'],
38
+ title: html.css('div.title-base > div.title-base-dvd1 > div.title-base-dvd2 > h1').text,
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,42 @@
1
+ module OpenDMM
2
+ module Maker
3
+ module Tameikegoro
4
+ include Maker
5
+
6
+ module Site
7
+ include HTTParty
8
+ base_uri 'tameikegoro.jp'
9
+
10
+ def self.item(name)
11
+ case name
12
+ when /^(MDYD)-?(\d{3})$/i
13
+ get("/works/-/detail/=/cid=#{$1.downcase}#{$2}")
14
+ end
15
+ end
16
+ end
17
+
18
+ module Parser
19
+ def self.parse(content)
20
+ page_uri = content.request.last_uri
21
+ html = Nokogiri::HTML(content)
22
+ specs = Utils.hash_by_split(html.css('#work-detail > h4, p').map(&:text))
23
+ return {
24
+ actresses: specs['出演女優'].split,
25
+ code: specs['品番'],
26
+ cover_image: html.at_css('#work-pake')['src'].gsub(/pm.jpg$/, 'pl.jpg'),
27
+ description: html.css('#work-detail > h5').text,
28
+ directors: specs['監督'].split,
29
+ genres: specs['ジャンル'].split,
30
+ label: specs['レーベル'],
31
+ page: page_uri.to_s,
32
+ release_date: specs['発売日'].remove('DVD/'),
33
+ sample_images: html.css('#sample-pic > a > img').map { |img| img['src'].gsub(/js(?=-\d+\.jpg)/, 'jp') },
34
+ series: specs['シリーズ'],
35
+ thumbnail_image: html.at_css('#work-pake')['src'],
36
+ title: html.css('#work-detail > h3').text,
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ module OpenDMM
2
+ module Maker
3
+ module ToSatsu
4
+ include Maker
5
+
6
+ module Site
7
+ include HTTParty
8
+ base_uri 'to-satsu.com'
9
+
10
+ def self.item(name)
11
+ case name
12
+ when /^(CLUB)-?(\d{3})$/i
13
+ get("/works/#{$1.downcase}/#{$1.downcase}#{$2}/#{$1.downcase}#{$2}.html")
14
+ end
15
+ end
16
+ end
17
+
18
+ module Parser
19
+ def self.parse(content)
20
+ page_uri = content.request.last_uri
21
+ html = Nokogiri::HTML(content)
22
+ specs = Utils.hash_from_dl(html.css('#main > div > div.main-detail > div.ttl-data > dl'))
23
+ return {
24
+ code: specs['品番:'].text,
25
+ cover_image: html.at_css('#main > div > div.main-detail > div.ttl-pac > a')['href'],
26
+ description: html.xpath('//*[@id="main"]/div/div[@class="main-detail"]/div[@class="ttl-comment"]/div[not(@class)]').text,
27
+ genres: specs['ジャンル:'].text,
28
+ movie_length: specs['収録時間:'].text,
29
+ page: page_uri.to_s,
30
+ release_date: specs['発売日:'].text,
31
+ sample_images: html.css('#main > div > div.main-detail > div.ttl-sample > img').map { |img| img['src'] },
32
+ series: specs['シリーズ:'].text,
33
+ thumbnail_image: html.at_css('#main > div > div.main-detail > div.ttl-pac > a > img')['src'],
34
+ title: html.css('#main > div > div.capt2').text,
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ module OpenDMM
2
+ module Maker
3
+ module Waap
4
+ include Maker
5
+
6
+ module Site
7
+ include HTTParty
8
+ base_uri 'www.waap.co.jp'
9
+
10
+ def self.item(name)
11
+ name =~ /(\w+)-?(\d+)/
12
+ case name
13
+ when /^(AIR|CWM|ECB|WSS)-?(\d{3})$/i
14
+ get("/work/item.php?itemcode=#{$1.upcase}#{$2}")
15
+ end
16
+ end
17
+ end
18
+
19
+ module Parser
20
+ def self.parse(content)
21
+ page_uri = content.request.last_uri
22
+ html = Nokogiri::HTML(content)
23
+ specs = Utils.hash_by_split(html.css('ul.title_shosai li.wkact_ser_maker02').map(&:text))
24
+ return {
25
+ actresses: specs['出演者'].split,
26
+ brand: specs['ブランド'],
27
+ code: specs['品番'],
28
+ cover_image: html.at_css('ul#title_img_all li.title_img a')['href'],
29
+ description: html.css('div#title_cmt_all').text,
30
+ directors: specs['監督'].split,
31
+ genres: specs['ジャンル'].split,
32
+ label: specs['レーベル'],
33
+ maker: specs['メーカー'],
34
+ movie_length: specs['収録時間'],
35
+ page: page_uri.to_s,
36
+ release_date: specs['発売日'],
37
+ sample_images: html.css('ul.samplepicture_list li a').map { |a| a['href'] },
38
+ series: specs['シリーズ'],
39
+ thumbnail_image: html.at_css('#title_img_all > li.title_img > a > img')['src'],
40
+ title: html.css('ul#pan_list li').last.text,
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ require 'opendmm/utils'
2
+
3
+ module OpenDMM
4
+ module SearchEngine
5
+ module JavLibrary
6
+ module Site
7
+ include HTTParty
8
+ base_uri 'www.javlibrary.com'
9
+ follow_redirects false
10
+
11
+ def self.search(name)
12
+ get("/ja/vl_searchbyid.php?keyword=#{name}")
13
+ end
14
+
15
+ def self.item(id)
16
+ get("/ja/?v=#{id}")
17
+ end
18
+ end
19
+
20
+ module Parser
21
+ def self.parse_search_result(content)
22
+ html = Nokogiri::HTML(content)
23
+ first_result = html.css('#rightcolumn > div.videothumblist > div.videos > div.video > a').first
24
+ first_result['href'].remove('./?v=') if first_result
25
+ end
26
+
27
+ def self.parse_item(content)
28
+ page_uri = content.request.last_uri
29
+ html = Nokogiri::HTML(content)
30
+ return {
31
+ actresses: html.css('#video_cast .text span.cast').map(&:text),
32
+ code: html.css('#video_id .text').text,
33
+ cover_image: html.at_css('#video_jacket > a')['href'],
34
+ directors: html.css('#video_director .text span.director').map(&:text),
35
+ genres: html.css('#video_genres .text span.genre').map(&:text),
36
+ label: html.css('#video_label .text').text,
37
+ maker: html.css('#video_maker .text').text,
38
+ movie_length: html.css('#video_length .text').text + ' minutes',
39
+ page: page_uri.to_s,
40
+ release_date: html.css('#video_date .text').text,
41
+ thumbnail_image: html.at_css('#video_jacket_img')['src'],
42
+ title: html.css('#video_title > h3').text.remove(html.css('#video_id .text').text),
43
+ }
44
+ end
45
+ end
46
+
47
+ def self.search(name)
48
+ search_result = Site.search(name)
49
+ if search_result.code == 302
50
+ jav_id = search_result.headers['location'].remove('./?v=')
51
+ else
52
+ jav_id = Parser.parse_search_result(search_result)
53
+ end
54
+ Parser.parse_item(Site.item(jav_id)) if jav_id
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,119 @@
1
+ require 'active_support/core_ext/array/access'
2
+ require 'active_support/core_ext/array/grouping'
3
+ require 'active_support/core_ext/module/aliasing'
4
+ require 'active_support/core_ext/numeric/time'
5
+ require 'active_support/core_ext/string/starts_ends_with'
6
+ require 'chronic_duration'
7
+
8
+ class << Date
9
+ def parse_with_chinese_support(str)
10
+ case str
11
+ when /(\d{4})年(\d{1,2})月(\d{1,2})日/
12
+ return new($1.to_i, $2.to_i, $3.to_i)
13
+ else
14
+ return parse_without_chinese_support(str)
15
+ end
16
+ end
17
+ alias_method_chain :parse, :chinese_support
18
+ end
19
+
20
+ class << ChronicDuration
21
+ def parse_with_chinese_support(str)
22
+ case str
23
+ when /(\d+)(\s*)分/
24
+ return $1.to_i.minutes
25
+ else
26
+ return parse_without_chinese_support(str)
27
+ end
28
+ end
29
+ alias_method_chain :parse, :chinese_support
30
+ end
31
+
32
+ class NilClass
33
+ def text
34
+ ''
35
+ end
36
+ end
37
+
38
+ module OpenDMM
39
+ module Utils
40
+ def self.hash_from_dl(dl)
41
+ dts = dl.css('dt').map(&:text).map(&:squish)
42
+ dds = dl.children.select do |node|
43
+ node.name == 'dt' || node.name == 'dd'
44
+ end.split do |node|
45
+ node.name == 'dt'
46
+ end[1..-1].map do |nodes|
47
+ node_set = Nokogiri::XML::NodeSet.new(dl.document)
48
+ nodes.each do |node|
49
+ node_set << node
50
+ end
51
+ node_set
52
+ end
53
+ Hash[dts.zip(dds)]
54
+ end
55
+
56
+ def self.hash_by_split(array, delimiter = /[::]/)
57
+ array.map do |str|
58
+ slices = str.split(delimiter, 2).map(&:squish)
59
+ end.select do |pair|
60
+ pair.size == 2
61
+ end.to_h
62
+ end
63
+
64
+ def self.force_utf8(content)
65
+ # This is to get rid of the annoying error message:
66
+ # 'encoding error : input conversion failed due to input error'
67
+ $stderr.reopen('/dev/null', 'w')
68
+ encoding = Nokogiri::HTML(content).encoding
69
+ $stderr = STDERR
70
+ content = content.encode('UTF-8', encoding, invalid: :replace, undef: :replace, replace: '')
71
+ end
72
+
73
+ def self.cleanup(details)
74
+ return nil unless details
75
+ details = self.squish(details)
76
+ if details[:movie_length].instance_of? String
77
+ details[:movie_length] = ChronicDuration.parse(details[:movie_length])
78
+ end
79
+ if details[:page]
80
+ if details[:cover_image] && !details[:cover_image].start_with?('http')
81
+ details[:cover_image] = URI.join(details[:page], details[:cover_image]).to_s
82
+ end
83
+ if details[:sample_images]
84
+ details[:sample_images] = details[:sample_images].map do |uri|
85
+ uri.start_with?('http') ? uri : URI.join(details[:page], uri).to_s
86
+ end
87
+ end
88
+ if details[:thumbnail_image] && !details[:thumbnail_image].start_with?('http')
89
+ details[:thumbnail_image] = URI.join(details[:page], details[:thumbnail_image]).to_s
90
+ end
91
+ end
92
+ if details[:release_date].instance_of? String
93
+ details[:release_date] = Date.parse(details[:release_date])
94
+ end
95
+ details
96
+ end
97
+
98
+ def self.squish(obj)
99
+ case obj
100
+ when String
101
+ obj.squish!
102
+ obj.gsub!(/^[\s-]*$/, '')
103
+ when Hash
104
+ obj = obj.map do |k, v|
105
+ [k, squish(v)]
106
+ end.select do |kv|
107
+ kv.second.present?
108
+ end.to_h.symbolize_keys
109
+ when Array
110
+ obj = obj.map do |v|
111
+ squish(v)
112
+ end.select do |v|
113
+ v.present?
114
+ end
115
+ end
116
+ return obj.present? ? obj : nil
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,3 @@
1
+ module OpenDMM
2
+ VERSION = '0.0.2'
3
+ end
data/opendmm.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'opendmm/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'opendmm'
7
+ spec.version = OpenDMM::VERSION
8
+ spec.authors = ['Jun Zhou']
9
+ spec.email = ['pinepara@gmail.com']
10
+ spec.summary = 'OpenDMM: an open-source Japanese AV search engine'
11
+ spec.license = 'MIT'
12
+
13
+ spec.files = `git ls-files`.lines.map(&:chomp)
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_development_dependency 'bundler'
19
+ spec.add_development_dependency 'hashdiff'
20
+ spec.add_development_dependency 'rake'
21
+ spec.add_dependency 'activesupport'
22
+ spec.add_dependency 'chronic_duration'
23
+ spec.add_dependency 'httparty'
24
+ spec.add_dependency 'nokogiri'
25
+ end
@@ -0,0 +1,33 @@
1
+ {
2
+ "actresses": [
3
+ "水咲(滝澤)ローラ"
4
+ ],
5
+ "code": "ABP-013",
6
+ "cover_image": "http://image.prestige-av.com/images/prestige/abp/013/pb_e_abp-013.jpg",
7
+ "description": "通販限定商品!生写真7枚付きの特典商品です。本数限定となりますのでお早めにお求め下さい!!プレステージ専属女優 『水咲 ローラ』 が熱気を漂わせながら超濃厚なセックスを展開!男と相互奉仕の応酬をして、貪るような肉食っぷりを披露!焦らされたカラダは手マンされ、カメラが水没するほど何度も大量潮吹き!パイパンマ〇コにパワフルな腰使いでピストンされ、本気汁まみれで悶えっぱなし!!",
8
+ "genres": [
9
+ "通販限定",
10
+ "潮吹き",
11
+ "女優",
12
+ "パイパン"
13
+ ],
14
+ "label": "ABSOLUTELY P…",
15
+ "maker": "プレステージ",
16
+ "movie_length": 7200,
17
+ "page": "http://www.prestige-av.com/item/prestige/ABP-013",
18
+ "release_date": "2013-07-02",
19
+ "sample_images": [
20
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_0_abp-013.jpg",
21
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_1_abp-013.jpg",
22
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_2_abp-013.jpg",
23
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_3_abp-013.jpg",
24
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_4_abp-013.jpg",
25
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_5_abp-013.jpg",
26
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_6_abp-013.jpg",
27
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_7_abp-013.jpg",
28
+ "http://image.prestige-av.com/images/prestige/abp/013/cap_e_8_abp-013.jpg"
29
+ ],
30
+ "series": "天然成分由来",
31
+ "thumbnail_image": "http://image.prestige-av.com/images/prestige/abp/013/pf_p_abp-013.jpg",
32
+ "title": "天然成分由来 水咲ローラ汁120%+生写真7枚付き"
33
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "actresses": [
3
+ "絵色 千佳"
4
+ ],
5
+ "code": "ABS-014",
6
+ "cover_image": "http://image.prestige-av.com/images/prestige/abs/014/pb_e_abs-014.jpg",
7
+ "description": "お嬢様系の超美少女が登場。イラマチオ気味にフェラさせられたチ○コをマ○コに突き挿され快感にウットリ。中出しされピンク色のマ○コから精子を垂らしピクピク痙攣も見逃せない。男の大きな足をゆっくりと舐め出し、ネットリとした舌使いで激エロ奉仕。四つん這いやチングリ返しになった男の尻を目を閉じて舐めるシーンもエロ過ぎ!学生服姿で肛門丸見えにさせられたり潮吹きもエロい!3Pになりバックから美尻をプルンプルン波打たせながら打ち込まれ本番になり、角度を変えてピストンされ発射は口へ。連続でハメられ2度目も口に掛けられお掃除",
8
+ "genres": [
9
+ "潮吹き",
10
+ "女優",
11
+ "中出し"
12
+ ],
13
+ "label": "ABSOLUTE",
14
+ "maker": "プレステージ",
15
+ "movie_length": 7200,
16
+ "page": "http://www.prestige-av.com/item/prestige/ABS-014",
17
+ "release_date": "2011-02-08",
18
+ "sample_images": [
19
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_0_abs-014.jpg",
20
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_1_abs-014.jpg",
21
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_2_abs-014.jpg",
22
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_3_abs-014.jpg",
23
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_4_abs-014.jpg",
24
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_5_abs-014.jpg",
25
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_6_abs-014.jpg",
26
+ "http://image.prestige-av.com/images/prestige/abs/014/cap_e_7_abs-014.jpg"
27
+ ],
28
+ "series": "貸し切り、純潔サロン",
29
+ "thumbnail_image": "http://image.prestige-av.com/images/prestige/abs/014/pf_p_abs-014.jpg",
30
+ "title": "貸し切り、純潔サロン04"
31
+ }