carrierwave-video-thumbnailer 0.1.1
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 +3 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rvmrc.sample +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +34 -0
- data/carrierwave-video-thumbnailer.gemspec +60 -0
- data/gemspec.yml +19 -0
- data/lib/carrierwave/video/thumbnailer.rb +77 -0
- data/lib/carrierwave/video/thumbnailer/ffmpegthumbnailer.rb +77 -0
- data/lib/carrierwave/video/thumbnailer/ffmpegthumbnailer/options.rb +71 -0
- data/lib/carrierwave/video/thumbnailer/version.rb +8 -0
- data/spec/lib/ffmpegthumbnailer_spec.rb +66 -0
- data/spec/lib/thumbnailer_spec.rb +147 -0
- data/spec/spec_helper.rb +7 -0
- metadata +195 -0
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.rvmrc.sample
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create gemset use cvtn-devel
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "carrierwave-video-thumbnailer Documentation" --protected
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2012 Pavel Argentov
|
2
|
+
Copyright (c) 2012 Evrone.com
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# carrierwave-video-thumbnailer
|
2
|
+
|
3
|
+
* [Homepage](https://github.com/evrone/carrierwave-video-thumbnailer#readme)
|
4
|
+
* [Issues](https://github.com/evrone/carrierwave-video-thumbnailer/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/carrierwave-video-thumbnailer/frames)
|
6
|
+
* [Email](mailto:argentoff at gmail.com)
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
A thumbnailer plugin for Carrierwave. It mixes into your uploader setup and
|
11
|
+
makes easy thumbnailing of your uploaded videos. This software is quite an
|
12
|
+
alpha right now so any kind of OpenSource collaboration is welcome.
|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
Runs `ffmpegthumbnailer` with CLI keys provided by your configuration or just
|
17
|
+
uses quite a reasonable ffmpegthumbnailer's defaults. See Examples section for
|
18
|
+
details.
|
19
|
+
|
20
|
+
## Examples
|
21
|
+
|
22
|
+
Here's a working example:
|
23
|
+
|
24
|
+
In your Rails `app/uploaders/reel_uploader.rb`:
|
25
|
+
|
26
|
+
class ReelUploader < CarrierWave::Uploader::Base
|
27
|
+
include CarrierWave::Video # for your video processing
|
28
|
+
include CarrierWave::Video::Thumbnailer
|
29
|
+
|
30
|
+
version :thumb do
|
31
|
+
process thumbnail: [{format: 'png', quality: 10, size: 192, strip: true, logger: Rails.logger}]
|
32
|
+
def full_filename for_file
|
33
|
+
png_name for_file, version_name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def png_name for_file, version_name
|
38
|
+
%Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.png}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
## Thumbnailer Options
|
44
|
+
|
45
|
+
The options are passed as a hash to the `thumbnail` processing callback as
|
46
|
+
shown in the example. The options may be, according to ffmpegthumbnailer's
|
47
|
+
manual:
|
48
|
+
|
49
|
+
* format: 'jpg' or 'png' ('jpg' is the default).
|
50
|
+
* quality: compression quality (1 to 10, default is 8).
|
51
|
+
* size: thumbnail length in pixels (defaults to 128).
|
52
|
+
* strip: movie film strip decoration (defaults to `false`).
|
53
|
+
* seek: where to take the snapshot. May be specified as HH:MM:SS or X%.
|
54
|
+
Defaults to 10%.
|
55
|
+
* square: if set to `true` makes a square thumbnail regardless of an initial
|
56
|
+
aspect ratio.
|
57
|
+
* workaround: if set to `true` runs ffmpegthumbnailer in some safe mode
|
58
|
+
(read `man ffmpegthumbnailer` for further explanations).
|
59
|
+
* logger: an object behaving like Rails.logger (may be omitted).
|
60
|
+
|
61
|
+
## Requirements
|
62
|
+
|
63
|
+
`ffmpegthumbnailer` binary should be present on the PATH.
|
64
|
+
|
65
|
+
## Install
|
66
|
+
|
67
|
+
$ gem install carrierwave-video-thumbnailer
|
68
|
+
|
69
|
+
Or `gem 'carrierwave-video-thumbnailer'` in your Gemfile.
|
70
|
+
|
71
|
+
## Acknowledgements
|
72
|
+
|
73
|
+
Huge Thanks to **Rachel Heaton** (<https://github.com/rheaton>) whose
|
74
|
+
`carrierwave-video` gem has inspired me (and where I've borrowed some code as
|
75
|
+
well).
|
76
|
+
|
77
|
+
Thanks to [Evrone Web Laboratory](http://evrone.com) which feeds me well enough (with the
|
78
|
+
tasks of course) to do this job.
|
79
|
+
|
80
|
+
## Copyright
|
81
|
+
|
82
|
+
Copyright (c) 2012 Pavel Argentov
|
83
|
+
Copyright (c) 2012 Evrone.com
|
84
|
+
|
85
|
+
See [LICENSE.txt](LICENSE.txt) for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rubygems/tasks'
|
24
|
+
Gem::Tasks.new
|
25
|
+
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new
|
28
|
+
|
29
|
+
task :test => :spec
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
require 'yard'
|
33
|
+
YARD::Rake::YardocTask.new
|
34
|
+
task :doc => :yard
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'carrierwave/video/thumbnailer/version'
|
14
|
+
CarrierWave::Video::Thumbnailer::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
|
24
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
25
|
+
|
26
|
+
gem.files = `git ls-files`.split($/)
|
27
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
28
|
+
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
31
|
+
end
|
32
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
33
|
+
|
34
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
35
|
+
gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
|
36
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
37
|
+
|
38
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
39
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
40
|
+
})
|
41
|
+
|
42
|
+
gem.requirements = gemspec['requirements']
|
43
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
44
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
45
|
+
gem.post_install_message = gemspec['post_install_message']
|
46
|
+
|
47
|
+
split = lambda { |string| string.split(/,\s*/) }
|
48
|
+
|
49
|
+
if gemspec['dependencies']
|
50
|
+
gemspec['dependencies'].each do |name,versions|
|
51
|
+
gem.add_dependency(name,split[versions])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if gemspec['development_dependencies']
|
56
|
+
gemspec['development_dependencies'].each do |name,versions|
|
57
|
+
gem.add_development_dependency(name,split[versions])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/gemspec.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
name: carrierwave-video-thumbnailer
|
2
|
+
summary: "Video thumbnailer plugin for CarrierWave"
|
3
|
+
description: "Lets you make video thumbnails in carrierwave via ffmpegthumbnailer"
|
4
|
+
license: MIT
|
5
|
+
authors: Pavel Argentov
|
6
|
+
email: argentoff@gmail.com
|
7
|
+
homepage: https://github.com/evrone/carrierwave-video-thumbnailer#readme
|
8
|
+
|
9
|
+
dependencies:
|
10
|
+
carrierwave: '>= 0'
|
11
|
+
|
12
|
+
development_dependencies:
|
13
|
+
pry: '>= 0'
|
14
|
+
activesupport: ~> 3.2.8
|
15
|
+
bundler: ~> 1.0
|
16
|
+
rake: ~> 0.8
|
17
|
+
rspec: ~> 2.4
|
18
|
+
rubygems-tasks: ~> 0.2
|
19
|
+
yard: ~> 0.8
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'carrierwave'
|
2
|
+
require 'carrierwave/video/thumbnailer/version'
|
3
|
+
require 'carrierwave/video/thumbnailer/ffmpegthumbnailer'
|
4
|
+
|
5
|
+
module CarrierWave
|
6
|
+
module Video
|
7
|
+
module Thumbnailer
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def thumbnail options = {}
|
13
|
+
process thumbnail: options
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def thumbnail opts = {}
|
19
|
+
cache_stored_file! if !cached?
|
20
|
+
|
21
|
+
@options = CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions.new(opts)
|
22
|
+
format = @options.format || 'jpg'
|
23
|
+
|
24
|
+
tmp_path = File.join( File.dirname(current_path), "tmpfile.#{format}" )
|
25
|
+
thumbnailer = FFMpegThumbnailer.new(current_path, tmp_path)
|
26
|
+
|
27
|
+
with_thumbnailing_callbacks do
|
28
|
+
thumbnailer.run(@options)
|
29
|
+
File.rename tmp_path, current_path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def with_thumbnailing_callbacks(&block)
|
36
|
+
callbacks = @options.callbacks
|
37
|
+
logger = @options.logger
|
38
|
+
begin
|
39
|
+
send_thumbnailing_callback(callbacks[:before_thumbnail])
|
40
|
+
setup_thumbnailing_logger
|
41
|
+
block.call
|
42
|
+
send_thumbnailing_callback(callbacks[:after_thumbnail])
|
43
|
+
rescue => e
|
44
|
+
send_thumbnailing_callback(callbacks[:rescue])
|
45
|
+
|
46
|
+
if logger
|
47
|
+
logger.error "#{e.class}: #{e.message}"
|
48
|
+
e.backtrace.each do |b|
|
49
|
+
logger.error b
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
raise CarrierWave::ProcessingError.new("Failed to thumbnail with ffmpegthumbnailer. Check ffmpegthumbnailer install and verify video is not corrupt. Original error: #{e}")
|
54
|
+
ensure
|
55
|
+
reset_thumbnailing_logger
|
56
|
+
send_thumbnailing_callback(callbacks[:ensure])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def send_thumbnailing_callback(callback)
|
61
|
+
model.send(callback, @options) if callback.present?
|
62
|
+
end
|
63
|
+
|
64
|
+
def setup_thumbnailing_logger
|
65
|
+
return unless @options.logger.present?
|
66
|
+
@ffmpegthumbnailer_logger = FFMpegThumbnailer.logger
|
67
|
+
FFMpegThumbnailer.logger = @options.logger
|
68
|
+
end
|
69
|
+
|
70
|
+
def reset_thumbnailing_logger
|
71
|
+
return unless @ffmpegthumbnailer_logger
|
72
|
+
FFMpegThumbnailer.logger = @ffmpegthumbnailer_logger
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'carrierwave/video/thumbnailer/ffmpegthumbnailer/options'
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
module Video
|
5
|
+
module Thumbnailer
|
6
|
+
class FFMpegThumbnailer
|
7
|
+
|
8
|
+
# Explicit class methods
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Sets a required thumbnailer binary
|
12
|
+
def binary=(bin)
|
13
|
+
@ffmpegthumbnailer = bin
|
14
|
+
end
|
15
|
+
|
16
|
+
# Tells the thumbnailer binary name
|
17
|
+
def binary
|
18
|
+
@ffmpegthumbnailer.nil? ? 'ffmpegthumbnailer' : @ffmpegthumbnailer
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger= log
|
22
|
+
@logger = log
|
23
|
+
end
|
24
|
+
|
25
|
+
def logger
|
26
|
+
return @logger if @logger
|
27
|
+
logger = Logger.new(STDOUT)
|
28
|
+
logger.level = Logger::INFO
|
29
|
+
@logger = logger
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :input_path, :output_path
|
35
|
+
|
36
|
+
def initialize in_path, out_path
|
37
|
+
@input_path = in_path
|
38
|
+
@output_path = out_path
|
39
|
+
end
|
40
|
+
|
41
|
+
def run options
|
42
|
+
logger = options.logger
|
43
|
+
cmd = %Q{#{CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.binary} -i #{input_path} -o #{output_path} #{options.to_cli}}.rstrip
|
44
|
+
|
45
|
+
logger.info("Running....#{cmd}") if logger
|
46
|
+
outputs = []
|
47
|
+
exit_code = nil
|
48
|
+
|
49
|
+
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
50
|
+
stderr.each("r") do |line|
|
51
|
+
outputs << line
|
52
|
+
end
|
53
|
+
exit_code = wait_thr.value
|
54
|
+
end
|
55
|
+
|
56
|
+
handle_exit_code(exit_code, outputs, logger)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def handle_exit_code(exit_code, outputs, logger)
|
62
|
+
return unless logger
|
63
|
+
if exit_code == 0
|
64
|
+
logger.info("Success!")
|
65
|
+
else
|
66
|
+
outputs.each do |output|
|
67
|
+
logger.error(output)
|
68
|
+
end
|
69
|
+
logger.error("Failure!")
|
70
|
+
end
|
71
|
+
exit_code
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Video
|
3
|
+
module Thumbnailer
|
4
|
+
|
5
|
+
# Options to be be converted to CLI parameters
|
6
|
+
class Options < Hash
|
7
|
+
|
8
|
+
BOOLEAN = [
|
9
|
+
:square,
|
10
|
+
:strip,
|
11
|
+
:workaround
|
12
|
+
]
|
13
|
+
|
14
|
+
def initialize opts
|
15
|
+
opts.each { |k, v| self[k] = v}
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_cli
|
19
|
+
self.map do |k, v|
|
20
|
+
if BOOLEAN.include? k
|
21
|
+
cli_key k if v
|
22
|
+
else
|
23
|
+
"#{cli_key k} #{cli_val v}"
|
24
|
+
end
|
25
|
+
end.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def cli_key k
|
31
|
+
'-' + (
|
32
|
+
case k
|
33
|
+
when :size then 's'
|
34
|
+
when :seek then 't'
|
35
|
+
when :quality then 'q'
|
36
|
+
when :square then 'a'
|
37
|
+
when :strip then 'f'
|
38
|
+
when :workaround then 'w'
|
39
|
+
else
|
40
|
+
'-noop'
|
41
|
+
end
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def cli_val v
|
46
|
+
v.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class FFMpegThumbnailerOptions
|
52
|
+
|
53
|
+
attr_reader :format, :options, :logger, :callbacks, :custom
|
54
|
+
|
55
|
+
def initialize options
|
56
|
+
@callbacks = options.delete(:callbacks) || {}
|
57
|
+
@custom = options.delete :custom
|
58
|
+
@format = options.delete :format
|
59
|
+
@logger = options.delete :logger
|
60
|
+
@options = Options.new options
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_cli
|
64
|
+
%Q{#{"-c #{format} " if format}#{@options.to_cli}#{" #{custom}" if custom}}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'carrierwave/video/thumbnailer'
|
3
|
+
|
4
|
+
describe CarrierWave::Video::Thumbnailer::FFMpegThumbnailer do
|
5
|
+
|
6
|
+
describe "#run" do
|
7
|
+
let(:input_file_path) { '/tmp/file.mov' }
|
8
|
+
let(:output_file_path) { '/tmp/file.jpg' }
|
9
|
+
let(:binary) { 'thumbnailrrr' }
|
10
|
+
|
11
|
+
let(:thumbnailer) { CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.new(input_file_path, output_file_path) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.binary = binary
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should run the ffmpegthumbnailer binary" do
|
18
|
+
@options = CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions.new({})
|
19
|
+
command = "#{binary} -i #{input_file_path} -o #{output_file_path}"
|
20
|
+
Open3.should_receive(:popen3).with(command)
|
21
|
+
|
22
|
+
thumbnailer.run @options
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with full set of CLI options" do
|
26
|
+
|
27
|
+
it "runs the thumbnailer with all corresponding CLI keys" do
|
28
|
+
|
29
|
+
opts = {
|
30
|
+
format: 'png',
|
31
|
+
size: '512',
|
32
|
+
seek: '20%',
|
33
|
+
quality: 10,
|
34
|
+
square: true,
|
35
|
+
strip: true,
|
36
|
+
workaround: true,
|
37
|
+
custom: '-v'
|
38
|
+
}
|
39
|
+
|
40
|
+
@options = CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions.new opts
|
41
|
+
|
42
|
+
cli = "#{binary} -i #{input_file_path} -o #{output_file_path} -c png -s 512 -t 20% -q 10 -a -f -w -v"
|
43
|
+
Open3.should_receive(:popen3).with(cli)
|
44
|
+
|
45
|
+
thumbnailer.run @options
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "given a logger" do
|
51
|
+
let(:logger) { mock(:logger) }
|
52
|
+
|
53
|
+
it "should run and log results" do
|
54
|
+
@options = CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions.new({logger: logger})
|
55
|
+
command = "#{binary} -i #{input_file_path} -o #{output_file_path}"
|
56
|
+
Open3.should_receive(:popen3).with(command)
|
57
|
+
logger.should_receive(:info).with("Running....#{command}")
|
58
|
+
logger.should_receive(:error).with("Failure!")
|
59
|
+
|
60
|
+
thumbnailer.run @options
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'carrierwave/video/thumbnailer'
|
3
|
+
|
4
|
+
describe CarrierWave::Video::Thumbnailer do
|
5
|
+
|
6
|
+
it "should have a VERSION constant" do
|
7
|
+
subject.const_get('VERSION').should_not be_empty
|
8
|
+
end
|
9
|
+
|
10
|
+
#class FFMpegThumbnailer; end
|
11
|
+
|
12
|
+
class TestVideoUploader
|
13
|
+
include CarrierWave::Video::Thumbnailer
|
14
|
+
def cached?; end
|
15
|
+
def cache_stored_file!; end
|
16
|
+
def model
|
17
|
+
@thumbnailer ||= FFMpegThumbnailer.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:uploader) { TestVideoUploader.new }
|
22
|
+
|
23
|
+
describe ".thumbnail" do
|
24
|
+
it "processes the model" do
|
25
|
+
TestVideoUploader.should_receive(:process).with(thumbnail: {option: 'something'})
|
26
|
+
TestVideoUploader.thumbnail({option: 'something'})
|
27
|
+
end
|
28
|
+
|
29
|
+
it "does not require options" do
|
30
|
+
TestVideoUploader.should_receive(:process).with(thumbnail: {})
|
31
|
+
TestVideoUploader.thumbnail
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#thumbnail" do
|
36
|
+
let(:format) { 'jpg' }
|
37
|
+
let(:thumbnailer) { mock }
|
38
|
+
|
39
|
+
before do
|
40
|
+
uploader.stub(:current_path).and_return('video/path/file.jpg')
|
41
|
+
|
42
|
+
CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.should_receive(:new).at_most(10).times.and_return(thumbnailer)
|
43
|
+
end
|
44
|
+
|
45
|
+
context "with no options set" do
|
46
|
+
before { File.should_receive(:rename).with('video/path/tmpfile.jpg', 'video/path/file.jpg') }
|
47
|
+
|
48
|
+
it "runs the thumbnailer with empty options list" do
|
49
|
+
thumbnailer.should_receive(:run) do |options|
|
50
|
+
expect(options.options).to be_empty
|
51
|
+
end
|
52
|
+
uploader.thumbnail
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with callbacks set" do
|
57
|
+
before { thumbnailer.should_receive(:run) }
|
58
|
+
let(:opts) do
|
59
|
+
{
|
60
|
+
callbacks: {
|
61
|
+
before_thumbnail: :method1,
|
62
|
+
after_thumbnail: :method2,
|
63
|
+
rescue: :method3,
|
64
|
+
ensure: :method4
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
context "no exceptions raised" do
|
70
|
+
before { File.should_receive(:rename).with('video/path/tmpfile.jpg', 'video/path/file.jpg') }
|
71
|
+
|
72
|
+
it "calls before_thumbnail, after_thumbnail, and ensure" do
|
73
|
+
uploader.model.should_receive(:method1).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
74
|
+
uploader.model.should_receive(:method2).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
75
|
+
uploader.model.should_not_receive(:method3)
|
76
|
+
uploader.model.should_receive(:method4).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
77
|
+
|
78
|
+
uploader.thumbnail(opts)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "exception raised" do
|
83
|
+
let(:e) { StandardError.new("test error") }
|
84
|
+
before { File.should_receive(:rename).and_raise(e) }
|
85
|
+
|
86
|
+
|
87
|
+
it "calls before_thumbnail and ensure" do
|
88
|
+
uploader.model.should_receive(:method1).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
89
|
+
uploader.model.should_not_receive(:method2)
|
90
|
+
uploader.model.should_receive(:method3).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
91
|
+
uploader.model.should_receive(:method4).with(an_instance_of CarrierWave::Video::Thumbnailer::FFMpegThumbnailerOptions).ordered
|
92
|
+
|
93
|
+
lambda do
|
94
|
+
uploader.thumbnail(opts)
|
95
|
+
end.should raise_exception(CarrierWave::ProcessingError)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "with logger set" do
|
101
|
+
let(:logger) { mock }
|
102
|
+
before do
|
103
|
+
uploader.model.stub(:logger).and_return(logger)
|
104
|
+
thumbnailer.should_receive(:run)
|
105
|
+
end
|
106
|
+
|
107
|
+
context "with no exceptions" do
|
108
|
+
before { File.should_receive(:rename).with('video/path/tmpfile.jpg', 'video/path/file.jpg') }
|
109
|
+
|
110
|
+
it "sets FFMpegThumbnailer logger to logger and resets" do
|
111
|
+
old_logger = CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.logger
|
112
|
+
CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.should_receive(:logger=).with(logger).ordered
|
113
|
+
CarrierWave::Video::Thumbnailer::FFMpegThumbnailer.should_receive(:logger=).with(old_logger).ordered
|
114
|
+
uploader.thumbnail(logger: logger)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "with exceptions" do
|
119
|
+
let(:e) { StandardError.new("test error") }
|
120
|
+
before { File.should_receive(:rename).with('video/path/tmpfile.jpg', 'video/path/file.jpg').and_raise(e) }
|
121
|
+
|
122
|
+
it "logs exception" do
|
123
|
+
logger.should_receive(:error).with("#{e.class}: #{e.message}")
|
124
|
+
logger.should_receive(:error).any_number_of_times # backtrace
|
125
|
+
|
126
|
+
lambda do
|
127
|
+
uploader.thumbnail(logger: logger)
|
128
|
+
end.should raise_exception(CarrierWave::ProcessingError)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "with custom passed in" do
|
134
|
+
before { File.should_receive(:rename).with('video/path/tmpfile.jpg', 'video/path/file.jpg') }
|
135
|
+
|
136
|
+
it "takes the provided custom param" do
|
137
|
+
thumbnailer.should_receive(:run) do |opts|
|
138
|
+
opts.custom.should eq '-s 256'
|
139
|
+
end
|
140
|
+
|
141
|
+
uploader.thumbnail(custom: '-s 256')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carrierwave-video-thumbnailer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pavel Argentov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: carrierwave
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: pry
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activesupport
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.2.8
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.2.8
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bundler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0.8'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.8'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.4'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.4'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rubygems-tasks
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.2'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: yard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0.8'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.8'
|
142
|
+
description: Lets you make video thumbnails in carrierwave via ffmpegthumbnailer
|
143
|
+
email: argentoff@gmail.com
|
144
|
+
executables: []
|
145
|
+
extensions: []
|
146
|
+
extra_rdoc_files:
|
147
|
+
- ChangeLog.md
|
148
|
+
- LICENSE.txt
|
149
|
+
- README.md
|
150
|
+
files:
|
151
|
+
- .document
|
152
|
+
- .gitignore
|
153
|
+
- .rspec
|
154
|
+
- .rvmrc.sample
|
155
|
+
- .yardopts
|
156
|
+
- ChangeLog.md
|
157
|
+
- Gemfile
|
158
|
+
- LICENSE.txt
|
159
|
+
- README.md
|
160
|
+
- Rakefile
|
161
|
+
- carrierwave-video-thumbnailer.gemspec
|
162
|
+
- gemspec.yml
|
163
|
+
- lib/carrierwave/video/thumbnailer.rb
|
164
|
+
- lib/carrierwave/video/thumbnailer/ffmpegthumbnailer.rb
|
165
|
+
- lib/carrierwave/video/thumbnailer/ffmpegthumbnailer/options.rb
|
166
|
+
- lib/carrierwave/video/thumbnailer/version.rb
|
167
|
+
- spec/lib/ffmpegthumbnailer_spec.rb
|
168
|
+
- spec/lib/thumbnailer_spec.rb
|
169
|
+
- spec/spec_helper.rb
|
170
|
+
homepage: https://github.com/evrone/carrierwave-video-thumbnailer#readme
|
171
|
+
licenses:
|
172
|
+
- MIT
|
173
|
+
post_install_message:
|
174
|
+
rdoc_options: []
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
none: false
|
185
|
+
requirements:
|
186
|
+
- - ! '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
requirements: []
|
190
|
+
rubyforge_project:
|
191
|
+
rubygems_version: 1.8.24
|
192
|
+
signing_key:
|
193
|
+
specification_version: 3
|
194
|
+
summary: Video thumbnailer plugin for CarrierWave
|
195
|
+
test_files: []
|