UA-Bot/main.go

324 lines
7.8 KiB
Go
Raw Normal View History

package main
import (
"bufio"
"context"
"fmt"
"os"
"path"
"regexp"
"strings"
2024-01-05 21:42:47 +00:00
"time"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
2024-01-05 21:42:47 +00:00
"github.com/UA-Fediland/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()
2024-01-04 20:01:06 +00:00
ROOM_ID := os.Getenv("MATRIX_ROOM_ID")
2024-01-04 23:06:35 +00:00
log.SetLevel(log.DebugLevel)
if err != nil {
log.Fatal(err)
}
ex, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
blacklistRegexes, err := parseRegexFile(path.Join(ex, "blacklist.txt"))
if err != nil {
log.Fatal(err)
}
whitelistRegexes, err := parseRegexFile(path.Join(ex, "whitelist.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)
}
2024-01-05 18:29:04 +00:00
var subscribers []*mastodon.Account
var pg mastodon.Pagination
log.Debug("get followers list")
for {
fs, err := masto_client.GetAccountFollowers(context.Background(), masto_user.ID, &pg)
if err != nil {
log.Fatal(err)
}
subscribers = append(subscribers, fs...)
2024-01-05 21:42:47 +00:00
// log.Debug(pg)
// log.Debug(pg.MaxID)
if pg.MaxID == "" {
break
}
2024-01-05 21:42:47 +00:00
time.Sleep(200 * time.Millisecond)
}
2024-01-05 21:45:49 +00:00
log.Debugf("subscribers count: %v", len(subscribers))
2024-01-05 21:42:47 +00:00
// for _, subscriber := range subscribers {
// log.Debug(subscriber.Acct)
// }
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...")
2024-01-04 20:01:06 +00:00
matrix_client.SendText(m_id.RoomID(ROOM_ID), "Бот запущений!")
syncer.OnEventType(m_event.EventReaction, func(source mautrix.EventSource, ev *m_event.Event) {
2024-01-04 22:50:35 +00:00
log.Debug("reactions")
2024-01-04 20:01:06 +00:00
// if ev.RoomID == ROOM_ID && ev.Content != nil &&
content := ev.Content.AsReaction()
key := []rune(content.RelatesTo.Key)
2024-01-04 22:50:35 +00:00
log.Debug(content.RelatesTo.Key)
2024-01-04 20:01:06 +00:00
if ev.RoomID.String() == ROOM_ID && (key[0] == '👍' || key[0] == '👎') {
2024-01-04 22:50:35 +00:00
log.Debug("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
}
2024-01-04 20:01:06 +00:00
// matrix_client.SendMessageEvent(ROOM_ID, "m.room.message", interface{})
body := fmt.Sprintf(`#%d: Схвалено
%s
`, post.ID, status.URL)
2024-01-04 20:01:06 +00:00
_, err := matrix_client.SendMessageEvent(m_id.RoomID(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)
2024-01-04 20:01:06 +00:00
_, err := matrix_client.SendMessageEvent(m_id.RoomID(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 blacklistRegexes {
if regex.MatchString(notif.Account.Acct) {
_, err := masto_client.AccountBlock(ctx, notif.Account.ID)
if err == nil {
matrix_client.SendText(m_id.RoomID(ROOM_ID), fmt.Sprintf("%s заблокований автоматично регулярним виразом: %s", notif.Account.Acct, regex.String()))
}
continue notif_loop
}
}
2024-01-05 18:29:04 +00:00
subscribers = append(subscribers, &notif.Account)
masto_client.PostStatus(ctx, &mastodon.Toot{
Status: fmt.Sprintf("Вітаємо у нашій спільноті! @%s", notif.Account.Acct),
Visibility: mastodon.VisibilityUnlisted,
})
}
2024-01-04 19:05:56 +00:00
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 {
2024-01-05 18:29:04 +00:00
log.Debugf(`post passed reply check (%v)`, notif.Status.ID)
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 user has subscription", notif.Status.ID)
for _, regex := range whitelistRegexes {
if regex.MatchString(notif.Account.Acct) {
_, err = masto_client.Reblog(ctx, notif.Status.ID)
if err != nil {
log.Error(err)
}
log.Debugf("post %v belongs to whitelisted user (%v) by regex: %v", notif.Status.ID, notif.Account.Acct, regex.String())
continue notif_loop
}
}
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
}
2024-01-04 20:01:06 +00:00
message, err := matrix_client.SendText(m_id.RoomID(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",
})
}
}
}
}