seamus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Scott Burton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,40 @@
1
+ = Seamus
2
+
3
+ Seamus is not an Irish monk. Instead, it inspects a file and returns whatever metadata it can determine.
4
+
5
+ == Usage
6
+
7
+ Mix Seamus in to your class and get a hash of #file_attributes appropriate to the file type.
8
+ Provide an instance of File, or any class that responds to #path, and include Seamus:
9
+
10
+ class MyClass
11
+ include Seamus
12
+ attr_accessor :file
13
+
14
+ def initialize(path)
15
+ @path = File.open(path)
16
+ end
17
+ end
18
+
19
+ my_file = MyClass.new("path/to/file.mov")
20
+ my_file.file_attributes
21
+
22
+ # => {"video_codec"=>"h264", "bitrate_units"=>"kb/s", "container"=>"mov,mp4,m4a,3gp,3g2,mj2", "audio_channels_string"=>"stereo", "audio?"=>true, "audio_channels"=>2, "video?"=>true, "audio_sample_rate"=>44100, "bitrate"=>346, "audio_codec"=>"mpeg4aac", "video_colorspace"=>"yuv420p", "height"=>576, "audio_sample_units"=>"Hz", "fps"=>"7.00", "duration"=>84000, "width"=>1024}
23
+
24
+
25
+ Generate thumbnails automatically:
26
+
27
+ my_file.thumbnail {|thumb| my_open_file_instance.write thumb.read }
28
+
29
+ Files that probably can't generate thumbnails (audio, PDF, etc.) will raise ThumbnailError.
30
+
31
+ Video and audio file attributes are inspected using the RVideo gem.
32
+
33
+ == Note on Patches/Pull Requests
34
+
35
+ * I'd be very surprised if anyone wanted to do such a thing.
36
+
37
+
38
+ == Copyright
39
+
40
+ Copyright (c) 2009 Scott Burton. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "seamus"
8
+ gem.summary = %Q{Seamus is not an Irish monk}
9
+ gem.description = %Q{Seamus is not an Irish monk. Instead, it inspects a file and returns whatever metadata it can determine.}
10
+ gem.email = "scottburton11@gmail.com"
11
+ gem.homepage = "http://github.com/scottburton11/Seamus"
12
+ gem.authors = ["Scott Burton"]
13
+ end
14
+
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
+ end
18
+
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+ begin
32
+ require 'cucumber/rake/task'
33
+ Cucumber::Rake::Task.new(:features)
34
+ rescue LoadError
35
+ task :features do
36
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
37
+ end
38
+ end
39
+
40
+
41
+
42
+ task :default => :spec
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION.yml')
47
+ config = YAML.load(File.read('VERSION.yml'))
48
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
49
+ else
50
+ version = ""
51
+ end
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "Seamus #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
58
+
data/Seamus.gemspec ADDED
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{seamus}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Scott Burton"]
9
+ s.date = %q{2009-12-02}
10
+ s.description = %q{Seamus is not an Irish monk. Instead, it inspects a file and returns whatever metadata it can determine.}
11
+ s.email = %q{scottburton11@gmail.com}
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = [
17
+ ".document",
18
+ ".gitignore",
19
+ "LICENSE",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "Seamus.gemspec",
23
+ "VERSION",
24
+ "features/Seamus.feature",
25
+ "features/step_definitions/Seamus_steps.rb",
26
+ "features/support/env.rb",
27
+ "lib/Seamus.rb",
28
+ "lib/core/numeric.rb",
29
+ "lib/mime_table.rb",
30
+ "lib/seamus/inspector.rb",
31
+ "lib/seamus/inspector/application_inspector.rb",
32
+ "lib/seamus/inspector/audio_inspector.rb",
33
+ "lib/seamus/inspector/video_inspector.rb",
34
+ "lib/seamus/processor.rb",
35
+ "lib/seamus/processor/application_processor.rb",
36
+ "lib/seamus/processor/audio_processor.rb",
37
+ "lib/seamus/processor/video_processor.rb",
38
+ "spec/Seamus_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/scottburton11/Seamus}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.5}
45
+ s.summary = %q{Seamus is not an Irish monk}
46
+ s.test_files = [
47
+ "spec/Seamus_spec.rb",
48
+ "spec/spec_helper.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
56
+ else
57
+ end
58
+ else
59
+ end
60
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'Seamus'
3
+
4
+ require 'spec/expectations'
data/lib/Seamus.rb ADDED
@@ -0,0 +1,160 @@
1
+ require 'rvideo'
2
+ require 'digest/md5'
3
+
4
+ require 'tempfile'
5
+
6
+ $LOAD_PATH << './lib'
7
+
8
+ require 'core/numeric'
9
+ require 'seamus/inspector'
10
+ require 'seamus/inspector/video_inspector'
11
+ require 'seamus/inspector/audio_inspector'
12
+ require 'seamus/inspector/application_inspector'
13
+ require 'seamus/processor'
14
+ require 'seamus/processor/video_processor'
15
+ require 'seamus/processor/audio_processor'
16
+ require 'seamus/processor/application_processor'
17
+ require 'mime_table'
18
+
19
+
20
+ ## Seamus - The File Inspector
21
+ # Mix Seamus in to your class and get a hash of #file_attributes appropriate to the file type.
22
+ # Provide an instance of File, or any class that responds to #path, and include Seamus:
23
+ #
24
+ # class MyClass
25
+ # include Seamus
26
+ # attr_accessor :file
27
+ #
28
+ # def initialize(path)
29
+ # @path = File.open(path)
30
+ # end
31
+ # end
32
+ #
33
+ # my_file = MyClass.new("path/to/file.mov")
34
+ # my_file.file_attributes
35
+ #
36
+ # # => {"video_codec"=>"h264", "bitrate_units"=>"kb/s", "container"=>"mov,mp4,m4a,3gp,3g2,mj2", "audio_channels_string"=>"stereo", "audio?"=>true, "audio_channels"=>2, "video?"=>true, "audio_sample_rate"=>44100, "bitrate"=>346, "audio_codec"=>"mpeg4aac", "video_colorspace"=>"yuv420p", "height"=>576, "audio_sample_units"=>"Hz", "fps"=>"7.00", "duration"=>84000, "width"=>1024}
37
+ #
38
+ #
39
+ # Generate thumbnails automatically:
40
+ #
41
+ # my_file.thumbnail {|thumb| my_open_file_instance.write thumb.read }
42
+ #
43
+
44
+
45
+ module Seamus
46
+
47
+ module ClassMethods
48
+
49
+ end
50
+
51
+ module InstanceMethods
52
+
53
+ def file_path
54
+ file.path
55
+ end
56
+
57
+ def file_name
58
+ File.basename(file_path)
59
+ end
60
+
61
+ def file_attributes
62
+ @file_attributes ||= inspect_file
63
+ end
64
+
65
+ def md5
66
+ @md5 ||= Digest::MD5.file(file_path)
67
+ end
68
+
69
+ def md5_hex_string
70
+ md5.to_s
71
+ end
72
+
73
+ def md5_base64_encoded
74
+ Base64.encode64(md5.digest).strip
75
+ end
76
+
77
+ def thumbnail(&block)
78
+ @thumbnail ||= generate_thumbnail
79
+ if block_given?
80
+ begin
81
+ @thumbnail.open
82
+ yield @thumbnail
83
+ ensure
84
+ @thumbnail.close
85
+ end
86
+ end
87
+ return @thumbnail
88
+ end
89
+
90
+ protected
91
+
92
+ def inspect_file
93
+ inspector = Seamus.const_get("#{file_type.classify}Inspector").new(file_path)
94
+ return inspector.stats
95
+ end
96
+
97
+ def generate_thumbnail
98
+ processor = Seamus.const_get("#{file_type.classify}Processor").new(file_path, file_attributes)
99
+ begin
100
+ processor.thumbnail
101
+ rescue ThumbnailError => e
102
+
103
+ end
104
+
105
+ end
106
+
107
+ private
108
+
109
+ def file_type
110
+ # begin
111
+ # @file_attributes["content-type"].split("/").first
112
+ # rescue
113
+ determine_type_from_extension
114
+ # end
115
+ end
116
+
117
+ def determine_type_from_extension
118
+ begin
119
+ Mime::Type.lookup_by_extension(extension).to_s.split("/").first
120
+ rescue NoMethodError
121
+ "application"
122
+ rescue NameError
123
+ if MimeTable
124
+ MimeTable.lookup_by_extension(extension).to_s.split("/").first
125
+ else
126
+ raise LoadError, "Mime module not loaded"
127
+ end
128
+ end
129
+ end
130
+
131
+ # returns the last segment of the filename, eg "foo.mov".extension => ".mov"
132
+ def extension
133
+ file_name.split('.').last.downcase
134
+ end
135
+
136
+ # Add file_attributes as getter methods
137
+ def method_missing(method, *args, &block)
138
+ if file_attributes.include?(method.to_s)
139
+ file_attributes[method.to_s]
140
+ else
141
+ super(method, *args, &block)
142
+ end
143
+ end
144
+
145
+ end
146
+
147
+
148
+
149
+ def self.included(receiver)
150
+ receiver.extend ClassMethods
151
+ receiver.send :include, InstanceMethods
152
+ end
153
+
154
+ end
155
+
156
+
157
+
158
+ class ThumbnailError < Exception
159
+
160
+ end
@@ -0,0 +1,13 @@
1
+ class Numeric
2
+
3
+ def evenize(operator = '+')
4
+ raise ArgumentError, "invalid argument (must be `+' or `-')" unless %w(+ -).include?(operator)
5
+ round.send(operator, modulo(2))
6
+ end
7
+
8
+ def oddize(operator = '+')
9
+ raise ArgumentError, "invalid argument (must be `+' or `-')" unless %w(+ -).include?(operator)
10
+ self %2 > 0 ? self : round.send(operator, 1)
11
+ end
12
+
13
+ end
data/lib/mime_table.rb ADDED
@@ -0,0 +1,134 @@
1
+ # This module is intended to be a lightweight substitute for the
2
+ # ActionPack Mime::Type module provided with Rails.
3
+ # It should be used for mime type lookups only and is not
4
+ # a full replacement for Mime::Type.
5
+
6
+ class MimeTable
7
+
8
+ class << self
9
+
10
+ @@types = []
11
+
12
+ def register(content_type, extension)
13
+ @@types << {:content_type => content_type, :extension => extension}
14
+ end
15
+
16
+ def lookup_by_extension(ext)
17
+ ext = ext.gsub(/^\./, "").to_sym if ext.is_a?(String)
18
+ MimeType.new(@@types.select {|t| t[:extension] == ext }.first)
19
+ end
20
+
21
+ end
22
+
23
+ class MimeType
24
+ attr_reader :content_type, :extension
25
+
26
+ def initialize(options)
27
+ @content_type = options[:content_type]
28
+ @extension = options[:extension]
29
+ end
30
+
31
+ def to_s
32
+ @content_type.to_s
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ MimeTable.register "application/flash", :fla
40
+ MimeTable.register "application/illustrator", :ai
41
+ MimeTable.register "application/msword", :doc
42
+ MimeTable.register "application/octet-stream", :bin
43
+ MimeTable.register "application/pdf", :pdf
44
+ MimeTable.register "application/postscript", :ps
45
+ MimeTable.register "application/rtf", :rtf
46
+ MimeTable.register "application/vnd.ms-excel", :xls
47
+ MimeTable.register "application/vnd.ms-powerpoint", :pps
48
+ MimeTable.register "application/x-bittorrent", :torrent
49
+ MimeTable.register "application/x-compress", :z
50
+ MimeTable.register "application/x-compressed", :tgz
51
+ MimeTable.register "application/x-dvi", :dvi
52
+ MimeTable.register "application/x-gzip", :gz
53
+ MimeTable.register "application/x-photoshop", :psd
54
+ MimeTable.register "application/x-shockwave-flash", :swf
55
+ MimeTable.register "application/x-stuffit", :sit
56
+ MimeTable.register "application/x-tar", :tar
57
+ MimeTable.register "application/zip", :zip
58
+ MimeTable.register "audio/aiff", :aif
59
+ MimeTable.register "audio/basic", :snd
60
+ MimeTable.register "audio/it", :it
61
+ MimeTable.register "audio/mp4", :f4a
62
+ MimeTable.register "audio/mpeg", :mp2
63
+ MimeTable.register "audio/mpeg", :mp3
64
+ MimeTable.register "audio/ogg", :ogg
65
+ MimeTable.register "audio/wav", :wav
66
+ MimeTable.register "audio/x-jam", :jam
67
+ MimeTable.register "audio/x-m4a", :m4a
68
+ MimeTable.register "audio/x-midi", :mid
69
+ MimeTable.register "audio/x-mpegurl", :m3u
70
+ MimeTable.register "audio/x-ms-wma", :wma
71
+ MimeTable.register "image/bmp", :bmp
72
+ MimeTable.register "image/cineon", :cin
73
+ MimeTable.register "image/dpx", :dpx
74
+ MimeTable.register "image/gif", :gif
75
+ MimeTable.register "image/jpeg", :jpg
76
+ MimeTable.register "image/pict", :pic
77
+ MimeTable.register "image/png", :png
78
+ MimeTable.register "image/svg+xml", :svg
79
+ MimeTable.register "image/tiff", :tif
80
+ MimeTable.register "image/vnd.dxf", :dxf
81
+ MimeTable.register "image/x-pcx", :pcx
82
+ MimeTable.register "image/x-pict", :pct
83
+ MimeTable.register "image/x-quicktime", :qif
84
+ MimeTable.register "text/UTF-8", :txt
85
+ MimeTable.register "text/x-java-source", :jav
86
+ MimeTable.register "text/x-script.python", :py
87
+ MimeTable.register "text/x-script.sh", :sh
88
+ MimeTable.register "video/mp4", :f4v
89
+ MimeTable.register "video/mp4", :mp4
90
+ MimeTable.register "video/quicktime", :mov
91
+ MimeTable.register "video/x-dv", :dv
92
+ MimeTable.register "video/x-flv", :flv
93
+ MimeTable.register "video/x-m4v", :m4v
94
+ MimeTable.register "video/x-motion-jpeg", :mjpg
95
+ MimeTable.register "video/x-mpeg", :mpg
96
+ MimeTable.register "video/x-ms-asf", :asf
97
+ MimeTable.register "video/x-ms-wmv", :wmv
98
+ MimeTable.register "video/x-msvideo", :avi
99
+ MimeTable.register "video/x-sgi-movie", :mv
100
+ MimeTable.register "vmd-rn-realmedia", :rm
101
+ MimeTable.register "vnd.microsoft.icon", :ico
102
+ MimeTable.register "vnd.rn-realaudio", :ra
103
+ MimeTable.register "vnd.rn-realmedia-vbr", :rmvb
104
+ # MimeTable::Type.register_alias "application/postscript", :eps
105
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xla
106
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlb
107
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xld
108
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlk
109
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xll
110
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlm
111
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlt
112
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlv
113
+ # MimeTable::Type.register_alias "application/vnd.ms-excel", :xlw
114
+ # MimeTable::Type.register_alias "application/vnd.ms-powerpoint", :ppt
115
+ # MimeTable::Type.register_alias "application/x-gzip", :gzip
116
+ # MimeTable::Type.register_alias "audio/aiff", :aifc
117
+ # MimeTable::Type.register_alias "audio/aiff", :aiff
118
+ # MimeTable::Type.register_alias "audio/ogg", :oga
119
+ # MimeTable::Type.register_alias "audio/ogg", :ogv
120
+ # MimeTable::Type.register_alias "audio/ogg", :ogx
121
+ # MimeTable::Type.register_alias "audio/ogg", :spx
122
+ # MimeTable::Type.register_alias "audio/x-midi", :midi
123
+ # MimeTable::Type.register_alias "image/jpeg", :jfif
124
+ # MimeTable::Type.register_alias "image/jpeg", :jpeg
125
+ # MimeTable::Type.register_alias "image/pict", :pict
126
+ # MimeTable::Type.register_alias "image/tiff", :tiff
127
+ # MimeTable::Type.register_alias "text/plain", :log
128
+ # MimeTable::Type.register_alias "text/x-java-source", :java
129
+ # MimeTable::Type.register_alias "video/mpeg", :m1v
130
+ # MimeTable::Type.register_alias "video/mpeg", :m2a
131
+ # MimeTable::Type.register_alias "video/mpeg", :m2v
132
+ # MimeTable::Type.register_alias "video/quicktime", :qt
133
+ # MimeTable::Type.register_alias "video/x-mpeg", :mpeg
134
+ # MimeTable::Type.register_alias "video/x-ms-asf", :asx
@@ -0,0 +1,24 @@
1
+ module Seamus
2
+ class ApplicationInspector < Inspector
3
+
4
+ def initialize(file_path)
5
+ @file = File.new(file_path)
6
+ end
7
+
8
+ def stats
9
+ inspection_attributes(stat(@file))
10
+ end
11
+
12
+ private
13
+
14
+ def stat(file)
15
+ File.stat(file.path)
16
+ end
17
+
18
+ def inspection_attributes(stat)
19
+ attr_hash = {"size" => stat.size}
20
+ return attr_hash
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ module Seamus
2
+ class AudioInspector < Inspector
3
+
4
+ def initialize(file_path)
5
+ @file = File.new(file_path)
6
+ end
7
+
8
+ def stats
9
+ inspection_attributes(stat(@file))
10
+ end
11
+
12
+ private
13
+
14
+ def inspection_attributes(stat)
15
+ attr_hash = {}
16
+ ["audio?", "audio_bitrate", "audio_channels", "audio_channels_string", "audio_codec", "audio_sample_rate", "audio_sample_units", "bitrate", "bitrate_units", "container", "duration"].each do |attribute|
17
+ attr_hash[attribute.to_s] = stat.send(attribute) if stat.respond_to?(attribute)
18
+ end
19
+ return attr_hash
20
+ end
21
+
22
+ def stat(file)
23
+ RVideo::Inspector.new(:raw_response => raw_response(file))
24
+ end
25
+
26
+ def raw_response(file)
27
+ process = IO.popen("ffmpeg -i '#{file.path}' 2>&1", "r")
28
+ response = process.read
29
+ process.close
30
+ return response
31
+ end
32
+
33
+
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ module Seamus
2
+ class VideoInspector < Inspector
3
+
4
+ def initialize(file_path)
5
+ @file = File.new(file_path)
6
+ end
7
+
8
+ def stats
9
+ inspection_attributes(stat(@file))
10
+ end
11
+
12
+ private
13
+
14
+ def inspection_attributes(stat)
15
+ attr_hash = {}
16
+ ["audio?", "audio_bitrate", "audio_channels", "audio_channels_string", "audio_codec", "audio_sample_rate", "audio_sample_units", "bitrate", "bitrate_units", "container", "duration", "fps", "height", "video?", "video_codec", "video_colorspace", "width"].each do |attribute|
17
+ attr_hash[attribute.to_s] = stat.send(attribute) if stat.respond_to?(attribute)
18
+ end
19
+ return attr_hash
20
+ end
21
+
22
+ def stat(file)
23
+ RVideo::Inspector.new(:raw_response => raw_response)
24
+ end
25
+
26
+ def raw_response
27
+ response = ffmpeg_response_process.read
28
+ ffmpeg_response_process.close
29
+ return response
30
+ end
31
+
32
+ def ffmpeg_response_process
33
+ IO.popen("ffmpeg -i '#{@file.path}' 2>&1", "r")
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Seamus
2
+ class Inspector
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Seamus
2
+ class ApplicationProcessor < Processor
3
+
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Seamus
2
+ class AudioProcessor < Processor
3
+
4
+ attr_reader :file_attributes
5
+
6
+ def initialize(file_path, file_attributes)
7
+ @file = File.open(file_path, "r")
8
+ @file_attributes = file_attributes
9
+ end
10
+
11
+ def thumbnail
12
+ raise ThumbnailError, "invalid type for thumbnail"
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ module Seamus
2
+ class VideoProcessor < Processor
3
+
4
+ attr_reader :file_attributes
5
+
6
+ def initialize(file_path, file_attributes)
7
+ @file_attributes = file_attributes
8
+ @file = File.open(file_path, "r")
9
+ end
10
+
11
+ def thumbnail
12
+ thumb = thumb_tempfile
13
+ IO.popen("ffmpeg -y -ss #{start_time} -i '#{@file.path}' -t 00:00:01 -vcodec mjpeg -vframes 1 -an -f rawvideo -s #{dimensions_string} - 2> /dev/null") do |io|
14
+ thumb.write io.read
15
+ end
16
+ thumb.close
17
+ return thumb
18
+ end
19
+
20
+ private
21
+
22
+ def start_time
23
+ (file_attributes["duration"] || 10000)/3333
24
+ end
25
+
26
+ # nodoc
27
+ def thumb_tempfile
28
+ Tempfile.new("#{File.basename(@file.path, File.extname(@file.path))}_thumb.jpg")
29
+ end
30
+
31
+ def aspect_ratio
32
+ width = (file_attributes["width"]).to_f
33
+ height = (file_attributes["height"]).to_f
34
+ return (width/height)
35
+ end
36
+
37
+ # For ffmpeg dimensions to work, the dimension components have to be even numbers,
38
+ # so odd numbers are coerced to even numbers
39
+ def dimensions_string(constant_width=320)
40
+ "#{constant_width.evenize}x#{(constant_width/aspect_ratio).to_i.evenize}"
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ module Seamus
2
+ class Processor
3
+
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Seamus" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'Seamus'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+
8
+ Spec::Runner.configure do |config|
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seamus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Scott Burton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-02 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Seamus is not an Irish monk. Instead, it inspects a file and returns whatever metadata it can determine.
17
+ email: scottburton11@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - .document
27
+ - .gitignore
28
+ - LICENSE
29
+ - README.rdoc
30
+ - Rakefile
31
+ - Seamus.gemspec
32
+ - VERSION
33
+ - features/Seamus.feature
34
+ - features/step_definitions/Seamus_steps.rb
35
+ - features/support/env.rb
36
+ - lib/Seamus.rb
37
+ - lib/core/numeric.rb
38
+ - lib/mime_table.rb
39
+ - lib/seamus/inspector.rb
40
+ - lib/seamus/inspector/application_inspector.rb
41
+ - lib/seamus/inspector/audio_inspector.rb
42
+ - lib/seamus/inspector/video_inspector.rb
43
+ - lib/seamus/processor.rb
44
+ - lib/seamus/processor/application_processor.rb
45
+ - lib/seamus/processor/audio_processor.rb
46
+ - lib/seamus/processor/video_processor.rb
47
+ - spec/Seamus_spec.rb
48
+ - spec/spec_helper.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/scottburton11/Seamus
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Seamus is not an Irish monk
77
+ test_files:
78
+ - spec/Seamus_spec.rb
79
+ - spec/spec_helper.rb