package main import ( "encoding/json" "flag" "fmt" "log" "math/rand" "net/http" "os" "regexp" "time" "mcquay.me/exmo" irc "github.com/fluffle/goirc/client" ) var host = flag.String("host", "localhost:6668", "irc server hostname") var channel = flag.String("channel", "#exmormon", "irc channel") var top = flag.Int("top", 5, "number of top posts to use") func main() { maddr := os.Getenv("ADDR") if maddr == "" { fmt.Fprintf(os.Stderr, "failed to set ADDR\n") os.Exit(1) } if err := exmo.Metrics(maddr); err != nil { fmt.Fprintf(os.Stderr, "can't http: %v\n", err) os.Exit(1) } rand.Seed(time.Now().UnixNano()) flag.Parse() log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) done := make(chan bool) register(*host, *channel, done) <-done } const name = "reddit-exmo" func register(host, channel string, done chan<- bool) { var p *regexp.Regexp c := irc.SimpleClient(name, name) c.EnableStateTracking() c.HandleFunc( irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { conn.Join(channel) var err error p, err = regexp.Compile(`\b` + conn.Me().Nick + `\b`) if err != nil { log.Printf("%+v", err) } }, ) c.HandleFunc( irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) { done <- true }, ) c.HandleFunc( irc.PRIVMSG, func(conn *irc.Conn, line *irc.Line) { if p.MatchString(line.Text()) { log.Printf("addressed me: %v", line.Text()) } }, ) go func() { seen := map[string]int{} prime, err := items() if err != nil { log.Printf("%+v", err) } for _, i := range prime { seen[i.ID] = i.Score } for { latest, err := items() if err != nil { log.Printf("%+v", err) } for _, i := range latest { if _, ok := seen[i.ID]; ok { continue } log.Printf("decided to talk about this: %+v", i) seen[i.ID] = i.Score c.Privmsgf(channel, "%v", i) } time.Sleep(5 * time.Minute) } }() if err := c.ConnectTo(host); err != nil { fmt.Printf("Connection error: %s\n", err) } } type item struct { ID string `json:"id"` Author string `json:"author"` Score int `json:"score"` URL string `json:"url"` Title string `json:"title"` Comments int `json:"num_comments"` } func (i item) String() string { com := "" switch i.Comments { case 0: // nothing case 1: com = " (1 comment)" default: com = fmt.Sprintf(" (%d comments)", i.Comments) } url := fmt.Sprintf("https://redd.it/%s", i.ID) return fmt.Sprintf("%s %v (current score: %d) %s", i.Title, com, i.Score, url) } type response struct { Data struct { Children []struct { Data item } } } func items() ([]item, error) { url := fmt.Sprintf("https://www.reddit.com/r/exmormon.json") client := http.Client{} req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } req.Header.Set("User-Agent", "sm bot") resp, err := client.Do(req) if err != nil { return nil, err } rresp := response{} if err := json.NewDecoder(resp.Body).Decode(&rresp); err != nil { return nil, err } defer resp.Body.Close() items := []item{} for _, child := range rresp.Data.Children { items = append(items, child.Data) } if len(items) < *top { return items, nil } return items[:*top], nil }