#!/usr/bin/env python import argparse from pathlib import Path from progress.bar import Bar import shutil import subprocess def files_and_dirs_for_directory(path): filepaths = [] dirpaths = [] for dirpath, dirnames, filenames in path.walk(): dirpaths.append(dirpath) for filename in filenames: filepath = dirpath / filename filepaths.append(filepath) return set(filepaths), set(dirpaths) def make_paths_relative(paths, relative_to_path): return set(path.relative_to(relative_to_path) for path in paths) def replace_suffix(path, suffix): return path.with_name(path.stem + suffix) def convert_filepath(path): if path.suffix == ".flac": return replace_suffix(path, ".mp3") return path def ffmpeg_flac_to_mp3(in_path, out_path): print("") subprocess.run(["ffmpeg", "-hide_banner", "-loglevel", "warning", "-stats", "-i", in_path, "-ab", "320k", "-map_metadata", "0", "-id3v2_version", "3", out_path], check=True) print("") if __name__ == "__main__": parser = argparse.ArgumentParser(prog="convert-flac-dir-to-mp3") parser.add_argument("from_dir", type=Path) parser.add_argument("to_dir", type=Path) args = parser.parse_args() from_path = args.from_dir.absolute() to_path = args.to_dir.absolute() if not from_path.exists(): raise Exception("from_path does not exist") if not to_path.exists(): raise Exception("to_path does not exist") if not from_path.is_dir(): raise Exception("from_path is not a directory") if not to_path.is_dir(): raise Exception("to_path is not a directory") print(f"Converting {from_path} to {to_path}…") from_filepaths, from_dirpaths = files_and_dirs_for_directory(from_path) to_filepaths, to_dirpaths = files_and_dirs_for_directory(to_path) relative_from_filepaths = make_paths_relative(from_filepaths, from_path) relative_to_filepaths = make_paths_relative(to_filepaths, to_path) converted_from_filepaths = set(convert_filepath(filepath) for filepath in relative_from_filepaths) filepaths_missing_in_to_path = converted_from_filepaths - relative_to_filepaths relative_from_dirpaths = make_paths_relative(from_dirpaths, from_path) relative_to_dirpaths = make_paths_relative(to_dirpaths, to_path) dirpaths_missing_in_to_path = relative_from_dirpaths - relative_to_dirpaths print(f"Missing {len(filepaths_missing_in_to_path)} files and {len(dirpaths_missing_in_to_path)} directories") if len(dirpaths_missing_in_to_path) > 0: for dirpath in Bar("Creating directories").iter(dirpaths_missing_in_to_path): (to_path / dirpath).mkdir(parents=True, exist_ok=True) if len(filepaths_missing_in_to_path) > 0: for filepath in Bar("Creating files").iter(filepaths_missing_in_to_path): if filepath in relative_from_filepaths: # Just copy the file shutil.copy(from_path / filepath, to_path / filepath) elif filepath.suffix == ".mp3" and replace_suffix(filepath, ".flac") in relative_from_filepaths: # Convert from flac print("") print(f"Converting {to_path / filepath}…") # Tempfile for ffmpeg tmpfilepath = filepath.with_name(".~" + filepath.name) (to_path / tmpfilepath).unlink(missing_ok=True) print(f"Using tempfile for ffmpeg {to_path / tmpfilepath}…") # Convert ffmpeg_flac_to_mp3(from_path / replace_suffix(filepath, ".flac"), to_path / tmpfilepath) # Rename tempfile (to_path / tmpfilepath).rename(to_path / filepath) else: raise Exception("Unable to figure out how to get {to_path / filepath} from {from_path}")