12 5ad39add 2021-04-27 op "path/filepath"
16 7cc05214 2021-04-27 op irc "github.com/fluffle/goirc/client"
17 5659492e 2021-12-02 op "golang.org/x/net/html"
21 88370dfe 2021-11-07 op baseurl = flag.String("baseurl", "gemini://m2i.omarpolo.com", "base url")
22 7cc05214 2021-04-27 op matrixOutDir = flag.String("matrix-out", "", "matrix out directory")
24 88370dfe 2021-11-07 op msgRe = regexp.MustCompile(`https://.*/[^\s]+\.(txt|png|jpg|jpeg|gif)`)
25 c6fd4def 2021-07-30 op channel = "#gemini-it"
27 88370dfe 2021-11-07 op tooLongRe = regexp.MustCompile(`full message at (https://libera.ems.host/.*)[)]`)
29 5659492e 2021-12-02 op httplink = regexp.MustCompile(`https?://[^\s]+`)
32 7cc05214 2021-04-27 op func matrix2gemini(conn *irc.Conn, line *irc.Line) {
33 ae97f748 2021-07-30 op matches := msgRe.FindAllString(line.Text(), -1)
35 7cc05214 2021-04-27 op // it's not a good idea to defer inside a loop, but we know
36 7cc05214 2021-04-27 op // len(matches) is small (usually just 1). Morover, I like
37 7cc05214 2021-04-27 op // living in danger!
39 7cc05214 2021-04-27 op for _, link := range matches {
40 7cc05214 2021-04-27 op resp, err := http.Get(link)
41 7cc05214 2021-04-27 op if err != nil {
44 7cc05214 2021-04-27 op fmt.Sprintf("failed to download %q: %s", link, err),
48 7cc05214 2021-04-27 op defer resp.Body.Close()
50 ae97f748 2021-07-30 op ext := path.Ext(link)
51 88370dfe 2021-11-07 op tmpfile, err := ioutil.TempFile(*matrixOutDir, "message-*"+ext)
52 7cc05214 2021-04-27 op if err != nil {
53 7cc05214 2021-04-27 op conn.Privmsg(channel, fmt.Sprintf("failed to tmpfile: %s", err))
56 7cc05214 2021-04-27 op defer tmpfile.Close()
58 7cc05214 2021-04-27 op io.Copy(tmpfile, resp.Body)
63 5ad39add 2021-04-27 op "better: %s/%s",
65 5ad39add 2021-04-27 op filepath.Base(tmpfile.Name()),
71 88370dfe 2021-11-07 op func messageTooLong(conn *irc.Conn, line *irc.Line) {
72 88370dfe 2021-11-07 op matches := tooLongRe.FindStringSubmatch(line.Text())
73 88370dfe 2021-11-07 op if len(matches) != 2 {
77 88370dfe 2021-11-07 op url := matches[1]
79 88370dfe 2021-11-07 op resp, err := http.Get(url)
80 88370dfe 2021-11-07 op if err != nil {
83 88370dfe 2021-11-07 op fmt.Sprintf("failed to download %q: %s", url, err),
87 88370dfe 2021-11-07 op defer resp.Body.Close()
89 88370dfe 2021-11-07 op sb := &strings.Builder{}
90 88370dfe 2021-11-07 op if _, err := io.Copy(sb, resp.Body); err != nil {
93 88370dfe 2021-11-07 op fmt.Sprintf("failed to read body of %q: %s", url, err),
98 88370dfe 2021-11-07 op conn.Privmsg(channel, fmt.Sprintf("%s ha detto:", line.Nick))
99 88370dfe 2021-11-07 op for _, line := range strings.Split(sb.String(), "\n") {
100 88370dfe 2021-11-07 op conn.Privmsg(
107 5659492e 2021-12-02 op func getPageTitle(node *html.Node) string {
108 5659492e 2021-12-02 op for child := node.FirstChild; child != nil; child = child.NextSibling {
109 5659492e 2021-12-02 op if child.Type == html.ElementNode && child.Data == "title" {
110 5659492e 2021-12-02 op text := node.FirstChild.Data
111 5659492e 2021-12-02 op return strings.Trim(text, " \t\n")
117 5659492e 2021-12-02 op func getPageHead(node *html.Node) *html.Node {
118 5659492e 2021-12-02 op if node.Type == html.ElementNode && node.Data == "head" {
122 5659492e 2021-12-02 op for child := node.FirstChild; child != nil; child = child.NextSibling {
123 5659492e 2021-12-02 op if n := getPageHead(node); n != nil {
130 5659492e 2021-12-02 op func pagetitle(conn *irc.Conn, line *irc.Line) {
131 5659492e 2021-12-02 op matches := httplink.FindAllString(line.Text(), -1)
133 5659492e 2021-12-02 op for _, link := range matches {
134 5659492e 2021-12-02 op resp, err := http.Get(link)
135 5659492e 2021-12-02 op if err != nil {
138 5659492e 2021-12-02 op defer resp.Body.Close()
140 5659492e 2021-12-02 op doc, err := html.Parse(resp.Body)
141 5659492e 2021-12-02 op if err != nil {
145 5659492e 2021-12-02 op head := getPageHead(doc)
146 5659492e 2021-12-02 op if head == nil {
149 5659492e 2021-12-02 op if title := getPageTitle(head); title != "" {
150 5659492e 2021-12-02 op conn.Privmsg(channel, title)
155 7cc05214 2021-04-27 op func dostuff(conn *irc.Conn, line *irc.Line) {
156 7cc05214 2021-04-27 op matrix2gemini(conn, line)
157 88370dfe 2021-11-07 op messageTooLong(conn, line)
158 5659492e 2021-12-02 op pagetitle(conn, line)
162 7cc05214 2021-04-27 op func main() {
165 7cc05214 2021-04-27 op cfg := irc.NewConfig("gemitbot")
166 7cc05214 2021-04-27 op cfg.SSL = true
167 d0286003 2021-07-30 op cfg.SSLConfig = &tls.Config{ServerName: "irc.libera.chat"}
168 d0286003 2021-07-30 op cfg.Server = "irc.libera.chat:7000"
169 7cc05214 2021-04-27 op cfg.NewNick = func(n string) string { return n + "^" }
171 7cc05214 2021-04-27 op c := irc.Client(cfg)
173 7cc05214 2021-04-27 op c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
174 7cc05214 2021-04-27 op log.Println("connected, joining", channel)
175 7cc05214 2021-04-27 op conn.Join(channel)
178 7cc05214 2021-04-27 op c.HandleFunc(irc.PRIVMSG, dostuff)
179 7cc05214 2021-04-27 op c.HandleFunc(irc.ACTION, dostuff)
181 7cc05214 2021-04-27 op quit := make(chan bool)
183 7cc05214 2021-04-27 op c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
187 7cc05214 2021-04-27 op if err := c.Connect(); err != nil {
188 7cc05214 2021-04-27 op log.Fatalln("connection error:", err)