mastotool/main.go

182 lines
4.3 KiB
Go
Raw Normal View History

2018-11-22 04:35:51 +01:00
package main
import (
"bufio"
"context"
"flag"
"fmt"
"math"
"os"
"time"
mastodon "github.com/mattn/go-mastodon"
"github.com/muesli/goprogressbar"
)
var (
client *mastodon.Client
2018-11-22 06:48:21 +01:00
self *mastodon.Account
2018-11-22 04:35:51 +01:00
topN = flag.Int("top", 10, "shows the top N items in each category")
maxToots = flag.Int("recent", 0, "only account for the N most recent toots (excl replies & boosts)")
columns = flag.Int("columns", 80, "displays tables with N columns")
configFile = flag.String("config", "mastodon.json", "uses the specified config file")
// user = flag.String("user", "@fribbledom@mastodon.social", "shows stats for this user")
)
2018-11-22 22:25:08 +01:00
func registerApp(config *Config) (string, error) {
2018-11-22 04:35:51 +01:00
app, err := mastodon.RegisterApp(context.Background(), &mastodon.AppConfig{
Server: config.Value("instance").(string),
ClientName: "statootstics",
2018-11-22 22:25:08 +01:00
Scopes: "read",
2018-11-22 04:35:51 +01:00
Website: "",
})
if err != nil {
2018-11-22 22:25:08 +01:00
return "", err
2018-11-22 04:35:51 +01:00
}
config.Set("id", app.ClientID)
config.Set("secret", app.ClientSecret)
2018-11-22 22:25:08 +01:00
config.Set("redirectURI", app.RedirectURI)
return app.AuthURI, nil
2018-11-22 04:35:51 +01:00
}
func initClient() {
var err error
2018-11-22 22:25:08 +01:00
var instance, token, redirectURI, authURI, id, secret string
2018-11-22 04:35:51 +01:00
config, err := LoadConfig(*configFile)
if err == nil {
instance = config.Value("instance").(string)
id = config.Value("id").(string)
2018-11-22 22:25:08 +01:00
secret = config.Value("secret").(string)
token = config.Value("token").(string)
redirectURI = config.Value("redirectURI").(string)
2018-11-22 04:35:51 +01:00
}
scanner := bufio.NewScanner(os.Stdin)
if len(instance) == 0 {
fmt.Print("Which instance to connect to (e.g. https://mastodon.social): ")
scanner.Scan()
if scanner.Err() != nil {
panic(err)
}
instance = scanner.Text()
2018-11-22 22:25:08 +01:00
config.Set("instance", instance)
2018-11-22 04:35:51 +01:00
}
if len(id) == 0 {
2018-11-22 22:25:08 +01:00
authURI, err = registerApp(&config)
2018-11-22 04:35:51 +01:00
if err != nil {
panic(err)
}
id = config.Value("id").(string)
secret = config.Value("secret").(string)
2018-11-22 22:25:08 +01:00
redirectURI = config.Value("redirectURI").(string)
2018-11-22 04:35:51 +01:00
}
2018-11-22 22:25:08 +01:00
mConfig := &mastodon.Config{
AccessToken: token,
Server: instance,
ClientID: id,
ClientSecret: secret,
}
client = mastodon.NewClient(mConfig)
if len(mConfig.AccessToken) == 0 {
fmt.Printf("Please visit %s and enter the generated token: ", authURI)
scanner.Scan()
if scanner.Err() != nil {
panic(err)
}
code := scanner.Text()
err = client.AuthenticateToken(context.Background(), code, redirectURI)
2018-11-22 04:35:51 +01:00
if err != nil {
panic(err)
}
2018-11-22 22:25:08 +01:00
config.Set("token", mConfig.AccessToken)
config.Save(*configFile)
2018-11-22 04:35:51 +01:00
}
}
func main() {
flag.Parse()
initClient()
2018-11-22 06:48:21 +01:00
var err error
self, err = client.GetAccountCurrentUser(context.Background())
2018-11-22 04:35:51 +01:00
if err != nil {
panic(err)
}
/*
accounts, err := client.AccountsSearch(context.Background(), *user, 1)
if err != nil {
panic(err)
}
2018-11-22 06:48:21 +01:00
self = accounts[0]
2018-11-22 04:35:51 +01:00
*/
stats := &stats{
DaysActive: int(time.Since(self.CreatedAt).Hours() / 24),
Followers: self.FollowersCount,
Following: self.FollowingCount,
Toots: make(map[string]*tootStat),
Tags: make(map[string]*tootStat),
Replies: make(map[string]*tootStat),
Mentions: make(map[string]int64),
Boosts: make(map[string]int64),
2018-11-22 06:48:21 +01:00
Responses: make(map[string]int64),
2018-11-22 04:35:51 +01:00
}
pb := &goprogressbar.ProgressBar{
Text: fmt.Sprintf("Loading toots for %s", self.Username),
Total: self.StatusesCount,
PrependTextFunc: func(p *goprogressbar.ProgressBar) string {
return fmt.Sprintf("%d of %d", p.Current, int64(math.Max(float64(p.Current), float64(self.StatusesCount))))
},
Current: 0,
Width: 40,
}
var pg mastodon.Pagination
for {
pg.Limit = 40
statuses, err := client.GetAccountStatuses(context.Background(), self.ID, &pg)
if err != nil {
panic(err)
}
abort := false
2018-11-22 04:35:51 +01:00
for _, s := range statuses {
err = parseToot(s, stats)
if err != nil {
panic(err)
}
pb.Current += 1
pb.LazyPrint()
if *maxToots > 0 && len(stats.Toots) >= *maxToots {
abort = true
2018-11-22 04:35:51 +01:00
break
}
}
// For some reason, either because it's Pleroma or because I have too few toots,
// `pg.MaxID` never equals `""` and we get stuck looping forever. Add a simple
// break condition on "no statuses fetched" to avoid the issue.
if abort || pg.MaxID == "" || len(statuses) == 0 {
2018-11-22 04:35:51 +01:00
break
}
time.Sleep(1000 * time.Millisecond)
}
fmt.Printf("\n\n")
printAccountStats(stats)
printInteractionStats(stats)
printTootStats(stats)
printTagStats(stats)
}