video_screenshoter 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,8 @@ require "fileutils"
3
3
  require "video_screenshoter/abstract"
4
4
  require "video_screenshoter/video"
5
5
  require "video_screenshoter/hls"
6
+ require "video_screenshoter/image"
7
+ require "shellwords"
6
8
 
7
9
  module VideoScreenshoter
8
10
  class << self
@@ -16,8 +18,13 @@ module VideoScreenshoter
16
18
 
17
19
  def self.new params
18
20
  raise ArgumentError.new('Input is needed') unless params[:input]
19
- raise ArgumentError.new('Incorrect type param') unless [nil, 'hls', 'video'].include? params[:type]
20
- params[:type] ||= File.extname(params[:input]) == '.m3u8' ? 'hls' : 'video'
21
- params[:type] == 'hls' ? VideoScreenshoter::Hls.new(params) : VideoScreenshoter::Video.new(params)
21
+ raise ArgumentError.new('Incorrect type param') unless [nil, 'hls', 'video', 'image'].include? params[:type]
22
+ if params[:type] == 'hls' || File.extname(params[:input]).downcase == '.m3u8'
23
+ VideoScreenshoter::Hls.new(params)
24
+ elsif params[:type] == 'image' || ['.gif','.png','.jpg','.jpeg', '.png'].include?(File.extname(params[:input]).downcase)
25
+ VideoScreenshoter::Image.new(params)
26
+ else
27
+ VideoScreenshoter::Video.new(params)
28
+ end
22
29
  end
23
30
  end
@@ -2,9 +2,12 @@
2
2
 
3
3
  module VideoScreenshoter
4
4
  class Abstract
5
- attr_accessor :ffmpeg, :imagemagick, :output_dir, :output_file, :input, :times, :duration, :verbose, :size, :presets
5
+ attr_accessor :ffmpeg, :imagemagick, :output_dir, :output_file, :input, :exact, :times, :offset_start, :offset_end, :duration, :verbose, :size, :presets
6
6
 
7
7
  def initialize params
8
+ params.each_with_index do |param, index|
9
+ params[index] = Shellwords.escape(param) if param.is_a?(String)
10
+ end
8
11
  [:ffmpeg, :imagemagick, :output_dir, :output_file, :verbose].each do |attr|
9
12
  self.send("#{attr}=".to_sym, params[attr].nil? ? VideoScreenshoter.send(attr) : params[attr])
10
13
  end
@@ -12,15 +15,36 @@ module VideoScreenshoter
12
15
  self.input = params[:input]
13
16
  self.duration = input_duration
14
17
  raise ArgumentError.new('Incorrect or empty m3u8 playlist') if duration.to_i == 0
15
- self.times = params[:times].to_a.map do |time|
16
- if time.is_a?(String) && matches = time.match(/(.*)%$/)
17
- time = matches[1].to_f / 100 * duration
18
+
19
+ # if false ffmpeg uses fast seek by keyframes like: ffmpeg -ss ... -i
20
+ self.exact = params[:exact]
21
+
22
+ if params[:times]
23
+ self.exact = true if exact.nil?
24
+ self.times = params[:times].to_a.map do |time|
25
+ if time.is_a?(String) && matches = time.match(/(.*)%$/)
26
+ time = matches[1].to_f / 100 * duration
27
+ end
28
+ time = duration + time if time < 0
29
+ time = time.to_i
30
+ time
31
+ end.uniq
32
+ elsif (number = params[:number].to_i) > 0
33
+ [:offset_start, :offset_end].each do |attr|
34
+ if percent = params[attr].to_s.match(/^(\d+)%$/).to_a[1]
35
+ self.send("#{attr}=", duration * percent.to_i / 100.0)
36
+ else
37
+ self.send("#{attr}=", params[attr].to_f)
38
+ end
18
39
  end
19
- time = duration + time if time < 0
20
- time = time.to_i
21
- time
22
- end.uniq
40
+ self.times = number.times.to_a.map { |time| ((offset_start + (duration - offset_start - offset_end) / number * time) * 100).round / 100.0 }.uniq
41
+ else
42
+ raise ArgumentError.new('times or number required') if times.empty?
43
+ end
44
+
23
45
  self.size = params[:size] ? "-s #{params[:size]}" : ''
46
+
47
+ # TODO possibility to replace original image by presetted image
24
48
  if params[:presets] && params[:presets].is_a?(Hash)
25
49
  self.presets = {}
26
50
  params[:presets].each do |name, preset|
@@ -36,15 +60,26 @@ module VideoScreenshoter
36
60
  end
37
61
 
38
62
  def ffmpeg_command input, output, time
39
- "#{ffmpeg} -i #{input} -acodec -an -ss #{time} #{size} -f image2 -vframes 1 -y #{output} 2>/dev/null 1>&2"
63
+ is = exact ? "-i #{input} -ss #{time}" : "-ss #{time} -i #{input}"
64
+ "#{ffmpeg} #{is} -acodec -an #{size} -f image2 -vframes 1 -y #{output} 1>/dev/null 2>&1"
65
+ end
66
+
67
+ def ffmpeg_run time = nil
68
+ cmd = ffmpeg_command(input, output_fullpath(time), time)
69
+ puts cmd if verbose
70
+ system cmd
71
+ end
72
+
73
+ def output_with_preset input, preset_name
74
+ File.join(output_dir, File.basename(input, File.extname(input)) + '_' + preset_name.to_s + File.extname(input))
40
75
  end
41
76
 
42
77
  def imagemagick_command input, preset_name
43
78
  preset = presets[preset_name.to_sym]
44
79
  if !preset || preset.empty?
45
- "cp #{input} #{File.join(File.dirname(input), File.basename(input, File.extname(input)) + '_' + preset_name.to_s + File.extname(input))}"
80
+ "cp #{input} #{output_with_preset(input, preset_name)}"
46
81
  else
47
- "#{imagemagick} #{input} #{preset} #{File.join(File.dirname(input), File.basename(input, File.extname(input)) + '_' + preset_name.to_s + File.extname(input))}"
82
+ "#{imagemagick} #{input} #{preset} #{output_with_preset(input, preset_name)}"
48
83
  end
49
84
  end
50
85
 
@@ -53,7 +88,7 @@ module VideoScreenshoter
53
88
  presets.each do |preset_name, preset|
54
89
  cmd = imagemagick_command(scr, preset_name)
55
90
  puts cmd if verbose
56
- `#{cmd}`
91
+ system cmd
57
92
  end
58
93
  end
59
94
  end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module VideoScreenshoter
4
+ class Image < Abstract
5
+
6
+ def initialize params
7
+ params.each_with_index do |param, index|
8
+ params[index] = Shellwords.escape(param) if param.is_a?(String)
9
+ end
10
+ [:ffmpeg, :imagemagick, :output_dir, :output_file, :verbose].each do |attr|
11
+ self.send("#{attr}=".to_sym, params[attr].nil? ? VideoScreenshoter.send(attr) : params[attr])
12
+ end
13
+ FileUtils.mkdir_p self.output_dir
14
+ self.input = params[:input]
15
+ if params[:presets] && params[:presets].is_a?(Hash)
16
+ self.presets = {}
17
+ params[:presets].each do |name, preset|
18
+ self.presets[name.to_sym] = !preset || preset.empty? || preset.index('-') == 0 ? preset : "-resize #{preset}"
19
+ end
20
+ end
21
+ raise ArgumentError.new('Presets are needed') if presets.nil? || presets.empty?
22
+ end
23
+
24
+ def run
25
+ imagemagick_run input
26
+ Hash[*presets.keys.map { |p| [p, output_with_preset(input, p)] }.flatten]
27
+ end
28
+
29
+ alias :make_screenshots :run
30
+ alias :make_thumbnails :run
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module VideoScreenshoter
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -8,12 +8,7 @@ module VideoScreenshoter
8
8
  end
9
9
 
10
10
  def run
11
- times.each do |time|
12
- cmd = ffmpeg_command(input, output_fullpath(time), time)
13
- puts cmd if verbose
14
- `#{cmd}`
15
- imagemagick_run output_fullpath(time)
16
- end
11
+ times.each { |time| ffmpeg_run(time) and imagemagick_run(output_fullpath(time)) }
17
12
  end
18
13
 
19
14
  alias :make_screenshots :run
Binary file
@@ -81,4 +81,22 @@ class VideoScreenshoterTest < Test::Unit::TestCase
81
81
  end
82
82
  end
83
83
  end
84
+
85
+ context 'image' do
86
+ setup do
87
+ @input = 'test/fixtures/test.jpg'
88
+ @output_dir = '/tmp/image_screenshots_test'
89
+ @presets = {:big=>"1280x720", :small=>"144x81", :big43=>"-resize 1280x960^ -gravity center -crop 1280x960+0+0", :small43=>"-resize 144x108^ -gravity center -crop 144x108+0+0"}
90
+ `rm -r #{@output_dir}` if File.exists? @output_dir
91
+ @res = VideoScreenshoter.new(:input => @input, :output_dir => @output_dir, :presets => @presets, :type => 'image').run
92
+ end
93
+ should 'create screenshots' do
94
+ assert_equal @presets.count, @res.count
95
+ @res.values.each do |res|
96
+ assert File.exists?(res)
97
+ assert File.size(res) > 0
98
+ end
99
+ assert File.size(@res.values.first) != File.size(@res.values.last)
100
+ end
101
+ end
84
102
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: video_screenshoter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-10 00:00:00.000000000 Z
12
+ date: 2014-04-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -90,8 +90,10 @@ files:
90
90
  - lib/video_screenshoter.rb
91
91
  - lib/video_screenshoter/abstract.rb
92
92
  - lib/video_screenshoter/hls.rb
93
+ - lib/video_screenshoter/image.rb
93
94
  - lib/video_screenshoter/version.rb
94
95
  - lib/video_screenshoter/video.rb
96
+ - test/fixtures/test.jpg
95
97
  - test/test_helper.rb
96
98
  - test/video_screenshoter_test.rb
97
99
  - video_screenshoter.gemspec
@@ -110,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
112
  version: '0'
111
113
  segments:
112
114
  - 0
113
- hash: 1646458223958900487
115
+ hash: -2212613341637156165
114
116
  required_rubygems_version: !ruby/object:Gem::Requirement
115
117
  none: false
116
118
  requirements:
@@ -119,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  version: '0'
120
122
  segments:
121
123
  - 0
122
- hash: 1646458223958900487
124
+ hash: -2212613341637156165
123
125
  requirements:
124
126
  - ffmpeg
125
127
  - imagemagick
@@ -129,5 +131,6 @@ signing_key:
129
131
  specification_version: 3
130
132
  summary: Make screenshots from video or m3u8 files using ffmpeg
131
133
  test_files:
134
+ - test/fixtures/test.jpg
132
135
  - test/test_helper.rb
133
136
  - test/video_screenshoter_test.rb