Rewrite for new API

This commit is contained in:
Kevin Thompson 2024-11-10 17:23:41 -06:00
parent 801396923b
commit 856e1b1cbd
5 changed files with 113 additions and 126 deletions

View File

@ -1,10 +1,9 @@
package config
var (
BotToken = " " // Define your bot token here
CFBDAPIKey = " " // Define your CFBD API Key here
BotToken = "REDACTED"
CFBDAPIKey = "ay2L+7JSttYQP9e10qxpAkluht7NHcyEnSqbBUsqWrwVjBcl02QH2XjOaVDnPRBy"
)
func LoadConfig() {
// Just leaving this here in case we need to add stuff later.
}

2
go.mod
View File

@ -1,6 +1,6 @@
module discord-cfb-bot
go 1.19
go 1.23.0
require github.com/bwmarrin/discordgo v0.28.1

View File

@ -1,41 +1,41 @@
package bot
import (
"discord-cfb-bot/config"
"discord-cfb-bot/internal/clients"
"github.com/bwmarrin/discordgo"
"fmt"
"strings"
"fmt"
"strings"
"discord-cfb-bot/internal/clients/cfb" // Adjust this import path as needed
"github.com/bwmarrin/discordgo"
)
var Bot *discordgo.Session
// MessageCreate handles incoming messages and triggers the appropriate response
func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from the bot itself
if m.Author.ID == s.State.User.ID {
return
}
func Start() error {
var err error
Bot, err = discordgo.New("Bot " + config.BotToken)
// Command for fetching college football scores
if strings.HasPrefix(m.Content, "!cfb") {
// Extract any arguments (e.g., week number) if needed
weekNumber := 10 // Replace this with dynamic parsing if necessary
games, err := cfb.FetchScoreboard(weekNumber)
if err != nil {
return fmt.Errorf("error creating a Discord session: %w", err)
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Error fetching games: %s", err))
return
}
fmt.Println("Discord session created successfully")
Bot.AddHandler(commandHandler)
err = Bot.Open()
if err != nil {
return fmt.Errorf("Error opening connection: %w", err)
if len(games) == 0 {
s.ChannelMessageSend(m.ChannelID, "No games found for this week.")
return
}
fmt.Println("Bot is now running.")
return nil
// Send formatted game summaries
for _, game := range games {
gameSummary := cfb.FormatGameOutput(game)
s.ChannelMessageSend(m.ChannelID, gameSummary)
}
}
}
func commandHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Author.Bot {
return
}
if strings.HasPrefix(m.Content, "!s ") {
teamName := strings.TrimSpace(strings.TrimPrefix(m.Content, "!s "))
response := clients.GetGameInfo(teamName)
s.ChannelMessageSend(m.ChannelID, response)
}
}

81
internal/clients/cfb.go Normal file
View File

@ -0,0 +1,81 @@
package cfb
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
)
// Game represents the structure of a single game
type Game struct {
AwayTeam string `json:"away_team"`
AwayScore string `json:"away_score"`
HomeTeam string `json:"home_team"`
HomeScore string `json:"home_score"`
GameState string `json:"game_state"`
CurrentPeriod string `json:"current_period"`
StartTime string `json:"start_time"`
ContestClock string `json:"contest_clock"`
StartTimeEpoch int64 `json:"start_time_epoch"`
}
// FetchScoreboard retrieves and parses the scoreboard data from the specified API URL
func FetchScoreboard(weekNumber int) ([]Game, error) {
apiKey := os.Getenv("CFBD_API_KEY")
if apiKey == "" {
return nil, errors.New("missing API key")
}
url := fmt.Sprintf("https://ncaa.ewnix.net/scoreboard/football/fbs/2024/%d/all-conf", weekNumber)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch scoreboard, status code: %d", resp.StatusCode)
}
body, _ := ioutil.ReadAll(resp.Body)
var data struct {
Games []struct {
Game Game `json:"game"`
} `json:"games"`
}
if err := json.Unmarshal(body, &data); err != nil {
return nil, fmt.Errorf("error parsing scoreboard: %w", err)
}
games := make([]Game, len(data.Games))
for i, g := range data.Games {
// Adjust start time by subtracting 5 hours for upcoming games
if g.Game.GameState == "upcoming" {
epochTime := time.Unix(g.Game.StartTimeEpoch, 0).Add(-5 * time.Hour)
g.Game.StartTime = epochTime.Format("03:04PM ET")
}
games[i] = g.Game
}
return games, nil
}
// FormatGameOutput formats the game data into a string
func FormatGameOutput(game Game) string {
if game.GameState == "live" {
return fmt.Sprintf("%s: *%s* %s: *%s* Quarter: %s Time Remaining: %s",
game.AwayTeam, game.AwayScore, game.HomeTeam, game.HomeScore, game.CurrentPeriod, game.ContestClock)
}
return fmt.Sprintf("%s: %s %s: %s Final",
game.AwayTeam, game.AwayScore, game.HomeTeam, game.HomeScore)
}

View File

@ -1,93 +0,0 @@
package clients
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"discord-cfb-bot/config"
)
type Game struct {
ID int `json:"id"`
StartDate string `json:"startDate"`
Status string `json:"status"`
Period *int `json:"period"`
Clock *string `json:"clock"`
HomeTeam Team `json:"homeTeam"`
AwayTeam Team `json:"awayTeam"`
}
type Team struct {
Name string `json:"name"`
Points *int `json:"points"`
}
func GetGameInfo(teamName string) string {
apiURL := "https://apinext.collegefootballdata.com/scoreboard"
req, _ := http.NewRequest("GET", apiURL, nil)
req.Header.Set("Authorization", "Bearer "+config.CFBDAPIKey) // Use the API key from config
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Sprintf("Failed to reach the scoreboard API: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Sprintf("Failed to reach the scoreboard API. Status code: %d", resp.StatusCode)
}
body, _ := ioutil.ReadAll(resp.Body)
var games []Game
if err := json.Unmarshal(body, &games); err != nil {
return "Error parsing the API response."
}
for _, game := range games {
if strings.Contains(strings.ToLower(game.HomeTeam.Name), strings.ToLower(teamName)) ||
strings.Contains(strings.ToLower(game.AwayTeam.Name), strings.ToLower(teamName)) {
startTime, _ := time.Parse(time.RFC3339, game.StartDate)
adjustedTime := startTime.Add(-5 * time.Hour) // Subtract 5 hours for upcoming games
formattedTime := adjustedTime.Format("03:04 PM")
if game.Status == "in_progress" {
return fmt.Sprintf("%s: **%d** %s: **%d** | Quarter: %d | Time Remaining: %s",
game.AwayTeam.Name, valueOrZero(game.AwayTeam.Points),
game.HomeTeam.Name, valueOrZero(game.HomeTeam.Points),
*game.Period, derefOrDefault(game.Clock, "00:00"))
} else if game.Status == "scheduled" {
return fmt.Sprintf("Upcoming: %s @ %s at %s Eastern",
game.AwayTeam.Name, game.HomeTeam.Name, formattedTime)
} else if game.Status == "completed" {
return fmt.Sprintf("Final: %s: %d %s: %d",
game.AwayTeam.Name, valueOrZero(game.AwayTeam.Points),
game.HomeTeam.Name, valueOrZero(game.HomeTeam.Points))
}
}
}
return "No game found for the specified team."
}
// Helper function to safely dereference pointers
func derefOrDefault(str *string, defaultVal string) string {
if str != nil {
return *str
}
return defaultVal
}
// Helper function to return a value or zero if nil
func valueOrZero(val *int) int {
if val != nil {
return *val
}
return 0
}