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


import os

# Папка, которую чиним
ROOT = r'C:\path\to\broken\folder'

# Пары кодировок для попытки: (как читается сейчас -> как должно быть)
# Порядок перебора — от самой частой к редкой
ENCODING_PAIRS = [
    ('latin-1', 'utf-8'),   # Привет -> Привет
    ('cp1251', 'utf-8'),
    ('cp866', 'cp1251'),
    ('cp1251', 'cp866'),
    ('latin-1', 'cp1251'),
    ('utf-8', 'cp866'),
]

def fix_name(name):
    """Пробуем декодировать имя в разных кодировках."""
    for src, dst in ENCODING_PAIRS:
        try:
            fixed = name.encode(src).decode(dst)
            # Проверка: имя не должно содержать "мусорных" символов
            if fixed != name and all(ord(c) >= 32 for c in fixed):
                return fixed
        except (UnicodeEncodeError, UnicodeDecodeError):
            continue
    return None

def rename_bottom_up(root):
    # Сначала собираем всё дерево
    all_paths = []
    for dirpath, dirnames, filenames in os.walk(root, topdown=False):
        for name in filenames + dirnames:
            all_paths.append(os.path.join(dirpath, name))

    # topdown=False уже даёт порядок снизу вверх
    renamed = 0
    for path in all_paths:
        if not os.path.exists(path):
            continue
        dirname, basename = os.path.split(path)
        fixed = fix_name(basename)
        if fixed and fixed != basename:
            new_path = os.path.join(dirname, fixed)
            try:
                os.rename(path, new_path)
                print(f'OK: {basename!r} -> {fixed!r}')
                renamed += 1
            except OSError as e:
                print(f'FAIL: {basename!r} ({e})')
    print(f'\nВсего переименовано: {renamed}')

if __name__ == '__main__':
    rename_bottom_up(ROOT)