# TyChat TUI auto installer # This is bugged pice of shit because of crossplatform # I will only officialy supporting Windows and UNIX-Like systems excluding MacOS and KolibriOS import os import sys import shutil import subprocess import platform import urllib.request import zipfile # Configuration, you can change if you like, for example, making a fork of my messenger REPO_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client.git" PROJECT_DIR = "TyChat-Client-Build" VENV_DIR = os.path.join(PROJECT_DIR, "setup-venv") ENTRY_POINT = "TUI.py" DEPENDENCIES = [ "pyinstaller", "python-socketio", "websocket-client", "numpy", "sounddevice", "prompt_toolkit" ] GREEN = '\033[92m' RESET = '\033[0m' def run_command(command, cwd=None, shell=False): """Wrapper to run shell commands.""" try: subprocess.run(command, cwd=cwd, check=True, shell=shell) except subprocess.CalledProcessError as e: print(f"[ERROR] Command failed: {' '.join(command)}") sys.exit(1) def get_venv_paths(): """Determine paths based on the operating system and check for valid executables.""" # Resolve to an absolute path so altering cwd downstream doesn't break relative lookups absolute_venv = os.path.abspath(VENV_DIR) if platform.system() == "Windows": return os.path.join(absolute_venv, "Scripts", "python.exe"), os.path.join(absolute_venv, "Scripts", "pip.exe") # Check for python3, fallback to python python_path = os.path.join(absolute_venv, "bin", "python3") if not os.path.exists(python_path): python_path = os.path.join(absolute_venv, "bin", "python") # Check for pip3, fallback to pip pip_path = os.path.join(absolute_venv, "bin", "pip3") if not os.path.exists(pip_path): pip_path = os.path.join(absolute_venv, "bin", "pip") return python_path, pip_path def download_and_extract_zip(url, target_dir): """Downloads the repository source ZIP and extracts its contents into target_dir.""" zip_path = "repo_archive.zip" try: print(" -> Git not found. Downloading source ZIP archive...") # Download the zip file urllib.request.urlretrieve(url, zip_path) print(" -> Extracting archive...") with zipfile.ZipFile(zip_path, 'r') as zip_ref: # The archive extracts into a root folder like 'TyChat-Client' or 'TyChat-Client-main' # We look at the first directory level inside the ZIP root_in_zip = zip_ref.namelist()[0].split('/')[0] zip_ref.extractall(".") # Rename the extracted folder to match your expected PROJECT_DIR if os.path.exists(root_in_zip): os.rename(root_in_zip, target_dir) except Exception as e: print(f"[ERROR] Failed to download or extract the repository ZIP: {e}") sys.exit(1) finally: # Clean up the downloaded zip file if os.path.exists(zip_path): os.remove(zip_path) def main(): # Cleanup existing build if os.path.exists(PROJECT_DIR): shutil.rmtree(PROJECT_DIR) print("[*] Cloning repository...") # Check if git is available in the system PATH if shutil.which("git"): run_command(["git", "clone", REPO_URL, PROJECT_DIR]) else: # Fallback to the direct zip archive if git is missing zip_url = "https://git.idkmail.ru/lohrrrr/TyChat-Client/archive/main.zip" download_and_extract_zip(zip_url, PROJECT_DIR) print("[*] Creating virtual environment...") run_command([sys.executable, "-m", "venv", VENV_DIR]) python_exe, pip_exe = get_venv_paths() print("[*] Upgrading pip...") run_command([python_exe, "-m", "pip", "install", "--upgrade", "pip"]) print("[*] Installing dependencies...") for dep in DEPENDENCIES: print(f" -> Installing {dep}...") run_command([pip_exe, "install", dep]) print("[*] Building standalone binary...") # Run PyInstaller (and pray to the god) run_command([python_exe, "-m", "PyInstaller", "--onefile", "--name", "TyChat", ENTRY_POINT], cwd=PROJECT_DIR) dist_dir = os.path.join(PROJECT_DIR, "dist") if os.path.exists(dist_dir): print(f"\n{GREEN}Your executable file is located in {os.path.abspath(dist_dir)}{RESET}") else: print(f"\n[!] Build complete, but 'dist' directory not found at: {dist_dir}.") if __name__ == "__main__": main()