media_processing_tool 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ # THIS CLASS IS CURRENTLY JUST A PASSTHROUGH TO THE GENERIC PUBLISH MAP PROCESSOR
2
+
3
+ require 'logger'
4
+ require 'udam_utils/publish_map_processor'
5
+ module MediaProcessingTool
6
+
7
+ class Publisher
8
+
9
+ attr_accessor :logger, :object, :publisher
10
+
11
+ # @param [Hash] params
12
+ # @option params [Object|nil] :logger
13
+ # @Option params [String] :config_file_path
14
+ def initialize(params = {})
15
+ @logger = params[:logger] ||= Logger.new(STDOUT)
16
+
17
+ @interrupted = false
18
+ Signal.trap 'INT' do stop end
19
+ Signal.trap 'TERM' do stop end
20
+ Signal.trap 'SIGINT' do stop end
21
+
22
+ #@config_file_path = params[:config_file_path]
23
+ #raise ArgumentError, 'Missing required parameter :config_file_path' unless @config_file_path
24
+ #load_configuration_from_file(@config_file_path)
25
+
26
+
27
+ publisher_options = params
28
+ @publisher = UDAMUtils::GenericPublishMapProcessor.new(publisher_options)
29
+
30
+ end # initialize
31
+
32
+ def stop
33
+ @interrupted = true
34
+ puts 'Quitting on interrupt signal.'
35
+ while true
36
+ puts 'Exiting...'
37
+ exit
38
+ end
39
+ end # stop
40
+
41
+ def process(object, params = { })
42
+ publisher.process_object(params.merge(:object => object))
43
+ end
44
+
45
+ def publish(object, params = {})
46
+ #@object = object
47
+ #publisher.process_object(object)
48
+ end # publish
49
+
50
+ end # Publisher
51
+
52
+ end # MediaProcessingTool
@@ -0,0 +1,30 @@
1
+ require 'media_processing_tool/xml_parser/identifier'
2
+ require 'final_cut_pro/xml_parser'
3
+ require 'itunes/xml_parser'
4
+ module MediaProcessingTool
5
+
6
+ class XMLParser
7
+
8
+ # Gives access to the last document returned by the Identifier
9
+ # This gives access to the identifiers instance parameters (such determined type) for use later
10
+ def self.identifier_document
11
+ @identifier_document
12
+ end # self.identifier_document
13
+
14
+ def self.parse(xml, args = { })
15
+ @identifier_document = Identifier.load(xml, args)
16
+
17
+ case @identifier_document.type
18
+ when :final_cut_pro
19
+ doc = FinalCutPro::XMLParser.parse(@identifier_document.xml_document, args)
20
+ when :itunes
21
+ doc = ITunes::XMLParser.parse(xml, args)
22
+ else
23
+ doc = @identifier_document
24
+ end
25
+ doc
26
+ end # self.parse
27
+
28
+ end # XMLParser
29
+
30
+ end # MediaProcessingTool
@@ -0,0 +1,38 @@
1
+ require 'axml'
2
+
3
+ module MediaProcessingTool
4
+
5
+ class XMLParser
6
+
7
+ class Document
8
+
9
+ def self.xml_as_document(xml, params = {})
10
+ AXML.xml_as_document(xml)
11
+ end # self.xml_as_document
12
+
13
+ def self.load(xml, params = { })
14
+ new(xml, params)
15
+ end # self.load
16
+
17
+ def initialize(xml, params = { })
18
+ @xml_document = self.class.xml_as_document(xml, params)
19
+ end # initialize
20
+
21
+ def xml_document
22
+ @xml_document
23
+ end # xml_document
24
+
25
+ def root
26
+ xml_document.root
27
+ end # root
28
+
29
+ # Gets the
30
+ def root_type
31
+ @root_type ||= root.name
32
+ end # type
33
+
34
+ end # Document
35
+
36
+ end # XMLParser
37
+
38
+ end # MediaProcessingTool
@@ -0,0 +1,43 @@
1
+ require 'media_processing_tool/xml_parser/document'
2
+ module MediaProcessingTool
3
+
4
+ class XMLParser
5
+
6
+ class Identifier < Document
7
+
8
+ def initialize(xml, params = { })
9
+ super(xml, params)
10
+ end # initialize
11
+
12
+ def is_fcpxml?
13
+ root_type == 'fcpxml'
14
+ end # is_fcpxml?
15
+
16
+ def is_xmeml?
17
+ root_type == 'xmeml'
18
+ end # is_xmeml?
19
+
20
+ def is_plist?
21
+ root_type == 'plist'
22
+ end # is_plist?
23
+
24
+ def is_final_cut_pro?
25
+ is_xmeml? || is_fcpxml?
26
+ end # is_final_cut_pro?
27
+
28
+ def is_itunes?
29
+ is_plist? and !xml_document.find('/plist/dict/key[text()="Tracks"]').empty?
30
+ end # is_itunes?
31
+
32
+ def type
33
+ return :final_cut_pro if is_final_cut_pro?
34
+ return :itunes if is_itunes?
35
+ return :plist if is_plist?
36
+ return :unknown
37
+ end # source_application
38
+
39
+ end # Identifier
40
+
41
+ end # XMLParser
42
+
43
+ end # MediaProcessingTool
@@ -0,0 +1,132 @@
1
+ require 'media_processing_tool/xml_parser'
2
+ require 'media_processing_tool/publisher'
3
+ require 'mig'
4
+ module MediaProcessingTool
5
+
6
+ class XMLProcessor
7
+
8
+ def self.process(xml, params = { })
9
+
10
+ end # self.process
11
+
12
+ DEFAULT_FILE_PATH_FIELD_NAME = :path_on_file_system
13
+
14
+ attr_accessor :logger
15
+
16
+ # @return [Boolean] determines if the files parsed from the XML should be sent to a publisher
17
+ attr_accessor :publish
18
+
19
+ def initialize(params = { })
20
+ initialize_logger(params)
21
+
22
+ @publish = params.fetch(:publish, true)
23
+ @default_file_path_field_name = params[:@default_file_path_field_name] || DEFAULT_FILE_PATH_FIELD_NAME
24
+
25
+ initialize_mig(params.dup)
26
+ initialize_default_publisher(params.dup)
27
+ end # initialize
28
+
29
+ def initialize_logger(params = { })
30
+ @logger = params[:logger] ||= Logger.new(params[:log_to] || STDOUT)
31
+ logger.level = params[:log_level] if params[:log_level]
32
+ params[:logger] = logger unless params[:logger]
33
+ end # initialize_logger
34
+
35
+ def initialize_mig(params = {})
36
+ logger.debug { "Initializing Media Processing Tool. #{params}" }
37
+ @mig = MediaInformationGatherer.new(params)
38
+ end # initialize_mig
39
+
40
+ def initialize_default_publisher(params = {})
41
+ logger.debug { "Initializing Default Publisher. #{params}" }
42
+ params[:file_path_field_name] = @default_file_path_field_name
43
+ @default_publisher = MediaProcessingTool::Publisher.new(params)
44
+ end # initialize_publisher
45
+
46
+ def document
47
+ @document
48
+ end # document
49
+ alias :doc :document
50
+
51
+ def document_type
52
+ @identifier_document.type
53
+ end # document_type
54
+
55
+ def publisher(params = {})
56
+ @publisher
57
+ end # publisher
58
+
59
+ def process(xml, params = {})
60
+ @xml_file_path = File.exists?(xml) ? xml : nil
61
+
62
+ @document = XMLParser.parse(xml)
63
+ @identifier_document = XMLParser.identifier_document
64
+ @params = params
65
+
66
+ @files = document.respond_to?(:files) ? document.files : [ ]
67
+ @results = { }
68
+
69
+ #force_default_publisher = params[:force_default_publisher]
70
+ force_default_publisher = params.fetch(:force_default_publisher, true)
71
+
72
+ if force_default_publisher
73
+ @publisher = @default_publisher.dup
74
+ @results[:files] = process_document_files(@files, :publisher => @publisher) if @files
75
+ else
76
+ # TODO PUT IN DYNAMIC PUBLISHER HANDLING
77
+ doc_type = document_type
78
+ end
79
+
80
+ #{ :files => files, :sequences => sequences }
81
+
82
+ @results
83
+ end # process
84
+
85
+ def process_document_files(_files, params = {})
86
+ publisher = params[:publisher]
87
+
88
+ run_mig = params.fetch(:run_mig, true)
89
+
90
+ _results = [ ]
91
+ total_files = _files.length
92
+ current_file_counter = 0
93
+ _files.each do |file|
94
+ current_file_counter += 1
95
+ full_file_path = file[@default_file_path_field_name]
96
+
97
+ logger.debug { "Processing Document File #{current_file_counter} of #{total_files}. File Path: #{full_file_path}" }
98
+ if run_mig
99
+ _mig = run_mig_on_file(full_file_path)
100
+ file[:metadata_sources] = _mig ? _mig.metadata_sources : { }
101
+ else
102
+ logger.debug { 'Media Information Gathering SKIPPED. run_mig set to false.' }
103
+ end
104
+ file[:xml_file_path] = @xml_file_path
105
+ file_result = { file: file }
106
+ file_result[:publish_result] = publisher.process(file) if publish and publisher
107
+
108
+ _results << file_result
109
+ end
110
+ _results
111
+ end # process_files
112
+
113
+ def process_document_sequences(params = {})
114
+ sequences = doc.respond_to?(:sequences) ? doc.sequences : [ ]
115
+ end # process_sequences
116
+
117
+ def process_document_tracks(params = {})
118
+ tracks = doc.respond_to?(:tracks) ? doc.tracks : [ ]
119
+ end # process_tracks
120
+
121
+ def run_mig_on_file(full_file_path, params = {})
122
+ if File.exists?(full_file_path)
123
+ @mig.run(full_file_path)
124
+ return @mig
125
+ else
126
+ logger.debug { "Media Information Gathering SKIPPED. File Not Found. #{full_file_path}" }
127
+ return false
128
+ end
129
+ end # run_mig_on_file
130
+
131
+ end # XMLProcessor
132
+ end # MediaProcessingTool
data/lib/mig.rb ADDED
@@ -0,0 +1,158 @@
1
+ require 'logger'
2
+ require 'mig/modules/exiftool'
3
+ require 'mig/modules/ffmpeg'
4
+ require 'mig/modules/mediainfo'
5
+ require 'mig/modules/media_type'
6
+ require 'mig/modules/common'
7
+
8
+ class MediaInformationGatherer
9
+
10
+ File::Stat.class_eval do
11
+
12
+ TO_HASH_METHODS = [
13
+ :atime, :blksize, :blockdev?, :blocks, :chardev?, :ctime, :dev, :dev_major, :dev_minor, :directory?,
14
+ :executable?, :executable_real?, :file?, :ftype, :gid, :grpowned?, :ino, :mode, :mtime, :nlink, :owned?,
15
+ :pipe?, :rdev, :rdev_major, :rdev_minor, :readable?, :readable_real?,
16
+ :setgid?, :setuid?, :size, :size?, :socket?, :sticky?, :symlink?, :uid,
17
+ :world_readable?, :world_writable?, :writable?, :writable_real?, :zero?
18
+ ]
19
+
20
+ def to_hash
21
+ if defined?(__callee__)
22
+ return (self.methods - Object.methods - [__callee__]).each_with_object({}) { |meth, acc| acc[meth] = self.send(meth) if self.method(meth).arity == 0 }
23
+ else
24
+ #(self.methods - Object.methods).each({}) { |meth, acc| acc[meth] = self.send(meth) if self.method(meth).arity == 0 }
25
+ hash_out = { }
26
+ TO_HASH_METHODS.each do |meth|
27
+ hash_out[meth] = self.send(meth) if self.methods.include?(meth.to_s) and self.method(meth).arity == 0
28
+ end
29
+ return hash_out
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ attr_reader :log, :options
36
+
37
+ # @param [Hash] _options
38
+ # @option options [String] :exiftool_cmd_path
39
+ # @option options [String] :ffmpeg_cmd_path
40
+ # @option options [String] :mediainfo_cmd_path
41
+ def initialize(_options = { })
42
+ @options = { }
43
+ @options.merge!(_options)
44
+
45
+ @log = options[:logger] || $log || Logger.new(STDOUT)
46
+ log.debug { "#{self.class.name} - Options loaded. #{options}" }
47
+
48
+ options[:logger] ||= log
49
+
50
+ params = options.dup
51
+
52
+ @exiftool = ExifTool.new( params )
53
+ @ffmpeg = FFMPEG.new( params )
54
+ @mediainfo = Mediainfo.new( params )
55
+
56
+ @media_typer = MediaType.new
57
+
58
+ @default_run_file_stat = options.fetch(:run_file_stat, true)
59
+ @default_run_file_magic = options.fetch(:run_filemagic, true)
60
+ @default_run_mediainfo = options.fetch(:run_mediainfo, true)
61
+ @default_run_ffmpeg = options.fetch(:run_ffmpeg, true)
62
+ @default_run_exiftool = options.fetch(:run_exiftool, true)
63
+ @default_run_common = options.fetch(:run_common, true)
64
+ end # initialize
65
+
66
+ def media_type; @media_type ||= { } end
67
+ def metadata_sources; @metadata_sources ||= { } end
68
+
69
+ # @param [String] file_path The path to the file to gather information about
70
+ def run(file_path, options = { })
71
+ @media_type = { }
72
+ @metadata_sources = { }
73
+
74
+ raise Errno::ENOENT, "File Not Found. File Path: '#{file_path}'" unless File.exist?(file_path)
75
+
76
+
77
+ gathering_start = Time.now
78
+ log.debug { "Gathering metadata for file: #{file_path}"}
79
+ @metadata_sources = run_modules(file_path, options)
80
+ log.debug { "Metadata gathering completed. Took: #{Time.now - gathering_start} seconds" }
81
+
82
+ metadata_sources
83
+ end # run
84
+
85
+ # @param [String] file_path The path of the file to gather information about
86
+ # @return [Hash]
87
+ def run_modules(file_path, options = { })
88
+ run_file_stat = options.fetch(:run_file_stat, @default_run_file_stat)
89
+ run_filemagic = options.fetch(:run_filemagic, @default_run_filemagic)
90
+ run_mediainfo = options.fetch(:run_mediainfo, @default_run_mediainfo)
91
+ run_ffmpeg = options.fetch(:run_ffmpeg, @default_run_ffmpeg)
92
+ run_exiftool = options.fetch(:run_exiftool, @default_run_exiftool)
93
+ run_common = options.fetch(:run_common, @default_run_common)
94
+
95
+ if run_file_stat
96
+ log.debug { 'Running File Stat.' }
97
+ start = Time.now and metadata_sources[:stat] = File.stat(file_path).to_hash rescue { :error => { :message => $!.message, :backtrace => $!.backtrace } }
98
+ log.debug { "File Stat took #{Time.now - start}" }
99
+ end
100
+
101
+ if run_filemagic
102
+ log.debug { 'Running Filemagic.' }
103
+ start = Time.now and metadata_sources[:filemagic] = @media_typer.run(file_path, options) rescue { :error => { :message => $!.message, :backtrace => $!.backtrace } }
104
+ log.debug { "Filemagic took #{Time.now - start}" }
105
+ end
106
+
107
+ if run_mediainfo
108
+ log.debug { 'Running MediaInfo.' }
109
+ start = Time.now and metadata_sources[:mediainfo] = @mediainfo.run(file_path, options) rescue { :error => { :message => $!.message, :backtrace => $!.backtrace } }
110
+ log.debug { "MediaInfo took #{Time.now - start}" }
111
+ end
112
+
113
+ if run_ffmpeg
114
+ log.debug { 'Running FFMPEG.' }
115
+ start = Time.now and metadata_sources[:ffmpeg] = @ffmpeg.run(file_path, options) rescue { :error => { :message => $!.message, :backtrace => $!.backtrace } }
116
+ log.debug { "FFMpeg took #{Time.now - start}" }
117
+ end
118
+
119
+ if run_exiftool
120
+ log.debug { 'Running ExifTool.' }
121
+ start = Time.now and metadata_sources[:exiftool] = @exiftool.run(file_path) rescue { :error => { :message => $!.message, :backtrace => $!.backtrace } }
122
+ log.debug { "ExifTool took #{Time.now - start}" }
123
+ end
124
+
125
+ set_media_type
126
+ metadata_sources[:media_type] = media_type
127
+
128
+ metadata_sources[:common] = Common.common_variables(metadata_sources) if run_common
129
+
130
+ metadata_sources
131
+ end # run_modules
132
+
133
+ def get_media_type_using_exiftool
134
+ exiftool_md = metadata_sources[:exiftool]
135
+ return unless exiftool_md.is_a?(Hash)
136
+
137
+ mime_type = exiftool_md['MIMEType']
138
+ return unless mime_type.is_a?(String)
139
+
140
+ type, sub_type = mime_type.split('/')
141
+ return unless type
142
+
143
+ { :type => type, :subtype => sub_type }
144
+ end
145
+
146
+ def get_media_type_using_filemagic
147
+ filemagic_md = metadata_sources[:filemagic]
148
+ return unless filemagic_md.is_a?(Hash)
149
+ return unless filemagic_md[:type]
150
+
151
+ filemagic_md
152
+ end
153
+
154
+ def set_media_type
155
+ @media_type = get_media_type_using_filemagic || get_media_type_using_exiftool
156
+ end
157
+
158
+ end # MediaInformationGatherer