seamus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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