From 99a81a201b58c20c6ab46ace731215e79b480d53 Mon Sep 17 00:00:00 2001 From: Noah Theus Date: Sun, 31 Aug 2025 03:49:57 +0200 Subject: [PATCH 1/3] feat: Parse environment variables from .env file --- config/config.go | 12 ++++++++++-- go.mod | 1 + go.sum | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 53e9257..dec9dbb 100644 --- a/config/config.go +++ b/config/config.go @@ -5,18 +5,26 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "github.com/joho/godotenv" envconfig "github.com/sethvargo/go-envconfig" ) var BotConfig config func LoadConfig() { + + if err := godotenv.Load(); err != nil { + log.Info().Err(err).Msg("Failed to load .env file, using the system environment") + } else { + log.Info().Err(err).Msg(".env file loaded successfully") + } + if err := envconfig.Process(context.Background(), &BotConfig); err != nil { - log.Panic().Err(err).Msg("Error parsing config from env variables") + log.Panic().Err(err).Msg("Failed to parse config from env variables") } zerolog.SetGlobalLevel(zerolog.Level(BotConfig.LogLevel)) - log.Info().Msg("Loaded config") + log.Info().Msg("Config loaded successfully") log.Debug().Interface("config", BotConfig).Msg("") } diff --git a/go.mod b/go.mod index c067f00..8502be1 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( require ( github.com/andybalholm/cascadia v1.3.3 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect golang.org/x/net v0.43.0 // indirect diff --git a/go.sum b/go.sum index c9b21ee..2fd7de9 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= From 38db97bdcf10df7f2dab32812bad9f82c5173e2b Mon Sep 17 00:00:00 2001 From: Noah Theus Date: Sun, 31 Aug 2025 03:51:36 +0200 Subject: [PATCH 2/3] refactor: Standardized logging to be more uniform --- bot.go | 6 +++--- botIO/authenticate.go | 4 ++-- botIO/sending.go | 10 +++++----- commands/commands.go | 4 ++-- main.go | 2 +- steam/api.go | 4 ++-- steam/http.go | 18 +++++++++--------- steam/profile.go | 8 ++++---- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bot.go b/bot.go index e2e15b9..c6fe072 100644 --- a/bot.go +++ b/bot.go @@ -18,10 +18,10 @@ func bot() { go steam.StartWatchers(bot) for update := range updates { - log.Debug().Interface("update", update).Msg("Received update") + log.Debug().Interface("update", update).Msg("Update received") if update.Message == nil || update.Message.Text == "" { - log.Debug().Int("UpdateID", update.UpdateID).Msg("Unable to parse update") + log.Debug().Int("UpdateID", update.UpdateID).Msg("Failed to parse update") continue } if update.Message.Time().UTC().Unix() < time.Now().UTC().Unix() { @@ -30,7 +30,7 @@ func bot() { } if update.Message.IsCommand() { - log.Info().Int64("ChatID", update.Message.Chat.ID).Int64("UserID", update.Message.From.ID).Str("Text", update.Message.Text).Msg("Received Command") + log.Info().Int64("ChatID", update.Message.Chat.ID).Int64("UserID", update.Message.From.ID).Str("Text", update.Message.Text).Msg("Command received") commands.Commands(update, bot) } } diff --git a/botIO/authenticate.go b/botIO/authenticate.go index 747f8b6..65ce465 100644 --- a/botIO/authenticate.go +++ b/botIO/authenticate.go @@ -9,7 +9,7 @@ import ( func Authenticate() (tgbotapi.UpdatesChannel, *tgbotapi.BotAPI) { bot, err := tgbotapi.NewBotAPI(config.BotConfig.TelegramAPIToken) if err != nil { - log.Panic().Err(err).Msg("Failed to authenticate") + log.Panic().Err(err).Msg("Failed to authenticate to Telegram") } bot.Debug = false @@ -20,7 +20,7 @@ func Authenticate() (tgbotapi.UpdatesChannel, *tgbotapi.BotAPI) { updates := tgbotapi.NewUpdate(0) updates.Timeout = 60 - log.Info().Int64("ID", bot.Self.ID).Str("username", bot.Self.UserName).Msg("Authenticated to Telegram API") + log.Info().Int64("ID", bot.Self.ID).Str("username", bot.Self.UserName).Msg("Authenticated to Telegram successfully") return bot.GetUpdatesChan(updates), bot diff --git a/botIO/sending.go b/botIO/sending.go index 4576603..297b3e5 100644 --- a/botIO/sending.go +++ b/botIO/sending.go @@ -12,7 +12,7 @@ func SendMessage(message tgbotapi.MessageConfig, bot *tgbotapi.BotAPI) (result t return } - log.Info().Int64("chat", result.Chat.ID).Str("msg", result.Text).Msg("Sent message") + log.Info().Int64("chat", result.Chat.ID).Str("msg", result.Text).Msg("Sent message successfully") log.Debug().Interface("msg", result).Msg("") return result @@ -25,7 +25,7 @@ func EditMessage(message tgbotapi.EditMessageTextConfig, bot *tgbotapi.BotAPI) ( return } - log.Info().Int64("chat", result.Chat.ID).Str("msg", result.Text).Msg("Edited message") + log.Info().Int64("chat", result.Chat.ID).Str("msg", result.Text).Msg("Edited message successfully") log.Debug().Interface("msg", result).Msg("") return result @@ -38,7 +38,7 @@ func SendVideo(message tgbotapi.VideoConfig, bot *tgbotapi.BotAPI) (result tgbot return } - log.Info().Int64("chat", result.Chat.ID).Msg("Sent video") + log.Info().Int64("chat", result.Chat.ID).Msg("Sent video successfully") log.Debug().Interface("video", result).Msg("") return result @@ -51,7 +51,7 @@ func SendPhoto(message tgbotapi.PhotoConfig, bot *tgbotapi.BotAPI) (result tgbot return } - log.Info().Int64("chat", result.Chat.ID).Msg("Sent photo") + log.Info().Int64("chat", result.Chat.ID).Msg("Sent photo successfully") log.Debug().Interface("photo", result).Msg("") return result @@ -64,7 +64,7 @@ func SendSticker(message tgbotapi.StickerConfig, bot *tgbotapi.BotAPI) (result t return } - log.Info().Int64("chat", result.Chat.ID).Msg("Sent sticker") + log.Info().Int64("chat", result.Chat.ID).Msg("Sent sticker successfully") log.Debug().Interface("sticker", result).Msg("") return result diff --git a/commands/commands.go b/commands/commands.go index 2291e6d..7fdcbe6 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -22,11 +22,11 @@ func SetBotCommands(bot *tgbotapi.BotAPI) { result, err := bot.Request(commands) if err != nil { - log.Error().Err(err).Msg("Failed to set own commands") + log.Error().Err(err).Msg("Failed to publish commands to Telegram") return } - log.Debug().Interface("commands", result).Msg("Set own commands") + log.Debug().Interface("commands", result).Msg("Published commands to Telegram successfully") } func Commands(update tgbotapi.Update, bot *tgbotapi.BotAPI) { diff --git a/main.go b/main.go index fcc9cfb..345adc1 100644 --- a/main.go +++ b/main.go @@ -38,6 +38,6 @@ func configureLogger() { output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.DateTime} log.Logger = zerolog.New(output).With().Timestamp().Caller().Logger() - log.Info().Msg("Started Logger") + log.Info().Msg("Logger started successfully") } diff --git a/steam/api.go b/steam/api.go index 9a41911..f73f19b 100644 --- a/steam/api.go +++ b/steam/api.go @@ -11,8 +11,8 @@ func GetPlayerDetails(steamID uint64) (summary steamapi.PlayerSummary) { response, err := steamapi.GetPlayerSummaries([]uint64{steamID}, config.BotConfig.SteamAPIKey) if err != nil { - log.Error().Err(err).Msg("Failed to get Player Summary") + log.Error().Err(err).Msg("Failed to retrive player summary") } - log.Debug().Interface("Player", response[0]).Msg("Got PlayerSummary from Steam API") + log.Debug().Interface("Player", response[0]).Msg("Retrived player summary from SteamAPI successfully") return response[0] } diff --git a/steam/http.go b/steam/http.go index 2c734fa..8fca3d0 100644 --- a/steam/http.go +++ b/steam/http.go @@ -19,7 +19,7 @@ func GetComments(steamID uint64, start int, count int) (page CommentsPage) { url, err := url.Parse(baseURL + strconv.FormatUint(steamID, 10)) if err != nil { - log.Error().Err(err).Msg("Unable to Parse SteamID into URL") + log.Error().Err(err).Msg("Failed to parse SteamID into URL") return } @@ -30,7 +30,7 @@ func GetComments(steamID uint64, start int, count int) (page CommentsPage) { resp, err := http.Get(url.String()) if err != nil || resp.StatusCode != http.StatusOK { - log.Error().Err(err).Int("Response Code", resp.StatusCode).Msg("Failed to get Comments") + log.Error().Err(err).Int("Response Code", resp.StatusCode).Msg("Failed to retrieve comments") } defer resp.Body.Close() @@ -38,16 +38,16 @@ func GetComments(steamID uint64, start int, count int) (page CommentsPage) { // Read the response body body, err := io.ReadAll(resp.Body) if err != nil { - log.Error().Err(err).Msg("Failed to parse Comments") + log.Error().Err(err).Msg("Failed to parse comments") log.Trace().Interface("Body", resp.Body) } err = json.Unmarshal(body, &page) if err != nil { - log.Error().Err(err).Msg("Failed to parse Comments as JSON") + log.Error().Err(err).Msg("Failed to parse comments as JSON") } - log.Trace().Interface("CommentPage", page).Uint64("ProfileID", steamID).Msg("Got Comment Page") + log.Trace().Interface("CommentPage", page).Uint64("ProfileID", steamID).Msg("Retrieved Comment Page successfully") return page } @@ -56,7 +56,7 @@ func parseComments(rawComments CommentsPage) (comments []Comment) { doc, err := goquery.NewDocumentFromReader(strings.NewReader(rawComments.CommentsHTML)) if err != nil { - log.Error().Err(err).Msg("Error while parsing CommentsHTML") + log.Error().Err(err).Msg("Failed to parse CommentsHTML") return } doc.Find(".commentthread_comment.responsive_body_text").Each(func(i int, s *goquery.Selection) { @@ -64,14 +64,14 @@ func parseComments(rawComments CommentsPage) (comments []Comment) { parsedID, err := strconv.ParseUint(strings.TrimPrefix(s.AttrOr("id", ""), "comment_"), 10, 64) if err != nil { - log.Error().Err(err).Msg("Error while parsing Comment ID") + log.Error().Err(err).Msg("Failed to parse Comment ID") return } c.ID = parsedID c.Timestamp, err = strconv.ParseInt(s.Find(".commentthread_comment_timestamp").AttrOr("data-timestamp", ""), 10, 64) if err != nil { - log.Error().Err(err).Msg("Error while parsing Comment Timestamp") + log.Error().Err(err).Msg("Failed to parse Comment Timestamp") return } @@ -85,6 +85,6 @@ func parseComments(rawComments CommentsPage) (comments []Comment) { }) slices.Reverse(comments) - log.Trace().Interface("Comments", comments).Msg("Parsed Comment Page") + log.Trace().Interface("Comments", comments).Msg("Parsed comment page successfully") return comments } diff --git a/steam/profile.go b/steam/profile.go index ec0b1b0..2711cce 100644 --- a/steam/profile.go +++ b/steam/profile.go @@ -33,7 +33,7 @@ func StartWatchers(bot *tgbotapi.BotAPI) { } func watcher(bot *tgbotapi.BotAPI, steamID uint64, sleeptime time.Duration) { - log.Info().Uint64("SteamID", steamID).Msg("Started Watcher") + log.Info().Uint64("SteamID", steamID).Msg("Starting Watcher") var newestProcessedComment int64 = 0 @@ -56,9 +56,9 @@ func watcher(bot *tgbotapi.BotAPI, steamID uint64, sleeptime time.Duration) { profileOwner := GetPlayerDetails(steamID) for _, comment := range parseComments(currentCommentsPage) { - log.Debug().Interface("Comment", comment).Msg("Processing Comment") + log.Debug().Interface("Comment", comment).Msg("Processing comment") if comment.Timestamp <= newestProcessedComment { - log.Debug().Uint64("CommentID", comment.ID).Msg("Skipping Comment") + log.Debug().Uint64("CommentID", comment.ID).Msg("Skipping comment") continue } @@ -69,7 +69,7 @@ func watcher(bot *tgbotapi.BotAPI, steamID uint64, sleeptime time.Duration) { Text: fmt.Sprintf(`%s just commented on %s's profile:`, comment.AuthorProfileURL, comment.Author, profileOwner.ProfileURL, profileOwner.PersonaName) + "\n" + "
" + comment.Text + "
", } - log.Info().Interface("Comment", comment).Msg("Notifying about new Comment") + log.Info().Interface("Comment", comment).Msg("Notifying about new comment") botIO.SendMessage(msg, bot) time.Sleep(time.Minute / 20) } From 17ca2cff1bbd358088c57806a045aaa10b0746e4 Mon Sep 17 00:00:00 2001 From: Noah Theus Date: Sun, 31 Aug 2025 04:12:04 +0200 Subject: [PATCH 3/3] docs: README changes --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index aa69129..8a6c28d 100644 --- a/README.md +++ b/README.md @@ -27,15 +27,18 @@ services: ## Running on Linux -Grab a release from the [releases page](https://github.com/watn3y/steamsalty/releases). Make sure to set your **environment variables** accordingly. +Grab a release from the [releases page](https://github.com/watn3y/steamsalty/releases). Make sure to set your [environment variables](#environment-variables) accordingly. ## Environment Variables -| Variable | Description | Default | -| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------| ------------------ | -| `STEAMSALTY_LOGLEVEL` | LogLevel as described [in the zerolog documentation](https://pkg.go.dev/github.com/rs/zerolog@v1.34.0#readme-simple-leveled-logging-example) | 1 (Info) | -| `STEAMSALTY_TELEGRAMAPITOKEN` | Telegram Bot Token, get from @BotFather | None, **required** | -| `STEAMSALTY_STEAMAPIKEY` | Steam API Key, get from [steamcommunity.com/dev/apikey](https://steamcommunity.com/dev/apikey) | None, **required** | -| `STEAMSALTY_CHATID` | Chat to notify about new Comments | None, **required** | -| `STEAMSALTY_WATCHERS` | SteamIDs (in SteamID64 format) to check for new Profile Comments | None, **required** | -| `STEAMSALTY_SLEEPINTERVAL` | Amount of time to wait between requests to Steam in seconds | 60 | +> [!NOTE] +> For development purposes, SteamSalty supports loading environment variables from a .env file placed in the project root directory. + +| Variable | Description | Default | Required | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------| ------------------ | -------------- | +| `STEAMSALTY_LOGLEVEL` | LogLevel as described [in the zerolog documentation](https://pkg.go.dev/github.com/rs/zerolog@v1.34.0#readme-simple-leveled-logging-example) | 1 (Info) | ❌ | +| `STEAMSALTY_TELEGRAMAPITOKEN` | Telegram BotToken, get it from [@BotFather on Telegram](https://t.me/BotFather) | None | ✅ | +| `STEAMSALTY_STEAMAPIKEY` | Steam API Key, get it from [steamcommunity.com/dev/apikey](https://steamcommunity.com/dev/apikey) | None | ✅ | +| `STEAMSALTY_CHATID` | Chat to notify about new comments | None | ✅ | +| `STEAMSALTY_WATCHERS` | SteamIDs (in SteamID64 format) to check for new profile comments | None | ✅ | +| `STEAMSALTY_SLEEPINTERVAL` | Amount of time to wait between requests to Steam in seconds | 60 | ❌ |