def undo_rename(status, todo): ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension'] "undo renaming (operation mode)" maxnames = max(map(lambda x: len(x['names']), status.values())) if len(jack_progress.status_all['names']) >= maxnames: dir_too = 1 else: dir_too = 0 maxnames = max(maxnames, len(jack_progress.status_all['names'])) if maxnames > 1: # undo dir renaming cwd = os.getcwd() if jack_freedb.dir_created and jack_utils.check_path(jack_freedb.dir_created, cwd) and dir_too: new_name, old_name = jack_progress.status_all['names'][-2:] jack_utils.rename_path(old_name, new_name) # this changes cwd! info("cwd now " + os.getcwd()) jack_functions.progress("all", "undo", "dir") else: maxnames = max(map(lambda x: len(x['names']), status.values())) # undo file renaming for i in todo: if maxnames < 2: break act_names = status[i[NUM]]['names'] if len(act_names) == maxnames: for j in (ext, '.wav'): new_name, old_name = act_names[-2:] new_name, old_name = new_name + j, old_name + j if not os.path.exists(old_name): if j == ext: print 'NOT renaming "' + old_name + '": it doesn\'t exist.' else: if os.path.exists(new_name): print 'NOT renaming "' + old_name + '" to "' + new_name + '" because dest. exists.' else: jack_functions.progress(i[NUM], "undo", "-") os.rename(old_name, new_name) else: info("nothing to do.")
def filter_tracks(toc_just_read, status): "filter out data tracks" global datatracks if toc_just_read and jack_helpers.helpers[cf['_ripper']].has_key("toc_cmd") and cf['_ripper'] != cf['_toc_prog']: ripper_tracks = jack_functions.gettoc(cf['_ripper']) if ripper_tracks != jack_ripstuff.all_tracks: for i in range(len(jack_ripstuff.all_tracks)): rtn = jack_utils.has_track(ripper_tracks, jack_ripstuff.all_tracks[i][NUM]) if rtn >= 0: for j in range(6): # "NUM LEN START COPY PRE CH" (not: "RIP RATE NAME") if ripper_tracks[rtn][j] != jack_ripstuff.all_tracks[i][j]: jack_functions.progress(i + 1, "patch", "%s %d -> %d" % (fields[j], jack_ripstuff.all_tracks[i][j], ripper_tracks[rtn][j])) jack_ripstuff.all_tracks[i][j] = ripper_tracks[rtn][j] debug("Track %02d %s" % (i + 1, fields[j]) + `jack_ripstuff.all_tracks[i][j]` + " != " + `ripper_tracks[rtn][j]` + " (trusting %s; to the right)" % cf['_ripper']) else: jack_functions.progress(i + 1, "off", "non-audio") datatracks.append(i + 1) info("Track %02d not found by %s. Treated as non-audio." % (i + 1, cf['_ripper'])) if not toc_just_read: datatracks += [x for x in status.keys() if status[x]["off"] and status[x]["off"] == ["non-audio"]]
def update_progress(status, todo): ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension'] "update progress file at user's request (operation mode)" if cf['_upd_progress']: # users may still have a valid jack.freedb file lying around if not jack_freedb.names_available: err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, todo, cf['_freedb_form_file'], verb = 0, dirs = 1) for i in todo: num = i[NUM] if not status[num]['dae']: filename = jack_functions.check_file(num, i, ".wav") if filename: status[num]['dae'] = " * [ simulated ]" jack_functions.progress(num, "dae", status[num]['dae']) if not status[num]['enc']: filename = jack_functions.check_file(num, i, ext) if filename: if ext.upper() == ".MP3": x = jack_mp3.mp3format(filename + ext) temp_rate = x['bitrate'] elif ext.upper() == ".OGG" and ogg: x = ogg.vorbis.VorbisFile(filename + ext) temp_rate = int(x.raw_total(0) * 8 / x.time_total(0) / 1000 + 0.5) elif ext.upper() == ".FLAC" and flac: f = flac.FLAC(filename + ext) size = os.path.getsize(filename + ext) if f.info and size: temp_rate = int(size * 8 * f.info.sample_rate / f.info.total_samples / 1000) else: temp_rate = 0 else: error("don't know how to handle %s files." % ext) status[num]['enc'] = `temp_rate` + cf['_progr_sep'] + "[simulated]" jack_functions.progress(num, "enc", status[num]['enc'])
def find_workdir(): "search for a dir containing a toc-file or do the multi-mode" tries = 0 toc_just_read = 0 debug("multi_mode:" + `cf['_multi_mode']`) while (not os.path.exists(cf['_toc_file'])) or cf['_multi_mode']: tries = tries + 1 if tries > 2: break if cf['_guess_mp3s']: jack_ripstuff.all_tracks = jack_functions.guesstoc(cf['_guess_mp3s']) else: if cf['_multi_mode']: debug("multimode all_tracks reset") jack_ripstuff.all_tracks = [] else: if cf['_image_toc_file']: # put the absolute path in the variable since we'll change cwd soon cf['_image_toc_file'] = os.path.abspath(cf['_image_toc_file']) jack_ripstuff.all_tracks, dummy, dummy = jack_functions.cdrdao_gettoc(cf['_image_toc_file']) else: if cf['_image_file']: warning("No TOC file for image '%s' specified, reading TOC from CD device." % cf['_image_file']) cf['_image_file'] = os.path.abspath(cf['_image_file']) jack_ripstuff.all_tracks = jack_functions.gettoc(cf['_toc_prog']) toc_just_read = 1 if cf['_scan_dirs']: dirs = [os.getcwd()] # Also scan base_dir since it's not guaranteed that users # run jack in base_dir if cf['_base_dir']: cf['_base_dir'] = expand(cf['_base_dir']) if os.path.exists(cf['_base_dir']) and cf['_base_dir'] not in dirs: dirs.append(cf['_base_dir']) else: dirs = cf['_searchdirs'] while cf['_scan_dirs'] > 0: cf['_scan_dirs'] = cf['_scan_dirs'] - 1 new_dirs = [] for i in dirs: if not i in new_dirs: new_dirs.append(i) try: subdir = os.listdir(i) except OSError, msg: print "skipped %s, %s" % (i, msg) continue for j in subdir: dir = os.path.join(i,j) if os.path.isdir(dir) and not dir in new_dirs: new_dirs.append(dir) dirs = new_dirs possible_dirs = [] # dirs matching inserted CD jack_dirs = [] # dirs containing toc_file for i in dirs: if os.path.exists(os.path.join(i, cf['_toc_file'])): jack_dirs.append(i) file_toc, dummy, dummy = jack_functions.cdrdao_gettoc(os.path.join(i, cf['_toc_file'])) if jack_freedb.freedb_id(jack_ripstuff.all_tracks) == jack_freedb.freedb_id(file_toc): possible_dirs.append(i) if cf['_multi_mode']: unique_dirs = [] for i in range(len(jack_dirs)): found = 0 for j in range(i + 1,len(jack_dirs)): if os.path.samefile(jack_dirs[i], jack_dirs[j]): found = 1 if not found: unique_dirs.append(jack_dirs[i]) for i in unique_dirs: jack_ripstuff.all_tracks, dummy, track1_offset = jack_functions.cdrdao_gettoc(os.path.join(i, cf['_toc_file'])) err, jack_tag.track_names, jack_tag.locale_names, cd_id, revision = freedb_names(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, jack_ripstuff.all_tracks, os.path.join(i, cf['_freedb_form_file']), verb = 0, warn = 0) if err or cf['_force']:# this means freedb data is not there yet info("matching dir found: %d" % i) pid = os.fork() if pid == CHILD: os.chdir(i) ch_args = sys.argv for killarg in ('--force', '--multi-mode'): if killarg in ch_args: ch_args.remove(killarg) info("running" + `ch_args`) os.execvp(ch_args[0], ch_args) else: respid, res = os.waitpid(pid, 0) sys.exit() unique_dirs = [] for i in range(len(possible_dirs)): found = 0 for j in range(i + 1,len(possible_dirs)): if os.path.samefile(possible_dirs[i], possible_dirs[j]): found = 1 if not found: unique_dirs.append(possible_dirs[i]) info("matching dir found: " + possible_dirs[i]) if len(unique_dirs) > 1: error("found more than one workdir, change to the correct one.") elif len(unique_dirs) == 1: os.chdir(unique_dirs[0]) else: if cf['_create_dirs']: cf['_base_dir'] = expand(cf['_base_dir']) if not os.path.exists(cf['_base_dir']): os.makedirs(cf['_base_dir']) os.chdir(cf['_base_dir']) dir_name = jack_version.prog_name + "-" + jack_freedb.freedb_id(jack_ripstuff.all_tracks, warn=0) if not os.path.exists(dir_name) and not os.path.isdir(dir_name): os.mkdir(dir_name) os.chdir(dir_name) jack_freedb.dir_created = dir_name jack_functions.progress("all", "mkdir", jack_freedb.dir_created) if not cf['_multi_mode']: if not os.path.exists(cf['_toc_file']): jack_functions.cdrdao_puttoc(cf['_toc_file'], jack_ripstuff.all_tracks, jack_freedb.freedb_id(jack_ripstuff.all_tracks)) jack_freedb.freedb_template(jack_ripstuff.all_tracks) # generate freedb form if tocfile is created if not os.path.exists(cf['_freedb_form_file']): jack_freedb.freedb_template(jack_ripstuff.all_tracks) else: break
def interpret_db_file(all_tracks, todo, freedb_form_file, verb, dirs = 0, warn = None): "read freedb file and rename dir(s)" global names_available, dir_created freedb_rename = 0 if warn == None: err, track_names, locale_names, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, todo, freedb_form_file, verb = verb) else: err, track_names, locale_names, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, todo, freedb_form_file, verb = verb, warn = warn) if (not err) and dirs: freedb_rename = 1 # The user wants us to use the current dir, unconditionally. if cf['_claim_dir']: dir_created = jack_utils.split_dirname(os.getcwd())[-1] jack_functions.progress("all", "mkdir", dir_created) cf['_claim_dir'] = 0 if cf['_rename_dir'] and dir_created: new_dirs, new_dir = jack_utils.mkdirname(track_names, cf['_dir_template']) old_dir = os.getcwd() old_dirs = jack_utils.split_dirname(old_dir) dirs_created = jack_utils.split_dirname(dir_created) # only do the following if we are where we think we are and the dir has to be # renamed. if jack_utils.check_path(dirs_created, old_dirs) and not jack_utils.check_path(dirs_created, new_dirs): jack_utils.rename_path(dirs_created, new_dirs) print "Info: cwd now", os.getcwd() jack_functions.progress("all", 'ren', unicode(dir_created + "-->" + new_dir, cf['_charset'], "replace")) if not err: cd = track_names[0] year = genretxt = None if len(cd) > 2: year = `cd[2]` if len(cd) > 3: genretxt = id3genres[cd[3]] filenames.append('') # FIXME: possibly put the dir here, but in no # case remove this since people access filenames with i[NUM] which starts at 1 num = 1 for i in track_names[1:]: replacelist = {"n": cf['_rename_num'] % num, "l": cd[1], "t": i[1], "y": year, "g": genretxt} if cf['_various']: replacelist["a"] = i[0] newname = jack_misc.multi_replace(cf['_rename_fmt_va'], replacelist, "rename_fmt_va", warn = (num == 1)) else: replacelist["a"] = cd[0] newname = jack_misc.multi_replace(cf['_rename_fmt'], replacelist, "rename_fmt", warn = (num == 1)) exec("newname = newname" + cf['_char_filter']) for char_i in range(len(cf['_unusable_chars'])): try: a = unicode(cf['_unusable_chars'][char_i], locale.getpreferredencoding(), "replace") b = unicode(cf['_replacement_chars'][char_i], locale.getpreferredencoding(), "replace") except UnicodeDecodeError: warning("Cannot substitute unusable character %d." % (char_i+1)) else: newname = string.replace(newname, a, b) filenames.append(newname) num += 1 names_available = 1 else: freedb_rename = 0 return err, track_names, locale_names, freedb_rename, revision
def freedb_query(cd_id, tracks, file): if cf['_freedb_dir']: if local_freedb(cd_id, cf['_freedb_dir'], file)==0: # use local database (if any) return 0 qs = "cmd=cddb query " + cd_id + " " + `len(tracks)` + " " # query string for i in tracks: qs = qs + `i[START] + MSF_OFFSET` + " " qs = qs + `(MSF_OFFSET + tracks[-1][START] + tracks[-1][LEN]) / CDDA_BLOCKS_PER_SECOND` hello = "hello=" + cf['_username'] + " " + cf['_hostname'] + " " + freedb_servers[cf['_freedb_server']]['id'] qs = urllib.quote_plus(qs + "&" + hello + "&proto=6", "=&") url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + qs if cf['_cont_failed_query']: try: f = urllib2.urlopen(url) except IOError: traceback.print_exc() err = 1 return err else: f = urllib2.urlopen(url) buf = f.readline() if buf and buf[0:1] == "2": if buf[0:3] in ("210", "211"): # Found inexact or multiple exact matches, list follows if buf[0:3] == "211": global freedb_inexact_match freedb_inexact_match = 1 print "Found the following matches. Choose one:" num = 1 matches = [] while 1: buf = f.readline() try: buf = unicode(buf, "utf-8") except UnicodeDecodeError: buf = unicode(buf, "latin-1") if not buf: break buf = string.rstrip(buf) if buf != ".": print "%2i" % num + ".) " + buf.encode(locale.getpreferredencoding(), "replace") matches.append(buf) num = num + 1 x = -1 while x < 0 or x > num - 1: input = raw_input(" 0.) none of the above: ") if not input: continue try: x = int(input) except ValueError: x = -1 # start the loop again if not x: print "ok, aborting." sys.exit() buf = matches[x-1] buf = string.split(buf, " ", 2) freedb_cat = buf[0] cd_id = buf[1] err = 0 elif buf[0:3] == "200": buf = string.split(buf) freedb_cat = buf[1] elif buf[0:3] == "202": if cf['_cont_failed_query']: warning(buf + f.read() + " How about trying another --server?") err = 1 return err else: error(buf + f.read() + " How about trying another --server?") else: if cf['_cont_failed_query']: warning(buf + f.read() + " --don't know what to do, aborting query.") err = 1 return err else: error(buf + f.read() + " --don't know what to do, aborting query.") cmd = "cmd=cddb read " + freedb_cat + " " + cd_id url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + urllib.quote_plus(cmd + "&" + hello + "&proto=6", "=&") f = urllib2.urlopen(url) buf = f.readline() if buf and buf[0:3] == "210": # entry follows if os.path.exists(file): os.rename(file, file + ".bak") of = open(file, "w") buf = f.readline() while buf: buf = string.rstrip(buf) if buf != ".": of.write(buf + "\n") buf = f.readline() of.close() jack_functions.progress("all", "freedb_cat", freedb_cat) jack_progress.status_all['freedb_cat'] = freedb_cat err = 0 else: print string.rstrip(buf) print f.read() warning("could not query freedb entry") err = 1 f.close() else: print string.rstrip(buf) print f.read() warning("could not check freedb category") err = 2 f.close() return err
def main_loop(mp3s_todo, wavs_todo, space, dae_queue, enc_queue, track1_offset): global_error = 0 # remember if something went wrong actual_load = -2 # this is always smaller than max_load waiting_load = 0 # are we waiting for the load to drop? waiting_space = 0 # are we waiting for disk space to be freed? space_waiting = 0 # how much space _running_ subprocesses will consume space_adjust = 0 # by how much space has been modified blocked = 0 # we _try_ do detect deadlocks cycles = 0 # it's sort of a timer last_update = 0 # screen updates are done once per second pause = 0 # no new encoders are started if pause==1 flags = "[ ]" # runtime controllable flags enc_running = 0 # what is going on? dae_running = 0 # what is going on? rotate = "/-\\|" rotate_ball = " .o0O0o." rot_cycle = len(rotate) rot_ball_cycle = len(rotate_ball) rot_count = 0 global_done = 0 first_encoder = 1 ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']] ['target']]['file_extension'] global_blocks = jack_functions.tracksize( wavs_todo)[BLOCKS] + jack_functions.tracksize(mp3s_todo)[BLOCKS] ##################### ### MAIN LOOP ### ##################### global_start = time.time() while mp3s_todo or enc_queue or dae_queue or enc_running or dae_running: orig_space = space # feed in the WAVs which have been there from the start if mp3s_todo and jack_functions.tracksize(mp3s_todo[0])[ENC] < space: waiting_space = 0 enc_queue.append(mp3s_todo[0]) space = space - jack_functions.tracksize(mp3s_todo[0])[ENC] jack_status.enc_stat_upd(mp3s_todo[0][NUM], "waiting for encoder.") mp3s_todo = mp3s_todo[1:] # start new DAE subprocess elif (len(enc_queue) + enc_running) < ( cf['_read_ahead'] + cf['_encoders'] ) and dae_queue and dae_running < cf['_rippers'] and ( (jack_functions.tracksize(dae_queue[0])[BOTH] < space) or (cf['_only_dae'] and jack_functions.tracksize(dae_queue[0])[WAV] < space) or (cf['_otf'] and jack_functions.tracksize(dae_queue[0])[ENC] < space)): waiting_space = 0 this_is_ok = 1 if pause: this_is_ok = 0 jack_status.dae_stat_upd(dae_queue[0][NUM], "Paused. Press 'c' to continue.") elif cf['_rip_from_device']: all_tracks_on_cd = jack_functions.gettoc(cf['_toc_prog']) if not jack_utils.cmp_toc_cd(jack_ripstuff.all_tracks_orig, all_tracks_on_cd, what=(NUM, LEN)): while dae_queue: track = dae_queue[0] dae_queue = dae_queue[1:] jack_status.dae_stat_upd( track[NUM], "Wrong disc - aborting this track") global_error = global_error + 1 this_is_ok = 0 if this_is_ok: if cf['_only_dae']: space_waiting = space_waiting + jack_functions.tracksize( dae_queue[0])[WAV] space = space - jack_functions.tracksize(dae_queue[0])[WAV] elif cf['_otf']: space_waiting = space_waiting + jack_functions.tracksize( dae_queue[0])[ENC] space = space - jack_functions.tracksize(dae_queue[0])[ENC] else: space_waiting = space_waiting + jack_functions.tracksize( dae_queue[0])[BOTH] space = space - jack_functions.tracksize( dae_queue[0])[BOTH] dae_running = dae_running + 1 track = dae_queue[0] dae_queue = dae_queue[1:] if cf['_otf']: # note: image_reader can't do otf at the moment. jack_status.dae_stat_upd( track[NUM], ":DAE: waiting for status report...") if cf['_encoder'] in ("lame", "gogo", "flac", "mppenc"): jack_status.enc_stat_upd( track[NUM], "[no otf status for %s]" % cf['_encoder']) else: jack_status.enc_stat_upd(track[NUM], "waiting for encoder.") enc_running = enc_running + 1 if first_encoder: first_encoder = 0 global_start = time.time() data = jack_workers.start_new_otf(track, cf['_ripper'], cf['_encoder']) jack_children.children.append(data['rip']) jack_children.children.append(data['enc']) else: if jack_status.enc_status[track[NUM]]: jack_status.enc_cache[ track[NUM]] = jack_status.enc_status[track[NUM]] jack_status.enc_stat_upd(track[NUM], "[...]") jack_status.dae_stat_upd( track[NUM], ":DAE: waiting for status report...") if cf['_rip_from_device']: jack_children.children.append( jack_workers.start_new_ripper( track, cf['_ripper'])) elif cf['_image_file']: jack_children.children.append( jack_workers.ripread(track, track1_offset)) else: jack_status.dae_stat_upd( track[NUM], ":?AE: don't know how to rip this!") # start new encoder subprocess if enc_queue and enc_running < cf['_encoders']: if jack_functions.tracksize( enc_queue[0])[ENC] <= space + space_waiting: waiting_space = 0 actual_load = jack_misc.loadavg() if actual_load < cf['_max_load']: waiting_load = 0 enc_running = enc_running + 1 track = enc_queue[0] enc_queue = enc_queue[1:] jack_status.enc_stat_upd(track[NUM], "waiting for encoder...") jack_children.children.append( jack_workers.start_new_encoder(track, cf['_encoder'])) if first_encoder: first_encoder = 0 global_start = time.time() else: waiting_load = 1 # check for subprocess output readfd = [sys.stdin.fileno()] for i in jack_children.children: readfd.append(i['fd']) try: rfd, wfd, xfd = select.select(readfd, [], [], cf['_update_interval']) except: rfd, wfd, xfd = [], [], [] jack_term.tmod.sig_winch_handler(None, None) # check for keyboard commands if sys.stdin.fileno() in rfd: last_update = last_update - cf['_update_interval'] cmd = jack_term.tmod.getkey() sys.stdin.flush() if string.upper(cmd) == "Q": jack_display.exit() elif not pause and string.upper(cmd) == "P": pause = 1 flags = flags[:1] + "P" + flags[2:] elif string.upper( cmd) == "C" or pause and string.upper(cmd) == "P": pause = 0 flags = flags[:1] + " " + flags[2:] elif not flags[3] == "e" and string.upper(cmd) == "E": for i in jack_children.children: if i['type'] == "encoder": os.kill(i['pid'], signal.SIGSTOP) flags = flags[:3] + "e" + flags[4:] elif flags[3] == "e" and string.upper(cmd) == "E": for i in jack_children.children: if i['type'] == "encoder": os.kill(i['pid'], signal.SIGCONT) flags = flags[:3] + " " + flags[4:] elif not flags[2] == "r" and string.upper(cmd) == "R": for i in jack_children.children: if i['type'] == "ripper": os.kill(i['pid'], signal.SIGSTOP) flags = flags[:2] + "r" + flags[3:] elif flags[2] == "r" and string.upper(cmd) == "R": for i in jack_children.children: if i['type'] == "ripper": os.kill(i['pid'], signal.SIGCONT) flags = flags[:2] + " " + flags[3:] elif string.upper(cmd) == "U": cycles = 29 # do periodic stuff _now_ else: jack_term.tmod.move_pad(cmd) if cmd == 'KEY_RESIZE': continue last_update = time.time() # read from file with activity for i in jack_children.children: if i['fd'] in rfd: if os.uname()[0] == "Linux" and i['type'] != "image_reader": try: x = i['file'].read() except (IOError, ValueError): pass else: read_chars = 0 x = "" while read_chars < jack_helpers.helpers[ i['prog']]['status_blocksize']: try: xchar = i['file'].read(1) except (IOError, ValueError): break x = x + xchar read_chars = read_chars + 1 try: rfd2, wfd2, xfd2 = select.select([i['fd']], [], [], 0.0) except: rfd2, wfd2, xfd2 = [], [], [] jack_term.tmod.sig_winch_handler(None, None) if i['fd'] not in rfd2: break # put read data into child's buffer i['buf'] = i['buf'] + x if jack_helpers.helpers[i['prog']].has_key('filters'): for fil in jack_helpers.helpers[i['prog']]['filters']: i['buf'] = fil[0].sub(fil[1], i['buf']) i['buf'] = i['buf'][-jack_helpers. helpers[i['prog']]['status_blocksize']:] # check for exiting child processes if jack_children.children: respid, res = os.waitpid(-1, os.WNOHANG) if respid != 0: last_update = last_update - cf[ '_update_interval'] # ensure info is printed new_ch = [] exited_proc = [] for i in jack_children.children: if i['pid'] == respid: if exited_proc != []: error("pid " + ` respid ` + " found at multiple child processes") exited_proc = i else: new_ch.append(i) if not exited_proc: error("unknown process (" + ` respid ` + ") has exited") jack_children.children = new_ch x = "" try: x = exited_proc['file'].read() except (IOError, ValueError): pass exited_proc['buf'] = ( exited_proc['buf'] + x)[-jack_helpers. helpers[exited_proc['prog']]['status_blocksize']:] exited_proc['file'].close() global_error = global_error + res track = exited_proc['track'] num = track[NUM] stop_time = time.time() speed = (track[LEN] / float(CDDA_BLOCKS_PER_SECOND)) / ( stop_time - exited_proc['start_time']) if exited_proc['type'] in ("ripper", "image_reader"): dae_running = dae_running - 1 if cf['_exec_when_done'] and exited_proc[ 'type'] == "ripper" and dae_running == 0 and len( dae_queue) == 0: os.system(cf['_exec_rip_done']) if not res: if not exited_proc['otf']: if os.path.exists(track[NAME] + ".wav"): if jack_functions.tracksize( track)[WAV] != jack_utils.filesize( track[NAME] + ".wav"): res = 242 jack_status.dae_stat_upd( num, jack_status.get_2_line( exited_proc['buf'])) else: jack_status.dae_stat_upd( num, jack_status.get_2_line(exited_proc['buf'])) res = 243 global_error = global_error + res if res and not cf['_sloppy']: if os.path.exists(track[NAME] + ".wav"): os.remove(track[NAME] + ".wav") space = space + jack_functions.tracksize( track)[WAV] if cf['_otf']: os.kill(exited_proc['otf-pid'], signal.SIGTERM) if os.path.exists(track[NAME] + ext): os.remove(track[NAME] + ext) space = space + jack_functions.tracksize( track)[ENC] if not cf['_otf'] and not cf[ '_only_dae'] and track not in jack_encstuff.mp3s_ready: space = space + jack_functions.tracksize( track)[ENC] jack_status.dae_stat_upd( num, 'DAE failed with status ' + ` res ` + ", wav removed.") else: if exited_proc['type'] == "image_reader": jack_status.dae_stat_upd( num, jack_status.get_2_line(exited_proc['buf'])) else: if exited_proc['otf'] and jack_helpers.helpers[ exited_proc['prog']].has_key( 'otf-final_status_fkt'): exec(jack_helpers.helpers[exited_proc['prog']] ['otf-final_status_fkt']) in globals( ), locals() else: last_status = None # (only used in cdparanoia) exec(jack_helpers.helpers[exited_proc['prog']] ['final_status_fkt']) in globals( ), locals() jack_status.dae_stat_upd(num, final_status) if jack_status.enc_cache[num]: jack_status.enc_stat_upd( num, jack_status.enc_cache[num]) jack_status.enc_cache[num] = "" jack_functions.progress(num, "dae", jack_status.dae_status[num]) if not cf['_otf'] and not cf[ '_only_dae'] and track not in jack_encstuff.mp3s_ready: if waiting_space: mp3s_todo.append(track) space = space + jack_functions.tracksize( track)[ENC] else: jack_status.enc_stat_upd( num, 'waiting for encoder.') enc_queue.append(track) space_waiting = space_waiting - jack_functions.tracksize( track)[WAV] elif exited_proc['type'] == "encoder": enc_running = enc_running - 1 # completed vbr files shouldn't be to small, but this still # caused confusion so again, vbr is an exception: if not cf['_vbr'] and not res and jack_functions.tracksize( track)[ENC] * 0.99 > jack_utils.filesize( track[NAME] + ext): res = 242 global_error = global_error + res if res: global_blocks = global_blocks - exited_proc['track'][ LEN] global_start = global_start + exited_proc[ 'elapsed'] / (enc_running + 1) if global_start > time.time(): global_start = time.time() if os.path.exists(track[NAME] + ext): # mp3enc doesn't report errors when out of disk space... os.remove(track[NAME] + ext) space = space + jack_functions.tracksize(track)[ENC] jack_status.enc_stat_upd( num, 'coding failed, err#' + ` res `) else: global_done = global_done + exited_proc['track'][LEN] if cf['_vbr']: rate = int( (jack_utils.filesize(track[NAME] + ext) * 0.008) / (track[LEN] / 75.0)) else: rate = track[RATE] jack_status.enc_stat_upd( num, "[coding @" + '%s' % jack_functions.pprint_speed(speed) + "x done, %dkbit" % rate) jack_functions.progress(num, "enc", ` rate `, jack_status.enc_status[num]) if not cf['_otf'] and not cf['_keep_wavs']: os.remove(track[NAME] + ".wav") space = space + jack_functions.tracksize( track)[WAV] else: error("child process of unknown type (" + exited_proc['type'] + ") exited") if global_error: jack_display.smile = " :-[" space_adjust += orig_space - space if last_update + cf['_update_interval'] <= time.time(): last_update = time.time() # interpret subprocess output for i in jack_children.children: if i['type'] == "ripper": if len(i['buf']) == jack_helpers.helpers[ i['prog']]['status_blocksize']: if i['otf'] and jack_helpers.helpers[ i['prog']].has_key('otf-status_fkt'): exec(jack_helpers.helpers[i['prog']] ['otf-status_fkt']) in globals(), locals() else: exec(jack_helpers.helpers[i['prog']] ['status_fkt']) in globals(), locals() if new_status: try: jack_status.dae_stat_upd( i['track'][NUM], ":DAE: " + new_status) except: debug("error in dae_stat_upd") elif i['type'] == "encoder": if len(i['buf']) == jack_helpers.helpers[ i['prog']]['status_blocksize']: tmp_d = {'i': i.copy(), 'percent': 0} try: exec(jack_helpers.helpers[i['prog']] ['percent_fkt']) in globals(), tmp_d except: tmp_d['percent'] = 0 debug("error in percent_fkt of %s." % ` i `) i['percent'] = tmp_d['percent'] if i['percent'] > 0: i['elapsed'] = time.time() - i['start_time'] speed = ((i['track'][LEN] / float(CDDA_BLOCKS_PER_SECOND)) * (i['percent'] / 100)) / i['elapsed'] eta = (100 - i['percent']) * i['elapsed'] / i['percent'] eta_ms = "%02i:%02i" % (eta / 60, eta % 60) jack_status.enc_stat_upd( i['track'][NUM], '%2i%% done, ETA:%6s, %sx' % (i['percent'], eta_ms, jack_functions.pprint_speed(speed))) #jack_term.tmod.dae_stat_upd(i['track'][NUM], None, i['percent']) elif i['type'] == "image_reader": line = string.strip( jack_status.get_2_line(i['buf'], default="")) if line: jack_status.dae_stat_upd(i['track'][NUM], line) if line.startswith("Error"): global_error = global_error + 1 else: error("unknown subprocess type \"" + i['type'] + "\".") cycles = cycles + 1 if cycles % 30 == 0: if cf['_recheck_space'] and not cf['space_from_argv'][ 'history'][-1][0] == "argv": actual_space = jack_functions.df() if space_adjust: diff = actual_space - space if diff > space_adjust: space = space + space_adjust space_adjust = 0 waiting_space = 0 else: space = space + diff space_adjust = space_adjust - diff else: if actual_space < space: space_adjust = space - actual_space space = actual_space if space_adjust and enc_running == 0 and dae_running == 0: waiting_space = waiting_space + 1 if not waiting_space >= 2 and not waiting_load and enc_running == 0 and dae_running == 0: blocked = blocked + 1 else: blocked = 0 total_done = global_done for i in jack_children.children: total_done = total_done + (i['percent'] / 100) * i['track'][LEN] elapsed = time.time() - global_start if global_blocks > 0: percent = total_done / global_blocks else: percent = 0 if percent > 0 and elapsed > 40: eta = ((1 - percent) * elapsed / percent) eta_hms = " ETA=%i:%02i:%02i" % (eta / 3600, (eta % 3600) / 60, eta % 60) else: eta_hms = "" if string.strip(flags[1:-1]): print_flags = " " + flags else: print_flags = "" if dae_running: rot = rotate_ball[rot_count % rot_ball_cycle] else: rot = rotate[rot_count % rot_cycle] rot_count = rot_count + 1 # print status if blocked > 2: jack_display.special_line = " ...I feel blocked - quit with 'q' if you get bored... " if blocked > 5: space = jack_functions.df() - cf['_keep_free'] elif waiting_load and waiting_space >= 2: jack_display.special_line = " ...waiting for load (%.2f)" % actual_load + ") < %.2f" % cf[ '_max_load'] + " and for " + jack_functions.pprint_i( space_adjust, "%i %sBytes") + " to be freed... " elif waiting_space >= 2: jack_display.special_line = " ...waiting for " + jack_functions.pprint_i( space_adjust, "%i %sBytes") + " to be freed.... " elif waiting_load: jack_display.special_line = " ...waiting for load (%.2f) to drop below %.2f..." % ( actual_load, cf['_max_load']) else: jack_display.special_line = None jack_display.bottom_line = "(" + rot + ") " \ + "SPACE:" * (space_adjust != 0) \ + "space:" * (space_adjust == 0) \ + jack_functions.pprint_i(space, "%i%sB") \ + (" waiting_WAVs:%02i" % len(enc_queue)) \ + " DAE:" + `cf['_rippers'] - dae_running` + "+" + `dae_running` \ + " ENC:" + `cf['_encoders'] - enc_running` + "+" + `enc_running` \ + eta_hms \ + " errors: " + `global_error` \ + jack_display.smile + print_flags jack_term.tmod.update(jack_display.special_line, jack_display.bottom_line) return global_error
def tag(freedb_rename): global a_artist, a_title ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension'] if cf['_vbr'] and not cf['_only_dae']: total_length = 0 total_size = 0 for i in jack_ripstuff.all_tracks_todo_sorted: total_length = total_length + i[LEN] total_size = total_size + jack_utils.filesize(i[NAME] + ext) if cf['_set_id3tag'] and not jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['can_posttag']: cf['_set_id3tag'] = 0 # maybe export? if jack_freedb.names_available: a_artist = track_names[0][0] # unicode a_title = track_names[0][1] # unicode p_artist = locale_names[0][0] # string p_title = locale_names[0][1] # string if cf['_set_id3tag'] or freedb_rename: jack_m3u.init() # use freedb year and genre data if available if cf['_id3_year'] == -1 and len(track_names[0]) >= 3: cf['_id3_year'] = track_names[0][2] if cf['_id3_genre'] == -1 and len(track_names[0]) == 4: cf['_id3_genre'] = track_names[0][3] print "Tagging", for i in jack_ripstuff.all_tracks_todo_sorted: sys.stdout.write(".") ; sys.stdout.flush() mp3name = i[NAME] + ext wavname = i[NAME] + ".wav" if track_names[i[NUM]][0]: t_artist = track_names[i[NUM]][0] else: t_artist = a_artist t_name = track_names[i[NUM]][1] t_comm = "" if not cf['_only_dae'] and cf['_set_id3tag']: if len(t_name) > 30: if string.find(t_name, "(") != -1 and string.find(t_name, ")") != -1: # we only use the last comment t_comm = string.split(t_name, "(")[-1] if t_comm[-1] == ")": t_comm = t_comm[:-1] if t_comm[-1] == " ": t_comm = t_comm[:-1] t_name2 = string.replace(t_name, " (" + t_comm + ") ", "") t_name2 = string.replace(t_name2, " (" + t_comm + ")", "") t_name2 = string.replace(t_name2, "(" + t_comm + ") ", "") t_name2 = string.replace(t_name2, "(" + t_comm + ")", "") else: t_comm = "" if jack_helpers.helpers[cf['_encoder']]['target'] == "mp3": if cf['_write_id3v2']: _set_id3_tag( mp3name, eyed3.id3.ID3_V2_4, 'utf-8', a_title, t_name, (i[NUM],len(jack_ripstuff.all_tracks_orig)), t_artist, cf['_id3_genre'], cf['_id3_year'], None, int(i[LEN] * 1000.0 / 75 + 0.5) ) if cf['_write_id3v1']: # encoding ?? _set_id3_tag( mp3name, eyed3.id3.ID3_V1_1, 'latin1', a_title, t_name, (i[NUM],len(jack_ripstuff.all_tracks_orig)), t_artist, cf['_id3_genre'], cf['_id3_year'], t_comm, int(i[LEN] * 1000.0 / 75 + 0.5) ) elif jack_helpers.helpers[cf['_encoder']]['target'] == "flac": if flac: f = flac.FLAC(mp3name) if f.vc is None: f.add_vorbiscomment() f.vc['ALBUM'] = a_title f.vc['TRACKNUMBER'] = str(i[NUM]) f.vc['TITLE'] = t_name f.vc['ARTIST'] = t_artist if cf['_id3_genre'] != -1: f.vc['GENRE'] = id3genres[cf['_id3_genre']] if cf['_id3_year'] != -1: f.vc['DATE'] = str(cf['_id3_year']) f.save() else: print print "Please install python-mutagen package." print "Without it, you'll not be able to tag FLAC tracks." elif jack_helpers.helpers[cf['_encoder']]['target'] == "ogg": vf = ogg.vorbis.VorbisFile(mp3name) oggi = vf.comment() oggi.clear() oggi.add_tag('ALBUM', a_title.encode("utf-8")) oggi.add_tag('TRACKNUMBER', `i[NUM]`) oggi.add_tag('TITLE', t_name.encode("utf-8")) oggi.add_tag('ARTIST', t_artist.encode("utf-8")) if cf['_id3_genre'] != -1: oggi.add_tag('GENRE', id3genres[cf['_id3_genre']]) if cf['_id3_year'] != -1: oggi.add_tag('DATE', `cf['_id3_year']`) oggi.write_to(mp3name) if freedb_rename: newname = jack_freedb.filenames[i[NUM]] try: i[NAME] = unicode(i[NAME], "utf-8") except UnicodeDecodeError: i[NAME] = unicode(i[NAME], "latin-1") if i[NAME] != newname: p_newname = newname.encode(locale.getpreferredencoding(), "replace") u_newname = newname newname = newname.encode(cf['_charset'], "replace") p_mp3name = i[NAME].encode(locale.getpreferredencoding(), "replace") + ext p_wavname = i[NAME].encode(locale.getpreferredencoding(), "replace") + ".wav" ok = 1 if os.path.exists(newname + ext): ok = 0 print 'NOT renaming "' + p_mp3name + '" to "' + p_newname + ext + '" because dest. exists.' if cf['_keep_wavs']: print 'NOT renaming "' + p_wavname + '" to "' + p_newname + ".wav" + '" because dest. exists.' elif cf['_keep_wavs'] and os.path.exists(newname + ".wav"): ok = 0 print 'NOT renaming "' + p_wavname + '" to "' + p_newname + ".wav" + '" because dest. exists.' print 'NOT renaming "' + p_mp3name + '" to "' + p_newname + ext + '" because WAV dest. exists.' if ok: if not cf['_only_dae']: try: os.rename(mp3name, newname + ext) except OSError: error('Cannot rename "%s" to "%s" (Filename is too long or has unusable characters)' % (p_mp3name, p_newname + ext)) jack_m3u.add(newname + ext) if cf['_keep_wavs']: os.rename(wavname, newname + ".wav") jack_m3u.add_wav(newname + ".wav") jack_functions.progress(i[NUM], "ren", "%s-->%s" % (i[NAME], u_newname)) elif cf['_silent_mode']: jack_functions.progress(i[NUM], "err", "while renaming track") print if not cf['_silent_mode']: if jack_freedb.names_available: print "Done with \"" + p_artist + " - " + p_title + "\"." else: print "All done.", if cf['_set_id3tag'] and cf['_id3_year'] != -1: print "Year: %4i" % cf['_id3_year'], if cf['_id3_genre'] == -1: print if cf['_set_id3tag'] and cf['_id3_genre'] != -1: if cf['_id3_genre'] <0 or cf['_id3_genre'] > len(id3genres): print "Genre: [unknown]" else: print "Genre: %s" % id3genres[cf['_id3_genre']] if cf['_vbr'] and not cf['_only_dae']: print "Avg. bitrate: %03.0fkbit" % ((total_size * 0.008) / (total_length / 75)) else: print if jack_m3u.m3u: os.environ["JACK_JUST_ENCODED"] = "\n".join(jack_m3u.m3u) if jack_m3u.wavm3u: os.environ["JACK_JUST_RIPPED"] = "\n".join(jack_m3u.wavm3u) jack_m3u.write()