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 +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +40 -0
- data/Rakefile +58 -0
- data/Seamus.gemspec +60 -0
- data/VERSION +1 -0
- data/features/Seamus.feature +9 -0
- data/features/step_definitions/Seamus_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/lib/Seamus.rb +160 -0
- data/lib/core/numeric.rb +13 -0
- data/lib/mime_table.rb +134 -0
- data/lib/seamus/inspector/application_inspector.rb +24 -0
- data/lib/seamus/inspector/audio_inspector.rb +35 -0
- data/lib/seamus/inspector/video_inspector.rb +37 -0
- data/lib/seamus/inspector.rb +5 -0
- data/lib/seamus/processor/application_processor.rb +5 -0
- data/lib/seamus/processor/audio_processor.rb +16 -0
- data/lib/seamus/processor/video_processor.rb +44 -0
- data/lib/seamus/processor.rb +5 -0
- data/spec/Seamus_spec.rb +7 -0
- data/spec/spec_helper.rb +10 -0
- metadata +79 -0
data/.document
ADDED
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
|
File without changes
|
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
|
data/lib/core/numeric.rb
ADDED
@@ -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,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
|
data/spec/Seamus_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
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
|