blinkbox_films 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/blinkbox_films/film.rb +26 -0
- data/lib/blinkbox_films/film_page.rb +69 -0
- data/lib/blinkbox_films/search.rb +18 -18
- data/lib/blinkbox_films.rb +2 -1
- data/spec/feature/film_page_spec.rb +16 -0
- data/spec/feature/search_spec.rb +5 -5
- data/spec/lib/blinkbox_films/film_page_spec.rb +37 -0
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e695abee9304b0cde5c7193c45caaaba9e128104
|
4
|
+
data.tar.gz: de8ce6b1da05feb99e1b98824953d5a18601c84b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1132b4616635c34f1837e1b81428611e7e82a5282ca64949ac4ba9569e17c97532350f70b61d75d617e16d4b9e005ccf93fd0bf31c3125f8605421b91a6c5b8c
|
7
|
+
data.tar.gz: 526309666d94232b4205956ff01c9794ef890fd0fdba60295bc77e6d020b533544afc9825a29822231b8c7dafd77a377a80876da1179e3984aeb047b639f72e7
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BlinkboxFilms
|
2
|
+
class Film
|
3
|
+
def initialize(
|
4
|
+
title:,
|
5
|
+
url: nil,
|
6
|
+
image_url: nil,
|
7
|
+
certificate: nil,
|
8
|
+
release_year: nil,
|
9
|
+
running_time_in_minutes: nil,
|
10
|
+
buy_price: nil,
|
11
|
+
rental_price: nil
|
12
|
+
)
|
13
|
+
@title = title
|
14
|
+
@url = url
|
15
|
+
@image_url = image_url
|
16
|
+
@certificate = certificate
|
17
|
+
@release_year = release_year
|
18
|
+
@running_time_in_minutes = running_time_in_minutes
|
19
|
+
@buy_price = buy_price
|
20
|
+
@rental_price = rental_price
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :title, :url, :image_url, :certificate, :release_year,
|
24
|
+
:running_time_in_minutes, :buy_price, :rental_price
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'httpclient'
|
4
|
+
|
5
|
+
module BlinkboxFilms
|
6
|
+
class FilmPage
|
7
|
+
def initialize(body:, url: nil)
|
8
|
+
@body = body
|
9
|
+
@url = url
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :body, :url
|
13
|
+
|
14
|
+
def self.from_url(url)
|
15
|
+
response = HTTPClient.new.get(url)
|
16
|
+
FilmPage.new(body: Nokogiri::HTML(response.body), url: url)
|
17
|
+
end
|
18
|
+
|
19
|
+
def film
|
20
|
+
Film.new(
|
21
|
+
title: title,
|
22
|
+
url: url,
|
23
|
+
image_url: image_url,
|
24
|
+
release_year: release_year,
|
25
|
+
certificate: certificate,
|
26
|
+
running_time_in_minutes: running_time_in_minutes,
|
27
|
+
rental_price: rental_price,
|
28
|
+
buy_price: buy_price
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def title
|
33
|
+
body.css('h1').first.content.strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def image_url
|
37
|
+
body.css('.c-packShot noscript img').first.attributes['src'].value
|
38
|
+
end
|
39
|
+
|
40
|
+
def release_year
|
41
|
+
match = body.css('.g-assetInfo li').map { |n| %r{(\d{4})}.match(n.content) }.compact.first
|
42
|
+
match && match[1].to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
def certificate
|
46
|
+
match = body.css('.g-assetInfo li').map { |n| %r{CERT (.*)}.match(n.content) }.compact.first
|
47
|
+
match && match[1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def running_time_in_minutes
|
51
|
+
match = body.css('.g-assetInfo li').map { |n| %r{(\d+) HRS (\d+) MINS}.match(n.content) }.compact.first
|
52
|
+
match && (match[1].to_i * 60 + match[2].to_i)
|
53
|
+
end
|
54
|
+
|
55
|
+
def rental_price
|
56
|
+
select_price(body, '.c-retailButton--rental .c-retailButton__price > text()')
|
57
|
+
end
|
58
|
+
|
59
|
+
def buy_price
|
60
|
+
select_price(body, '.c-retailButton--purchase .c-retailButton__price > text()')
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def select_price(body, selector)
|
65
|
+
price_tag = body.css(selector).first
|
66
|
+
price_tag && price_tag.text.strip
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -6,20 +6,20 @@ module BlinkboxFilms
|
|
6
6
|
class Search
|
7
7
|
def search(query)
|
8
8
|
r = response(query)
|
9
|
-
|
10
|
-
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
|
9
|
+
films = film_fragments(r.body).map { |f|
|
10
|
+
Film.new(
|
11
|
+
title: film_title(f),
|
12
|
+
url: film_url(f),
|
13
|
+
image_url: film_image_url(f),
|
14
|
+
certificate: film_certificate(f),
|
15
|
+
running_time_in_minutes: film_running_time_in_minutes(f)
|
16
|
+
)
|
17
17
|
}
|
18
18
|
|
19
|
-
if
|
19
|
+
if films.empty? & !no_results_page?(r.body)
|
20
20
|
raise BlinkboxFilms::SearchResultsPageNotRecognised
|
21
21
|
else
|
22
|
-
|
22
|
+
films
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -32,35 +32,35 @@ module BlinkboxFilms
|
|
32
32
|
HTTPClient.new.get('http://www.blinkbox.com/search', { 'Search' => query })
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def film_fragments(page)
|
36
36
|
Nokogiri::HTML(page).css('.p-searchResults li.b-assetCollection__item')
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
39
|
+
def film_title(fragment)
|
40
40
|
fragment.css('h3').first.content.strip
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
u = URI.parse(
|
43
|
+
def film_url(fragment)
|
44
|
+
u = URI.parse(extract_film_path_or_url(fragment))
|
45
45
|
u.host ||= 'www.blinkbox.com'
|
46
46
|
u.scheme ||= 'http'
|
47
47
|
u.to_s
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
50
|
+
def extract_film_path_or_url(fragment)
|
51
51
|
fragment.css('h3 a').first.attributes['href'].value
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
54
|
+
def film_image_url(fragment)
|
55
55
|
fragment.css('noscript img').first.attributes['src'].value
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
58
|
+
def film_certificate(fragment)
|
59
59
|
match = fragment.css('.c-assetCollectionItem__metaDataItem').map { |n| %r{CERT (\S+)}.match(n.content) }.compact.first
|
60
60
|
match && match[1]
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def film_running_time_in_minutes(fragment)
|
64
64
|
match = fragment.css('.c-assetCollectionItem__metaDataItem').map { |n| %r{(\d+) HRS? (\d+) MINS?}.match(n.content) }.compact.first
|
65
65
|
match && (match[1].to_i * 60 + match[2].to_i)
|
66
66
|
end
|
data/lib/blinkbox_films.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'blinkbox_films'
|
3
|
+
|
4
|
+
describe 'A film page', :vcr do
|
5
|
+
subject { BlinkboxFilms::FilmPage.from_url('http://www.blinkbox.com/movies/the-dark-knight-(28710)').film }
|
6
|
+
|
7
|
+
it { expect(subject.title).to eq('The Dark Knight') }
|
8
|
+
it { expect(subject.url).to eq('http://www.blinkbox.com/movies/the-dark-knight-(28710)') }
|
9
|
+
it { expect(subject.image_url).to match(%r{http://cdn\d+.blinkboxmedia.com/i/contentasset3/000/028/710/gl0lloqf/v=317/w=215;h=306;rm=Crop;q=85/image.jpg}) }
|
10
|
+
it { expect(subject.release_year).to eq(2008) }
|
11
|
+
it { expect(subject.certificate).to eq('12') }
|
12
|
+
it { expect(subject.running_time_in_minutes).to eq(152) }
|
13
|
+
it { expect(subject.rental_price).to eq('£2.49') }
|
14
|
+
it { expect(subject.buy_price).to eq('£6.99') }
|
15
|
+
end
|
16
|
+
|
data/spec/feature/search_spec.rb
CHANGED
@@ -10,11 +10,11 @@ describe 'A search' do
|
|
10
10
|
subject { BlinkboxFilms::Search.new.search('dark knight') }
|
11
11
|
|
12
12
|
it { expect(subject).to_not be_empty }
|
13
|
-
it { expect(subject.first
|
14
|
-
it { expect(subject.first
|
15
|
-
it { expect(subject.first
|
16
|
-
it { expect(subject.first
|
17
|
-
it { expect(subject.first
|
13
|
+
it { expect(subject.first.title).to eq('The Dark Knight') }
|
14
|
+
it { expect(subject.first.url).to eq('http://www.blinkbox.com/movies/the-dark-knight-(28710)') }
|
15
|
+
it { expect(subject.first.image_url).to eq('http://cdn2.blinkboxmedia.com/i/contentasset31/000/028/710/1gkiab4e/v=316/w=234;h=132;rm=Crop;q=85/image.jpg') }
|
16
|
+
it { expect(subject.first.certificate).to eq('12') }
|
17
|
+
it { expect(subject.first.running_time_in_minutes).to eq(152) }
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'with unrecognised page format returned' do
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BlinkboxFilms::FilmPage do
|
4
|
+
describe '#buy_price' do
|
5
|
+
subject { BlinkboxFilms::FilmPage.new(body: body) }
|
6
|
+
|
7
|
+
context 'standard price' do
|
8
|
+
let(:body) {
|
9
|
+
Nokogiri::HTML('<button type="submit" class="c-retailButton c-retailButton--purchase">
|
10
|
+
BUY
|
11
|
+
<span class="c-retailButton__price">
|
12
|
+
£6.99
|
13
|
+
</span>
|
14
|
+
</button>')
|
15
|
+
}
|
16
|
+
|
17
|
+
it { expect(subject.buy_price).to eq('£6.99') }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'discount price' do
|
21
|
+
let(:body) {
|
22
|
+
Nokogiri::HTML('<button type="submit" class="c-retailButton c-retailButton--purchase">
|
23
|
+
BUY
|
24
|
+
<span class="c-retailButton__price">
|
25
|
+
£3.99
|
26
|
+
<span class="c-retailButton__saving c-retailButton__saving--purchase">
|
27
|
+
£6.99
|
28
|
+
</span>
|
29
|
+
</span>
|
30
|
+
</button>')
|
31
|
+
}
|
32
|
+
|
33
|
+
it { expect(subject.buy_price).to eq('£3.99') }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blinkbox_films
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Chippindale
|
@@ -103,9 +103,13 @@ files:
|
|
103
103
|
- LICENSE.txt
|
104
104
|
- Rakefile
|
105
105
|
- lib/blinkbox_films.rb
|
106
|
+
- lib/blinkbox_films/film.rb
|
107
|
+
- lib/blinkbox_films/film_page.rb
|
106
108
|
- lib/blinkbox_films/search.rb
|
107
109
|
- lib/blinkbox_films/search_results_page_not_recognised.rb
|
110
|
+
- spec/feature/film_page_spec.rb
|
108
111
|
- spec/feature/search_spec.rb
|
112
|
+
- spec/lib/blinkbox_films/film_page_spec.rb
|
109
113
|
- spec/spec_helper.rb
|
110
114
|
homepage: https://github.com/mocoso/blinkbox_films
|
111
115
|
licenses:
|