blinkbox_films 0.0.3 → 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 +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:
|