diff --git a/music-tools.py b/music-tools.py index e08ff0b..30bae40 100755 --- a/music-tools.py +++ b/music-tools.py @@ -2,6 +2,7 @@ import argparse import convert_file_encoding +import split_flac def create_convert_parser(subparsers): @@ -16,10 +17,22 @@ def create_convert_parser(subparsers): parser.set_defaults(func=convert_file_encoding.execute) +def create_split_parser(subparsers): + parser = subparsers.add_parser( + "split", + description="Разделение FLAC-файла по CUE с переносом оригинала во временную директорию", + ) + parser.add_argument( + "directory", type=str, help="Path to target directory with flac and cue files" + ) + parser.set_defaults(func=split_flac.execute) + + if __name__ == "__main__": top_parser = argparse.ArgumentParser() subparsers = top_parser.add_subparsers() create_convert_parser(subparsers) + create_split_parser(subparsers) args = top_parser.parse_args() print(args) diff --git a/split_flac.py b/split_flac.py new file mode 100644 index 0000000..cbe621c --- /dev/null +++ b/split_flac.py @@ -0,0 +1,109 @@ +import argparse +import os +import shutil +import subprocess +import tempfile +import sys + + +def ensure_utils(): + if not all(shutil.which(cmd) for cmd in ["shnsplit", "cuetag"]): + raise RuntimeError("Ошибка: Требуются shnsplit и cuetag") + + +def find_cue_file(directory): + cue_files = [] + for f in os.listdir(directory): + if f.lower().endswith(".cue"): + cue_files.append(f) + if len(cue_files) != 1: + for f in cue_files: + print("Found CUE-file", f) + raise RuntimeError("Error: found multiple cue files") + return cue_files[0] + + +def find_flac_file(directory, cue_file): + cue_basename, _ = os.path.splitext(cue_file) + flac_file = cue_basename + ".flac" + if not os.path.exists(os.path.join(directory, flac_file)): + raise RuntimeError("Error: flac file not found", flac_file) + return flac_file + + +def process_directory(directory): + print("Search files in", directory) + + cue_file = find_cue_file(directory) + print("CUE:", cue_file) + + flac_file = find_flac_file(directory, cue_file) + print("FLAC:", flac_file) + + flac_full_path = os.path.join(directory, flac_file) + + # Создание временной директории + with tempfile.TemporaryDirectory(dir=directory) as tmp_dir: + try: + # Перенос оригинального FLAC во временную директорию + print("Move original FLAC file to", tmp_dir) + tmp_flac = os.path.join(tmp_dir, flac_file) + shutil.move(flac_full_path, tmp_flac) + + # Выполнение разделения в исходной директории + print("Split FLAC-file...") + subprocess.run( + [ + "shnsplit", + "-f", + cue_file, + "-o", + "flac", + "-t", + "%n - %t", + tmp_flac, + ], + cwd=directory, + check=True, + ) + + # Добавление метаданных + print("Add tags from CUE-file...") + split_files = [f for f in os.listdir(directory) if f.endswith(".flac")] + + if split_files: + subprocess.run( + ["cuetag", cue_file] + split_files, + cwd=directory, + check=True, + ) + + except subprocess.CalledProcessError as e: + print(f"Error: {e}") + # Возврат оригинала при ошибке + shutil.move(tmp_flac, flac_full_path) + return + + print("Done! File split and tagged") + + +def find_all_directories(root_dir): + """Рекурсивный поиск всех поддиректорий в указанной директории""" + dir_list = [] + for root, dirs, _ in os.walk(root_dir): + for dir_name in dirs: + if not dir_name.startswith("."): + full_path = os.path.join(root, dir_name) + dir_list.append(full_path) + return dir_list + + +def execute(args): + root_dir = args.directory + for d in find_all_directories(root_dir): + try: + process_directory(d) + except: + print("Failed", d) + print("Continue") + print()