Music transcoder!!
This commit is contained in:
		
						commit
						e48574b4ce
					
				
					 4 changed files with 413 additions and 0 deletions
				
			
		
							
								
								
									
										107
									
								
								music_transcoder/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								music_transcoder/__main__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,107 @@
 | 
			
		|||
from dataclasses import dataclass
 | 
			
		||||
import click
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
INPUT_FILE_EXTS_OPUSENC = [
 | 
			
		||||
    ".flac",
 | 
			
		||||
    ".wav",
 | 
			
		||||
    ".aiff",
 | 
			
		||||
]
 | 
			
		||||
INPUT_FILE_EXTS_COPY = [
 | 
			
		||||
    ".opus",
 | 
			
		||||
    ".ogg",  # this can also contain FLAC (fry about it)
 | 
			
		||||
    ".mp3",
 | 
			
		||||
    ".m4a",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_opusenc_args(
 | 
			
		||||
    input_path: str,
 | 
			
		||||
    output_path: str,
 | 
			
		||||
    bitrate: int = 192,
 | 
			
		||||
) -> list[str]:
 | 
			
		||||
    return [
 | 
			
		||||
        "opusenc",
 | 
			
		||||
        "--bitrate",
 | 
			
		||||
        str(bitrate),
 | 
			
		||||
        "--music",
 | 
			
		||||
        input_path,
 | 
			
		||||
        output_path,
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@dataclass
 | 
			
		||||
class InputFile:
 | 
			
		||||
    filepath: str
 | 
			
		||||
    relpath: str
 | 
			
		||||
    relpath_noext: str
 | 
			
		||||
    transcode: bool
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@click.option(
 | 
			
		||||
    "--input-dir",
 | 
			
		||||
    "-i",
 | 
			
		||||
    type=click.Path(exists=True, dir_okay=True, file_okay=False, resolve_path=True),
 | 
			
		||||
)
 | 
			
		||||
@click.option(
 | 
			
		||||
    "--output-dir",
 | 
			
		||||
    "-o",
 | 
			
		||||
    type=click.Path(
 | 
			
		||||
        exists=False, dir_okay=True, file_okay=False, writable=True, resolve_path=True
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
@click.command()
 | 
			
		||||
def music_transcoder(input_dir, output_dir):
 | 
			
		||||
    input_files: list[InputFile] = []
 | 
			
		||||
 | 
			
		||||
    for dirpath, _, filenames in os.walk(input_dir):
 | 
			
		||||
        for filename in filenames:
 | 
			
		||||
            _, ext = os.path.splitext(filename)
 | 
			
		||||
 | 
			
		||||
            transcode: bool
 | 
			
		||||
            if ext in INPUT_FILE_EXTS_OPUSENC:
 | 
			
		||||
                transcode = True
 | 
			
		||||
            elif ext in INPUT_FILE_EXTS_COPY:
 | 
			
		||||
                transcode = False
 | 
			
		||||
            else:
 | 
			
		||||
                print("[WARN] rejecting file:", dirpath, filename)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            filepath = os.path.join(dirpath, filename)
 | 
			
		||||
            relpath = os.path.relpath(filepath, input_dir)
 | 
			
		||||
            relpath_noext, _ = os.path.splitext(relpath)
 | 
			
		||||
            input_files.append(
 | 
			
		||||
                InputFile(
 | 
			
		||||
                    filepath=filepath,
 | 
			
		||||
                    relpath=relpath,
 | 
			
		||||
                    relpath_noext=relpath_noext,
 | 
			
		||||
                    transcode=transcode,
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    for input_file in input_files:
 | 
			
		||||
        if input_file.transcode:
 | 
			
		||||
            output_path = os.path.join(output_dir, input_file.relpath_noext + ".opus")
 | 
			
		||||
        else:
 | 
			
		||||
            output_path = os.path.join(output_dir, input_file.relpath)
 | 
			
		||||
 | 
			
		||||
        if os.path.exists(output_path):
 | 
			
		||||
            print("[WARN] skipping existing file", output_path)
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        output_path_dir, _ = os.path.split(output_path)
 | 
			
		||||
        os.makedirs(output_path_dir, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
        if not input_file.transcode:
 | 
			
		||||
            print("[INFO] hardlinking lossy file →", output_path)
 | 
			
		||||
            os.link(input_file.filepath, output_path)
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        print("[INFO] transcoding lossless file →", output_path)
 | 
			
		||||
        opusenc_args = get_opusenc_args(input_file.filepath, output_path)
 | 
			
		||||
        subprocess.run(opusenc_args, check=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    music_transcoder()
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue