X-Git-Url: http://club.cc.cmu.edu/~cmccabe/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=superrip.rb;h=cc413db54e924d753286f72d72c2f330dc6ae56d;hb=235c8f2e5692d8c89145085057609de827dc0aee;hp=3826483042d060120025b38310450ae49c33b6be;hpb=b046723cf8f054d29927c9fe421d0cbaaaed44c8;p=cmccabe-bin diff --git a/superrip.rb b/superrip.rb index 3826483..cc413db 100755 --- a/superrip.rb +++ b/superrip.rb @@ -16,14 +16,14 @@ require 'ostruct' #----------------------------------------------------------------- # constants #----------------------------------------------------------------- -$cd_dev = "/dev/cdrom" +$children = Hash.new #----------------------------------------------------------------- # functions #----------------------------------------------------------------- def my_system(cmd) puts cmd - system(cmd) unless $opts.dry_run + system(cmd) unless $opts.dry_run == true ($?.exitstatus == 0) or raise "#{cmd} failed" end @@ -34,36 +34,69 @@ end def get_number_of_tracks_on_cd look_for_tracks = false - IO.popen("cdda2wav -v summary -J dev=#{$cd_dev} 2>&1", "r") do |io| + lines = Array.new + IO.popen("cdda2wav -v summary -J dev=#{$opts.cd_dev} 2>&1", "r") do |io| io.readlines.each do |line| line.chomp! + lines << line if (line =~ /^AUDIOtrack/) then look_for_tracks = true elsif (look_for_tracks == true) then look_for_tracks = false - line =~ /[ \t]*1-([1234567890][1234567890]*)[^1234567890]/ \ - or raise "couldn't understand cdda2wav output!" + line =~ /[ \t]*1-([ 1234567890][1234567890]*)[^1234567890]/ \ + or raise "couldn't understand cdda2wav output! (line:#{line})" return $1.to_i end end end - raise "couldn't find what we were looking for in cdda2wav output!" + raise "couldn't find what we were looking for in cdda2wav output! \ +output:#{lines.join('\n')}" end -def audiorip(track, number) +# Process the WAV file into an MP3 and FLAC file. +# This is done in a background process. +def process_wav(track) + FileUtils.mkdir_p(track.flac_dir, $fu_args) + my_system("flac -f '#{track.wav_file_name}' \ +--output-name='#{track.flac_file_name}' &>/dev/null") + my_system("flac --test '#{track.flac_file_name}' &>/dev/null") + FileUtils.mkdir_p(track.mp3_dir, $fu_args) + my_system("lame -q 1 -b 192 '#{track.wav_file_name}' \ +'#{track.mp3_file_name}' &>/dev/null") + FileUtils.rm_f(track.wav_file_name, $fu_args) +end + +def audiorip(tnum, track) begin - my_system("nice -1 cdparanoia -w -d #{$cd_dev} #{number}") + my_system("nice -1 cdparanoia -w -d #{$opts.cd_dev} #{tnum}") rescue - raise "failed to rip track #{number} (#{track.name})" + raise "failed to rip track #{tnum} (#{track.name})" end # cdparanoia always outputs to cdda.wav FileUtils.mv("cdda.wav", track.wav_file_name, $fu_args) - # TODO: spawn a thread to do this stuff in the background - FileUtils.mkdir_p(track.flac_dir, $fu_args) - my_system("flac -c #{track.wav_file_name} > #{track.flac_file_name}") - my_system("lame -q 1 -b 192 #{track.wav_file_name} > #{track.mp3_file_name}") - FileUtils.rm_f(track.wav_file, $fu_args) + # If there are too many processes, wait for one of them to terminate + if ($children.keys.length > $opts.max_children) then + pid, status = Process.wait2(-1) + if (status.exitstatus != 0) then + raise "process #{pid} failed with exitstatus #{status.exitstatus}" + end + $children.delete(pid) + end + + pid = Process.fork + if (pid == nil) then + retcode = 0 + begin + process_wav(track) + rescue Exception => e + puts "*** FATAL ERROR: #{e}" + retcode = 1 + end + Kernel.exit(retcode) + else + $children[pid] = 1 + end end #----------------------------------------------------------------- @@ -73,12 +106,18 @@ class MyOptions def self.parse(args) opts = OpenStruct.new opts.dry_run = false + opts.max_children = 4 + opts.cd_dev = "/dev/cdrom" $fu_args = { :verbose => true } # Fill in opts values parser = OptionParser.new do |myparser| myparser.banner = "Usage: #{ File.basename($0) } [opts]" myparser.separator("Specific options:") + myparser.on("--dev [DEV]", "-D", + "choose the cdrom device file to use") do |dev| + opts.cd_dev = dev + end myparser.on("--dry-run", "-d", "Show what would be done, without doing it.") do |a| opts.dry_run = true @@ -94,6 +133,14 @@ class MyOptions opts.manifest_file = file opts.partial = true end + myparser.on("--max-children [NCHILD]", "-j", + "The maximum number of child processes to allow at any \ +given time") do |nchild| + opts.max_children = nchild.to_i + if (opts.max_children < 1) then + raise "can't set max_children to #{opts.max_children}" + end + end end parser.parse!(args) @@ -103,7 +150,8 @@ class MyOptions end class Track - attr_accessor :name, :flac_dir, :flac_file_name, :mp3_dir, :mp3_file_name + attr_accessor :name, :flac_dir, :flac_file_name, :mp3_dir, :mp3_file_name, + :wav_file_name def initialize(name) if name =~ /\[LL\]/ then raise "you can't include [LL] in a track name" @@ -117,15 +165,15 @@ class Track (name =~ /([^\/][^\/]*)\/([^\/]*[^\/])/) or \ raise "track name must be of the form 'foo/bar'" @name = name - @flac_dir = "#{1} [LL]" - @flac_file_name = "#{@flac_dir}/#{2}.flac" - @mp3_dir = "#{1}" - @mp3_file_name = "#{@mp3_dir}/#{2}.mp3" - @wav_file_name = "#{1}__#{2}.wav" + @flac_dir = "#{$1} [LL]" + @flac_file_name = "#{@flac_dir}/#{$2}.flac" + @mp3_dir = "#{$1}" + @mp3_file_name = "#{@mp3_dir}/#{$2}.mp3" + @wav_file_name = "#{$1}__#{$2}.wav" end def inspect - "#{@name}" + "track(\"#{@name}\")" end end @@ -145,11 +193,16 @@ class Manifest if (@t.empty?) then raise "you must define some tracks" end - @t.each { |t| t.validate } - if (not $opts.partial) then - (1..num_tracks).each do |t| - if not @t[t].defined? - raise "don't know what to do with track #{t}" + if ($opts.partial) then + highest_track = @t.keys.sort[-1] + if (num_tracks < highest_track) then + raise "can't rip track #{highest_track}, because there are \ +only #{num_tracks} tracks" + end + else + (1..num_tracks).each do |tnum| + if not @t.has_key?(tnum) + raise "don't know what to do with track #{tnum}" end end end @@ -158,9 +211,15 @@ class Manifest end def rip(num_tracks) - (1..num_tracks).each do |t| - next unless @t.defined?(t) - audiorip(t) + (1..num_tracks).each do |tnum| + next unless @t.has_key?(tnum) + audiorip(tnum, @t[tnum]) + end + prc = Process.waitall + prc.each do |pair| + if (pair[1].exitstatus != 0) then + raise "process #{pair[0]} failed with exitstatus #{pair[1].exitstatus}" + end end end @@ -192,8 +251,10 @@ die_unless_installed("cdparanoia") die_unless_installed("cdda2wav") manifest = Manifest.new($opts.manifest_file) -#puts manifest.inspect +puts manifest.inspect num_tracks = get_number_of_tracks_on_cd() puts "found #{num_tracks} tracks" -#manifest.rip(num_tracks) +manifest.validate(num_tracks) +manifest.rip(num_tracks) +puts "*** FINISHED ***" exit 0