package main import ( "bytes" "context" "encoding/base64" "encoding/json" "fmt" "log" "os" "strings" "git.fromouter.space/hamcha/tg" "github.com/mattn/go-mastodon" ) type mastodonConfig struct { Server string ClientID string ClientSecret string Email string Password string Chats []int64 } var mastodonClient *mastodon.Client var mastodonChats map[int64]bool func mastodon_init() { file, err := os.Open(*mastodonconf) if err != nil { return } defer file.Close() var cfg mastodonConfig err = json.NewDecoder(file).Decode(&cfg) if err != nil { log.Fatalf("[mastodon] ERR: Could not load mastodon config file (malformed or unreadable file): " + err.Error()) } mastodonClient = mastodon.NewClient(&mastodon.Config{ Server: cfg.Server, ClientID: cfg.ClientID, ClientSecret: cfg.ClientSecret, }) err = mastodonClient.Authenticate(context.Background(), cfg.Email, cfg.Password) if err != nil { log.Fatalf("[mastodon] ERR: Error authenticating: " + err.Error()) } mastodonChats = make(map[int64]bool) for _, chatid := range cfg.Chats { mastodonChats[chatid] = true } log.Println("[mastodon] Loaded and ready!") } func mastodon_message(broker *tg.Broker, update tg.APIMessage) { if isCommand(update, "post") { // Make sure only whitelisted chats can post if _, ok := mastodonChats[update.Chat.ChatID]; !ok { broker.SendTextMessage(update.Chat, "Mi spiace, non puoi postare stati da qui!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } // Make replies work if update.ReplyTo != nil { update.User = update.ReplyTo.User update.Text = update.ReplyTo.Text if update.ReplyTo.Photo != nil { update.Photo = update.ReplyTo.Photo update.Caption = update.ReplyTo.Caption } } // Check for media if update.Photo != nil { maxsz := 0 photo := tg.APIPhotoSize{} for _, curphoto := range update.Photo { if curphoto.Width > maxsz { maxsz = curphoto.Width photo = curphoto } } broker.GetFile(photo.FileID, func(broker *tg.Broker, data tg.BrokerUpdate) { if data.Type == tg.BError { log.Printf("[mastodon] Received error from broker: %s\n", *data.Error) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } pbytes, err := base64.StdEncoding.DecodeString(*data.Bytes) if err != nil { log.Printf("[mastodon] Base64 decode error: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } imgreader := bytes.NewReader(pbytes) broker.SendChatAction(update.Chat, tg.ActionUploadingPhoto) attach, err := mastodonClient.UploadMediaFromReader(context.Background(), imgreader) if err != nil { log.Printf("[mastodon] Upload failed: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } text := "" if update.Caption != nil { text = *(update.Caption) } status, err := sendToot(text, attach.ID) if err != nil { log.Printf("[mastodon] Send toot failed: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } broker.SendTextMessage(update.Chat, fmt.Sprintf("Fatto!", status.URL), &tg.MessageOptions{ ReplyID: &update.MessageID, }) }) return } // Strip command from beginning of text string, if it's there text := *(update.Text) if strings.HasPrefix(text, "/post ") || strings.HasPrefix(text, "/post@"+*botname+" ") { text = text[strings.IndexRune(text, ' ')+1:] } status, err := sendToot(text, "") if err != nil { log.Printf("[mastodon] Send toot failed: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } broker.SendTextMessage(update.Chat, fmt.Sprintf("Fatto!", status.URL), &tg.MessageOptions{ ReplyID: &update.MessageID, }) } } func sendToot(status string, media mastodon.ID) (*mastodon.Status, error) { var medialist []mastodon.ID if media != "" { medialist = []mastodon.ID{media} } return mastodonClient.PostStatus(context.Background(), &mastodon.Toot{ Status: status, MediaIDs: medialist, Sensitive: false, Visibility: "public", }) }