opendmm 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/README.md +9 -0
- data/Rakefile +77 -0
- data/bin/opendmm +24 -0
- data/lib/opendmm.rb +9 -0
- data/lib/opendmm/maker.rb +60 -0
- data/lib/opendmm/makers/aknr.rb +38 -0
- data/lib/opendmm/makers/ako3.rb +39 -0
- data/lib/opendmm/makers/anna_and_hanako.rb +40 -0
- data/lib/opendmm/makers/apa.rb +40 -0
- data/lib/opendmm/makers/aroma.rb +63 -0
- data/lib/opendmm/makers/attackers.rb +55 -0
- data/lib/opendmm/makers/aurora.rb +45 -0
- data/lib/opendmm/makers/baltan.rb +40 -0
- data/lib/opendmm/makers/befree.rb +42 -0
- data/lib/opendmm/makers/bi.rb +44 -0
- data/lib/opendmm/makers/bijin_majo.rb +39 -0
- data/lib/opendmm/makers/candy.rb +41 -0
- data/lib/opendmm/makers/caribbean.rb +40 -0
- data/lib/opendmm/makers/dip.rb +43 -0
- data/lib/opendmm/makers/dmm_collection.rb +39 -0
- data/lib/opendmm/makers/ebody.rb +42 -0
- data/lib/opendmm/makers/ideapocket.rb +68 -0
- data/lib/opendmm/makers/kawaii.rb +41 -0
- data/lib/opendmm/makers/kira_kira.rb +41 -0
- data/lib/opendmm/makers/madonna.rb +41 -0
- data/lib/opendmm/makers/moodyz.rb +48 -0
- data/lib/opendmm/makers/munekyunkissa.rb +42 -0
- data/lib/opendmm/makers/opera.rb +47 -0
- data/lib/opendmm/makers/oppai.rb +57 -0
- data/lib/opendmm/makers/premium.rb +43 -0
- data/lib/opendmm/makers/prestige.rb +66 -0
- data/lib/opendmm/makers/s1.rb +41 -0
- data/lib/opendmm/makers/sod.rb +44 -0
- data/lib/opendmm/makers/tameikegoro.rb +42 -0
- data/lib/opendmm/makers/to_satsu.rb +40 -0
- data/lib/opendmm/makers/waap.rb +46 -0
- data/lib/opendmm/search_engines/jav_library.rb +58 -0
- data/lib/opendmm/utils.rb +119 -0
- data/lib/opendmm/version.rb +3 -0
- data/opendmm.gemspec +25 -0
- data/test/fixtures/ABP-013.json +33 -0
- data/test/fixtures/ABS-014.json +31 -0
- data/test/fixtures/ABY-003.json +32 -0
- data/test/fixtures/ADN-019.json +37 -0
- data/test/fixtures/AIR-017.json +34 -0
- data/test/fixtures/AKO-011.json +20 -0
- data/test/fixtures/ALB-182.json +31 -0
- data/test/fixtures/ANND-066.json +29 -0
- data/test/fixtures/AP-001.json +24 -0
- data/test/fixtures/APAA-182.json +38 -0
- data/test/fixtures/APAK-051.json +42 -0
- data/test/fixtures/ARM-191.json +28 -0
- data/test/fixtures/ARMG-223.json +27 -0
- data/test/fixtures/ATID-183.json +41 -0
- data/test/fixtures/BBI-104.json +33 -0
- data/test/fixtures/BEB-001.json +35 -0
- data/test/fixtures/BF-175.json +31 -0
- data/test/fixtures/BID-017.json +40 -0
- data/test/fixtures/BIJN-006.json +25 -0
- data/test/fixtures/BLK-049.json +27 -0
- data/test/fixtures/BRA-002.json +34 -0
- data/test/fixtures/BWB-005.json +31 -0
- data/test/fixtures/CHN-008.json +31 -0
- data/test/fixtures/CHS-015.json +32 -0
- data/test/fixtures/CLUB-003.json +22 -0
- data/test/fixtures/CND-012.json +29 -0
- data/test/fixtures/CWM-156.json +34 -0
- data/test/fixtures/Carib 021511-620.json +27 -0
- data/test/fixtures/DCOL-017.json +25 -0
- data/test/fixtures/DGL-007.json +24 -0
- data/test/fixtures/DOM-045.json +36 -0
- data/test/fixtures/EBOD-109.json +30 -0
- data/test/fixtures/ECB-078.json +33 -0
- data/test/fixtures/EDD-189.json +33 -0
- data/test/fixtures/ESK-232.json +31 -0
- data/test/fixtures/EZD-369.json +32 -0
- data/test/fixtures/FSET-399.json +40 -0
- data/test/fixtures/HAZ-009.json +33 -0
- data/test/fixtures/HON-001.json +31 -0
- data/test/fixtures/IDBD-447.json +32 -0
- data/test/fixtures/INU-013.json +34 -0
- data/test/fixtures/IPSD-041.json +40 -0
- data/test/fixtures/IPTD-464.json +35 -0
- data/test/fixtures/IPTD-629.json +32 -0
- data/test/fixtures/IPZ-005.json +35 -0
- data/test/fixtures/JBD-153.json +42 -0
- data/test/fixtures/JBS-004.json +32 -0
- data/test/fixtures/JOB-010.json +33 -0
- data/test/fixtures/JUC-285.json +36 -0
- data/test/fixtures/JUFD-137.json +33 -0
- data/test/fixtures/JUX-007.json +35 -0
- data/test/fixtures/JUX-119.json +35 -0
- data/test/fixtures/KAWD-249.json +30 -0
- data/test/fixtures/KIRD-147.json +28 -0
- data/test/fixtures/KISD-042.json +32 -0
- data/test/fixtures/LLR-005.json +35 -0
- data/test/fixtures/MAS-042.json +36 -0
- data/test/fixtures/MBD-148.json +32 -0
- data/test/fixtures/MDC-002.json +33 -0
- data/test/fixtures/MDYD-544.json +34 -0
- data/test/fixtures/MEK-008.json +32 -0
- data/test/fixtures/MIAD-490.json +34 -0
- data/test/fixtures/MIDD-599.json +36 -0
- data/test/fixtures/MIDD-643.json +32 -0
- data/test/fixtures/MIDD-644.json +30 -0
- data/test/fixtures/MIDE-004.json +34 -0
- data/test/fixtures/MIGD-284.json +34 -0
- data/test/fixtures/MIGD-336.json +33 -0
- data/test/fixtures/MIGD-337.json +35 -0
- data/test/fixtures/MIMK-005.json +36 -0
- data/test/fixtures/MINT-004.json +35 -0
- data/test/fixtures/MIQD-010.json +27 -0
- data/test/fixtures/MIRD-071.json +41 -0
- data/test/fixtures/MIRD-072.json +47 -0
- data/test/fixtures/MIRD-073.json +38 -0
- data/test/fixtures/MIXS-005.json +34 -0
- data/test/fixtures/MMY-010.json +32 -0
- data/test/fixtures/NAGE-001.json +33 -0
- data/test/fixtures/NDR-001.json +32 -0
- data/test/fixtures/NOF-003.json +36 -0
- data/test/fixtures/NPS-130.json +18 -0
- data/test/fixtures/OBA-045.json +35 -0
- data/test/fixtures/ONSD-570.json +29 -0
- data/test/fixtures/OPUD-125.json +46 -0
- data/test/fixtures/OSR-003.json +32 -0
- data/test/fixtures/PARM-028.json +21 -0
- data/test/fixtures/PBD-134.json +29 -0
- data/test/fixtures/PGD-306.json +34 -0
- data/test/fixtures/PJD-085.json +31 -0
- data/test/fixtures/PPB-008.json +31 -0
- data/test/fixtures/PPP-001.json +45 -0
- data/test/fixtures/PPPD-102.json +33 -0
- data/test/fixtures/PPSD-028.json +40 -0
- data/test/fixtures/PPT-004.json +31 -0
- data/test/fixtures/PTS-230.json +17 -0
- data/test/fixtures/PTV-001.json +28 -0
- data/test/fixtures/PXD-027.json +37 -0
- data/test/fixtures/RAW-005.json +32 -0
- data/test/fixtures/RBD-183.json +40 -0
- data/test/fixtures/SAD-031.json +35 -0
- data/test/fixtures/SDDE-312.json +34 -0
- data/test/fixtures/SDMT-802.json +32 -0
- data/test/fixtures/SDMU-008.json +38 -0
- data/test/fixtures/SDNM-011.json +37 -0
- data/test/fixtures/SET-007.json +32 -0
- data/test/fixtures/SGA-001.json +31 -0
- data/test/fixtures/SHKD-415.json +38 -0
- data/test/fixtures/SNIS-041.json +34 -0
- data/test/fixtures/SOE-259.json +31 -0
- data/test/fixtures/SPC-001.json +31 -0
- data/test/fixtures/SPS-008.json +32 -0
- data/test/fixtures/SRS-015.json +32 -0
- data/test/fixtures/SSPD-077.json +44 -0
- data/test/fixtures/STAR-359.json +33 -0
- data/test/fixtures/SUPD-065.json +41 -0
- data/test/fixtures/TDT-018.json +31 -0
- data/test/fixtures/TMAM-034.json +14 -0
- data/test/fixtures/TMCY-039.json +14 -0
- data/test/fixtures/TMDI-040.json +14 -0
- data/test/fixtures/TMEM-044.json +14 -0
- data/test/fixtures/TMVI-042.json +14 -0
- data/test/fixtures/TRD-062.json +31 -0
- data/test/fixtures/URE-011.json +38 -0
- data/test/fixtures/WA-201.json +17 -0
- data/test/fixtures/WAT-003.json +33 -0
- data/test/fixtures/WPC-002.json +35 -0
- data/test/fixtures/WSS-231.json +33 -0
- data/test/fixtures/XND-023.json +32 -0
- data/test/fixtures/XV-100.json +18 -0
- data/test/fixtures/XV-1000.json +24 -0
- data/test/fixtures/YRH-008.json +35 -0
- data/test/fixtures/YRZ-009.json +32 -0
- data/test/fixtures/ZEX-068.json +18 -0
- data/test/fixtures_test.rb +76 -0
- 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
|
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
|
+
}
|