diff --git a/README.md b/README.md index 4883df9..086a6e3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TG WS Proxy -Локальный SOCKS5-прокси для Telegram Desktop, который перенаправляет трафик через WebSocket-соединения к указанным серверам, помогая частично ускорить работу Telegram. - +Локальный SOCKS5-прокси для Telegram Desktop, который перенаправляет трафик через WebSocket-соединения к указанным серверам, помогая частично ускорить работу Telegram. + **Ожидаемый результат аналогичен прокидыванию hosts для Web Telegram**: ускорение загрузки и скачивания файлов, загрузки сообщений и части медиа. image @@ -20,7 +20,37 @@ Telegram Desktop → SOCKS5 (127.0.0.1:1080) → TG WS Proxy → WSS (kws*.web.t ## Установка -### Из исходников +### Fedora (GNOME) + +Для установки в Linux с GNOME выполните: + +### Ubuntu/Debian: + +```bash +# Установите зависимости +sudo apt install libappindicator3-1 python3-tk xclip + +# Запустите скрипт установки +./install.sh +``` +### Fedora / RHEL: + +```bash +# Установите зависимости +sudo dnf install python3-pip python3-tkinter libappindicator-gtk3 + +# Запустите скрипт установки +./install.sh +``` + +После установки приложение появится в меню приложений и будет доступно по команде `tg-ws-proxy`. + +**Для удаления:** +```bash +./uninstall.sh +``` + +### Из исходников (кроссплатформенно) ```bash pip install -r requirements.txt @@ -28,7 +58,7 @@ pip install -r requirements.txt ## Использование -### Tray-приложение (рекомендуется для Windows) +### Tray-приложение (Linux/Windows) ```bash python tg_ws_tray.py @@ -87,7 +117,11 @@ python tg_ws_proxy.py -v ## Конфигурация -Tray-приложение хранит конфигурацию в `%APPDATA%/TgWsProxy/config.json`: +Tray-приложение хранит конфигурацию в: +- **Windows:** `%APPDATA%/TgWsProxy/config.json` +- **Linux:** `~/.config/tgwsproxy/config.json` + +Пример конфигурации: ```json { @@ -100,7 +134,9 @@ Tray-приложение хранит конфигурацию в `%APPDATA%/Tg } ``` -Логи записываются в `%APPDATA%/TgWsProxy/proxy.log`. +Логи записываются в: +- **Windows:** `%APPDATA%/TgWsProxy/proxy.log` +- **Linux:** `~/.config/tgwsproxy/proxy.log` ## Сборка exe @@ -111,6 +147,14 @@ pip install pyinstaller pyinstaller tg_ws_proxy.spec ``` +## Требования для Linux + +Для работы tray-приложения в GNOME требуется: + +```bash +sudo dnf install libappindicator-gtk3 python3-tkinter xclip +``` + ## Дисклеймер Проект частично vibecoded by Opus 4.6. Если вы найдете баг, то создайте Issue с его описанем. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..44190b1 --- /dev/null +++ b/install.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# Установка TG WS Proxy в Fedora (GNOME) + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +APP_NAME="tg-ws-proxy" +APP_DIR="$HOME/.local/share/$APP_NAME" +BIN_DIR="$HOME/.local/bin" +DESKTOP_DIR="$HOME/.local/share/applications" +ICON_DIR="$HOME/.local/share/icons/hicolor" + +echo "🔧 Установка TG WS Proxy..." + +# Создаём директории +mkdir -p "$APP_DIR" +mkdir -p "$BIN_DIR" +mkdir -p "$DESKTOP_DIR" +mkdir -p "$ICON_DIR/scalable/apps" +mkdir -p "$ICON_DIR/512x512/apps" +mkdir -p "$ICON_DIR/256x256/apps" +mkdir -p "$ICON_DIR/128x128/apps" +mkdir -p "$ICON_DIR/64x64/apps" +mkdir -p "$ICON_DIR/32x32/apps" + +# Копируем файлы приложения +echo "📁 Копирование файлов..." +cp "$SCRIPT_DIR/tg_ws_proxy.py" "$APP_DIR/" +cp "$SCRIPT_DIR/tg_ws_tray.py" "$APP_DIR/" +cp "$SCRIPT_DIR/icon.ico" "$APP_DIR/" 2>/dev/null || true + +# Создаём скрипт запуска +echo "📝 Создание скрипта запуска..." +cat > "$BIN_DIR/tg-ws-proxy" << 'EOF' +#!/bin/bash +exec python3 "$HOME/.local/share/tg-ws-proxy/tg_ws_tray.py" "$@" +EOF +chmod +x "$BIN_DIR/tg-ws-proxy" + +# Создаём .desktop файл +echo "🖥️ Создание .desktop файла..." +cat > "$DESKTOP_DIR/tg-ws-proxy.desktop" << EOF +[Desktop Entry] +Version=1.0 +Name=TG WS Proxy +Name[ru]=TG WS Proxy +Comment=Telegram WebSocket Proxy for Desktop +Comment[ru]=Telegram WebSocket Proxy для рабочего стола +Exec=$BIN_DIR/tg-ws-proxy +Icon=tg-ws-proxy +Terminal=false +Type=Application +Categories=Network;Proxy; +Keywords=telegram;proxy;socks; +StartupNotify=false +EOF + +# Создаём иконки из icon.ico или генерируем SVG +echo "🎨 Установка иконок..." + +# Создаём SVG иконку (универсальная) +cat > "$ICON_DIR/scalable/apps/tg-ws-proxy.svg" << 'EOF' + + + T + +EOF + +# Генерируем PNG иконки из SVG с помощью convert (если есть) или создаём заглушки +if command -v convert &> /dev/null; then + for size in 512 256 128 64 32; do + convert -background none \ + "$ICON_DIR/scalable/apps/tg-ws-proxy.svg" \ + -resize "${size}x${size}" \ + "$ICON_DIR/${size}x${size}/apps/tg-ws-proxy.png" 2>/dev/null || true + done +fi + +# Если PNG не создались, создадим символические ссылки на SVG +for size in 512 256 128 64 32; do + if [ ! -f "$ICON_DIR/${size}x${size}/apps/tg-ws-proxy.png" ]; then + ln -sf ../../scalable/apps/tg-ws-proxy.svg \ + "$ICON_DIR/${size}x${size}/apps/tg-ws-proxy.png" 2>/dev/null || true + fi +done + +# Обновляем кэш иконок +if command -v gtk-update-icon-cache &> /dev/null; then + gtk-update-icon-cache -f "$HOME/.local/share/icons/hicolor" 2>/dev/null || true +fi + +# Обновляем базу данных desktop файлов +if command -v update-desktop-database &> /dev/null; then + update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true +fi + +# Устанавливаем зависимости Python +echo "📦 Установка Python зависимостей..." +if command -v pip3 &> /dev/null; then + pip3 install --user -r "$SCRIPT_DIR/requirements.txt" +elif command -v pip &> /dev/null; then + pip install --user -r "$SCRIPT_DIR/requirements.txt" +else + echo "⚠️ pip не найден. Установите зависимости вручную:" + echo " pip install -r requirements.txt" +fi + +echo "" +echo "✅ Установка завершена!" +echo "" +echo "📍 Приложение установлено в: $APP_DIR" +echo "🚀 Запустить можно через меню приложений или командой: tg-ws-proxy" +echo "" +echo "⚠️ Для работы в GNOME может потребзоваться AppIndicator:" +echo " sudo dnf install libappindicator-gtk3" +echo "" diff --git a/tg-ws-proxy.desktop b/tg-ws-proxy.desktop new file mode 100644 index 0000000..78c7db4 --- /dev/null +++ b/tg-ws-proxy.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=1.0 +Name=TG WS Proxy +Name[ru]=TG WS Proxy +Comment=Telegram WebSocket Proxy for Desktop +Comment[ru]=Telegram WebSocket Proxy для рабочего стола +Exec=python3 %h/tg_ws_tray.py +Icon=tg-ws-proxy +Terminal=false +Type=Application +Categories=Network;Proxy; +Keywords=telegram;proxy;socks; +StartupNotify=false diff --git a/tg_ws_tray.py b/tg_ws_tray.py index 99a628b..c728b08 100644 --- a/tg_ws_tray.py +++ b/tg_ws_tray.py @@ -1,10 +1,10 @@ from __future__ import annotations -import ctypes import json import logging import os -import psutil +import platform +import subprocess import sys import threading import time @@ -25,15 +25,33 @@ except ImportError: try: import customtkinter as ctk + from tkinter import messagebox, filedialog except ImportError: ctk = None # type: ignore + messagebox = None # type: ignore + filedialog = None # type: ignore + +try: + import psutil +except ImportError: + psutil = None # type: ignore # Proxy engine import tg_ws_proxy APP_NAME = "TgWsProxy" -APP_DIR = Path(os.environ.get("APPDATA", Path.home())) / APP_NAME +IS_WINDOWS = platform.system() == "Windows" +IS_LINUX = platform.system() == "Linux" + +# Platform-specific paths +if IS_WINDOWS: + APP_DIR = Path(os.environ.get("APPDATA", Path.home())) / APP_NAME +elif IS_LINUX: + APP_DIR = Path.home() / ".config" / APP_NAME.lower() +else: + APP_DIR = Path.home() / f".{APP_NAME.lower()}" + CONFIG_FILE = APP_DIR / "config.json" LOG_FILE = APP_DIR / "proxy.log" FIRST_RUN_MARKER = APP_DIR / ".first_run_done" @@ -212,11 +230,104 @@ def restart_proxy(): def _show_error(text: str, title: str = "TG WS Proxy — Ошибка"): - ctypes.windll.user32.MessageBoxW(0, text, title, 0x10) + """Показать диалог ошибки (кроссплатформенно).""" + if IS_WINDOWS: + try: + import ctypes + ctypes.windll.user32.MessageBoxW(0, text, title, 0x10) + return + except Exception: + pass + # Linux / fallback + if messagebox: + root = ctk.CTk() if ctk else None + if root: + root.withdraw() + messagebox.showerror(title, text, parent=root) + root.destroy() + else: + log.error("%s: %s", title, text) + else: + log.error("%s: %s", title, text) def _show_info(text: str, title: str = "TG WS Proxy"): - ctypes.windll.user32.MessageBoxW(0, text, title, 0x40) + """Показать информационный диалог (кроссплатформенно).""" + if IS_WINDOWS: + try: + import ctypes + ctypes.windll.user32.MessageBoxW(0, text, title, 0x40) + return + except Exception: + pass + # Linux / fallback + if messagebox: + root = ctk.CTk() if ctk else None + if root: + root.withdraw() + messagebox.showinfo(title, text, parent=root) + root.destroy() + else: + log.info("%s: %s", title, text) + else: + log.info("%s: %s", title, text) + + +def _copy_to_clipboard(text: str): + """Copy text to clipboard (кроссплатформенно).""" + if IS_WINDOWS: + try: + import ctypes.wintypes + CF_UNICODETEXT = 13 + kernel32 = ctypes.windll.kernel32 + user32 = ctypes.windll.user32 + + user32.OpenClipboard(0) + user32.EmptyClipboard() + + encoded = text.encode("utf-16-le") + b"\x00\x00" + h = kernel32.GlobalAlloc(0x0042, len(encoded)) + p = kernel32.GlobalLock(h) + ctypes.memmove(p, encoded, len(encoded)) + kernel32.GlobalUnlock(h) + user32.SetClipboardData(CF_UNICODETEXT, h) + user32.CloseClipboard() + return + except Exception as exc: + log.error("Windows clipboard failed: %s", exc) + + # Linux: try xclip or xsel + if IS_LINUX: + for cmd in [["xclip", "-selection", "clipboard"], + ["xsel", "--clipboard", "--input"]]: + try: + proc = subprocess.Popen( + cmd, stdin=subprocess.PIPE, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + proc.communicate(text.encode("utf-8")) + if proc.returncode == 0: + log.debug("Copied via %s", cmd[0]) + return + except Exception: + continue + log.warning("xclip/xsel not available for clipboard") + + # Fallback: try tkinter clipboard + try: + import tkinter as tk + root = tk.Tk() + root.withdraw() + root.clipboard_clear() + root.clipboard_append(text) + root.update() + root.destroy() + log.debug("Copied via tkinter clipboard") + return + except Exception: + pass + + log.error("Failed to copy to clipboard on this platform") + def _on_open_in_telegram(icon=None, item=None): @@ -393,10 +504,26 @@ def _edit_config_dialog(): root.mainloop() +def _open_file_platform_specific(path: Path): + """Открыть файл в стандартном приложении платформы.""" + try: + if IS_WINDOWS: + os.startfile(str(path)) + elif IS_LINUX: + # для xdg-open (freedesktop standard) + subprocess.Popen(["xdg-open", str(path)]) + else: + # для macOS + subprocess.Popen(["open", str(path)]) + except Exception as exc: + log.error("Failed to open file: %s", exc) + _show_error(f"Не удалось открыть файл:\n{exc}") + + def _on_open_logs(icon=None, item=None): log.info("Opening log file: %s", LOG_FILE) if LOG_FILE.exists(): - os.startfile(str(LOG_FILE)) + _open_file_platform_specific(LOG_FILE) else: _show_info("Файл логов ещё не создан.", "TG WS Proxy") @@ -589,9 +716,10 @@ def main(): _show_info("Приложение уже запущено.", os.path.basename(sys.argv[0])) return - # Hide console window if running as frozen exe - if getattr(sys, "frozen", False): + # Hide console window if running as frozen exe on Windows + if getattr(sys, "frozen", False) and IS_WINDOWS: try: + import ctypes ctypes.windll.user32.ShowWindow( ctypes.windll.kernel32.GetConsoleWindow(), 0) except Exception: diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..6041a35 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Удаление TG WS Proxy из Fedora + +set -e + +APP_NAME="tg-ws-proxy" +APP_DIR="$HOME/.local/share/$APP_NAME" +BIN_DIR="$HOME/.local/bin" +DESKTOP_DIR="$HOME/.local/share/applications" +ICON_DIR="$HOME/.local/share/icons/hicolor" + +echo "🗑️ Удаление TG WS Proxy..." + +# Удаляем файлы приложения +rm -rf "$APP_DIR" + +# Удаляем скрипт запуска +rm -f "$BIN_DIR/tg-ws-proxy" + +# Удаляем .desktop файл +rm -f "$DESKTOP_DIR/tg-ws-proxy.desktop" + +# Удаляем иконки +rm -f "$ICON_DIR/scalable/apps/tg-ws-proxy.svg" +for size in 512 256 128 64 32; do + rm -f "$ICON_DIR/${size}x${size}/apps/tg-ws-proxy.png" +done + +# Обновляем кэш иконок +if command -v gtk-update-icon-cache &> /dev/null; then + gtk-update-icon-cache -f "$HOME/.local/share/icons/hicolor" 2>/dev/null || true +fi + +# Обновляем базу данных desktop файлов +if command -v update-desktop-database &> /dev/null; then + update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true +fi + +# Удаляем конфиг и логи (опционально) +if [ -d "$HOME/.config/tgwsproxy" ]; then + read -p "📁 Удалить конфиг и логи? (~/.config/tgwsproxy) [y/N]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$HOME/.config/tgwsproxy" + echo "🗑️ Конфиг и логи удалены" + fi +fi + +echo "" +echo "✅ TG WS Proxy удалён!"