max-telegram-bridge-bot/helpmenu.go
Andrey Lugovskoy f57105d2b6
Some checks failed
Build / build (push) Has been cancelled
crosspost: fix long album caption + strip custom emoji and whitespace padding
- MAX→TG album: caption over Telegram's 1024 media-group limit is no longer lost —
  the album is sent without an inline caption and the full text follows as a
  separate message (sendMaxAlbumToTg, covers both direct and queued delivery).
- Forwarded text: strip Telegram custom_emoji (MAX can't render them; the fallback
  glyph only littered the copy) in tgEntitiesToHTML, and collapse whitespace padding
  (runs of spaces/nbsp, trailing spaces, 3+ blank lines) in crosspost captions —
  cuts bloated length (MAX ~4000 char limit) and fixes ugly gaps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ajcn7YhgeexPwbfrUNMj8u
2026-07-03 13:00:46 +04:00

163 lines
9.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"strings"
)
// --- /start и /help как меню ---
// Вместо «портянки» по /start показываем короткий интро + inline-кнопки. Детали
// (как связать группы/каналы, команды, FAQ) — за кнопками (callback help:*),
// редактируем то же сообщение. Кнопки «добавить в группу/канал» — deep-link Telegram.
// tgStartMenu — короткий интро + главное меню.
func (b *Bridge) tgStartMenu() (string, *InlineKeyboardMarkup) {
text := "🔗 <b>Мост между Telegram и MAX</b>\n\n" +
"Пишете в одном мессенджере — сообщение автоматически появляется в другом. " +
"Группы и каналы: текст, фото, видео, голосовые, файлы.\n\n" +
"🔒 Бот не хранит тексты сообщений — только ID для синхронизации правок, " +
"и те удаляются через 30 дней.\n\n" +
"Выберите действие 👇"
kb := NewInlineKeyboard(
NewInlineRow(
InlineKeyboardButton{Text: " В группу Telegram", URL: b.cfg.TgBotURL + "?startgroup=true"},
InlineKeyboardButton{Text: " В канал Telegram", URL: b.cfg.TgBotURL + "?startchannel=true"},
),
NewInlineRow(InlineKeyboardButton{Text: "🤖 Добавить MAX-бота", URL: b.cfg.MaxBotURL}),
NewInlineRow(NewInlineButton("📋 Как связать группы", "help:groups")),
NewInlineRow(NewInlineButton("🧵 Темы форума", "help:threads")),
NewInlineRow(NewInlineButton("📡 Кросспостинг каналов", "help:channels")),
NewInlineRow(
NewInlineButton("⌨️ Команды", "help:cmds"),
NewInlineButton("❓ Вопросы", "help:faq"),
),
)
// Расширенные функции (импорт/комменты/антиспам/PRO) приходят от расширения через
// extraHelp — в публичном коде их не хардкодим. Кнопка только если расширение есть.
if strings.TrimSpace(b.extraHelp) != "" {
kb.Rows = append(kb.Rows, NewInlineRow(NewInlineButton("✨ Ещё: импорт, PRO, антиспам", "help:more")))
}
// Если задана подробная инструкция (HELP_FILE/help.html) — кнопка на полный текст.
if customHelp() != "" {
kb.Rows = append(kb.Rows, NewInlineRow(NewInlineButton("📖 Полная инструкция", "help:full")))
}
return text, kb
}
// helpBackKb — клавиатура с одной кнопкой «назад в меню».
func helpBackKb() *InlineKeyboardMarkup {
return NewInlineKeyboard(NewInlineRow(NewInlineButton("⬅️ Назад", "help:home")))
}
func (b *Bridge) helpGroupsText() string {
return "📋 <b>Как связать группы</b>\n\n" +
"1. Добавьте бота в обе группы:\n" +
" • Telegram — кнопка «➕ В группу Telegram»\n" +
" • MAX — " + b.cfg.MaxBotURL + "\n" +
" (если поиск в MAX не находит по полному имени — введите имя <b>без суффикса</b> <code>_bot</code>)\n" +
"2. В MAX сделайте бота администратором группы <b>с правом «Доступ к сообщениям»</b> " +
"(читать все сообщения). Без этого права бот не видит команды и сообщения — связка не сработает.\n" +
"3. В Telegram — администратором, только если группа с темами (форум). " +
"В обычных группах не требуется.\n" +
"4. В одной из групп отправьте <code>/bridge</code> — бот выдаст ключ.\n" +
"5. Отправьте <code>/bridge ключ</code> во второй группе.\n" +
"6. Готово — сообщения зеркалятся в обе стороны." + b.reserveBotHint()
}
func (b *Bridge) helpThreadsText() string {
return "🧵 <b>Темы форума (threads)</b>\n\n" +
"Если TG-группа — форум с темами (topics):\n\n" +
"<code>/thread</code> — выполните <b>внутри нужной темы</b>: сообщения из связанной " +
"MAX-группы будут приходить именно в эту тему.\n\n" +
"<code>/thread_bridge</code> — связать <b>отдельную</b> тему с <b>отдельной</b> MAX-группой: " +
"выполните в теме → бот выдаст ключ → в MAX-группе отправьте <code>/thread_bridge ключ</code>.\n\n" +
"<code>/thread_unbridge</code> — разорвать связку темы.\n\n" +
"⚠️ При обычном <code>/bridge</code> на всю группу в MAX уходят сообщения из ВСЕХ тем. " +
"Чтобы зеркалить только одну тему: <code>/unbridge</code> на группе → <code>/thread_bridge</code> в нужной теме."
}
func (b *Bridge) helpChannelsText() string {
return "📡 <b>Кросспостинг каналов</b>\n\n" +
"1. Добавьте бота администратором (с правом постинга) в оба канала:\n" +
" • Telegram — " + b.cfg.TgBotURL + "\n" +
" • MAX — " + b.cfg.MaxBotURL + "\n" +
"2. Перешлите пост из TG-канала в личку TG-боту.\n" +
"3. Бот покажет ID канала — скопируйте.\n" +
"4. В личке MAX-бота (" + b.cfg.MaxBotURL + ") отправьте: <code>/crosspost ID</code>\n" +
"5. Перешлите пост из MAX-канала туда же — готово!\n\n" +
"Управление: <code>/crosspost</code> — список связок с кнопками, либо перешлите " +
"пост из связанного канала." + b.reserveBotHint()
}
func (b *Bridge) helpCmdsText() string {
return "⌨️ <b>Команды</b>\n\n" +
"<code>/bridge</code> — создать ключ для связки групп\n" +
"<code>/bridge ключ</code> — связать эту группу по ключу\n" +
"<code>/bridge prefix on|off</code> — префикс [TG]/[MAX]\n" +
"<code>/pause</code> — поставить связку на паузу (не зеркалить, не удаляя)\n" +
"<code>/unpause</code> — возобновить пересылку\n" +
"<code>/unbridge</code> — удалить связку\n" +
"<code>/thread</code> — направить MAX → текущий топик (форум)\n" +
"<code>/thread_bridge</code> — связать тред с отдельной MAX-группой\n" +
"<code>/thread_unbridge</code> — разорвать связку треда\n" +
"<code>/crosspost</code> — связки каналов и управление"
}
func (b *Bridge) helpFaqText() string {
return "❓ <b>Частые вопросы</b>\n\n" +
"<b>Бот хранит мои сообщения?</b>\n" +
"Нет. Только ID для синхронизации правок, удаляются через 30 дней.\n\n" +
"<b>Что пересылается?</b>\n" +
"Текст, фото, видео, голосовые, документы, альбомы, правки.\n\n" +
"<b>Нужно ли делать бота админом?</b>\n" +
"В MAX — да. В Telegram — только в форум-группах и в каналах (для постинга).\n\n" +
"<b>Сообщения не доходят?</b>\n" +
"Проверьте, что бот добавлен в нужный чат и является администратором.\n\n" +
"💬 Поддержка: https://t.me/+0ucbOj4wBwQzMWNi"
}
// handleHelpMenuCallback — навигация по меню /start (help:*). Редактирует сообщение.
// Возвращает true, если callback обработан здесь.
func (b *Bridge) handleHelpMenuCallback(ctx context.Context, query *TGCallback, data string) bool {
if !strings.HasPrefix(data, "help:") {
return false
}
chatID := query.Message.Chat.ID
msgID := query.Message.MessageID
var text string
var kb *InlineKeyboardMarkup
switch data {
case "help:home":
text, kb = b.tgStartMenu()
case "help:groups":
text, kb = b.helpGroupsText(), helpBackKb()
case "help:threads":
text, kb = b.helpThreadsText(), helpBackKb()
case "help:channels":
text, kb = b.helpChannelsText(), helpBackKb()
case "help:cmds":
text, kb = b.helpCmdsText(), helpBackKb()
case "help:faq":
text, kb = b.helpFaqText(), helpBackKb()
case "help:more":
if h := strings.TrimSpace(b.extraHelp); h != "" {
text, kb = h, helpBackKb()
} else {
text, kb = b.tgStartMenu()
}
case "help:full":
if ch := customHelp(); ch != "" {
text, kb = ch, helpBackKb()
} else {
text, kb = b.tgStartMenu()
}
default:
b.tg.AnswerCallback(ctx, query.ID, "")
return true
}
b.tg.EditMessageText(ctx, chatID, msgID, text, &SendOpts{ParseMode: "HTML", ReplyMarkup: kb})
b.tg.AnswerCallback(ctx, query.ID, "")
return true
}