| import re |
| from typing import Dict, Any, Optional, List |
| from pathlib import Path |
| from i18n import _i18n |
|
|
| MAX_LENGTH = 255 |
| OFFSET = 10 |
| if OFFSET < MAX_LENGTH: |
| SAFE_MAX_LENGTH = MAX_LENGTH - OFFSET |
| else: |
| SAFE_MAX_LENGTH = MAX_LENGTH |
|
|
| class Namer: |
|
|
| @staticmethod |
| def sanitize(name: str) -> str: |
| """ |
| Очистить имя файла от недопустимых символов |
| |
| Args: |
| name: Исходное имя |
| |
| Returns: |
| Очищенное имя |
| """ |
| sanitized = re.sub(r'[<>:"/\\|?*]', "_", name) |
| sanitized = re.sub(r"_+", "_", sanitized) |
| sanitized = sanitized.strip("_. ") |
| return sanitized |
|
|
| @staticmethod |
| def short(name: str, length: Optional[int] = None) -> str: |
| """ |
| Сократить длинное имя |
| |
| Args: |
| name: Исходное имя |
| length: Желаемая длина |
| |
| Returns: |
| Сокращенное имя |
| """ |
| if length: |
| if len(name) > length: |
| return f"{name[:int(length // 2)]}...{name[-int(length // 2.5):]}" |
| else: |
| return name |
| else: |
| if len(name) > SAFE_MAX_LENGTH: |
| return f"{name[:int(SAFE_MAX_LENGTH // 4)]}...{name[-int(SAFE_MAX_LENGTH // 4):]}" |
| else: |
| return name |
|
|
| @staticmethod |
| def iter(filepath: str | Path) -> str: |
| """ |
| Создать уникальное имя файла, добавляя (n) если файл существует |
| |
| Args: |
| filepath: Исходный путь |
| |
| Returns: |
| Уникальный путь |
| """ |
| filepath_ = Path(filepath) |
| if not filepath_.exists(): |
| return filepath_.as_posix() |
|
|
| counter = 1 |
| while True: |
| new_filename = filepath_.stem + f" ({counter})" |
| new_filepath = filepath_.with_stem(new_filename) |
| if not new_filepath.exists(): |
| return new_filepath.as_posix() |
| counter += 1 |
|
|
| @staticmethod |
| def template(template: str, **kwargs: Any) -> str: |
| """ |
| Применить шаблон с подстановкой ключей |
| |
| Args: |
| template: Шаблон |
| **kwargs: Ключи для подстановки |
| |
| Returns: |
| Результат подстановки |
| """ |
| if kwargs: |
| for key in kwargs: |
| template = template.replace(str(key), str(kwargs[key])) |
| return template |
|
|
| @staticmethod |
| def dedup_template(template: str, keys: List[str] = []) -> str: |
| """ |
| Удалить дублирующиеся ключи из шаблона |
| |
| Args: |
| template: Шаблон |
| keys: Список ключей |
| |
| Returns: |
| Шаблон без дубликатов |
| """ |
| seen = set() |
| pattern = r"({})".format("|".join(re.escape(key) for key in keys)) |
|
|
| def replace(match: re.Match) -> str: |
| key = match.group(1) |
| if key in seen: |
| return "" |
| seen.add(key) |
| return key |
|
|
| result = re.sub(pattern, replace, template) |
| return result |
|
|
| @staticmethod |
| def short_input_name_template(template: str, **kwargs: Any) -> str: |
| """ |
| Сократить имя входного файла с учетом шаблона |
| |
| Args: |
| template: Шаблон |
| **kwargs: Ключи для подстановки |
| |
| Returns: |
| Сокращенное имя |
| """ |
| if kwargs: |
| input_file_name = kwargs.get("NAME", None) |
| if input_file_name: |
| merged_keys_value = "" |
| no_keys_template = template |
| for key in kwargs: |
| if key != "NAME": |
| merged_keys_value += str(kwargs[key]) |
| for key in kwargs: |
| no_keys_template = no_keys_template.replace(str(key), "") |
| len_merged_keys = len(merged_keys_value) |
| len_no_keys = len(no_keys_template) |
| free_length = SAFE_MAX_LENGTH - (len_merged_keys + len_no_keys) |
| len_file_name = len(input_file_name) |
| start_index = free_length // 2 |
| end_index = free_length // 2.5 |
| if len_file_name > free_length: |
| return f"{input_file_name[:int(start_index)]}...{input_file_name[-int(end_index):]}" |
| else: |
| return input_file_name |
| else: |
| print(_i18n("name_key_missing")) |
| return "" |
| else: |
| print(_i18n("keys_required")) |
| return "" |