worth_watching 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/README.md +233 -28
- data/lib/worth_watching/aggregator.rb +110 -122
- data/lib/worth_watching/movie.rb +20 -1
- data/lib/worth_watching/version.rb +1 -1
- data/lib/worth_watching/written_review.rb +12 -5
- data/spec/support/json_responses/0_movie_search_result.json +1 -0
- data/spec/support/json_responses/1_movie_search_result.json +1 -0
- data/spec/support/json_responses/3_movie_search_result.json +1 -0
- data/spec/support/json_responses/rt_top_16_dvd_rentals.json +0 -33
- data/spec/support/json_responses/rt_top_16_in_cinemas.json +0 -33
- data/spec/support/json_responses/toy_story_reviews_rt.json +0 -34
- data/spec/unit/aggregator_spec.rb +57 -6
- data/spec/unit/movie_spec.rb +12 -1
- data/spec/unit/written_review_spec.rb +52 -0
- data/worth_watching.gemspec +3 -3
- metadata +13 -6
- data/config/example_config.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 048abc5a75b5f585a50481cab76c699ec622a4a6
|
4
|
+
data.tar.gz: 7ed6a1134722d026b11ee25d54db2338a7c19e1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5903062650b35280dd7373b4ea9c8079936809ca8f554f92282599eac15dd8db00d20108021123c634fd8f14cd0b99432de91e42d0455b9f364fb7ffcba8ef09
|
7
|
+
data.tar.gz: 983f743ff6b0dd3e0ad3b640ea09c7874fca898305d3356b18249419e06f6d9eb2509566a4db123239e28725300d3fa9a5560ecdb95c4cdf4784100c6c73e679
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,43 @@
|
|
1
|
-
|
1
|
+
## WorthWatching
|
2
2
|
|
3
|
-
WorthWatching is a gem that
|
3
|
+
WorthWatching is a gem that aggregates movie review data from a
|
4
4
|
number of different sources.
|
5
5
|
|
6
|
-
|
6
|
+
Currently, the supported info sources are [Rotten Tomatoes](http://rottentomatoes.com), [IMDb](http://imdb.com) and [Metacritic](http://metacritic.com).
|
7
|
+
|
8
|
+
### What info does WorthWatching aggregate?
|
9
|
+
|
10
|
+
The gem was designed to retrieve the overall rating form each source. But it also
|
11
|
+
retrieves extra info that may be useful.
|
12
|
+
|
13
|
+
The full list of info retrieved for each movie:
|
14
|
+
|
15
|
+
- title
|
16
|
+
- plot (no spoilers, just the general description)
|
17
|
+
- director
|
18
|
+
- cast
|
19
|
+
- genre
|
20
|
+
- release date
|
21
|
+
- **Rotten Tomatoes rating (n out of 100)**
|
22
|
+
- **IMDb rating (n out of 10)**
|
23
|
+
- **Metacritic rating (n out of 100)**
|
24
|
+
- Rotten Tomatoes movie URL
|
25
|
+
- IMDb movie URL
|
26
|
+
- Metacritic movie URL
|
27
|
+
- Rotten Tomaotes movie ID
|
28
|
+
- IMDb movie ID
|
29
|
+
- poster image URL
|
30
|
+
- reviews
|
31
|
+
|
32
|
+
Note that the success of the aggregation process is entirely dependent on knowing
|
33
|
+
the Rotten Tomatoes ID *first*.
|
34
|
+
|
35
|
+
However, you can use the `search_by_title` method to first search for a movie.
|
36
|
+
The search results include the Rotten Tomatoes ID, which you can then use aggregate movie info as
|
37
|
+
usual with the `aggregate_movie` method.
|
38
|
+
|
39
|
+
If you would like to know why this is the case, or are just interested in how aggregation happens,
|
40
|
+
[read here]() for some extra information.
|
7
41
|
|
8
42
|
## Installation
|
9
43
|
|
@@ -21,52 +55,223 @@ Or install it yourself as:
|
|
21
55
|
|
22
56
|
## Setup
|
23
57
|
|
24
|
-
|
58
|
+
- Apply for the required API keys. You will need a [Rotten Tomatoes API Key](http://developer.rottentomatoes.com/) and a [TMDB API key](http://docs.themoviedb.apiary.io/).
|
25
59
|
|
26
|
-
* Fill in the details of your API keys in config/config.yml
|
27
60
|
|
28
61
|
## Usage
|
29
62
|
|
63
|
+
### Getting started
|
64
|
+
```ruby
|
65
|
+
# Create a new aggregator, passing in your API keys
|
66
|
+
movie_aggregator = WorthWatching::Aggregator.new("rotten_tomato_api_key", "tmdb_api_key")
|
67
|
+
```
|
68
|
+
|
69
|
+
### Searching for a movie by title
|
70
|
+
|
71
|
+
Pass the title of the movie, and the maximum number of results to return
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Search for movies by title. Returns an array of hashes, each hash representing
|
75
|
+
# a movie in the search result
|
76
|
+
# Note that it returns the Rotten Tomatoes ID for each movie, which is vital to aggregation
|
77
|
+
movie_aggregator.search_by_title("the godfather", 4)
|
78
|
+
=> [{:title=>"The Godfather", :rt_id=>"12911", :year=>"1972"},
|
79
|
+
{:title=>"The Godfather, Part II", :rt_id=>"12926", :year=>"1974"},
|
80
|
+
{:title=>"The Godfather, Part III", :rt_id=>"13476", :year=>"1990"},
|
81
|
+
{:title=>"The Godfather of Green Bay", :rt_id=>"341816359", :year=>"2005"}]
|
82
|
+
```
|
83
|
+
|
84
|
+
### Retrieving info for a single movie
|
30
85
|
```ruby
|
31
|
-
# Create a new aggregator
|
32
|
-
movie_aggregator = WorthWatching::Aggregator.new("rotten_tomatoes_api_key", "tmdb_api_key")
|
33
86
|
|
34
|
-
#
|
35
|
-
toy_story_3 = movie_aggregator.
|
87
|
+
# Pass the movie's Rotten Tomatoes ID
|
88
|
+
toy_story_3 = movie_aggregator.aggregate_movie("770672122")
|
36
89
|
|
37
|
-
# We now have a Movie object and can access many attributes
|
38
|
-
toy_story_3.title
|
90
|
+
# We now have a Movie object and can access many attributes...
|
91
|
+
toy_story_3.title
|
39
92
|
=> "Toy Story 3"
|
93
|
+
```
|
40
94
|
|
95
|
+
### Rating Info
|
96
|
+
```ruby
|
97
|
+
# Access ratings individually
|
41
98
|
toy_story_3.rt_rating
|
42
99
|
=> 99
|
43
100
|
|
44
101
|
toy_story_3.imdb_rating
|
45
|
-
=>
|
102
|
+
=> 8.5
|
46
103
|
|
47
104
|
toy_story_3.metacritic_rating
|
48
105
|
=> 92
|
49
106
|
|
107
|
+
# Get the rating summary as a string
|
108
|
+
puts toy_story_3.rating_summary
|
109
|
+
=> "Rotten Tomatoes rating: 99
|
110
|
+
IMDB rating: 8.5
|
111
|
+
Metacritic rating: 92"
|
112
|
+
```
|
113
|
+
### General movie info
|
114
|
+
```ruby
|
115
|
+
toy_story_3.plot
|
116
|
+
=> "Pixar returns to their first success with Toy Story 3. The movie begins with
|
117
|
+
Andy leaving for college and donating his beloved toys -- including Woody
|
118
|
+
(Tom Hanks) and Buzz (Tim Allen) -- to a daycare. While the crew meets new friends,
|
119
|
+
including Ken (Michael Keaton), they soon grow to hate their new surroundings and
|
120
|
+
plan an escape. The film was directed by Lee Unkrich from a script co-authored by
|
121
|
+
Little Miss Sunshine scribe Michael Arndt. ~ Perry Seibert, Rovi"
|
122
|
+
|
123
|
+
toy_story_3.director
|
124
|
+
=> "Lee Unkrich"
|
125
|
+
|
126
|
+
toy_story_3.cast
|
127
|
+
=> "Tom Hanks, Tim Allen, Joan Cusack, Ned Beatty"
|
128
|
+
|
129
|
+
toy_story_3.genre
|
130
|
+
=> "Animation"
|
131
|
+
|
132
|
+
toy_story_3.release_date
|
133
|
+
=> #<Date: 2010-06-18 ((2455366j,0s,0n),+0s,2299161j)>
|
134
|
+
|
135
|
+
# Rotten Tomatoes URL
|
136
|
+
toy_story_3.rt_url
|
137
|
+
=> "http://www.rottentomatoes.com/m/toy_story_3/"
|
138
|
+
|
139
|
+
toy_story_3.imdb_url
|
140
|
+
=> "http://www.imdb.com/title/tt0435761/"
|
141
|
+
|
142
|
+
toy_story_3.metacritic_url
|
143
|
+
=> "http://www.metacritic.com/movie/toy-story-3"
|
144
|
+
|
145
|
+
# Rotten Tomatoes ID
|
146
|
+
toy_story_3.rt_id
|
147
|
+
=> "770672122"
|
148
|
+
|
149
|
+
toy_story_3.imdb_id
|
150
|
+
=> "0435761"
|
151
|
+
|
152
|
+
toy_story_3.poster
|
153
|
+
=> "http://cf2.imgobject.com/t/p/original/tOwAAVeL1p3ls9dhOBo45ElodU3.jpg"
|
50
154
|
|
51
|
-
# Get a
|
52
|
-
|
155
|
+
# Get a general summary
|
156
|
+
puts toy_story_3.summary
|
157
|
+
=> "Toy Story 3
|
158
|
+
------------------------------------------------------------
|
159
|
+
Released: 18 Jun 2010
|
160
|
+
------------------------------------------------------------
|
161
|
+
Pixar returns to their first success with Toy Story 3. The movie begins with Andy
|
162
|
+
leaving for college and donating his beloved toys -- including Woody (Tom Hanks)
|
163
|
+
and Buzz (Tim Allen) -- to a daycare. While the crew meets new friends,
|
164
|
+
including Ken (Michael Keaton), they soon grow to hate their new surroundings
|
165
|
+
and plan an escape. The film was directed by Lee Unkrich from a script
|
166
|
+
co-authored by Little Miss Sunshine scribe Michael Arndt. ~ Perry Seibert, Rovi
|
167
|
+
------------------------------------------------------------
|
168
|
+
Cast: Tom Hanks, Tim Allen, Joan Cusack, Ned Beatty
|
169
|
+
------------------------------------------------------------
|
170
|
+
Rotten Tomatoes rating: 99
|
171
|
+
IMDB rating: 8.5
|
172
|
+
Metacritic rating: 92"
|
173
|
+
```
|
174
|
+
|
175
|
+
### Movie reviews
|
176
|
+
Sourced from Rotten Tomatoes. ``Movie`` object has an instance variable ``reviews``,
|
177
|
+
which is an array of ``WrittenReview`` objects.
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
# Get the first review
|
181
|
+
a_review = toy_story_3.reviews.last
|
182
|
+
a_review.author
|
183
|
+
=> "Ailsa Caine"
|
184
|
+
|
185
|
+
a_review.date
|
186
|
+
=> #<Date: 2010-07-22 ((2455400j,0s,0n),+0s,2299161j)>
|
187
|
+
|
188
|
+
a_review.quote
|
189
|
+
=> "By [Pixar's] high standards this isn't the best, but by anyone else's, it's close to perfection."
|
190
|
+
|
191
|
+
# Reviews are those collated by Rotten Tomatoes, where the review scale is binary ("fresh" or "rotten")
|
192
|
+
a_review.rating
|
193
|
+
=> "fresh"
|
194
|
+
|
195
|
+
# The review's original score (not always available)
|
196
|
+
a_review.original_score
|
197
|
+
=> "4/5"
|
53
198
|
|
54
|
-
|
199
|
+
a_review.source
|
200
|
+
=> "Little White Lies"
|
55
201
|
|
56
|
-
|
57
|
-
=> "
|
202
|
+
a_review.link
|
203
|
+
=> "http://www.littlewhitelies.co.uk/theatrical-reviews/toy-story-3/"
|
58
204
|
|
59
|
-
|
60
|
-
|
61
|
-
=> "
|
62
|
-
|
63
|
-
movie duly slumps into a mess."
|
205
|
+
# Convenience method to summarise the review as a string
|
206
|
+
a_review.to_s
|
207
|
+
=> "Ailsa Caine wrote on 2010-07-22 : By [Pixar's] high standards this isn't the best, but by anyone else's, it's close to perfection.
|
208
|
+
Rating: 4/5"
|
64
209
|
```
|
65
210
|
|
66
|
-
|
211
|
+
### Aggregating a list of movies
|
212
|
+
The Rotten Tomatoes API supports a number of pre-defined lists for both cinema/theater
|
213
|
+
releases and DVD releases. For example, if you want to aggregate info for each movie
|
214
|
+
on the Box Office list (best performing cinema releases), WorthWatching supports this.
|
215
|
+
|
216
|
+
Pass the name of the list you would like to process (as a Symbol), the country code
|
217
|
+
(ISO 3166-1 alpha-2) of the country you would like info to be localised to (as a Symbol),
|
218
|
+
and finally, the maximum number of movies on the list you are interested in.
|
219
|
+
|
220
|
+
The available lists mirror those available through the Rotten Tomatoes API.
|
221
|
+
|
222
|
+
They are:
|
223
|
+
|
224
|
+
- ``:box_office`` - top box office earning movies, sorted by most recent weekend gross
|
225
|
+
ticket sales
|
226
|
+
- ``:in_theaters`` - movies currently in theaters/cinemas
|
227
|
+
- ``:opening`` - current opening movies in the theaters/cinema
|
228
|
+
- ``:upcoming`` - upcoming movies in theaters/cinema
|
229
|
+
- ``:top_rentals`` - top DVD rentals
|
230
|
+
- ``:current_releases`` - current DVD releases
|
231
|
+
- ``:new_releases`` - new DVD releases
|
232
|
+
- ``:upcoming_dvd`` - upcoming DVD releases
|
233
|
+
|
234
|
+
**Be careful using this feature! Since WorthWatching will aggregate info for each movie on the list,
|
235
|
+
there is the potential to make a significant number of API calls through repeated use.**
|
236
|
+
|
237
|
+
**The Rotten Tomatoes API
|
238
|
+
does have rate limits (as of March 2014: 5 calls a second, 10,000 calls a day)**
|
239
|
+
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
|
243
|
+
# Aggregate the top 4 box office movies in the UK
|
244
|
+
top_movies = movie_aggregator.aggregate_list(:box_office, :uk, 4)
|
245
|
+
|
246
|
+
# Or the top 6 releases on DVD in the US
|
247
|
+
top_dvds = movie_aggregator.aggregate_list(:top_rentals, :us, 6)
|
248
|
+
|
249
|
+
# The above list-based methods return an array of Movie objects
|
250
|
+
number_1_movie = top_movies.first
|
251
|
+
|
252
|
+
number_1_movie.title
|
253
|
+
=> "Captain America: The Winter Soldier"
|
254
|
+
|
255
|
+
number_1_movie.metacritic_rating
|
256
|
+
=> 71
|
257
|
+
```
|
258
|
+
|
259
|
+
### Why is the returned list empty?
|
260
|
+
|
261
|
+
This may be because some movies do not have the minimum amount of data available
|
262
|
+
in order to aggregate their rating info, and are therefore 'discarded' during the aggregation
|
263
|
+
process.
|
264
|
+
|
265
|
+
If a movie's IMDb ID is not available through the Rotten Tomatoes API, rating info
|
266
|
+
cannot be retrieved.
|
267
|
+
|
268
|
+
During testing I also noticed that movies with no available release date were likely
|
269
|
+
to be very obscure and not have any rating info associated with them either. This is
|
270
|
+
the other criteria for a movie being discarded.
|
271
|
+
|
272
|
+
This only tends to happen with very small release independent films, particularly foreign ones.
|
273
|
+
|
274
|
+
The lists where the above is most likely are ``:upcoming`` and ``:upcoming_dvd``, since they
|
275
|
+
contain movies that probably don't have any rating info yet, as they haven't been released.
|
67
276
|
|
68
|
-
|
69
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
72
|
-
5. Create new Pull Request
|
277
|
+
The opposite is true for lists like ``:box_office`` and ``top_rentals``.
|
@@ -1,11 +1,13 @@
|
|
1
|
-
require 'httparty'
|
2
1
|
require 'nokogiri'
|
3
2
|
require 'open-uri'
|
3
|
+
require 'typhoeus'
|
4
|
+
require 'json'
|
4
5
|
|
5
6
|
module WorthWatching
|
6
7
|
class Aggregator
|
7
8
|
|
8
9
|
attr_accessor :rt_api_key, :tmdb_api_key
|
10
|
+
attr_reader :movie
|
9
11
|
|
10
12
|
RT_API_BASE_URL = 'http://api.rottentomatoes.com/api/public/v1.0'
|
11
13
|
TMDB_API_BASE_URL = 'http://api.themoviedb.org/3'
|
@@ -17,152 +19,129 @@ module WorthWatching
|
|
17
19
|
end
|
18
20
|
|
19
21
|
# Retrieve the details of a specific movie using its IMDB ID
|
22
|
+
#
|
20
23
|
# @param rt_id [String] the Rotten Tomatoes ID of the movie
|
21
24
|
# @return [Movie] a Movie object representing the movie
|
22
|
-
def
|
23
|
-
uri = "#{RT_API_BASE_URL}/movies/#{rt_id}.json?apikey=#{rt_api_key}"
|
24
|
-
movie_hash =
|
25
|
+
def aggregate_movie(rt_id)
|
26
|
+
uri = "#{RT_API_BASE_URL}/movies/#{rt_id}.json?apikey=#{@rt_api_key}"
|
27
|
+
movie_hash = JSON.parse(Typhoeus.get(uri).body)
|
25
28
|
|
26
|
-
|
29
|
+
@movie = Movie.new(movie_hash)
|
30
|
+
aggregate
|
27
31
|
end
|
28
32
|
|
29
|
-
# Retrieve a list of movies
|
30
|
-
#
|
31
|
-
# @
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
# Retrieve a list of movies, then aggregate info for each one
|
34
|
+
#
|
35
|
+
# @param list_name[Symbol] the name of the Rotten Tomato list. Possible values: :box_office,
|
36
|
+
# :in_theaters, :opening, :upcoming, :top_rentals, :current_releases, :new_releases, :upcoming_dvd
|
37
|
+
# @param country [Symbol] Localised data for the selected country (ISO 3166-1 alpha-2)
|
38
|
+
# @param result_limit [Integer] the max number of movies to return in the list
|
39
|
+
# @return [Array] an array of Movie objects
|
40
|
+
def aggregate_list(list_name, country, result_limit)
|
41
|
+
case list_name
|
42
|
+
|
43
|
+
# Build the appropriate URI based on the list name.
|
44
|
+
# Some enpoints use 'limit' to specify max results to return, some use 'page_limit'.
|
45
|
+
# Pass both to make the code simpler
|
46
|
+
when :box_office, :in_theaters, :opening, :upcoming
|
47
|
+
uri = "#{RT_API_BASE_URL}/lists/movies/#{list_name.to_s}.json?limit=#{result_limit}"\
|
48
|
+
"&page_limit=#{result_limit}&page=1&country=#{country.to_s}&apikey=#{@rt_api_key}"
|
49
|
+
when :top_rentals, :current_releases, :new_releases, :upcoming_dvd
|
50
|
+
|
51
|
+
# The API endpoint uses 'upcoming' for both DVD and cinema releases
|
52
|
+
# Need to avoid this clash by using ':upcoming_dvd' as possible method param,
|
53
|
+
# but change back when building the URI
|
54
|
+
list_name = :upcoming if list_name == :upcoming_dvd
|
55
|
+
uri = "#{RT_API_BASE_URL}/lists/dvds/#{list_name.to_s}.json?limit=#{result_limit}"\
|
56
|
+
"&page_limit=#{result_limit}&page=1&country=#{country.to_s}&apikey=#{@rt_api_key}"
|
41
57
|
end
|
42
58
|
|
43
|
-
|
44
|
-
movie_list = movie_list["movies"]
|
45
|
-
in_theaters = []
|
46
|
-
|
47
|
-
movie_list.each do |movie|
|
48
|
-
if enough_info?(movie)
|
49
|
-
movie = movie_info(movie['id'])
|
50
|
-
in_theaters << movie
|
51
|
-
end
|
52
|
-
end
|
53
|
-
Aggregator.clean_up(in_theaters)
|
54
|
-
return in_theaters
|
59
|
+
get_movie_list(uri)
|
55
60
|
end
|
56
61
|
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# @param
|
60
|
-
# @
|
61
|
-
|
62
|
-
|
62
|
+
# Search for movies using a query string. Returns a max of 4 results
|
63
|
+
#
|
64
|
+
# @param movie_title [String] the title of the movie to search for
|
65
|
+
# @param result_limit [Integer] the max number of results to return
|
66
|
+
# @return [Array, false] an array containing hashes represting each movie in the search results, or
|
67
|
+
# false if no results are found.
|
68
|
+
def search_by_title(movie_title, result_limit)
|
69
|
+
uri = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=#{@rt_api_key}&q=#{CGI.escape(movie_title)}&page_limit=#{result_limit}"
|
63
70
|
|
64
|
-
|
65
|
-
movie.metacritic_rating = extra_info[:metacritic_rating]
|
66
|
-
movie.metacritic_url = extra_info[:metacritic_url]
|
71
|
+
response = JSON.parse(Typhoeus.get(uri).body)
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
if response["total"] == 0
|
74
|
+
return false
|
75
|
+
else
|
76
|
+
# Build the array of movie serach results. Have to use a regexp to extract the Rotten Tomatoes
|
77
|
+
# ID from the movie link since the API does not return it directly.
|
78
|
+
return response["movies"].inject([]) do |movie_list, movie|
|
79
|
+
movie_list << { :title => movie["title"], :rt_id => movie["links"]["self"].match(/\/[0-9]+\./).to_s.gsub(/[\/\.]/, ""), :year => movie["year"].to_s }
|
80
|
+
movie_list
|
81
|
+
end
|
82
|
+
end
|
72
83
|
end
|
73
84
|
|
74
85
|
private
|
75
86
|
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
# @return [
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# Extract IMDB rating
|
87
|
-
extra_info[:imdb_rating] = imdb_page.css('.votes strong').text
|
88
|
-
|
89
|
-
# Extract Metacritic rating (IMDB has a page listing MC reviews)
|
90
|
-
imdb_mc_page = Nokogiri::HTML(open("http://www.imdb.com/title/tt#{imdb_id}/criticreviews"))
|
91
|
-
|
92
|
-
mc_rating = imdb_mc_page.css(".metascore > span").text
|
93
|
-
|
94
|
-
if mc_rating != ""
|
95
|
-
extra_info[:metacritic_rating] = mc_rating
|
96
|
-
extra_info[:metacritic_url] = imdb_mc_page.css(".see-more .offsite-link")[0]["href"]
|
97
|
-
else
|
98
|
-
extra_info[:metacritic_rating] = "No Rating"
|
99
|
-
extra_info[:metacritic_url] = "No URL"
|
100
|
-
end
|
101
|
-
|
102
|
-
return extra_info
|
87
|
+
# Aggregates extra info about @movie that cannot be derived directly from the
|
88
|
+
# Rotten Tomatoes API e.g IMDb/Metacritic rating, HQ posters
|
89
|
+
#
|
90
|
+
# @return [Movie] the movie with aggregated info completed
|
91
|
+
def aggregate
|
92
|
+
retrieve_imdb_info
|
93
|
+
retrieve_metacritic_info
|
94
|
+
get_poster
|
95
|
+
get_reviews
|
96
|
+
return @movie
|
103
97
|
end
|
104
98
|
|
105
|
-
|
106
|
-
|
107
|
-
omdb_response =
|
99
|
+
# Retrieves and updates the current movie's IMDb rating
|
100
|
+
def retrieve_imdb_info
|
101
|
+
omdb_response = JSON.parse(Typhoeus.get("http://www.omdbapi.com/?i=tt#{@movie.imdb_id}").body)
|
108
102
|
|
109
103
|
if omdb_response["Response"] == "True"
|
110
|
-
imdb_rating = omdb_response["imdbRating"]
|
111
|
-
movie_title = omdb_response["Title"]
|
112
|
-
|
113
|
-
mc_info = scrape_metacritic_info(movie_title)
|
114
|
-
|
115
|
-
mc_rating = mc_info[:mc_rating]
|
116
|
-
mc_link = mc_info[:mc_url]
|
117
|
-
else
|
118
|
-
imdb_rating = "Unavailable"
|
119
|
-
end
|
120
|
-
|
121
|
-
# Extract IMDB rating
|
122
|
-
extra_info[:imdb_rating] = imdb_rating
|
123
|
-
|
124
|
-
if mc_rating != ""
|
125
|
-
extra_info[:metacritic_rating] = mc_rating
|
126
|
-
extra_info[:metacritic_url] = mc_link
|
104
|
+
@movie.imdb_rating = omdb_response["imdbRating"]
|
127
105
|
else
|
128
|
-
|
129
|
-
extra_info[:metacritic_url] = "No URL"
|
106
|
+
@movie.imdb_rating = "Unavailable"
|
130
107
|
end
|
131
|
-
|
132
|
-
return extra_info
|
133
108
|
end
|
134
109
|
|
135
|
-
#
|
136
|
-
def
|
137
|
-
|
110
|
+
# Retrieves and updates the current movie's Metacritic rating and URL
|
111
|
+
def retrieve_metacritic_info
|
112
|
+
metacritic_page = Nokogiri::HTML(open("http://www.metacritic.com/search/"\
|
113
|
+
"movie/#{CGI.escape(@movie.title)}/results"))
|
138
114
|
|
139
|
-
|
140
|
-
|
141
|
-
"movie/#{CGI.escape(movie_title)}/results"))
|
142
|
-
mc_info[:mc_rating] = metacritic_page.css('.first_result .metascore_w').text
|
143
|
-
mc_info[:mc_url] = "http://www.metacritic.com#{metacritic_page.at_css('.first_result a').attr(:href)}"
|
115
|
+
scraped_rating = metacritic_page.css('.first_result .metascore_w').text
|
116
|
+
metacritic_url = "http://www.metacritic.com#{metacritic_page.at_css('.first_result a').attr(:href)}"
|
144
117
|
|
145
|
-
|
118
|
+
# If attempt to scrape results in empty string, info must not be available
|
119
|
+
if scraped_rating == ""
|
120
|
+
scraped_rating = "No Rating"
|
121
|
+
metacritic_url = "No URL"
|
122
|
+
end
|
123
|
+
|
124
|
+
@movie.metacritic_rating = scraped_rating
|
125
|
+
@movie.metacritic_url = metacritic_url
|
146
126
|
end
|
147
127
|
|
148
|
-
#
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
uri = "#{TMDB_API_BASE_URL}/movie/tt#{imdb_id}?api_key=#{tmdb_api_key}"
|
153
|
-
movie_info = HTTParty.get(uri, :headers => { 'Accept' => 'application/json'})
|
128
|
+
# Updates the current movie's high resolution poster URL
|
129
|
+
def get_poster
|
130
|
+
uri = "#{TMDB_API_BASE_URL}/movie/tt#{@movie.imdb_id}?api_key=#{tmdb_api_key}"
|
131
|
+
movie_info = JSON.parse(Typhoeus.get(uri).body)
|
154
132
|
|
155
133
|
if movie_info.has_key?("poster_path")
|
156
|
-
"http://cf2.imgobject.com/t/p/original" + movie_info["poster_path"]
|
134
|
+
@movie.poster = "http://cf2.imgobject.com/t/p/original" + movie_info["poster_path"]
|
157
135
|
else
|
158
|
-
"No poster available"
|
136
|
+
@movie.poster = "No poster available"
|
159
137
|
end
|
160
138
|
end
|
161
139
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
140
|
+
# Retrieves and updates the current movie's reviews
|
141
|
+
def get_reviews
|
142
|
+
uri = "#{RT_API_BASE_URL}/movies/#{@movie.rt_id}/reviews.json?review_type=top_critic"\
|
143
|
+
"&page_limit=5&page=1&country=uk&apikey=#{@rt_api_key}"
|
144
|
+
review_hash = JSON.parse(Typhoeus.get(uri).body)
|
166
145
|
|
167
146
|
review_list = []
|
168
147
|
|
@@ -170,11 +149,12 @@ module WorthWatching
|
|
170
149
|
review_list << WrittenReview.new(review)
|
171
150
|
end
|
172
151
|
|
173
|
-
|
152
|
+
@movie.reviews = review_list
|
174
153
|
end
|
175
154
|
|
176
155
|
# Checks that a given movie has enough information available via API to aggregate
|
177
156
|
# data. It MUST have an IMDb id and a release date.
|
157
|
+
#
|
178
158
|
# @param [Hash] the hash representation of the movie to check
|
179
159
|
# @return [Boolean] whether the movie has a theater release date and IMDb ID
|
180
160
|
def enough_info?(movie)
|
@@ -197,13 +177,21 @@ module WorthWatching
|
|
197
177
|
return has_release_date && has_imdb_id
|
198
178
|
end
|
199
179
|
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
180
|
+
# Retrieves a list of movies from the Rotten Tomatoes API, then aggregates
|
181
|
+
# info for each one
|
182
|
+
#
|
183
|
+
# @param uri [String] the Rotten Tomatoes API endpoint for the list
|
184
|
+
# @return [Array] an array of Movie objects
|
185
|
+
def get_movie_list(uri)
|
186
|
+
response = JSON.parse(Typhoeus.get(uri).body)
|
187
|
+
movie_list_response = response["movies"]
|
188
|
+
|
189
|
+
movie_list = movie_list_response.inject([]) do |list, movie|
|
190
|
+
list << aggregate_movie(movie['id']) if enough_info?(movie)
|
191
|
+
list
|
192
|
+
end
|
193
|
+
|
194
|
+
return movie_list
|
207
195
|
end
|
208
196
|
end
|
209
197
|
end
|