Last active
August 9, 2023 20:34
-
-
Save steveherrin/cb307fe81319f2c68fd3314f6422f91b to your computer and use it in GitHub Desktop.
Reencode a music library from FLAC to Opus
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pathlib | |
import subprocess | |
import sys | |
REENCODE_EXTENSIONS = {'.flac', '.m4a', '.alac'} | |
COPY_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.mp3', '.opus', '.ogg'} | |
IGNORE_EXTENSIONS = {'.log', '.cue', '.txt'} | |
def _iter_tree(root: pathlib.Path): | |
if not root.is_dir(): | |
raise ValueError(f'{root} is not a directory') | |
for child in sorted(root.iterdir()): | |
if not child.is_dir(): | |
yield child | |
elif child.is_dir(): | |
for descendent in _iter_tree(child): | |
yield descendent | |
def encode_music_tree(src: pathlib.Path, dest: pathlib.Path): | |
for src_file in _iter_tree(src): | |
rel = src_file.relative_to(src) | |
dest_file = dest / rel | |
file_name = src_file.name | |
if file_name.startswith('.') or any(file_name.lower().endswith(ext) for ext in IGNORE_EXTENSIONS): | |
continue | |
elif any(file_name.lower().endswith(ext) for ext in COPY_EXTENSIONS): | |
command = ['cp', src_file, dest_file] | |
elif any(file_name.lower().endswith(ext) for ext in REENCODE_EXTENSIONS): | |
dest_file = dest_file.parent / (file_name.rsplit('.', 1)[0] + '.opus') | |
command = ['ffmpeg', '-i', src_file, '-vn', '-c:a', 'libopus', '-b:a', '128000', dest_file] | |
else: | |
ext = file_name.rsplit('.', 1)[-1] | |
if ext != file_name: # don't print this for files with no extension | |
print(f'unrecognized extension: .{ext}', file=sys.stderr) | |
continue | |
dest_file.parent.mkdir(parents=True, exist_ok=True) | |
result = subprocess.run(command, capture_output=True, encoding='utf-8') | |
if result.returncode != 0: | |
print(result.stderr, file=sys.stderr) | |
raise Exception(f"Error running '{' '.join(map(str, command))}'") | |
if __name__ == '__main__': | |
src = pathlib.Path(sys.argv[1]).resolve() | |
dest = pathlib.Path(sys.argv[2]).resolve() | |
encode_music_tree(src, dest) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment