simpbot/main.go
Steve 4f12bdc1c9
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
use access token when available
2021-12-08 13:22:56 -05:00

251 lines
7.2 KiB
Go

package main
import (
"fmt"
"log"
"net/url"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
var Homeserver string
var Username string
var Password string
var DimensionServer string
var HomeserverDomain string
var Token string
var GitCommit string
var GitTag string
var Statefile string
var CurrStreamCnt int
var MostStreamCnt int
var StartTime time.Time
func main() {
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/simpbot")
err := viper.ReadInConfig()
if err != nil {
log.Fatalf("Fatal error config file: %v \n", err)
}
viper.SetConfigType("yaml")
Homeserver = viper.GetString("homeserver")
viper.SetDefault("domain", Homeserver)
viper.SetDefault("statefile", "simpstate")
Username = viper.GetString("username")
Password = viper.GetString("password")
Token = viper.GetString("access_token")
DimensionServer = viper.GetString("dimension")
HomeserverDomain = viper.GetString("domain")
Statefile = viper.GetString("statefile")
CurrStreamCnt = 0
MostStreamCnt = 0
StartTime = time.Now()
var vtubers []*Vtuber
log.Println("Logging into", Homeserver, "as", Username)
var client *mautrix.Client
if Token == "" {
client, err = mautrix.NewClient(Homeserver, "", "")
if err != nil {
panic(err)
}
} else {
log.Println("using token login")
client, err = mautrix.NewClient(Homeserver, id.NewUserID(Username, HomeserverDomain), Token)
if err != nil {
panic(err)
}
}
client.Store = NewLazyMemStore(Statefile)
if Token == "" {
login_res, err := client.Login(&mautrix.ReqLogin{
Type: "m.login.password",
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: Username},
Password: Password,
StoreCredentials: true,
})
if err != nil {
panic(err)
}
Token = login_res.AccessToken
viper.Set("access_token", Token)
log.Println("Login succesful, saving access_token to config file")
err = viper.WriteConfig()
if err != nil {
panic(err)
}
} else {
log.Println("skipping login since token provided")
}
syncer := client.Syncer.(*mautrix.DefaultSyncer)
syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, evt *event.Event) {
if evt.Sender == client.UserID {
return //ignore events from self
}
fmt.Printf("<%[1]s> %[4]s (%[2]s/%[3]s)\n", evt.Sender, evt.Type.String(), evt.ID, evt.Content.AsMessage().Body)
body := evt.Content.AsMessage().Body
body_s := strings.Split(body, " ")
if body_s[0] != "!simp" {
return
}
if len(body_s) < 2 {
return //nothing to parse
}
switch body_s[1] {
case "info":
// print info page
var infomsg string
vlist := []string{}
for _, vt := range vtubers {
ann := ""
if vt.AnnounceLive {
ann = "*"
}
vlist = append(vlist, fmt.Sprintf("%v%v", vt.Name, ann))
}
infomsg = fmt.Sprintf("Currently Simping For: \n%v", strings.Join(vlist, "\n"))
client.SendText(evt.RoomID, infomsg)
case "stats":
var statmsg string
vlist := []string{}
t := 0
for _, vt := range vtubers {
vlist = append(vlist, fmt.Sprintf("%v Total:%v", vt.Name, vt.TotalStreams))
t = t + vt.TotalStreams
}
statmsg = fmt.Sprintf("Current Stats Since %v:\n%v\n\nTotal Streams: %v\nMost Concurrent: %v/%v\n", StartTime, strings.Join(vlist, "\n"), t, MostStreamCnt, len(vtubers))
client.SendText(evt.RoomID, statmsg)
case "version":
// print version
if GitTag != "" {
client.SendText(evt.RoomID, "SimpBot version "+GitTag)
} else {
client.SendText(evt.RoomID, "SimpBot version "+GitCommit)
}
case "reload":
//reload config
client.SendText(evt.RoomID, "Reloading config")
fmt.Println("Reload requested,reloading vtubers")
vtubers = LoadVtubers()
case "help":
client.SendText(evt.RoomID, "Supported commands: info,version,stats")
default:
//command not found
client.SendText(evt.RoomID, "command not recognized")
}
})
syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) {
fmt.Printf("<%[1]s> %[4]s (%[2]s/%[3]s)\n", evt.Sender, evt.Type.String(), evt.ID, evt.Content.AsMessage().Body)
if evt.Content.AsMember().Membership.IsInviteOrJoin() {
_, err = client.JoinRoomByID(evt.RoomID)
if err != nil {
fmt.Printf("error joining room %v", evt.RoomID)
} else {
fmt.Printf("joined room %v", evt.RoomID)
}
}
})
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGUSR1)
vtubers = LoadVtubers()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed,reloading vtubers:", e.Name)
vtubers = LoadVtubers()
})
go func() {
for {
time.Sleep(30 * time.Second)
roomResp, err := client.JoinedRooms()
if err != nil {
log.Println("error getting joined rooms")
log.Println(err)
log.Println("Skipping iteration")
continue
}
rooms := roomResp.JoinedRooms
// We're going to assume they're only stream one video at a time
for _, v := range vtubers {
v.Update()
if v.IsLive() {
for _, room := range rooms {
//check to see if already embeded
var content YoutubeWidget
err = client.StateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, &content)
if content.ID == "" {
if v.AnnounceLive {
client.SendText(room, v.LiveMsg)
} else {
if isValidUrl(v.LiveMsg) {
client.SendNotice(room, fmt.Sprintf("%v has gone live", v.Name))
} else {
client.SendNotice(room, v.LiveMsg)
}
}
client.SendNotice(room, fmt.Sprintf("%v's Title: %v", v.Name, v.CurrentStreamTitle))
resp, err := client.SendStateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, NewYT(v.Name+"'s stream", v.CurrentStream, string(room)))
if err != nil {
log.Println("error embeding video")
log.Println(err)
}
v.TotalStreams = v.TotalStreams + 1
CurrStreamCnt = CurrStreamCnt + 1
if CurrStreamCnt > MostStreamCnt {
MostStreamCnt = CurrStreamCnt
}
log.Printf("Embed stream %v for %v ", resp, v.Name)
}
}
} else {
//Not live, check to see if there's any embeds and remove them
for _, room := range rooms {
var content YoutubeWidget
err = client.StateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, &content)
if err == nil && content.ID != "" {
//event found, kill it
resp, err := client.SendStateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, struct{}{})
if err != nil {
log.Println("error removing video embed")
log.Println(err)
}
CurrStreamCnt = CurrStreamCnt - 1
log.Printf("Embed stream %v removed %v", resp, v.Name)
}
}
}
}
}
}()
err = client.Sync()
if err != nil {
panic(err)
}
}
func isValidUrl(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false
}
u, err := url.Parse(toTest)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
return true
}