diff --git a/src/music/convert.py b/src/music/convert.py index 762f2a6..bf714d0 100644 --- a/src/music/convert.py +++ b/src/music/convert.py @@ -11,19 +11,23 @@ from multiprocessing import Pool logger = logging.getLogger(__name__) -def convert_audio_file(args): - cmd, output_tmp, output_path = args +def run_task(args): + task = args[0] subprocess.run(cmd, shell=True) - os.makedirs(output_path.parent, exist_ok=True) - shutil.move(output_tmp, output_path) - + os.makedirs(task.output_path.parent, exist_ok=True) + shutil.move(task.output_tmp, task.output_path) class ConversionConfig(NamedTuple): input_dir: Path output_dir: Path - output_fmt: str - input_fmt: str + output_ext: str + input_ext: str + +class Task(NamedTuple): + cmd: str + output_tmp: Path + output_path: Path def _get_converted_path(input_path: Path, config: ConversionConfig): @@ -33,15 +37,34 @@ def _get_converted_path(input_path: Path, config: ConversionConfig): """ relative_path = input_path.relative_to(config.input_dir) - output_filename = str(input_path.stem) + f".{config.output_fmt}" + output_filename = str(input_path.stem) + f".{config.output_ext}" output_filename.replace("'", "") output_path = config.output_dir / relative_path.parent / output_filename return output_path - -def get_files_recursive(search_path: Path, extension: str): +def get_files_recursive(search_path: Path, + extension: str) -> list[Path]: return list(search_path.rglob(f"*.{extension}")) +def ffmpeg_convert(input_path: Path, + output_dir: Path, + output_ext: str) -> str: + output_tmp = output_dir / (str(uuid.uuid4()) + f".{output_ext}") + cmd = f"ffmpeg -i '{input_path}' -ab 320k -map_metadata 0 -id3v2_version 3 '{output_tmp}'" + +def build_conversion_tasks(input_files: list[Path], + output_files: list[Path], + config: ConversionConfig) -> list[Tasks]: + tasks = [] + for input_path, output_path in zip(input_files, output_files): + cmd = get_conversion_cmd(input_path, config.output_dir, config.output_ext) + tasks.append((cmd, output_tmp, output_path)) + return tasks + +def get_unconverted_files(input_files: list[Path], + config: ConversionConfig) -> list[Path]: + output_files = [_get_converted_path(f, config) for f in input_files] + return [f for f in output_files if not f.exists()] def convert(config: ConversionConfig): @@ -51,26 +74,13 @@ def convert(config: ConversionConfig): os.makedirs(config.output_dir, exist_ok=True) input_files = get_files_recursive( - config.input_dir.resolve(), config.input_fmt - ) - output_files = [] - for input_file in input_files: - candidate_output = _get_converted_path(input_file) - if not candidate_output.exists(): - output_files.append(candidate_output) - print(output_files) - - tasks = [] - for idx, (input_path, output_path) in enumerate(zip(input_files, output_files)): - - logger.info("Converting file %d of %d", idx, len(input_files)) - - output_tmp = self.output_dir / (str(uuid.uuid4()) + f".{self.output_fmt}") - cmd = f"ffmpeg -i '{input_path}' -ab 320k -map_metadata 0 -id3v2_version 3 '{output_tmp}'" - tasks.append((cmd, output_tmp, output_path)) + config.input_dir.resolve(), config.input_ext) + output_files = get_uncoverted_files(input_files, config) + tasks = build_conversion_tasks(input_files, output_files, config) + with Pool(10) as p: - p.map(convert_audio_file, tasks) + p.map(run_task, tasks) def move(input_dir: Path, output_dir: Path):