LoginSignup
4
3

More than 5 years have passed since last update.

mastodonのtootを原始人くんが喋ってくれるbot作った

Last updated at Posted at 2019-02-17

TL;DR

  • ぼくも原始人くんとなかよくなりたいになった

まずはcliで作った

  • そもそもmasotodonのAPI叩いたりしたことなかったので勉強がてらcliで作った
  • goでmastodonのクライアントあるんだっけって思ったけど速攻で mattnさんのやつ 見つけた
  • 以下原始人くんが最新のトゥートを拾ってきて翻訳してトゥートするとても簡単なコード
package main

import (
    "context"
    "fmt"
    "github.com/mattn/genshijin"
    "github.com/mattn/go-mastodon"
    "log"
)

func main() {
    c := mastodon.NewClient(&mastodon.Config{
        Server:       "https://example.com",
        ClientID:     "",
        ClientSecret: "",
    })
    err := c.Authenticate(context.Background(), "", "")
    if err != nil {
        log.Fatal(err)
    }
    s, err := c.GetAccountStatuses(context.Background(), mastodon.ID("2"), &mastodon.Pagination{})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(s[0].Content)
    _, err = c.PostStatus(context.Background(), &mastodon.Toot{
        Status: genshijin.Shaberu(s[0].Content),
    })
    if err != nil {
        log.Fatal(err)
    }
}

RSSを取得してtootさせるようにしてみた

  • 自身がtootしたらすぐ原始人くんがtootするようにしたかった
  • 「自身がtootした」っていうeventにhookさせる簡単な方法が思いつかなかったのでzapierでRSS取得して自鯖にPOSTするってZAP設置してみた
    • mastodon本体に手を入れたくなかった
    • サーバー側に新着かどうか判定するために保存するcache等もつくりたくなかった
  • FTLには出したくなかったので未収載にした
package main

import (
    "context"
    "fmt"
    "github.com/mattn/genshijin"
    "github.com/mattn/go-mastodon"
    "log"
    "net/http"
    "strings"
)

func handler(w http.ResponseWriter, r *http.Request) {
    c := mastodon.NewClient(&mastodon.Config{
        Server:       "",
        ClientID:     "",
        ClientSecret: "",
    })
    err := c.Authenticate(context.Background(), "", "")
    if err != nil {
        log.Fatal(err)
    }
    r.ParseForm()
    toot := genshijin.Shaberu(strings.Join(r.Form["toot"], ","))
    _, err = c.PostStatus(context.Background(), &mastodon.Toot{
        Status:     toot,
        Visibility: "unlisted",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Fprintf(w, "Hello, World")
    fmt.Println(toot)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8888", nil)
}
  • 作ったはいいけど15分に一度ぐらいの周期っぽいので全然おもしろくなかった

原始人くん自ら取りに行かせるようにしてみた

  • 今現在動いてるのがこれ
  • 最後のtootを last_toot に入れておいて同じであれば5秒スリープして再取得とか言うぶん投げっぷり
    • 実装中なんどかHttp Status Code 429 が帰ってきてこまりました
    • CPUが回りすぎているのでなんとかせねばならん
  • boostを弾きたいのでboostかどうかを Status.Reblog != nil で判定してるのだけど行儀が良いのかよくわからんになってる
package main

import (
    "context"
    "fmt"
    "github.com/mattn/genshijin"
    "github.com/mattn/go-mastodon"
    "log"
    "time"
)

func main() {
    c := mastodon.NewClient(&mastodon.Config{
        Server:       "",
        ClientID:     "",
        ClientSecret: "",
    })
    err := c.Authenticate(context.Background(), "", "")
    if err != nil {
        log.Fatal(err)
    }
    last_toot := ""
    for {
        s, err := c.GetAccountStatuses(context.Background(), mastodon.ID("2"), &mastodon.Pagination{})
        if err != nil {
            fmt.Println(err)
            time.Sleep(60 * time.Second)
            continue
        }
        if s[0].Reblog != nil {
            time.Sleep(5 * time.Second)
            continue
        }
        toot := genshijin.Shaberu(s[0].Content)
        if last_toot != toot {
            c.PostStatus(context.Background(), &mastodon.Toot{
                Status:     toot,
                Visibility: "unlisted",
            })
            fmt.Println(toot)
            last_toot = toot
        }
        time.Sleep(5 * time.Second)
    }
}

[追記]StreamingAPIでやった

package main

import (
        "context"
        "fmt"
        "github.com/mattn/genshijin"
        "github.com/mattn/go-mastodon"
        "log"
)

func main() {
        c := mastodon.NewClient(&mastodon.Config{
                Server:       "",
                ClientID:     "",
                ClientSecret: "",
        })

        err := c.Authenticate(context.Background(), "", "")
        if err != nil {
                log.Fatal(err)
        }

        wsc := c.NewWSClient()
        q, err := wsc.StreamingWSPublic(context.Background(), true)
        if err != nil {
                log.Fatal(err)
        }
        for e := range q {
                if t, ok := e.(*mastodon.UpdateEvent); ok {
                        if t.Status.Sensitive {
                                continue
                        }

                        fmt.Printf("\x1b[37m[%s] \x1b[35m%-20s: \x1b[33m%s\n", t.Status.CreatedAt.Local().Format("15:04:05"), t.Status.Account..Acct, t.Status.Content)
                        c.PostStatus(context.Background(), &mastodon.Toot{
                                Status:     genshijin.Shaberu(t.Status.Content),
                                Visibility: "unlisted",
                        })
                }
        }
}
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3