Compare commits

...

3 Commits

Author SHA1 Message Date
7f95c31498 alpha release 2024-04-27 17:05:14 -04:00
075bdb2782 tagging role, embedding message content 2024-04-27 16:36:39 -04:00
42d5fc9dbe channel map moved to config 2024-04-27 12:34:35 -04:00
5 changed files with 162 additions and 76 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
config.json

View File

@ -1,4 +0,0 @@
{
"discord_bot_token": "MTIxNzA3NDM3ODE1MjM0NTcwMA.G5Evvi.AQ571YcyJK-Zt1RflylKU1K1Cnwuf80LOD43qw",
"discord_channel_id": "590581442392621067"
}

14
example.config.json Normal file
View File

@ -0,0 +1,14 @@
{
"discord_bot_token": "YOUR_BOT_TOKEN",
"role_map": {
"Role 1": "ROLE_ID_NUMBER",
"Role 2": "ROLE_ID_NUMBER",
"Role 3": "ROLE_ID_NUMBER"
},
"channel_map": {
"Channel 1": "ROLE_ID_NUMBER",
"Channel 2": "ROLE_ID_NUMBER",
"Channel 3": "ROLE_ID_NUMBER"
},
"url": "https://fallout.bethesda.net/en/news"
}

198
main.go
View File

@ -15,12 +15,21 @@ import (
) )
type Config struct { type Config struct {
DiscordBotToken string `json:"discord_bot_token"` DiscordBotToken string `json:"discord_bot_token"`
DiscordChannelID string `json:"discord_channel_id"` // Add more configuration fields here ChannelMap map[string]string `json:"channel_map"`
RoleMap map[string]string `json:"role_map"`
URL string `json:"url"`
} }
func main() { func main() {
//Initialize Time
//date := "April 16, 2024"
date := time.Now().Format("January 2, 2006")
// At the beginning of the main function
log.Println("Starting the bot...")
// Open and read the configuration file // Open and read the configuration file
configFile, err := os.Open("config.json") configFile, err := os.Open("config.json")
if err != nil { if err != nil {
@ -37,17 +46,32 @@ func main() {
return return
} }
// Access the Discord bot token from the configuration // After loading the configuration
log.Println("Loaded configuration from config.json")
// Access the Discord bot token and channel ID from the configuration
token := config.DiscordBotToken token := config.DiscordBotToken
if token == "" { if token == "" {
fmt.Println("Discord bot token is not set in config file") fmt.Println("Discord bot token is not set in config file")
return return
} }
// channelMap := config.ChannelMap
channelID := config.DiscordChannelID if len(channelMap) == 0 {
if channelID == "" { fmt.Println("Channel map is not set in config file")
fmt.Println("Discord channel ID is not set in config file") return
}
roleMap := config.RoleMap
if len(roleMap) == 0 {
fmt.Println("Role map is not set in config file")
return
}
url := config.URL
if url == "" {
fmt.Println("URL is not set in config file")
return
} }
// Create a new Discord session using the provided bot token // Create a new Discord session using the provided bot token
@ -57,20 +81,23 @@ func main() {
return return
} }
// After creating the Discord session
log.Println("Created Discord session")
// Register messageCreate as a callback for the messageCreate events // Register messageCreate as a callback for the messageCreate events
dg.AddHandler(messageCreate) dg.AddHandler(messageCreate)
dg.AddHandler(message2Create)
// Open a websocket connection to Discord and begin listening // Open a websocket connection to Discord and begin listening
err = dg.Open() err = dg.Open()
if err != nil { if err != nil {
fmt.Println("Error opening Discord connection:", err) fmt.Println("Error opening Discord connection:", err)
return return
} }
// After opening the Discord connection
log.Println("Opened Discord connection")
// Run the scraping and message sending function once at the specified time // Run the scraping and message sending function at start up
sendNotifications(dg, channelID, scrapeNews()) sendNotifications(dg, fetchUrl(url), channelMap, roleMap, date)
// Schedule the scraping and message sending function to run once a day // Schedule the scraping and message sending function to run once a day
ticker := time.NewTicker(24 * time.Hour) ticker := time.NewTicker(24 * time.Hour)
@ -81,19 +108,17 @@ func main() {
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
sendNotifications(dg, channelID, scrapeNews()) sendNotifications(dg, fetchUrl(url), channelMap, roleMap, date)
} }
} }
}() }()
//test()
// Wait here until CTRL-C or other term signal is received // Wait here until CTRL-C or other term signal is received
fmt.Println("Bot is now running. Press CTRL-C to exit.") fmt.Println("Bot is now running. Press CTRL-C to exit.")
<-make(chan struct{}) <-make(chan struct{})
} }
func scrapeNews() string { func fetchUrl(url string) string {
// Create a new context // Create a new context
ctx := context.Background() ctx := context.Background()
ctx, cancel := chromedp.NewContext( ctx, cancel := chromedp.NewContext(
@ -105,7 +130,7 @@ func scrapeNews() string {
// Navigate to the Fallout news page // Navigate to the Fallout news page
var html string var html string
err := chromedp.Run(ctx, chromedp.Tasks{ err := chromedp.Run(ctx, chromedp.Tasks{
chromedp.Navigate("https://fallout.bethesda.net/en/news"), chromedp.Navigate(url),
chromedp.OuterHTML("html", &html), chromedp.OuterHTML("html", &html),
}) })
if err != nil { if err != nil {
@ -117,59 +142,107 @@ func scrapeNews() string {
} }
// Add a function to extract relevant tags from the HTML content // Add a function to extract relevant tags from the HTML content
func extractTags(html string) []string { func extractNewsArticles(html string) []map[string]string {
var tags []string var articles []map[string]string
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
if err != nil { if err != nil {
fmt.Println("Error parsing HTML:", err) fmt.Println("Error parsing HTML:", err)
return tags return articles
} }
// Find and extract tags with class name "news-module-feed-item-details-tag"
doc.Find("span.news-module-feed-item-details-tag").Each(func(i int, s *goquery.Selection) { // Find and extract each article
tag := strings.TrimSpace(s.Text()) doc.Find("article.news-module-feed-item").Each(func(i int, s *goquery.Selection) {
tags = append(tags, tag) article := make(map[string]string)
// Extract link
link, exists := s.Find("a.news-module-feed-item-image").Attr("href")
if exists {
article["link"] = "https://fallout.bethesda.net" + link
}
// Extract title
title := strings.TrimSpace(s.Find("h3.news-module-feed-item-title").Text())
article["title"] = title
// Extract tag
tag := strings.TrimSpace(s.Find("span.news-module-feed-item-details-tag").Text())
article["tag"] = tag
// Extract date
date := strings.TrimSpace(s.Find("span.news-module-feed-item-details-date").Text())
article["date"] = date
// Extract game
game := strings.TrimSpace(s.Find("span.news-module-feed-item-details-game").Text())
article["game"] = game
// Extract blurb
blurb := strings.TrimSpace(s.Find("p.news-module-feed-item-blurb").Text())
article["blurb"] = blurb
// Extract image URL
imageURL, exists := s.Find("img.news-module-feed-item-image-tag").Attr("src")
if exists {
article["imageURL"] = "https:" + imageURL
}
articles = append(articles, article)
}) })
return tags
return articles
} }
// Define a map to associate each desired tag with its corresponding Discord channel ID func sendNotifications(session *discordgo.Session, html string, channelMap, roleMap map[string]string, specifiedDate string) {
var tagChannelMap = map[string]string{ // Extract articles from the HTML content
"Patch Notes": "556093419341086749", articles := extractNewsArticles(html)
"Atomic Shop": "590581442392621067",
"News": "558335339018846228",
// Add more tags and corresponding channel IDs as needed
}
func sendNotifications(session *discordgo.Session, channelID string, html string) { // Iterate over extracted articles
// Extract tags from the HTML content for _, article := range articles {
tags := extractTags(html) tag := article["tag"]
date := article["date"]
link := article["link"]
blurb := article["blurb"]
title := article["title"]
imageURL := article["imageURL"]
// Define today's date string
today := time.Now().Format("January 2, 2006")
// Iterate over extracted tags
for _, tag := range tags {
// Check if the tag is in the desired tags list // Check if the tag is in the desired tags list
if tagChannelID, ok := tagChannelMap[tag]; ok { if channelID, ok := channelMap[tag]; ok {
// Check if today's date matches the tag // Check if the article's date matches the specified date
if tag == today { if date == specifiedDate {
// Create a rich embed
embed := &discordgo.MessageEmbed{
Title: title,
Description: blurb,
URL: link,
Image: &discordgo.MessageEmbedImage{
URL: imageURL,
},
Color: 0x00ff00, // Green color for the embed
}
// Send a message to the corresponding Discord channel // Send a message to the corresponding Discord channel
message := fmt.Sprintf("Today's date matches the tag '%s' on the Fallout news page!", tag) message := fmt.Sprintf("New <@&%s> have been released!", roleMap[tag])
_, err := session.ChannelMessageSend(tagChannelID, message) _, err := session.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{
Content: message,
Embed: embed,
AllowedMentions: &discordgo.MessageAllowedMentions{}, // Allow mentions
})
if err != nil { if err != nil {
fmt.Printf("Error sending message to Discord channel %s: %s\n", tagChannelID, err) fmt.Printf("Error sending message to Discord channel %s: %s\n", channelID, err)
continue continue
} }
fmt.Println("Message sent to Discord channel:", tagChannelID) fmt.Println("Message sent to Discord channel:", channelID)
} else {
// Send a different message indicating the tag was found // Tag the corresponding role
message := fmt.Sprintf("Tag '%s' found on the Fallout news page, but it's not today's date.", tag) //if roleID, ok := roleMap[tag]; ok {
_, err := session.ChannelMessageSend(tagChannelID, message) // _, err := session.ChannelMessageSend(channelID, fmt.Sprintf("<@&%s>", roleID))
if err != nil { // if err != nil {
fmt.Printf("Error sending message to Discord channel %s: %s\n", tagChannelID, err) // fmt.Printf("Error tagging role %s in Discord channel %s: %s\n", roleID, channelID, err)
continue // } else {
} // fmt.Printf("Role %s tagged in Discord channel %s\n", roleID, channelID)
fmt.Println("Message sent to Discord channel:", tagChannelID) // }
//}
} }
} }
} }
@ -183,20 +256,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
} }
// If the message content is "!hello", respond with "Hello!" // If the message content is "!hello", respond with "Hello!"
if m.Content == "!hello1" { if m.Content == "!hello" {
_, _ = s.ChannelMessageSend(m.ChannelID, "Hello!") _, _ = s.ChannelMessageSend(m.ChannelID, "Hello!")
} }
} }
// This function will be called whenever a new message is created
func message2Create(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages created by the bot itself
if m.Author.ID == s.State.User.ID {
return
}
// If the message content is "!hello", respond with "Hello!"
if m.Content == "!hello" {
_, _ = s.ChannelMessageSend(m.ChannelID, "You are SUCH a NERD")
}
}

View File

@ -1,4 +1,19 @@
go mod download # Fallout News Discord Bot
go run main.go
right now it scrapes bethesda news and spit back dates in console and prints if today is today ## PreReqs
- Go
- Discord Developer Bot Credentials
- Discord Channels IDs
- Discord Role IDs
## Get Started
Go Get dependancies
`go mod download`
`cp example.config.json config.json`
fill out credentials in config with your information
Run the Bot:
`go run main.go`