2024-04-27 01:20:47 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-04-28 02:30:53 +00:00
|
|
|
"NukaNewsBot/commands"
|
2024-04-27 01:20:47 +00:00
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
|
|
"github.com/bwmarrin/discordgo"
|
|
|
|
"github.com/chromedp/chromedp"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
2024-04-27 16:34:35 +00:00
|
|
|
DiscordBotToken string `json:"discord_bot_token"`
|
2024-04-27 21:05:14 +00:00
|
|
|
ChannelMap map[string]string `json:"channel_map"`
|
|
|
|
RoleMap map[string]string `json:"role_map"`
|
|
|
|
URL string `json:"url"`
|
2024-04-27 01:20:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
2024-04-27 20:36:39 +00:00
|
|
|
//Initialize Time
|
2024-04-27 21:05:14 +00:00
|
|
|
//date := "April 16, 2024"
|
|
|
|
date := time.Now().Format("January 2, 2006")
|
2024-04-27 20:36:39 +00:00
|
|
|
|
2024-04-27 16:34:35 +00:00
|
|
|
// At the beginning of the main function
|
|
|
|
log.Println("Starting the bot...")
|
|
|
|
|
2024-04-27 02:30:28 +00:00
|
|
|
// Open and read the configuration file
|
|
|
|
configFile, err := os.Open("config.json")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Error opening config file:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer configFile.Close()
|
|
|
|
|
|
|
|
// Parse the configuration from JSON
|
|
|
|
var config Config
|
|
|
|
err = json.NewDecoder(configFile).Decode(&config)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Error decoding config JSON:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-27 16:34:35 +00:00
|
|
|
// After loading the configuration
|
|
|
|
log.Println("Loaded configuration from config.json")
|
|
|
|
|
|
|
|
// Access the Discord bot token and channel ID from the configuration
|
2024-04-27 02:30:28 +00:00
|
|
|
token := config.DiscordBotToken
|
|
|
|
if token == "" {
|
|
|
|
fmt.Println("Discord bot token is not set in config file")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-27 21:05:14 +00:00
|
|
|
channelMap := config.ChannelMap
|
|
|
|
if len(channelMap) == 0 {
|
|
|
|
fmt.Println("Channel map 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
|
|
|
|
}
|
2024-04-27 02:30:28 +00:00
|
|
|
|
2024-04-27 20:36:39 +00:00
|
|
|
url := config.URL
|
|
|
|
if url == "" {
|
|
|
|
fmt.Println("URL is not set in config file")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-27 02:30:28 +00:00
|
|
|
// Create a new Discord session using the provided bot token
|
|
|
|
dg, err := discordgo.New("Bot " + token)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Error creating Discord session:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-27 16:34:35 +00:00
|
|
|
// After creating the Discord session
|
|
|
|
log.Println("Created Discord session")
|
|
|
|
|
2024-04-28 02:30:53 +00:00
|
|
|
// Register commandHandler as a callback for message creation events
|
|
|
|
dg.AddHandler(commands.CommandHandler)
|
|
|
|
|
|
|
|
// After creating the Discord session
|
|
|
|
log.Println("Listening for Commands")
|
2024-04-27 02:30:28 +00:00
|
|
|
|
|
|
|
// Open a websocket connection to Discord and begin listening
|
|
|
|
err = dg.Open()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Error opening Discord connection:", err)
|
|
|
|
return
|
|
|
|
}
|
2024-04-27 16:34:35 +00:00
|
|
|
// After opening the Discord connection
|
|
|
|
log.Println("Opened Discord connection")
|
2024-04-27 02:30:28 +00:00
|
|
|
|
2024-04-27 20:36:39 +00:00
|
|
|
// Run the scraping and message sending function at start up
|
2024-04-28 02:30:53 +00:00
|
|
|
//sendNotifications(dg, fetchUrl(url), channelMap, roleMap, date)
|
2024-04-27 01:20:47 +00:00
|
|
|
|
2024-04-27 02:30:28 +00:00
|
|
|
// Schedule the scraping and message sending function to run once a day
|
|
|
|
ticker := time.NewTicker(24 * time.Hour)
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
// Run the scraping and message sending function when the ticker ticks
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
2024-04-27 21:05:14 +00:00
|
|
|
sendNotifications(dg, fetchUrl(url), channelMap, roleMap, date)
|
2024-04-27 02:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Wait here until CTRL-C or other term signal is received
|
|
|
|
fmt.Println("Bot is now running. Press CTRL-C to exit.")
|
|
|
|
<-make(chan struct{})
|
2024-04-27 01:20:47 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 20:36:39 +00:00
|
|
|
func fetchUrl(url string) string {
|
2024-04-27 01:20:47 +00:00
|
|
|
// Create a new context
|
|
|
|
ctx := context.Background()
|
|
|
|
ctx, cancel := chromedp.NewContext(
|
|
|
|
ctx,
|
|
|
|
chromedp.WithLogf(log.Printf),
|
|
|
|
)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
// Navigate to the Fallout news page
|
|
|
|
var html string
|
|
|
|
err := chromedp.Run(ctx, chromedp.Tasks{
|
2024-04-27 20:36:39 +00:00
|
|
|
chromedp.Navigate(url),
|
2024-04-27 01:20:47 +00:00
|
|
|
chromedp.OuterHTML("html", &html),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the HTML content
|
|
|
|
return html
|
|
|
|
}
|
|
|
|
|
2024-04-27 01:59:05 +00:00
|
|
|
// Add a function to extract relevant tags from the HTML content
|
2024-04-27 20:36:39 +00:00
|
|
|
func extractNewsArticles(html string) []map[string]string {
|
|
|
|
var articles []map[string]string
|
|
|
|
|
2024-04-27 02:30:28 +00:00
|
|
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Error parsing HTML:", err)
|
2024-04-27 20:36:39 +00:00
|
|
|
return articles
|
2024-04-27 02:30:28 +00:00
|
|
|
}
|
2024-04-27 20:36:39 +00:00
|
|
|
|
|
|
|
// Find and extract each article
|
|
|
|
doc.Find("article.news-module-feed-item").Each(func(i int, s *goquery.Selection) {
|
|
|
|
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)
|
2024-04-27 02:30:28 +00:00
|
|
|
})
|
2024-04-27 20:36:39 +00:00
|
|
|
|
|
|
|
return articles
|
2024-04-27 01:59:05 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 21:05:14 +00:00
|
|
|
func sendNotifications(session *discordgo.Session, html string, channelMap, roleMap map[string]string, specifiedDate string) {
|
2024-04-27 20:36:39 +00:00
|
|
|
// Extract articles from the HTML content
|
|
|
|
articles := extractNewsArticles(html)
|
2024-04-27 02:30:28 +00:00
|
|
|
|
2024-04-27 20:36:39 +00:00
|
|
|
// Iterate over extracted articles
|
|
|
|
for _, article := range articles {
|
|
|
|
tag := article["tag"]
|
|
|
|
date := article["date"]
|
|
|
|
link := article["link"]
|
|
|
|
blurb := article["blurb"]
|
|
|
|
title := article["title"]
|
|
|
|
imageURL := article["imageURL"]
|
2024-04-27 02:30:28 +00:00
|
|
|
|
|
|
|
// Check if the tag is in the desired tags list
|
2024-04-27 21:05:14 +00:00
|
|
|
if channelID, ok := channelMap[tag]; ok {
|
2024-04-27 20:36:39 +00:00
|
|
|
// Check if the article's date matches the specified date
|
|
|
|
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
|
2024-04-27 02:30:28 +00:00
|
|
|
}
|
2024-04-27 20:36:39 +00:00
|
|
|
|
|
|
|
// Send a message to the corresponding Discord channel
|
2024-04-27 21:05:14 +00:00
|
|
|
message := fmt.Sprintf("New <@&%s> have been released!", roleMap[tag])
|
|
|
|
_, err := session.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{
|
|
|
|
Content: message,
|
2024-04-27 20:36:39 +00:00
|
|
|
Embed: embed,
|
2024-04-27 21:05:14 +00:00
|
|
|
AllowedMentions: &discordgo.MessageAllowedMentions{}, // Allow mentions
|
2024-04-27 20:36:39 +00:00
|
|
|
})
|
2024-04-27 02:30:28 +00:00
|
|
|
if err != nil {
|
2024-04-27 21:05:14 +00:00
|
|
|
fmt.Printf("Error sending message to Discord channel %s: %s\n", channelID, err)
|
2024-04-27 02:30:28 +00:00
|
|
|
continue
|
|
|
|
}
|
2024-04-27 21:05:14 +00:00
|
|
|
fmt.Println("Message sent to Discord channel:", channelID)
|
|
|
|
|
2024-04-27 02:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-27 02:15:11 +00:00
|
|
|
|
2024-04-27 01:20:47 +00:00
|
|
|
// This function will be called whenever a new message is created
|
2024-04-28 02:30:53 +00:00
|
|
|
//func CommandHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|
|
|
// // Ignore messages created by the bot itself
|
|
|
|
// if m.Author.ID == s.State.User.ID {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Check if the message starts with a command prefix
|
|
|
|
// if strings.HasPrefix(m.Content, "!") {
|
|
|
|
// // Extract the command and arguments
|
|
|
|
// parts := strings.Fields(m.Content)
|
|
|
|
// command := parts[0]
|
|
|
|
//
|
|
|
|
// // Find the corresponding handler function in the map
|
|
|
|
// if handlerFunc, ok := commands.CommandMap[command]; ok {
|
|
|
|
// // Call the handler function
|
|
|
|
// handlerFunc(s, m)
|
|
|
|
// } else {
|
|
|
|
// // Respond to unknown commands
|
|
|
|
// _, _ = s.ChannelMessageSend(m.ChannelID, "Unknown command. Type !help for a list of commands.")
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|