Загрузка данных


import os
import re
import shutil
from pathlib import Path

# === НАСТРОЙКИ ===
# Сразу подставил твои пути с экрана, при необходимости поправь
SOURCE_DIR = Path(r"C:\Users\n.o.ishanhodzhaeva\Desktop\Forma\1 ТФ")
OUTPUT_DIR = Path(r"C:\Users\n.o.ishanhodzhaeva\Desktop\Forma\res")

YEAR = "2023"

# Список папок, которые нужно ОСТАВИТЬ
KEEP_FOLDERS = {
    "мр и др": "МР и др",
    "мр и др.": "МР и др",
    "рпд": "РПД",
    "рпп": "РПП"
}

# Ищет код направления в любой части названия папки (например, "22.03.02 Металлургия" или "1. 54.03.01 Дизайн")
OP_CODE_REGEX = re.compile(r"(\d{2}\.\d{2}\.\d{2})")

# Удаляет цифры в начале папок ("3 РПД" -> "РПД")
LEADING_NUM_REGEX = re.compile(r"^\d+[\.\s_-]*")

# Ищет "2022-2023", "2022_2023", "2022/2023" или просто "2022" в названиях файлов и папок
BAD_YEAR_REGEX = re.compile(r"2022(?:\s*[-_\/]\s*2023)?")

SYSTEM_FILES = {"thumbs.db", ".ds_store", "desktop.ini"}


def is_valid_file(file_path: Path) -> bool:
    """Проверяет, что файл не системный и не относится к 2022 / 2022-2023 году."""
    name_lower = file_path.name.lower()
    if name_lower in SYSTEM_FILES or name_lower.startswith("~$"):
        return False
    if BAD_YEAR_REGEX.search(name_lower):
        return False
    return True


def has_any_valid_files(dir_path: Path) -> bool:
    """Проверяет, есть ли внутри папки хотя бы один нормальный файл (защита от пустых папок)."""
    for item in dir_path.rglob("*"):
        if item.is_file():
            # Если файл лежит внутри папки "2022-2023", игнорируем его
            rel_parts = item.relative_to(dir_path).parts
            if any(BAD_YEAR_REGEX.search(part.lower()) for part in rel_parts):
                continue
            if is_valid_file(item):
                return True
    return False


def clean_2022_items(profile_dir: Path):
    """Удаляет все папки и файлы, связанные с 2022 / 2022-2023 годом."""
    # 1. Сначала сносим целые подпапки с 2022-2023 в названии
    for item in list(profile_dir.rglob("*")):
        if item.exists() and item.is_dir() and BAD_YEAR_REGEX.search(item.name.lower()):
            shutil.rmtree(item)
            print(f"  [Удалена папка 2022] '{item.name}'")

    # 2. Затем удаляем отдельные файлы с 2022-2023 и системный мусор
    for item in list(profile_dir.rglob("*")):
        if item.exists() and item.is_file():
            if item.name.lower() in SYSTEM_FILES:
                item.unlink()
            elif BAD_YEAR_REGEX.search(item.name.lower()):
                item.unlink()
                print(f"  [Удален файл 2022] '{item.name}'")


def move_file_safely(src_file: Path, target_dir: Path):
    """Безопасно перемещает файл, не перезаписывая существующие."""
    target_path = target_dir / src_file.name
    counter = 1
    while target_path.exists():
        target_path = target_dir / f"{src_file.stem}_{counter}{src_file.suffix}"
        counter += 1
    shutil.move(str(src_file), str(target_path))


def process_profile_content(profile_dir: Path):
    """Чистит 2022 год, оставляет МР и др, РПД, РПП, а остальные файлы выносит в корень."""
    # Сначала вычищаем всё за 2022-2023 год
    clean_2022_items(profile_dir)

    for item in list(profile_dir.iterdir()):
        if not item.is_dir():
            continue

        clean_name = LEADING_NUM_REGEX.sub("", item.name).strip()
        clean_name_lower = clean_name.lower()

        # 1. Если это одна из 3 папок (МР и др, РПД, РПП)
        if clean_name_lower in KEEP_FOLDERS:
            standard_name = KEEP_FOLDERS[clean_name_lower]
            target_dir = profile_dir / standard_name

            if item != target_dir:
                if not target_dir.exists():
                    item.rename(target_dir)
                    print(f"  [Переименована] '{item.name}' -> '{standard_name}'")
                else:
                    for sub_item in item.iterdir():
                        if sub_item.is_file():
                            move_file_safely(sub_item, target_dir)
                        elif sub_item.is_dir():
                            shutil.move(str(sub_item), str(target_dir / sub_item.name))
                    shutil.rmtree(item)
                    print(f"  [Объединена] '{item.name}' -> '{standard_name}'")

        # 2. Все остальные папки — достаем файлы в корень и удаляем папку
        else:
            files_moved = 0
            for sub_item in item.rglob("*"):
                if sub_item.is_file():
                    move_file_safely(sub_item, profile_dir)
                    files_moved += 1

            shutil.rmtree(item)
            print(f"  [Распакована и удалена] '{item.name}' (вынесено файлов: {files_moved})")


def main():
    if not SOURCE_DIR.exists():
        print(f"Ошибка: Исходная папка {SOURCE_DIR} не найдена!")
        return

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    for root, dirs, _ in os.walk(SOURCE_DIR):
        root_path = Path(root)

        # Защита от захвата самой папки с результатами, если она лежит внутри SOURCE_DIR
        if OUTPUT_DIR in root_path.parents or root_path == OUTPUT_DIR:
            dirs.clear()
            continue

        match = OP_CODE_REGEX.search(root_path.name)

        if match:
            op_code = match.group(1)

            for profile_dir in root_path.iterdir():
                if not profile_dir.is_dir():
                    continue

                # Пропускаем профиль, если он сам называется "2022-2023"
                if BAD_YEAR_REGEX.search(profile_dir.name.lower()):
                    print(f"\n[Пропуск папки 2022] {profile_dir.name}")
                    continue

                # ГЛАВНАЯ ПРОВЕРКА: если папка профиля пустая (или там только пустые папки/файлы 2022), пропускаем!
                if not has_any_valid_files(profile_dir):
                    print(f"\n[Пропуск пустой папки] {op_code} -> {profile_dir.name}")
                    continue

                profile_name = profile_dir.name.strip()
                new_folder_name = f"{YEAR} {op_code} {profile_name}"
                target_profile_path = OUTPUT_DIR / new_folder_name

                print(f"\nОбработка: {new_folder_name}")

                if target_profile_path.exists():
                    shutil.rmtree(target_profile_path)
                shutil.copytree(profile_dir, target_profile_path)

                process_profile_content(target_profile_path)

            # Не идем вглубь профилей, чтобы не обрабатывать их внутренности как новые направления
            dirs.clear()

    print("\nГотово! Все папки собраны в:", OUTPUT_DIR)


if __name__ == "__main__":
    main()