UA-Bot/main.go

305 lines
7.5 KiB
Go
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"context"
"fmt"
"os"
"path"
"regexp"
"strings"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
"github.com/mattn/go-mastodon"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"maunium.net/go/mautrix"
m_event "maunium.net/go/mautrix/event"
m_id "maunium.net/go/mautrix/id"
)
type Post struct {
ID int
PostId string
MessageId string
}
func parseRegexFile(path string) ([]regexp.Regexp, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
file_scanner := bufio.NewScanner(file)
file_scanner.Split(bufio.ScanLines)
var result []regexp.Regexp
for file_scanner.Scan() {
text := file_scanner.Text()
if strings.Trim(text, " ")[0] != '#' {
regex, err := regexp.Compile(text)
if err != nil {
return nil, err
}
result = append(result, *regex)
}
}
return result, nil
}
func main() {
ctx := context.Background()
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
ex, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
domainRegexes, err := parseRegexFile(path.Join(ex, "domains.txt"))
if err != nil {
log.Fatal(err)
}
nicknameRegexes, err := parseRegexFile(path.Join(ex, "nicknames.txt"))
if err != nil {
log.Fatal(err)
}
// log.Info(nicknameRegexes, domainRegexes)
db, err := gorm.Open(postgres.Open(fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s",
os.Getenv("POSTGRES_HOST"),
os.Getenv("POSTGRES_USER"),
os.Getenv("POSTGRES_PASSWORD"),
os.Getenv("POSTGRES_DB"),
os.Getenv("POSTGRES_PORT"))), &gorm.Config{})
db.AutoMigrate(&Post{})
if err != nil {
log.Fatal(err)
}
masto_client := mastodon.NewClient(&mastodon.Config{
Server: os.Getenv("MASTODON_HOMESERVER"),
ClientID: os.Getenv("MASTODON_CLIENT_ID"),
ClientSecret: os.Getenv("MASTODON_CLIENT_SECRET"),
AccessToken: os.Getenv("MASTODON_ACCESS_TOKEN"),
})
masto_user, err := masto_client.GetAccountCurrentUser(ctx)
if err != nil {
log.Fatal(err)
}
// log.Println(my_account)
matrix_client, err := mautrix.NewClient(os.Getenv("MATRIX_HOMESERVER"), m_id.UserID(os.Getenv("MATRIX_USERNAME")), os.Getenv("MATRIX_ACCESS_TOKEN"))
matrix_client.Store = mautrix.NewAccountDataStore("ua.in.fediland.uabot", matrix_client)
syncer := matrix_client.Syncer.(*mautrix.DefaultSyncer)
if err != nil {
log.Fatal(err)
}
log.Info("starting...")
syncer.OnEventType(m_event.EventReaction, func(source mautrix.EventSource, ev *m_event.Event) {
log.Info("reactions")
// if ev.RoomID == os.Getenv("MATRIX_ROOM_ID") && ev.Content != nil &&
content := ev.Content.AsReaction()
key := []rune(content.RelatesTo.Key)
log.Info(content.RelatesTo.Key)
if ev.RoomID.String() == os.Getenv("MATRIX_ROOM_ID") && (key[0] == '👍' || key[0] == '👎') {
log.Info("reacted well")
var post Post
if err := db.First(&post, "message_id = ?", content.RelatesTo.EventID.String()).Error; err != nil {
log.Error(err)
return
}
status, err := masto_client.GetStatus(ctx, mastodon.ID(post.PostId))
if err != nil {
log.Error(err)
return
}
if key[0] == '👍' {
_, err = masto_client.Reblog(ctx, mastodon.ID(post.PostId))
if err != nil {
log.Error(err)
return
}
// matrix_client.SendMessageEvent(os.Getenv("MATRIX_ROOM_ID"), "m.room.message", interface{})
body := fmt.Sprintf(`#%d: Схвалено
%s
`, post.ID, status.URL)
_, err := matrix_client.SendMessageEvent(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), m_event.EventMessage, &m_event.MessageEventContent{
Body: body,
MsgType: m_event.MsgText,
NewContent: &m_event.MessageEventContent{
MsgType: m_event.MsgText,
Body: body},
RelatesTo: &m_event.RelatesTo{
Type: m_event.RelReplace,
EventID: m_id.EventID(post.MessageId),
},
})
if err != nil {
log.Error(err)
}
} else {
body := fmt.Sprintf(`#%d: Відмовлено
%s
`, post.ID, status.URL)
_, err := matrix_client.SendMessageEvent(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), m_event.EventMessage, &m_event.MessageEventContent{
Body: body,
MsgType: m_event.MsgText,
NewContent: &m_event.MessageEventContent{
MsgType: m_event.MsgText,
Body: body,
},
RelatesTo: &m_event.RelatesTo{
Type: m_event.RelReplace,
EventID: m_id.EventID(post.MessageId),
},
})
if err != nil {
log.Error(err)
}
}
}
})
events, err := masto_client.StreamingUser(ctx)
if err != nil {
log.Fatal(err)
}
go func() {
for {
if err := matrix_client.Sync(); err != nil {
log.Error(fmt.Errorf("Sync() returned %s", err))
}
}
}()
notif_loop:
for {
notif_event, ok := (<-events).(*mastodon.NotificationEvent)
if !ok {
continue
}
notif := notif_event.Notification
// log.Println(notif)
if notif.Type == "follow" {
acct_parsed := strings.Split(notif.Account.Acct, "@")
for _, regex := range domainRegexes {
if len(acct_parsed) == 2 && regex.MatchString(acct_parsed[1]) {
_, err := masto_client.AccountBlock(ctx, notif.Account.ID)
if err == nil {
matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf("%s заблокований автоматично регексом доменів: %s", notif.Account.Acct, regex.String()))
}
continue notif_loop
}
}
for _, regex := range nicknameRegexes {
if regex.MatchString(acct_parsed[0]) {
_, err := masto_client.AccountBlock(ctx, notif.Account.ID)
if err == nil {
matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf("%s заблокований автоматично регексом нікнеймів: %s", notif.Account.Acct, regex.String()))
}
continue notif_loop
}
}
masto_client.PostStatus(ctx, &mastodon.Toot{
Status: fmt.Sprintf("Вітаємо у нашій спільноті! @%s", notif.Account.Acct),
Visibility: mastodon.VisibilityUnlisted,
})
}
if notif.Type == "mention" {
log.Debugf("post %v mentioned bot", notif.Status.ID)
}
if notif.Type == "mention" && notif.Status.InReplyToID == nil && notif.Status.InReplyToAccountID == nil {
log.Debugf(`post passed reply check (%v)
text: %v
actor: %v`, notif.Status.ID, notif.Status.Content, notif.Account.Acct)
subscribers, err := masto_client.GetAccountFollowers(ctx, masto_user.ID, &mastodon.Pagination{Limit: 10000})
if err != nil {
log.Error(err)
continue
}
ok := false
for _, subscriber := range subscribers {
if subscriber.ID == notif.Account.ID {
ok = true
break
}
}
if ok && notif.Status.Visibility == "public" {
log.Debugf("post %v is public and has subscription", notif.Status.ID)
if err := db.Create(&Post{
PostId: string(notif.Status.ID),
}).Error; err != nil {
log.Error(err)
continue
}
var post Post
if err := db.First(&post, "post_id = ?", string(notif.Status.ID)).Error; err != nil {
log.Error(err)
continue
}
message, err := matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf(`#%d: На модерації
%s
👍 - Так
👎 - Ні
`, post.ID, notif.Status.URL))
if err != nil {
log.Fatal(err)
db.Delete(&post, post.ID)
}
post.MessageId = message.EventID.String()
db.Save(&post)
}
if ok && notif.Status.Visibility == "direct" && notif.Status.Content == "ping" {
masto_client.PostStatus(ctx, &mastodon.Toot{
Status: "meow",
InReplyToID: notif.Status.ID,
Visibility: "direct",
})
}
}
}
}