spotlite 0.7.2 → 0.8.0

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +8 -41
  4. data/Rakefile +23 -3
  5. data/lib/spotlite.rb +1 -8
  6. data/lib/spotlite/movie.rb +169 -80
  7. data/lib/spotlite/person.rb +90 -14
  8. data/lib/spotlite/string_extensions.rb +9 -9
  9. data/lib/spotlite/version.rb +1 -1
  10. data/spec/fixtures/movie_find_conan +722 -0
  11. data/spec/fixtures/{search_no_results → movie_find_no_results} +95 -149
  12. data/spec/fixtures/nm0000233/index +6118 -0
  13. data/spec/fixtures/nm0005132/index +817 -740
  14. data/spec/fixtures/nm0864666/index +199 -221
  15. data/spec/fixtures/nm1659547/index +748 -719
  16. data/spec/fixtures/person_find_conan +722 -0
  17. data/spec/fixtures/{search_the_core → person_find_no_results} +112 -219
  18. data/spec/fixtures/tt0002186/index +212 -242
  19. data/spec/fixtures/tt0047396/releaseinfo +217 -292
  20. data/spec/fixtures/tt0112873/index +556 -539
  21. data/spec/fixtures/tt0133093/criticreviews +169 -250
  22. data/spec/fixtures/tt0133093/fullcredits +212 -299
  23. data/spec/fixtures/tt0133093/index +444 -491
  24. data/spec/fixtures/tt0133093/keywords +416 -492
  25. data/spec/fixtures/tt0133093/mediaindex_still_frame +114 -158
  26. data/spec/fixtures/tt0133093/releaseinfo +282 -344
  27. data/spec/fixtures/tt0133093/technical +1144 -0
  28. data/spec/fixtures/tt0133093/trivia +1350 -1230
  29. data/spec/fixtures/tt0169547/index +629 -644
  30. data/spec/fixtures/tt0317248/index +579 -608
  31. data/spec/fixtures/tt1134629/fullcredits +257 -340
  32. data/spec/spec_helper.rb +24 -23
  33. data/spec/spotlite/find_spec.rb +38 -0
  34. data/spec/spotlite/movie_spec.rb +73 -57
  35. data/spec/spotlite/person_spec.rb +60 -1
  36. data/spotlite.gemspec +9 -9
  37. metadata +34 -56
  38. data/lib/spotlite/box_office_top.rb +0 -11
  39. data/lib/spotlite/coming_soon.rb +0 -24
  40. data/lib/spotlite/in_theaters.rb +0 -25
  41. data/lib/spotlite/list.rb +0 -18
  42. data/lib/spotlite/opening_this_week.rb +0 -11
  43. data/lib/spotlite/search.rb +0 -45
  44. data/lib/spotlite/top.rb +0 -23
  45. data/spec/fixtures/movies_coming_soon +0 -2103
  46. data/spec/fixtures/movies_in_theaters +0 -2708
  47. data/spec/fixtures/top +0 -10823
  48. data/spec/spotlite/box_office_top_spec.rb +0 -29
  49. data/spec/spotlite/coming_soon_spec.rb +0 -29
  50. data/spec/spotlite/opening_this_week_spec.rb +0 -29
  51. data/spec/spotlite/search_spec.rb +0 -34
  52. data/spec/spotlite/top_spec.rb +0 -21
  53. data/tasks/fixtures.rake +0 -15
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cde36af5671b2f9ca6b4a495c1776c5ba6517e14
4
+ data.tar.gz: af543b22410dfedcdbb8ae0b9891f5001641d43a
5
+ SHA512:
6
+ metadata.gz: 6b4aa323ca78309219b4859defec059dadffa3745ad134cfe5f96425306ee2f5a65df089396f0b5a3186d50495689b04b7d086a4b7c6a98bb4125adf818e61f4
7
+ data.tar.gz: e3dac3d146ef5d59712706114c838ad03c9916653556c2c97902989245ec38e850ebc6718bea65d3e4b6375d0ea75ba6ae653dd04f595fad3be552876ff3d4c8
@@ -1,3 +1,17 @@
1
+ ## v0.8.0 06-Jul-2014
2
+
3
+ * Added `Spotlite::Movie.search` class method to perform advanced search by parameters
4
+ * Added `Spotlite::Movie.find` class method for simple title search
5
+ * Added `technical` method for `Movie` class to get movie technical information
6
+ * Added `alternative_titles` method for `Movie` class
7
+ * Added `Spotlite::Person.search` class method to perform advanced search by parameters
8
+ * Added `Spotlite::Person.find` class method for simple name search
9
+ * Added `filmography` method for `Person` class
10
+ * Moved task to refresh fixtures out of namespace. Now it can be called as `rake refresh_fixtures`
11
+ * Added `rake console` task. It will automatically `require 'spotlite'`
12
+ * Removed `Spotlite::List` class and all of its subclasses
13
+
14
+
1
15
  ## v0.7.2 15-Dec-2013
2
16
 
3
17
  * Fixes for updated Top 250 page
data/README.md CHANGED
@@ -22,62 +22,29 @@ Or install it yourself as:
22
22
 
23
23
  > require 'spotlite'
24
24
  # Access movie directly by its IMDb ID
25
- > movie = Spotlite::Movie.new("0133093")
25
+ > movie = Spotlite::Movie.new('0133093')
26
26
  # Or use search instead
27
- > list = Spotlite::Search.new("the matrix").movies
27
+ > list = Spotlite::Movie.find('the matrix')
28
28
  > movie = list.first
29
29
  > movie.title
30
30
  => "The Matrix"
31
31
  > movie.runtime
32
32
  => 136
33
33
  > movie.genres
34
- => ["Action", "Adventure", "Sci-Fi"]
34
+ => ["Action", "Sci-Fi"]
35
35
  > movie.countries
36
36
  => [{:code=>"us", :name=>"USA"}, {:code=>"au", :name=>"Australia"}]
37
37
  > movie.directors
38
- => [{:imdb_id=>"0905152", :name=>"Andy Wachowski"},
39
- {:imdb_id=>"0905154", :name=>"Lana Wachowski"}]
40
- > movie.cast[0..4]
41
- => [{:imdb_id=>"0000206", :name=>"Keanu Reeves", :character=>"Neo"},
42
- {:imdb_id=>"0000401", :name=>"Laurence Fishburne", :character=>"Morpheus"},
43
- {:imdb_id=>"0005251", :name=>"Carrie-Anne Moss", :character=>"Trinity"},
44
- {:imdb_id=>"0915989", :name=>"Hugo Weaving", :character=>"Agent Smith"},
45
- {:imdb_id=>"0287825", :name=>"Gloria Foster", :character=>"Oracle"}]
38
+ => [#<Spotlite::Person:0x007f96a092be70 @imdb_id="0905152", @name="Andy Wachowski", @url="http://www.imdb.com/name/nm0905152/", @credits_category="Directed by", @credits_text="(as The Wachowski Brothers)">, #<Spotlite::Person:0x007f96a092bda8 @imdb_id="0905154", @name="Lana Wachowski", @url="http://www.imdb.com/name/nm0905154/", @credits_category="Directed by", @credits_text="(as The Wachowski Brothers)">]
39
+ > movie.cast[0..2]
40
+ => [#<Spotlite::Person:0x007f96a19521a0 @imdb_id="0000206", @name="Keanu Reeves", @url="http://www.imdb.com/name/nm0000206/", @credits_category="Cast", @credits_text="Neo">, #<Spotlite::Person:0x007f96a1951c28 @imdb_id="0000401", @name="Laurence Fishburne", @url="http://www.imdb.com/name/nm0000401/", @credits_category="Cast", @credits_text="Morpheus">, #<Spotlite::Person:0x007f96a1951a70 @imdb_id="0005251", @name="Carrie-Anne Moss", @url="http://www.imdb.com/name/nm0005251/", @credits_category="Cast", @credits_text="Trinity">]
46
41
 
47
- ### IMDb Top 250
48
-
49
- > list = Spotlite::Top.new.movies
50
-
51
- ### Movies opening this week
52
-
53
- > list = Spotlite::OpeningThisWeek.new.movies
54
-
55
- ### This week's box office top 10
56
-
57
- > list = Spotlite::BoxOfficeTop.new.movies
58
-
59
- ### Movies that are coming soon
60
-
61
- > list = Spotlite::ComingSoon.new.movies
62
-
63
42
  ## Important notice
64
43
 
65
44
  Movie titles will be localized if movie has an alternative title specific to your country.
66
45
  Example: _The Great Gatsby_ (http://www.imdb.com/title/tt1343092) has an alternative title _Gatsby le magnifique_ `France (imdb display title)` and will be localized accordingly based on your IP address, if you reside in France. Non-localized title is still avaliable with `original_title` method.
67
46
  Sorry, there is nothing I can do about it at the moment.
68
47
 
69
- ## Class tree
70
-
71
- Spotlite
72
- |
73
- |- Movie
74
- `- List
75
- |- Search
76
- |- Top
77
- `- InTheaters
78
- |- OpeningThisWeek
79
- `- BoxOfficeTop
80
-
81
48
  ## Contributing
82
49
 
83
50
  1. Fork it
@@ -125,13 +92,13 @@ First, run tests with `LIVE_TEST=true` environment variable:
125
92
 
126
93
  Adjust methods that are failing, according to the new layout. And refresh fixtures:
127
94
 
128
- $ rake fixtures:refresh
95
+ $ rake refresh_fixtures
129
96
 
130
97
  It will run through all elements of `IMDB_SAMPLES` hash to get fresh data.
131
98
 
132
99
  ## License
133
100
 
134
- Copyright (c) 2013 Artem Pakk
101
+ Copyright (c) 2013-2014 Artem Pakk
135
102
 
136
103
  MIT License
137
104
 
data/Rakefile CHANGED
@@ -1,8 +1,28 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
- load File.expand_path(File.dirname(__FILE__) + "/tasks/fixtures.rake")
5
-
6
4
  RSpec::Core::RakeTask.new("spec")
7
-
8
5
  task :default => :spec
6
+
7
+ desc "Launch irb console"
8
+ task :console do
9
+ require 'irb'
10
+ require 'irb/completion'
11
+ require 'spotlite'
12
+ ARGV.clear
13
+ IRB.start
14
+ end
15
+
16
+ desc "Refresh spec fixtures with fresh data from IMDb.com"
17
+ task :refresh_fixtures do
18
+ require File.expand_path(File.dirname(__FILE__) + "/spec/spec_helper")
19
+
20
+ IMDB_SAMPLES.each_pair do |url, fixture|
21
+ page = `curl -isH "Accept-Language: en-us" '#{url}'`
22
+
23
+ File.open(File.expand_path(File.dirname(__FILE__) + "/spec/fixtures/#{fixture}"), 'w') do |f|
24
+ f.write(page)
25
+ end
26
+
27
+ end
28
+ end
@@ -8,11 +8,4 @@ require "nokogiri"
8
8
  require "spotlite/version"
9
9
  require "spotlite/movie"
10
10
  require "spotlite/person"
11
- require "spotlite/list"
12
- require "spotlite/search"
13
- require "spotlite/top"
14
- require "spotlite/in_theaters"
15
- require "spotlite/opening_this_week"
16
- require "spotlite/box_office_top"
17
- require "spotlite/coming_soon"
18
- require "spotlite/string_extensions"
11
+ require "spotlite/string_extensions"
@@ -1,12 +1,13 @@
1
- module Spotlite
1
+ require 'cgi'
2
2
 
3
+ module Spotlite
3
4
  # Represents a movie on IMDb.com
4
5
  class Movie
5
- attr_accessor :imdb_id, :title, :year
6
+ attr_accessor :imdb_id, :url
6
7
 
7
8
  # Initialize a new movie object by its IMDb ID as a string
8
9
  #
9
- # movie = Spotlite::Movie.new("0133093")
10
+ # movie = Spotlite::Movie.new('0133093')
10
11
  #
11
12
  # Spotlite::Movie class objects are lazy loading. No HTTP request
12
13
  # will be performed upon object initialization. HTTP request will
@@ -14,10 +15,49 @@ module Spotlite
14
15
  # Currently, all data is spread across 6 pages: main movie page,
15
16
  # /releaseinfo, /fullcredits, /keywords, /trivia, and /criticreviews
16
17
  def initialize(imdb_id, title = nil, year = nil)
17
- @imdb_id = imdb_id
18
+ @imdb_id = "%07d" % imdb_id.to_i
18
19
  @title = title
19
20
  @year = year
20
- @url = "http://www.imdb.com/title/tt#{imdb_id}/"
21
+ @url = "http://www.imdb.com/title/tt#{@imdb_id}/"
22
+ end
23
+
24
+ # Returns a list of movies as an array of +Spotlite::Movie+ objects
25
+ # Takes single parameter and searches for movies by title and alternative titles
26
+ def self.find(query)
27
+ results = Nokogiri::HTML open("http://www.imdb.com/find?q=#{CGI::escape(query)}&s=tt&ttype=ft", 'Accept-Language' => 'en-us')
28
+ results.css('.result_text').map do |result|
29
+ imdb_id = result.at('a')['href'].parse_imdb_id
30
+ title = result.at('a').text.strip
31
+ year = result.children.take(3).last.text.parse_year
32
+
33
+ [imdb_id, title, year]
34
+ end.map do |values|
35
+ self.new(*values)
36
+ end
37
+ end
38
+
39
+ # Returns a list of movies as an array of +Spotlite::Movie+ objects
40
+ # Takes optional parameters as a hash
41
+ # See https://github.com/defeed/spotlite/wiki/Advanced-movie-search for details
42
+ def self.search(params = {})
43
+ defaults = {
44
+ :title_type => 'feature',
45
+ :view => 'simple',
46
+ :count => 250,
47
+ :start => 1,
48
+ :sort => 'moviemeter,asc'
49
+ }
50
+ params = defaults.merge(params).map{ |k, v| "#{k}=#{v}" }.join('&')
51
+ results = Nokogiri::HTML open("http://www.imdb.com/search/title?#{params}", 'Accept-Language' => 'en-us')
52
+ results.css('td.title').map do |result|
53
+ imdb_id = result.at('a')['href'].parse_imdb_id
54
+ title = result.at('a').text.strip
55
+ year = result.at('.year_type').text.parse_year
56
+
57
+ [imdb_id, title, year]
58
+ end.map do |values|
59
+ self.new(*values)
60
+ end
21
61
  end
22
62
 
23
63
  # Returns title as a string
@@ -27,7 +67,7 @@ module Spotlite
27
67
 
28
68
  # Returns original non-english title as a string
29
69
  def original_title
30
- details.at("h1.header span.title-extra[itemprop='name']").children.first.text.gsub('"', "").strip rescue nil
70
+ details.at("h1.header span.title-extra[itemprop='name']").children.first.text.gsub('"', '').strip rescue nil
31
71
  end
32
72
 
33
73
  # Returns year of original release as an integer
@@ -42,12 +82,12 @@ module Spotlite
42
82
 
43
83
  # Returns Metascore rating as an integer
44
84
  def metascore
45
- details.at("div.star-box-details a[href^=criticreviews]").text.strip.split("/").first.to_i rescue nil
85
+ details.at("div.star-box-details a[href^=criticreviews]").text.strip.split('/').first.to_i rescue nil
46
86
  end
47
87
 
48
88
  # Returns number of votes as an integer
49
89
  def votes
50
- details.at("div.star-box-details span[itemprop='ratingCount']").text.gsub(/[^\d+]/, "").to_i rescue nil
90
+ details.at("div.star-box-details span[itemprop='ratingCount']").text.gsub(/[^\d+]/, '').to_i rescue nil
51
91
  end
52
92
 
53
93
  # Returns short description as a string
@@ -75,7 +115,7 @@ module Spotlite
75
115
  def countries
76
116
  array = []
77
117
  details.css("div.txt-block a[href^='/country/']").each do |node|
78
- array << {:code => node["href"].clean_href, :name => node.text.strip}
118
+ array << {:code => node['href'].clean_href, :name => node.text.strip}
79
119
  end
80
120
 
81
121
  array
@@ -86,7 +126,7 @@ module Spotlite
86
126
  def languages
87
127
  array = []
88
128
  details.css("div.txt-block a[href^='/language/']").each do |node|
89
- array << {:code => node["href"].clean_href, :name => node.text.strip}
129
+ array << {:code => node['href'].clean_href, :name => node.text.strip}
90
130
  end
91
131
 
92
132
  array
@@ -94,25 +134,24 @@ module Spotlite
94
134
 
95
135
  # Returns runtime (length) in minutes as an integer
96
136
  def runtime
97
- details.at("time[itemprop='duration']").text.to_i rescue nil ||
98
- details.at("#overview-top .infobar").text.strip[/\d{2,3} min/].to_i rescue nil
137
+ details.at("time[itemprop='duration']").text.gsub(',', '').to_i rescue nil
99
138
  end
100
139
 
101
140
  # Returns primary poster URL as a string
102
141
  def poster_url
103
- src = details.at("#img_primary img")["src"] rescue nil
142
+ src = details.at('#img_primary img')['src'] rescue nil
104
143
 
105
144
  if src =~ /^(http:.+@@)/ || src =~ /^(http:.+?)\.[^\/]+$/
106
- $1 + ".jpg"
145
+ $1 + '.jpg'
107
146
  end
108
147
  end
109
148
 
110
149
  # Returns an array of recommended movies as an array of initialized objects of +Movie+ class
111
150
  def recommended_movies
112
- details.css(".rec-title").map do |node|
151
+ details.css('.rec-title').map do |node|
113
152
  imdb_id = node.at("a[href^='/title/tt']")['href'].parse_imdb_id
114
- title = node.at("a").text.strip
115
- year = node.at("span").text.parse_year
153
+ title = node.at('a').text.strip
154
+ year = node.at('span').text.parse_year
116
155
 
117
156
  [imdb_id, title, year]
118
157
  end.map do |values|
@@ -130,50 +169,95 @@ module Spotlite
130
169
  movie_trivia.css("div.sodatext").map { |node| node.text.strip } rescue []
131
170
  end
132
171
 
133
- # Returns a list of directors as an array of hashes
134
- # with keys: +imdb_id+ (string) and +name+ (string)
172
+ # Returns a list of movie alternative titles as an array of hashes
173
+ # with keys +title+ (string) and +comment+ (string)
174
+ def alternative_titles
175
+ array = []
176
+ release_info.css('#akas').css('tr').map do |row|
177
+ cells = row.css('td')
178
+ array << { :title => cells.last.text.strip, :comment => cells.first.text.strip }
179
+ end
180
+
181
+ array
182
+ end
183
+
184
+ # Returns a list of directors as an array of +Spotlite::Person+ objects
135
185
  def directors
136
- parse_staff("Directed by")
186
+ parse_crew('Directed by')
137
187
  end
138
188
 
139
- # Returns a list of writers as an array of hashes
140
- # with keys: +imdb_id+ (string) and +name+ (string)
189
+ # Returns a list of writers as an array of +Spotlite::Person+ objects
141
190
  def writers
142
- parse_staff("Writing Credits")
191
+ parse_crew('Writing Credits')
143
192
  end
144
193
 
145
- # Returns a list of producers as an array of hashes
146
- # with keys: +imdb_id+ (string) and +name+ (string)
194
+ # Returns a list of producers as an array of +Spotlite::Person+ objects
147
195
  def producers
148
- parse_staff("Produced by")
196
+ parse_crew('Produced by')
197
+ end
198
+
199
+ # Returns a list of starred actors as an array of +Spotlite::Person+ objects
200
+ def stars
201
+ details.css("td#overview-top div[itemprop='actors'] a[href^='/name/nm']").map do |node|
202
+ imdb_id = node['href'].parse_imdb_id
203
+ name = node.text.strip
204
+
205
+ [imdb_id, name]
206
+ end.map do |values|
207
+ Spotlite::Person.new(*values)
208
+ end
149
209
  end
150
210
 
151
- # Returns a list of actors as an array of hashes
152
- # with keys: +imdb_id+ (string), +name+ (string), and +character+ (string)
211
+ # Returns a list of actors as an array +Spotlite::Person+ objects
153
212
  def cast
154
- table = full_credits.css("table.cast_list")
155
- names = table.css("td[itemprop='actor']").map { |node| node.text.strip } rescue []
156
- links = table.css("td[itemprop='actor'] a").map { |node| node["href"].clean_href } rescue []
157
- imdb_ids = links.map { |link| link.parse_imdb_id } unless links.empty?
158
- characters = table.css("td.character").map { |node| node.text.clean_character }
159
-
160
- array = []
161
- 0.upto(names.size - 1) do |i|
162
- array << {:imdb_id => imdb_ids[i], :name => names[i], :character => characters[i]}
213
+ full_credits.css('table.cast_list tr').reject do |row|
214
+ # Skip 'Rest of cast' row
215
+ row.children.size == 1
216
+ end.map do |row|
217
+ imdb_id = row.at('td:nth-child(2) a')['href'].parse_imdb_id
218
+ name = row.at('td:nth-child(2) a').text.strip_whitespace
219
+ credits_text = row.last_element_child.text.strip_whitespace
220
+
221
+ [imdb_id, name, 'Cast', credits_text]
222
+ end.map do |values|
223
+ Spotlite::Person.new(*values)
163
224
  end
164
-
165
- array
166
225
  end
167
226
 
168
- # Returns a list of starred actors as an array of hashes
169
- # with keys: +imdb_id+ (string) and +name+ (string)
170
- def stars
227
+ # Returns a list of crew members of a certain category as an array +Spotlite::Person+ objects
228
+ def parse_crew(category)
229
+ table = full_credits.search("[text()^='#{category}']").first.next_element rescue []
230
+ if table && table.name == 'table'
231
+ table.css('tr').reject do |row|
232
+ # Skip empty table rows with one non-braking space
233
+ row.text.strip.size == 1
234
+ end.map do |row|
235
+ imdb_id = row.first_element_child.at('a')['href'].parse_imdb_id
236
+ name = row.first_element_child.at('a').text.strip_whitespace
237
+ credits_text = row.last_element_child.text.strip_whitespace
238
+
239
+ [imdb_id, name, category, credits_text]
240
+ end.map do |values|
241
+ Spotlite::Person.new(*values)
242
+ end
243
+ end
244
+ end
245
+
246
+ # Combines all crew categories and returns an array of +Spotlite::Person+ objects
247
+ def crew
248
+ crew_categories.map{ |category| parse_crew(category) }.flatten
249
+ end
250
+
251
+ # Returns combined `cast` and `crew` as an array of +Spotlite::Person+ objects
252
+ def credits
253
+ cast + crew
254
+ end
255
+
256
+ # Returns available crew categories, e.g. "Art Department", "Writing Credits", or "Stunts", as an array of strings
257
+ def crew_categories
171
258
  array = []
172
- details.css("td#overview-top div[itemprop='actors'] a[href^='/name/nm']").map do |node|
173
- name = node.text.strip
174
- imdb_id = node["href"].parse_imdb_id
175
-
176
- array << {:imdb_id => imdb_id, :name => name}
259
+ full_credits.css('h4.dataHeaderWithBorder').reject{ |h| h['id'] == 'cast' }.map do |node|
260
+ array << (node.children.size > 1 ? node.children.first.text.strip_whitespace : node.children.text.strip_whitespace)
177
261
  end
178
262
 
179
263
  array
@@ -186,15 +270,17 @@ module Spotlite
186
270
  # If day and month are unknown, 1st of January is assigned
187
271
  def release_dates
188
272
  array = []
189
- release_info.at("#release_dates").css("tr").map do |row|
190
- code = row.at("a")["href"].clean_href.split("=").last.downcase rescue nil
191
- region = row.at("a").text rescue nil
192
- date = row.at("td.release_date").text.strip.parse_date rescue nil
193
- comment = row.css("td").last.text.strip.clean_release_comment rescue nil
273
+ table = release_info.at('#release_dates')
274
+ table.css('tr').map do |row|
275
+ cells = row.css('td')
276
+ code = cells.first.at('a')['href'].clean_href.split('=').last.downcase rescue nil
277
+ region = cells.first.at('a').text rescue nil
278
+ date = cells.at('.release_date').text.strip.parse_date
279
+ comment = cells.last.text.strip.clean_release_comment
194
280
  comment = nil if comment.empty?
195
281
 
196
282
  array << {:code => code, :region => region, :date => date, :comment => comment}
197
- end
283
+ end unless table.nil?
198
284
 
199
285
  array
200
286
  end
@@ -223,17 +309,33 @@ module Spotlite
223
309
  # Returns URLs of movie still frames as an array of strings
224
310
  def images
225
311
  array = []
226
- still_frames.css("#media_index_thumbnail_grid img").map do |image|
227
- src = image["src"] rescue nil
312
+ still_frames.css('#media_index_thumbnail_grid img').map do |image|
313
+ src = image['src'] rescue nil
228
314
 
229
315
  if src =~ /^(http:.+@@)/ || src =~ /^(http:.+?)\.[^\/]+$/
230
- array << $1 + ".jpg"
316
+ array << $1 + '.jpg'
231
317
  end
232
318
  end
233
319
 
234
320
  array
235
321
  end
236
322
 
323
+ # Returns technical information like film length, aspect ratio, cameras, etc. as a hash of arrays of strings
324
+ def technical
325
+ hash = {}
326
+ table = technical_info.at_css('#technical_content table') rescue nil
327
+
328
+ table.css('tr').map do |row|
329
+ hash[row.css('td').first.text.strip] = row.css('td').last.children.
330
+ map(&:text).
331
+ map(&:strip_whitespace).
332
+ reject(&:empty?).
333
+ reject{|i| i == '|'}
334
+ end unless table.nil?
335
+
336
+ hash
337
+ end
338
+
237
339
  private
238
340
 
239
341
  def details # :nodoc:
@@ -241,48 +343,35 @@ module Spotlite
241
343
  end
242
344
 
243
345
  def release_info # :nodoc:
244
- @release_info ||= open_page("releaseinfo")
346
+ @release_info ||= open_page('releaseinfo')
245
347
  end
246
348
 
247
349
  def full_credits # :nodoc:
248
- @full_credits ||= open_page("fullcredits")
350
+ @full_credits ||= open_page('fullcredits')
249
351
  end
250
352
 
251
353
  def plot_keywords # :nodoc:
252
- @plot_keywords ||= open_page("keywords")
354
+ @plot_keywords ||= open_page('keywords')
253
355
  end
254
356
 
255
357
  def movie_trivia # :nodoc:
256
- @movie_trivia ||= open_page("trivia")
358
+ @movie_trivia ||= open_page('trivia')
257
359
  end
258
360
 
259
361
  def reviews
260
- @reviews ||= open_page("criticreviews")
362
+ @reviews ||= open_page('criticreviews')
261
363
  end
262
364
 
263
- def still_frames
264
- @still_frames ||= open_page("mediaindex?refine=still_frame")
365
+ def still_frames # :nodoc:
366
+ @still_frames ||= open_page('mediaindex?refine=still_frame')
265
367
  end
266
368
 
267
- def open_page(page = nil) # :nodoc:
268
- Nokogiri::HTML(open("http://www.imdb.com/title/tt#{@imdb_id}/#{page}",
269
- "Accept-Language" => "en-us"))
369
+ def technical_info
370
+ @technical_info ||= open_page('technical')
270
371
  end
271
372
 
272
- def parse_staff(staff) # :nodoc:
273
- array = []
274
- # table = full_credits.at("a[name='#{staff}']").parent.parent.parent.parent rescue nil
275
- table = full_credits.search("[text()*='#{staff}']").first.next_element rescue nil
276
- if table && table.name == "table"
277
- table.css("a[href^='/name/nm']").map do |node|
278
- imdb_id = node["href"].parse_imdb_id
279
- name = node.text.strip
280
-
281
- array << {:imdb_id => imdb_id, :name => name}
282
- end
283
- end
284
-
285
- array.uniq
373
+ def open_page(page = nil) # :nodoc:
374
+ Nokogiri::HTML open("#{@url}#{page}", 'Accept-Language' => 'en-us')
286
375
  end
287
376
  end
288
377