commit e44ee1cd193a8eed1eb3144fae2a1e45178256bf Author: urbnywrt <14278436+urbnywrt@users.noreply.github.com> Date: Wed Mar 19 00:50:49 2025 +0300 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37e2338 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.venv/* +.vscode/* +profiles/* \ No newline at end of file diff --git a/AnyDesk.exe b/AnyDesk.exe new file mode 100644 index 0000000..8c962a7 Binary files /dev/null and b/AnyDesk.exe differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..610f624 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 urbnywrt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/image-1.png b/image-1.png new file mode 100644 index 0000000..c90ce1f Binary files /dev/null and b/image-1.png differ diff --git a/image.png b/image.png new file mode 100644 index 0000000..0ecdeac Binary files /dev/null and b/image.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..8e90018 --- /dev/null +++ b/main.py @@ -0,0 +1,348 @@ +import os +import shutil +import time +import psutil +import subprocess + +# ANSI escape codes for text color and formatting +RESET = '\033[0m' +BOLD = '\033[1m' +RED = '\033[91m' # Для повторяющихся цифр +GREEN = '\033[92m' # Для возрастающих последовательностей +YELLOW = '\033[93m' # Для убывающих последовательностей +BLUE = '\033[94m' # Для палиндромов +MAGENTA = '\033[95m' # Для специальных чисел (228, 1488, 322) + +def find_ad_anynet_id(file_path): + """Ищет строку ad.anynet.id в файле.""" + try: + with open(file_path, 'r') as file: + for line in file: + if line.startswith('ad.anynet.id='): + return line.strip() + except Exception as e: + print(f"Error reading file {file_path}: {e}") + return None + +def get_file_content(file_path): + """Читает содержимое файла.""" + try: + with open(file_path, 'r') as file: + return file.read() + except Exception as e: + print(f"Error reading file {file_path}: {e}") + return "" + +def is_beautiful_id(id_str): + """Определяет, является ли ID 'красивым'.""" + # Проверка на повторяющиеся цифры (например, 1111) + for i in range(len(id_str) - 3): + if id_str[i] == id_str[i+1] == id_str[i+2] == id_str[i+3]: + # Находим все вхождения повторяющейся цифры + repeated_digit = id_str[i] + part = '' + j = i + while j < len(id_str) and id_str[j] == repeated_digit: + part += id_str[j] + j += 1 + return {'type': 'repeated', 'part': part} + + # Проверка на возрастающую последовательность (например, 1234) + if ''.join(sorted(id_str)) == id_str and len(set(id_str)) == len(id_str): + return {'type': 'ascending', 'part': id_str} + + # Проверка на убывающую последовательность (например, 4321) + if ''.join(sorted(id_str, reverse=True)) == id_str and len(set(id_str)) == len(id_str): + return {'type': 'descending', 'part': id_str} + + # Проверка на палиндром (симметричные числа, например, 1221) + if id_str == id_str[::-1]: + return {'type': 'palindrome', 'part': id_str} + + # Проверка на наличие чисел 228, 1488, 322 + special_numbers = ['228', '1488', '322'] + for number in special_numbers: + if number in id_str: + return {'type': 'special_number', 'part': number} + + # Временно закомментировано условие про короткие ID + # if len(id_str) <= 9: + # return {'type': 'short', 'part': id_str} + + return None + +def parse_profiles(profiles_dir): + """Парсит профили и ищет 'красивые' ID.""" + profiles = {} + beautiful_profiles = {} + + # Проверяем, существует ли директория + if not os.path.exists(profiles_dir): + print(f"Profiles directory '{profiles_dir}' does not exist!") + return profiles, beautiful_profiles + + # Проверяем содержимое директории + dir_contents = os.listdir(profiles_dir) + if not dir_contents: + print(f"Profiles directory '{profiles_dir}' is empty!") + return profiles, beautiful_profiles + + print(f"Contents of profiles directory: {dir_contents}") + + for profile_name in dir_contents: + profile_path = os.path.join(profiles_dir, profile_name) + if not os.path.isdir(profile_path): + print(f"Skipping non-directory item: {profile_name}") + continue + + # Учитываем новую структуру: profiles/ADx/AnyDesk/system.conf + anydesk_dir = os.path.join(profile_path, "AnyDesk") + system_conf_path = os.path.join(anydesk_dir, "system.conf") + + if not os.path.exists(system_conf_path): + print(f"system.conf not found in profile: {profile_name}") + continue + + print(f"Parsing profile: {profile_name}") + ad_anynet_id = find_ad_anynet_id(system_conf_path) + if ad_anynet_id: + id_value = ad_anynet_id.split('=')[1] + profiles[profile_name] = { + 'id': id_value, + 'config_path': system_conf_path + } + beauty_info = is_beautiful_id(id_value) + if beauty_info: + beautiful_profiles[profile_name] = {'id': id_value, 'beauty_info': beauty_info} + else: + print(f"No ad.anynet.id found in system.conf for profile: {profile_name}") + + return profiles, beautiful_profiles + + +def highlight_beautiful_id(id_str, beauty_info): + """Подсвечивает 'красивую' часть ID.""" + part = beauty_info['part'] + type_ = beauty_info['type'] + + highlighted_id = id_str + + if type_ == 'repeated': + # Находим все вхождения повторяющейся части и подсвечиваем их красным + start_index = 0 + while True: + start_index = highlighted_id.find(part, start_index) + if start_index == -1: + break + end_index = start_index + len(part) + highlighted_part = RED + BOLD + part + RESET + highlighted_id = highlighted_id[:start_index] + highlighted_part + highlighted_id[end_index:] + start_index += len(highlighted_part) # Учитываем длину подсвеченной части + + elif type_ == 'ascending': + # Подсвечиваем возрастающие последовательности зеленым + start_index = highlighted_id.find(part) + if start_index != -1: + end_index = start_index + len(part) + highlighted_part = GREEN + BOLD + part + RESET + highlighted_id = highlighted_id[:start_index] + highlighted_part + highlighted_id[end_index:] + + elif type_ == 'descending': + # Подсвечиваем убывающие последовательности желтым + start_index = highlighted_id.find(part) + if start_index != -1: + end_index = start_index + len(part) + highlighted_part = YELLOW + BOLD + part + RESET + highlighted_id = highlighted_id[:start_index] + highlighted_part + highlighted_id[end_index:] + + elif type_ == 'palindrome': + # Подсвечиваем палиндромы синим + start_index = highlighted_id.find(part) + if start_index != -1: + end_index = start_index + len(part) + highlighted_part = BLUE + BOLD + part + RESET + highlighted_id = highlighted_id[:start_index] + highlighted_part + highlighted_id[end_index:] + + elif type_ == 'special_number': + # Подсвечиваем специальные числа магентой + start_index = highlighted_id.find(part) + if start_index != -1: + end_index = start_index + len(part) + highlighted_part = MAGENTA + BOLD + part + RESET + highlighted_id = highlighted_id[:start_index] + highlighted_part + highlighted_id[end_index:] + + return highlighted_id + +def kill_process(process_name): + """Убивает процесс по имени.""" + try: + for proc in psutil.process_iter(['name']): + if proc.info['name'] == process_name: + proc.kill() + except Exception as e: + pass # Игнорируем ошибки при завершении процесса + +def generate_profiles(output_dir, anydesk_exe_path, num_ids, timeout_seconds): + """Генерирует профили AnyDesk.""" + appdata_dir = os.getenv('APPDATA') + anydesk_config_dir = os.path.join(appdata_dir, "AnyDesk") + + # Определяем следующий доступный номер профиля + existing_profiles = [name for name in os.listdir(output_dir) if name.startswith("AD") and name[2:].isdigit()] + next_profile_number = max([int(name[2:]) for name in existing_profiles], default=0) + 1 + + # Прогресс-бар + print("Generating profiles:") + for i in range(next_profile_number, next_profile_number + num_ids): + progress = int((i - next_profile_number + 1) / num_ids * 100) + bar = f"[{'#' * (progress // 2):<50}] {progress}%" + print(f"\r{bar}", end="") + + profile_name = f"AD{i}" + profile_dir = os.path.join(output_dir, profile_name) + anydesk_subdir = os.path.join(profile_dir, "AnyDesk") + os.makedirs(anydesk_subdir, exist_ok=True) + + # Убиваем процесс AnyDesk + kill_process("AnyDesk.exe") + + # Запускаем AnyDesk + subprocess.Popen([anydesk_exe_path], shell=True) + time.sleep(timeout_seconds) + + # Копируем конфигурацию с обработкой ошибок + try: + if os.path.exists(anydesk_config_dir): + shutil.copytree(anydesk_config_dir, anydesk_subdir, dirs_exist_ok=True) + except Exception as e: + pass + #print(f"\nError copying files for profile {profile_name}: {e}") + + # Убиваем процесс AnyDesk снова + kill_process("AnyDesk.exe") + if os.path.exists(anydesk_config_dir): + shutil.rmtree(anydesk_config_dir, ignore_errors=True) + + print("\nAll profiles generated successfully!") + +def apply_profile(profiles_dir, profile_name): + """Копирует конфигурацию профиля в папку AnyDesk пользователя и запускает AnyDesk.""" + appdata_dir = os.getenv('APPDATA') + anydesk_config_dir = os.path.join(appdata_dir, "AnyDesk") + + # Удаляем текущую конфигурацию AnyDesk + if os.path.exists(anydesk_config_dir): + shutil.rmtree(anydesk_config_dir, ignore_errors=True) + + # Находим путь к конфигурации выбранного профиля + profile_path = os.path.join(profiles_dir, profile_name) + anydesk_subdir = os.path.join(profile_path, "AnyDesk") + + if not os.path.exists(anydesk_subdir): + print(f"Profile '{profile_name}' does not exist or is invalid!") + return + + # Копируем конфигурацию профиля в папку AnyDesk + try: + shutil.copytree(anydesk_subdir, anydesk_config_dir, dirs_exist_ok=True) + print(f"Profile '{profile_name}' applied successfully!") + except Exception as e: + print(f"Error applying profile '{profile_name}': {e}") + return + + # Запускаем AnyDesk + anydesk_exe_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "AnyDesk.exe") + if not os.path.exists(anydesk_exe_path): + print(f"Error: AnyDesk.exe not found at {anydesk_exe_path}") + return + + subprocess.Popen([anydesk_exe_path], shell=True) + print("AnyDesk started with the selected profile.") + +def main_menu(): + # Определяем директорию для профилей + script_dir = os.path.dirname(os.path.abspath(__file__)) + profiles_dir = os.path.join(script_dir, "profiles") + os.makedirs(profiles_dir, exist_ok=True) + + # Путь к AnyDesk.exe по умолчанию + default_anydesk_path = os.path.join(script_dir, "AnyDesk.exe") + + # Парсим профили один раз для использования в меню + profiles, beautiful_profiles = parse_profiles(profiles_dir) + + while True: + print("\nMain Menu:") + print("1. Parse Profiles") + print("2. Generate Profiles") + print("3. View Beautiful IDs") + print("4. Get Configuration by ID") + print("5. Apply Profile to AnyDesk") + print("6. Exit") + choice = input("Enter your choice: ") + + if choice == '1': + profiles, beautiful_profiles = parse_profiles(profiles_dir) + print("Profiles parsed successfully!") + print("Found IDs:") + for profile_name, profile_data in profiles.items(): + print(f"{profile_name}: {profile_data['id']}") + + elif choice == '2': + anydesk_exe_path = input(f"Enter the path to AnyDesk.exe (default: {default_anydesk_path}): ").strip() + if not anydesk_exe_path: + anydesk_exe_path = default_anydesk_path # Используем путь по умолчанию + + num_ids = int(input("Enter the number of IDs to generate: ")) + timeout_seconds = int(input("Enter timeout duration (in seconds): ")) + + generate_profiles(profiles_dir, anydesk_exe_path, num_ids, timeout_seconds) + print("Profiles generated successfully!") + + # Обновляем список профилей после генерации + profiles, beautiful_profiles = parse_profiles(profiles_dir) + print("Updated Found IDs:") + for profile_name, profile_data in profiles.items(): + print(f"{profile_name}: {profile_data['id']}") + + elif choice == '3': + print("\nBeautiful IDs:") + if beautiful_profiles: + for profile_name, data in beautiful_profiles.items(): + id_str = data['id'] + beauty_info = data['beauty_info'] + highlighted_id = highlight_beautiful_id(id_str, beauty_info) + print(f"{profile_name}: {highlighted_id}") + else: + print("No beautiful IDs found.") + + elif choice == '4': + user_input = input("Enter ID to get configuration (or 'exit' to cancel): ") + if user_input.lower() == 'exit': + continue + + found = False + for profile_name, profile_data in profiles.items(): + if profile_data['id'] == user_input: + print(f"Configuration for profile {profile_name}:") + config_content = get_file_content(profile_data['config_path']) + print(config_content) + found = True + break + + if not found: + print("ID not found.") + + elif choice == '5': + profile_name = input("Enter the profile name to apply (e.g., AD1): ") + apply_profile(profiles_dir, profile_name) + + elif choice == '6': + print("Exiting...") + break + + else: + print("Invalid choice. Please try again.") + +if __name__ == "__main__": + main_menu() \ No newline at end of file diff --git a/readme-ru.md b/readme-ru.md new file mode 100644 index 0000000..f2a01d5 --- /dev/null +++ b/readme-ru.md @@ -0,0 +1,71 @@ +# Генератор и парсер профилей AnyDesk + +![GitHub top language](https://img.shields.io/badge/language-Python-blue) +![GitHub license](https://img.shields.io/badge/license-MIT-green) + +**Генератор и парсер профилей AnyDesk** — это инструмент для автоматической генерации, анализа и управления профилями AnyDesk. +Скрипт позволяет создавать новые профили, находить "красивые" ID, просматривать конфигурации и применять выбранные профили в AnyDesk. + +--- + +## Основные возможности + +1. **Генерация профилей AnyDesk**: + + - Создание новых профилей с уникальными ID. + - Настройка времени ожидания для каждого профиля. +2. **Поиск "красивых" ID**: + + - Повторяющиеся цифры (например, `55555`). + - Возрастающие (`1234`) и убывающие (`4321`) последовательности. + - Палиндромы (например, `123321`). + - Специальные числа: `228`, `1488`, `322`. +3. **Просмотр конфигураций**: + + - Возможность просмотра содержимого файла `system.conf` по конкретному ID. +4. **Применение профиля в AnyDesk**: + + - Копирование выбранной конфигурации в папку AnyDesk пользователя. + - Запуск AnyDesk с новым профилем. +5. **Подсветка "красивых" ID**: + + - Различные цвета для разных типов "красивых" ID: + - Повторяющиеся цифры: **красный**. + - Возрастающие последовательности: **зеленый**. + - Убывающие последовательности: **желтый**. + - Палиндромы: **синий**. + - Специальные числа: **магента**. + +--- + +## Установка + +1. **Python 3.6+**: + + - Убедитесь, что Python установлен на вашем компьютере. Вы можете скачать его [здесь](https://www.python.org/downloads/). +2. **Библиотеки**: + + - Установите необходимую библиотеку `psutil` с помощью команды: + + ```bash + pip install psutil + ``` +3. **AnyDesk**: + + - Скрипт использует исполняемый файл `AnyDesk.exe`. Убедитесь, что он находится в одной папке со скриптом или укажите путь к нему. + +--- + +## Использование + +1. **Запуск программы**: + Запустите скрипт в терминале: + + ```bash + python main.py + + ``` + +``` +1. **Главное меню**: +``` diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..0cf6a33 --- /dev/null +++ b/readme.md @@ -0,0 +1,107 @@ +# AnyDesk Profile Generator and Parser + +![GitHub top language](https://img.shields.io/badge/language-Python-blue) +![GitHub license](https://img.shields.io/badge/license-MIT-green) + +**AnyDesk Profile Generator and Parser** is a tool for automatically generating, analyzing, and managing AnyDesk profiles. The script allows you to create new profiles, find "beautiful" IDs, view configurations, and apply selected profiles in AnyDesk. + +--- + +## Features + +1. **Generate AnyDesk Profiles**: + + - Create new profiles with unique IDs. + - Configure timeout for each profile generation. +2. **Find "Beautiful" IDs**: + + - Repeating digits (e.g., `55555`). + - Ascending (`1234`) and descending (`4321`) sequences. + - Palindromes (e.g., `123321`). + - Special numbers: `228`, `1488`, `322`. +3. **View Configurations**: + + - View the contents of the `system.conf` file by a specific ID. +4. **Apply a Profile to AnyDesk**: + + - Copy the selected configuration to the user's AnyDesk folder. + - Launch AnyDesk with the new profile. +5. **Highlight "Beautiful" IDs**: + + - Different colors for different types of "beautiful" IDs: + - Repeating digits: **red**. + - Ascending sequences: **green**. + - Descending sequences: **yellow**. + - Palindromes: **blue**. + - Special numbers: **magenta**. + +--- + +## Installation + +1. **Python 3.6+**: + + - Make sure Python is installed on your computer. You can download it [here](https://www.python.org/downloads/). +2. **Libraries**: + + - Install the required library `psutil` using the following command: + + ```bash + pip install psutil + ``` +3. **AnyDesk**: + + - The script uses the `AnyDesk.exe` executable file. Ensure it is located in the same folder as the script or specify its path. + +--- + +## Usage + +1. **Run the Program**: + Start the script in the terminal: + + ```bash + python main.py + ``` +2. **Main Menu** : + After launching, you will see the main menu: + ![alt text](image.png) + +## Notes on Color Display + +* **Color Support** + * The script uses ANSI escape codes for colored output. + * For correct color display, it is recommended to use Windows Terminal or any modern terminal emulator that supports ANSI colors. + * If you are using the default Windows Command Prompt (cmd.exe), colors may not display correctly due to limited ANSI support. + + +## Examples + +1. "Beautiful" IDs: + ![alt text](image-1.png) + +## Project Structure + +``` +project/ +│ +├── main.py # Main script +├── profiles/ # Folder for storing profiles +│ ├── AD1/ +│ │ └── AnyDesk/ +│ │ └── system.conf +│ ├── AD2/ +│ │ └── AnyDesk/ +│ │ └── system.conf +│ └── ... +└── README.md # Documentation +``` + +## License + +This project is distributed under the [MIT License](LICENSE). You can freely use, modify, and distribute this code. + +## Author + +Author: **urbnywrt** +GitHub: [urbnywrt](https://github.com/urbnywrt)