This commit is contained in:
stryan 2021-05-21 12:45:24 -04:00
commit 45c63330a1
6 changed files with 340 additions and 0 deletions

9
go.mod Normal file
View File

@ -0,0 +1,9 @@
module simpbot
go 1.15
require (
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect
maunium.net/go/mautrix v0.9.12
)

70
go.sum Normal file
View File

@ -0,0 +1,70 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/maulogger/v2 v2.2.4/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
maunium.net/go/mautrix v0.9.12 h1:iNsKOCyK/BqN6Q/7A1aLj1B0/lMbr81LIg+Lry1Vjuo=
maunium.net/go/mautrix v0.9.12/go.mod h1:7IzKfWvpQtN+W2Lzxc0rLvIxFM3ryKX6Ys3S/ZoWbg8=

27
live.go Normal file
View File

@ -0,0 +1,27 @@
package main
import "time"
type StreamList struct {
Total string `json:"total"`
Streams []Stream `json:"items"`
}
type Channel struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Photo string `json:"photo"`
EnglishName string `json:"english_name"`
}
type Stream struct {
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
TopicID string `json:"topic_id"`
PublishedAt time.Time `json:"published_at"`
AvailableAt time.Time `json:"available_at"`
Duration int `json:"duration"`
Status string `json:"status"`
StartScheduled time.Time `json:"start_scheduled"`
Channel Channel `json:"channel"`
}

111
main.go Normal file
View File

@ -0,0 +1,111 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"time"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
)
var Homeserver = flag.String("homeserver", "", "Matrix homeserver")
var Username = flag.String("username", "", "Matrix username localpart")
var Password = flag.String("password", "", "Matrix password")
var DimensionServer = flag.String("dimension", "", "Dimension server URL")
var HomeserverDomain = flag.String("domain", "", "Matrix homserver domain (the part after : )")
func main() {
flag.Parse()
if *Username == "" || *Password == "" || *Homeserver == "" || *DimensionServer == "" || *HomeserverDomain == "" {
_, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
flag.PrintDefaults()
os.Exit(1)
}
fmt.Println("Logging into", *Homeserver, "as", *Username)
client, err := mautrix.NewClient(*Homeserver, "", "")
if err != nil {
panic(err)
}
_, 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)
}
fmt.Println("Login successful")
syncer := client.Syncer.(*mautrix.DefaultSyncer)
syncer.OnEventType(event.EventMessage, 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)
})
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.Println("joined room")
}
}
})
vtubers := []*Vtuber{NewVtuber("Ina", "UCMwGHR0BTZuLsmjY_NT5Pwg", "The High Priestess is Live"), NewVtuber("Kiara", "UCHsx4Hqa-1ORjQTh9TYDhww", "The Bird has Landed"), NewVtuber("Calliope", "UCL_qhgtOy0dy1Agp8vkySQg", "The Reapers here")}
go func() {
for {
time.Sleep(30 * time.Second)
roomResp, err := client.JoinedRooms()
if err != nil {
log.Println("error gettting joined rooms")
}
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 == "" {
client.SendText(room, v.LiveMsg)
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)
}
log.Printf("Embed event %v", resp)
}
}
} 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 removed video embed")
log.Println(err)
}
log.Printf("Emebed remove %v", resp)
}
}
}
}
}
}()
err = client.Sync()
if err != nil {
panic(err)
}
}

60
vtuber.go Normal file
View File

@ -0,0 +1,60 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type Vtuber struct {
Name string
ChannelID string
CurrentStream string
LiveMsg string
}
func NewVtuber(name, channelID, liveMsg string) *Vtuber {
return &Vtuber{
Name: name,
ChannelID: channelID,
CurrentStream: "",
LiveMsg: liveMsg,
}
}
func (v *Vtuber) IsLive() bool {
return v.CurrentStream != ""
}
func (v *Vtuber) Update() error {
url := fmt.Sprintf("https://holodex.net/api/v2/live?channel_id=%s&lang=all&sort=available_at&order=desc&limit=25&offset=0&paginated=%3Cempty%3E", v.ChannelID)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
jsonBody, _ := ioutil.ReadAll(res.Body)
var sl StreamList
err = json.Unmarshal(jsonBody, &sl)
if err != nil {
log.Println("error parsing json for vtuber")
return err
}
found := false
for _, s := range sl.Streams {
if s.Status == "live" {
v.CurrentStream = s.ID
found = true
}
}
if !found {
v.CurrentStream = ""
}
return nil
}

63
youtube.go Normal file
View File

@ -0,0 +1,63 @@
package main
import (
"net/url"
"time"
)
type Integration struct {
Category string `json:"category"`
Type string `json:"type"`
}
type DimensionAppMetadata struct {
InRoomID string `json:"inRoomId"`
WrapperURLBase string `json:"wrapperUrlBase"`
WrapperID string `json:"wrapperId"`
ScalarWrapperID string `json:"scalarWrapperId"`
Integration Integration `json:"integration"`
LastUpdatedTs int64 `json:"lastUpdatedTs"`
}
type Data struct {
VideoURL string `json:"videoUrl"`
URL string `json:"url"`
DimensionAppMetadata DimensionAppMetadata `json:"dimension:app:metadata"`
}
type YoutubeWidget struct {
Type string `json:"type"`
URL string `json:"url"`
Name string `json:"name"`
Data Data `json:"data"`
CreatorUserID string `json:"creatorUserId"`
ID string `json:"id"`
RoomID string `json:"roomId"`
EventID string `json:"eventId"`
}
type Unsigned struct {
Age int `json:"age"`
}
func NewYT(videoName, videoID, roomID string) *YoutubeWidget {
encodedVod := url.QueryEscape("https://youtube.com/embed/" + videoID)
return &YoutubeWidget{
Type: "im.vector.modular.widgets",
URL: "https://" + *DimensionServer + "/widgets/video?url=" + encodedVod,
Name: videoName,
Data: Data{
VideoURL: "https://www.youtube.com/watch?v=" + videoID,
URL: "https://youtube.com/embed/" + videoID,
DimensionAppMetadata: DimensionAppMetadata{
InRoomID: roomID,
WrapperURLBase: "https://" + *DimensionServer + "/widgets/video?url=",
WrapperID: "video",
ScalarWrapperID: "youtube",
Integration: Integration{
Category: "widget",
Type: "youtube",
},
LastUpdatedTs: time.Now().UnixNano() / int64(time.Millisecond),
},
},
CreatorUserID: "@" + *Username + ":" + *HomeserverDomain,
ID: "dimension-m.video-simp",
}
}