initial cleanup

This commit is contained in:
stryan 2023-05-14 18:45:55 -04:00
parent de2e8d014a
commit 0a34a59328
9 changed files with 414 additions and 376 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
config.yaml
statedata
config.yml
simpbot

View File

@ -1,10 +1,10 @@
FROM golang:1.18 as builder
FROM golang:1.20 as builder
WORKDIR /go/src/app
COPY . .
RUN apt update && apt upgrade -y
RUN go build
FROM alpine:latest as final
FROM debian:stable-slim as final
WORKDIR /srv/
RUN mkdir /srv/simpbot
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

View File

@ -1,53 +0,0 @@
---
- hosts: localhost
tasks:
- name: check simpbot version
uri:
url: https://git.saintnet.tech/api/v1/repos/stryan/simpbot/releases?limit=1
return_content: true
register: simpbot_latest
- name: "downloading and installing simpbot {{ simpbot_latest.json[0].tag_name }}"
block:
- name: create temp directory
tempfile:
state: directory
suffix: dwn
register: tempfolder_1
- name: download simpbot
loop: "{{ simpbot_latest.json[0].assets }}"
when: "'amd64.tar.gz' in item.name"
unarchive:
remote_src: yes
src: "{{ item.browser_download_url }}"
dest: "{{ tempfolder_1.path }}"
keep_newer: yes
- name: installing simpbot binary
copy:
remote_src: yes
src: "{{ tempfolder_1.path }}/simpbot"
dest: /usr/local/bin/
mode: '0755'
register: new_binary
- name: installing unit file
copy:
remote_src: yes
src: "{{ tempfolder_1.path }}/init/simpbot.service"
dest: /etc/systemd/system/simpbot.service
register: new_unit
- name: reload systemd with new unit
systemd:
daemon_reload: yes
when: new_unit.changed or new_binary.changed
- name: start service
systemd:
name: simpbot
state: restarted
when: new_binary.changed

35
go.mod
View File

@ -1,13 +1,38 @@
module git.saintnet.tech/stryan/simpbot
go 1.15
go 1.20
require (
github.com/charmbracelet/log v0.2.1
github.com/fsnotify/fsnotify v1.5.1
github.com/spf13/viper v1.9.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211014172544-2b766c08f1c0 // indirect
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect
golang.org/x/text v0.3.7 // indirect
maunium.net/go/mautrix v0.9.29
)
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/btcsuite/btcutil v1.0.2 // indirect
github.com/charmbracelet/lipgloss v0.7.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211014172544-2b766c08f1c0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

30
go.sum
View File

@ -51,6 +51,8 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
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=
@ -64,6 +66,10 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
github.com/charmbracelet/log v0.2.1 h1:1z7jpkk4yKyjwlmKmKMM5qnEDSpV32E7XtWhuv0mTZE=
github.com/charmbracelet/log v0.2.1/go.mod h1:GwFfjewhcVDWLrpAbY5A0Hin9YOlEn40eWT4PNaxFT4=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -95,6 +101,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -210,6 +218,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@ -220,6 +230,11 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
@ -233,6 +248,10 @@ github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
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=
@ -246,6 +265,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -269,8 +291,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
@ -468,8 +490,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -685,8 +707,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

304
main.go
View File

@ -2,36 +2,18 @@ package main
import (
"fmt"
"log"
"net/url"
"os"
"os/signal"
"strings"
"syscall"
"time"
"sync"
"github.com/charmbracelet/log"
"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() {
simp := newSimp()
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/simpbot")
@ -40,255 +22,65 @@ func main() {
log.Fatalf("Fatal error config file: %v \n", err)
}
viper.SetConfigType("yaml")
Homeserver = viper.GetString("homeserver")
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)
Username := viper.GetString("username")
Password := viper.GetString("password")
Token := viper.GetString("access_token")
simp.holodexToken = viper.GetString("api_token")
HomeserverDomain := viper.GetString("domain")
DimensionServer := viper.GetString("dimension")
log.Info("logging into matrix", "homeserver", Homeserver, "username", Username)
err = simp.SetupMatrix(Username, Password, Token, Homeserver, HomeserverDomain, DimensionServer)
if err != nil {
panic(err)
log.Fatal(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 simp.holodexToken == "" {
log.Warn("No holodex API token provided, unlikely to be able to get streams")
}
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()
simp.vtubers = loadVtubers()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed,reloading vtubers:", e.Name)
vtubers = LoadVtubers()
simp.vtubers = loadVtubers()
})
var wg sync.WaitGroup
stop := make(chan bool)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
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 err != nil {
log.Printf("error getting state event in room %v: %v", room, err)
continue
}
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)
}
}
}
}
}
<-c
log.Info("trying to shutdown cleanly")
simp.Stop()
stop <- true
}()
err = client.Sync()
if err != nil {
panic(err)
}
wg.Add(1)
go func() {
err = simp.client.Sync()
if err != nil {
log.Warn(err)
}
wg.Done()
}()
wg.Add(1)
go func() {
simp.Run()
wg.Done()
log.Info("simpbot shutdown")
}()
log.Info("simpbot running")
wg.Wait()
log.Info("shutting down")
}
func isValidUrl(toTest string) bool {
func isValidURL(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false

281
simp.go Normal file
View File

@ -0,0 +1,281 @@
package main
import (
"fmt"
"net/url"
"strings"
"time"
"github.com/charmbracelet/log"
"github.com/spf13/viper"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
type simp struct {
client *mautrix.Client
dimensionServer string
holodexToken string
startTime time.Time
currStream int
maxStream int
vtubers []*Vtuber
stop chan bool
}
func newSimp() *simp {
return &simp{
startTime: time.Now(),
stop: make(chan bool),
}
}
func (s *simp) Run() {
ticker := time.NewTicker(time.Second * 3)
for {
select {
case <-s.stop:
return
case <-ticker.C:
roomResp, err := s.client.JoinedRooms()
if err != nil {
log.Warnf("error getting joined rooms: %v, skipping iteration", err)
continue
}
rooms := roomResp.JoinedRooms
// We're going to assume they're only stream one video at a time
for _, v := range s.vtubers {
err = v.Update(s.holodexToken)
if err != nil {
log.Warn(err)
}
if v.IsLive() {
for _, room := range rooms {
//check to see if already embeded
var content youtubeWidget
err = s.client.StateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, &content)
if err != nil {
log.Printf("error getting state event in room %v: %v", room, err)
}
if content.ID == "" {
if v.AnnounceLive {
s.client.SendText(room, v.LiveMsg)
} else {
if isValidURL(v.LiveMsg) {
s.client.SendNotice(room, fmt.Sprintf("%v has gone live", v.Name))
} else {
s.client.SendNotice(room, v.LiveMsg)
}
}
s.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 {
s.client.SendText(room, fmt.Sprintf("Pinging %v", subs))
}
resp, err := s.client.SendStateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, s.NewYT(v.Name+"'s stream", v.CurrentStream, string(room)))
if err != nil {
log.Warnf("error embeding video: %v", err)
}
v.TotalStreams = v.TotalStreams + 1
s.currStream++
if s.currStream > s.maxStream {
s.maxStream = s.currStream
}
log.Info("Embed stream added", "event", resp, "vtuber", v.Name)
}
}
} else {
//Not live, check to see if there's any embeds and remove them
for _, room := range rooms {
var content youtubeWidget
err = s.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 := s.client.SendStateEvent(room, event.NewEventType("im.vector.modular.widgets"), "dimension-m.video-simp-"+v.Name, struct{}{})
if err != nil {
log.Warnf("error removing embed: %v", err)
}
s.currStream--
log.Info("Embed stream removed", "event", resp, "vtuber", v.Name)
}
}
}
}
}
}
}
func (s *simp) SetupMatrix(uname, pass, token, hs, domain, dserver string) error {
uid := id.NewUserID(strings.ToLower(uname), strings.ToLower(domain))
if token == "" {
client, err := mautrix.NewClient(hs, "", "")
if err != nil {
return err
}
s.client = client
} else {
log.Info("using token login")
client, err := mautrix.NewClient(hs, uid, token)
if err != nil {
return err
}
s.client = client
}
dataFilter := &mautrix.Filter{
AccountData: mautrix.FilterPart{
Limit: 20,
NotTypes: []event.Type{
event.NewEventType("s.batch"),
},
},
}
store := mautrix.NewAccountDataStore("simp.batch", s.client)
fID, err := s.client.CreateFilter(dataFilter)
if err != nil {
return err
}
store.SaveFilterID(uid, fID.FilterID)
s.client.Store = store
if token == "" {
loginRes, err := s.client.Login(&mautrix.ReqLogin{
Type: "m.login.password",
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: uname},
Password: pass,
StoreCredentials: true,
})
if err != nil {
return err
}
token = loginRes.AccessToken
viper.Set("access_token", token)
log.Info("Login succesful, saving access_token to config file")
err = viper.WriteConfig()
if err != nil {
return err
}
} else {
log.Info("skipping login since token provided")
}
syncer := s.client.Syncer.(*mautrix.DefaultSyncer)
syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, evt *event.Event) {
if evt.Sender == s.client.UserID {
return //ignore events from self
}
log.Debugf("<%[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
bodyS := strings.Split(body, " ")
if bodyS[0] != "!simp" {
return
}
if len(bodyS) < 2 {
return //nothing to parse
}
switch bodyS[1] {
case "info":
// print info page
var infomsg string
vlist := []string{}
for _, vt := range s.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"))
s.client.SendText(evt.RoomID, infomsg)
case "stats":
var statmsg string
vlist := []string{}
t := 0
for _, vt := range s.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", s.startTime, strings.Join(vlist, "\n"), t, s.maxStream, len(s.vtubers))
s.client.SendText(evt.RoomID, statmsg)
case "version":
s.client.SendText(evt.RoomID, "not implemented")
case "reload":
//reload config
s.client.SendText(evt.RoomID, "Reloading config")
log.Info("Reload requested,reloading vtubers")
s.vtubers = loadVtubers()
case "subscribe":
if len(bodyS) < 3 {
s.client.SendText(evt.RoomID, "Need a member to subscribe to")
}
vt := bodyS[2]
var subbed bool
for _, v := range s.vtubers {
if strings.ToUpper(v.Name) == strings.ToUpper(vt) {
v.Subs[evt.Sender] = true
subbed = true
}
}
if subbed {
s.client.SendText(evt.RoomID, "subbed")
} else {
s.client.SendText(evt.RoomID, "could not identify talent to subscribe to")
}
case "help":
s.client.SendText(evt.RoomID, "Supported commands: info,version,stats,reload,subscribe")
default:
//command not found
s.client.SendText(evt.RoomID, "command not recognized")
}
})
syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) {
log.Infof("<%[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 = s.client.JoinRoomByID(evt.RoomID)
if err != nil {
log.Warnf("error joining room %v", evt.RoomID)
} else {
log.Infof("joined room %v", evt.RoomID)
}
}
})
return nil
}
func (s *simp) Stop() {
s.stop <- true
s.client.StopSync()
}
func (s *simp) NewYT(videoName, videoID, roomID string) *youtubeWidget {
encodedVod := url.QueryEscape("https://youtube.com/embed/" + videoID)
return &youtubeWidget{
Type: "im.vector.modular.widgets",
URL: "https://" + s.dimensionServer + "/widgets/video?url=" + encodedVod,
Name: videoName,
Data: videoData{
VideoURL: "https://www.youtube.com/watch?v=" + videoID,
URL: "https://youtube.com/embed/" + videoID,
DimensionAppMetadata: dimensionAppMetadata{
InRoomID: roomID,
WrapperURLBase: "https://" + s.dimensionServer + "/widgets/video?url=",
WrapperID: "video",
ScalarWrapperID: "youtube",
Integration: integration{
Category: "widget",
Type: "youtube",
},
LastUpdatedTs: time.Now().UnixNano() / int64(time.Millisecond),
},
},
CreatorUserID: string(s.client.UserID),
ID: "dimension-m.video-simp",
}
}

View File

@ -4,14 +4,14 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/charmbracelet/log"
"github.com/spf13/viper"
"maunium.net/go/mautrix/id"
)
type VtuberConfig struct {
type vtuberConfig struct {
Name string `mapstructure:"name"`
ChannelID string `mapstructure:"channelid"`
LiveMsg string `mapstructure:"msg"`
@ -29,7 +29,7 @@ type Vtuber struct {
Subs map[id.UserID]bool
}
func NewVtuber(name, channelID, liveMsg string, announce bool) *Vtuber {
func newVtuber(name, channelID, liveMsg string, announce bool) *Vtuber {
return &Vtuber{
Name: name,
ChannelID: channelID,
@ -42,28 +42,30 @@ func NewVtuber(name, channelID, liveMsg string, announce bool) *Vtuber {
}
}
func LoadVtubers() []*Vtuber {
var vtubersRaw []VtuberConfig
func loadVtubers() []*Vtuber {
var vtubersRaw []vtuberConfig
var vtubers []*Vtuber
err := viper.UnmarshalKey("vtubers", &vtubersRaw)
if err != nil {
panic(err)
}
for _, vt := range vtubersRaw {
log.Printf("adding vtuber %v", vt)
vtubers = append(vtubers, NewVtuber(vt.Name, vt.ChannelID, vt.LiveMsg, vt.Announce))
log.Infof("adding vtuber %v", vt)
vtubers = append(vtubers, newVtuber(vt.Name, vt.ChannelID, vt.LiveMsg, vt.Announce))
}
return vtubers
}
//IsLive returns whether the specified Vtuber is live
func (v *Vtuber) IsLive() bool {
return v.CurrentStream != ""
}
func (v *Vtuber) Update(api_key string) error {
//Update takes an apiKey and updates the vtuber struct
func (v *Vtuber) Update(apiKey string) 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)
req.Header.Set("X-APIKEY", api_key)
req.Header.Set("X-APIKEY", apiKey)
if err != nil {
return err
}
@ -76,7 +78,6 @@ func (v *Vtuber) Update(api_key string) error {
var sl StreamList
err = json.Unmarshal(jsonBody, &sl)
if err != nil {
log.Printf("error parsing json for vtuber %v:%v", v.Name, err)
return err
}
found := false

View File

@ -1,63 +1,32 @@
package main
import (
"net/url"
"time"
)
type Integration struct {
type integration struct {
Category string `json:"category"`
Type string `json:"type"`
}
type DimensionAppMetadata struct {
type dimensionAppMetadata struct {
InRoomID string `json:"inRoomId"`
WrapperURLBase string `json:"wrapperUrlBase"`
WrapperID string `json:"wrapperId"`
ScalarWrapperID string `json:"scalarWrapperId"`
Integration Integration `json:"integration"`
Integration integration `json:"integration"`
LastUpdatedTs int64 `json:"lastUpdatedTs"`
}
type Data struct {
type videoData struct {
VideoURL string `json:"videoUrl"`
URL string `json:"url"`
DimensionAppMetadata DimensionAppMetadata `json:"dimension:app:metadata"`
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 youtubeWidget struct {
Type string `json:"type"`
URL string `json:"url"`
Name string `json:"name"`
Data videoData `json:"data"`
CreatorUserID string `json:"creatorUserId"`
ID string `json:"id"`
RoomID string `json:"roomId"`
EventID string `json:"eventId"`
}
type Unsigned struct {
type unsignedAge 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",
}
}