autogg 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENCE ADDED
@@ -0,0 +1,8 @@
1
+ Copyright (c) 2011 Evan Simmons
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
data/README ADDED
@@ -0,0 +1 @@
1
+ Encodes all flac files in a given directory to ogg in another given directory while preserving the directory structure. Also if rb-inotify is installed and -w flag is passed, it will watch for changes on the filesystem and rescan the directory, encoding the new files.
@@ -0,0 +1,15 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'autogg'
3
+ s.summary = 'converts a folder of flacs to ogg, preserving directory structure'
4
+ s.description = File.read(File.join(File.dirname(__FILE__), 'README'))
5
+ s.requirements << 'oggenc must be installed on the base system'
6
+ s.version = "0.2.0"
7
+ s.author = 'Evan Simmons'
8
+ s.email = 'esims89@gmail.com'
9
+ s.homepage = 'https://github.com/estk/autogg'
10
+ s.platform = Gem::Platform::RUBY
11
+ s.required_ruby_version = '>=1.9'
12
+ s.files = Dir['**/**']
13
+ s.executables = [ 'autogg' ]
14
+ s.has_rdoc = false
15
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'autogg/runner'
3
+ runner = OggEncode::Runner.run(ARGV)
@@ -0,0 +1,83 @@
1
+ require 'find'
2
+ require_relative 'progressbar'
3
+
4
+ module OggEncode
5
+ class OggEncoder
6
+ class << self
7
+
8
+ def oggencdir
9
+ Find.find( @paths.flac ) do |path|
10
+ if FileTest.directory?( path )
11
+ if File.basename( path )[0] == ?.
12
+ Find.prune
13
+ else
14
+ #@pbar.inc
15
+ end
16
+ elsif Flac.exists?( path ) and not Ogg.exists?( getoutpath(path) )
17
+ encfile( path )
18
+ end
19
+ end
20
+ Process.waitall ; @ps_hash = {}
21
+ end
22
+
23
+ def encfile( inpath )
24
+ outpath = getoutpath( inpath )
25
+ @ps_hash.store( nil, outpath ) do
26
+ IO.popen %Q{oggenc #{@oggargs.join(' ')} "#{inpath}" -o "#{outpath}"}
27
+ end
28
+ @pbar.inc
29
+ end
30
+
31
+ def getoutpath( inpath )
32
+ outpath = inpath.gsub( @paths.flac, @paths.ogg )
33
+ outpath.gsub!( /\.flac/, '.ogg' )
34
+ end
35
+
36
+ def count_flacs
37
+ c = 0
38
+ Find.find( @paths.flac ) {|p| c += 1 if Flac.exists?( p ) }
39
+ c
40
+ end
41
+
42
+ def count_oggs
43
+ c = 0
44
+ Find.find( @paths.ogg ) {|p| c += 1 if Ogg.exists?( p ) }
45
+ c
46
+ end
47
+
48
+ def interupt
49
+ puts "\n" + "Shutting down and removing partially encoded files"
50
+ @ps_hash.each do |pid, path|
51
+ File.delete( path )
52
+ end
53
+ exit
54
+ end
55
+
56
+ def watcher
57
+ require 'rb-inotify'
58
+ notifier = INotify::Notifier.new
59
+ notifier.watch( @paths.flac, :create ) do |e|
60
+ puts %Q{#{Time.now.ctime}: #{e.name} was modified, rescaning...}
61
+ oggencdir ; Process.waitall
62
+ puts "watching #{@paths.flac}"
63
+ end
64
+ puts "watching #{@paths.flac}"
65
+ notifier.run
66
+ end
67
+
68
+ def encode( options )
69
+ @options = options
70
+ @paths = options.paths
71
+ @oggargs = options.oggargs
72
+ @ps_hash = SizedPsHash.new( options.max_procs )
73
+ @pbar = ProgressBar.new( "Subdirectory progress", ( count_flacs - count_oggs ) )
74
+ oggencdir ; @pbar.finish
75
+ watcher if options.watch
76
+ end
77
+ end
78
+
79
+ trap "INT" do
80
+ interupt
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,55 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ module OggEncode
5
+ class Parser
6
+ def self.parse(args)
7
+
8
+ script_name = File.basename( $0 )
9
+ options = OpenStruct.new
10
+ options.watch = false
11
+ options.max_procs = 4
12
+ options.oggargs = ['-Q']
13
+
14
+ op = OptionParser.new do |opts|
15
+ opts.banner = "Usage: autogg.rb [options] flacpath oggpath [ -o oggenc args ... ]\n" +
16
+ "Example: #{script_name} ~/music/flac/ ~/music/ogg/ --watch --oggenc-args -q8\n" +
17
+ " Ex2: #{script_name} ~/music/flac/ ~/music/ogg/ -o -q8,-Q,--utf8"
18
+
19
+ opts.on( '-w', '--watch',
20
+ "Watch flacpath for changes, then rescan " +
21
+ "and encode if any files are created within" ) do
22
+ options.watch = true
23
+ end
24
+
25
+ opts.on( '-m', '--max-processes n', "Maximum number of encoding processes running at once" ) do |n|
26
+ options.max_procs = n.to_i
27
+ end
28
+
29
+ opts.on( '-o', '--oggenc-args arglist', Array,
30
+ "Specify arguments to me be passed through to oggenc" ) do |ary|
31
+ options.oggargs << ary
32
+ options.oggargs.flatten!
33
+ end
34
+
35
+ opts.on( '-h', '--help', 'Display this screen' ) do
36
+ puts opts
37
+ puts dirinfo
38
+ exit
39
+ end
40
+ end
41
+ op.parse!
42
+
43
+ if ( ARGV.length == 2 ) and ARGV.all? { |a| File.directory?( a )}
44
+ paths = OpenStruct.new
45
+ paths.flac = ARGV[0] ; paths.ogg = ARGV[1]
46
+ options.paths = paths
47
+ else
48
+ puts op
49
+ exit
50
+ end
51
+
52
+ options
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,236 @@
1
+ #
2
+ # Ruby/ProgressBar - a text progress bar library
3
+ #
4
+ # Copyright (C) 2001-2005 Satoru Takabayashi <satoru@namazu.org>
5
+ # All rights reserved.
6
+ # This is free software with ABSOLUTELY NO WARRANTY.
7
+ #
8
+ # You can redistribute it and/or modify it under the terms
9
+ # of Ruby's license.
10
+ #
11
+
12
+ class ProgressBar
13
+ VERSION = "0.9"
14
+
15
+ def initialize (title, total, out = STDERR)
16
+ @title = title
17
+ @total = total
18
+ @out = out
19
+ @terminal_width = 80
20
+ @bar_mark = "o"
21
+ @current = 0
22
+ @previous = 0
23
+ @finished_p = false
24
+ @start_time = Time.now
25
+ @previous_time = @start_time
26
+ @title_width = 14
27
+ @format = "%-#{@title_width}s %3d%% %s %s"
28
+ @format_arguments = [:title, :percentage, :bar, :stat]
29
+ clear
30
+ show
31
+ end
32
+ attr_reader :title
33
+ attr_reader :current
34
+ attr_reader :total
35
+ attr_accessor :start_time
36
+
37
+ private
38
+ def fmt_bar
39
+ bar_width = do_percentage * @terminal_width / 100
40
+ sprintf("|%s%s|",
41
+ @bar_mark * bar_width,
42
+ " " * (@terminal_width - bar_width))
43
+ end
44
+
45
+ def fmt_percentage
46
+ do_percentage
47
+ end
48
+
49
+ def fmt_stat
50
+ if @finished_p then elapsed else eta end
51
+ end
52
+
53
+ def fmt_stat_for_file_transfer
54
+ if @finished_p then
55
+ sprintf("%s %s %s", bytes, transfer_rate, elapsed)
56
+ else
57
+ sprintf("%s %s %s", bytes, transfer_rate, eta)
58
+ end
59
+ end
60
+
61
+ def fmt_title
62
+ @title[0,(@title_width - 1)] + ":"
63
+ end
64
+
65
+ def convert_bytes (bytes)
66
+ if bytes < 1024
67
+ sprintf("%6dB", bytes)
68
+ elsif bytes < 1024 * 1000 # 1000kb
69
+ sprintf("%5.1fKB", bytes.to_f / 1024)
70
+ elsif bytes < 1024 * 1024 * 1000 # 1000mb
71
+ sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
72
+ else
73
+ sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
74
+ end
75
+ end
76
+
77
+ def transfer_rate
78
+ bytes_per_second = @current.to_f / (Time.now - @start_time)
79
+ sprintf("%s/s", convert_bytes(bytes_per_second))
80
+ end
81
+
82
+ def bytes
83
+ convert_bytes(@current)
84
+ end
85
+
86
+ def format_time (t)
87
+ t = t.to_i
88
+ sec = t % 60
89
+ min = (t / 60) % 60
90
+ hour = t / 3600
91
+ sprintf("%02d:%02d:%02d", hour, min, sec);
92
+ end
93
+
94
+ # ETA stands for Estimated Time of Arrival.
95
+ def eta
96
+ if @current == 0
97
+ "ETA: --:--:--"
98
+ else
99
+ elapsed = Time.now - @start_time
100
+ eta = elapsed * @total / @current - elapsed;
101
+ sprintf("ETA: %s", format_time(eta))
102
+ end
103
+ end
104
+
105
+ def elapsed
106
+ elapsed = Time.now - @start_time
107
+ sprintf("Time: %s", format_time(elapsed))
108
+ end
109
+
110
+ def eol
111
+ if @finished_p then "\n" else "\r" end
112
+ end
113
+
114
+ def do_percentage
115
+ if @total.zero?
116
+ 100
117
+ else
118
+ @current * 100 / @total
119
+ end
120
+ end
121
+
122
+ def get_width
123
+ # FIXME: I don't know how portable it is.
124
+ default_width = 80
125
+ begin
126
+ tiocgwinsz = 0x5413
127
+ data = [0, 0, 0, 0].pack("SSSS")
128
+ if @out.ioctl(tiocgwinsz, data) >= 0 then
129
+ rows, cols, xpixels, ypixels = data.unpack("SSSS")
130
+ if cols >= 0 then cols else default_width end
131
+ else
132
+ default_width
133
+ end
134
+ rescue Exception
135
+ default_width
136
+ end
137
+ end
138
+
139
+ def show
140
+ arguments = @format_arguments.map {|method|
141
+ method = sprintf("fmt_%s", method)
142
+ send(method)
143
+ }
144
+ line = sprintf(@format, *arguments)
145
+
146
+ width = get_width
147
+ if line.length == width - 1
148
+ @out.print(line + eol)
149
+ @out.flush
150
+ elsif line.length >= width
151
+ @terminal_width = [@terminal_width - (line.length - width + 1), 0].max
152
+ if @terminal_width == 0 then @out.print(line + eol) else show end
153
+ else # line.length < width - 1
154
+ @terminal_width += width - line.length + 1
155
+ show
156
+ end
157
+ @previous_time = Time.now
158
+ end
159
+
160
+ def show_if_needed
161
+ if @total.zero?
162
+ cur_percentage = 100
163
+ prev_percentage = 0
164
+ else
165
+ cur_percentage = (@current * 100 / @total).to_i
166
+ prev_percentage = (@previous * 100 / @total).to_i
167
+ end
168
+
169
+ # Use "!=" instead of ">" to support negative changes
170
+ if cur_percentage != prev_percentage ||
171
+ Time.now - @previous_time >= 1 || @finished_p
172
+ show
173
+ end
174
+ end
175
+
176
+ public
177
+ def clear
178
+ @out.print "\r"
179
+ @out.print(" " * (get_width - 1))
180
+ @out.print "\r"
181
+ end
182
+
183
+ def finish
184
+ @current = @total
185
+ @finished_p = true
186
+ show
187
+ end
188
+
189
+ def finished?
190
+ @finished_p
191
+ end
192
+
193
+ def file_transfer_mode
194
+ @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
195
+ end
196
+
197
+ def format= (format)
198
+ @format = format
199
+ end
200
+
201
+ def format_arguments= (arguments)
202
+ @format_arguments = arguments
203
+ end
204
+
205
+ def halt
206
+ @finished_p = true
207
+ show
208
+ end
209
+
210
+ def inc (step = 1)
211
+ @current += step
212
+ @current = @total if @current > @total
213
+ show_if_needed
214
+ @previous = @current
215
+ end
216
+
217
+ def set (count)
218
+ if count < 0 || count > @total
219
+ raise "invalid count: #{count} (total: #{@total})"
220
+ end
221
+ @current = count
222
+ show_if_needed
223
+ @previous = @current
224
+ end
225
+
226
+ def inspect
227
+ "#<ProgressBar:#{@current}/#{@total}>"
228
+ end
229
+ end
230
+
231
+ class ReversedProgressBar < ProgressBar
232
+ def do_percentage
233
+ 100 - super
234
+ end
235
+ end
236
+
@@ -0,0 +1,12 @@
1
+ require_relative 'parser'
2
+ require_relative 'utils'
3
+ require_relative 'encoder'
4
+
5
+ module OggEncode
6
+ class Runner
7
+ def self.run(argv)
8
+ options = Parser.parse( argv )
9
+ OggEncoder.encode( options )
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module OggEncode
2
+ class Flac < File
3
+ def self.exists?( path )
4
+ file?( path ) and basename( path ) =~ /\.flac$/
5
+ end
6
+ end
7
+
8
+ class Ogg < File
9
+ def self.exists?( path )
10
+ file?( path ) and basename( path ) =~ /\.ogg$/
11
+ end
12
+ end
13
+
14
+ class SizedPsHash < Hash
15
+
16
+ def initialize( max )
17
+ @max = max
18
+ super
19
+ end
20
+
21
+ def store( pid, path, &block )
22
+ while size >= @max
23
+ pid = Process.wait
24
+ delete( pid )
25
+ end
26
+ ps = block.call
27
+ super( ps.pid, path )
28
+ end
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autogg
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.0
6
+ platform: ruby
7
+ authors:
8
+ - Evan Simmons
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-26 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: |
17
+ Encodes all flac files in a given directory to ogg in another given directory while preserving the directory structure. Also if rb-inotify is installed and -w flag is passed, it will watch for changes on the filesystem and rescan the directory, encoding the new files.
18
+
19
+ email: esims89@gmail.com
20
+ executables:
21
+ - autogg
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - autogg.gemspec
28
+ - LICENCE
29
+ - autogg-0.2.0.gem
30
+ - bin/autogg
31
+ - README
32
+ - lib/autogg/progressbar.rb
33
+ - lib/autogg/runner.rb
34
+ - lib/autogg/parser.rb
35
+ - lib/autogg/encoder.rb
36
+ - lib/autogg/utils.rb
37
+ homepage: https://github.com/estk/autogg
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "1.9"
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ requirements:
58
+ - oggenc must be installed on the base system
59
+ rubyforge_project:
60
+ rubygems_version: 1.7.2
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: converts a folder of flacs to ogg, preserving directory structure
64
+ test_files: []
65
+