From 0aa12f40ebbfb4ef65f2a6e8bc401d066ca32d7a Mon Sep 17 00:00:00 2001 From: davidramiro Date: Mon, 28 Oct 2024 12:49:56 +0100 Subject: [PATCH] chore: switch telegram library --- go.mod | 11 +-- go.sum | 4 +- internal/notifier/notifier.go | 10 +-- internal/telegram/telegram.go | 120 +++++++++++++---------------- internal/telegram/telegram_test.go | 38 +-------- 5 files changed, 70 insertions(+), 113 deletions(-) diff --git a/go.mod b/go.mod index 5742efd..c3406c4 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,16 @@ module streamobserver go 1.20 require ( - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 + github.com/go-telegram/bot v1.9.1 + github.com/rs/zerolog v1.33.0 + github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect -) - -require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/rs/zerolog v1.33.0 - github.com/stretchr/testify v1.9.0 + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.12.0 // indirect ) diff --git a/go.sum b/go.sum index fbb88b3..49c2a1f 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/go-telegram/bot v1.9.1 h1:4vkNV6vDmEPZaYP7sZYaagOaJyV4GerfOPkjg/Ki5ic= +github.com/go-telegram/bot v1.9.1/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= diff --git a/internal/notifier/notifier.go b/internal/notifier/notifier.go index ca3b758..7ce290e 100644 --- a/internal/notifier/notifier.go +++ b/internal/notifier/notifier.go @@ -2,6 +2,7 @@ package notifier import ( "errors" + "github.com/go-telegram/bot/models" "os" "path/filepath" "streamobserver/internal/logger" @@ -9,7 +10,6 @@ import ( "streamobserver/internal/telegram" "streamobserver/internal/twitch" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "gopkg.in/yaml.v3" ) @@ -25,14 +25,14 @@ type twitchStream struct { game string status bool notified bool - notificationMessage tgbotapi.Message + notificationMessage models.Message } type restreamerStream struct { stream restreamer.Stream status bool notified bool - notificationMessage tgbotapi.Message + notificationMessage models.Message } type notifierConfig struct { @@ -162,7 +162,7 @@ func checkAndNotifyTwitch(streamToCheck *twitchStream, chatID int64) { } } else { - if streamToCheck.status && streamToCheck.notified && streamToCheck.notificationMessage.MessageID != 0 { + if streamToCheck.status && streamToCheck.notified && streamToCheck.notificationMessage.ID != 0 { telegram.SendUpdateStreamOffline(streamToCheck.notificationMessage, chatID) } logger.Log.Debug().Str("Channel", streamToCheck.username).Msg("Channel offline.") @@ -202,7 +202,7 @@ func checkAndNotifyRestreamer(streamToCheck *restreamerStream, chatID int64) { logger.Log.Debug().Str("Channel", streamInfo.UserName).Msg("Online and status has not changed.") } } else { - if streamToCheck.status && streamToCheck.notified && streamToCheck.notificationMessage.MessageID != 0 { + if streamToCheck.status && streamToCheck.notified && streamToCheck.notificationMessage.ID != 0 { telegram.SendUpdateStreamOffline(streamToCheck.notificationMessage, chatID) } logger.Log.Debug().Str("Channel", streamToCheck.stream.ID).Msg("Channel offline.") diff --git a/internal/telegram/telegram.go b/internal/telegram/telegram.go index c847daa..d79bd57 100644 --- a/internal/telegram/telegram.go +++ b/internal/telegram/telegram.go @@ -1,18 +1,19 @@ package telegram import ( + "context" "errors" + "github.com/go-telegram/bot" + "github.com/go-telegram/bot/models" "streamobserver/internal/config" "streamobserver/internal/logger" "streamobserver/internal/restreamer" "streamobserver/internal/twitch" "streamobserver/internal/util" "strings" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) -var bot *tgbotapi.BotAPI +var b *bot.Bot const ( twitchPrefix = "https://twitch.tv/" @@ -28,50 +29,50 @@ func InitBot(debug bool) error { return err } - bot, err = tgbotapi.NewBotAPI(config.Telegram.ApiKey) + b, err = bot.New(config.Telegram.ApiKey) + if err != nil { + return err + } + + user, err := b.GetMe(context.TODO()) if err != nil { return err } - bot.Debug = debug - logger.Log.Info().Msgf("Authorized on Telegram account %s", bot.Self.UserName) + logger.Log.Info().Msgf("Authorized on Telegram account %s", user.Username) return nil } // SendTwitchStreamInfo generates a message from a Twitch stream struct and sends it to a chat ID. -func SendTwitchStreamInfo(chatID int64, stream twitch.Stream) (tgbotapi.Message, error) { - if bot == nil { +func SendTwitchStreamInfo(chatID int64, stream twitch.Stream) (models.Message, error) { + if b == nil { logger.Log.Error().Msg("Bot not initialized.") - return tgbotapi.Message{}, errors.New("bot not initialized") + return models.Message{}, errors.New("bot not initialized") } util.FormatTwitchPhotoUrl(&stream.ThumbnailURL) - caption := "" + stream.UserName + " is streaming " + stream.GameName + ": " + stream.Title + "\n" + twitchPrefix + stream.UserName + " [" + liveText + "]" - - photoMessage, err := createPhotoMessage(caption, chatID, stream.ThumbnailURL) - if err != nil { - return tgbotapi.Message{}, errors.New("could not send message") - } + caption := stream.UserName + " is streaming " + stream.GameName + ": " + stream.Title + "\n" + twitchPrefix + stream.UserName + " [" + liveText + "]" - ret, err := bot.Send(photoMessage) + photoMessage := createPhotoMessage(caption, chatID, stream.ThumbnailURL) + ret, err := b.SendPhoto(context.TODO(), &photoMessage) logger.Log.Debug().Interface("Message", ret).Msg("Sent message.") if err != nil { logger.Log.Error().Err(err).Msg("error sending Telegram message") - return tgbotapi.Message{}, err + return models.Message{}, err } if ret.Chat.ID != chatID { - return tgbotapi.Message{}, errors.New("error sending Telegram message") + return models.Message{}, errors.New("error sending Telegram message") } - return ret, nil + return *ret, nil } // SendRestreamerStreamInfo generates a message from a Restreamer stream struct and sends it to a chat ID. -func SendRestreamerStreamInfo(chatID int64, streamInfo restreamer.StreamInfo, stream restreamer.Stream) (tgbotapi.Message, error) { - if bot == nil { +func SendRestreamerStreamInfo(chatID int64, streamInfo restreamer.StreamInfo, stream restreamer.Stream) (models.Message, error) { + if b == nil { logger.Log.Error().Msg("Bot not initialized.") - return tgbotapi.Message{}, errors.New("bot not initialized") + return models.Message{}, errors.New("bot not initialized") } var streamLink string @@ -81,88 +82,77 @@ func SendRestreamerStreamInfo(chatID int64, streamInfo restreamer.StreamInfo, st streamLink = stream.CustomURL } - caption := "" + streamInfo.UserName + " is streaming: " + streamInfo.Description + "\n" + streamLink + " [" + liveText + "]" + caption := streamInfo.UserName + " is streaming: " + streamInfo.Description + "\n" + streamLink + " [" + liveText + "]" - photoMessage, err := createPhotoMessage(caption, chatID, streamInfo.ThumbnailURL) - if err != nil { - return tgbotapi.Message{}, errors.New("could not send message") - } - - ret, err := bot.Send(photoMessage) + photoMessage := createPhotoMessage(caption, chatID, streamInfo.ThumbnailURL) + ret, err := b.SendPhoto(context.TODO(), &photoMessage) logger.Log.Debug().Interface("Message", ret).Msg("Sent message.") if err != nil { logger.Log.Error().Err(err).Msg("error sending Telegram message") - return tgbotapi.Message{}, err + return models.Message{}, err } if ret.Chat.ID != chatID { - return tgbotapi.Message{}, errors.New("error sending Telegram message") + return models.Message{}, errors.New("error sending Telegram message") } - return ret, nil + return *ret, nil } // SendUpdateTwitchStreamInfo updates a previously sent message with new stream info. -func SendUpdateTwitchStreamInfo(chatID int64, message tgbotapi.Message, stream twitch.Stream) (tgbotapi.Message, error) { - if bot == nil { +func SendUpdateTwitchStreamInfo(chatID int64, message models.Message, stream twitch.Stream) (models.Message, error) { + if b == nil { logger.Log.Error().Msg("Bot not initialized.") - return tgbotapi.Message{}, errors.New("bot not initialized") + return models.Message{}, errors.New("bot not initialized") } - newcaption := "" + stream.UserName + " is streaming " + stream.GameName + ": " + stream.Title + "\n" + twitchPrefix + stream.UserName + " [" + liveText + "]" + newcaption := stream.UserName + " is streaming " + stream.GameName + ": " + stream.Title + "\n" + twitchPrefix + stream.UserName + " [" + liveText + "]" - config := tgbotapi.NewEditMessageCaption(chatID, message.MessageID, newcaption) - config.ParseMode = tgbotapi.ModeHTML - ret, err := bot.Send(config) + ret, err := b.EditMessageCaption(context.TODO(), &bot.EditMessageCaptionParams{ + ChatID: message.Chat.ID, + MessageID: message.ID, + Caption: newcaption, + }) if err != nil { logger.Log.Error().Err(err).Msg("error updating Telegram message") - return tgbotapi.Message{}, err + return models.Message{}, err } if ret.Chat.ID != chatID { - return tgbotapi.Message{}, errors.New("error updating Telegram message") + return models.Message{}, errors.New("error updating Telegram message") } - return ret, nil + return *ret, nil } // SendUpdateStreamOffline takes a previously sent message and edits it to reflect the changed stream status. -func SendUpdateStreamOffline(message tgbotapi.Message, chatID int64) (tgbotapi.Message, error) { +func SendUpdateStreamOffline(message models.Message, chatID int64) (models.Message, error) { logger.Log.Debug().Interface("Message", message).Msg("Updating Message") newtext := strings.Replace(message.Caption, liveText, offlineText, 1) newtext = strings.Replace(newtext, "is streaming", "was streaming", 1) - config := tgbotapi.NewEditMessageCaption(chatID, message.MessageID, newtext) - config.ParseMode = tgbotapi.ModeHTML - config.CaptionEntities = message.CaptionEntities - ret, err := bot.Send(config) + ret, err := b.EditMessageCaption(context.TODO(), &bot.EditMessageCaptionParams{ + ChatID: message.Chat.ID, + MessageID: message.ID, + Caption: newtext, + }) if err != nil { logger.Log.Error().Err(err).Msg("error updating Telegram message") - return tgbotapi.Message{}, err + return models.Message{}, err } if ret.Chat.ID != chatID { - return tgbotapi.Message{}, errors.New("error updating Telegram message") + return models.Message{}, errors.New("error updating Telegram message") } - return ret, nil + return *ret, nil } -func createPhotoMessage(caption string, chatID int64, url string) (tgbotapi.PhotoConfig, error) { - photoBytes, err := util.GetPhotoFromUrl(url) - if err != nil { - logger.Log.Error().Err(err).Msg("Could not send photo on Telegram") - return tgbotapi.PhotoConfig{}, errors.New("could not retrieve photo") +func createPhotoMessage(caption string, chatID int64, url string) bot.SendPhotoParams { + return bot.SendPhotoParams{ + ChatID: chatID, + Photo: &models.InputFileString{Data: url}, + Caption: caption, } - - photoFileBytes := tgbotapi.FileBytes{ - Name: "picture", - Bytes: photoBytes, - } - config := tgbotapi.NewPhoto(chatID, photoFileBytes) - config.Caption = caption - config.ParseMode = tgbotapi.ModeHTML - return config, nil - } diff --git a/internal/telegram/telegram_test.go b/internal/telegram/telegram_test.go index 7bc5b96..b3b0323 100644 --- a/internal/telegram/telegram_test.go +++ b/internal/telegram/telegram_test.go @@ -43,7 +43,10 @@ func init() { if err != nil { panic(err) } - InitBot(true) + err = InitBot(true) + if err != nil { + panic(err) + } config, err := config.GetConfig() if err != nil { @@ -58,39 +61,6 @@ func init() { testchatid = &config.General.TestChatID } -func TestCreatePhotoMessageNotImage(t *testing.T) { - // Testing broken URL - _, err := createPhotoMessage("test", 42, "https://via.placeholder.com/notanimage") - expectedError := "could not retrieve photo" - - if assert.Error(t, err, "should report error on broken image URL") { - assert.Equal(t, expectedError, err.Error(), "error message should reflect image retrieval issue") - } -} - -func TestCreatePhotoMessageBrokenUrl(t *testing.T) { - // Testing 404 URL - _, err := createPhotoMessage("test", 42, "http://notfound.tld/image.jpg") - expectedError := "could not retrieve photo" - - if assert.Error(t, err, "should report error on non-image URL") { - assert.Equal(t, expectedError, err.Error(), "error message should reflect image retrieval issue") - } -} - -func TestCreatePhotoMessageValid(t *testing.T) { - // Testing created Photo Config - testcaption := "testcaption" - testid := int64(42) - result, err := createPhotoMessage(testcaption, testid, "https://via.placeholder.com/300.jpg") - - if assert.NoError(t, err) { - assert.Equal(t, testcaption, result.Caption, "config should return expected caption") - assert.Equal(t, testid, result.ChatID, "config should return expected chatID") - assert.True(t, result.File.NeedsUpload(), "not yet send message should indicate file upload bool") - } -} - func TestSendTwitchStreamInfo(t *testing.T) { result, err := SendTwitchStreamInfo(*testchatid, *testTwitchStream)