royw-dvdprofiler2xbmc 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -17,9 +17,9 @@ begin
17
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
18
  gem.add_dependency('activesupport','>= 2.0.2')
19
19
  gem.add_dependency('xml-simple','>= 1.0.12')
20
- gem.add_dependency('royw-imdb','>= 0.1.1')
21
- gem.add_dependency('royw-tmdb','>= 0.1.1')
22
- gem.add_dependency('royw-dvdprofiler_collection','>= 0.1.1')
20
+ gem.add_dependency('royw-imdb','>= 0.1.2')
21
+ gem.add_dependency('royw-tmdb','>= 0.1.5')
22
+ gem.add_dependency('royw-dvdprofiler_collection','>= 0.1.2')
23
23
  gem.add_dependency('log4r','>= 1.0.5')
24
24
  gem.add_dependency('commandline','>= 0.7.10')
25
25
  gem.add_dependency('mash','>= 0.0.3')
@@ -64,4 +64,10 @@ Rake::RDocTask.new do |rdoc|
64
64
  rdoc.rdoc_files.include('lib/**/*.rb')
65
65
  end
66
66
 
67
+ desc "stalk github until gem is published"
68
+ task :stalk do
69
+ `gemstalk royw dvdprofiler2xbmc`
70
+ end
71
+
72
+
67
73
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 18
2
+ :patch: 19
3
3
  :major: 0
4
4
  :minor: 0
@@ -22,6 +22,9 @@ require 'dvdprofiler2xbmc/controllers/app'
22
22
  require 'dvdprofiler2xbmc/controllers/fanart_controller'
23
23
  require 'dvdprofiler2xbmc/controllers/nfo_controller'
24
24
  require 'dvdprofiler2xbmc/controllers/thumbnail_controller'
25
+ require 'dvdprofiler2xbmc/models/dvdprofiler_info'
26
+ require 'dvdprofiler2xbmc/models/imdb_info'
27
+ require 'dvdprofiler2xbmc/models/tmdb_info'
25
28
  require 'dvdprofiler2xbmc/models/media'
26
29
  require 'dvdprofiler2xbmc/models/media_files'
27
30
  require 'dvdprofiler2xbmc/models/xbmc_info'
@@ -7,16 +7,20 @@
7
7
  # or
8
8
  # FanartController.update(media)
9
9
  class FanartController
10
- attr_reader :media_path, :image_files, :year, :media_subdirs, :title, :title_with_year
11
10
 
11
+ # == Synopsis
12
+ # class access method
12
13
  def self.update(media)
13
14
  FanartController.new(media).update
14
15
  end
15
16
 
17
+ # == Synopsis
18
+ # media => Media instance
16
19
  def initialize(media)
17
20
  @media = media
18
21
  end
19
22
 
23
+ # == Synopsis
20
24
  # update the meta-data and thumbnails
21
25
  def update
22
26
  result = true
@@ -31,6 +35,7 @@ class FanartController
31
35
 
32
36
  protected
33
37
 
38
+ # == Synopsis
34
39
  # link the largest fanart to moviename-fanart.jpg
35
40
  def link_fanart(dest_filespec)
36
41
  %w(original mid thumb).each do |size|
@@ -47,6 +52,7 @@ class FanartController
47
52
  end
48
53
  end
49
54
 
55
+ # == Synopsis
50
56
  # fetch all of the fanart for the movie
51
57
  # save to files using format: moviename-fanart.size.N.jpg
52
58
  # where size is the fanart size ['original', 'mid', 'thumb']
@@ -63,6 +69,7 @@ class FanartController
63
69
  end
64
70
  end
65
71
 
72
+ # == Synopsis
66
73
  # generate a filespec using format: moviename-fanart.size.N
67
74
  # where size is the fanart size ['original', 'mid', 'thumb']
68
75
  # and N is a sequential integer starting at 0
@@ -1,6 +1,10 @@
1
1
 
2
2
  # == Synopsis
3
- # NFO (info) files
3
+ # This is the heart and soul of the application. This is
4
+ # where the different media meta data are merged into the
5
+ # info (.nfo) format needed by XBMC.
6
+ #
7
+ # TODO: This class is rather large and should be refactored.
4
8
  #
5
9
  # the @info hash has keys that map directly to the .nfo file
6
10
  #
@@ -13,10 +17,12 @@
13
17
  # NfoController.update(media)
14
18
  class NfoController
15
19
 
20
+ # == Synopsis
16
21
  def self.update(media)
17
22
  NfoController.new(media).update
18
23
  end
19
24
 
25
+ # == Synopsis
20
26
  def initialize(media)
21
27
  @media = media
22
28
  @info = Hash.new
@@ -25,6 +31,7 @@ class NfoController
25
31
  self.imdb_id = @xbmc_info.movie['id']
26
32
  end
27
33
 
34
+ # == Synopsis
28
35
  # merge meta-data from the DVD Profiler collection.xml and from IMDB
29
36
  # into the @movie hash
30
37
  def update
@@ -37,15 +44,25 @@ class NfoController
37
44
  self.isbn ||= load_isbn_id
38
45
  self.imdb_id ||= load_imdb_id
39
46
 
40
- # load the profiles
41
- dvd_hash = load_dvdprofiler
42
- imdb_hash = load_imdb(dvd_hash)
43
- tmdb_hash = load_tmdb
47
+ box_set_parent_titles = []
48
+ production_years = []
49
+ released_years = []
50
+
51
+ dvdprofiler_info = load_dvdprofiler_info
52
+ unless dvdprofiler_info.nil?
53
+ box_set_parent_titles = dvdprofiler_info.box_set_parent_titles
54
+ production_years = dvdprofiler_info.production_years
55
+ released_years = dvdprofiler_info.released_years
56
+ end
57
+
58
+ imdb_info = load_imdb_info(box_set_parent_titles, production_years, released_years)
59
+ unless imdb_info.nil?
60
+ self.imdb_id ||= imdb_info.imdb_id
61
+ end
44
62
 
45
- # merge the profiles into the @info hash
46
- @info.merge!(tmdb_hash_to_info(tmdb_hash))
47
- @info.merge!(imdb_hash_to_info(imdb_hash))
48
- @info.merge!(dvd_hash_to_info(dvd_hash))
63
+ tmdb_info = load_tmdb_info
64
+
65
+ @info = merge(@info, dvdprofiler_info, imdb_info, tmdb_info)
49
66
 
50
67
  # map any genres
51
68
  @info['genre'] = remap_genres(@info['genre'])
@@ -59,14 +76,7 @@ class NfoController
59
76
  result
60
77
  end
61
78
 
62
- def remap_genres(genres)
63
- genres ||= []
64
- genres += @media.media_subdirs.split('/') if AppConfig[:subdirs_as_genres]
65
- new_genres = map_genres(genres.uniq).uniq.compact
66
- new_genres = nil if new_genres.blank?
67
- new_genres
68
- end
69
-
79
+ # == Synopsis
70
80
  # return the ISBN or nil
71
81
  def isbn
72
82
  unless @info['isbn'].blank?
@@ -75,12 +85,14 @@ class NfoController
75
85
  @media.isbn
76
86
  end
77
87
 
88
+ # == Synopsis
78
89
  # set the ISBN
79
90
  def isbn=(n)
80
91
  @media.isbn = n.to_s unless n.blank?
81
92
  @media.isbn
82
93
  end
83
94
 
95
+ # == Synopsis
84
96
  # return the IMDB ID or nil
85
97
  def imdb_id
86
98
  unless @info['id'].blank?
@@ -93,6 +105,7 @@ class NfoController
93
105
  @media.imdb_id
94
106
  end
95
107
 
108
+ # == Synopsis
96
109
  # set the IMDB ID
97
110
  def imdb_id=(ident)
98
111
  if ident.blank?
@@ -107,6 +120,55 @@ class NfoController
107
120
 
108
121
  protected
109
122
 
123
+ def load_dvdprofiler_info
124
+ dvdprofiler_info = nil
125
+ # load the profile infos
126
+ dvdprofiler_info = DvdprofilerInfo.find(:isbn => self.isbn,
127
+ :title => @media.title,
128
+ :year => @media.year,
129
+ :filespec => @media.path_to(:dvdprofiler_xml))
130
+ unless dvdprofiler_info.nil?
131
+ self.isbn ||= dvdprofiler_info.isbn
132
+ @media.year = dvdprofiler_info.year if(@media.year.blank? && !dvdprofiler_info.year.blank?)
133
+ end
134
+ dvdprofiler_info
135
+ end
136
+
137
+ def load_imdb_info(box_set_parent_titles, production_years, released_years)
138
+ imdb_info = nil
139
+ unless File.exist?(@media.path_to(:no_imdb_lookup))
140
+ possible_imdb_titles = get_imdb_titles(box_set_parent_titles)
141
+ imdb_info = ImdbInfo.find(:imdb_id => self.imdb_id,
142
+ :titles => possible_imdb_titles,
143
+ :media_years => [@media.year.to_i],
144
+ :production_years => production_years,
145
+ :released_years => released_years,
146
+ :filespec => @media.path_to(:imdb_xml),
147
+ :logger => AppConfig[:logger])
148
+ end
149
+ imdb_info
150
+ end
151
+
152
+ def load_tmdb_info
153
+ tmdb_info = nil
154
+ unless File.exist?(@media.path_to(:no_tmdb_lookup))
155
+ tmdb_info = TmdbInfo.find(:imdb_id => self.imdb_id,
156
+ :api_key => TMDB_API_KEY,
157
+ :filespec => @media.path_to(:tmdb_xml))
158
+ end
159
+ tmdb_info
160
+ end
161
+
162
+ def merge(info, dvdprofiler_info, imdb_info, tmdb_info)
163
+ # merge the profiles into the @info hash
164
+ # Note, order is important as each overwrites what is previously in @info
165
+ info.merge!(tmdb_info.to_xbmc_info) unless tmdb_info.nil?
166
+ info.merge!(imdb_info.to_xbmc_info) unless imdb_info.nil?
167
+ info.merge!(dvdprofiler_info.to_xbmc_info) unless dvdprofiler_info.nil?
168
+ info
169
+ end
170
+
171
+ # == Synopsis
110
172
  # save as a .nfo file, creating a backup if the .nfo already exists
111
173
  def save
112
174
  begin
@@ -120,6 +182,8 @@ class NfoController
120
182
  end
121
183
  end
122
184
 
185
+ # == Synopsis
186
+ # load the ISBN from a manually created .isbn file
123
187
  def load_isbn_id
124
188
  ident = nil
125
189
  filespec = @media.path_to(:isbn)
@@ -129,6 +193,8 @@ class NfoController
129
193
  ident
130
194
  end
131
195
 
196
+ # == Synopsis
197
+ # load the IMDB ID from a manually created .imdb file
132
198
  def load_imdb_id
133
199
  ident = nil
134
200
  filespec = @media.path_to(:imdb)
@@ -138,199 +204,29 @@ class NfoController
138
204
  ident
139
205
  end
140
206
 
141
- # load from the collection
142
- # return movie hash
143
- def load_dvdprofiler
144
- dvd_hash = Hash.new
145
- # find ISBN for each title and assign to the media
146
- profiles = DvdprofilerProfile.all(:isbn => self.isbn, :title => @media.title, :year => @media.year)
147
- if profiles.length > 1
148
- title = "#{@media.title}#{@media.year.blank? ? '' : ' (' + @media.year + ')'}"
149
- Dvdprofiler2Xbmc.multiple_profiles << "#{title} #{profiles.collect{|prof| prof.isbn}.join(", ")}"
150
- AppConfig[:logger].warn { "Multiple profiles found for #{title}" }
151
- else
152
- profile = profiles.first
153
- unless profile.nil?
154
- self.isbn ||= profile.isbn
155
- AppConfig[:logger].info { "ISBN => #{self.isbn}" } unless self.isbn.nil?
156
- profile.save(@media.path_to(:dvdprofiler_xml))
157
- dvd_hash = profile.dvd_hash
158
- @media.year = [dvd_hash[:productionyear]].flatten.sort.first if @media.year.blank? && !dvd_hash[:productionyear].blank?
159
- end
160
- end
161
- dvd_hash
162
- end
163
-
164
- # load data from IMDB.com
165
- # return movie hash
166
- def load_imdb(dvd_hash)
167
- imdb_hash = Hash.new
168
- unless File.exist?(@media.path_to(:no_imdb_lookup))
169
- profile = ImdbProfile.first(:imdb_id => self.imdb_id,
170
- :titles => self.get_imdb_titles(dvd_hash),
171
- :media_years => [@media.year.to_i],
172
- :production_years => dvd_hash[:productionyear],
173
- :released_years => dvd_hash[:released],
174
- :filespec => @media.path_to(:imdb_xml),
175
- :logger => AppConfig[:logger]
176
- )
177
- unless profile.nil?
178
- self.imdb_id ||= profile.imdb_id
179
- AppConfig[:logger].info { "IMDB ID => #{self.imdb_id}" } unless self.imdb_id.nil?
180
- imdb_hash = profile.movie
181
- end
182
- end
183
- imdb_hash
184
- end
185
-
186
- # load data form themovieDb.com
187
- # return movie hash
188
- def load_tmdb
189
- tmdb_hash = Hash.new
190
- unless File.exist?(@media.path_to(:no_tmdb_lookup))
191
- profile = TmdbProfile.first(:imdb_id => self.imdb_id,
192
- :api_key => TMDB_API_KEY,
193
- :filespec => @media.path_to(:tmdb_xml))
194
- unless profile.nil?
195
- tmdb_hash = profile.movie
196
- end
197
- end
198
- tmdb_hash
199
- end
200
-
201
- def get_imdb_titles(dvd_hash)
207
+ # == Synopsis
208
+ # get an Array of String titles
209
+ def get_imdb_titles(box_set_parent_titles)
202
210
  titles = []
203
211
  titles << @info['title'] unless @info['title'].blank?
204
212
  titles << @media.title unless @media.title.blank?
205
- titles += get_parent_titles(dvd_hash)
213
+ titles += box_set_parent_titles
206
214
  titles.uniq.compact
207
215
  end
208
216
 
209
- # try to find box set parent's title
210
- def get_parent_titles(dvd_hash)
211
- titles = []
212
- unless dvd_hash[:boxset].blank?
213
- begin
214
- AppConfig[:logger].debug { "Need to find box set parent's title" }
215
- parent_isbn = dvd_hash[:boxset].first['parent'].first
216
- unless parent_isbn.blank?
217
- parent_profile = DvdprofilerProfile.first(:isbn => parent_isbn)
218
- unless parent_profile.blank?
219
- titles << parent_profile.title
220
- titles += get_parent_titles(parent_profile.dvd_hash)
221
- end
222
- end
223
- rescue
224
- end
225
- end
226
- AppConfig[:logger].debug { "parent titles => #{titles.pretty_inspect}" } unless titles.empty?
227
- titles
228
- end
229
-
230
- DVD_HASH_TO_INFO_MAP = {
231
- :rating => 'mpaa',
232
- :plot => 'outline',
233
- :overview => 'plot',
234
- :runningtime => 'runtime',
235
- :actors => 'actor',
236
- :isbn => 'isbn',
237
- :imdb_id => 'id',
238
- :directors => 'director'
239
- # Unused => :ProfileTimestamp, :ID, :MediaTypes, :UPC, :CollectionNumber
240
- # :CollectionType, :DistTrait, :OriginalTitle, :CountryOfOrigin
241
- # :ProductionYear, :RunningTime, :RatingSystem, :RatingAge, :RatingVariant
242
- # :CaseType, :Genres, :Regions, :Format, :Features, :Studios, :MediaCompanies
243
- # :Audio, :Subtitles, :'SRP DenominationType', :Actors, :Credits, :Overview
244
- # :EasterEggs, :Disks, :SortTitle, :LastEdited, :WishPriority, :PurchaseInfo
245
- # :Review, :Events, :BoxSet, :LoanInfo, :Notes, :Tags, :Locks
246
- }
247
-
248
- # map the given dvd_hash into a @movie hash
249
- def dvd_hash_to_info(dvd_hash)
250
- info = Hash.new
251
- unless dvd_hash.nil?
252
- dvd_hash[:genres] ||= []
253
- info['genre'] = dvd_hash[:genres] unless dvd_hash[:genres].blank?
254
- info['title'] = dvd_hash[:title]
255
- info['year'] = [dvd_hash[:productionyear], dvd_hash[:released]].flatten.uniq.collect{|s| ((s =~ /(\d{4})/) ? $1 : nil)}.uniq.compact.first
256
- DVD_HASH_TO_INFO_MAP.each do |key, value|
257
- info[value] = dvd_hash[key] unless dvd_hash[key].blank?
258
- end
259
- end
260
- info
261
- end
262
-
263
- def to_first_year(value)
264
- [value]
265
- end
266
-
267
- IMDB_HASH_TO_INFO_MAP = {
268
- 'title' => 'title',
269
- 'mpaa' => 'mpaa',
270
- 'rating' => 'rating',
271
- 'plot' => 'plot',
272
- 'tagline' => 'tagline',
273
- 'year' => 'year',
274
- 'directors' => 'director',
275
- 'length' => 'runtime',
276
- 'genres' => 'genre',
277
- 'id' => 'id',
278
- # Unused: 'company', 'countries', 'poster_url', 'writers', 'photos'
279
- # 'poster', 'color', 'aspect_ratio', 'languages', 'release_date'
280
- # 'tiny_poster_url', 'also_known_as'
281
- }
282
- def imdb_hash_to_info(imdb_hash)
283
- info = Hash.new
284
- unless imdb_hash.blank?
285
- IMDB_HASH_TO_INFO_MAP.each do |key, value|
286
- info[value] = imdb_hash[key] unless imdb_hash[key].blank?
287
- end
288
- info['id'] = self.imdb_id if info['id'].blank?
289
- # special cases:
290
- if info['mpaa'].blank? && !imdb_hash['certifications'].blank?
291
- imdb_hash['certifications'].each do |certs|
292
- if certs['country'] == 'USA'
293
- AppConfig[:logger].info { "Using alternative USA certification instead of mpaa rating" }
294
- info['mpaa'] = certs['rating'] unless certs['rating'].blank?
295
- break
296
- end
297
- end
298
- end
299
- unless imdb_hash['cast_members'].blank?
300
- imdb_hash['cast_members'].each do |anon|
301
- # anon[2] => {name,role}
302
- info['actor'] ||= []
303
- info['actor'] << {'name' => anon[0], 'role' => anon[1]}
304
- end
305
- end
306
- info['year'] ||= imdb_hash['release_year']
307
- end
308
- info
309
- end
310
-
311
- TMDB_HASH_TO_INFO_MAP = {
312
- # urls
313
- # scores
314
- # idents
315
- # titles
316
- # imdb_ids
317
- # alternative_titles
318
- # posters
319
- # types
320
- # fanarts
321
- 'short_overviews' => 'plot',
322
- 'releases' => 'year'
323
- }
324
- def tmdb_hash_to_info(tmdb_hash)
325
- info = Hash.new
326
- unless tmdb_hash.blank?
327
- TMDB_HASH_TO_INFO_MAP.each do |key, value|
328
- info[value] = tmdb_hash[key].first unless tmdb_hash[key].blank?
329
- end
330
- end
331
- info
217
+ # == Synopsis
218
+ # remap genres
219
+ # genres => Array of String genres
220
+ # returns Array of String genres
221
+ def remap_genres(genres)
222
+ genres ||= []
223
+ genres += @media.media_subdirs.split('/') if AppConfig[:subdirs_as_genres]
224
+ new_genres = map_genres(genres.uniq).uniq.compact
225
+ new_genres = nil if new_genres.blank?
226
+ new_genres
332
227
  end
333
228
 
229
+ # == Synopsis
334
230
  # map the given genres using the AppConfig[:genre_maps].
335
231
  # given an Array of String genres
336
232
  # returns an Array of String genres that have been mapped, are unique, and do not include any nils
@@ -1,5 +1,5 @@
1
1
  # == Synopsis
2
- # Media encapsulates information about a single media file
2
+ # Used to fetch thumbnail images from
3
3
  #
4
4
  # Usage:
5
5
  # controller = ThumbnailController.new(media)
@@ -42,7 +42,9 @@ class ThumbnailController
42
42
  dest_image_filespec = @media.path_to(:thumbnail)
43
43
  puts "fetch_imdb_thumbnail(#{imdb_id}) => #{source_uri}"
44
44
  begin
45
- File.open(dest_image_filespec, "wb") {|f| f.write(open(source_uri).read)}
45
+ File.open(dest_image_filespec, "wb") do |f|
46
+ f.write(read_page(source_uri.escape_unicode))
47
+ end
46
48
  rescue Exception => e
47
49
  AppConfig[:logger].error { "Error downloading image from \"#{source_uri}\" to \"#{dest_image_filespec}\" - #{e.to_s}" }
48
50
  end
@@ -67,4 +69,8 @@ class ThumbnailController
67
69
  end
68
70
  end
69
71
 
72
+ def read_page(page)
73
+ open(page).read
74
+ end
75
+
70
76
  end
@@ -0,0 +1,108 @@
1
+ class DvdprofilerInfo
2
+
3
+ def initialize(profile)
4
+ @profile = profile
5
+ end
6
+
7
+ # == Synopsis
8
+ # see DvdprofilerProfile.all for options
9
+ # really should include at least: :title, :year, :isbn, :filespec
10
+ def self.find(options)
11
+ dvdprofiler_info = nil
12
+ # find ISBN for each title and assign to the media
13
+ profiles = DvdprofilerProfile.all(options)
14
+ if profiles.length > 1
15
+ media_title = "#{options[:title]}#{options[:year].blank? ? '' : ' (' + options[:year] + ')'}"
16
+ Dvdprofiler2Xbmc.multiple_profiles << "#{media_title} #{profiles.collect{|prof| prof.isbn}.join(", ")}"
17
+ AppConfig[:logger].warn { "Multiple profiles found for #{media_title}" }
18
+ else
19
+ profile = profiles.first
20
+ unless profile.nil?
21
+ AppConfig[:logger].info { "ISBN => #{options[:isbn]}" } unless options[:isbn].nil?
22
+ profile.save(options[:filespec])
23
+ dvdprofiler_info = DvdprofilerInfo.new(profile)
24
+ end
25
+ end
26
+ dvdprofiler_info
27
+ end
28
+
29
+ private
30
+
31
+ # == Synopsis
32
+ # maps the Dvdprofiler.dvd_hash to the info hash
33
+ DVD_HASH_TO_INFO_MAP = {
34
+ :rating => 'mpaa',
35
+ :plot => 'outline',
36
+ :overview => 'plot',
37
+ :runningtime => 'runtime',
38
+ :actors => 'actor',
39
+ :isbn => 'isbn',
40
+ :imdb_id => 'id',
41
+ :directors => 'director'
42
+ # Unused => :ProfileTimestamp, :ID, :MediaTypes, :UPC, :CollectionNumber
43
+ # :CollectionType, :DistTrait, :OriginalTitle, :CountryOfOrigin
44
+ # :ProductionYear, :RunningTime, :RatingSystem, :RatingAge, :RatingVariant
45
+ # :CaseType, :Genres, :Regions, :Format, :Features, :Studios, :MediaCompanies
46
+ # :Audio, :Subtitles, :'SRP DenominationType', :Actors, :Credits, :Overview
47
+ # :EasterEggs, :Disks, :SortTitle, :LastEdited, :WishPriority, :PurchaseInfo
48
+ # :Review, :Events, :BoxSet, :LoanInfo, :Notes, :Tags, :Locks
49
+ }
50
+
51
+ public
52
+
53
+ # == Synopsis
54
+ # map the given dvd_hash into a @movie hash
55
+ def to_xbmc_info
56
+ info = Hash.new
57
+ unless @profile.dvd_hash.nil?
58
+ @profile.dvd_hash[:genres] ||= []
59
+ info['genre'] = @profile.dvd_hash[:genres] unless @profile.dvd_hash[:genres].blank?
60
+ info['title'] = @profile.dvd_hash[:title]
61
+ info['year'] = [@profile.dvd_hash[:productionyear], @profile.dvd_hash[:released]].flatten.uniq.collect{|s| ((s =~ /(\d{4})/) ? $1 : nil)}.uniq.compact.first
62
+ DVD_HASH_TO_INFO_MAP.each do |key, value|
63
+ info[value] = @profile.dvd_hash[key] unless @profile.dvd_hash[key].blank?
64
+ end
65
+ end
66
+ info
67
+ end
68
+
69
+ def isbn
70
+ @profile.isbn rescue nil
71
+ end
72
+
73
+ # == Synopsis
74
+ # return the lowest production year as the year
75
+ def year
76
+ [@profile.dvd_hash[:productionyear]].flatten.uniq.compact.sort.first rescue nil
77
+ end
78
+
79
+ # == Synopsis
80
+ # try to find box set parent's title
81
+ def box_set_parent_titles
82
+ titles = []
83
+ unless @profile.dvd_hash[:boxset].blank?
84
+ begin
85
+ AppConfig[:logger].debug { "Need to find box set parent's title" }
86
+ parent_isbn = @profile.dvd_hash[:boxset].first['parent'].first
87
+ unless parent_isbn.blank?
88
+ parent_profile = DvdprofilerProfile.first(:isbn => parent_isbn)
89
+ unless parent_profile.blank?
90
+ titles << parent_profile.title
91
+ titles += get_parent_titles(parent_profile.dvd_hash)
92
+ end
93
+ end
94
+ rescue
95
+ end
96
+ end
97
+ AppConfig[:logger].debug { "parent titles => #{titles.pretty_inspect}" } unless titles.empty?
98
+ titles
99
+ end
100
+
101
+ def production_years
102
+ @profile.dvd_hash[:productionyear] rescue []
103
+ end
104
+
105
+ def released_years
106
+ @profile.dvd_hash[:released] rescue []
107
+ end
108
+ end
@@ -0,0 +1,70 @@
1
+ class ImdbInfo
2
+
3
+ def initialize(profile)
4
+ @profile = profile
5
+ end
6
+
7
+ # == Synopsis
8
+ # See ImdbProfile.all for options
9
+ def self.find(options)
10
+ imdb_info = nil
11
+ profile = ImdbProfile.first(options)
12
+ unless profile.nil?
13
+ imdb_info = ImdbInfo.new(profile)
14
+ end
15
+ imdb_info
16
+ end
17
+
18
+ # == Synopsis
19
+ # maps the imdb.movie hash to the info hash
20
+ IMDB_HASH_TO_INFO_MAP = {
21
+ 'title' => 'title',
22
+ 'mpaa' => 'mpaa',
23
+ 'rating' => 'rating',
24
+ 'plot' => 'plot',
25
+ 'tagline' => 'tagline',
26
+ 'year' => 'year',
27
+ 'directors' => 'director',
28
+ 'length' => 'runtime',
29
+ 'genres' => 'genre',
30
+ 'id' => 'id',
31
+ # Unused: 'company', 'countries', 'poster_url', 'writers', 'photos'
32
+ # 'poster', 'color', 'aspect_ratio', 'languages', 'release_date'
33
+ # 'tiny_poster_url', 'also_known_as'
34
+ }
35
+
36
+ # == Synopsis
37
+ # maps the imdb.movie hash to the info hash
38
+ def to_xbmc_info
39
+ info = Hash.new
40
+ unless @profile.movie.blank?
41
+ IMDB_HASH_TO_INFO_MAP.each do |key, value|
42
+ info[value] = @profile.movie[key] unless @profile.movie[key].blank?
43
+ end
44
+ info['id'] = self.imdb_id if info['id'].blank?
45
+ # special cases:
46
+ if info['mpaa'].blank? && !@profile.movie['certifications'].blank?
47
+ @profile.movie['certifications'].each do |certs|
48
+ if certs['country'] == 'USA'
49
+ AppConfig[:logger].info { "Using alternative USA certification instead of mpaa rating" }
50
+ info['mpaa'] = certs['rating'] unless certs['rating'].blank?
51
+ break
52
+ end
53
+ end
54
+ end
55
+ unless @profile.movie['cast_members'].blank?
56
+ @profile.movie['cast_members'].each do |anon|
57
+ # anon[2] => {name,role}
58
+ info['actor'] ||= []
59
+ info['actor'] << {'name' => anon[0], 'role' => anon[1]}
60
+ end
61
+ end
62
+ info['year'] ||= @profile.movie['release_year']
63
+ end
64
+ info
65
+ end
66
+
67
+ def imdb_id
68
+ @profile.imdb_id rescue nil
69
+ end
70
+ end
@@ -0,0 +1,51 @@
1
+ class TmdbInfo
2
+
3
+ def initialize(profile)
4
+ @profile = profile
5
+ end
6
+
7
+ # == Synopsis
8
+ # load data from themovieDb.com
9
+ # see TmdbProfile.all for options
10
+ def self.find(options)
11
+ tmdb_info = nil
12
+ profile = TmdbProfile.first(options)
13
+ unless profile.nil?
14
+ tmdb_info = TmdbInfo.new(profile)
15
+ end
16
+ tmdb_info
17
+ end
18
+
19
+ private
20
+
21
+ # == Synopsis
22
+ # map the tmdb.movie hash into the info hash
23
+ TMDB_HASH_TO_INFO_MAP = {
24
+ # urls
25
+ # scores
26
+ # idents
27
+ # titles
28
+ # imdb_ids
29
+ # alternative_titles
30
+ # posters
31
+ # types
32
+ # fanarts
33
+ 'short_overviews' => 'plot',
34
+ 'releases' => 'year'
35
+ }
36
+
37
+ public
38
+
39
+ # == Synopsis
40
+ # map the tmdb.movie hash into the info hash
41
+ def to_xbmc_info
42
+ info = Hash.new
43
+ unless @profile.movie.blank?
44
+ TMDB_HASH_TO_INFO_MAP.each do |key, value|
45
+ info[value] = @profile.movie[key].first unless @profile.movie[key].blank?
46
+ end
47
+ end
48
+ info
49
+ end
50
+
51
+ end
@@ -1,178 +1,53 @@
1
- # NOTE extremely ugly and non-DRY. Probably good candidate for meta programming.
2
1
 
3
2
  # override the classes' read_page method and replace with one
4
3
  # that will cache pages in spec/samples/{url}
5
4
 
6
- class FanartController
7
- private
8
- def read_page(page)
9
- html = nil
10
- filespec = page.gsub(/^http:\//, 'spec/samples')
11
- if File.exist?(filespec)
12
- html = open(filespec).read
13
- else
14
- html = open(page).read
15
- cache_html_files(page, html)
16
- end
17
- html
18
- end
19
-
20
- # this is used to save imdb pages so they may be used by rspec
21
- def cache_html_files(page, html)
22
- begin
23
- filespec = page.gsub(/^http:\//, 'spec/samples')
24
- unless File.exist?(filespec)
25
- puts "caching #{filespec}"
26
- File.mkdirs(File.dirname(filespec))
27
- File.open(filespec, 'w') { |f| f.puts html }
5
+ module CacheExtensions
6
+ # == Synopsis
7
+ # Attach the read_page and cache_file methods to the given
8
+ # class (cls) and use the given directory for the cache files
9
+ def self.attach_to(cls, directory='/tmp')
10
+
11
+ # define the read_page(page) method on the given class: cls
12
+ cls.send('define_method', "read_page") do |page|
13
+ data = nil
14
+ filespec = page.gsub(/^http:\//, directory).gsub(/\/$/, '.html')
15
+ if File.exist?(filespec)
16
+ data = open(filespec).read
17
+ else
18
+ data = open(page).read
19
+ cache_file(page, data)
28
20
  end
29
- rescue Exception => eMsg
30
- puts eMsg.to_s
31
- end
32
- end
33
- end
34
-
35
- class TmdbMovie
36
- private
37
- def read_page(page)
38
- html = nil
39
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
40
- if File.exist?(filespec)
41
- html = open(filespec).read
42
- else
43
- html = open(page).read
44
- cache_html_files(page, html)
45
- end
46
- html
47
- end
48
-
49
- # this is used to save imdb pages so they may be used by rspec
50
- def cache_html_files(page, html)
51
- begin
52
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
53
- unless File.exist?(filespec)
54
- puts "caching #{filespec}"
55
- File.mkdirs(File.dirname(filespec))
56
- File.open(filespec, 'w') { |f| f.puts html }
21
+ data
22
+ end
23
+
24
+ # define the cache_file(page, data) method on the given class: cls
25
+ cls.send('define_method', "cache_file") do |page, data|
26
+ begin
27
+ filespec = page.gsub(/^http:\//, directory).gsub(/\/$/, '.html')
28
+ unless File.exist?(filespec)
29
+ puts "caching #{filespec}"
30
+ File.mkdirs(File.dirname(filespec))
31
+ File.open(filespec, 'w') { |f| f.puts data }
32
+ end
33
+ rescue Exception => eMsg
34
+ puts eMsg.to_s
57
35
  end
58
- rescue Exception => eMsg
59
- puts eMsg.to_s
60
36
  end
61
37
  end
62
- end
63
38
 
64
- class TmdbImage
65
- private
66
- def read_page(page)
67
- html = nil
68
- filespec = page.gsub(/^http:\//, 'spec/samples')
69
- if File.exist?(filespec)
70
- html = open(filespec).read
71
- else
72
- html = open(page).read
73
- cache_html_files(page, html)
74
- end
75
- html
76
- end
77
-
78
- # this is used to save imdb pages so they may be used by rspec
79
- def cache_html_files(page, html)
80
- begin
81
- filespec = page.gsub(/^http:\//, 'spec/samples')
82
- unless File.exist?(filespec)
83
- puts "caching #{filespec}"
84
- File.mkdirs(File.dirname(filespec))
85
- File.open(filespec, 'w') { |f| f.puts html }
39
+ # == Synopsis
40
+ # Find all classes that have a read_page instance method and
41
+ # then overwrite that read_page method with one that handles
42
+ # the caching. Use the given directory for the cache files.
43
+ def self.attach_to_read_page_classes(directory='/tmp')
44
+ ObjectSpace.each_object(Class) do |cls|
45
+ if(cls.public_instance_methods(false).include?("read_page") ||
46
+ cls.protected_instance_methods(false).include?("read_page") ||
47
+ cls.private_instance_methods(false).include?("read_page"))
48
+ CacheExtensions.attach_to(cls, directory)
86
49
  end
87
- rescue Exception => eMsg
88
- puts eMsg.to_s
89
50
  end
90
51
  end
91
52
  end
92
53
 
93
- class ImdbMovie
94
- private
95
- def read_page(page)
96
- html = nil
97
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
98
- if File.exist?(filespec)
99
- html = open(filespec).read
100
- else
101
- html = open(page).read
102
- cache_html_files(page, html)
103
- end
104
- html
105
- end
106
-
107
- # this is used to save imdb pages so they may be used by rspec
108
- def cache_html_files(page, html)
109
- begin
110
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
111
- unless File.exist?(filespec)
112
- puts "caching #{filespec}"
113
- File.mkdirs(File.dirname(filespec))
114
- File.open(filespec, 'w') { |f| f.puts html }
115
- end
116
- rescue Exception => eMsg
117
- puts eMsg.to_s
118
- end
119
- end
120
- end
121
-
122
- class ImdbSearch
123
- private
124
- def read_page(page)
125
- html = nil
126
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
127
- if File.exist?(filespec)
128
- html = open(filespec).read
129
- else
130
- html = open(page).read
131
- cache_html_files(page, html)
132
- end
133
- html
134
- end
135
-
136
- # this is used to save imdb pages so they may be used by rspec
137
- def cache_html_files(page, html)
138
- begin
139
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
140
- unless File.exist?(filespec)
141
- puts "caching #{filespec}"
142
- File.mkdirs(File.dirname(filespec))
143
- File.open(filespec, 'w') { |f| f.puts html }
144
- end
145
- rescue Exception => eMsg
146
- puts eMsg.to_s
147
- end
148
- end
149
- end
150
-
151
- class ImdbImage
152
- private
153
- def read_page(page)
154
- html = nil
155
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
156
- if File.exist?(filespec)
157
- html = open(filespec).read
158
- else
159
- html = open(page).read
160
- cache_html_files(page, html)
161
- end
162
- html
163
- end
164
-
165
- # this is used to save imdb pages so they may be used by rspec
166
- def cache_html_files(page, html)
167
- begin
168
- filespec = page.gsub(/^http:\//, 'spec/samples').gsub(/\/$/, '.html')
169
- unless File.exist?(filespec)
170
- puts "caching #{filespec}"
171
- File.mkdirs(File.dirname(filespec))
172
- File.open(filespec, 'w') { |f| f.puts html }
173
- end
174
- rescue Exception => eMsg
175
- puts eMsg.to_s
176
- end
177
- end
178
- end
data/spec/spec_helper.rb CHANGED
@@ -6,13 +6,20 @@ rescue LoadError
6
6
  require 'spec'
7
7
  end
8
8
 
9
- $:.unshift(File.dirname(__FILE__) + '/../lib')
10
- require 'dvdprofiler2xbmc'
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
11
 
12
- require File.dirname(__FILE__) + '/cache_extensions'
12
+ require 'dvdprofiler2xbmc'
13
13
 
14
14
  TMPDIR = File.join(File.dirname(__FILE__), '../tmp')
15
-
16
15
  SAMPLES_DIR = File.join(File.dirname(__FILE__), 'samples')
17
16
 
17
+ require 'cache_extensions'
18
+ CacheExtensions.attach_to_read_page_classes(SAMPLES_DIR)
19
+
18
20
  Signal.trap("INT") { exit(-1) }
21
+
22
+ Spec::Runner.configure do |config|
23
+
24
+ end
25
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: royw-dvdprofiler2xbmc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roy Wright
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-19 00:00:00 -07:00
12
+ date: 2009-04-20 00:00:00 -07:00
13
13
  default_executable: dvdprofiler2xbmc
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.1.1
43
+ version: 0.1.2
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: royw-tmdb
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: 0.1.1
53
+ version: 0.1.5
54
54
  version:
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: royw-dvdprofiler_collection
@@ -60,7 +60,7 @@ dependencies:
60
60
  requirements:
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: 0.1.1
63
+ version: 0.1.2
64
64
  version:
65
65
  - !ruby/object:Gem::Dependency
66
66
  name: log4r
@@ -124,8 +124,11 @@ files:
124
124
  - lib/dvdprofiler2xbmc/controllers/fanart_controller.rb
125
125
  - lib/dvdprofiler2xbmc/controllers/nfo_controller.rb
126
126
  - lib/dvdprofiler2xbmc/controllers/thumbnail_controller.rb
127
+ - lib/dvdprofiler2xbmc/models/dvdprofiler_info.rb
128
+ - lib/dvdprofiler2xbmc/models/imdb_info.rb
127
129
  - lib/dvdprofiler2xbmc/models/media.rb
128
130
  - lib/dvdprofiler2xbmc/models/media_files.rb
131
+ - lib/dvdprofiler2xbmc/models/tmdb_info.rb
129
132
  - lib/dvdprofiler2xbmc/models/xbmc_info.rb
130
133
  - lib/dvdprofiler2xbmc/open_cache_extension.rb
131
134
  - lib/dvdprofiler2xbmc/views/cli.rb