mirror of
https://github.com/BEARlogin/max-telegram-bridge-bot.git
synced 2026-04-28 03:39:46 +00:00
Preserve links in TG→MAX crossposts; deliver text when video fails
Two issues reported by a user via the bridge: 1. Links vanish on TG channel → MAX crosspost. formatTgCrosspostCaption returned raw text and forwardTgToMax dropped markdown format for the crosspost branch, so text_link entities became plain text. Now formatTgCrosspostCaption runs tgEntitiesToMarkdown, and forwardTgToMax always uses markdown. Media group flusher also skips the second conversion for crosspost items (caption is already markdown) and keeps markdown format. 2. When a channel video is too big for Bot API getFile (e.g. HD > 2 GB on local server), the whole post was dropped — even the caption text was lost. Video upload failure no longer returns from forwardTgToMax; the fallback branch appends a "[Видео]" marker so subscribers in MAX at least get the text and know a video was attached but not relayed. The fallback condition now checks presence of any media instead of only msg.Text == "" (it missed video-with-caption posts) and also covers Animation and Photo. Tradeoff: crosspost replacements now operate on markdown text. URL- and phrase-level replacements keep working; regex rules touching markdown characters (_, *, [, ]) may need adjustment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
49af1b6432
commit
63b95e4c8c
3 changed files with 29 additions and 14 deletions
|
|
@ -84,13 +84,17 @@ func formatMaxCaption(upd *maxschemes.MessageCreatedUpdate, prefix, newline bool
|
|||
return formatAttribution(name, text, newline)
|
||||
}
|
||||
|
||||
// formatTgCrosspostCaption — для кросспостинга каналов (без attribution и префиксов)
|
||||
// formatTgCrosspostCaption — для кросспостинга каналов (без attribution и префиксов).
|
||||
// Конвертирует entities в markdown, чтобы ссылки и форматирование сохранились
|
||||
// при пересылке в MAX. Replacements, если настроены, применяются поверх markdown.
|
||||
func formatTgCrosspostCaption(msg *TGMessage) string {
|
||||
text := msg.Text
|
||||
entities := msg.Entities
|
||||
if text == "" {
|
||||
text = msg.Caption
|
||||
entities = msg.CaptionEntities
|
||||
}
|
||||
return text
|
||||
return tgEntitiesToMarkdown(text, entities)
|
||||
}
|
||||
|
||||
// formatMaxCrosspostCaption — для кросспостинга каналов (без attribution и префиксов)
|
||||
|
|
|
|||
|
|
@ -114,14 +114,17 @@ func (b *Bridge) flushMediaGroup(ctx context.Context, groupID string) {
|
|||
}
|
||||
}
|
||||
|
||||
// Форматируем caption
|
||||
// Форматируем caption.
|
||||
// Для crosspost caption уже в markdown (см. formatTgCrosspostCaption),
|
||||
// повторно конвертировать нельзя — entities ссылаются на offsets сырого текста.
|
||||
mdCaption := caption
|
||||
if entities != nil {
|
||||
if entities != nil && !isCrosspost {
|
||||
mdCaption = tgEntitiesToMarkdown(caption, entities)
|
||||
}
|
||||
|
||||
m := maxbot.NewMessage().SetChat(maxChatID).SetText(mdCaption)
|
||||
if mdCaption != caption {
|
||||
// Для crosspost caption уже markdown; для bridge — markdown если были entities.
|
||||
if isCrosspost || mdCaption != caption {
|
||||
m.SetFormat("markdown")
|
||||
}
|
||||
if replyTo != "" {
|
||||
|
|
|
|||
26
telegram.go
26
telegram.go
|
|
@ -732,7 +732,7 @@ func (b *Bridge) forwardTgToMax(ctx context.Context, msg *TGMessage, maxChatID i
|
|||
} else {
|
||||
slog.Error("TG→MAX video upload failed", "err", err)
|
||||
b.tg.SendMessage(ctx, msg.Chat.ID, uploadErrMsg(fmt.Sprintf("Не удалось отправить видео \"%s\" в MAX", name), err), nil)
|
||||
return
|
||||
// Видео не залилось — не блокируем отправку текста/подписи, fallback ниже подмешает [Видео].
|
||||
}
|
||||
} else if msg.VideoNote != nil {
|
||||
if checkSize(msg.VideoNote.FileSize, "circle.mp4") {
|
||||
|
|
@ -854,8 +854,11 @@ func (b *Bridge) forwardTgToMax(ctx context.Context, msg *TGMessage, maxChatID i
|
|||
mdText = tgEntitiesToMarkdown(rawText, entities)
|
||||
}
|
||||
|
||||
// Fallback для неудавшейся загрузки медиа
|
||||
if mediaAttType == "" && msg.Text == "" {
|
||||
// Fallback: медиа было, но не загрузилось (либо не хватило места, либо Bot API
|
||||
// не смог его скачать). Подмешиваем маркер типа, чтобы хотя бы текст прошёл.
|
||||
hasMedia := msg.Video != nil || msg.VideoNote != nil || msg.Document != nil ||
|
||||
msg.Voice != nil || msg.Audio != nil || msg.Sticker != nil || msg.Animation != nil || msg.Photo != nil
|
||||
if mediaAttType == "" && hasMedia {
|
||||
mediaType := ""
|
||||
switch {
|
||||
case msg.Video != nil:
|
||||
|
|
@ -870,10 +873,16 @@ func (b *Bridge) forwardTgToMax(ctx context.Context, msg *TGMessage, maxChatID i
|
|||
mediaType = "[Аудио]"
|
||||
case msg.Sticker != nil:
|
||||
mediaType = "[Стикер]"
|
||||
default:
|
||||
return
|
||||
case msg.Animation != nil:
|
||||
mediaType = "[GIF]"
|
||||
case msg.Photo != nil:
|
||||
mediaType = "[Фото]"
|
||||
}
|
||||
if mdText != "" {
|
||||
mdText = mdText + "\n" + mediaType
|
||||
} else {
|
||||
mdText = mediaType
|
||||
}
|
||||
mdText = mdText + mediaType
|
||||
}
|
||||
|
||||
// Reply ID
|
||||
|
|
@ -897,10 +906,9 @@ func (b *Bridge) forwardTgToMax(ctx context.Context, msg *TGMessage, maxChatID i
|
|||
|
||||
// Если для этого чата уже есть сообщения в очереди — не отправляем напрямую,
|
||||
// чтобы не нарушить порядок. Сразу ставим в очередь.
|
||||
// Caption для crosspost уже содержит markdown (formatTgCrosspostCaption),
|
||||
// так что формат одинаков для обоих режимов.
|
||||
format := "markdown"
|
||||
if isCrosspost {
|
||||
format = ""
|
||||
}
|
||||
|
||||
if b.hasPendingForChat("tg2max", maxChatID) {
|
||||
slog.Info("TG→MAX queued (pending exists)", "uid", uid, "tgChat", msg.Chat.ID, "maxChat", maxChatID)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue