130 lines · 3.1 KB · Go
RawDownload
package main import (	"bufio"	"crypto/md5"	"errors"	"flag"	"fmt"	"io"	"log"	"os"	"sort"	"strings"	"time" 	irc "github.com/fluffle/goirc/client"	"github.com/mmcdole/gofeed") var (	server   = flag.String("server", "", "IRC server")	channel  = flag.String("channel", "", "IRC channel")	nick     = flag.String("nick", "", "IRC nickname")	period   = flag.String("period", "10m", "Update period")	seenPath = flag.String("seen", "", "\"Seen\" entries store")	postOld  = flag.Bool("post-old", false, "Post all entries on the first fetch ever")) func main() {	flag.Parse()	if !flag.Parsed() || *server == "" || *channel == "" || *nick == "" || *seenPath == "" || len(flag.Args()) == 0 {		flag.Usage()		if flag.Parsed() {			fmt.Fprintln(os.Stderr, "Flags -server, -channel, -nick and -seen are not optional.")			fmt.Fprintln(os.Stderr, "At least one url has to be provided.")		}		os.Exit(1)	} 	updatePeriod, err := time.ParseDuration(*period)	if err == nil && updatePeriod < 5*time.Minute {		err = fmt.Errorf("too short: %s", updatePeriod)	}	if err != nil {		fmt.Fprintf(os.Stderr, "update period: %s", err)		os.Exit(1)	} 	seenFile, err := os.OpenFile(*seenPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)	if err != nil {		fmt.Fprintf(os.Stderr, "seen file: %s", err)		os.Exit(1)	}	defer seenFile.Close()	seenReader := bufio.NewReader(seenFile)	seen := make(map[[md5.Size]byte]struct{})	for {		if url, err := seenReader.ReadString('\n'); err != nil {			if errors.Is(err, io.EOF) {				break			}			fmt.Fprintf(os.Stderr, "seen file: %s", err)			os.Exit(1)		} else {			url := []byte(strings.TrimSpace(url))			seen[md5.Sum(url)] = struct{}{}		}	} 	urls := flag.Args()	skipFirst := make(map[string]struct{})	if len(seen) == 0 && !*postOld {		for _, url := range urls {			skipFirst[url] = struct{}{}		}	} 	cfg := irc.NewConfig(*nick, "feed2ircbot", "feed2irc bot")	c := irc.Client(cfg)	c.EnableStateTracking()	c.HandleFunc(irc.CONNECTED, func(*irc.Conn, *irc.Line) {		log.Printf("irc: connected")		c.Join(*channel)	})	c.HandleFunc(irc.DISCONNECTED, func(*irc.Conn, *irc.Line) {		log.Printf("irc: disconnected")		os.Exit(1)	}) 	joinedChan := make(chan bool, 1)	c.HandleFunc(irc.JOIN, func(c *irc.Conn, line *irc.Line) {		if c.Me().Nick == line.Nick {			log.Printf("irc: joined")			close(joinedChan)		}	})	if err := c.ConnectTo(*server); err != nil {		fmt.Fprintf(os.Stderr, "irc: %s", err)		os.Exit(1)	} 	<-joinedChan	for {		for _, url := range urls {			p := gofeed.NewParser()			if feed, err := p.ParseURL(url); err != nil {				log.Printf("%s: %s", url, err)			} else {				sort.Sort(feed)				for _, item := range feed.Items {					sum := md5.Sum([]byte(item.Link))					if _, have := seen[sum]; !have {						if _, err := fmt.Fprintln(seenFile, item.Link); err != nil {							log.Printf("seen file: %s", err)							os.Exit(1)						}						seenFile.Sync()						seen[sum] = struct{}{}						if _, skip := skipFirst[url]; !skip {							s := fmt.Sprintf("%s | %s\n", item.Title, item.Link)							c.Privmsgln(*channel, s)						}					}				}				delete(skipFirst, url)			}		}		time.Sleep(updatePeriod)	}}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t