feat: split out GoTelegram project

This commit is contained in:
Андрей Бобырев
2026-06-06 10:57:31 +03:00
commit f6eb56b88d
27 changed files with 32684 additions and 0 deletions

161
gotelegram-bot/README.md Normal file
View File

@@ -0,0 +1,161 @@
# goTelegram Pro v2.5.0 Bot
Production-quality Telegram bot for managing MTProxy (telemt engine) on Linux servers.
## Features
- **Complete CLI Feature Parity** - All menu items from CLI version
- Install (Quick/Stealth modes)
- Status monitoring
- Proxy link generation
- Share with QR codes
- Service restart
- Logs viewing
- Mode/template changes
- Backup/restore
- telemt updates
- Website/SSL management
- Remove installation
- Promotional links
- **Template Browsing** - Browse categories → templates → preview → install
- **Per-user MTProxy Keys** - Manage telemt `[access.users]` from inline bot menus
- **Per-user QR Import** - Show QR codes for every Telegram proxy key
- **Local Web Admin** - Shows SSH tunnel instructions for the 127.0.0.1:1984 dashboard
- **V1 Migration** - Detects old mtg Docker container and offers migration
- **Access Control** - ALLOWED_IDS from .env
- **Async/Await** - Full async support via python-telegram-bot v21+
- **Inline Keyboards** - Modern UI with callback-based navigation
- **Shell Integration** - Executes system commands via asyncio subprocess
- **Error Handling** - Production-ready error handling
## Installation
Recommended installation path is the main CLI menu:
```bash
gotelegram
```
Then choose `12) Telegram-bot` → install/update. On repeat goTelegram Pro bootstrap/update, an already installed bot is refreshed automatically: code, i18n files and requirements are copied to `/opt/gotelegram-bot`, `.env` is preserved, dependencies are checked and `gotelegram-bot` is restarted.
### Prerequisites
- Python 3.8+
- Linux system with systemd
- telemt installed and running
- Telegram Bot Token from @BotFather
### Setup
1. Install dependencies:
```bash
pip install -r requirements.txt
```
2. Create .env file:
```bash
cp config.example.env .env
# Edit .env and set your BOT_TOKEN
nano .env
```
3. (Optional) Restrict access to specific users:
```bash
# Edit .env and uncomment ALLOWED_IDS
# ALLOWED_IDS=123456789,987654321
```
### Running the Bot
```bash
python3 bot.py
```
For systemd service:
```bash
[Unit]
Description=goTelegram Pro Bot
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/gotelegram-bot
ExecStart=/opt/gotelegram-bot/venv/bin/python /opt/gotelegram-bot/bot.py
Restart=always
RestartSec=5
Environment=PATH=/opt/gotelegram-bot/venv/bin:/usr/bin
[Install]
WantedBy=multi-user.target
```
## Configuration
### .env Variables
- `BOT_TOKEN` - Telegram bot token (required)
- `ALLOWED_IDS` - Comma-separated user IDs (optional, all users allowed if empty)
- `BOT_LANG` - Default language inherited from goTelegram Pro install language
### System Paths
- `GOTELEGRAM_CONFIG` - `/opt/gotelegram/config.json`
- `TELEMT_CONFIG` - `/etc/telemt/config.toml`
- `TELEMT_SERVICE` - `telemt` (systemd service name)
- `WEBSITE_ROOT` - `/var/www/gotelegram-site`
- `BACKUP_DIR` - `/opt/gotelegram/backups`
- `BACKUP_SCHEDULE_FILE` - `/opt/gotelegram/backup_schedule.json`
- `TEMPLATES_CATALOG` - `/opt/gotelegram/templates_catalog.json`
## Architecture
### Single File Design
All functionality in one `bot.py` for simplicity and ease of deployment.
### Command Handlers
- `/start` - Main menu
- `/help` - Help text
- `/status` - Quick status
- `/logs` - Recent logs
### Callback Handlers
Organized by feature:
- Installation (quick/stealth modes)
- Status monitoring
- Backup/restore
- Backup schedules: off, daily, weekly, monthly
- SSL management
- Updates
- Removal
### Shell Integration
Async subprocess wrapper:
```python
code, stdout, stderr = await sh("command", "arg1", "arg2")
```
## Callback Data Convention
- `menu_*` - Menu items
- `install_mode_*` - Install options
- `quick_dom_*` - Domain selection
- `stealth_cat_*` - Template categories
- `stealth_tpl_*` - Template selection
- `stealth_confirm_*` - Confirm installation
- `backup_*` - Backup operations
- `ssl_*` - SSL operations
- `restore_backup_*` - Restore operations
## Credits
- **telemt** - MTProxy engine foundation
- **HTML5UP** - Beautiful web templates
- **Learning Zone** - Educational resources
- **Start Bootstrap** - Bootstrap framework
- **Community** - Your feedback and support
## License
goTelegram Pro v2.5.0 - Open source community project

3361
gotelegram-bot/bot.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
# goTelegram Pro v2.5.0 Bot Configuration
# Copy this to .env and fill in your values
# Telegram Bot Token from @BotFather
BOT_TOKEN=your_bot_token_from_@BotFather
# Comma-separated list of allowed Telegram user IDs
# Leave empty to allow all users
# ALLOWED_IDS=123456789,987654321

167
gotelegram-bot/i18n.py Normal file
View File

@@ -0,0 +1,167 @@
"""
goTelegram Pro v2.5.0 Bot — i18n module
Provides per-user language preferences and a simple t()/tf() API.
Usage:
from i18n import t, tf, set_user_lang, get_user_lang, get_language_name
msg = t(user_id, "menu_status")
msg = tf(user_id, "backup_created_fmt", filename)
Language files live next to this module in lang/<code>.json.
Per-user choices are persisted to USER_LANG_FILE (one JSON dict: user_id -> code).
"""
import json
import logging
import os
from pathlib import Path
from typing import Dict, Optional
logger = logging.getLogger(__name__)
# ── Paths ─────────────────────────────────────────────────────────────────
_MODULE_DIR = Path(__file__).resolve().parent
LANG_DIR = _MODULE_DIR / "lang"
USER_LANG_FILE = Path("/opt/gotelegram-bot/user_langs.json")
GOTELEGRAM_CONFIG = Path("/opt/gotelegram/config.json")
GOTELEGRAM_LANG_MARKER = Path("/opt/gotelegram/.language")
# Supported codes; keep in sync with lang/*.json
SUPPORTED_LANGS = ("en", "ru")
def _detect_default_lang() -> str:
candidates = []
try:
if GOTELEGRAM_CONFIG.exists():
with open(GOTELEGRAM_CONFIG, "r", encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, dict):
candidates.extend([data.get("language"), data.get("lang")])
except Exception as e:
logger.warning("failed to read goTelegram Pro language config: %s", e)
try:
if GOTELEGRAM_LANG_MARKER.exists():
candidates.append(GOTELEGRAM_LANG_MARKER.read_text(encoding="utf-8").strip()[:2])
except Exception as e:
logger.warning("failed to read goTelegram Pro language marker: %s", e)
candidates.append(os.getenv("BOT_LANG", ""))
for raw in candidates:
code = str(raw or "").strip().lower()
if code in SUPPORTED_LANGS:
return code
return "en"
DEFAULT_LANG = _detect_default_lang()
LANG_NAMES = {
"en": "English",
"ru": "Русский",
}
# ── Caches ────────────────────────────────────────────────────────────────
_LANG_CACHE: Dict[str, Dict[str, str]] = {}
_USER_LANGS: Dict[int, str] = {}
_USER_LANGS_LOADED = False
def _load_lang_file(code: str) -> Dict[str, str]:
"""Load lang/<code>.json into the cache and return it."""
if code in _LANG_CACHE:
return _LANG_CACHE[code]
path = LANG_DIR / f"{code}.json"
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
if not isinstance(data, dict):
raise ValueError("lang file must contain a top-level object")
_LANG_CACHE[code] = data
return data
except FileNotFoundError:
logger.warning("lang file not found: %s", path)
except Exception as e:
logger.warning("failed to load %s: %s", path, e)
_LANG_CACHE[code] = {}
return _LANG_CACHE[code]
def _load_user_langs() -> None:
"""Load per-user language preferences from USER_LANG_FILE."""
global _USER_LANGS, _USER_LANGS_LOADED
_USER_LANGS_LOADED = True
try:
if USER_LANG_FILE.exists():
with open(USER_LANG_FILE, "r", encoding="utf-8") as f:
raw = json.load(f)
if isinstance(raw, dict):
_USER_LANGS = {
int(k): v for k, v in raw.items()
if isinstance(v, str) and v in SUPPORTED_LANGS
}
except Exception as e:
logger.warning("failed to load user_langs: %s", e)
_USER_LANGS = {}
def _save_user_langs() -> None:
"""Persist per-user language preferences."""
try:
USER_LANG_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(USER_LANG_FILE, "w", encoding="utf-8") as f:
json.dump(
{str(k): v for k, v in _USER_LANGS.items()},
f, ensure_ascii=False, indent=2,
)
except Exception as e:
logger.warning("failed to save user_langs: %s", e)
# ── Public API ────────────────────────────────────────────────────────────
def get_user_lang(user_id: Optional[int]) -> str:
"""Return the language code for the given user (or DEFAULT_LANG)."""
if not _USER_LANGS_LOADED:
_load_user_langs()
if user_id is None:
return _detect_default_lang()
return _USER_LANGS.get(int(user_id), _detect_default_lang())
def set_user_lang(user_id: int, code: str) -> bool:
"""Set the per-user language preference and persist it."""
if not _USER_LANGS_LOADED:
_load_user_langs()
code = (code or "").strip().lower()
if code not in SUPPORTED_LANGS:
return False
_USER_LANGS[int(user_id)] = code
_save_user_langs()
return True
def get_language_name(code: str) -> str:
return LANG_NAMES.get(code, code)
def t(user_id: Optional[int], key: str, default: Optional[str] = None) -> str:
"""Translate key for the given user. Falls back to English, then default/key."""
code = get_user_lang(user_id)
table = _load_lang_file(code)
if key in table:
return table[key]
if code != "en":
en_table = _load_lang_file("en")
if key in en_table:
return en_table[key]
return default if default is not None else key
def tf(user_id: Optional[int], key: str, *args, default: Optional[str] = None) -> str:
"""Format a translated string with positional args using %-formatting."""
template = t(user_id, key, default=default)
try:
return template % args if args else template
except (TypeError, ValueError):
return template

118
gotelegram-bot/lang/en.json Normal file
View File

@@ -0,0 +1,118 @@
{
"lang_english": "English",
"lang_russian": "Русский",
"lang_title": "🌐 Language",
"lang_current": "Current language: %s",
"lang_saved": "Language saved: %s",
"lang_choose": "Choose your language:",
"welcome_title": "goTelegram Pro v%s",
"welcome_subtitle": "🤖 MTProxy Management Bot",
"welcome_powered": "Powered by telemt engine",
"welcome_prompt": "Select an action from the menu below:",
"waiting_admin_title": "👋 Hi, %s!",
"waiting_admin_body": "The bot is not configured yet.\nYour Telegram ID: <code>%s</code>\n\nAssign you as administrator?",
"btn_yes": "✅ Yes",
"btn_no": "❌ No",
"access_denied": "⛔ Access denied.\nYour ID: <code>%s</code>",
"help_title": "goTelegram Pro Bot — Commands",
"help_lines": "/start — Main menu\n/help — This help\n/status — Quick status\n/logs — Latest logs\n/lang — Change language\n/addadmin ID — Add admin\n/deladmin ID — Remove admin\n\nUse the menu buttons for other operations.",
"menu_install": "⚙️ Install",
"menu_status": "📊 Status",
"menu_link": "🔗 Link",
"menu_share": "📤 Share",
"menu_restart": "🔄 Restart",
"menu_logs": "📋 Logs",
"menu_change": "⚡ Change Mode/Template",
"menu_backup": "💾 Backup",
"menu_restore": "↩️ Restore",
"menu_update": "📡 Update telemt",
"menu_website": "🌐 Website/SSL",
"menu_promo": "🎁 Promo",
"menu_stats": "📊 Traffic Stats",
"menu_users": "🔑 Keys",
"menu_admin_web": "🖥 Web Admin",
"menu_remove": "🗑️ Remove",
"menu_admins": "👤 Admins",
"menu_credits": " Credits",
"menu_language": "🌐 Language",
"menu_close": "❌ Close",
"btn_back": "⬅️ Back",
"btn_refresh": "🔄 Refresh",
"btn_cancel": "❌ Cancel",
"btn_confirm": "✅ Confirm",
"status_checking": "⏳ Checking status...",
"status_title": "📊 Current Status",
"status_service": "Service",
"status_running": "✅ Running",
"status_stopped": "❌ Stopped",
"status_telemt": "Telemt",
"status_mode": "Mode",
"status_template": "Template",
"status_domain": "Domain",
"status_port": "Port",
"status_listen_port": "Listen Port",
"status_tls_domain": "TLS Domain",
"logs_failed": "Failed to retrieve logs",
"link_fetching": "⏳ Fetching link...",
"link_unavailable": "Link unavailable (proxy not installed?)",
"share_title": "📤 Share Proxy",
"share_body": "Send this link to your client:",
"restart_title": "🔄 Restart",
"restart_progress": "⏳ Restarting telemt...",
"restart_ok": "✅ telemt restarted",
"restart_fail": "❌ Restart failed",
"install_title": "⚙️ Install / Update",
"install_pick_mode": "Select installation mode:",
"install_mode_lite": "🚀 Lite (quick, no site)",
"install_mode_pro": "🎨 Pro (stealth + website)",
"backup_title": "💾 Backup",
"backup_creating": "⏳ Creating backup...",
"backup_created_fmt": "✅ Backup created: %s",
"backup_failed": "❌ Backup creation failed",
"backup_list_title": "Available backups:",
"backup_none": "No backups yet",
"backup_restore_title": "↩️ Restore backup",
"backup_restoring": "⏳ Restoring...",
"backup_restored": "✅ Backup restored",
"update_title": "📡 Update telemt",
"update_progress": "⏳ Updating telemt binary...",
"update_ok": "✅ telemt updated",
"update_fail": "❌ Update failed",
"website_title": "🌐 Website / SSL",
"ssl_renew_progress": "⏳ Renewing SSL...",
"ssl_renewed": "✅ SSL renewed",
"ssl_renew_fail": "❌ SSL renew failed",
"ssl_status_title": "🔒 SSL Status",
"remove_title": "🗑️ Remove",
"remove_warn": "⚠️ This will stop and remove telemt, nginx site and configs. Continue?",
"remove_progress": "⏳ Removing...",
"remove_done": "✅ Removed",
"admins_title": "👤 Administrators",
"admins_list": "Current admin IDs:",
"admins_empty": "No admins configured",
"promo_title": "🎁 Promo",
"credits_title": " Credits",
"cg_title": "🔗 Custom Git Template",
"cg_ask_url": "Send me the HTTPS git URL of a static site repository.\nOptionally append <code>@branch</code>.",
"cg_cloning": "⏳ Cloning %s ...",
"cg_invalid": "❌ Invalid URL. Only HTTPS git URLs are allowed.",
"cg_timeout": "❌ Clone timeout (repository too large or slow)",
"cg_too_big": "❌ Repository too large (>100MB)",
"cg_no_index": "❌ No index.html found in repository",
"cg_ok_fmt": "✅ Custom template downloaded: %s"
}

118
gotelegram-bot/lang/ru.json Normal file
View File

@@ -0,0 +1,118 @@
{
"lang_english": "English",
"lang_russian": "Русский",
"lang_title": "🌐 Язык",
"lang_current": "Текущий язык: %s",
"lang_saved": "Язык сохранён: %s",
"lang_choose": "Выберите язык:",
"welcome_title": "goTelegram Pro v%s",
"welcome_subtitle": "🤖 Бот управления MTProxy",
"welcome_powered": "На базе движка telemt",
"welcome_prompt": "Выберите действие в меню ниже:",
"waiting_admin_title": "👋 Привет, %s!",
"waiting_admin_body": "Бот ещё не настроен.\nВаш Telegram ID: <code>%s</code>\n\nНазначить вас администратором?",
"btn_yes": "✅ Да",
"btn_no": "❌ Нет",
"access_denied": "⛔ Доступ запрещён.\nВаш ID: <code>%s</code>",
"help_title": "goTelegram Pro Bot — Команды",
"help_lines": "/start — Главное меню\n/help — Эта справка\n/status — Быстрый статус\n/logs — Последние логи\n/lang — Сменить язык\n/addadmin ID — Добавить админа\n/deladmin ID — Удалить админа\n\nИспользуйте кнопки меню для остальных операций.",
"menu_install": "⚙️ Установить",
"menu_status": "📊 Статус",
"menu_link": "🔗 Ссылка",
"menu_share": "📤 Поделиться",
"menu_restart": "🔄 Перезапуск",
"menu_logs": "📋 Логи",
"menu_change": "⚡ Сменить режим/шаблон",
"menu_backup": "💾 Бекап",
"menu_restore": "↩️ Восстановить",
"menu_update": "📡 Обновить telemt",
"menu_website": "🌐 Сайт/SSL",
"menu_promo": "🎁 Промо",
"menu_stats": "📊 Трафик",
"menu_users": "🔑 Ключи",
"menu_admin_web": "🖥 Веб-админка",
"menu_remove": "🗑️ Удалить",
"menu_admins": "👤 Админы",
"menu_credits": " О проекте",
"menu_language": "🌐 Язык",
"menu_close": "❌ Закрыть",
"btn_back": "⬅️ Назад",
"btn_refresh": "🔄 Обновить",
"btn_cancel": "❌ Отмена",
"btn_confirm": "✅ Подтвердить",
"status_checking": "⏳ Проверяю статус...",
"status_title": "📊 Текущий статус",
"status_service": "Сервис",
"status_running": "✅ Работает",
"status_stopped": "❌ Остановлен",
"status_telemt": "Telemt",
"status_mode": "Режим",
"status_template": "Шаблон",
"status_domain": "Домен",
"status_port": "Порт",
"status_listen_port": "Порт прослушивания",
"status_tls_domain": "TLS домен",
"logs_failed": "Не удалось получить логи",
"link_fetching": "⏳ Получаю ссылку...",
"link_unavailable": "Ссылка недоступна (прокси не установлен?)",
"share_title": "📤 Поделиться прокси",
"share_body": "Отправьте эту ссылку клиенту:",
"restart_title": "🔄 Перезапуск",
"restart_progress": "⏳ Перезапускаю telemt...",
"restart_ok": "✅ telemt перезапущен",
"restart_fail": "❌ Ошибка перезапуска",
"install_title": "⚙️ Установка / Обновление",
"install_pick_mode": "Выберите режим установки:",
"install_mode_lite": "🚀 Lite (быстро, без сайта)",
"install_mode_pro": "🎨 Pro (маскировка + сайт)",
"backup_title": "💾 Бекап",
"backup_creating": "⏳ Создаю бекап...",
"backup_created_fmt": "✅ Бекап создан: %s",
"backup_failed": "❌ Не удалось создать бекап",
"backup_list_title": "Доступные бекапы:",
"backup_none": "Бекапов пока нет",
"backup_restore_title": "↩️ Восстановление бекапа",
"backup_restoring": "⏳ Восстанавливаю...",
"backup_restored": "✅ Бекап восстановлен",
"update_title": "📡 Обновление telemt",
"update_progress": "⏳ Обновляю telemt...",
"update_ok": "✅ telemt обновлён",
"update_fail": "❌ Ошибка обновления",
"website_title": "🌐 Сайт / SSL",
"ssl_renew_progress": "⏳ Обновляю SSL...",
"ssl_renewed": "✅ SSL обновлён",
"ssl_renew_fail": "❌ Ошибка обновления SSL",
"ssl_status_title": "🔒 Статус SSL",
"remove_title": "🗑️ Удаление",
"remove_warn": "⚠️ Это остановит и удалит telemt, сайт nginx и конфиги. Продолжить?",
"remove_progress": "⏳ Удаляю...",
"remove_done": "✅ Удалено",
"admins_title": "👤 Администраторы",
"admins_list": "Текущие ID админов:",
"admins_empty": "Админы не настроены",
"promo_title": "🎁 Промо",
"credits_title": " О проекте",
"cg_title": "🔗 Свой git-шаблон",
"cg_ask_url": "Отправьте HTTPS git-URL репозитория со статическим сайтом.\nПри желании добавьте <code>@branch</code>.",
"cg_cloning": "⏳ Клонирую %s ...",
"cg_invalid": "❌ Неверный URL. Разрешены только HTTPS git-URL.",
"cg_timeout": "❌ Таймаут клонирования (репозиторий слишком большой или медленный)",
"cg_too_big": "❌ Репозиторий слишком большой (>100МБ)",
"cg_no_index": "❌ В репозитории не найден index.html",
"cg_ok_fmt": "✅ Свой шаблон загружен: %s"
}

View File

@@ -0,0 +1,3 @@
python-telegram-bot>=21.0
python-dotenv>=1.0.0
toml>=0.10.2