Decouple layers 🚀
This commit is contained in:
parent
0ccb1226fc
commit
a1b10758cd
52
cfg/environ.go
Normal file
52
cfg/environ.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package cfg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MASTODON_ACCESS_TOKEN = "MASTODON_ACCESS_TOKEN"
|
||||||
|
MASTODON_SERVER_ADDRESS = "MASTODON_SERVER_ADDRESS"
|
||||||
|
MASTODON_TOOT_FOOTER = "MASTODON_TOOT_FOOTER"
|
||||||
|
MASTODON_TOOT_MAX_CHARACTERS = "MASTODON_TOOT_MAX_CHARACTERS"
|
||||||
|
MASTODON_TOOT_VISIBILITY = "MASTODON_TOOT_VISIBILITY"
|
||||||
|
TELEGRAM_BOT_TOKEN = "TELEGRAM_BOT_TOKEN"
|
||||||
|
TELEGRAM_CHAT_ID = "TELEGRAM_CHAT_ID"
|
||||||
|
TELEGRAM_DEBUG = "TELEGRAM_DEBUG"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check the specified Mastodon visibility and return it if valid or return
|
||||||
|
// unlisted if it's not valid.
|
||||||
|
// The specified string will be cheched case unsensitive.
|
||||||
|
func parseMastodonVisibility(s string) string {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
// Keep sorted since we search inside.
|
||||||
|
visibilities := []string{"direct", "private", "public", "unlisted"}
|
||||||
|
r := sort.SearchStrings(visibilities, s)
|
||||||
|
if r < len(visibilities) && visibilities[r] == s {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unlisted"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return configured Mastodon visibility for toot.
|
||||||
|
func GetMastodonVisibility() string {
|
||||||
|
return parseMastodonVisibility(os.Getenv(MASTODON_TOOT_VISIBILITY))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Mastodon max characters and return 500 as default in case of errors.
|
||||||
|
func parseMastodonMaxCharacters(s string) int {
|
||||||
|
if n, err := strconv.ParseUint(s, 10, 32); err == nil {
|
||||||
|
return int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 500
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMastodonMaxCharacters() int {
|
||||||
|
return parseMastodonMaxCharacters(os.Getenv(MASTODON_TOOT_MAX_CHARACTERS))
|
||||||
|
}
|
30
cfg/environ_test.go
Normal file
30
cfg/environ_test.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package cfg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/alecthomas/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseMastodonVisibility(t *testing.T) {
|
||||||
|
assert.Equal(t, parseMastodonVisibility("public"), "public")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("direct"), "direct")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("unlisted"), "unlisted")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("private"), "private")
|
||||||
|
|
||||||
|
assert.Equal(t, parseMastodonVisibility("Public"), "public")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("diRect"), "direct")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("unlisTED"), "unlisted")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("PRIVATE"), "private")
|
||||||
|
|
||||||
|
assert.Equal(t, parseMastodonVisibility("True"), "unlisted")
|
||||||
|
assert.Equal(t, parseMastodonVisibility("eriol"), "unlisted")
|
||||||
|
assert.Equal(t, parseMastodonVisibility(""), "unlisted")
|
||||||
|
assert.Equal(t, parseMastodonVisibility(" "), "unlisted")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseMastodonMaxCharacters(t *testing.T) {
|
||||||
|
assert.Equal(t, parseMastodonMaxCharacters("42"), 42)
|
||||||
|
assert.Equal(t, parseMastodonMaxCharacters("-42"), 500)
|
||||||
|
assert.Equal(t, parseMastodonMaxCharacters("hello"), 500)
|
||||||
|
}
|
104
cmd/run.go
104
cmd/run.go
|
@ -1,20 +1,19 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cking/go-mastodon"
|
mastodonapi "github.com/cking/go-mastodon"
|
||||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"noa.mornie.org/eriol/telegram-group2mastodon/cfg"
|
||||||
|
"noa.mornie.org/eriol/telegram-group2mastodon/mastodon"
|
||||||
"noa.mornie.org/eriol/telegram-group2mastodon/utils"
|
"noa.mornie.org/eriol/telegram-group2mastodon/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +22,6 @@ const (
|
||||||
MASTODON_SERVER_ADDRESS = "MASTODON_SERVER_ADDRESS"
|
MASTODON_SERVER_ADDRESS = "MASTODON_SERVER_ADDRESS"
|
||||||
MASTODON_TOOT_FOOTER = "MASTODON_TOOT_FOOTER"
|
MASTODON_TOOT_FOOTER = "MASTODON_TOOT_FOOTER"
|
||||||
MASTODON_TOOT_MAX_CHARACTERS = "MASTODON_TOOT_MAX_CHARACTERS"
|
MASTODON_TOOT_MAX_CHARACTERS = "MASTODON_TOOT_MAX_CHARACTERS"
|
||||||
MASTODON_TOOT_VISIBILITY = "MASTODON_TOOT_VISIBILITY"
|
|
||||||
TELEGRAM_BOT_TOKEN = "TELEGRAM_BOT_TOKEN"
|
TELEGRAM_BOT_TOKEN = "TELEGRAM_BOT_TOKEN"
|
||||||
TELEGRAM_CHAT_ID = "TELEGRAM_CHAT_ID"
|
TELEGRAM_CHAT_ID = "TELEGRAM_CHAT_ID"
|
||||||
TELEGRAM_DEBUG = "TELEGRAM_DEBUG"
|
TELEGRAM_DEBUG = "TELEGRAM_DEBUG"
|
||||||
|
@ -38,15 +36,14 @@ var runCmd = &cobra.Command{
|
||||||
Every messages posted in the Telegram groups the bot is in will be posted into
|
Every messages posted in the Telegram groups the bot is in will be posted into
|
||||||
the specified Mastodon account.`,
|
the specified Mastodon account.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
mastodon_instance := os.Getenv(MASTODON_SERVER_ADDRESS)
|
mastodonInstance := os.Getenv(MASTODON_SERVER_ADDRESS)
|
||||||
c := mastodon.NewClient(&mastodon.Config{
|
c := mastodonapi.NewClient(&mastodonapi.Config{
|
||||||
Server: mastodon_instance,
|
Server: mastodonInstance,
|
||||||
AccessToken: os.Getenv(MASTODON_ACCESS_TOKEN),
|
AccessToken: os.Getenv(MASTODON_ACCESS_TOKEN),
|
||||||
})
|
})
|
||||||
log.Println("Crating a new client for mastondon istance:", mastodon_instance)
|
log.Println("Crating a new client for mastondon istance:", mastodonInstance)
|
||||||
max_characters := parseMastodonMaxCharacters(os.Getenv(MASTODON_TOOT_MAX_CHARACTERS))
|
allowedTelegramChat := parseTelegramChatID(os.Getenv(TELEGRAM_CHAT_ID))
|
||||||
allowed_telegram_chat := parseTelegramChatID(os.Getenv(TELEGRAM_CHAT_ID))
|
log.Println("Allowed telegram chat id:", allowedTelegramChat)
|
||||||
log.Println("Allowed telegram chat id:", allowed_telegram_chat)
|
|
||||||
|
|
||||||
bot, err := tgbotapi.NewBotAPI(os.Getenv(TELEGRAM_BOT_TOKEN))
|
bot, err := tgbotapi.NewBotAPI(os.Getenv(TELEGRAM_BOT_TOKEN))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -62,39 +59,26 @@ the specified Mastodon account.`,
|
||||||
|
|
||||||
for update := range updates {
|
for update := range updates {
|
||||||
chatID := update.Message.Chat.ID
|
chatID := update.Message.Chat.ID
|
||||||
if chatID != allowed_telegram_chat {
|
if chatID != allowedTelegramChat {
|
||||||
log.Printf("Error: telegram chat %d is not the allowed one: %d\n",
|
log.Printf("Error: telegram chat %d is not the allowed one: %d\n",
|
||||||
chatID,
|
chatID,
|
||||||
allowed_telegram_chat,
|
allowedTelegramChat,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if update.Message != nil {
|
if update.Message != nil {
|
||||||
messageID := update.Message.MessageID
|
messageID := update.Message.MessageID
|
||||||
|
maxChars := cfg.GetMastodonMaxCharacters()
|
||||||
|
tootVisibility := cfg.GetMastodonVisibility()
|
||||||
|
tootFooter := os.Getenv(MASTODON_TOOT_FOOTER)
|
||||||
|
|
||||||
if update.Message.Text != "" {
|
if update.Message.Text != "" {
|
||||||
log.Printf("Text message received. Message id: %d\n", messageID)
|
log.Printf("Text message received. Message id: %d\n", messageID)
|
||||||
|
|
||||||
text := update.Message.Text
|
text := update.Message.Text
|
||||||
in_reply_to := ""
|
messages := utils.SplitTextAtChunk(text, maxChars, tootFooter)
|
||||||
|
mastodon.PostToots(c, messages, tootVisibility)
|
||||||
toot_footer := os.Getenv(MASTODON_TOOT_FOOTER)
|
|
||||||
|
|
||||||
messages := utils.SplitTextAtChunk(text, max_characters, toot_footer)
|
|
||||||
for _, message := range messages {
|
|
||||||
status, err := c.PostStatus(context.Background(), &mastodon.Toot{
|
|
||||||
Status: message,
|
|
||||||
Visibility: parseMastodonVisibility(os.Getenv(MASTODON_TOOT_VISIBILITY)),
|
|
||||||
InReplyToID: mastodon.ID(in_reply_to),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Could not post status: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("Posted status %s", status.URL)
|
|
||||||
in_reply_to = string(status.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if update.Message.Photo != nil {
|
} else if update.Message.Photo != nil {
|
||||||
log.Printf("Photo received. Message id: %d\n", messageID)
|
log.Printf("Photo received. Message id: %d\n", messageID)
|
||||||
|
@ -116,32 +100,14 @@ the specified Mastodon account.`,
|
||||||
log.Printf("Could not download file: %v", err)
|
log.Printf("Could not download file: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
attachment, err := c.UploadMediaFromReader(
|
|
||||||
context.Background(), file)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Could not upload media: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
file.Close()
|
|
||||||
log.Printf("Posted attachment %s", attachment.TextURL)
|
|
||||||
|
|
||||||
mediaIds := [...]mastodon.ID{attachment.ID}
|
mastodon.PostPhoto(
|
||||||
caption := update.Message.Caption
|
c,
|
||||||
if len(caption) > max_characters {
|
file,
|
||||||
caption = caption[:max_characters]
|
update.Message.Caption,
|
||||||
}
|
maxChars,
|
||||||
status, err := c.PostStatus(context.Background(), &mastodon.Toot{
|
tootVisibility,
|
||||||
// Write the caption in the toot because it almost probably
|
)
|
||||||
// doesn't describe the image.
|
|
||||||
Status: caption,
|
|
||||||
MediaIDs: mediaIds[:],
|
|
||||||
Visibility: parseMastodonVisibility(os.Getenv(MASTODON_TOOT_VISIBILITY)),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Could not post status: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("Posted status %s", status.URL)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,21 +127,6 @@ func parseBoolOrFalse(s string) bool {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the specified Mastodon visibility and return it if valid or return
|
|
||||||
// unlisted if it's not valid.
|
|
||||||
// The specified string will be cheched case unsensitive.
|
|
||||||
func parseMastodonVisibility(s string) string {
|
|
||||||
s = strings.ToLower(s)
|
|
||||||
// Keep sorted since we search inside.
|
|
||||||
visibilities := []string{"direct", "private", "public", "unlisted"}
|
|
||||||
r := sort.SearchStrings(visibilities, s)
|
|
||||||
if r < len(visibilities) && visibilities[r] == s {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unlisted"
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadFile(url string) (io.ReadCloser, error) {
|
func downloadFile(url string) (io.ReadCloser, error) {
|
||||||
response, err := http.Get(url)
|
response, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -189,15 +140,6 @@ func downloadFile(url string) (io.ReadCloser, error) {
|
||||||
return response.Body, nil
|
return response.Body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Mastodon max characters and return 500 as default in case of errors.
|
|
||||||
func parseMastodonMaxCharacters(s string) int {
|
|
||||||
if n, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
||||||
return int(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 500
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseTelegramChatID(s string) int64 {
|
func parseTelegramChatID(s string) int64 {
|
||||||
r, err := strconv.ParseInt(s, 10, 64)
|
r, err := strconv.ParseInt(s, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,26 +15,3 @@ func TestParseBoolOrFalse(t *testing.T) {
|
||||||
assert.Equal(t, parseBoolOrFalse("FALSE"), false)
|
assert.Equal(t, parseBoolOrFalse("FALSE"), false)
|
||||||
assert.Equal(t, parseBoolOrFalse("false"), false)
|
assert.Equal(t, parseBoolOrFalse("false"), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseMastodonVisibility(t *testing.T) {
|
|
||||||
assert.Equal(t, parseMastodonVisibility("public"), "public")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("direct"), "direct")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("unlisted"), "unlisted")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("private"), "private")
|
|
||||||
|
|
||||||
assert.Equal(t, parseMastodonVisibility("Public"), "public")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("diRect"), "direct")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("unlisTED"), "unlisted")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("PRIVATE"), "private")
|
|
||||||
|
|
||||||
assert.Equal(t, parseMastodonVisibility("True"), "unlisted")
|
|
||||||
assert.Equal(t, parseMastodonVisibility("eriol"), "unlisted")
|
|
||||||
assert.Equal(t, parseMastodonVisibility(""), "unlisted")
|
|
||||||
assert.Equal(t, parseMastodonVisibility(" "), "unlisted")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseMastodonMaxCharacters(t *testing.T) {
|
|
||||||
assert.Equal(t, parseMastodonMaxCharacters("42"), 42)
|
|
||||||
assert.Equal(t, parseMastodonMaxCharacters("-42"), 500)
|
|
||||||
assert.Equal(t, parseMastodonMaxCharacters("hello"), 500)
|
|
||||||
}
|
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -3,6 +3,7 @@ module noa.mornie.org/eriol/telegram-group2mastodon
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/alecthomas/assert v1.0.0
|
||||||
github.com/cking/go-mastodon v0.0.6
|
github.com/cking/go-mastodon v0.0.6
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||||
github.com/spf13/cobra v1.3.0
|
github.com/spf13/cobra v1.3.0
|
||||||
|
@ -10,11 +11,16 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/alecthomas/colour v0.1.0 // indirect
|
||||||
|
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gorilla/websocket v1.4.1 // indirect
|
github.com/gorilla/websocket v1.4.1 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/sergi/go-diff v1.2.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
10
go.sum
10
go.sum
|
@ -51,6 +51,12 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
||||||
|
github.com/alecthomas/assert v1.0.0 h1:3XmGh/PSuLzDbK3W2gUbRXwgW5lqPkuqvRgeQ30FI5o=
|
||||||
|
github.com/alecthomas/assert v1.0.0/go.mod h1:va/d2JC+M7F6s+80kl/R3G7FUiW6JzUO+hPhLyJ36ZY=
|
||||||
|
github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=
|
||||||
|
github.com/alecthomas/colour v0.1.0/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
||||||
|
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48=
|
||||||
|
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
@ -263,6 +269,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||||
|
@ -310,6 +317,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
@ -536,6 +545,7 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
|
||||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|
59
mastodon/post.go
Normal file
59
mastodon/post.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package mastodon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
mastodonapi "github.com/cking/go-mastodon"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Post one or more toots.
|
||||||
|
func PostToots(client *mastodonapi.Client, messages []string, visibility string) {
|
||||||
|
in_reply_to := ""
|
||||||
|
for _, message := range messages {
|
||||||
|
status, err := client.PostStatus(context.Background(), &mastodonapi.Toot{
|
||||||
|
Status: message,
|
||||||
|
Visibility: visibility,
|
||||||
|
InReplyToID: mastodonapi.ID(in_reply_to),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Could not post status: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("Posted status %s", status.URL)
|
||||||
|
in_reply_to = string(status.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post a photo on mastodon with caption.
|
||||||
|
func PostPhoto(
|
||||||
|
client *mastodonapi.Client,
|
||||||
|
file io.ReadCloser,
|
||||||
|
caption string,
|
||||||
|
maxCharacters int,
|
||||||
|
visibility string) {
|
||||||
|
attachment, err := client.UploadMediaFromReader(
|
||||||
|
context.Background(), file)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Could not upload media: %v", err)
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
log.Printf("Posted attachment %s", attachment.TextURL)
|
||||||
|
|
||||||
|
mediaIds := [...]mastodonapi.ID{attachment.ID}
|
||||||
|
if len(caption) > maxCharacters {
|
||||||
|
caption = caption[:maxCharacters]
|
||||||
|
}
|
||||||
|
status, err := client.PostStatus(context.Background(), &mastodonapi.Toot{
|
||||||
|
// Write the caption in the toot because it almost probably
|
||||||
|
// doesn't describe the image.
|
||||||
|
Status: caption,
|
||||||
|
MediaIDs: mediaIds[:],
|
||||||
|
Visibility: visibility,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Could not post status: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("Posted status %s", status.URL)
|
||||||
|
}
|
Loading…
Reference in a new issue