commit f149a074980be5933f95cef4de286d42831a2c7d
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-06-20T02:14:09Z |
| subject | Attach message as text file if message too long |
commit f149a074980be5933f95cef4de286d42831a2c7d
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-06-20T02:14:09Z
Attach message as text file if message too long
---
adaptors/tg/botsend.go | 107 ++++++++++++++++++++++++------
cmd/README.md | 4 ++
datasources/cjlookup/QueryResult.go | 1 +
datasources/kmb/QueryResult.go | 1 +
datasources/mtr/bus/QueryResult.go | 1 +
i18n/messages.go | 1 +
main.go | 10 +--
query/objects.go | 1 +
resources/langpacks/zh-Hant/messages.json | 1 +
resources/po/zh-Hant/messages.po | 8 ++-
resources/pot/messages.pot | 8 ++-
resources/src/messages.json | 1 +
utils/shortcuts.go | 11 +++
13 files changed, 126 insertions(+), 29 deletions(-)
diff --git a/adaptors/tg/botsend.go b/adaptors/tg/botsend.go
index 8625dc4..57a635a 100644
--- a/adaptors/tg/botsend.go
+++ b/adaptors/tg/botsend.go
@@ -1,26 +1,33 @@
package tg
import (
+ "fmt"
+ "strings"
+
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ i18n "github.com/tgckpg/golifehk/i18n"
query "github.com/tgckpg/golifehk/query"
+ utils "github.com/tgckpg/golifehk/utils"
)
-func BotSendText(bot *tgbotapi.BotAPI, update *tgbotapi.Update, mesg *string) {
- var msg tgbotapi.MessageConfig
- msg = tgbotapi.NewMessage(update.Message.Chat.ID, *mesg)
+func BotSendText(lang string, bot *tgbotapi.BotAPI, update *tgbotapi.Update, mesg *string) error {
+ if update == nil || update.Message == nil || mesg == nil {
+ return fmt.Errorf("nil update/message/text")
+ }
+
+ chatID := update.Message.Chat.ID
+ replyTo := update.Message.MessageID
+
+ msg := tgbotapi.NewMessage(chatID, *mesg)
msg.ParseMode = "MarkdownV2"
+ msg.ReplyToMessageID = replyTo
- msg.ReplyToMessageID = update.Message.MessageID
- bot.Send(msg)
+ return sendMessageOrFile(lang, bot, msg, *mesg)
}
func BotSend(bot *tgbotapi.BotAPI, update *tgbotapi.Update, qResult query.IQueryResult) (bool, error) {
-
- var msg tgbotapi.MessageConfig
mesg, err := qResult.Message()
-
if err != nil {
- // not sent, error
return false, err
}
@@ -28,40 +35,98 @@ func BotSend(bot *tgbotapi.BotAPI, update *tgbotapi.Update, qResult query.IQuery
switch mesgType {
case "IGNORE":
- // not sent with no error tells the parent to look for other processors
return false, nil
}
- var chatId int64
- if update.Message != nil {
- chatId = update.Message.Chat.ID
- msg.ReplyToMessageID = update.Message.MessageID
- }
-
- if update.CallbackQuery != nil {
- chatId = update.CallbackQuery.Message.Chat.ID
+ chatID, replyTo, err := getChatAndReply(update)
+ if err != nil {
+ return false, err
}
- msg = tgbotapi.NewMessage(chatId, mesg)
+ msg := tgbotapi.NewMessage(chatID, mesg)
msg.ParseMode = "MarkdownV2"
+ if replyTo != 0 {
+ msg.ReplyToMessageID = replyTo
+ }
+
switch mesgType {
case "PlainText":
- case "Table":
+ case "Table":
buttonRows := [][]tgbotapi.InlineKeyboardButton{}
+
for _, row := range qResult.GetTableData() {
buttons := []tgbotapi.InlineKeyboardButton{}
+
for _, cell := range row {
button := tgbotapi.NewInlineKeyboardButtonData(cell.Name, cell.Value)
buttons = append(buttons, button)
}
+
buttonRows = append(buttonRows, buttons)
}
msg.ReplyMarkup = tgbotapi.NewInlineKeyboardMarkup(buttonRows...)
}
- bot.Send(msg)
+ if err := sendMessageOrFile(qResult.UserLang(), bot, msg, mesg); err != nil {
+ return false, err
+ }
+
return true, nil
}
+
+func getChatAndReply(update *tgbotapi.Update) (chatID int64, replyTo int, err error) {
+ if update == nil {
+ return 0, 0, fmt.Errorf("nil update")
+ }
+
+ if update.Message != nil {
+ return update.Message.Chat.ID, update.Message.MessageID, nil
+ }
+
+ if update.CallbackQuery != nil && update.CallbackQuery.Message != nil {
+ return update.CallbackQuery.Message.Chat.ID, 0, nil
+ }
+
+ return 0, 0, fmt.Errorf("update has no message or callback message")
+}
+
+func sendMessageOrFile(lang string, bot *tgbotapi.BotAPI, msg tgbotapi.MessageConfig, text string) error {
+ _, err := bot.Send(msg)
+ if err == nil {
+ return nil
+ }
+
+ if !strings.Contains(err.Error(), "message is too long") {
+ return err
+ }
+
+ doc := tgbotapi.NewDocument(
+ msg.ChatID,
+ tgbotapi.FileBytes{
+ Name: "message.txt",
+ Bytes: []byte(utils.UnescapeMDv2Text(text)),
+ },
+ )
+
+ langPack, err := i18n.LoadKeys(lang)
+ doc.Caption = i18n.TG_MESG_TOO_LONG.Text(langPack)
+
+ if msg.ReplyToMessageID != 0 {
+ doc.ReplyToMessageID = msg.ReplyToMessageID
+ }
+
+ // Keep inline keyboard if this was a table result.
+ //
+ // This is useful when the text is too long but the buttons are still needed.
+ doc.ReplyMarkup = msg.ReplyMarkup
+
+ _, docErr := bot.Send(doc)
+ if docErr != nil {
+ return fmt.Errorf("send message failed: %w; send document failed: %w", err, docErr)
+ }
+
+ return nil
+}
diff --git a/cmd/README.md b/cmd/README.md
new file mode 100644
index 0000000..d0df092
--- /dev/null
+++ b/cmd/README.md
@@ -0,0 +1,4 @@
+1. Edit i18n/messages.go
+2. Run cmd/po-export.sh
+3. Update resources/pot/messages.pot and messages.po
+4. Run cmd/po-build.sh
diff --git a/datasources/cjlookup/QueryResult.go b/datasources/cjlookup/QueryResult.go
index ffc7425..572000c 100644
--- a/datasources/cjlookup/QueryResult.go
+++ b/datasources/cjlookup/QueryResult.go
@@ -41,6 +41,7 @@ func writeCCharInfo(sb *strings.Builder, cc *CChar) {
}
func (this QueryResult) DataType() string { return this.ResultType }
+func (this QueryResult) UserLang() string { return this.Lang }
func (this QueryResult) Consumed() bool { return this.isConsumed }
func (this QueryResult) GetTableData() [][]query.TableCell { return nil }
diff --git a/datasources/kmb/QueryResult.go b/datasources/kmb/QueryResult.go
index 486dd2e..fa77e43 100644
--- a/datasources/kmb/QueryResult.go
+++ b/datasources/kmb/QueryResult.go
@@ -59,6 +59,7 @@ func writeShortRoute(lang *string, sb *strings.Builder, r *RouteStop) {
func (this QueryResult) DataType() string { return this.dataType }
func (this QueryResult) Consumed() bool { return this.isConsumed }
+func (this QueryResult) UserLang() string { return this.Lang }
func (this QueryResult) GetTableData() [][]query.TableCell { return this.tableData }
func (this *QueryResult) Message() (string, error) {
diff --git a/datasources/mtr/bus/QueryResult.go b/datasources/mtr/bus/QueryResult.go
index 0ae96fc..9d8789d 100644
--- a/datasources/mtr/bus/QueryResult.go
+++ b/datasources/mtr/bus/QueryResult.go
@@ -45,6 +45,7 @@ func writeShortRoute(lang *string, sb *strings.Builder, b *BusStop) {
}
func (this QueryResult) DataType() string { return this.dataType }
+func (this QueryResult) UserLang() string { return this.Lang }
func (this QueryResult) Consumed() bool { return this.isConsumed }
func (this QueryResult) GetTableData() [][]query.TableCell { return this.tableData }
diff --git a/i18n/messages.go b/i18n/messages.go
index 3f42809..8da4a3d 100644
--- a/i18n/messages.go
+++ b/i18n/messages.go
@@ -9,6 +9,7 @@ const (
DS_MTR_NO_NEAREST_STOPS Key = "DS.MTR.NO_NEAREST_STOPS"
DS_MTR_NO_SCHEDULES Key = "DS.MTR.NO_SCHEDULES"
NO_RESULTS Key = "NO_RESULTS"
+ TG_MESG_TOO_LONG Key = "TG.MESSAGE_TOO_LONG"
UNITS_MINUTE Key = "UNITS.MINUTE"
UNITS_KM Key = "UNITS.KM"
UNITS_METER Key = "UNITS.METER"
diff --git a/main.go b/main.go
index f32b85f..635a13b 100644
--- a/main.go
+++ b/main.go
@@ -31,6 +31,8 @@ func main() {
for update := range updates {
+ lang := "zh-Hant"
+
if update.CallbackQuery != nil {
callback := tgbotapi.NewCallback(update.CallbackQuery.ID, "")
bot.Request(callback)
@@ -40,7 +42,7 @@ func main() {
if !f_sent && f_err != nil {
mesg := utils.MDv2Text(fmt.Sprintf("%s", f_err))
- tgadaptor.BotSendText(bot, &update, &mesg)
+ tgadaptor.BotSendText(lang, bot, &update, &mesg)
}
continue
@@ -56,13 +58,13 @@ func main() {
mesg, processed := utils.SystemControl(update.Message)
if processed {
if mesg != "" {
- tgadaptor.BotSendText(bot, &update, &mesg)
+ tgadaptor.BotSendText(lang, bot, &update, &mesg)
}
continue
}
tgMesg := update.Message
- q := query.QueryMessage{Lang: "zh-Hant", Text: tgMesg.Text}
+ q := query.QueryMessage{Lang: lang, Text: tgMesg.Text}
if tgMesg.Location != nil {
q.Location = &query.GeoLocation{tgMesg.Location.Latitude, tgMesg.Location.Longitude}
@@ -72,7 +74,7 @@ func main() {
if !isGroup && !f_sent && f_err != nil {
mesg := utils.MDv2Text(fmt.Sprintf("%s", f_err))
- tgadaptor.BotSendText(bot, &update, &mesg)
+ tgadaptor.BotSendText(lang, bot, &update, &mesg)
}
}
}
diff --git a/query/objects.go b/query/objects.go
index 50120e0..d56d332 100644
--- a/query/objects.go
+++ b/query/objects.go
@@ -29,4 +29,5 @@ type IQueryResult interface {
DataType() string
GetTableData() [][]TableCell
Consumed() bool
+ UserLang() string
}
diff --git a/resources/langpacks/zh-Hant/messages.json b/resources/langpacks/zh-Hant/messages.json
index aacfa2a..29d53ab 100644
--- a/resources/langpacks/zh-Hant/messages.json
+++ b/resources/langpacks/zh-Hant/messages.json
@@ -7,6 +7,7 @@
"DS.MTR.NO_NEAREST_STOPS": "%s 範圍內找不到港鐵巴士站,最近 %d 個站為:",
"DS.MTR.NO_SCHEDULES": "沒有行程(收左工了?全日得一班?)",
"NO_RESULTS": "找不到結果",
+ "TG.MESSAGE_TOO_LONG": "訊息太長,以附件方式傳送",
"UNITS.KM": "%.1f 公里",
"UNITS.METER": "%.0f 米",
"UNITS.MILE": "%.1f 英哩",
diff --git a/resources/po/zh-Hant/messages.po b/resources/po/zh-Hant/messages.po
index 743b3a8..5143b11 100644
--- a/resources/po/zh-Hant/messages.po
+++ b/resources/po/zh-Hant/messages.po
@@ -3,14 +3,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-03-10 16:50+0800\n"
+"POT-Creation-Date: 2026-06-20 02:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Translate Toolkit 3.19.3\n"
+"X-Generator: Translate Toolkit 3.19.11\n"
#: .DS.KMB.ETA.DEPARTED
msgid "%s (Leaved?)"
@@ -49,6 +49,10 @@ msgstr "沒有行程(收左工了?全日得一班?)"
msgid "No Results"
msgstr "找不到結果"
+#: .TG.MESSAGE_TOO_LONG
+msgid "Message was too long, attached as text file."
+msgstr "訊息太長,以附件方式傳送"
+
#: .UNITS.KM
msgid "%.1f km"
msgstr "%.1f 公里"
diff --git a/resources/pot/messages.pot b/resources/pot/messages.pot
index 8acf082..84c4c11 100644
--- a/resources/pot/messages.pot
+++ b/resources/pot/messages.pot
@@ -4,14 +4,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-03-10 16:50+0800\n"
+"POT-Creation-Date: 2026-06-20 02:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Translate Toolkit 3.19.3\n"
+"X-Generator: Translate Toolkit 3.19.11\n"
#: .DS.KMB.ETA.DEPARTED
msgid "%s (Leaved?)"
@@ -50,6 +50,10 @@ msgstr ""
msgid "No Results"
msgstr ""
+#: .TG.MESSAGE_TOO_LONG
+msgid "Message was too long, attached as text file."
+msgstr ""
+
#: .UNITS.KM
msgid "%.1f km"
msgstr ""
diff --git a/resources/src/messages.json b/resources/src/messages.json
index 2b80ed1..81641a7 100644
--- a/resources/src/messages.json
+++ b/resources/src/messages.json
@@ -7,6 +7,7 @@
"DS.MTR.NO_NEAREST_STOPS": "MTR Bus: Unable to find stations under %s. Listing nearest %d stations instead:",
"DS.MTR.NO_SCHEDULES": "Schedules are empty...perhaps Out of Service Time?",
"NO_RESULTS": "No Results",
+ "TG.MESSAGE_TOO_LONG": "Message was too long, attached as text file.",
"UNITS.KM": "%.1f km",
"UNITS.METER": "%.0f m",
"UNITS.MILE": "%.1f mi",
diff --git a/utils/shortcuts.go b/utils/shortcuts.go
index 7aa2ab1..3451b20 100644
--- a/utils/shortcuts.go
+++ b/utils/shortcuts.go
@@ -40,6 +40,17 @@ func MDv2Text(t string) string {
return sb.String()
}
+func UnescapeMDv2Text(t string) string {
+ sb := strings.Builder{}
+
+ for _, c := range MARKDOWN_ESC {
+ t = strings.Replace(t, "\\"+c, c, -1)
+ }
+
+ sb.WriteString(t)
+ return sb.String()
+}
+
func IsASCIIAlnum(s string) bool {
if s == "" {
return false