royw-dvdprofiler2xbmc 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,20 @@
1
- == 0.0.1 2009-03-18
2
1
 
3
- * 1 major enhancement:
4
- * refactored into gem using newgem
2
+ ignore file backups and generated content
3
+ tab cleanup and added Music => Musical default genre mapping
4
+ tab cleanup
5
+ general cleanup, minor refactoring
6
+ added limited support for stacking
7
+
8
+ == 0.0.3 2009-03-20
9
+ add support for moviename.no_imdb_lookup
10
+ create rc file on first run
11
+
12
+ == 0.0.2 2009-03-19
13
+ bumping version to see if gem will generate
14
+ forgot to remove old README
15
+ refactored into gem using newgem
16
+
17
+ == 0.0.1 2009-03-18
18
+ added IMDB scraping currently to get the IMDB ID
19
+ initial files
20
+ first commit
data/Manifest.txt CHANGED
@@ -4,13 +4,13 @@ PostInstall.txt
4
4
  README.rdoc
5
5
  Rakefile
6
6
  bin/dvdprofiler2xbmc
7
+ dvdprofiler2xbmc.gemspec
7
8
  lib/dvdprofiler2xbmc.rb
8
- lib/dvdprofiler2xbmc/app_config.rb
9
9
  lib/dvdprofiler2xbmc/app.rb
10
+ lib/dvdprofiler2xbmc/app_config.rb
10
11
  lib/dvdprofiler2xbmc/cli.rb
11
12
  lib/dvdprofiler2xbmc/collection.rb
12
13
  lib/dvdprofiler2xbmc/extensions.rb
13
- lib/dvdprofiler2xbmc/imdb_extensions.rb
14
- lib/dvdprofiler2xbmc/media_files.rb
15
14
  lib/dvdprofiler2xbmc/media.rb
15
+ lib/dvdprofiler2xbmc/media_files.rb
16
16
  lib/dvdprofiler2xbmc/nfo.rb
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ $hoe = Hoe.new('dvdprofiler2xbmc', Dvdprofiler2xbmc::VERSION) do |p|
11
11
  p.extra_deps = [
12
12
  ['activesupport','>= 2.0.2'],
13
13
  ['xml-simple','>= 1.0.12'],
14
- ['porras-imdb','>= 0.0.5'],
14
+ ['royw-imdb','>= 0.0.8'],
15
15
  ['log4r','>= 1.0.5'],
16
16
  ['commandline','>= 0.7.10'],
17
17
  ['mash','>= 0.0.3']
@@ -19,7 +19,7 @@ $hoe = Hoe.new('dvdprofiler2xbmc', Dvdprofiler2xbmc::VERSION) do |p|
19
19
  p.extra_dev_deps = [
20
20
  ['newgem', ">= #{::Newgem::VERSION}"]
21
21
  ]
22
-
22
+
23
23
  p.clean_globs |= %w[**/.DS_Store tmp *.log]
24
24
  path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
25
25
  p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{dvdprofiler2xbmc}
5
+ s.version = "0.0.4"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Roy Wright"]
9
+ s.date = %q{2009-03-25}
10
+ s.default_executable = %q{dvdprofiler2xbmc}
11
+ s.description = %q{This script will attempt to match up media files from a set of directories to the collection.xml file exported from DVD Profiler. For matches, the script will then create a {moviename}.nfo from the data in collections.xml and also copy the front cover image to {moviename}.tbn. Both files will be placed in the same directory as the source media file. Then on XBMC, set the source content to none to remove the meta data from the library, then set the source content back to Movies to import the media. This time, the data in the .nfo files will be used instead of scraping.}
12
+ s.email = ["roy@wright.org"]
13
+ s.executables = ["dvdprofiler2xbmc"]
14
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
15
+ s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "bin/dvdprofiler2xbmc", "dvdprofiler2xbmc.gemspec", "lib/dvdprofiler2xbmc.rb", "lib/dvdprofiler2xbmc/app.rb", "lib/dvdprofiler2xbmc/app_config.rb", "lib/dvdprofiler2xbmc/cli.rb", "lib/dvdprofiler2xbmc/collection.rb", "lib/dvdprofiler2xbmc/extensions.rb", "lib/dvdprofiler2xbmc/media.rb", "lib/dvdprofiler2xbmc/media_files.rb", "lib/dvdprofiler2xbmc/nfo.rb", "test/test_dvdprofiler2xbmc.rb", "test/test_helper.rb", "test/test_dvdprofiler2xbmc_cli.rb"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://www.github.com/royw/dvdprofiler2xbmc}
18
+ s.post_install_message = %q{PostInstall.txt}
19
+ s.rdoc_options = ["--main", "README.rdoc"]
20
+ s.require_paths = ["lib"]
21
+ s.rubyforge_project = %q{dvdprofiler2xbmc}
22
+ s.rubygems_version = %q{1.3.1}
23
+ s.summary = %q{This script will attempt to match up media files from a set of directories to the collection.xml file exported from DVD Profiler}
24
+ s.test_files = ["test/test_dvdprofiler2xbmc.rb", "test/test_helper.rb", "test/test_dvdprofiler2xbmc_cli.rb"]
25
+
26
+ if s.respond_to? :specification_version then
27
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
28
+ s.specification_version = 2
29
+
30
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
31
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.0.2"])
32
+ s.add_runtime_dependency(%q<xml-simple>, [">= 1.0.12"])
33
+ s.add_runtime_dependency(%q<royw-imdb>, [">= 0.0.8"])
34
+ s.add_runtime_dependency(%q<log4r>, [">= 1.0.5"])
35
+ s.add_runtime_dependency(%q<commandline>, [">= 0.7.10"])
36
+ s.add_runtime_dependency(%q<mash>, [">= 0.0.3"])
37
+ s.add_development_dependency(%q<newgem>, [">= 1.2.3"])
38
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
39
+ else
40
+ s.add_dependency(%q<activesupport>, [">= 2.0.2"])
41
+ s.add_dependency(%q<xml-simple>, [">= 1.0.12"])
42
+ s.add_dependency(%q<royw-imdb>, [">= 0.0.8"])
43
+ s.add_dependency(%q<log4r>, [">= 1.0.5"])
44
+ s.add_dependency(%q<commandline>, [">= 0.7.10"])
45
+ s.add_dependency(%q<mash>, [">= 0.0.3"])
46
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
47
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
48
+ end
49
+ else
50
+ s.add_dependency(%q<activesupport>, [">= 2.0.2"])
51
+ s.add_dependency(%q<xml-simple>, [">= 1.0.12"])
52
+ s.add_dependency(%q<royw-imdb>, [">= 0.0.8"])
53
+ s.add_dependency(%q<log4r>, [">= 1.0.5"])
54
+ s.add_dependency(%q<commandline>, [">= 0.7.10"])
55
+ s.add_dependency(%q<mash>, [">= 0.0.3"])
56
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
57
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
58
+ end
59
+ end
@@ -2,5 +2,5 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  module Dvdprofiler2xbmc
5
- VERSION = '0.0.3'
5
+ VERSION = '0.0.4'
6
6
  end
@@ -6,6 +6,8 @@
6
6
  # app.execute
7
7
  # app.report.each {|line| puts line}
8
8
  class DvdProfiler2Xbmc
9
+ include Singleton
10
+
9
11
  @interrupted = false
10
12
 
11
13
  # A trap("INT") in the Runner calls this to indicate that a ^C has been detected.
@@ -23,37 +25,24 @@ class DvdProfiler2Xbmc
23
25
 
24
26
  def initialize
25
27
  @media_files = nil
26
- @collection = nil
27
28
  end
28
29
 
30
+ # the application's main execution loop
29
31
  def execute
30
- @media_files = MediaFiles.new(AppConfig[:directories])
31
-
32
32
  collection_filepath = File.expand_path(AppConfig[:collection_filespec])
33
- @collection = Collection.new(collection_filepath)
33
+ collection = Collection.new(collection_filepath)
34
34
 
35
+ @media_files = MediaFiles.new(AppConfig[:directories], collection)
35
36
  @media_files.titles.each do |title, medias|
36
37
  break if DvdProfiler2Xbmc.interrupted?
37
- # the following lines are order dependent
38
- find_isbns(title, medias)
39
- copy_thumbnails(title, medias)
40
- create_nfos(title, medias)
38
+ medias.each do |media|
39
+ media.load
40
+ media.update if AppConfig[:do_update]
41
+ end
41
42
  end
42
43
 
43
44
  # set file and directory permissions
44
- AppConfig[:directories].each do |dir|
45
- Dir.glob(File.join(dir, '**/*')).each do |f|
46
- begin
47
- if File.directory?(f)
48
- File.chmod(AppConfig[:dir_permissions], f) unless AppConfig[:dir_permissions].nil?
49
- else
50
- File.chmod(AppConfig[:file_permissions], f) unless AppConfig[:file_permissions].nil?
51
- end
52
- rescue Exception => e
53
- AppConfig[:logger].error {e.to_s}
54
- end
55
- end
56
- end
45
+ AppConfig[:directories].each { |dir| set_permissions(dir) }
57
46
  end
58
47
 
59
48
  # generate the report.
@@ -63,63 +52,44 @@ class DvdProfiler2Xbmc
63
52
  buf = []
64
53
  unless DvdProfiler2Xbmc.interrupted?
65
54
  unless @media_files.nil?
66
- duplicates = duplicates_report
67
- unless duplicates.empty?
68
- buf << "Duplicates:\n"
69
- buf += duplicates
70
- end
71
-
72
- missing_isbns = missing_isbn_report
73
- unless missing_isbns.empty?
74
- buf += missing_isbns
75
- end
55
+ buf += gen_report('duplicates', 'Duplicates')
56
+ buf += gen_report('missing_isbns', 'Missing ISBNs')
57
+ buf += gen_report('missing_imdb_ids', 'Missing IMDB IDs')
58
+ buf += gen_report('missing_thumbnails', 'Missing Thumbnails')
76
59
  end
77
60
  end
78
61
  buf
79
62
  end
80
63
 
81
- protected
82
-
83
- # find ISBN for each title and assign to the media
84
- def find_isbns(title, medias)
85
- title_pattern = Collection.title_pattern(title)
86
- unless @collection.title_isbn_hash[title_pattern].nil?
87
- medias.each do |media|
88
- media.isbn = @collection.title_isbn_hash[title_pattern]
64
+ def gen_report(name, heading='')
65
+ buf = []
66
+ begin
67
+ lines = send("#{name}_report")
68
+ unless lines.empty?
69
+ buf << ''
70
+ buf << heading
71
+ buf += lines
89
72
  end
73
+ rescue Exception => e
74
+ AppConfig[:logger].error { "Error generating #{name} report - #{e.to_s}" }
90
75
  end
76
+ buf
91
77
  end
92
78
 
93
- # copy images from .../isbn.jpg to .../basename.jpg
94
- def copy_thumbnails(title, medias)
95
- medias.each do |media|
96
- unless media.isbn.nil?
97
- media.isbn.each do |isbn|
98
- src_image_filespec = File.join(AppConfig[:images_dir], "#{isbn}f.jpg")
99
- if File.exist?(src_image_filespec)
100
- dest_image_filespec = media.path_to(:thumbnail_extension)
101
- begin
102
- File.copy(src_image_filespec, dest_image_filespec)
103
- rescue Exception => e
104
- AppConfig[:logger].error {e.to_s}
105
- end
106
- end
107
- end
108
- end
109
- end
110
- end
79
+ protected
111
80
 
112
- # create nfo files from collection.isbn_dvd_hash
113
- def create_nfos(title, medias)
114
- medias.each do |media|
115
- unless media.isbn.nil?
116
- media.isbn.each do |isbn|
117
- dvd_hash = @collection.isbn_dvd_hash[isbn]
118
- unless dvd_hash.nil?
119
- nfo = NFO.new(media, dvd_hash)
120
- nfo.save
121
- end
81
+ # set the directory and file permissions for all files and directories under
82
+ # the given directory
83
+ def set_permissions(dir)
84
+ Dir.glob(File.join(dir, '**/*')).each do |f|
85
+ begin
86
+ if File.directory?(f)
87
+ File.chmod(AppConfig[:dir_permissions], f) unless AppConfig[:dir_permissions].nil?
88
+ else
89
+ File.chmod(AppConfig[:file_permissions], f) unless AppConfig[:file_permissions].nil?
122
90
  end
91
+ rescue Exception => e
92
+ AppConfig[:logger].error {e.to_s}
123
93
  end
124
94
  end
125
95
  end
@@ -140,15 +110,56 @@ class DvdProfiler2Xbmc
140
110
  end
141
111
 
142
112
  # unable to find ISBN for these titles report
143
- def missing_isbn_report
113
+ def missing_isbns_report
144
114
  buf = []
145
115
  @media_files.titles.each do |title, medias|
146
116
  if medias.nil?
147
117
  buf << "No media for #{title}"
148
118
  else
149
119
  if medias[0].isbn.nil?
150
- buf << "ISBN not found for #{title}"
151
- medias.each {|media| buf << " #{media.media_path}"}
120
+ paths = []
121
+ medias.each do |media|
122
+ unless File.exist? media.path_to(:no_isbn_extension)
123
+ paths << " #{media.media_path}"
124
+ end
125
+ end
126
+ unless paths.empty?
127
+ buf += paths
128
+ end
129
+ end
130
+ end
131
+ end
132
+ buf
133
+ end
134
+
135
+ def missing_imdb_ids_report
136
+ buf = []
137
+ @media_files.titles.each do |title, medias|
138
+ if medias.nil?
139
+ buf << "No media for #{title}"
140
+ else
141
+ medias.each do |media|
142
+ if media.imdb_id.blank?
143
+ buf << " #{title}"
144
+ break
145
+ end
146
+ end
147
+ end
148
+ end
149
+ buf
150
+ end
151
+
152
+ def missing_thumbnails_report
153
+ buf = []
154
+ @media_files.titles.each do |title, medias|
155
+ if medias.nil?
156
+ buf << "No media for #{title}"
157
+ else
158
+ medias.each do |media|
159
+ thumbnail = media.path_to(:thumbnail_extension)
160
+ unless File.exist?(thumbnail)
161
+ buf << " #{thumbnail} #{media.imdb_id.nil? ? '' : media.imdb_id}"
162
+ end
152
163
  end
153
164
  end
154
165
  end
@@ -11,39 +11,39 @@
11
11
  module AppConfig
12
12
  @config = Mash.new
13
13
  @yaml_filespec = File.join(ENV['HOME'], '.dvdprofiler2xbmcrc')
14
-
14
+
15
15
  def self.[](k)
16
16
  @config[k]
17
17
  end
18
-
18
+
19
19
  def self.[]=(k,v)
20
20
  @config[k] = v
21
21
  end
22
-
22
+
23
23
  def self.save
24
24
  begin
25
25
  File.delete(@yaml_filespec) if File.exist?(@yaml_filespec)
26
26
  AppConfig[:logger].info { "saving: #{@yaml_filespec}" }
27
27
  File.open(@yaml_filespec, "w") do |f|
28
- YAML.dump(@config, f)
28
+ YAML.dump(@config, f)
29
29
  end
30
30
  rescue Exception => e
31
31
  AppConfig[:logger].error { "Error saving config file \"#{@yaml_filespec} - " + e.to_s + "\n" + e.backtrace.join("\n")}
32
32
  end
33
33
  end
34
-
34
+
35
35
  def self.load
36
36
  begin
37
37
  if File.exist?(@yaml_filespec)
38
- @config.merge YAML.load_file(@yaml_filespec)
38
+ @config.merge YAML.load_file(@yaml_filespec)
39
39
  end
40
40
  rescue Exception => e
41
41
  AppConfig[:logger].error { "Error loading config file \"#{@yaml_filespec} - " + e.to_s }
42
42
  end
43
43
  end
44
-
44
+
45
45
  def self.default
46
- # Note, all paths and extensions are case sensitive
46
+ # Note, all paths and extensions are case sensitive
47
47
 
48
48
  # Array of paths to scan for media
49
49
  # Note, directories underneath these will be added as genres to
@@ -53,10 +53,10 @@ module AppConfig
53
53
  # Also note, that duplicate genres will be collapsed into single
54
54
  # genres in the .nfo file.
55
55
  @config.directories = [
56
- '/media/dad-kubuntu/public/data/videos_iso',
57
- '/media/dcerouter/public/data/videos_iso',
58
- '/media/royw-gentoo/public/data/videos_iso',
59
- '/media/royw-gentoo/public/data/movies'
56
+ '/media/dad-kubuntu/public/data/videos_iso',
57
+ '/media/dcerouter/public/data/videos_iso',
58
+ '/media/royw-gentoo/public/data/videos_iso',
59
+ '/media/royw-gentoo/public/data/movies'
60
60
  ]
61
61
 
62
62
  # Typical locations are:
@@ -80,17 +80,20 @@ module AppConfig
80
80
  @config.nfo_extension = 'nfo'
81
81
  @config.nfo_backup_extension = 'nfo~'
82
82
  @config.no_imdb_extension = 'no_imdb_lookup'
83
+ @config.no_isbn_extension = 'no_isbn'
83
84
 
84
85
  # map some genre names
85
86
  @config.genre_maps = {
86
- 'SciFi' => 'Science Fiction',
87
- 'Science-Fiction' => 'Science Fiction',
88
- 'Anime' => 'Animation',
89
- 'Musical' => 'Musicals'
90
- }
87
+ 'SciFi' => 'Science Fiction',
88
+ 'Science-Fiction' => 'Science Fiction',
89
+ 'Anime' => 'Animation',
90
+ 'Musical' => 'Musicals',
91
+ 'Music' => 'Musicals'
92
+ }
91
93
 
92
94
  @config.file_permissions = 0664
93
95
  @config.dir_permissions = 0777
94
96
  @config.imdb_query = true
97
+ @config.do_update = true
95
98
  end
96
99
  end
@@ -3,7 +3,6 @@ require 'yaml'
3
3
  require 'xmlsimple'
4
4
  require 'ftools'
5
5
  require 'imdb'
6
- require 'pp'
7
6
  require 'mash'
8
7
  require 'log4r'
9
8
  require 'commandline/optionparser'
@@ -13,11 +12,17 @@ require 'dvdprofiler2xbmc/app'
13
12
  require 'dvdprofiler2xbmc/app_config'
14
13
  require 'dvdprofiler2xbmc/collection'
15
14
  require 'dvdprofiler2xbmc/extensions'
16
- require 'dvdprofiler2xbmc/imdb_extensions'
17
15
  require 'dvdprofiler2xbmc/media'
18
16
  require 'dvdprofiler2xbmc/media_files'
19
17
  require 'dvdprofiler2xbmc/nfo'
20
18
 
19
+ # Command Line interface for the Dvdprofiler2Xbmc application.
20
+ # All application output is via AppConfig[:logger] so we have
21
+ # to set up the logger here.
22
+ # Also handle the command line options.
23
+ # Finally creates an instance of Dvdprofiler2Xbmc and executes
24
+ # it.
25
+
21
26
  module Dvdprofiler2xbmc
22
27
  # == Synopsis
23
28
  # Command line exit codes
@@ -33,47 +38,47 @@ module Dvdprofiler2xbmc
33
38
 
34
39
  def self.execute(stdout, arguments=[])
35
40
  exit_code = ExitCode::OK
36
-
37
- # we start a STDOUT logger, but it will be switched after
41
+
42
+ # we start a STDOUT logger, but it will be switched after
38
43
  # the config files are read if config[:logger_output] is set
39
44
  logger = Log4r::Logger.new('dvdprofiler2xbmc')
40
45
  logger.outputters = Log4r::StdoutOutputter.new(:console)
41
46
  logger.level = Log4r::DEBUG
42
-
47
+
43
48
  begin
44
- # trap ^C interrupts and let the app instance cleanly exit any long loops
45
- Signal.trap("INT") {DvdProfiler2Xbmc.interrupt}
46
-
47
-
48
- # parse the command line
49
- options = setupParser()
50
- od = options.parse(arguments)
51
-
52
- # load config values
53
- AppConfig.default
54
-
55
- # the first reinitialize_logger adds the command line logging options to the default config
56
- # then we load the config files
57
- # then we run reinitialize_logger again to modify the logger for any logging options from the config files
58
-
59
- reinitialize_logger(logger, od["--quiet"], od["--debug"])
60
- AppConfig.load
61
- # AppConfig[:pretend] = od["--pretend"]
62
- AppConfig[:imdb_query] = !od["--no_imdb_query"]
63
- AppConfig.save
64
- reinitialize_logger(logger, od["--quiet"], od["--debug"])
65
-
66
- unless od["--help"] || od["--version"]
67
- # create and execute class instance here
68
- app = DvdProfiler2Xbmc.new
69
- app.execute
70
- app.report.each {|line| puts line}
71
- end
49
+ # trap ^C interrupts and let the app instance cleanly exit any long loops
50
+ Signal.trap("INT") {DvdProfiler2Xbmc.interrupt}
51
+
52
+ # parse the command line
53
+ options = setupParser()
54
+ od = options.parse(arguments)
55
+
56
+ # load config values
57
+ AppConfig.default
58
+
59
+ # the first reinitialize_logger adds the command line logging options to the default config
60
+ # then we load the config files
61
+ # then we run reinitialize_logger again to modify the logger for any logging options from the config files
62
+
63
+ reinitialize_logger(logger, od["--quiet"], od["--debug"])
64
+ AppConfig.load
65
+ AppConfig[:imdb_query] = !od["--no_imdb_query"]
66
+ AppConfig.save
67
+ reinitialize_logger(logger, od["--quiet"], od["--debug"])
68
+
69
+ AppConfig[:do_update] = !od["--reports"]
70
+
71
+ unless od["--help"] || od["--version"]
72
+ # create and execute class instance here
73
+ app = DvdProfiler2Xbmc.instance
74
+ app.execute
75
+ app.report.each {|line| puts line}
76
+ end
72
77
  rescue Exception => eMsg
73
- logger.error {eMsg.to_s}
74
- logger.error {options.to_s}
75
- logger.error {eMsg.backtrace.join("\n")}
76
- exit_code = ExitCode::CRITICAL
78
+ logger.error {eMsg.to_s}
79
+ logger.error {options.to_s}
80
+ logger.error {eMsg.backtrace.join("\n")}
81
+ exit_code = ExitCode::CRITICAL
77
82
  end
78
83
  exit_code
79
84
  end
@@ -82,33 +87,33 @@ module Dvdprofiler2xbmc
82
87
  # Returns:: OptionParser instances
83
88
  def self.setupParser()
84
89
  options = OptionParser.new()
85
- options << Option.new(:flag, :names => %w(--help -h),
86
- :opt_found => lambda {Log4r::Logger['dvdprofiler2xbmc'].info{options.to_s}},
87
- :opt_description => "This usage information")
88
- options << Option.new(:flag, :names => %w(--version -v),
89
- :opt_found => lambda {Log4r::Logger['dvdprofiler2xbmc'].info{"Dvdprofiler2xbmc #{Dvdprofiler2xbmc::VERSION}"}},
90
- :opt_description => "This version of dvdprofiler2xbmc")
91
- # options << Option.new(:flag, :names => %w(--pretend -p))
92
- options << Option.new(:flag, :names => %w(--no_imdb_query -n))
93
- options << Option.new(:flag, :names => %w(--quiet -q))
94
- options << Option.new(:flag, :names => %w(--debug -d))
90
+ options << Option.new(:flag, :names => %w(--help -h),
91
+ :opt_found => lambda {Log4r::Logger['dvdprofiler2xbmc'].info{options.to_s}},
92
+ :opt_description => "This usage information")
93
+ options << Option.new(:flag, :names => %w(--version -v),
94
+ :opt_found => lambda {Log4r::Logger['dvdprofiler2xbmc'].info{"Dvdprofiler2xbmc #{Dvdprofiler2xbmc::VERSION}"}},
95
+ :opt_description => "This version of dvdprofiler2xbmc")
96
+ options << Option.new(:flag, :names => %w(--no_imdb_query -n), :opt_description => 'Do not query IMDB.com')
97
+ options << Option.new(:flag, :names => %w(--quiet -q), :opt_description => 'Display error messages only')
98
+ options << Option.new(:flag, :names => %w(--debug -d), :opt_description => 'Display debug messages')
99
+ options << Option.new(:flag, :names => %w(--reports -r), :opt_description => 'Display reports only. Do not do any updates.')
95
100
  options
96
101
  end
97
-
102
+
98
103
  # Reinitialize the logger using the loaded config.
99
104
  # logger:: logger for any user messages
100
105
  # config:: is the application's config hash.
101
106
  def self.reinitialize_logger(logger, quiet, debug)
102
107
  # switch the logger to the one specified in the config files
103
108
  unless AppConfig[:logfile].nil?
104
- logfile_outputter = Log4r::RollingFileOutputter.new(:logfile, :filename => AppConfig[:logfile], :maxsize => 1000000 )
105
- logger.add logfile_outputter
106
- logfile_outputter.level = Log4r::INFO
107
- Log4r::Outputter[:logfile].formatter = Log4r::PatternFormatter.new(:pattern => "[%l] %d :: %M")
108
- unless AppConfig[:logfile_level].nil?
109
- level_map = {'DEBUG' => Log4r::DEBUG, 'INFO' => Log4r::INFO, 'WARN' => Log4r::WARN}
110
- logfile_outputter.level = level_map[AppConfig[:logfile_level]] || Log4r::INFO
111
- end
109
+ logfile_outputter = Log4r::RollingFileOutputter.new(:logfile, :filename => AppConfig[:logfile], :maxsize => 1000000 )
110
+ logger.add logfile_outputter
111
+ logfile_outputter.level = Log4r::INFO
112
+ Log4r::Outputter[:logfile].formatter = Log4r::PatternFormatter.new(:pattern => "[%l] %d :: %M")
113
+ unless AppConfig[:logfile_level].nil?
114
+ level_map = {'DEBUG' => Log4r::DEBUG, 'INFO' => Log4r::INFO, 'WARN' => Log4r::WARN}
115
+ logfile_outputter.level = level_map[AppConfig[:logfile_level]] || Log4r::INFO
116
+ end
112
117
  end
113
118
  Log4r::Outputter[:console].level = Log4r::INFO
114
119
  Log4r::Outputter[:console].level = Log4r::WARN if quiet
@@ -118,5 +123,4 @@ module Dvdprofiler2xbmc
118
123
  end
119
124
  end
120
125
  end
121
-
122
-
126
+
@@ -42,7 +42,7 @@ class Collection
42
42
  save
43
43
  end
44
44
 
45
- # save as a collection.yaml file unless the existing
45
+ # save as a collection.yaml file unless the existing
46
46
  # collection.yaml is newer than the collection.xml
47
47
  def save
48
48
  unless @filespec.nil?
@@ -65,7 +65,7 @@ class Collection
65
65
  end
66
66
  end
67
67
 
68
- # load the collection from the collection.yaml if it exists,
68
+ # load the collection from the collection.yaml if it exists,
69
69
  # otherwise from the collection.xml
70
70
  def reload
71
71
  @title_isbn_hash.clear
@@ -102,10 +102,10 @@ class Collection
102
102
  name << a['FirstName'] unless a['FirstName'].blank?
103
103
  name << a['MiddleName'] unless a['MiddleName'].blank?
104
104
  name << a['LastName'] unless a['LastName'].blank?
105
- info = {}
106
- info['name'] = name.join(' ')
107
- info['role'] = a['Role']
108
- info
105
+ info = {}
106
+ info['name'] = name.join(' ')
107
+ info['role'] = a['Role']
108
+ info
109
109
  end
110
110
  end
111
111
  dvd_hash[:genres] = dvd[:genres].collect{|a| a[:genre]}.flatten unless dvd[:genres].blank?
@@ -148,7 +148,7 @@ class Collection
148
148
  title = src_title.dup
149
149
  title.downcase!
150
150
  TITLE_REPLACEMENTS.each do |replacement|
151
- replacement.each do |regex, value|
151
+ replacement.each do |regex, value|
152
152
  title.gsub!(regex, value)
153
153
  end
154
154
  end
@@ -54,13 +54,13 @@ class Object
54
54
  def blank?
55
55
  result = nil?
56
56
  unless result
57
- if respond_to? 'empty?'
58
- if respond_to? 'strip'
59
- result = strip.empty?
60
- else
61
- result = empty?
62
- end
63
- end
57
+ if respond_to? 'empty?'
58
+ if respond_to? 'strip'
59
+ result = strip.empty?
60
+ else
61
+ result = empty?
62
+ end
63
+ end
64
64
  end
65
65
  result
66
66
  end
@@ -83,7 +83,22 @@ class Numeric
83
83
  end
84
84
  end
85
85
  end
86
-
86
+
87
+ # # == Synopsis
88
+ # # add a mkdirs method to the File class
89
+ # class File
90
+ # ##
91
+ # # make directories including any missing in the path
92
+ # #
93
+ # # @param [String] dirspec the path to make sure exists
94
+ # def File.mkdirs(dirspec)
95
+ # unless File.exists?(dirspec)
96
+ # mkdirs(File.dirname(dirspec))
97
+ # Dir.mkdir(dirspec)
98
+ # end
99
+ # end
100
+ # end
101
+
87
102
  # == Synopsis
88
103
  # add a timer method to the Kernel
89
104
  module Kernel
@@ -1,35 +1,56 @@
1
1
  # == Synopsis
2
2
  # Media encapsulates information about a single media file
3
3
  class Media
4
- attr_reader :media_path, :nfo_files, :image_files, :year, :media_subdirs
5
- attr_accessor :isbn
4
+ attr_reader :media_path, :image_files, :year, :media_subdirs, :title, :title_with_year
6
5
 
7
6
  DISC_NUMBER_REGEX = /\.(cd|part|disk|disc)\d+/i
8
7
 
9
- def initialize(directory, media_file)
8
+ def initialize(directory, media_file, collection)
9
+ @collection = collection
10
10
  @media_subdirs = File.dirname(media_file)
11
11
  @media_path = File.expand_path(File.join(directory, media_file))
12
12
  Dir.chdir(File.dirname(@media_path))
13
13
  @nfo_files = Dir.glob("*.{#{AppConfig[:nfo_extensions].join(',')}}")
14
- @image_files = Dir.glob("*.{#{AppConfig[:media_extensions].join(',')}}")
14
+ @image_files = Dir.glob("*.{#{AppConfig[:thumbnail_extension]}}")
15
15
  @year = $1 if File.basename(@media_path) =~ /\s\-\s(\d{4})/
16
+ @title = find_title(@media_path)
17
+ @title_with_year = find_title_with_year(@title, @year)
18
+
19
+ @nfo = NFO.new(self, @collection)
20
+ @loaded = false
16
21
  end
17
22
 
18
- # return the media's title extracted from the filename and cleaned up
19
- def title
20
- if @title.nil?
21
- # ditch extensions including disc number (ex, a.part2.b => a, a.cd1.b => a)
22
- @title = File.basename(@media_path, ".*").gsub(DISC_NUMBER_REGEX, '')
23
- @title.gsub!(/\s\-\s\d{4}/, '') # remove year
24
- @title.gsub!(/\s\-\s0/, '') # remove "- 0", i.e., bad year
25
- @title.gsub!(/\(\d{4}\)/, '') # remove (year)
26
- @title.gsub!(/\[.+\]/, '') # remove square brackets
27
- @title.gsub!(/\s\s+/, ' ') # remove multiple whitespace
28
- @title = @title.strip # remove leading and trailing whitespace
29
- end
30
- @title
23
+ # load existing meta-data
24
+ def load
25
+ @nfo.load
26
+ @loaded = true
27
+ end
28
+
29
+ # update the meta-data and thumbnails
30
+ def update
31
+ load unless @loaded
32
+ @nfo.update
33
+ update_thumbnail
34
+ end
35
+
36
+ # return the ISBN or nil
37
+ def isbn
38
+ @nfo.isbn
39
+ end
40
+
41
+ # return the IMDB ID or nil
42
+ def imdb_id
43
+ @nfo.imdb_id
31
44
  end
32
45
 
46
+ # return a path to a file file based on the media's filespec
47
+ # but without any stacking parts and with the given extension
48
+ # instead of the media's extension.
49
+ # Example:
50
+ # media_path = '/a/b/c.m4v'
51
+ # path_to('nfo') => '/a/b/c.nfo'
52
+ # media_path = '/a/b/c.part1.m4v'
53
+ # path_to('nfo') => '/a/b/c.nfo'
33
54
  def path_to(type)
34
55
  # ditch all extensions (ex, a.b => a, a.cd1.b => a)
35
56
  new_path = File.basename(@media_path, ".*").gsub(DISC_NUMBER_REGEX, '')
@@ -39,13 +60,6 @@ class Media
39
60
  File.join(File.dirname(@media_path), new_path)
40
61
  end
41
62
 
42
- # return the media's title but with the (year) appended
43
- def title_with_year
44
- name = title
45
- name = "#{name} (#{@year})" unless @year.nil?
46
- name
47
- end
48
-
49
63
  def to_s
50
64
  buf = []
51
65
  buf << @media_path
@@ -53,4 +67,72 @@ class Media
53
67
  buf << title_with_year
54
68
  buf.join(' ')
55
69
  end
70
+
71
+ protected
72
+
73
+ # update the movie's thumbnail (.tbn) image
74
+ def update_thumbnail
75
+ if @nfo.isbn.blank?
76
+ unless @nfo.imdb_id.blank?
77
+ if @image_files.empty?
78
+ fetch_imdb_thumbnail(@nfo.imdb_id)
79
+ end
80
+ end
81
+ else
82
+ copy_thumbnail(@nfo.isbn)
83
+ end
84
+ @nfo.save
85
+ end
86
+
87
+ # fetch the thumbnail from IMDB and save as path_to('tbn')
88
+ def fetch_imdb_thumbnail(imdb_id)
89
+ imdb_movie = ImdbMovie.new(imdb_id.gsub(/^tt/, ''))
90
+ source_uri = imdb_movie.poster.image
91
+ dest_image_filespec = path_to(:thumbnail_extension)
92
+ puts "fetch_imdb_thumbnail(#{imdb_id}) => #{source_uri}"
93
+ begin
94
+ File.open(dest_image_filespec, "wb") {|f| f.write(open(source_uri).read)}
95
+ rescue Exception => e
96
+ AppConfig[:logger].error { "Error downloading image from \"#{source_uri}\" to \"#{dest_image_filespec}\" - #{e.to_s}" }
97
+ end
98
+ end
99
+
100
+ # copy images from .../isbn.jpg to .../basename.jpg
101
+ def copy_thumbnail(isbn)
102
+ src_image_filespec = File.join(AppConfig[:images_dir], "#{isbn}f.jpg")
103
+ if File.exist?(src_image_filespec)
104
+ dest_image_filespec = path_to(:thumbnail_extension)
105
+ do_copy = true
106
+ if File.exist?(dest_image_filespec)
107
+ if File.mtime(src_image_filespec) <= File.mtime(dest_image_filespec)
108
+ do_copy = false
109
+ end
110
+ end
111
+ begin
112
+ File.copy(src_image_filespec, dest_image_filespec) if do_copy
113
+ rescue Exception => e
114
+ AppConfig[:logger].error {e.to_s}
115
+ end
116
+ end
117
+ end
118
+
119
+ # return the media's title extracted from the filename and cleaned up
120
+ def find_title(media_path)
121
+ # ditch extensions including disc number (ex, a.part2.b => a, a.cd1.b => a)
122
+ title = File.basename(media_path, ".*").gsub(DISC_NUMBER_REGEX, '')
123
+ title.gsub!(/\s\-\s\d{4}/, '') # remove year
124
+ title.gsub!(/\s\-\s0/, '') # remove "- 0", i.e., bad year
125
+ title.gsub!(/\(\d{4}\)/, '') # remove (year)
126
+ title.gsub!(/\[.+\]/, '') # remove square brackets
127
+ title.gsub!(/\s\s+/, ' ') # remove multiple whitespace
128
+ title.strip # remove leading and trailing whitespace
129
+ end
130
+
131
+ # return the media's title but with the (year) appended
132
+ def find_title_with_year(title, year)
133
+ name = title
134
+ name = "#{name} (#{year})" unless year.nil?
135
+ name
136
+ end
137
+
56
138
  end
@@ -1,33 +1,49 @@
1
1
  # == Synopsis
2
2
  # encapsulation of all media files
3
3
  class MediaFiles
4
- attr_reader :medias, :titles
4
+ attr_reader :medias, :titles, :duplicate_titles
5
5
 
6
6
  # given:
7
7
  # directories Array of String directory pathspecs
8
- def initialize(directories)
9
- @medias = []
8
+ def initialize(directories, collection)
9
+ @collection = collection
10
+ @medias = find_medias(directories)
11
+ @titles = find_titles(@medias)
12
+ @duplicate_titles = find_duplicate_titles(@titles)
13
+ end
14
+
15
+ protected
16
+
17
+ # find all the media files in the given set of directories
18
+ def find_medias(directories)
19
+ medias = []
10
20
  directories.each do |dir|
11
21
  Dir.chdir(dir)
12
- @medias += Dir.glob("**/*.{#{AppConfig[:media_extensions].join(',')}}").collect do |filename|
13
- Media.new(dir, filename)
22
+ medias += Dir.glob("**/*.{#{AppConfig[:media_extensions].join(',')}}").collect do |filename|
23
+ Media.new(dir, filename, @collection)
14
24
  end
15
25
  end
16
- @titles = {}
17
- @medias.each do |media|
26
+ medias
27
+ end
28
+
29
+ # return a hash where the key is the media's title and
30
+ # the value is an Array of Media instances
31
+ def find_titles(medias)
32
+ titles = {}
33
+ medias.each do |media|
18
34
  title = media.title_with_year
19
- @titles[title] ||= []
20
- @titles[title] << media
35
+ titles[title] ||= []
36
+ titles[title] << media
21
37
  end
38
+ titles
22
39
  end
23
40
 
24
-
25
41
  # find duplicate titles and return them in a hash
26
42
  # where the key is the title and the value is an
27
43
  # array of Media objects
28
- def duplicate_titles
44
+ def find_duplicate_titles(titles)
29
45
  duplicates = {}
30
- @titles.each do |title, medias|
46
+ titles.each do |title, medias|
31
47
  base_medias = medias.collect{|media| media.path_to(:base) }.uniq
32
48
  if base_medias.length > 1
33
49
  duplicates[title] = medias
@@ -35,5 +51,6 @@ class MediaFiles
35
51
  end
36
52
  duplicates
37
53
  end
54
+
38
55
  end
39
56
 
@@ -1,81 +1,146 @@
1
+
1
2
  # == Synopsis
2
3
  # NFO (info) files
4
+ #
5
+ # the @movie hash has keys that map directly to the .nfo file
6
+ # the @dvd_hash has keys that map to DVD Profiler's Collection.xml file
3
7
  class NFO
4
- def initialize(media, dvd_hash)
8
+ def initialize(media, collection)
5
9
  @media = media
6
- @dvd_hash = dvd_hash
7
- load
10
+ @collection = collection
11
+ @dvd_hash = {}
12
+ @movie = {}
8
13
  end
9
14
 
10
15
  # save as a .nfo file, creating a backup if the .nfo already exists
11
16
  def save
12
17
  begin
13
- nfo_filespec = @media.path_to(:nfo_extension)
14
- nfo_backup_filespec = @media.path_to(:nfo_backup_extension)
15
- File.delete(nfo_backup_filespec) if File.exist?(nfo_backup_filespec)
16
- File.rename(nfo_filespec, nfo_backup_filespec) if File.exist?(nfo_filespec)
17
- File.open(nfo_filespec, "w") do |file|
18
- file.puts(to_nfo(@dvd_hash))
18
+ unless @movie.empty?
19
+ @movie['title'] = @media.title if @movie['title'].blank?
20
+ nfo_filespec = @media.path_to(:nfo_extension)
21
+ nfo_backup_filespec = @media.path_to(:nfo_backup_extension)
22
+ File.delete(nfo_backup_filespec) if File.exist?(nfo_backup_filespec)
23
+ File.rename(nfo_filespec, nfo_backup_filespec) if File.exist?(nfo_filespec)
24
+ File.open(nfo_filespec, "w") do |file|
25
+ file.puts(to_xml)
26
+ end
19
27
  end
20
28
  rescue Exception => e
21
- AppConfig[:logger].error { "Error saving nfo file - " + e.to_s }
29
+ AppConfig[:logger].error { "Error saving nfo file - " + e.to_s + "\n" + e.backtrace.join("\n")}
22
30
  end
23
31
  end
24
32
 
33
+ # load the .nfo file into the @movie hash
25
34
  def load
35
+ nfo_filespec = @media.path_to(:nfo_extension)
26
36
  begin
27
- nfo_filespec = @media.path_to(:nfo_extension)
28
- @movie = XmlSimple.xml_in(nfo_filespec) if File.exist? nfo_filespec
37
+ if File.exist?(nfo_filespec) && (File.size(nfo_filespec) > 1)
38
+ File.open(nfo_filespec) do |file|
39
+ @movie = XmlSimple.xml_in(file)
40
+ end
41
+ end
29
42
  rescue Exception => e
30
- AppConfig[:logger].error { "Error loading \"#{nfo_filespec}\" - " + e.to_s }
43
+ AppConfig[:logger].error { "Error loading \"#{nfo_filespec}\" - " + e.to_s + "\n" + e.backtrace.join("\n") }
44
+ raise e
31
45
  end
32
46
  end
33
47
 
34
- # return a nfo xml String from the given dvd_hash (from Collection)
35
- def to_nfo(dvd_hash)
36
- @movie ||= {}
37
- imdb_id = @movie['id']
38
- if AppConfig[:imdb_query] && imdb_id.blank?
39
- unless File.exist?(@media.path_to(:no_imdb_extension))
40
- imdb_id = imdb_lookup(dvd_hash)
48
+ # merge meta-data from the DVD Profiler collection.xml and from IMDB
49
+ # into the @movie hash
50
+ def update
51
+ begin
52
+ load_from_collection
53
+ if AppConfig[:imdb_query] && imdb_id.blank?
54
+ load_from_imdb
41
55
  end
56
+ @movie.merge!(to_movie(@dvd_hash))
57
+ rescue Exception => e
58
+ AppConfig[:logger].error { "Error updating \"#{nfo_filespec}\" - " + e.to_s + "\n" + e.backtrace.join("\n") }
59
+ raise e
42
60
  end
43
- @movie['title'] = dvd_hash[:title]
44
- @movie['mpaa'] = dvd_hash[:rating]
45
- @movie['year'] = dvd_hash[:productionyear]
46
- @movie['outline'] = dvd_hash[:overview]
47
- # @movie['plot'] = dvd_hash[:overview]
48
- @movie['runtime'] = dvd_hash[:runningtime]
49
- @movie['genre'] = map_genres((dvd_hash[:genres] + @media.media_subdirs.split('/')).uniq)
50
- @movie['actor'] = dvd_hash[:actors]
51
- @movie['id'] = imdb_id unless imdb_id.nil?
52
- @movie['isbn'] = dvd_hash[:isbn]
61
+ end
53
62
 
54
- begin
55
- XmlSimple.xml_out(@movie, 'NoAttr' => true, 'RootName' => 'movie')
56
- rescue Exception => e
57
- AppConfig[:logger].error { "Error creating nfo file - " + e.to_s }
63
+ # return the ISBN or nil
64
+ def isbn
65
+ if @dvd_hash[:isbn].blank?
66
+ @dvd_hash[:isbn] = @movie['isbn']
58
67
  end
68
+ @dvd_hash[:isbn]
69
+ end
70
+
71
+ # set the ISBN
72
+ def isbn=(isbn)
73
+ @dvd_hash[:isbn] = isbn
74
+ end
75
+
76
+ # return the IMDB ID or nil
77
+ def imdb_id
78
+ if @dvd_hash[:imdb_id].nil?
79
+ @dvd_hash[:imdb_id] = @movie['id']
80
+ end
81
+ unless @dvd_hash[:imdb_id].nil?
82
+ # make sure is not an array
83
+ @dvd_hash[:imdb_id] = [@dvd_hash[:imdb_id]].flatten.uniq.compact.first
84
+ end
85
+ end
86
+
87
+ # set the IMDB ID
88
+ def imdb_id=(id)
89
+ @dvd_hash[:imdb_id] = id
59
90
  end
60
91
 
61
92
  protected
62
93
 
63
- def map_genres(genres)
64
- new_genres = []
65
- genres.each do |genre|
66
- new_genres << (AppConfig[:genre_maps][genre].nil? ? genre : AppConfig[:genre_maps][genre])
94
+ # load @dvd_hash from the collection
95
+ def load_from_collection
96
+ # find ISBN for each title and assign to the media
97
+ if isbn.nil?
98
+ title_pattern = Collection.title_pattern(@media.title)
99
+ unless @collection.title_isbn_hash[title_pattern].nil?
100
+ isbn = [@collection.title_isbn_hash[title_pattern]].flatten.uniq.compact.first
101
+ end
102
+ end
103
+
104
+ # merge the meta-data from the collection to dvd_hash
105
+ unless isbn.nil?
106
+ collection_hash = @collection.isbn_dvd_hash[isbn]
107
+ @dvd_hash.merge!(collection_hash) unless collection_hash.blank?
67
108
  end
68
- new_genres.uniq.compact
109
+ end
110
+
111
+ # load data from IMDB.com and merge into the @dvd_hash
112
+ def load_from_imdb
113
+ unless File.exist?(@media.path_to(:no_imdb_extension))
114
+ years = (@media.year.nil? ? released_years(@dvd_hash) : [@media.year])
115
+ title = (@dvd_hash[:title].nil? ? @media.title : @dvd_hash[:title])
116
+ self.imdb_id = imdb_lookup(title, years) if self.imdb_id.blank?
117
+ unless self.imdb_id.nil?
118
+ imdb_movie = ImdbMovie.new(self.imdb_id.gsub(/^tt/, ''))
119
+ @dvd_hash.merge!(to_dvd_hash(imdb_movie))
120
+ end
121
+ end
122
+ end
123
+
124
+ # convert the @movie hash into xml and return the xml as a String
125
+ def to_xml
126
+ xml = ''
127
+ begin
128
+ xml = XmlSimple.xml_out(@movie, 'NoAttr' => true, 'RootName' => 'movie')
129
+ rescue Exception => e
130
+ AppConfig[:logger].error { "Error creating nfo file - " + e.to_s}
131
+ raise e
132
+ end
133
+ xml
69
134
  end
70
135
 
71
136
  # try to find the imdb id for the movie
72
- def imdb_lookup(dvd_hash)
137
+ def imdb_lookup(title, years)
73
138
  id = nil
74
- AppConfig[:logger].info { "Searching IMDB for \"#{dvd_hash[:title]}\"" }
75
- unless dvd_hash[:title].blank?
76
- years = released_years(dvd_hash)
139
+
140
+ AppConfig[:logger].info { "Searching IMDB for \"#{title}\"" }
141
+ unless title.blank?
77
142
  begin
78
- imdb_search = ImdbSearch.new(dvd_hash[:title])
143
+ imdb_search = ImdbSearch.new(title)
79
144
  id = imdb_search.find_id(:years => years, :media_path => @media.media_path)
80
145
  rescue Exception => e
81
146
  AppConfig[:logger].error { "Error searching IMDB - " + e.to_s }
@@ -95,13 +160,57 @@ class NFO
95
160
  end
96
161
  unless dvd_hash[:released].blank?
97
162
  years += dvd_hash[:released].collect do |date|
98
- y = nil
99
- y = $1.to_i if date =~ /(\d{4})\-/
100
- y
163
+ y = nil
164
+ y = $1.to_i if date =~ /(\d{4})\-/
165
+ y
101
166
  end
102
167
  end
103
168
  years.flatten.uniq.compact.sort
104
169
  end
105
170
 
171
+ # given a ImdbMovie instance, extract meta-data into and return a dvd_hash
172
+ def to_dvd_hash(imdb_movie)
173
+ dvd_hash = {}
174
+ dvd_hash[:title] = imdb_movie.title
175
+ dvd_hash[:imdb_id] = 'tt' + imdb_movie.id.gsub(/^tt/,'') unless imdb_movie.id.blank?
176
+ dvd_hash[:rating] = imdb_movie.mpaa
177
+ dvd_hash[:rating] ||= imdb_movie.certifications['USA']
178
+ dvd_hash[:productionyear] = imdb_movie.release_year
179
+ dvd_hash[:plot] = imdb_movie.plot
180
+ dvd_hash[:runningtime] = imdb_movie.length
181
+ dvd_hash[:genre] = imdb_movie.genres
182
+ dvd_hash[:actor] = imdb_movie.cast_members
183
+ dvd_hash
184
+ end
185
+
186
+ # map the given dvd_hash into a @movie hash
187
+ def to_movie(dvd_hash)
188
+ dvd_hash[:genres] ||= []
189
+ genres = map_genres((dvd_hash[:genres] + @media.media_subdirs.split('/')).uniq)
190
+ movie = {}
191
+ movie['title'] = dvd_hash[:title]
192
+ movie['mpaa'] = dvd_hash[:rating] unless dvd_hash[:rating].blank?
193
+ movie['year'] = dvd_hash[:productionyear] unless dvd_hash[:productionyear].blank?
194
+ movie['outline'] = dvd_hash[:overview] unless dvd_hash[:overview].blank?
195
+ movie['plot'] = dvd_hash[:plot] unless dvd_hash[:plot].blank?
196
+ movie['runtime'] = dvd_hash[:runningtime] unless dvd_hash[:runningtime].blank?
197
+ movie['actor'] = dvd_hash[:actors] unless dvd_hash[:actors].blank?
198
+ movie['isbn'] = dvd_hash[:isbn] unless dvd_hash[:isbn].blank?
199
+ movie['id'] = dvd_hash[:imdb_id] unless dvd_hash[:imdb_id].blank?
200
+ movie['genre'] = genres unless genres.blank?
201
+ movie
202
+ end
203
+
204
+ # map the given genres using the AppConfig[:genre_maps].
205
+ # given an Array of String genres
206
+ # returns an Array of String genres that have been mapped, are unique, and do not include any nils
207
+ def map_genres(genres)
208
+ new_genres = []
209
+ genres.each do |genre|
210
+ new_genres << (AppConfig[:genre_maps][genre].nil? ? genre : AppConfig[:genre_maps][genre])
211
+ end
212
+ new_genres.uniq.compact
213
+ end
214
+
106
215
  end
107
216
 
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.3
4
+ version: 0.0.4
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-03-20 00:00:00 -07:00
12
+ date: 2009-03-25 00:00:00 -07:00
13
13
  default_executable: dvdprofiler2xbmc
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -33,14 +33,14 @@ dependencies:
33
33
  version: 1.0.12
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
- name: porras-imdb
36
+ name: royw-imdb
37
37
  type: :runtime
38
38
  version_requirement:
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.0.5
43
+ version: 0.0.8
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: log4r
@@ -111,15 +111,15 @@ files:
111
111
  - README.rdoc
112
112
  - Rakefile
113
113
  - bin/dvdprofiler2xbmc
114
+ - dvdprofiler2xbmc.gemspec
114
115
  - lib/dvdprofiler2xbmc.rb
115
- - lib/dvdprofiler2xbmc/app_config.rb
116
116
  - lib/dvdprofiler2xbmc/app.rb
117
+ - lib/dvdprofiler2xbmc/app_config.rb
117
118
  - lib/dvdprofiler2xbmc/cli.rb
118
119
  - lib/dvdprofiler2xbmc/collection.rb
119
120
  - lib/dvdprofiler2xbmc/extensions.rb
120
- - lib/dvdprofiler2xbmc/imdb_extensions.rb
121
- - lib/dvdprofiler2xbmc/media_files.rb
122
121
  - lib/dvdprofiler2xbmc/media.rb
122
+ - lib/dvdprofiler2xbmc/media_files.rb
123
123
  - lib/dvdprofiler2xbmc/nfo.rb
124
124
  - test/test_dvdprofiler2xbmc.rb
125
125
  - test/test_helper.rb
@@ -1,95 +0,0 @@
1
- class ImdbMovie
2
- def raw_title
3
- document.at("h1").innerText
4
- end
5
-
6
- def video_game?
7
- raw_title =~ /\(VG\)/
8
- end
9
-
10
- def release_year
11
- document.search("//h5[text()^='Release Date']/..").innerHTML[/\d{4}/]
12
- end
13
-
14
- # return an Array of Strings containing AKA titles
15
- def also_known_as
16
- el = document.search("//h5[text()^='Also Known As:']/..").at('h5')
17
- aka = []
18
- while(!el.nil?)
19
- aka << el.to_s unless el.elem?
20
- el = el.next
21
- end
22
- aka.collect!{|a| a.gsub(/\([^\)]*\)/, '').strip}
23
- aka.uniq!
24
- aka.collect!{|a| a.blank? ? nil : a}
25
- aka.compact!
26
- aka
27
- end
28
- end
29
-
30
- class ImdbSearch
31
- # Find the IMDB ID for the current search title
32
- # The find can be helped a lot by including a years option that contains
33
- # an Array of integers that are the production year (plus/minus a year)
34
- # and the release year.
35
- def find_id(options={})
36
- id = nil
37
- found_movies = self.movies
38
- unless found_movies.nil?
39
- desired_movies = found_movies.select do |m|
40
- aka = m.also_known_as
41
- result = imdb_compare_titles(m.title, aka, @query) && !m.video_game? && !m.release_year.blank?
42
- if result
43
- AppConfig[:logger].debug { m.title }
44
- AppConfig[:logger].debug { "m.release_year => #{m.release_year}" }
45
- unless options[:years].blank?
46
- result = options[:years].include?(m.release_year.to_i)
47
- end
48
- end
49
- result
50
- end
51
- ids = desired_movies.collect{|m| m.id}.uniq.compact
52
- if ids.length == 1
53
- id = "tt#{ids[0]}"
54
- else
55
- AppConfig[:logger].debug { options[:media_path] } unless options[:media_path].nil?
56
- AppConfig[:logger].debug { options[:years].pretty_inspect }
57
- desired_movies.collect{|m| [m.raw_title, m.id, m.title, m.url, m.release_year.blank? ? 'no release date' : m.release_year]}.uniq.compact.each do |m|
58
- AppConfig[:logger].debug { m.pretty_inspect }
59
- end
60
- end
61
- end
62
- id
63
- end
64
-
65
- protected
66
-
67
- # compare the imdb title and the imdb title's AKAs against the media title.
68
- # note, on exact match lookups, IMDB will sometimes set the title to
69
- # 'trailers and videos' instead of the correct title.
70
- def imdb_compare_titles(imdb_title, aka_titles, media_title)
71
- result = fuzzy_compare_titles(imdb_title, media_title)
72
- unless result
73
- result = fuzzy_compare_titles(imdb_title, 'trailers and videos')
74
- unless result
75
- aka_titles.each do |aka|
76
- result = fuzzy_compare_titles(aka, media_title)
77
- break if result
78
- end
79
- end
80
- end
81
- result
82
- end
83
-
84
- # a fuzzy compare that is case insensitive and replaces '&' with 'and'
85
- # (because that is what IMDB occasionally does)
86
- def fuzzy_compare_titles(title1, title2)
87
- t1 = title1.downcase
88
- t2 = title2.downcase
89
- (t1 == t2) ||
90
- (t1.gsub(/&/, 'and') == t2.gsub(/&/, 'and')) ||
91
- (t1.gsub(/[-:]/, ' ') == t2.gsub(/[-:]/, ' ')) ||
92
- (t1.gsub('more at imdbpro ?', '') == t2)
93
- end
94
- end
95
-