300 lines
8.4 KiB
Go
300 lines
8.4 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
|
|
var HolodexToken string
|
|
|
|
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")
|
|
HolodexToken = viper.GetString("api_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
|
|
uid := id.NewUserID(strings.ToLower(Username), strings.ToLower(HomeserverDomain))
|
|
if Token == "" {
|
|
client, err = mautrix.NewClient(Homeserver, "", "")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
log.Println("using token login")
|
|
client, err = mautrix.NewClient(Homeserver, uid, Token)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
dataFilter := &mautrix.Filter{
|
|
AccountData: mautrix.FilterPart{
|
|
Limit: 20,
|
|
NotTypes: []event.Type{
|
|
event.NewEventType("simp.batch"),
|
|
},
|
|
},
|
|
}
|
|
store := mautrix.NewAccountDataStore("simp.batch", client)
|
|
fID, err := client.CreateFilter(dataFilter)
|
|
store.SaveFilterID(uid, fID.FilterID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
client.Store = store
|
|
|
|
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")
|
|
}
|
|
if HolodexToken == "" {
|
|
log.Println("No holodex API token provided, unlikely to be able to get streams")
|
|
}
|
|
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 "subscribe":
|
|
if len(body_s) < 3 {
|
|
client.SendText(evt.RoomID, "Need a member to subscribe to")
|
|
}
|
|
vt := body_s[2]
|
|
var subbed bool
|
|
for _, v := range vtubers {
|
|
if strings.ToUpper(v.Name) == strings.ToUpper(vt) {
|
|
v.Subs[evt.Sender] = true
|
|
subbed = true
|
|
}
|
|
}
|
|
if subbed {
|
|
client.SendText(evt.RoomID, "subbed")
|
|
} else {
|
|
client.SendText(evt.RoomID, "could not identify talent to subscribe to")
|
|
}
|
|
|
|
case "help":
|
|
client.SendText(evt.RoomID, "Supported commands: info,version,stats,reload,subscribe")
|
|
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 {
|
|
err = v.Update(HolodexToken)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
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))
|
|
var subs string
|
|
for k := range v.Subs {
|
|
subs += k.String() + " "
|
|
}
|
|
if len(v.Subs) > 0 {
|
|
client.SendText(room, fmt.Sprintf("Pinging %v", subs))
|
|
}
|
|
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
|
|
}
|