def what_todo(space, todo): #### check what is already there wavs_todo = [] mp3s_todo = [] remove_q = [] ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension'] for track in todo: wavs_todo.append(track) mp3s_todo.append(track) jack_encstuff.mp3s_ready = [] for track in todo: mp3 = track[NAME] + ext if os.path.exists(mp3): if cf['_overwrite']: space = space + jack_utils.filesize(mp3) remove_q.append(mp3) jack_status.enc_status[track[NUM]] = "will o/w file." elif not cf['_force'] and not jack_status.enc_status[track[NUM]]: space = space + jack_utils.filesize(mp3) remove_q.append(mp3) jack_status.enc_status[track[NUM]] = "no encoder run." # with vbr encoded files can't legally be too small # but to reduce confusion, the check is then removed: elif not cf['_vbr'] and jack_utils.filesize(mp3) <= jack_functions.tracksize(track)[ENC] * 0.99: # found by trial'n'err space = space + jack_utils.filesize(mp3) remove_q.append(mp3) jack_status.enc_status[track[NUM]] = "encoded file too small by " + jack_functions.pprint_i(jack_functions.tracksize(track)[ENC] - jack_utils.filesize(mp3)) + "." elif not cf['_vbr'] and jack_utils.filesize(mp3) >= jack_functions.tracksize(track)[ENC] * 1.05: # found by trial'n'err space = space + jack_utils.filesize(mp3) remove_q.append(mp3) jack_status.enc_status[track[NUM]] = "enc. file too large by " + jack_functions.pprint_i(jack_utils.filesize(mp3) - jack_functions.tracksize(track)[ENC]) + "." else: mp3s_todo.remove(track) jack_encstuff.mp3s_ready.append(track) else: if jack_status.enc_status[track[NUM]]: jack_status.enc_status[track[NUM]] = "[file lost-doing again]" jack_ripstuff.wavs_ready = [] for track in todo: wav = track[NAME] + ".wav" if os.path.exists(wav): if cf['_overwrite']: space = space + jack_utils.filesize(wav) remove_q.append(wav) jack_status.dae_status[track[NUM]] = "Existing WAV will be overwritten." elif jack_utils.filesize(wav) == jack_functions.tracksize(track)[WAV] and jack_status.dae_status[track[NUM]]: wavs_todo.remove(track) jack_ripstuff.wavs_ready.append(track) elif jack_utils.filesize(wav) == jack_functions.tracksize(track)[WAV]: space = space + jack_utils.filesize(wav) remove_q.append(wav) jack_status.dae_status[track[NUM]] = " ---- [Existing WAV not done by jack.]" if jack_status.enc_status[track[NUM]] == "[file lost-doing again]": jack_status.enc_status[track[NUM]] = "" else: space = space + jack_utils.filesize(wav) remove_q.append(wav) jack_status.dae_status[track[NUM]] = " ---- [Existing WAV was not complete.]" if jack_status.enc_status[track[NUM]] == "[file lost-doing again]": jack_status.enc_status[track[NUM]] = "" else: if jack_status.dae_status[track[NUM]]: if jack_status.enc_status[track[NUM]] == "[file lost-doing again]": jack_status.dae_status[track[NUM]] = " ---- [ both lost, doing again ]" jack_status.enc_status[track[NUM]] = "" elif cf['_keep_wavs'] or track not in jack_encstuff.mp3s_ready: jack_status.dae_status[track[NUM]] = " ---- [ WAV lost, doing again ]" if cf['_only_dae']: cf['_keep_wavs'] = 1 if not cf['_keep_wavs']: for track in todo: if track in jack_encstuff.mp3s_ready and track in wavs_todo: wavs_todo.remove(track) if cf['_reorder']: mp3s_todo.sort(jack_utils.cmp_toc) dae_queue = [] # This stores the tracks to rip enc_queue = [] # WAVs go here to get some codin' for track in wavs_todo: dae_queue.append(track) # copy track to dae + code in queue if track in mp3s_todo: mp3s_todo.remove(track) # remove mp3s which are not there yet if cf['_only_dae']: # if only_dae nothing is encoded _at_all_. mp3s_todo = [] # overwrite cached bitrates with those from argv if cf['bitrate']['history'][-1][0] == "argv": for i in wavs_todo: i[RATE] = cf['_bitrate'] for i in mp3s_todo: i[RATE] = cf['_bitrate'] return space, remove_q, wavs_todo, mp3s_todo, dae_queue, enc_queue
def do_freedb_submit(file, cd_id, cat = None): import httplib if not cat: hello = "hello=" + cf['_username'] + " " + cf['_hostname'] + " " + prog_name + " " + prog_version print "Info: querying categories..." url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + urllib.quote_plus("cmd=cddb lscat" + "&" + hello + "&proto=6", "=&") f = urllib2.urlopen(url) buf = f.readline() if buf[0:3] == "500": print "Info: LSCAT failed, using builtin categories..." cat = choose_cat() elif buf[0:3] == "210": cat = [] while 1: buf = f.readline() if not buf: break buf = string.rstrip(buf) if buf != ".": cat.append(buf) f.close() cat = choose_cat(cat) else: error("LSCAT failed: " + string.rstrip(buf) + f.read()) print "OK, using category `" + cat + "'." email = freedb_servers[cf['_freedb_server']]['my_mail'] print "Your e-mail address is needed to send error messages to you." x = raw_input("enter your e-mail-address [" + email + "]: ") if x: email = x info("Submitting...") selector = '/~cddb/submit.cgi' proxy = "" if os.environ.has_key('http_proxy'): proxy = os.environ['http_proxy'] def splittype(url): import re _typeprog = re.compile('^([^/:]+):') match = _typeprog.match(url) if match: scheme = match.group(1) return scheme, url[len(scheme) + 1:] return None, url def splithost(url): import re _hostprog = re.compile('^//([^/]+)(.*)$') match = _hostprog.match(url) if match: return match.group(1, 2) return None, url type, proxy = splittype(proxy) host, selector2 = splithost(proxy) h = httplib.HTTP(host) h.putrequest('POST', 'http://' + freedb_servers[cf['_freedb_server']]['host'] + selector) else: h = httplib.HTTP(freedb_servers[cf['_freedb_server']]['host']) h.putrequest('POST', '/~cddb/submit.cgi') h.putheader('Category', cat) h.putheader('Discid', cd_id) h.putheader('User-Email', email) if cf['_debug']: debug("will submit in test-mode, changes are not applied and you'll get an email which contains the data you submitted.") h.putheader('Submit-Mode', 'test') else: h.putheader('Submit-Mode', 'submit') h.putheader('Charset', 'UTF-8') if cf['_debug']: h.putheader('X-Cddbd-Note', 'Submission will not be applied to database if --debug is on.') else: h.putheader('X-Cddbd-Note', 'data submitted with ' + prog_name + ' (http://jack.sf.net)') h.putheader('Content-Length', str(jack_utils.filesize(file))) h.endheaders() # The user just wrote the file with a text editor so we assume that it # is in their locale. f = codecs.open(file, "r", locale.getpreferredencoding()) try: text = f.read() except UnicodeDecodeError: print "The freedb file does not match your current locale. Please convert it" print "to " + locale.getpreferredencoding() + " manually." sys.exit(1) h.send(text.encode("utf-8")) f.close() print err, msg, headers = h.getreply() f = h.getfile() if proxy: if err != 200: error("proxy: " + `err` + " " + msg + f.read()) else: buf = f.readline() err, msg = buf[0:3], buf[4:] # lets see if it worked: if err == 404: print "This server doesn't seem to support database submission via http." print "consider submitting via mail (" + progname + " -m). full error:\n" print err, msg
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()
def guesstoc(names): "Return track list based on guessed lengths" num = 1 start = 0 erg = [] progr = [] for i in names: i_name, i_ext = os.path.splitext(os.path.basename(i)) i_ext = i_ext.upper() # erg: NUM, LEN, START, COPY, PRE, CH, RIP, RATE, NAME if i_ext == ".MP3": x = jack_mp3.mp3format(i) if not x: error("could not get MP3 info for file \"%x\"" % i) blocks = int(x['length'] * CDDA_BLOCKS_PER_SECOND + 0.5) erg.append([num, blocks, start, 0, 0, 2, 1, x['bitrate'], i_name]) progr.append( [num, "dae", " * [ simulated ]"]) progr.append([ num, "enc", ` x['bitrate'] `, "[ s i m u l a t e d %3ikbit]" % (x['bitrate'] + 0.5) ]) elif i_ext == ".WAV": x = sndhdr.whathdr(i) if not x: error("this is not WAV-format: " + i) if x != ('wav', 44100, 2, -1, 16): error("unsupportet format " + ` x ` + " in " + i) blocks = jack_utils.filesize(i) blocks = blocks - 44 # substract WAV header extra_bytes = blocks % CDDA_BLOCKSIZE if not extra_bytes == 0: warning("this is not CDDA block-aligned: " + ` i `) yes = raw_input( "May I strip %d bytes (= %.4fseconds) off the end? " % (extra_bytes, extra_bytes / 2352.0 / 75.0)) if not string.upper((yes + "x")[0]) == "Y": print "Sorry, I can't process non-aligned files (yet). Bye!" sys.exit() f = open(i, "r+") f.seek(-extra_bytes, 2) f.truncate() f.close() blocks = blocks - extra_bytes blocks = blocks / CDDA_BLOCKSIZE erg.append( [num, blocks, start, 0, 0, 2, 1, cf['_bitrate'], i_name]) progr.append( [num, "dae", " =p [ s i m u l a t e d ]"]) elif i_ext == ".OGG": if ogg: x = ogg.vorbis.VorbisFile(i) blocks = int(x.time_total(0) * CDDA_BLOCKS_PER_SECOND + 0.5) bitrate = temp_rate = int( x.raw_total(0) * 8 / x.time_total(0) / 1000 + 0.5) erg.append([num, blocks, start, 0, 0, 2, 1, bitrate, i_name]) progr.append( [num, "dae", " * [ simulated ]"]) progr.append([ num, "enc", ` bitrate `, "[ s i m u l a t e d %3ikbit]" % bitrate ]) else: error("The OGG Python bindings are not installed.") elif i_ext == ".FLAC": if flac: # TODO: move all of this duplicate code (see update_progress in # jack_prepare.py) into a jack_flac or jack_audio or jack_formats. # The same goes for the OGG stuff above f = flac.FLAC(i) size = os.path.getsize(i) if f.info and size: blocks = int( float(f.info.total_samples) / f.info.sample_rate * CDDA_BLOCKS_PER_SECOND + 0.5) bitrate = int(size * 8 * f.info.sample_rate / f.info.total_samples / 1000) else: blocks = bitrate = 0 erg.append([num, blocks, start, 0, 0, 2, 1, bitrate, i_name]) progr.append( [num, "dae", " * [ simulated ]"]) progr.append([ num, "enc", ` bitrate `, "[ s i m u l a t e d %3ikbit]" % bitrate ]) else: error("The FLAC Python bindings are not installed.") else: error("don't know how to handle %s files." % i_ext) if cf['_name'] % num != i_name: progr.append([ num, "ren", cf['_name'] % num + "-->" + unicode(i_name, cf['_charset'], "replace") ]) num = num + 1 start = start + blocks for i in progr: # this is deferred so that it is only written if no # files fail progress(i) return erg
def ripread(track, offset=0): "rip one track from an image file." data = {} start_time = time.time() pid, master_fd = pty.fork() # this could also be done with a pipe, anyone? if pid == CHILD: #debug: #so=open("/tmp/stdout", "w") #sys.stdout = so #se=open("/tmp/stderr", "w+") #sys.stderr = se default_signals() # FIXME: all this offset stuff has to go, track 0 support has to come. print ":fAE: waiting for status report..." sys.stdout.flush() hdr = sndhdr.whathdr(cf['_image_file']) my_swap_byteorder = cf['_swap_byteorder'] my_offset = offset if hdr: ## I guess most people use cdparanoia 1- (instead of 0- if applicable) ## for image creation, so for a wav file use: image_offset = -offset else: if string.upper(cf['_image_file'])[-4:] == ".CDR": hdr = ('cdr', 44100, 2, -1, 16) # Unknown header, assuming cdr # ## assume old cdrdao which started at track 1, not at block 0 image_offset = -offset elif string.upper(cf['_image_file'])[-4:] == ".BIN": hdr = ('bin', 44100, 2, -1, 16) # Unknown header, assuming bin # ## assume new cdrdao which starts at block 0, byteorder is reversed. my_swap_byteorder = not my_swap_byteorder image_offset = 0 elif string.upper(cf['_image_file'])[-4:] == ".RAW": hdr = ('bin', 44100, 2, -1, 16) # Unknown header, assuming raw image_offset = 0 else: debug("unsupported image file " + cf['_image_file']) posix._exit(4) expected_filesize = jack_functions.tracksize( jack_ripstuff.all_tracks)[CDR] + CDDA_BLOCKSIZE * offset # ## WAVE header is 44 Bytes for normal PCM files... # if hdr[0] == 'wav': expected_filesize = expected_filesize + 44 if abs(jack_utils.filesize(cf['_image_file']) - expected_filesize) > CDDA_BLOCKSIZE: # we *do* allow a difference of one frame debug("image file size mismatch, aborted. %d != %d" % (jack_utils.filesize(cf['_image_file']), expected_filesize)) posix._exit(1) elif hdr[0] == 'wav' and (hdr[1], hdr[2], hdr[4]) != (44100, 2, 16): debug("unsupported WAV, need CDDA_fmt, aborted.") posix._exit(2) elif hdr[0] not in ('wav', 'cdr', 'bin'): debug("unsupported: " + hdr[0] + ", aborted.") posix._exit(3) else: f = open(cf['_image_file'], 'r') # ## set up output wav file: # wav = wave.open(track[NAME] + ".wav", 'w') wav.setnchannels(2) wav.setsampwidth(2) wav.setframerate(44100) wav.setnframes(0) wav.setcomptype('NONE', 'not compressed') # ## calculate (and seek to) position in image file # track_start = (track[START] + image_offset) * CDDA_BLOCKSIZE if hdr[0] == 'wav': track_start = track_start + 44 f.seek(track_start) # ## copy / convert the stuff # for i in range(0, track[LEN]): buf = array.array("h") buf.fromfile(f, 1176) # CDDA_BLOCKSIZE / 2 if not my_swap_byteorder: # this is inverted as WAVE swabs them anyway. buf.byteswap() wav.writeframesraw(buf.tostring()) if i % 1000 == 0: print ":fAE: Block " + ` i ` + "/" + ` track[LEN] ` + ( " (%2i%%)" % (i * 100 / track[LEN])) sys.stdout.flush() wav.close() f.close() stop_time = time.time() read_speed = track[LEN] / CDDA_BLOCKS_PER_SECOND / (stop_time - start_time) if read_speed < 100: print "[%2.0fx]" % read_speed, else: print "[99x]", if hdr[0] in ('bin', 'wav'): print "[ - read from image - ]" else: print "[cdr-WARNING, check byteorder !]" sys.stdout.flush() posix._exit(0) else: # we are not the child data['start_time'] = start_time data['pid'] = pid data['fd'] = master_fd data['file'] = os.fdopen(master_fd) data['cmd'] = "" data['buf'] = "" data['type'] = "image_reader" data['prog'] = "builtin" data['track'] = track data['percent'] = 0 data['otf'] = 0 data['elapsed'] = 0 return data