mmc 0.0.1
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.
- data/.gitignore +1 -0
- data/Gemfile +6 -0
- data/bin/mmc +286 -0
- data/lib/mmc.rb +1 -0
- data/mmc.gemspec +13 -0
- metadata +51 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/bin/mmc
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'json'
|
5
|
+
require 'open-uri'
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
# Method for converting fractions to decimals. Used below in "calculate_average" method.
|
9
|
+
def frac_to_float(str)
|
10
|
+
numerator, denominator = str.split("/").map(&:to_f)
|
11
|
+
denominator ||= 1
|
12
|
+
numerator/denominator
|
13
|
+
end
|
14
|
+
|
15
|
+
def identify_movie(title)
|
16
|
+
def search(title)
|
17
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=hv4pzbs4n46nmv7s9w87nzwu&q=#{title}&page_limit=20"
|
18
|
+
buffer = open(url).read
|
19
|
+
|
20
|
+
# convert JSON data into a hash
|
21
|
+
result = JSON.parse(buffer)
|
22
|
+
end
|
23
|
+
|
24
|
+
#Format and produce the search output
|
25
|
+
def search_output(movie_list)
|
26
|
+
count = 0
|
27
|
+
movie_list["movies"].each do |h|
|
28
|
+
print "#{count}) "
|
29
|
+
if count <10
|
30
|
+
print " " #Ensure that first column is 2 spaces wide
|
31
|
+
end
|
32
|
+
print "Title: #{h["title"]}"
|
33
|
+
if h["title"].length < 70
|
34
|
+
print " "*(70-h["title"].length) #Ensure that first column is 70 spaces wide
|
35
|
+
end
|
36
|
+
print "Year: #{h["year"]}"
|
37
|
+
print "\n"
|
38
|
+
count += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#Allow user to select a film from the search results
|
43
|
+
def user_select(movie_list)
|
44
|
+
print "Enter the number of the film you want: "
|
45
|
+
num = gets.to_i
|
46
|
+
movie_sought = movie_list["movies"][num]
|
47
|
+
end
|
48
|
+
|
49
|
+
# RUN FUNCTIONS IN IDENTIFY_MOVIE #
|
50
|
+
movie_list = search(title) #List of movies that match the search
|
51
|
+
total_num = movie_list["total"] #Total number of search results
|
52
|
+
puts "Which of these #{total_num} films did you mean?" #Ask user to identify the film they want to examine
|
53
|
+
search_output(movie_list)
|
54
|
+
user_select(movie_list)
|
55
|
+
end
|
56
|
+
|
57
|
+
def rt(id, score_only)
|
58
|
+
|
59
|
+
def get_movie(id)
|
60
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/movies/#{id}.json?apikey=hv4pzbs4n46nmv7s9w87nzwu"
|
61
|
+
buffer = open(url).read
|
62
|
+
# convert JSON data into a hash
|
63
|
+
result = JSON.parse(buffer)
|
64
|
+
return result
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pull up reviewers list
|
68
|
+
|
69
|
+
def get_all_critics(id, score_only)
|
70
|
+
if score_only #if score_only, just take all critics
|
71
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/movies/#{id}/reviews.json?review_type=all&page_limit=30&page=1&country=us&apikey=hv4pzbs4n46nmv7s9w87nzwu"
|
72
|
+
else
|
73
|
+
print "All critics, or just top critics? (all/top): "
|
74
|
+
type = gets.chomp!
|
75
|
+
if type == "top"
|
76
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/movies/#{id}/reviews.json?review_type=top_critic&country=us&apikey=hv4pzbs4n46nmv7s9w87nzwu"
|
77
|
+
elsif
|
78
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/movies/#{id}/reviews.json?review_type=all&page_limit=30&page=1&country=us&apikey=hv4pzbs4n46nmv7s9w87nzwu"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
buffer = open(url).read
|
82
|
+
# convert JSON data into a hash
|
83
|
+
result = JSON.parse(buffer)
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
|
87
|
+
#Form the list of critics, let users exclude critics
|
88
|
+
def filter_critics(movie_critics)
|
89
|
+
#Print out list of critics that have numerical reviews
|
90
|
+
count = 0
|
91
|
+
movie_critics["reviews"].each do |a|
|
92
|
+
if a["original_score"]
|
93
|
+
puts "#{count}) Critic: #{a["critic"]}"
|
94
|
+
end
|
95
|
+
count += 1
|
96
|
+
end
|
97
|
+
|
98
|
+
print "Which critics to exclude? (identify critic by number; put spaces between numbers; type \"n\" if none):"
|
99
|
+
temp = gets
|
100
|
+
unless temp == "n\n"
|
101
|
+
critic_num_to_exclude = temp.split(' ')
|
102
|
+
critic_num_to_exclude.collect!{|i| i.to_i } #convert array values to numbers
|
103
|
+
|
104
|
+
critic_to_exclude = []
|
105
|
+
|
106
|
+
critic_num_to_exclude.each do |n| #form an array of excluded critics reviews
|
107
|
+
critic_to_exclude << movie_critics["reviews"][n]
|
108
|
+
end
|
109
|
+
|
110
|
+
critic_to_exclude.each do |c| #delete excluded critics reviews from main array of review
|
111
|
+
movie_critics["reviews"].delete(c)
|
112
|
+
end
|
113
|
+
|
114
|
+
critics_list = critic_to_exclude.collect {|c| c["critic"]}
|
115
|
+
print "Excluded critics: #{critics_list} \n"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#Converts critic ratings, e.g. "A", "5/5", "78/100", to a 100 point scale
|
120
|
+
def score_convert(n)
|
121
|
+
score = 0
|
122
|
+
if n.length <= 2 #if the score is in "A", "A+", "C-" form
|
123
|
+
case n[0] #to account for the first letter
|
124
|
+
when "A"
|
125
|
+
score = 95
|
126
|
+
when "B"
|
127
|
+
score = 85
|
128
|
+
when "C"
|
129
|
+
score = 75
|
130
|
+
when "D"
|
131
|
+
score = 65
|
132
|
+
else
|
133
|
+
score = 50
|
134
|
+
end
|
135
|
+
|
136
|
+
case n[1] #to account for + and -
|
137
|
+
when "+"
|
138
|
+
score += 3
|
139
|
+
when "-"
|
140
|
+
score -=3
|
141
|
+
end
|
142
|
+
end
|
143
|
+
if n.include? "/" #if the score is in X/Y form
|
144
|
+
score = (frac_to_float(n)*100).to_i
|
145
|
+
end
|
146
|
+
score
|
147
|
+
end
|
148
|
+
|
149
|
+
def display_final_stats(movie_critics, score_only)
|
150
|
+
sum = 0
|
151
|
+
count = 0
|
152
|
+
movie_critics["reviews"].each_with_index do |a, index|
|
153
|
+
if a["original_score"]
|
154
|
+
unless score_only
|
155
|
+
puts "#{index}) "
|
156
|
+
puts "Critic: #{a["critic"]}"
|
157
|
+
puts "Original Score: #{a["original_score"]}"
|
158
|
+
end
|
159
|
+
|
160
|
+
converted_score = score_convert(a["original_score"])
|
161
|
+
puts "Converted Score: #{converted_score}" unless score_only
|
162
|
+
sum += converted_score
|
163
|
+
|
164
|
+
unless score_only
|
165
|
+
puts "Quote: #{a["quote"]}"
|
166
|
+
print "\n"
|
167
|
+
end
|
168
|
+
count += 1
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#Calculates average converted score, for all RT critics
|
173
|
+
avg_converted_score = ((sum.to_f)/count)
|
174
|
+
print "\n"
|
175
|
+
printf("Rotten tomatoes: %.2f", "#{avg_converted_score}")
|
176
|
+
print "\n"
|
177
|
+
return avg_converted_score
|
178
|
+
end
|
179
|
+
|
180
|
+
# RUN FUNCTIONS #
|
181
|
+
movie_found = get_movie(id) #movie_found is a hash that has the basic movie info
|
182
|
+
movie_critics = get_all_critics(id, score_only)
|
183
|
+
filter_critics(movie_critics) unless score_only
|
184
|
+
show_movie_details_score = display_final_stats(movie_critics, score_only)
|
185
|
+
end
|
186
|
+
|
187
|
+
def imdb(title) #returns the movie that the user selected
|
188
|
+
|
189
|
+
def get_movie(title)
|
190
|
+
url = "http://www.imdbapi.com/?i=&t=#{title}"
|
191
|
+
buffer = open(url).read
|
192
|
+
|
193
|
+
# convert JSON data into a hash
|
194
|
+
result = JSON.parse(buffer)
|
195
|
+
return result
|
196
|
+
end
|
197
|
+
|
198
|
+
movie_found = get_movie(title) #movie_found is a hash that has the basic movie info
|
199
|
+
|
200
|
+
#Print out basic info (not individual critics reviews)
|
201
|
+
print "IMDB Rating: ", movie_found["Rating"], "\n\n"
|
202
|
+
print "Title: ", movie_found["Title"], "\n"
|
203
|
+
print "Year: ", movie_found["Year"], "\n"
|
204
|
+
print "Runtime: ", movie_found["Runtime"], "\n"
|
205
|
+
print "\n"
|
206
|
+
return (movie_found["Rating"].to_f)*10
|
207
|
+
end
|
208
|
+
|
209
|
+
def metacritic(title)
|
210
|
+
#insert metacritic scraping here
|
211
|
+
movie = Nokogiri::HTML(open("http://www.metacritic.com/movie/#{title}"))
|
212
|
+
rating = movie.at_css(".score_value").text
|
213
|
+
print "Metacritic: ", rating, "\n"
|
214
|
+
return rating
|
215
|
+
end
|
216
|
+
|
217
|
+
def in_theaters
|
218
|
+
url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json?page_limit=25&page=1&country=us&apikey=hv4pzbs4n46nmv7s9w87nzwu"
|
219
|
+
buffer = open(url).read
|
220
|
+
|
221
|
+
# convert JSON data into a hash
|
222
|
+
result = JSON.parse(buffer)
|
223
|
+
movies = result["movies"]
|
224
|
+
movies.sort! {|x, y| x["ratings"]["critics_score"] <=> y["ratings"]["critics_score"]}
|
225
|
+
movies.reverse!
|
226
|
+
|
227
|
+
puts "Current Releases"
|
228
|
+
|
229
|
+
print "Score", " "*2, "Title", "\n"
|
230
|
+
movies.each do |h|
|
231
|
+
score = h["ratings"]["critics_score"]
|
232
|
+
print score
|
233
|
+
if score.to_s.length == 1
|
234
|
+
print " "*6
|
235
|
+
else
|
236
|
+
print " "*5
|
237
|
+
end
|
238
|
+
puts h["title"]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
temp = in_theaters
|
243
|
+
|
244
|
+
#Ask user to enter a title
|
245
|
+
print "Movie title (search entire Rotten Tomatoes database): "
|
246
|
+
title = gets #take in movie title from command line
|
247
|
+
title.chomp!.gsub!(' ', '+') # sub spaces for plus signs
|
248
|
+
|
249
|
+
#Find the movie, based on the user's input
|
250
|
+
movie = identify_movie(title)
|
251
|
+
|
252
|
+
#Reformat the title, so IMDB and MC will recognize it
|
253
|
+
title_for_imdb = movie["title"].downcase.gsub(" ", "+")
|
254
|
+
title_for_mc = movie["title"].downcase.gsub(" ", "-")
|
255
|
+
|
256
|
+
#Use ID to find the movie in RT
|
257
|
+
id = movie["id"]
|
258
|
+
|
259
|
+
#Let user jump straight to meta-metascore and skip everything else
|
260
|
+
|
261
|
+
print "Skip straight to the meta-metascore? (y/n)"
|
262
|
+
if gets.chomp! == "y"
|
263
|
+
score_only = true
|
264
|
+
end
|
265
|
+
|
266
|
+
#Run the 3 main functions for RT, IMDB, and MC
|
267
|
+
rt_score = rt(id, score_only)
|
268
|
+
mc_score = metacritic(title_for_mc).to_i
|
269
|
+
imdb_score = imdb(title_for_imdb)
|
270
|
+
|
271
|
+
#Let users define weights
|
272
|
+
if score_only
|
273
|
+
meta_meta_score = (rt_score + mc_score + imdb_score)/3.0
|
274
|
+
else
|
275
|
+
print "How much weight to Rotten Tomatoes? (0-1): "
|
276
|
+
rt_weight = gets.to_f
|
277
|
+
printf("How much weight to metacritic? (0 - %.2f): ", (1-rt_weight))
|
278
|
+
mc_weight = gets.to_f
|
279
|
+
imdb_weight = 1-(rt_weight+mc_weight)
|
280
|
+
printf("Weight to imdb is %.2f", imdb_weight)
|
281
|
+
print "\n"
|
282
|
+
#Calculate and display the meta-metascore
|
283
|
+
meta_meta_score = rt_score*rt_weight + imdb_score*imdb_weight + mc_score*mc_weight
|
284
|
+
end
|
285
|
+
printf("Meta-metascore: %.2f", meta_meta_score)
|
286
|
+
print "\n\n"
|
data/lib/mmc.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
#Empty file
|
data/mmc.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'mmc'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2011-10-22'
|
5
|
+
s.summary = "Meta metacritic"
|
6
|
+
s.description = "Calculates a 'meta metascore' for a given movie by averaging its scores from rotten tomatoes, metacritic, and imdb."
|
7
|
+
s.authors = ["Jimmy Li"]
|
8
|
+
s.email = 'jyl702@gmail.com'
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.executables = ['mmc']
|
11
|
+
s.homepage =
|
12
|
+
'http://rubygems.org/gems/mmc'
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mmc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jimmy Li
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-22 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Calculates a 'meta metascore' for a given movie by averaging its scores
|
15
|
+
from rotten tomatoes, metacritic, and imdb.
|
16
|
+
email: jyl702@gmail.com
|
17
|
+
executables:
|
18
|
+
- mmc
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- bin/mmc
|
25
|
+
- lib/mmc.rb
|
26
|
+
- mmc.gemspec
|
27
|
+
homepage: http://rubygems.org/gems/mmc
|
28
|
+
licenses: []
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 1.8.5
|
48
|
+
signing_key:
|
49
|
+
specification_version: 3
|
50
|
+
summary: Meta metacritic
|
51
|
+
test_files: []
|