-
Notifications
You must be signed in to change notification settings - Fork 4
/
movie.rb
298 lines (247 loc) · 7.89 KB
/
movie.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# TODO: IS it possible to download the files from tpb that have square braackets? URI.parse doesn't work with 'em.
# TODO: Consider 404 messages from TPB
# TODO: TPB gem should only be searching for movies
# TODO: Can we implement music for this as well?
# TODO: Integrated torrent application using ruby-torrent
# TODO: Streaming via ffmpeg
# TODO: Notifications that a resque queue completed but failed. "Push notifications"
require 'rubygems'
include RottenTomatoes
class Movie < ActiveRecord::Base
@queue = 'movie_queue'
scope :queued, :conditions => {:download_start => nil}
scope :ready, :conditions => {:download_start => true, :download_finish => true}
scope :downloading, :conditions => {:download_start => true, :download_finish => nil}
has_one :download
has_many :torrents
MINIMUM_SEEDS = 5
MAX_FILE_SIZE = 1000000000 # in bytes
MIN_FILE_SIZE = 400000000
CERTIFIED_FRESH_SCORE = 70
def rating_image
return "question_mark.png" if mpaa_rating.nil?
image_name = case mpaa_rating.downcase
when "r"
"R.png"
when "pg-13"
"PG-13.png"
when "g"
"G.png"
when "nc-17"
"NC-17.png"
when "pg"
"PG.png"
else
"question_mark.png"
end
File.join("ratings", image_name)
end
def rt_image
return "/assets/question_mark.png" if critics_score.nil?
if(critics_score > CERTIFIED_FRESH_SCORE)
"/assets/certified_fresh.png"
else
"/assets/splat.png"
end
end
def meta_image
return "/assets/question_mark.png" if audience_score.nil?
if(audience_score > CERTIFIED_FRESH_SCORE)
"/assets/meta_certified_fresh.png"
else
"/assets/meta_splat.png"
end
end
def display_filesize
return "" if download.nil?
filesize = download.filesize
if filesize.nil?
""
elsif(filesize > 1000000 && filesize < 1000000000)
"%0.1f" % (filesize / 1000000.0) + "mb"
elsif(filesize >= 1000000000)
"%0.1f" % (filesize / 1000000000.0) + "gb"
end
end
def queue_date
return "Loading..." if self.api_queried.nil?
return "(In Theatres)" if self.dvd_release_date.nil?
return "(#{self.year})" if (Date.today > self.dvd_release_date)
return "(Comes out #{self.dvd_release_date})" if self.dvd_release_date
end
def self.qualifies(result)
# TODO: Specifying categories?
# TODO: Delayed queue - add movies to queue.
# check min seeds
if result.seeds < MINIMUM_SEEDS
puts "Torrent didn't have enough seeds: #{result.seeds}"
return false
end
# check filesize
filesize = result.size.to_i
if filesize > MAX_FILE_SIZE || filesize < MIN_FILE_SIZE
puts "File was either too big or too small: #{result.size}"
return false
end
# check filename to see if it's parsable
begin
URI.parse(result.link)
rescue
puts "The URL was unparsable, so we're skipping it. #{result.link}"
return false
end
true
end
def percent_complete
return 0 if download.nil?
percent = download.percent_done
return 0 if percent.nil?
percent
end
def display_runtime
return "" if(runtime.nil?)
seconds_to_string(runtime * 60)
end
def display_eta
if self.download.nil?
return ""
end
if self.download_finish? || (self.download.eta != nil && self.download.eta <= 0)
return ""
end
eta = download.eta
return nil if (eta.nil?)
eta_in_seconds = eta.to_i
seconds_to_string(eta_in_seconds)
end
def seconds_to_string(seconds)
case
when seconds == 0
"Done"
when seconds < 60
"< 1 min"
when seconds > 60 && seconds < 3600
"#{(seconds / 60).to_i} mins"
when seconds >= 3600
"#{(seconds / 3600).to_i} hr #{(seconds / 60) % 60} mins"
else
"n/a"
end
end
def movie_cover_path
if api_queried.nil?
"loading_cover.png"
elsif thumbnail_url.nil?
"no_cover.png"
else
thumbnail_url
end
end
def update_from_api(search_term=self.search_term)
puts "Searching for #{search_term}"
Rotten.api_key = 'z2s2hk9pm7zw3zubd5mrbk2m'
result = RottenMovie.find(:title => search_term, :limit => 1)
update_attributes({
:name => result.title,
:dvd_release_date => result.release_dates.dvd,
:year => result.year,
:mpaa_rating => result.mpaa_rating,
:thumbnail_url => result.posters.detailed,
:url => result.links.alternate,
:audience_score => result.ratings.audience_score,
:critics_score => result.ratings.critics_score,
:runtime => result.runtime,
:api_queried => true
})
end
def self.perform(id, search_term=nil, auto_download=false)
movie = Movie.find(id)
unless movie.api_queried
include RottenTomatoes
Rotten.api_key = 'z2s2hk9pm7zw3zubd5mrbk2m'
unless search_term
search_term = movie.search_term
end
Notification.create(:notification => "Searching rotten tomatoes for '#{search_term}'")
puts "Searching Rotten Tomatoes API for movie #{search_term}"
if (search_term)
movie.update_from_api(search_term)
Notification.create(:notification => "Updated '#{search_term}' information using rotten tomatoes.")
end
end
if (movie.dvd_release_date)
if (Date.today + 1.week) > movie.dvd_release_date # movies are usually released a little bit ahead of their time
Resque.enqueue(Torrent, id) if auto_download
puts "Enqueued the torrent"
else
puts "The movie hasn't been released yet. Will not enqueue the download."
Notification.create(:notification => "The movie '#{movie.search_term}' is not available on DVD yet, and is not downloading.")
# TODO: Figure out how to enqueue this one. Schedule it on a date. Or just every night at midnight.
end
else
puts "The movie didn't have a DVD release date listed. It's probably still in theatres."
Notification.create(:notification => "The movie '#{movie.search_term}' is still in theatres and is not downloading.")
end
rescue Errno::ECONNRESET
Notification.create(:notification => "The connection could not be made. Are you connected to the internet?")
end
def self.filesize_in_bytes(filesize)
match = filesize.match(/([\d.]+)(.*)/)
if match
raw_size = match[1].to_f
case match[2].strip
when /gib/i then
raw_size * 1000000000
when /mib/i then
raw_size * 1000000
when /kib/i then
raw_size * 1000
else
nil
end
else
nil
end
end
def eligible_files
movie = Movie.find(id)
if (movie.name)
t = TorrentApi.new()
t.search_term = search_term
if results = t.search
filtered_results = results.select { |r| Movie.qualifies r }
end
end
filtered_results
end
def self.enqueue_all
Movie.queued.each do |movie|
Movie.perform(movie.id)
end
end
def self.get_movie_list(movie_name)
include RottenTomatoes
Rotten.api_key = 'z2s2hk9pm7zw3zubd5mrbk2m'
movies = RottenMovie.find(:title => movie_name, :limit => 10)
if(movies.is_a? Array)
movies.map { |movie| "#{movie.title} (#{movie.year})" }
elsif(movies.is_a? PatchedOpenStruct)
["#{movies.title} (#{movies.year})"]
else
raise "There was a type error on the returned result set."
end
end
def image_percentage_height
if download.nil?
return "250px"
end
if download.percent_done.nil?
return "250px"
end
total_height = 250
"#{(1.0 - (download.percent_done / 100.0)) * total_height}px"
end
def fetch_and_save_torrents(search_term)
Resque.enqueue(Torrent, self.id, search_term, :all, false)
end
end