def transcode(flac_file, output_dir, output_format): ''' Transcodes a FLAC file into another format. ''' # gather metadata from the flac file flac_info = mutagen.flac.FLAC(flac_file) sample_rate = flac_info.info.sample_rate bits_per_sample = flac_info.info.bits_per_sample dither = sample_rate > 48000 or bits_per_sample > 16 if flac_info.info.channels > 2: raise TranscodeDownmixException('FLAC file "%s" has more than 2 channels, unsupported' % flac_file) # determine the new filename transcode_file = os.path.join(output_dir, os.path.splitext(os.path.basename(flac_file))[0]) transcode_file += encoders[output_format]['ext'] if not os.path.exists(os.path.dirname(transcode_file)): try: os.makedirs(os.path.dirname(transcode_file)) except OSError as e: if e.errno == errno.EEXIST: # Harmless race condition -- another transcode process # beat us here. pass else: raise e commands = transcode_commands(output_format, dither, flac_file, transcode_file) results = run_pipeline(commands) # Check for problems. Because it's a pipeline, the earliest one is # usually the source. The exception is -SIGPIPE, which is caused # by "backpressure" due to a later command failing: ignore those # unless no other problem is found. last_sigpipe = None for (cmd, (code, stderr)) in zip(commands, results): if code: if code == -signal.SIGPIPE: last_sigpipe = (cmd, (code, stderr)) else: raise TranscodeException('Transcode of file "%s" failed: %s' % (flac_file, stderr)) if last_sigpipe: # XXX: this should probably never happen.... raise TranscodeException('Transcode of file "%s" failed: SIGPIPE' % flac_file) tagging.copy_tags(flac_file, transcode_file) (ok, msg) = tagging.check_tags(transcode_file) if not ok: raise TranscodeException('Tag check failed on transcoded file: %s' % msg) return transcode_file
def transcode(flac_file, output_dir, output_format): ''' Transcodes a FLAC file into another format. ''' # gather metadata from the flac file flac_info = mutagen.flac.FLAC(flac_file) sample_rate = flac_info.info.sample_rate bits_per_sample = flac_info.info.bits_per_sample resample = sample_rate > 48000 or bits_per_sample > 16 # if resampling isn't needed then needed_sample_rate will not be used. needed_sample_rate = None if resample: if sample_rate % 44100 == 0: needed_sample_rate = '44100' elif sample_rate % 48000 == 0: needed_sample_rate = '48000' else: raise UnknownSampleRateException( 'FLAC file "{0}" has a sample rate {1}, which is not 88.2 , 176.4 or 96kHz but needs resampling, this is unsupported' .format(flac_file, sample_rate)) if flac_info.info.channels > 2: raise TranscodeDownmixException( 'FLAC file "%s" has more than 2 channels, unsupported' % flac_file) # determine the new filename transcode_basename = os.path.splitext(os.path.basename(flac_file))[0] transcode_basename = re.sub(r'[\?<>\\*\|"]', '_', transcode_basename) transcode_file = os.path.join(output_dir, transcode_basename) transcode_file += encoders[output_format]['ext'] if not os.path.exists(os.path.dirname(transcode_file)): try: os.makedirs(os.path.dirname(transcode_file)) except OSError as e: if e.errno == errno.EEXIST: # Harmless race condition -- another transcode process # beat us here. pass else: raise e commands = transcode_commands(output_format, resample, needed_sample_rate, flac_file, transcode_file) results = run_pipeline(commands) # Check for problems. Because it's a pipeline, the earliest one is # usually the source. The exception is -SIGPIPE, which is caused # by "backpressure" due to a later command failing: ignore those # unless no other problem is found. last_sigpipe = None for (cmd, (code, stderr)) in zip(commands, results): if code: if code == -signal.SIGPIPE: last_sigpipe = (cmd, (code, stderr)) else: raise TranscodeException('Transcode of file "%s" failed: %s' % (flac_file, stderr)) if last_sigpipe: # XXX: this should probably never happen.... raise TranscodeException('Transcode of file "%s" failed: SIGPIPE' % flac_file) tagging.copy_tags(flac_file, transcode_file) (ok, msg) = tagging.check_tags(transcode_file) if not ok: raise TranscodeException('Tag check failed on transcoded file: %s' % msg) return transcode_file