Skip to content

Commit

Permalink
chore: switch telegram library
Browse files Browse the repository at this point in the history
  • Loading branch information
davidramiro committed Oct 28, 2024
1 parent 554283a commit 0aa12f4
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 113 deletions.
11 changes: 4 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
Expand Down
10 changes: 5 additions & 5 deletions internal/notifier/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package notifier

import (
"errors"
"github.com/go-telegram/bot/models"
"os"
"path/filepath"
"streamobserver/internal/logger"
"streamobserver/internal/restreamer"
"streamobserver/internal/telegram"
"streamobserver/internal/twitch"

tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"gopkg.in/yaml.v3"
)

Expand All @@ -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 {
Expand Down Expand Up @@ -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.")
Expand Down Expand Up @@ -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.")
Expand Down
120 changes: 55 additions & 65 deletions internal/telegram/telegram.go
Original file line number Diff line number Diff line change
@@ -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/"
Expand All @@ -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 := "<b>" + stream.UserName + "</b> is streaming <b>" + stream.GameName + "</b>: " + 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
Expand All @@ -81,88 +82,77 @@ func SendRestreamerStreamInfo(chatID int64, streamInfo restreamer.StreamInfo, st
streamLink = stream.CustomURL
}

caption := "<b>" + streamInfo.UserName + "</b> 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 := "<b>" + stream.UserName + "</b> is streaming <b>" + stream.GameName + "</b>: " + 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

}
38 changes: 4 additions & 34 deletions internal/telegram/telegram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down

0 comments on commit 0aa12f4

Please sign in to comment.