ffmpeg_progress 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90f77bff70d2e03a8fcef49490199f652ee1c78f
4
- data.tar.gz: 45f4aff12498c91bfe9c3670ea0b53d51eb37285
3
+ metadata.gz: a87f8c15bd7699211c31d0b253c355884e9ea1f0
4
+ data.tar.gz: 3bfc1f6bd6c6cd176f34c93a90c272735eb01588
5
5
  SHA512:
6
- metadata.gz: 16c6f7766bb04438b666e84655916a8fc05b27107ec67ce2dcb1510e86e53b95eddbc2cf3da452dfb875b269d42c703f0adf37b1370b9a2f911acfa9bc8c96d5
7
- data.tar.gz: 6560808c7430e8f3c2b868039c3a46170e4cd719384831a1324e749ae3beb771632b283658f8164ed0e708343b4f858a31d818f242d39db12dc7f3af76de50b3
6
+ metadata.gz: 71f43b1a4be93308c0a3e049896d981f6d8d3f3ac057257548b2befabc996e89688f6a1f7576a767c2992daad98974dff1e69c1bae41db76e3afb0293f9138cf
7
+ data.tar.gz: 17e574551623658a375a4b8375b254f5abf59d833875e375841e70fcc6758fd0d3e022dae17a39ef3d62e81d5fc7b6b0b014ae12e486d512ad0db072ed90c7ee
@@ -1,4 +1,4 @@
1
- =FfmpegProgress
1
+ =FFmpegProgress
2
2
 
3
3
  {<img src="http://inch-ci.org/github/Winterbraid/ffmpeg_progress.svg?branch=master" alt="Inline docs" />}[http://inch-ci.org/github/Winterbraid/ffmpeg_progress]
4
4
  {<img src="https://codeclimate.com/github/Winterbraid/ffmpeg_progress/badges/gpa.svg" />}[https://codeclimate.com/github/Winterbraid/ffmpeg_progress]
@@ -12,14 +12,14 @@ usual garbage.
12
12
 
13
13
  Convert from the shell with default options:
14
14
  # Will save to ./converted/test.mp4
15
- ruby -rffmpeg_progress -e "FfmpegProgress::Ffmpeg.new('test.avi').run"
15
+ ruby -rffmpeg_progress -e "FFmpegProgress::FFmpeg.new('test.avi').run"
16
16
 
17
17
  ==Example Use
18
18
  require 'ffmpeg_progress'
19
19
 
20
- include FfmpegProgress
20
+ include FFmpegProgress
21
21
 
22
- f = Ffmpeg.new 'input.avi'
22
+ f = FFmpeg.new 'input.avi'
23
23
 
24
24
  # Occurrences of '_INPUT_' will be replaced with the input file name.
25
25
  f.options = '-y -threads 0 -c:v libx264 -crf 22 -preset medium -c:a copy'
@@ -1,253 +1,11 @@
1
1
  require 'fileutils'
2
2
 
3
- # {include:file:README.rdoc}
4
- module FfmpegProgress
5
- # The current software version.
6
- VERSION = '1.0.2'
7
-
8
- # The date of the current version.
9
- DATE = '2014-10-31'
10
-
11
- # A short description of the software.
12
- ABOUT = 'A fancy progress bar for ffmpeg.'
13
-
14
- # Contains various examples of +ffmpeg+ options.
15
- module Presets
16
- # The default options. Convert the video to x264 and audio to AAC.
17
- DEFAULT_OPTS = '-y -threads 0 -strict -2 -c:a aac -b:a 96k ' \
18
- '-c:v libx264 -preset fast -tune fastdecode -crf 22 '
19
-
20
- # Read the default subtitles embedded in an input MKV file and hardcode
21
- # them into the video. Any embedded fonts must be extracted and installed
22
- # first to preserve them in the output, for example:
23
- # mkvextract attachments input.mkv {1..10}
24
- # cp *.ttf *.ttc *.otf ~/.fonts
25
- BURN_MKV_SUBS = '-y -threads 0 -strict -2 -sn -c:a copy ' \
26
- '-c:v libx264 -preset fast -tune fastdecode -crf 22 ' \
27
- '-vf "subtitles=_INPUT_"'
28
-
29
- # Like {BURN_MKV_SUBS}, but also downscale the video to 800px width.
30
- BURN_800 = '-y -threads 0 -strict -2 -sn -c:a aac -b:a 96k ' \
31
- '-c:v libx264 -preset fast -tune fastdecode -crf 22 ' \
32
- '-vf "[in]scale=800:-2[tmp];[tmp]subtitles=_INPUT_[out]"'
33
- end
34
-
35
- # Helper methods.
36
- module Utils
37
- # Colorize a string for the terminal (256-color mode).
38
- #
39
- # @param [String] string
40
- # @param [Integer] color
41
- # @return [String]
42
- def colorize(string, color)
43
- "\x1b[38;5;#{color}m#{string}\x1b[0m"
44
- end
45
-
46
- # Parse a time string in the +ffmpeg+ HH:MM:SS.ms format and return seconds.
47
- #
48
- # @param [String] time_string
49
- # @return [Integer]
50
- def parse_ffmpeg_time(time_string)
51
- array = time_string.rpartition('.').first.split(':').map(&:to_i)
52
-
53
- array[0] * 3600 + array[1] * 60 + array[2]
54
- end
55
- end
56
-
57
- # The class that does the actual work.
58
- class Ffmpeg
59
- include Presets
60
- include Utils
61
-
62
- # The log file for ffmpeg. Progress data will be read from here.
63
- LOG_FILE = 'ffmpeg.log'
64
-
65
- # The extension for the default output file.
66
- DEFAULT_EXT = 'mp4'
67
-
68
- # The directory for the default output file.
69
- DEFAULT_DIR = 'converted/'
70
-
71
- # The default theme, change this with {#theme=}. {FfmpegProgress} expects
72
- # a 256-color capable terminal.
73
- DEFAULT_THEME = {
74
- bars: 63, head: '[', full: '=', empty: '-', tail: ']',
75
- end_fg: 202, full_fg: 214, empty_fg: 202,
76
- time_fg: 214, block_fg: 214, finish_fg: 40, cancel_fg: 1
77
- }
78
-
79
- # The input file.
80
- # @return [String]
81
- attr_reader :input
82
-
83
- # The output file. Directories will be auto-created on execution.
84
- # @return [String]
85
- attr_accessor :output
86
-
87
- # Returns the duration (in seconds) of the input file.
88
- # @return [Integer]
89
- attr_reader :duration
90
-
91
- # Returns the duration of the input file as a +ffmpeg+ format string
92
- # (+HH:MM:SS.ms+).
93
- #
94
- # @return [Integer]
95
- attr_reader :duration_ff
96
-
97
- # The options to pass to +ffmpeg+. Any occurrences of the string +_INPUT_+
98
- # will be converted to the value of the {#input} attribute.
99
- # @return [String]
100
- attr_accessor :options
101
-
102
- # The theme for the progress bar. See {DEFAULT_THEME} for details.
103
- # @return [Hash]
104
- attr_accessor :theme
105
-
106
- # The PID of the last spawned +ffmpeg+ process, or +nil+ if none spawned
107
- # yet.
108
- # @return [Integer]
109
- attr_reader :pid
110
-
111
- # Creates a new {Ffmpeg} instance.
112
- #
113
- # @param [String] input_file the source file name.
114
- # @param [String] ffmpeg_options the options to pass to ffmpeg.
115
- # See {#options} for details and {Presets} for examples.
116
- # @return [Ffmpeg]
117
- def initialize(input_file = nil, ffmpeg_options = DEFAULT_OPTS)
118
- self.input = input_file
119
- @options = ffmpeg_options
120
-
121
- @output ||= nil
122
- @duration_ff ||= nil
123
- @duration ||= nil
124
-
125
- @block = nil
126
-
127
- @pid = nil
128
- @theme = DEFAULT_THEME
129
-
130
- @last_bar = nil
131
- end
3
+ require 'ffmpeg_progress/metadata.rb'
132
4
 
133
- # Set the input file.
134
- #
135
- # @param [String] string
136
- # @return [String]
137
- def input=(string)
138
- @input = string
5
+ require 'ffmpeg_progress/presets.rb'
6
+ require 'ffmpeg_progress/utils.rb'
7
+ require 'ffmpeg_progress/theme.rb'
8
+ require 'ffmpeg_progress/ffmpeg.rb'
139
9
 
140
- return @input unless @input
141
-
142
- @duration_ff = `ffmpeg -i \'#{@input}\' 2>&1`.scan(/..:..:..\.../).first
143
- @duration = parse_ffmpeg_time(@duration_ff)
144
-
145
- @output ||= "#{DEFAULT_DIR}#{@input.rpartition('.').first}.#{DEFAULT_EXT}"
146
-
147
- @input
148
- end
149
-
150
- # Returns the current +ffmpeg+ command that will be executed by {#run}.
151
- #
152
- # @return [String]
153
- def command
154
- "ffmpeg -i \'#{@input}\' #{@options} \'#{@output}\' &> #{LOG_FILE}"
155
- .gsub('_INPUT_', "'#{@input}'")
156
- end
157
-
158
- # Run +ffmpeg+ while printing a progress bar to the terminal.
159
- # If a block is passed, its return value will be attached to the
160
- # progress bar. The current {Ffmpeg} instance will be passed to
161
- # the block.
162
- #
163
- # @return [0]
164
- def run(&block)
165
- File.delete(LOG_FILE) if File.exist?(LOG_FILE)
166
-
167
- FileUtils.mkpath(@output.rpartition('/').first) if output.include?('/')
168
-
169
- @pid = spawn command
170
- @block = block
171
-
172
- sleep 1 until current_time
173
- monitor_progress
174
-
175
- cleanup
176
-
177
- 0
178
- end
179
-
180
- private
181
-
182
- # Display the progress bar while waiting for +ffmpeg+ to finish.
183
- def monitor_progress
184
- until Process.waitpid(@pid, Process::WNOHANG)
185
- print "\r#{progress_bar}"
186
- sleep 1
187
- end
188
-
189
- puts "\r#{progress_bar(@theme[:finish_fg], @duration_ff)}"
190
- rescue Interrupt
191
- puts "\r#{progress_bar(@theme[:cancel_fg])}"
192
- end
193
-
194
- # Display the progress bar.
195
- def progress_bar(time_fg = @theme[:time_fg], time = current_time)
196
- elements = bar_elements(time_fg, time)
197
-
198
- bar =
199
- "#{elements.head}#{elements.full}#{elements.empty}#{elements.tail}" \
200
- "#{elements.head}#{elements.time}#{elements.tail}"
201
-
202
- if @block
203
- block_value = colorize(@block.call(self), @theme[:block_fg])
204
- bar << "#{elements.head}#{block_value}#{elements.tail}"
205
- end
206
-
207
- bar
208
- end
209
-
210
- # Get the current time (in +ffmpeg+ format) from the log file.
211
- # Returns +nil+ if the actual transcoding process has not started yet.
212
- #
213
- # @return [String]
214
- def current_time
215
- return nil unless File.exist?(LOG_FILE)
216
- match = File.read(LOG_FILE).scan(/time=..:..:..\.../).last
217
-
218
- return '00:00:00.00' unless match
219
- match.delete('time=')
220
- end
221
-
222
- # Generate bar elements for a given +ffmpeg+ time.
223
- def bar_elements(time_fg, time)
224
- elements = Struct.new(:head, :tail, :full, :empty, :time)
225
- bars = (@theme[:bars] * parse_ffmpeg_time(time) / @duration).round
226
-
227
- elements.new(
228
- colorize(@theme[:head], @theme[:end_fg]),
229
- colorize(@theme[:tail], @theme[:end_fg]),
230
- colorize(@theme[:full] * bars, @theme[:full_fg]),
231
- colorize(@theme[:empty] * (@theme[:bars] - bars), @theme[:empty_fg]),
232
- colorize(time, time_fg)
233
- )
234
- end
235
-
236
- # Kill +ffmpeg+ if still running, and delete the log file.
237
- def cleanup
238
- Process.detach(@pid)
239
-
240
- ffmpeg_alive =
241
- begin
242
- Process.kill(0, @pid)
243
- true
244
- rescue Errno::ESRCH
245
- false
246
- end
247
-
248
- Process.kill('TERM', @pid) if ffmpeg_alive
249
-
250
- File.delete(LOG_FILE) if File.exist?(LOG_FILE)
251
- end
252
- end
253
- end
10
+ # {include:file:README.rdoc}
11
+ module FFmpegProgress; end
@@ -0,0 +1,177 @@
1
+ module FFmpegProgress
2
+ # The class that does the actual work.
3
+ class FFmpeg
4
+ include Presets
5
+ include Utils
6
+
7
+ # The log file for +ffmpeg+. Progress data will be read from here.
8
+ LOG_FILE = 'ffmpeg.log'
9
+
10
+ # The extension for the default output file.
11
+ DEFAULT_EXT = 'mp4'
12
+
13
+ # The directory for the default output file.
14
+ DEFAULT_DIR = 'converted/'
15
+
16
+ # The input file.
17
+ # @return [String]
18
+ attr_reader :input
19
+
20
+ # The output file. Directories will be auto-created on execution.
21
+ # @return [String]
22
+ attr_accessor :output
23
+
24
+ # Returns the duration (in seconds) of the input file.
25
+ # @return [Integer]
26
+ attr_reader :duration
27
+
28
+ # Returns the duration of the input file as a +ffmpeg+ format string
29
+ # +(HH:MM:SS.ms)+.
30
+ #
31
+ # @return [Integer]
32
+ attr_reader :duration_ff
33
+
34
+ # The options to pass to +ffmpeg+. Any occurrences of the string +\_INPUT\_+
35
+ # will be converted to the value of the {#input} attribute.
36
+ # @return [String]
37
+ attr_accessor :options
38
+
39
+ # The theme for the progress bar. See {Theme::DEFAULT_THEME} for details.
40
+ # @return [Hash]
41
+ attr_accessor :theme
42
+
43
+ # The PID of the last spawned +ffmpeg+ process, or +nil+ if none spawned
44
+ # yet.
45
+ # @return [Integer]
46
+ attr_reader :pid
47
+
48
+ # Creates a new {FFmpeg} instance.
49
+ #
50
+ # @param [String] input_file the source file name.
51
+ # @param [Hash] option_hash
52
+ # @option option_hash [String] :output the output file to write to.
53
+ # @option option_hash [String] :options the options to pass to +ffmpeg+.
54
+ # See {#options} for details and {Presets} for examples.
55
+ # @option option_hash [Hash, Theme] :theme either a theme hash or a {Theme}
56
+ # object.
57
+ # @option option_hash [Boolean] :bell whether to play a bell sound upon
58
+ # finishing the task. (See {Utils} for details.)
59
+ # @return [FFmpeg]
60
+ def initialize(input_file, option_hash = {})
61
+ self.input = input_file
62
+
63
+ @options = option_hash.fetch :options, DEFAULT_OPTIONS
64
+ @theme = Theme.from(option_hash.fetch :theme, Theme.new)
65
+ @bell = option_hash.fetch :bell, false
66
+
67
+ @output = option_hash.fetch :output, @output
68
+ @duration_ff ||= nil
69
+ @duration ||= nil
70
+
71
+ @block = nil
72
+
73
+ @pid = nil
74
+
75
+ @last_bar = nil
76
+ end
77
+
78
+ # Set the input file.
79
+ #
80
+ # @param [String] string
81
+ # @return [String]
82
+ def input=(string)
83
+ @input = string
84
+
85
+ return @input unless @input
86
+
87
+ @duration_ff = `ffmpeg -i \'#{@input}\' 2>&1`.scan(/..:..:..\.../).first
88
+ @duration = parse_ffmpeg_time(@duration_ff)
89
+
90
+ @output ||= "#{DEFAULT_DIR}#{@input.rpartition('.').first}.#{DEFAULT_EXT}"
91
+
92
+ @input
93
+ end
94
+
95
+ # Returns the current +ffmpeg+ command that will be executed by {#run}.
96
+ #
97
+ # @return [String]
98
+ def command
99
+ "ffmpeg -i \'#{@input}\' #{@options} \'#{@output}\' &> #{LOG_FILE}"
100
+ .gsub('_INPUT_', "'#{@input}'")
101
+ end
102
+
103
+ # Run +ffmpeg+ while printing a progress bar to the terminal.
104
+ # If a block is passed, its return value will be attached to the
105
+ # progress bar. The current {FFmpeg} instance will be passed to
106
+ # the block.
107
+ #
108
+ # @return [0]
109
+ def run(&block)
110
+ File.delete(LOG_FILE) if File.exist?(LOG_FILE)
111
+
112
+ FileUtils.mkpath(@output.rpartition('/').first) if output.include?('/')
113
+
114
+ @pid = spawn command
115
+ @block = block
116
+
117
+ sleep 1 until current_time
118
+ monitor_progress
119
+
120
+ cleanup
121
+
122
+ 0
123
+ end
124
+
125
+ private
126
+
127
+ # Display the progress bar while waiting for +ffmpeg+ to finish.
128
+ def monitor_progress
129
+ until Process.waitpid(@pid, Process::WNOHANG)
130
+ print "\r#{progress_bar}"
131
+ sleep 1
132
+ end
133
+
134
+ puts "\r#{progress_bar(@duration_ff, finished: true)}"
135
+ bell if @bell
136
+ rescue Interrupt, IRB::Abort
137
+ puts "\r#{progress_bar(current_time, interrupted: true)}"
138
+ end
139
+
140
+ # Display the progress bar.
141
+ def progress_bar(time = current_time, option_hash = {})
142
+ position = parse_ffmpeg_time(time).to_f / @duration
143
+ option_hash.merge!(block_output: (@block ? @block.call(self) : nil))
144
+
145
+ @theme.bar(position, time, option_hash)
146
+ end
147
+
148
+ # Get the current time (in +ffmpeg+ format) from the log file.
149
+ # Returns +nil+ if the actual transcoding process has not started yet.
150
+ #
151
+ # @return [String]
152
+ def current_time
153
+ return nil unless File.exist?(LOG_FILE)
154
+ match = File.read(LOG_FILE).scan(/time=..:..:..\.../).last
155
+
156
+ return '00:00:00.00' unless match
157
+ match.delete('time=')
158
+ end
159
+
160
+ # Kill +ffmpeg+ if still running, and delete the log file.
161
+ def cleanup
162
+ Process.detach(@pid)
163
+
164
+ ffmpeg_alive =
165
+ begin
166
+ Process.kill(0, @pid)
167
+ true
168
+ rescue Errno::ESRCH
169
+ false
170
+ end
171
+
172
+ Process.kill('TERM', @pid) if ffmpeg_alive
173
+
174
+ File.delete(LOG_FILE) if File.exist?(LOG_FILE)
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,11 @@
1
+ # {include:file:README.rdoc}
2
+ module FFmpegProgress
3
+ # The current software version.
4
+ VERSION = '1.1.0'
5
+
6
+ # The date of the current version.
7
+ DATE = '2014-10-31'
8
+
9
+ # A short description of the software.
10
+ ABOUT = 'A fancy progress bar for ffmpeg.'
11
+ end
@@ -0,0 +1,27 @@
1
+ module FFmpegProgress
2
+ # Contains various examples of +ffmpeg+ options.
3
+ module Presets
4
+ # The default options. Convert the video to x264 and audio to AAC.
5
+ DEFAULT_OPTIONS = '-y -threads 0 -strict -2 -c:a aac -b:a 96k ' \
6
+ '-c:v libx264 -preset fast -tune fastdecode -crf 22 '
7
+
8
+ # Read the default subtitles embedded in an input MKV file and hardcode
9
+ # them into the video. Any embedded fonts must be extracted and installed
10
+ # first to preserve them in the output, for example:
11
+ # mkvextract attachments input.mkv {1..10}
12
+ # cp *.ttf *.ttc *.otf ~/.fonts
13
+ BURN_MKV_SUBS = '-y -threads 0 -strict -2 -sn -c:a copy ' \
14
+ '-c:v libx264 -preset fast -tune fastdecode -crf 22 ' \
15
+ '-vf "subtitles=_INPUT_"'
16
+
17
+ # Like {BURN_MKV_SUBS}, but also downscale the video to 800px width.
18
+ BURN_800 = '-y -threads 0 -strict -2 -sn -c:a aac -b:a 96k ' \
19
+ '-c:v libx264 -preset fast -tune fastdecode -crf 22 ' \
20
+ '-vf "[in]scale=800:-2[tmp];[tmp]subtitles=_INPUT_[out]"'
21
+
22
+ # Scale to 800px width.
23
+ WIDTH_800 = '-y -threads 0 -strict -2 -sn -c:a aac -b:a 96k ' \
24
+ '-c:v libx264 -preset fast -tune fastdecode -crf 22 ' \
25
+ '-vf scale=800:-2'
26
+ end
27
+ end
@@ -0,0 +1,177 @@
1
+ module FFmpegProgress
2
+ # This is the class that handles progress bar themes and converting them into
3
+ # visual elements. {FFmpegProgress} expects a 256-color capable terminal.
4
+ class Theme
5
+ # The default theme.
6
+ DEFAULT_THEME = {
7
+ bars: 63, head_chr: '[', full_chr: '=', empty_chr: '-', tail_chr: ']',
8
+ end_fg: 202, full_fg: 214, empty_fg: 202,
9
+ time_fg: 214, block_fg: 214, finish_fg: 40, cancel_fg: 1
10
+ }
11
+
12
+ # The length of the progress bar.
13
+ #
14
+ # @return [Integer]
15
+ attr_accessor :bars
16
+
17
+ # The string to be used as the start of a section.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :head_chr
21
+
22
+ # The string to be used to draw the filled part of the bar.
23
+ #
24
+ # @return [String]
25
+ attr_accessor :full_chr
26
+
27
+ # The string to be used to draw the remaining part of the bar.
28
+ #
29
+ # @return [String]
30
+ attr_accessor :empty_chr
31
+
32
+ # The string to be used as the end of a section.
33
+ #
34
+ # @return [String]
35
+ attr_accessor :tail_chr
36
+
37
+ # The color of the beginning and end of a section.
38
+ #
39
+ # @return [Integer]
40
+ attr_accessor :end_fg
41
+
42
+ # The color of the filled part of the bar.
43
+ #
44
+ # @return [Integer]
45
+ attr_accessor :full_fg
46
+
47
+ # The color of the remaining part of the bar.
48
+ #
49
+ # @return [Integer]
50
+ attr_accessor :empty_fg
51
+
52
+ # The color of the current time position info.
53
+ #
54
+ # @return [Integer]
55
+ attr_accessor :time_fg
56
+
57
+ # The color of the optional block return value.
58
+ #
59
+ # @return [Integer]
60
+ attr_accessor :block_fg
61
+
62
+ # The color of the time position info on a completed task.
63
+ #
64
+ # @return [Integer]
65
+ attr_accessor :finish_fg
66
+
67
+ # The color of the time position info on an interrupted task.
68
+ #
69
+ # @return [Integer]
70
+ attr_accessor :cancel_fg
71
+
72
+ # Generates a new instance of Theme. Returns the argument if the argument
73
+ # is a Theme.
74
+ #
75
+ # @param [Hash, Theme] object
76
+ # @return [Theme]
77
+ def self.from(object)
78
+ return object if object.is_a? Theme
79
+ return new(object) if object.is_a? Hash
80
+ fail 'Argument must be either Theme or Hash.'
81
+ end
82
+
83
+ # Generates a new instance of Theme from a theme hash.
84
+ #
85
+ # @param [Hash] theme_hash
86
+ # @return [Theme]
87
+ def initialize(theme_hash = DEFAULT_THEME)
88
+ DEFAULT_THEME.merge(theme_hash).each_pair do |key, value|
89
+ method("#{key}=").call(value) if DEFAULT_THEME.key? key
90
+ end
91
+ end
92
+
93
+ # Returns a progress bar given a fractional position, a time string,
94
+ # and an optional block output string.
95
+ #
96
+ # @param [Float] position
97
+ # @param [String] time_string
98
+ # @param [Hash] option_hash
99
+ # @option option_hash [String] :block_output the output from the optional
100
+ # block passed to {FFmpeg#run}, if any.
101
+ # @option option_hash [Boolean] :interrupted has the task been canceled?
102
+ # @option option_hash [Boolean] :finished has the task finished?
103
+ # @return [String]
104
+ def bar(position, time_string = '00:00:00.00', option_hash = {})
105
+ output = "#{head}#{full(position)}#{empty(position)}#{tail}" \
106
+ "#{head}#{time(time_string, option_hash)}#{tail}"
107
+
108
+ if option_hash.fetch :block_output, false
109
+ output << "#{head}#{colorize(option_hash[:block_output], @block_fg)}" \
110
+ "#{tail}"
111
+ end
112
+
113
+ output
114
+ end
115
+
116
+ private
117
+
118
+ # Returns the contents of the time section.
119
+ #
120
+ # @param [String] time_string
121
+ # @param [Hash] option_hash
122
+ # @option option_hash [Boolean] :interrupted has the task been canceled?
123
+ # @option option_hash [Boolean] :finished has the task finished?
124
+ # @return [String]
125
+ def time(time_string, option_hash = {})
126
+ fg_color =
127
+ if option_hash.fetch :interrupted, false
128
+ @cancel_fg
129
+ elsif option_hash.fetch :finished, false
130
+ @finish_fg
131
+ else
132
+ @time_fg
133
+ end
134
+
135
+ colorize(time_string, fg_color)
136
+ end
137
+
138
+ # Returns the filled part of the progress bar given a fractional position.
139
+ #
140
+ # @param [Float] position
141
+ # @return [String]
142
+ def full(position)
143
+ colorize(@full_chr * (position * @bars).round, @full_fg)
144
+ end
145
+
146
+ # Returns the empty part of the progress bar given a fractional position.
147
+ #
148
+ # @param [Float] position
149
+ # @return [String]
150
+ def empty(position)
151
+ colorize(@empty_chr * (@bars - (position * @bars).round), @empty_fg)
152
+ end
153
+
154
+ # Returns a colorized section start element.
155
+ #
156
+ # @return [String]
157
+ def head
158
+ colorize(@head_chr, @end_fg)
159
+ end
160
+
161
+ # Returns a colorized section end element.
162
+ #
163
+ # @return [String]
164
+ def tail
165
+ colorize(@tail_chr, @end_fg)
166
+ end
167
+
168
+ # Colorize a string for the terminal (256-color mode).
169
+ #
170
+ # @param [String] string
171
+ # @param [Integer] color
172
+ # @return [String]
173
+ def colorize(string, color)
174
+ "\x1b[38;5;#{color}m#{string}\x1b[0m"
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,29 @@
1
+ module FFmpegProgress
2
+ # Helper methods.
3
+ module Utils
4
+ # The bell file to be used to signal completion.
5
+ BELL = "#{File.expand_path('../../..', __FILE__)}/" \
6
+ 'assets/LucasGonze_StLouisWaltz.ogg'
7
+
8
+ # Play the bell sound.
9
+ #
10
+ # @return [Integer] the PID of the bell process.
11
+ def bell
12
+ ffplay =
13
+ spawn "ffplay -nodisp -autoexit '#{BELL}' &> /dev/null"
14
+ Process.detach(ffplay)
15
+ ffplay
16
+ end
17
+
18
+ # Parse a time string in the +ffmpeg+ +HH:MM:SS.ms+ format and
19
+ # return seconds.
20
+ #
21
+ # @param [String] time_string
22
+ # @return [Integer]
23
+ def parse_ffmpeg_time(time_string)
24
+ array = time_string.rpartition('.').first.split(':').map(&:to_i)
25
+
26
+ array[0] * 3600 + array[1] * 60 + array[2]
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffmpeg_progress
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Winterbraid
@@ -19,7 +19,13 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - LICENSE.txt
21
21
  - README.rdoc
22
+ - assets/LucasGonze_StLouisWaltz.ogg
22
23
  - lib/ffmpeg_progress.rb
24
+ - lib/ffmpeg_progress/ffmpeg.rb
25
+ - lib/ffmpeg_progress/metadata.rb
26
+ - lib/ffmpeg_progress/presets.rb
27
+ - lib/ffmpeg_progress/theme.rb
28
+ - lib/ffmpeg_progress/utils.rb
23
29
  homepage: https://github.com/Winterbraid/ffmpeg_progress
24
30
  licenses:
25
31
  - MIT