package main import ( "context" "encoding/json" "fmt" "log" "os" "strings" "time" "github.com/PuerkitoBio/goquery" "github.com/bwmarrin/discordgo" "github.com/chromedp/chromedp" ) type Config struct { DiscordBotToken string `json:"discord_bot_token"` ChannelMap map[string]string `json:"channel_map"` // Add the channel map to the config URL string `json:"url"` // Add URL field to the config } func main() { //Initialize Time date := "April 26, 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 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 } // 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 if token == "" { fmt.Println("Discord bot token is not set in config file") return } // Access the channel map from the configuration tagChannelMap := config.ChannelMap 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 dg, err := discordgo.New("Bot " + token) if err != nil { fmt.Println("Error creating Discord session:", err) return } // After creating the Discord session log.Println("Created Discord session") // Register messageCreate as a callback for the messageCreate events dg.AddHandler(messageCreate) // Open a websocket connection to Discord and begin listening err = dg.Open() if err != nil { fmt.Println("Error opening Discord connection:", err) return } // After opening the Discord connection log.Println("Opened Discord connection") // Run the scraping and message sending function at start up sendNotifications(dg, fetchUrl(url), tagChannelMap, date) // 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: sendNotifications(dg, fetchUrl(url), tagChannelMap, date) } } }() // 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{}) } func fetchUrl(url string) string { // 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{ chromedp.Navigate(url), chromedp.OuterHTML("html", &html), }) if err != nil { log.Fatal(err) } // Return the HTML content return html } // Add a function to extract relevant tags from the HTML content func extractNewsArticles(html string) []map[string]string { var articles []map[string]string doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) if err != nil { fmt.Println("Error parsing HTML:", err) return articles } // 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) }) return articles } func sendNotifications(session *discordgo.Session, html string, tagChannelMap map[string]string, specifiedDate string) { // Extract articles from the HTML content articles := extractNewsArticles(html) // 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"] // Check if the tag is in the desired tags list if tagChannelID, ok := tagChannelMap[tag]; ok { // 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 } // Send a message to the corresponding Discord channel message := "New <@&568064042086694913> have been released!" _, err := session.ChannelMessageSendComplex(tagChannelID, &discordgo.MessageSend{ Content: message, // Replace 568064042086694913 with the ID of the role to mention Embed: embed, AllowedMentions: &discordgo.MessageAllowedMentions{Roles: []string{"568064042086694913"}}, // Replace ROLE_ID with the ID of the role to mention }) if err != nil { fmt.Printf("Error sending message to Discord channel %s: %s\n", tagChannelID, err) continue } fmt.Println("Message sent to Discord channel:", tagChannelID) } } } } // This function will be called whenever a new message is created func messageCreate(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, "Hello!") } }