From 90d1d6c267fcb5c328f08c1b9a621a0e83831ac5 Mon Sep 17 00:00:00 2001 From: Daniel Tam Date: Sat, 6 May 2023 18:32:36 -0500 Subject: [PATCH] initial commit --- .gitignore | 2 + README.md | 5 ++ config.ini.example | 16 +++++ go.mod | 10 +++ go.sum | 8 +++ main.go | 167 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 208 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.ini.example create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..462fade --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +config.ini +.devcontainer/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b51d03a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Reddit notify +An app that periodically checks a subreddit for a keyword and will send out an SMTP message if found + +# Config +Configuration is done via a `config.ini` file within the same location of the application. Check the example on how to properly set up the `config.ini` file. \ No newline at end of file diff --git a/config.ini.example b/config.ini.example new file mode 100644 index 0000000..91a15e4 --- /dev/null +++ b/config.ini.example @@ -0,0 +1,16 @@ +# Subreddit to parse +subreddit = rabbits + +# Interval (in minutes) to check subreddit +interval = 5 + +# Keyword to search for within title and text +keyword = cute + +# SMTP information +smtp_server = localhost +smtp_port = 25 +smtp_username = test +smtp_password = test +smtp_to = test@test.com +smtp_from = test@test.com diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c0b57c6 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module reddit_notify + +go 1.20 + +require ( + github.com/buger/jsonparser v1.1.1 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/mail.v2 v2.3.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..aec75a6 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d69d079 --- /dev/null +++ b/main.go @@ -0,0 +1,167 @@ +package main + +import ( + "fmt" + "io" + "net/http" + "os" + "strconv" + "strings" + "time" + + "github.com/buger/jsonparser" + "gopkg.in/ini.v1" + gomail "gopkg.in/mail.v2" +) + +var ( + subreddit, keyword, smtpServer, smtpTo, smtpFrom, smtpUsername, smtpPassword string + interval, smtpPort int +) + +func main() { + // Load config + cfg, err := ini.Load("config.ini") + + if err != nil { + quitConfigParseError(err.Error()) + } + + // Parse and check config values + if cfg.Section("app").HasKey("subreddit") { + subreddit = cfg.Section("app").Key("subreddit").String() + } else { + quitConfigParseError("Missing 'subreddit'") + } + + if cfg.Section("app").HasKey("interval") { + // default to 5 minutes + interval = cfg.Section("app").Key("interval").MustInt(5) + } else { + quitConfigParseError("Missing 'interval'") + } + + if cfg.Section("app").HasKey("keyword") { + keyword = cfg.Section("app").Key("keyword").String() + } else { + quitConfigParseError("Missing 'keyword'") + } + + if cfg.Section("smtp").HasKey("smtp_server") { + smtpServer = cfg.Section("smtp").Key("smtp_server").String() + } else { + quitConfigParseError("Missing 'smtp_server'") + } + + if cfg.Section("smtp").HasKey("smtp_port") { + // default to port 25 + smtpPort = cfg.Section("smtp").Key("smtp_port").MustInt(25) + } else { + quitConfigParseError("Missing 'smtp_port'") + } + + if cfg.Section("smtp").HasKey("smtp_username") { + smtpUsername = cfg.Section("smtp").Key("smtp_username").String() + } else { + quitConfigParseError("Missing 'smtp_username'") + } + + if cfg.Section("smtp").HasKey("smtp_password") { + smtpPassword = cfg.Section("smtp").Key("smtp_password").String() + } else { + quitConfigParseError("Missing 'smtp_password'") + } + + if cfg.Section("smtp").HasKey("smtp_to") { + smtpTo = cfg.Section("smtp").Key("smtp_to").String() + } else { + quitConfigParseError("Missing 'smtp_to'") + } + + if cfg.Section("smtp").HasKey("smtp_from") { + smtpFrom = cfg.Section("smtp").Key("smtp_from").String() + } else { + quitConfigParseError("Missing 'smtp_from'") + } + + loop() + +} + +func loop() { + // Setup + subreddit_rss := "https://www.reddit.com/r/" + subreddit + "/.json" + + client := &http.Client{} + req, err := http.NewRequest("GET", subreddit_rss, nil) + if err != nil { + fmt.Println(err) + } + + // Set a header otherwise it'll be blocked + req.Header.Set("User-Agent", "Golang_Reddit_Notif/1.0") + + // Continually GET subreddit for interval time + for { + + // Get from subreddit + resp, err := client.Do(req) + if err != nil { + fmt.Println(err) + } + + // Response from subreddit + body, _ := io.ReadAll(resp.Body) + resp.Body.Close() + + // Amount of items + limit64, _ := jsonparser.GetInt(body, "data", "dist") + limit := int(limit64) + + // Loop through titles and texts + for i := 0; i < limit; i++ { + index := strconv.Itoa(i) + title, _ := jsonparser.GetString(body, "data", "children", "["+index+"]", "data", "title") + text, _ := jsonparser.GetString(body, "data", "children", "["+index+"]", "data", "selftext") + url, _ := jsonparser.GetString(body, "data", "children", "["+index+"]", "data", "url") + alert := false + + // Check if keyword matches + if strings.Contains(strings.ToLower(title), keyword) { + alert = true + } else if strings.Contains(strings.ToLower(text), keyword) { + alert = true + } + + // Send alert if keyword found + if alert { + sendAlert(title, text, url) + } + + } + + // Sleep for interval time + time.Sleep(time.Duration(interval) * time.Minute) + } +} + +func quitConfigParseError(msg string) { + fmt.Println("Error parsing config.ini: ", msg) + os.Exit(1) +} + +func sendAlert(title string, text string, url string) { + // Setup + m := gomail.NewMessage() + m.SetHeader("From", smtpFrom) + m.SetHeader("To", smtpTo) + m.SetHeader("Subject", "Reddit Notify: Found match ("+title+")") + m.SetBody("text/plain", "Keyword: "+keyword+"\n\n\n"+title+"\n\n\n"+text) + + // Send via gomail + d := gomail.NewDialer(smtpServer, smtpPort, smtpUsername, smtpPassword) + + if err := d.DialAndSend(m); err != nil { + fmt.Println(err) + } +}