Compare commits

..

253 commits

Author SHA1 Message Date
4caa8d114e
chore(deps): update ghcr.io/luzifer-docker/action-env:master docker digest to 33e747a 2025-08-24 19:18:26 +00:00
313e42a6cb
fix(deps): update module github.com/stretchr/testify to v1.11.0 2025-08-24 18:34:50 +00:00
428735b3fe
ci(deps): update actions/checkout action to v5 2025-08-24 16:20:51 +00:00
4b220a0553
fix: link target changed
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-08-24 18:20:09 +02:00
da1112a4f5
chore(deps): update mysql:9.4.0 docker digest to 439bfb4 2025-08-22 00:18:02 +00:00
6dec23718b
chore(deps): update mysql:9.4.0 docker digest to 4ff1791 2025-08-21 21:18:01 +00:00
038fef397e
chore(deps): update ghcr.io/luzifer-docker/action-env:master docker digest to 371d25a 2025-08-20 08:48:01 +00:00
c629e37dad
chore(deps): update golang:1.25-alpine docker digest to f18a072 2025-08-17 11:48:10 +00:00
9879782dfe
chore(deps): update postgres:17.6 docker digest to 29e0bb0 2025-08-16 14:48:12 +00:00
24e4378b7a
Release: Twitch-Bot v3.36.1 2025-08-16 12:15:51 +02:00
253ced8a68
fix(ci): replace tool installation for new actions env
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-08-16 12:06:49 +02:00
fe902b908e
chore: "fix" linter errors
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-08-16 11:59:44 +02:00
0b2a0812d0
chore: replace actions runner image
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-08-16 11:53:12 +02:00
16ef36687a
chore(deps): update dependency esbuild to v0.25.9 2025-08-15 23:48:23 +00:00
cd4ee2538b
chore(deps): update postgres docker tag to v17.6 2025-08-14 20:48:10 +00:00
01fdd6235e
chore(deps): update dependency go to v1.25.0 2025-08-14 11:30:17 +00:00
21e990f94d
chore(deps): update postgres:17.5 docker digest to aadf2c0 2025-08-14 11:29:43 +00:00
f743479af2
fix(deps): update module github.com/getsentry/sentry-go to v0.35.1 2025-08-14 05:49:05 +00:00
6b2d42a7ee
chore(deps): update golang:1.25-alpine docker digest to 77dd832 2025-08-14 05:48:25 +00:00
2591d31045
chore(deps): update golang:1.25-alpine docker digest to 6032270 2025-08-14 00:18:23 +00:00
0cca5353dc
chore(deps): update golang docker tag to v1.25 2025-08-13 21:18:16 +00:00
25b22b70e7
chore(deps): update postgres:17.5 docker digest to 0f9d52b 2025-08-13 14:18:08 +00:00
e6aac58fbf
chore(deps): update mariadb docker tag to v11.8.3 2025-08-13 08:18:27 +00:00
fc77212892
chore(deps): update postgres:17.5 docker digest to aef2e62 2025-08-13 08:18:08 +00:00
718e1fa5f0
chore(deps): update postgres:17.5 docker digest to 7a554f4 2025-08-13 05:18:06 +00:00
590a5a53a7
chore(deps): update postgres:17.5 docker digest to 0d5b8e3 2025-08-13 02:18:06 +00:00
6b284d364c
chore(deps): update postgres:17.5 docker digest to fa6e571 2025-08-12 23:18:07 +00:00
ff713ea159
ci(deps): replace actions/checkout action with actions/checkout v4.3.0 2025-08-11 22:48:35 +00:00
f4a4d3d51c
ci(deps): update actions/checkout action to v5 2025-08-11 16:48:24 +00:00
51a1918522
ci(deps): update actions/checkout action to v4.3.0 2025-08-11 10:48:07 +00:00
4931b3ea1a
chore(deps): update luzifer/gh-arch-env docker digest to c4c8584 2025-08-11 00:18:07 +00:00
906f9b374c
fix(deps): update module golang.org/x/net to v0.43.0 2025-08-08 08:07:37 +00:00
1bccf39bab
fix(deps): update module golang.org/x/crypto to v0.41.0 2025-08-08 03:48:35 +00:00
4aec4e8168
chore(deps): update mysql:9.4.0 docker digest to a776e89 2025-08-08 03:47:56 +00:00
4376fe6499
chore(deps): update golang:1.24-alpine docker digest to c8c5f95 2025-08-06 22:48:15 +00:00
0e83695c05
chore(deps): update dependency go to v1.24.6 2025-08-06 18:48:15 +00:00
cbb4bc713f
chore(deps): update mysql:9.4.0 docker digest to 40e657e 2025-08-04 21:48:15 +00:00
e71a04fc6c
ci(deps): update docker/login-action action to v3.5.0 2025-08-04 14:17:57 +00:00
2863f6d07b
chore(deps): update luzifer/gh-arch-env docker digest to 4e4139b 2025-08-04 00:17:59 +00:00
fa2fa655c3
fix(deps): update module github.com/getsentry/sentry-go to v0.35.0 2025-07-31 22:18:30 +00:00
0c3cfc7f26
chore(deps): update mysql:9.4.0 docker digest to 082063d 2025-07-29 21:18:19 +00:00
62866e3595
chore(deps): update luzifer/gh-arch-env docker digest to ba7f618 2025-07-28 00:18:16 +00:00
21a0b3c453
fix(deps): update dependency axios to v1.11.0 2025-07-26 06:18:27 +00:00
085c04642a
fix(deps): update module gorm.io/gorm to v1.30.1 2025-07-24 03:18:31 +00:00
1064a28086
chore(deps): update mysql:9.4.0 docker digest to 2426e02 2025-07-24 00:48:24 +00:00
b1958b9135
chore(deps): update dependency esbuild to v0.25.8 2025-07-23 08:23:14 +00:00
6cbf195d4b
chore(deps): update mysql docker tag to v9.4.0 2025-07-22 21:48:25 +00:00
e50227ff92
chore(deps): update postgres:17.5 docker digest to 4d89c90 2025-07-22 14:48:26 +00:00
98d0f7561a
chore(deps): update postgres:17.5 docker digest to 378ef4a 2025-07-22 08:48:23 +00:00
2a081c9a9d
chore(deps): update dependency esbuild to v0.25.7 2025-07-22 05:48:51 +00:00
9dcde1ede4
chore(deps): update postgres:17.5 docker digest to 4a04f62 2025-07-22 05:48:22 +00:00
45f261feb6
chore(deps): update luzifer/gh-arch-env docker digest to ee481a0 2025-07-21 03:18:24 +00:00
a1e393a22b
chore(deps): update luzifer/gh-arch-env docker digest to c5eccd4 2025-07-21 00:18:24 +00:00
86ece55ccf
chore(deps): update golang:1.24-alpine docker digest to daae04e 2025-07-17 18:18:03 +00:00
d1a9dfda21
chore(deps): update mysql:9.3.0 docker digest to b9d8b7e 2025-07-17 06:17:56 +00:00
a338471d89
chore(deps): update mysql:9.3.0 docker digest to 1b3da21 2025-07-16 21:47:55 +00:00
b0f463643d
chore(deps): update mariadb:11.8.2 docker digest to 2bcbaec 2025-07-16 15:47:54 +00:00
85adc8c9a0
chore(deps): update mariadb:11.8.2 docker digest to 4d2b2f2 2025-07-16 12:47:55 +00:00
2c17456e53
chore(deps): update mariadb:11.8.2 docker digest to acf55e2 2025-07-16 10:17:55 +00:00
37276ee335
chore(deps): update golang:1.24-alpine docker digest to 48ee313 2025-07-16 02:48:09 +00:00
18b1587267
chore(deps): update mariadb:11.8.2 docker digest to ee8fadc 2025-07-16 00:48:10 +00:00
cacf08158e
chore(deps): update golang:1.24-alpine docker digest to 9c4b616 2025-07-15 23:48:10 +00:00
30eec0bcd9
chore(deps): update alpine:3.22 docker digest to 4bcff63 2025-07-15 22:18:10 +00:00
ceaa444b8a
chore(deps): update luzifer/gh-arch-env docker digest to 94f9a24 2025-07-14 00:18:23 +00:00
a6110ea605
fix(deps): update module golang.org/x/net to v0.42.0 2025-07-11 11:18:18 +00:00
3cfa35ba5e
chore(deps): update dependency esbuild to v0.25.6 2025-07-11 03:18:51 +00:00
c9fbcfcd87
chore(deps): update mysql:9.3.0 docker digest to 297f5ea 2025-07-11 03:18:22 +00:00
263137e947
chore(deps): update golang:1.24-alpine docker digest to ddf5200 2025-07-09 18:48:17 +00:00
50195a0f33
chore(deps): update dependency go to v1.24.5 2025-07-08 17:18:24 +00:00
1d17cfff31
fix(deps): update module github.com/getsentry/sentry-go to v0.34.1 2025-07-07 16:48:13 +00:00
98ee09ad87
chore(deps): update luzifer/gh-arch-env docker digest to e5f806a 2025-07-07 03:17:59 +00:00
ed2657f981
chore(deps): update luzifer/gh-arch-env docker digest to 3136663 2025-07-07 00:17:57 +00:00
d3ad8e2dab
chore(deps): update dependency @babel/eslint-parser to v7.28.0 2025-07-05 08:48:30 +00:00
8f135dc79d
chore(deps): update mysql:9.3.0 docker digest to f1049ce 2025-07-02 09:18:23 +00:00
da5ba74aaa
chore(deps): update mariadb:11.8.2 docker digest to 1e4ec03 2025-07-02 07:18:22 +00:00
aa17043566
chore(deps): update mysql:9.3.0 docker digest to f246779 2025-07-02 00:18:28 +00:00
bb8d62cca2
chore(deps): update postgres:17.5 docker digest to 3962158 2025-07-01 14:48:22 +00:00
6e6ef5227c
chore(deps): update postgres:17.5 docker digest to fc50da4 2025-07-01 08:48:21 +00:00
0d866c702f
chore(deps): update postgres:17.5 docker digest to 016154b 2025-07-01 05:48:21 +00:00
8d6f74d8eb
chore(deps): update luzifer/gh-arch-env docker digest to 9ce1419 2025-06-30 00:18:21 +00:00
ebef4df8c2
ci(deps): update ncipollo/release-action digest to bcfe547 2025-06-29 21:48:21 +00:00
8ff90c1bf3
Release: Twitch-Bot v3.36.0 2025-06-29 11:54:50 +02:00
0c3c066e25
ci(deps): update ncipollo/release-action digest to 9128f23 2025-06-29 02:18:10 +00:00
bf7385fab4
chore(deps): update mysql:9.3.0 docker digest to 9a084cc 2025-06-26 06:18:18 +00:00
efbd1f2e14
chore(deps): update mysql:9.3.0 docker digest to 5c9a1db 2025-06-26 03:18:18 +00:00
01fa504216
fix(deps): update module github.com/getsentry/sentry-go to v0.34.0 2025-06-23 14:48:37 +00:00
61a4a20395
chore(deps): update luzifer/gh-arch-env docker digest to 8800227 2025-06-23 03:48:14 +00:00
c261dba13a
chore(deps): update luzifer/gh-arch-env docker digest to 2bd09ea 2025-06-23 00:18:16 +00:00
a719e79962
fix(deps): update module gotest.tools/gotestsum to v1.12.3 2025-06-19 03:48:37 +00:00
0c6bc3a844
fix(deps): update dependency axios to v1.10.0 2025-06-17 12:24:16 +00:00
f5532cd86c
chore(deps): update luzifer/gh-arch-env docker digest to 58c1c17 2025-06-16 03:35:17 +00:00
d0068c6b84
chore(deps): update luzifer/gh-arch-env docker digest to 1eda280 2025-06-16 00:05:28 +00:00
a86e13960d
feat: migrate to new channel.hype_train.* v2 events
as the v1 versions of the events are now deprecated

fixes 

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-06-15 13:09:09 +02:00
ebe66edc3c
fix(deps): update module github.com/go-sql-driver/mysql to v1.9.3 2025-06-13 07:05:31 +00:00
f3a5fa3be0
chore(deps): update mysql:9.3.0 docker digest to 072f96c 2025-06-12 06:35:21 +00:00
fa529a5936
chore(deps): update mysql:9.3.0 docker digest to b3b4f16 2025-06-11 18:05:13 +00:00
b7013c1fbb
chore(deps): update mariadb docker tag to v11.8.2 2025-06-11 12:05:38 +00:00
f7e1509716
chore(deps): update postgres:17.5 docker digest to 6cf6142 2025-06-11 12:05:12 +00:00
24335e9451
chore(deps): update postgres:17.5 docker digest to cb51e9f 2025-06-11 06:04:52 +00:00
fd966855b4
chore(deps): update postgres:17.5 docker digest to 62d6869 2025-06-11 02:35:25 +00:00
8a28f58b06
chore(deps): update postgres:17.5 docker digest to 30a7233 2025-06-09 21:04:54 +00:00
74cd388928
fix(deps): update module github.com/go-git/go-git/v5 to v5.16.2 2025-06-09 09:52:06 +00:00
d0ed052a5a
ci: remove CRDB integration test
as for the license changes in CRDB it is no longer a supported database
for the bot.

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-06-09 11:50:31 +02:00
df9c548e2d
chore(deps): update luzifer/gh-arch-env docker digest to 9810b8a 2025-06-09 03:04:36 +00:00
7b837db5f6
chore(deps): update luzifer/gh-arch-env docker digest to 8f47e58 2025-06-09 00:04:47 +00:00
4e2241c7f4
chore(deps): update dependency @babel/eslint-parser to v7.27.5 2025-06-06 11:35:14 +00:00
432d06535f
chore(deps): update dependency go to v1.24.4 2025-06-05 22:37:04 +00:00
99775cb815
fix(deps): update module golang.org/x/net to v0.41.0 2025-06-05 21:06:26 +00:00
9fcb6fca77
chore(deps): update golang:1.24-alpine docker digest to 68932fa 2025-06-05 20:35:21 +00:00
a6c8f0aa15
fix(deps): update module github.com/go-git/go-git/v5 to v5.16.1 2025-06-04 10:15:36 +00:00
7fbc7b565b
fix(deps): update module gorm.io/driver/mysql to v1.6.0 2025-06-04 08:05:20 +00:00
0a45c0d92e
chore(deps): update mariadb:11.7.2 docker digest to fcc7fcd 2025-06-03 07:05:25 +00:00
438297fc75
chore(deps): update luzifer/gh-arch-env docker digest to b39254f 2025-06-02 03:34:43 +00:00
74e647de27
chore(deps): update luzifer/gh-arch-env docker digest to 53642f2 2025-06-02 00:05:12 +00:00
37cfc399e8
chore(deps): update golang:1.24-alpine docker digest to b4f875e 2025-05-31 08:34:28 +00:00
51328629b1
chore(deps): update golang:1.24-alpine docker digest to 2853d62 2025-05-31 06:05:07 +00:00
2e7a631e1c
chore(deps): update golang:1.24-alpine docker digest to b158e66 2025-05-31 02:33:53 +00:00
0d42d5336a
chore(deps): update mysql:9.3.0 docker digest to 04768cb 2025-05-30 21:34:16 +00:00
07eebd47b7
chore(deps): update alpine docker tag to v3.22 2025-05-30 19:04:13 +00:00
e3aa795604
chore(deps): update dependency esbuild to v0.25.5 2025-05-30 03:34:53 +00:00
de782bae4e
Update ghcr.io/luzifer-docker/crdb-gh-service Docker tag to v25.2.0 2025-05-27 16:04:21 +00:00
91a41f53c6
Update module gorm.io/driver/postgres to v1.6.0 2025-05-27 13:05:27 +00:00
7a1eb5b9d0
Update luzifer/gh-arch-env Docker digest to 1113ddb 2025-05-26 03:34:10 +00:00
e337b47938
Update luzifer/gh-arch-env Docker digest to cf87665 2025-05-26 00:04:54 +00:00
5bc8f1fa23
Update module gorm.io/gorm to v1.30.0 2025-05-25 08:07:53 +00:00
50190346d5
Update postgres:17.5 Docker digest to 6efd0df 2025-05-23 08:37:47 +00:00
beae543e0b
Update postgres:17.5 Docker digest to ea51edb 2025-05-23 02:37:32 +00:00
ebce29eb6a
Update postgres:17.5 Docker digest to bf0f80f 2025-05-22 21:06:24 +00:00
59862ccb8d
Update postgres:17.5 Docker digest to 20b542a 2025-05-22 18:07:45 +00:00
eb1f57d253
Update postgres:17.5 Docker digest to bbdcc04 2025-05-22 05:37:45 +00:00
ed20672011
Update postgres:17.5 Docker digest to 2718f68 2025-05-22 02:36:02 +00:00
183f5233e2
Update luzifer/gh-arch-env Docker digest to d0d04e6 2025-05-16 04:09:32 +00:00
5c86323bf5
Update luzifer/gh-arch-env Docker digest to 664cf41 2025-05-16 00:10:45 +00:00
bfa50a7d1c
Update module github.com/getsentry/sentry-go to v0.33.0 2025-05-15 13:07:50 +00:00
93ad13ce70
Update ghcr.io/luzifer-docker/crdb-gh-service Docker tag to v25.1.6 2025-05-14 08:08:21 +00:00
59546e19b2
Update postgres Docker tag to v17.5 2025-05-09 03:07:35 +00:00
d22132caac
Update luzifer/gh-arch-env Docker digest to 2a1435e 2025-05-09 03:07:11 +00:00
c368fea4de
Update luzifer/gh-arch-env Docker digest to 1fc386f 2025-05-09 00:08:46 +00:00
733bbbb6bf
Update module gorm.io/gorm to v1.26.1 2025-05-07 08:18:18 +00:00
702ef21be1
Update dependency go to v1.24.3 2025-05-06 23:07:40 +00:00
60d71ce66b
Update golang:1.24-alpine Docker digest to ef18ee7 2025-05-06 21:07:19 +00:00
5ec75f7a98
Update module gotest.tools/gotestsum to v1.12.2 2025-05-06 07:49:12 +00:00
fdcb02f7a9
Update dependency esbuild to v0.25.4 2025-05-06 00:36:53 +00:00
db873c9706
Update module golang.org/x/net to v0.40.0 2025-05-05 20:35:56 +00:00
5c6bf33914
Update mariadb:11.7.2 Docker digest to 11706a6 2025-05-05 19:05:58 +00:00
62d24e8fe1
Update module golang.org/x/oauth2 to v0.30.0 2025-05-05 13:37:57 +00:00
276d952be3
Update luzifer/gh-arch-env Docker digest to 90b9c6e 2025-05-02 04:35:46 +00:00
b4a9a7fee0
Update luzifer/gh-arch-env Docker digest to b6512b1 2025-05-01 04:06:11 +00:00
c29e82e3ab
Update dependency @babel/eslint-parser to v7.27.1 2025-04-30 15:36:17 +00:00
a4d505f505
Update mysql:9.3.0 Docker digest to 2247f6d 2025-04-30 09:34:18 +00:00
6d175a801c
Update luzifer/gh-arch-env Docker digest to 1f2ab7e 2025-04-30 03:34:41 +00:00
e9bf7b84a6
Update luzifer/gh-arch-env Docker digest to 1f2ab7e 2025-04-30 03:34:14 +00:00
992b7fe4af
Update mysql:9.3.0 Docker digest to 5b67216 2025-04-29 21:35:32 +00:00
e8f96f19d1
Pin dependencies 2025-04-29 13:07:38 +00:00
790576ddb5
Update postgres:17.4 Docker digest to 304ab81 2025-04-29 08:34:53 +00:00
6ec96f9daa
Update postgres:17.4 Docker digest to 4aed4b0 2025-04-29 06:06:14 +00:00
678a003307
Update luzifer/gh-arch-env Docker digest to 6af5cae 2025-04-29 03:35:38 +00:00
1fcc35524e
Update postgres:17.4 Docker digest to f57cfa8 2025-04-29 02:34:44 +00:00
865e38125a
Update postgres:17.4 Docker digest to cdb3f38 2025-04-29 00:04:22 +00:00
68a899cd79
Update ghcr.io/luzifer-docker/crdb-gh-service Docker tag to v25.1.5 2025-04-28 15:34:35 +00:00
34abf9d564
Update luzifer/gh-arch-env Docker digest to c8454dc 2025-04-28 04:05:00 +00:00
8ce0b5b294
Update luzifer/gh-arch-env Docker digest to 2c35624 2025-04-27 04:34:42 +00:00
574ca67c69
Update luzifer/gh-arch-env Docker digest to eb4fcf8 2025-04-27 03:36:31 +00:00
05d6c8bc50
Update luzifer/gh-arch-env Docker digest to b25582c 2025-04-26 04:04:11 +00:00
e4f0ec004d
Update dependency axios to v1.9.0 2025-04-25 09:19:37 +00:00
3db82d9c7b
Update module gorm.io/gorm to v1.26.0 2025-04-25 08:34:45 +00:00
53c6aa07fa
Update luzifer/gh-arch-env Docker digest to a5a2097 2025-04-25 04:05:41 +00:00
8355e6306a
Update luzifer/gh-arch-env Docker digest to 0ce058d 2025-04-24 03:05:25 +00:00
e0edb68d44
Update dependency esbuild to v0.25.3 2025-04-23 08:07:46 +00:00
5519e4de68
Update luzifer/gh-arch-env Docker digest to da08b5c 2025-04-23 04:05:53 +00:00
e76358fc4f
Update luzifer/gh-arch-env Docker digest to 1c9dcc4 2025-04-22 03:34:45 +00:00
04cc7762c2
Update luzifer/gh-arch-env Docker digest to 34982d6 2025-04-21 04:04:24 +00:00
acfc5cbe12
Update luzifer/gh-arch-env Docker digest to 975506f 2025-04-21 00:34:10 +00:00
09cf117501
Update luzifer/gh-arch-env Docker digest to c0b7839 2025-04-20 23:05:07 +00:00
facbdbe477
Update luzifer/gh-arch-env Docker digest to 35360d7 2025-04-20 04:32:56 +00:00
aebe017b27
Update luzifer/gh-arch-env Docker digest to f175b6a 2025-04-20 03:33:06 +00:00
fb628c24fc
Update luzifer/gh-arch-env Docker digest to dff7b93 2025-04-19 03:02:42 +00:00
68d24ccefc
Update luzifer/gh-arch-env Docker digest to 3e8be63 2025-04-18 03:32:35 +00:00
05012ecc96
Update luzifer/gh-arch-env Docker digest to 3ee6c15 2025-04-17 04:02:29 +00:00
92321e4054
Update luzifer/gh-arch-env Docker digest to 68f318a 2025-04-16 03:32:32 +00:00
8119140c46
Update module github.com/go-git/go-git/v5 to v5.16.0 2025-04-15 20:03:26 +00:00
ddded3decb
Update mysql Docker tag to v9.3.0 2025-04-15 04:02:58 +00:00
848c222233
Update luzifer/gh-arch-env Docker digest to 0088a8b 2025-04-15 04:02:36 +00:00
a7c238d67f
Tools: Remove dependency to gofumpt
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-14 10:23:47 +02:00
2ea0c3e746
Update luzifer/gh-arch-env Docker digest to f18a6a4 2025-04-14 04:02:24 +00:00
e46e7bd863
Update module github.com/Luzifer/rconfig/v2 to v2.6.0 2025-04-13 12:03:05 +00:00
870efae0b9
Update luzifer/gh-arch-env Docker digest to 3574a2f 2025-04-13 11:32:18 +00:00
2a01049812
Update luzifer/gh-arch-env Docker digest to bef18dd 2025-04-13 05:02:27 +00:00
2104690965
Update luzifer/gh-arch-env Docker digest to 889b3ac 2025-04-13 04:02:58 +00:00
5e9929f7be
CI: Lock down updates to workflow to once a week
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-12 15:42:46 +02:00
9c1718e090
Pin dependencies 2025-04-12 12:39:30 +00:00
bab21223c1
CI: Update to pinned CRDB service image
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-12 14:38:35 +02:00
4843f97231
CI: Update integration test to latest database versions
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-12 14:27:01 +02:00
d62e978c4e
Release: Twitch-Bot v3.35.4 2025-04-12 14:10:50 +02:00
1059f70468
[docs] Fix: Typo in URL
params are read from hash, not query

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-12 12:33:53 +02:00
365e1c9fcd
Update luzifer/gh-arch-env Docker digest to fd19117 2025-04-12 03:32:21 +00:00
1bd9cd578f
Update module github.com/go-git/go-git/v5 to v5.15.0 2025-04-11 09:02:31 +00:00
2719af4960
Update luzifer/gh-arch-env Docker digest to 6bfca0d 2025-04-11 04:02:35 +00:00
cf7811591c
Update module github.com/getsentry/sentry-go to v0.32.0 2025-04-10 10:03:06 +00:00
e86e1f9f91
Update luzifer/gh-arch-env Docker digest to d4a565d 2025-04-10 04:01:56 +00:00
a97dc76e1a
Update mariadb:11 Docker digest to 81e8930 2025-04-09 10:02:23 +00:00
14e8a5e2b7
Update mariadb:11 Docker digest to 2010ede 2025-04-09 07:02:54 +00:00
5da4196ba1
Update luzifer/gh-arch-env Docker digest to 23109db 2025-04-09 03:02:39 +00:00
b06b9d7645
Update postgres:15 Docker digest to fe45ed1 2025-04-08 18:02:45 +00:00
0be1a89019
Update postgres:15 Docker digest to 16c7497 2025-04-08 14:32:28 +00:00
2748dfe82b
Update postgres:15 Docker digest to 71807dd 2025-04-08 08:33:35 +00:00
5271b50ae6
Update module golang.org/x/net to v0.39.0 2025-04-08 06:02:54 +00:00
0bb1948a82
Update postgres:15 Docker digest to 2d3fd09 2025-04-08 06:02:11 +00:00
48b253d213
Update luzifer/gh-arch-env Docker digest to 9b07ef8 2025-04-08 03:02:25 +00:00
5b977d3f31
Update module github.com/go-sql-driver/mysql to v1.9.2 2025-04-07 12:02:53 +00:00
f7308345e0
Revert "CI: Disable Vue v3 / Bootstrap v5 updates"
Doesn't work, Renovate ignores this for security fixes

This reverts commit 207ebd3e52.
2025-04-07 10:16:01 +02:00
207ebd3e52
CI: Disable Vue v3 / Bootstrap v5 updates
as they need a full rewrite of the frontend which is in progress but
will take way more time.

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-07 10:11:56 +02:00
12de1efef2
Update luzifer/gh-arch-env Docker digest to 4c27bbc 2025-04-07 03:02:22 +00:00
0df88165c7
CI: Drop "stable" branch
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-07 00:08:31 +02:00
6421c87ed0
Update luzifer/gh-arch-env Docker digest to 60bef93 2025-04-06 21:46:50 +00:00
0eb8523939
Release: Twitch-Bot v3.35.3 2025-04-06 23:44:24 +02:00
de973e7fdf
Pin dependencies 2025-04-06 21:25:22 +00:00
2959c79e7e
Update Font Awesome to v6.7.2 2025-04-06 21:23:54 +00:00
7bfa1e6166
Update dependency go to v1.24.2 2025-04-06 21:22:10 +00:00
ed5768f80e
Update module golang.org/x/crypto to v0.37.0 2025-04-06 21:20:03 +00:00
5a842c8160
Update dependency eslint-plugin-vue to v9.33.0 2025-04-06 21:17:03 +00:00
52e54017e4
Update dependency eslint to v8.57.1 2025-04-06 21:14:18 +00:00
d3ba7c965a
Update dependency @babel/eslint-parser to v7.27.0 2025-04-06 21:11:18 +00:00
8c0fed012c
Pin dependencies 2025-04-06 21:04:37 +00:00
7f045fa928
Update dependency esbuild to ^0.25.0 [SECURITY] 2025-04-06 20:57:31 +00:00
bbe454ed4f
CI: Switch to alpine based build image, add image labels
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 22:56:11 +02:00
2543622abf
CI: Fix: Options must not end with newline
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 22:47:21 +02:00
22325da84f
Pin dependencies 2025-04-06 20:39:51 +00:00
1bde118f9d
CI: Pin Alpine repo to latest version
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 22:38:01 +02:00
019d46817e
Fix: Workflows do not understand references
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 16:29:35 +02:00
edc1d9da5b
CI: Re-join workflow, enable renovate
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 16:01:42 +02:00
a57aa101db
CI: Remove dependency on git-lfs
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 13:46:25 +02:00
c3788e19ab
Release: Twitch-Bot v3.35.2 2025-04-06 13:34:59 +02:00
5998a07892
Replace nodejs LTS version
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 13:24:59 +02:00
2c4fccd56d
Update Go & Node dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 13:20:29 +02:00
2393b2c4ab
Lint: Migrate linter config, use local linter, fix issues
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 13:14:57 +02:00
a6b30aa6e7
Replace LFS files
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2025-04-06 12:37:21 +02:00
99eecd1631
Release: Twitch-Bot v3.35.1 2024-12-12 11:18:57 +01:00
00320ba09c
Update node dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-12-12 11:11:58 +01:00
db2d80642a
Update Go dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-12-12 11:11:58 +01:00
3cfee5ccc9
[core] Fix: Reduce token requirements for category search
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-12-12 00:59:42 +01:00
9cac1686b8
CI: Configure git-changerelease
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-12-02 13:25:25 +01:00
f26ce9b0da
prepare release v3.35.0 2024-12-02 13:24:22 +01:00
dd80433cb0
[raffle] Fix: Raffle channel did not allow underscore in channel name
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-12-02 13:08:18 +01:00
0d76c58ede
[template] Add functions parseDuration, parseDurationToSeconds
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-11-25 00:40:53 +01:00
096657bcee
Improve CI and document Makefile
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-26 13:18:37 +02:00
ff475f286b
prepare release v3.34.0 2024-09-16 11:10:16 +02:00
06d7fcb019
Lint: Fix (theoretical) overflow issues
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-16 11:09:03 +02:00
710783aaf7
[core] Fix: StreamMarker contained wrong ID format
as of broken documentation

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-13 00:08:41 +02:00
19038dbc6e
[templating] Add currentVOD function
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-11 20:30:55 +02:00
740a71a173
[marker] Add marker info to actor result
in order to enable rules to access i.e. the position of the marker

Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-11 14:23:42 +02:00
e0a8ce3684
[linkcheck] Fix: Replace static (deprecated) user-agent list
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-05 12:50:58 +02:00
5a8459cedc
[marker] Implement actor to create stream markers
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2024-09-04 00:06:55 +02:00
56 changed files with 2162 additions and 1772 deletions

19
.git_changerelease.yaml Normal file
View file

@ -0,0 +1,19 @@
---
# Template to format the commit message containing the changelog change
# which will be used to add the tag to.
release_commit_message: "Release: Twitch-Bot {{.Version}}"
# Commands to run before committing the changelog and adding the tag.
# Therefore these can add content to be included into the release-
# commit. These commands have access to the `TAG_VERSION` variable
# which contains the tag to be applied after the commit. If the
# command specified here is prefixed with a `-` sign, the exit status
# will not fail the release process. If it is not prefixed with a `-`
# a non-zero exit status will terminate the release process. The
# commands will be run from the repostory root, so sub-dirs MUST be
# specified. All commands are run as `bash -ec "..."` so you can use
# bash inside the commands.
pre_commit_commands: []
...

1
.gitattributes vendored
View file

@ -1 +0,0 @@
docs/static/* filter=lfs diff=lfs merge=lfs -text

View file

@ -1,17 +1,42 @@
name: CI Workflow
on: push
permissions:
contents: read
jobs:
doc-generator:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs:
- test
test:
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Lint and test code
run: make lint test frontend_lint
- name: Build release (quick local for compile)
run: make build_prod
- name: Execute Trivy scan
run: make trivy
doc-generator:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [test]
defaults:
run:
shell: bash
container:
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
@ -21,9 +46,8 @@ jobs:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
lfs: true
show-progress: false
submodules: true
- name: Marking workdir safe
@ -31,15 +55,15 @@ jobs:
- name: Generate documentation
run: make render_docs DOCS_BASE_URL=https://luzifer.github.io/twitch-bot/
- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: .rendered-docs
- name: Deploy artifact
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
docker-publish:
if: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/master' }}
needs:
- test
needs: [test]
defaults:
run:
shell: bash
@ -47,83 +71,48 @@ jobs:
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Log into registry
uses: docker/login-action@v3
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Publish
run: bash ci/docker-publish.sh
integration-crdb:
if: ${{ github.ref == 'refs/heads/master' }}
needs:
- test
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
crdb:
image: luzifer/crdb-gh-service
options: --health-cmd "curl -sSf http://localhost:8080/health" --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
cockroachdb-bin
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Set up CRDB service
run: |
cockroach sql --host crdb --insecure <<EOF
CREATE DATABASE integration;
CREATE USER "twitch_bot" WITH PASSWORD NULL;
ALTER DATABASE integration OWNER to "twitch_bot";
EOF
- name: Run tests against CRDB
env:
GO_TEST_DB_ENGINE: postgres
GO_TEST_DB_DSN: host=crdb user=twitch_bot dbname=integration port=26257 sslmode=disable timezone=UTC
run: make short_test
integration-mariadb:
if: ${{ github.ref == 'refs/heads/master' }}
needs:
- test
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:11
image: mariadb:11.8.3@sha256:272084c2dec70619714df329c4ffcb336e3f8c723072c3f56f2e4015997bbf2c
env:
MYSQL_PASSWORD: twitch-bot-pass
MYSQL_ROOT_PASSWORD: root-pass
MYSQL_USER: twitch-bot
options: --health-cmd "healthcheck.sh --connect --innodb_initialized" --health-interval 10s --health-timeout 5s --health-retries 5
options: >-
--health-cmd "healthcheck.sh
--connect
--innodb_initialized"
--health-interval 10s
--health-retries 5
--health-timeout 5s
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
mariadb-clients
- uses: actions/checkout@v4
run: apt-get install -y --no-install-recommends mariadb-client
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Marking workdir safe
@ -139,33 +128,35 @@ jobs:
GO_TEST_DB_ENGINE: mysql
GO_TEST_DB_DSN: twitch-bot:twitch-bot-pass@tcp(mariadb:3306)/integration?charset=utf8mb4&parseTime=True
run: make short_test
integration-mysql:
if: ${{ github.ref == 'refs/heads/master' }}
needs:
- test
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8
image: mysql:9.4.0@sha256:439bfb4044dc59ade76c4e5c4065c02e5ba4d4007db32c40ac58d55c03069916
env:
MYSQL_PASSWORD: twitch-bot-pass
MYSQL_ROOT_PASSWORD: root-pass
MYSQL_USER: twitch-bot
options: --health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 5
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-retries 5
--health-timeout 5s
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
mariadb-clients
- uses: actions/checkout@v4
run: apt-get install -y --no-install-recommends mariadb-client
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Marking workdir safe
@ -181,27 +172,31 @@ jobs:
GO_TEST_DB_ENGINE: mysql
GO_TEST_DB_DSN: twitch-bot:twitch-bot-pass@tcp(mysql:3306)/integration?charset=utf8mb4&parseTime=True
run: make short_test
integration-postgres:
if: ${{ github.ref == 'refs/heads/master' }}
needs:
- test
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
image: postgres:17.6@sha256:29e0bb09c8e7e7fc265ea9f4367de9622e55bae6b0b97e7cce740c2d63c2ebc0
env:
POSTGRES_PASSWORD: twitch-bot-pass
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-retries 5
--health-timeout 5s
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Marking workdir safe
@ -209,17 +204,24 @@ jobs:
- name: Run tests against PostgreSQL
env:
GO_TEST_DB_ENGINE: postgres
GO_TEST_DB_DSN: host=postgres user=postgres password=twitch-bot-pass dbname=postgres port=5432 sslmode=disable timezone=UTC
GO_TEST_DB_DSN: >
host=postgres
user=postgres
password=twitch-bot-pass
dbname=postgres
port=5432
sslmode=disable
timezone=UTC
run: make short_test
release:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs:
- test
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
image: ghcr.io/luzifer-docker/action-env:master@sha256:33e747ae78dc2b8dc291a433f4c3c4d522cf565b449fe9c3e33a0c21f516a570
env:
CGO_ENABLED: 0
GOPATH: /go
@ -227,48 +229,19 @@ jobs:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
show-progress: false
- name: Marking workdir safe
run: |
git config --global --add safe.directory /__w/twitch-bot/twitch-bot
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Build release
run: make publish
- name: Extract changelog
run: awk "/^#/ && ++c==2{exit}; /^#/f" "History.md" | tail -n +2 >release_changelog.md
- name: Update stable branch
run: |
git branch -f stable ${GITHUB_SHA}
git push -f origin stable
- name: Release
uses: ncipollo/release-action@v1
uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af # v1
with:
artifacts: .build/*
bodyFile: release_changelog.md
draft: false
generateReleaseNotes: false
test:
if: ${{ github.ref != 'refs/heads/stable' }}
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: |
git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Lint and test code
run: make lint test frontend_lint
- name: Build release (quick local for compile)
run: make build_prod
- name: Execute Trivy scan
run: make trivy

View file

@ -1,174 +1,146 @@
# Derived from https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml
---
version: '2'
run:
# timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 5m
# Force readonly modules usage for checking
modules-download-mode: readonly
output:
formats:
- format: tab
tab:
path: stdout
issues:
# This disables the included exclude-list in golangci-lint as that
# list for example fully hides G304 gosec rule, errcheck, exported
# rule of revive and other errors one really wants to see.
# Smme detail: https://github.com/golangci/golangci-lint/issues/456
exclude-use-default: false
# Don't limit the number of shown issues: Report ALL of them
max-issues-per-linter: 0
max-same-issues: 0
colors: false
linters:
disable-all: true
default: none
enable:
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
- bodyclose # checks whether HTTP response body is closed successfully [fast: true, auto-fix: false]
- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: true, auto-fix: false]
- contextcheck # check the function whether use a non-inherited context [fast: false, auto-fix: false]
- copyloopvar # copyloopvar is a linter detects places where loop variables are copied [fast: true, auto-fix: false]
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
- durationcheck # check for two durations multiplied together [fast: false, auto-fix: false]
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
- forbidigo # Forbids identifiers [fast: true, auto-fix: false]
- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
- gocritic # The most opinionated Go source code linter [fast: true, auto-fix: false]
- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true]
- gosec # Inspects source code for security problems [fast: true, auto-fix: false]
- gosimple # Linter for Go source code that specializes in simplifying a code [fast: true, auto-fix: false]
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: true, auto-fix: false]
- ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
- mnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false]
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
- nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
- noctx # noctx finds sending http request without context.Context [fast: true, auto-fix: false]
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks [fast: true, auto-fix: false]
- stylecheck # Stylecheck is a replacement for golint [fast: true, auto-fix: false]
- tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false]
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: true, auto-fix: false]
- unconvert # Remove unnecessary type conversions [fast: true, auto-fix: false]
- unused # Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
- wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- copyloopvar
- dogsled
- durationcheck
- errcheck
- errchkjson
- forbidigo
- funlen
- gocognit
- goconst
- gocritic
- gocyclo
- godox
- gosec
- govet
- ineffassign
- misspell
- mnd
- nakedret
- nilerr
- nilnil
- noctx
- nolintlint
- revive
- staticcheck
- unconvert
- unused
- wastedassign
- wrapcheck
linters-settings:
settings:
funlen:
lines: 100
statements: 60
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 15
gomnd:
ignored-functions: 'strconv.(?:Format|Parse)\B+'
mnd:
ignored-functions:
- strconv.(?:Format|Parse)\B+
revive:
rules:
#- name: add-constant # Suggests using constant for magic numbers and string literals
# Opinion: Makes sense for strings, not for numbers but checks numbers
#- name: argument-limit # Specifies the maximum number of arguments a function can receive | Opinion: Don't need this
- name: atomic # Check for common mistaken usages of the `sync/atomic` package
- name: banned-characters # Checks banned characters in identifiers
- name: atomic
- name: banned-characters
arguments:
- ';' # Greek question mark
- name: bare-return # Warns on bare returns
- name: blank-imports # Disallows blank imports
- name: bool-literal-in-expr # Suggests removing Boolean literals from logic expressions
- name: call-to-gc # Warns on explicit call to the garbage collector
#- name: cognitive-complexity # Sets restriction for maximum Cognitive complexity.
# There is a dedicated linter for this
- name: confusing-naming # Warns on methods with names that differ only by capitalization
- name: confusing-results # Suggests to name potentially confusing function results
- name: constant-logical-expr # Warns on constant logical expressions
- name: context-as-argument # `context.Context` should be the first argument of a function.
- name: context-keys-type # Disallows the usage of basic types in `context.WithValue`.
#- name: cyclomatic # Sets restriction for maximum Cyclomatic complexity.
# There is a dedicated linter for this
#- name: datarace # Spots potential dataraces
# Is not (yet) available?
- name: deep-exit # Looks for program exits in funcs other than `main()` or `init()`
- name: defer # Warns on some [defer gotchas](https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1)
- name: dot-imports # Forbids `.` imports.
- name: duplicated-imports # Looks for packages that are imported two or more times
- name: early-return # Spots if-then-else statements that can be refactored to simplify code reading
- name: empty-block # Warns on empty code blocks
- name: empty-lines # Warns when there are heading or trailing newlines in a block
- name: errorf # Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()`
- name: error-naming # Naming of error variables.
- name: error-return # The error return parameter should be last.
- name: error-strings # Conventions around error strings.
- name: exported # Naming and commenting conventions on exported symbols.
arguments: ['sayRepetitiveInsteadOfStutters']
#- name: file-header # Header which each file should have.
# Useless without config, have no config for it
- name: flag-parameter # Warns on boolean parameters that create a control coupling
#- name: function-length # Warns on functions exceeding the statements or lines max
# There is a dedicated linter for this
#- name: function-result-limit # Specifies the maximum number of results a function can return
# Opinion: Don't need this
- name: get-return # Warns on getters that do not yield any result
- name: identical-branches # Spots if-then-else statements with identical `then` and `else` branches
- name: if-return # Redundant if when returning an error.
#- name: imports-blacklist # Disallows importing the specified packages
# Useless without config, have no config for it
- name: import-shadowing # Spots identifiers that shadow an import
- name: increment-decrement # Use `i++` and `i--` instead of `i += 1` and `i -= 1`.
- name: indent-error-flow # Prevents redundant else statements.
#- name: line-length-limit # Specifies the maximum number of characters in a lined
# There is a dedicated linter for this
#- name: max-public-structs # The maximum number of public structs in a file.
# Opinion: Don't need this
- name: modifies-parameter # Warns on assignments to function parameters
- name: modifies-value-receiver # Warns on assignments to value-passed method receivers
#- name: nested-structs # Warns on structs within structs
# Opinion: Don't need this
- name: optimize-operands-order # Checks inefficient conditional expressions
#- name: package-comments # Package commenting conventions.
# Opinion: Don't need this
- name: range # Prevents redundant variables when iterating over a collection.
- name: range-val-address # Warns if address of range value is used dangerously
- name: range-val-in-closure # Warns if range value is used in a closure dispatched as goroutine
- name: receiver-naming # Conventions around the naming of receivers.
- name: redefines-builtin-id # Warns on redefinitions of builtin identifiers
#- name: string-format # Warns on specific string literals that fail one or more user-configured regular expressions
# Useless without config, have no config for it
- name: string-of-int # Warns on suspicious casts from int to string
- name: struct-tag # Checks common struct tags like `json`,`xml`,`yaml`
- name: superfluous-else # Prevents redundant else statements (extends indent-error-flow)
- name: time-equal # Suggests to use `time.Time.Equal` instead of `==` and `!=` for equality check time.
- name: time-naming # Conventions around the naming of time variables.
- name: unconditional-recursion # Warns on function calls that will lead to (direct) infinite recursion
- name: unexported-naming # Warns on wrongly named un-exported symbols
- name: unexported-return # Warns when a public return is from unexported type.
- name: unhandled-error # Warns on unhandled errors returned by funcion calls
- ;
- name: bare-return
- name: blank-imports
- name: bool-literal-in-expr
- name: call-to-gc
- name: confusing-naming
- name: confusing-results
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: deep-exit
- name: defer
- name: dot-imports
- name: duplicated-imports
- name: early-return
- name: empty-block
- name: empty-lines
- name: errorf
- name: error-naming
- name: error-return
- name: error-strings
- name: exported
arguments:
- "fmt.(Fp|P)rint(f|ln|)"
- name: unnecessary-stmt # Suggests removing or simplifying unnecessary statements
- name: unreachable-code # Warns on unreachable code
- name: unused-parameter # Suggests to rename or remove unused function parameters
- name: unused-receiver # Suggests to rename or remove unused method receivers
#- name: use-any # Proposes to replace `interface{}` with its alias `any`
# Is not (yet) available?
- name: useless-break # Warns on useless `break` statements in case clauses
- name: var-declaration # Reduces redundancies around variable declaration.
- name: var-naming # Naming rules.
- name: waitgroup-by-value # Warns on functions taking sync.WaitGroup as a by-value parameter
- sayRepetitiveInsteadOfStutters
- name: flag-parameter
- name: get-return
- name: identical-branches
- name: if-return
- name: import-shadowing
- name: increment-decrement
- name: indent-error-flow
- name: modifies-parameter
- name: modifies-value-receiver
- name: optimize-operands-order
- name: range
- name: range-val-address
- name: range-val-in-closure
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: struct-tag
- name: superfluous-else
- name: time-equal
- name: time-naming
- name: unconditional-recursion
- name: unexported-naming
- name: unexported-return
- name: unhandled-error
arguments:
- fmt.(Fp|P)rint(f|ln|)
- name: unnecessary-stmt
- name: unreachable-code
- name: unused-parameter
- name: unused-receiver
- name: useless-break
- name: var-declaration
- name: var-naming
- name: waitgroup-by-value
...
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
- gofumpt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View file

@ -1,4 +1,4 @@
FROM luzifer/archlinux as builder
FROM golang:1.25-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 AS builder
COPY . /go/src/twitch-bot
WORKDIR /go/src/twitch-bot
@ -7,13 +7,11 @@ ENV CGO_ENABLED=0 \
GOPATH=/go
RUN set -ex \
&& pacman -Syy --noconfirm \
&& apk --no-cache add \
curl \
git \
git-lfs \
go \
make \
nodejs-lts-hydrogen \
nodejs \
npm \
&& git config --global --add safe.directory /go/src/twitch-bot \
&& make node_modules frontend_prod \
@ -24,9 +22,14 @@ RUN set -ex \
-ldflags "-X main.version=$(git describe --tags --always || echo dev)"
FROM alpine:latest
FROM alpine:3.22@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1
LABEL maintainer "Knut Ahlers <knut@ahlers.me>"
LABEL org.opencontainers.image.authors="Knut Ahlers <knut@ahlers.me>" \
org.opencontainers.image.url="https://github.com/users/Luzifer/packages/container/package/twitch-bot" \
org.opencontainers.image.documentation="https://luzifer.github.io/twitch-bot/" \
org.opencontainers.image.source="https://github.com/Luzifer/twitch-bot" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.title="Self-hosted alternative to one of the big Twitch bots managed by big companies"
ENV CONFIG=/data/config.yaml \
STORAGE_CONN_STRING=/data/store.db

View file

@ -1,3 +1,99 @@
# 3.36.1 / 2025-08-16
* Bugfixes
* fix(deps): update dependency axios to v1.11.0
* fix(deps): update module github.com/getsentry/sentry-go to v0.35.1
* fix(deps): update module golang.org/x/crypto to v0.41.0
* fix(deps): update module golang.org/x/net to v0.43.0
* fix(deps): update module gorm.io/gorm to v1.30.1
* chore(deps): update dependency @babel/eslint-parser to v7.28.0
* chore(deps): update dependency esbuild to v0.25.9
* chore(deps): update dependency go to v1.25.0
* chore(deps): update mariadb docker tag to v11.8.3
* chore(deps): update mysql docker tag to v9.4.0
* chore(deps): update postgres docker tag to v17.6
# 3.36.0 / 2025-06-29
* Improvements
* Use new `channel.hype_train.*` v2 events
* Drop support for CockroachDB
* Bugfixes
* Update alpine docker tag to v3.22
* Update dependency go to v1.24.4
* Update mariadb docker tag to v11.8.2
* Update mysql Docker tag to v9.3.0
* Update postgres Docker tag to v17.5
* Update dependency axios to v1.10.0
* Update dependency @babel/eslint-parser to v7.27.5
* Update dependency esbuild to v0.25.5
* Update module github.com/getsentry/sentry-go to v0.34.0
* Update module github.com/go-git/go-git/v5 to v5.16.2
* Update module github.com/go-sql-driver/mysql to v1.9.3
* Update module github.com/Luzifer/rconfig/v2 to v2.6.0
* Update module golang.org/x/net to v0.41.0
* Update module golang.org/x/oauth2 to v0.30.0
* Update module gorm.io/driver/mysql to v1.6.0
* Update module gorm.io/driver/postgres to v1.6.0
* Update module gorm.io/gorm to v1.30.0
# 3.35.4 / 2025-04-12
* Bugfixes
* [docs] Fix: Typo in URL
* CI: Drop "stable" branch
* Update luzifer/gh-arch-env Docker digest to fd19117
* Update mariadb:11 Docker digest to 81e8930
* Update module github.com/getsentry/sentry-go to v0.32.0
* Update module github.com/go-git/go-git/v5 to v5.15.0
* Update module github.com/go-sql-driver/mysql to v1.9.2
* Update module golang.org/x/net to v0.39.0
* Update postgres:15 Docker digest to fe45ed1
# 3.35.3 / 2025-04-06
* Bugfixes
* Update Font Awesome to v6.7.2
* Update dependency go to v1.24.2
* Update module golang.org/x/crypto to v0.37.0
* Update dependency eslint-plugin-vue to v9.33.0
* Update dependency eslint to v8.57.1
* Update dependency @babel/eslint-parser to v7.27.0
* Update dependency esbuild to ^0.25.0 [SECURITY]
* CI: Switch to alpine based build image, add image labels
# 3.35.2 / 2025-04-06
* Bugfixes
* Update Go & Node dependencies
* Fix: Replace nodejs LTS version
* Lint: Migrate linter config, use local linter, fix issues
# 3.35.1 / 2024-12-12
* Bugfixes
* [core] Fix: Reduce token requirements for category search
* Update node dependencies
* Update Go dependencies
# 3.35.0 / 2024-12-02
* New Features
* [template] Add functions `parseDuration`, `parseDurationToSeconds`
* Bugfixes
* [raffle] Fix: Raffle channel did not allow underscore in channel name
# 3.34.0 / 2024-09-16
* New Features
* [marker] Implement actor to create stream markers
* [templating] Add `currentVOD` function
* Bugfixes
* [linkcheck] Fix: Replace static (deprecated) user-agent list
# 3.33.2 / 2024-08-27
* Bugfixes

View file

@ -1,55 +1,77 @@
DOCS_BASE_URL:=/
HUGO_VERSION:=0.117.0
default: lint frontend_lint test
## Tool Binaries
GO_RUN := go run -modfile ./tools/go.mod
GO_TEST = $(GO_RUN) gotest.tools/gotestsum --format pkgname
GOLANCI_LINT = golangci-lint
build_prod: frontend_prod
##@ General
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Building
build_prod: frontend_prod ## Build release binary locally
go build \
-trimpath \
-mod=readonly \
-ldflags "-X main.version=$(shell git describe --tags --always || echo dev)"
lint:
golangci-lint run
publish: frontend_prod
publish: frontend_prod ## Run build tooling to produce all binaries
bash ./ci/build.sh
short_test:
go test -cover -test.short -v ./...
##@ Development
test:
go test -cover -v ./...
lint: ## Run Linter against code
$(GOLANCI_LINT) run ./...
# --- Editor frontend
short_test: ## Run tests not depending on network
$(GO_TEST) --hide-summary skipped -- ./... -cover -short
test: ## Run all tests
$(GO_TEST) --hide-summary skipped -- ./... -cover
##@ Editor frontend
frontend_prod: export NODE_ENV=production
frontend_prod: frontend
frontend_prod: frontend ## Build frontend in production mode
frontend: node_modules
frontend: node_modules ## Build frontend
node ci/build.mjs
frontend_lint: node_modules
frontend_lint: node_modules ## Lint frontend files
./node_modules/.bin/eslint \
--ext .js,.vue \
--fix \
src
node_modules:
node_modules: ## Install node modules
npm ci --include dev
# --- Tools
##@ Tooling
update_ua_list:
# User-Agents provided by https://www.useragents.me/
curl -sSf https://www.useragents.me/api | jq -r '.data[].ua' | grep -v 'Trident' >internal/linkcheck/user-agents.txt
update-chrome-major: ## Patch latest Chrome major version into linkcheck
sed -i -E \
's/chromeMajor = [0-9]+/chromeMajor = $(shell curl -sSf https://lv.luzifer.io/v1/catalog/google-chrome/stable/version | cut -d '.' -f 1)/' \
internal/linkcheck/useragent.go
gh-workflow:
bash ci/create-workflow.sh
##@ Vulnerability scanning
# -- Vulnerability scanning --
trivy:
trivy: ## Run Trivy against the code
trivy fs . \
--dependency-tree \
--exit-code 1 \
@ -58,23 +80,23 @@ trivy:
--quiet \
--scanners misconfig,license,secret,vuln \
--severity HIGH,CRITICAL \
--skip-dirs docs
--skip-dirs docs,tools
# -- Documentation Site --
##@ Documentation
docs: actor_docs eventclient_docs template_docs
docs: actor_docs eventclient_docs template_docs ## Generate all documentation
actor_docs:
actor_docs: ## Generate actor documentation
go run . --storage-conn-string $(shell mktemp).db actor-docs >docs/content/configuration/actors.md
template_docs:
template_docs: ## Generate template function documentation
go run . --storage-conn-string $(shell mktemp).db tpl-docs >docs/content/configuration/templating.md
eventclient_docs:
eventclient_docs: ## Generate eventclient documentation
echo -e "---\ntitle: EventClient\nweight: 10000\n---\n" >docs/content/overlays/eventclient.md
docker run --rm -i -v $(CURDIR):$(CURDIR) -w $(CURDIR) node:18-alpine sh -ec 'npx --yes jsdoc-to-markdown --files ./internal/apimodules/overlays/default/eventclient.js' >>docs/content/overlays/eventclient.md
render_docs: hugo_$(HUGO_VERSION)
render_docs: hugo_$(HUGO_VERSION) ## Render documentation site
./hugo_$(HUGO_VERSION) \
--baseURL "$(DOCS_BASE_URL)" \
--cleanDestinationDir \

View file

@ -1,7 +0,0 @@
name: CI Workflow
on: push
permissions:
contents: read
jobs: {}

View file

@ -1,44 +0,0 @@
---
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
permissions:
contents: read
pages: write
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: true
show-progress: false
submodules: true
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Generate documentation
run: make render_docs DOCS_BASE_URL=https://luzifer.github.io/twitch-bot/
- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v1
with:
path: .rendered-docs
- name: Deploy artifact
uses: actions/deploy-pages@v1
...

View file

@ -1,30 +0,0 @@
---
if: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/master' }}
needs: [test]
defaults:
run:
shell: bash
permissions:
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Log into registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Publish
run: bash ci/docker-publish.sh
...

View file

@ -1,54 +0,0 @@
---
if: ${{ github.ref == 'refs/heads/master' }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
crdb:
image: luzifer/crdb-gh-service
options: >-
--health-cmd "curl -sSf http://localhost:8080/health"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
cockroachdb-bin
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Set up CRDB service
run: |
cockroach sql --host crdb --insecure <<EOF
CREATE DATABASE integration;
CREATE USER "twitch_bot" WITH PASSWORD NULL;
ALTER DATABASE integration OWNER to "twitch_bot";
EOF
- name: Run tests against CRDB
env:
GO_TEST_DB_ENGINE: postgres
GO_TEST_DB_DSN: host=crdb user=twitch_bot dbname=integration port=26257 sslmode=disable timezone=UTC
run: make short_test
...

View file

@ -1,57 +0,0 @@
---
if: ${{ github.ref == 'refs/heads/master' }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:11
env:
MYSQL_PASSWORD: twitch-bot-pass
MYSQL_ROOT_PASSWORD: root-pass
MYSQL_USER: twitch-bot
options: >-
--health-cmd "healthcheck.sh --connect --innodb_initialized"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
mariadb-clients
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Set up MariaDB service
run: |
mariadb -h mariadb -u root --password=root-pass <<EOF
CREATE DATABASE integration DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
GRANT ALL ON integration.* TO 'twitch-bot'@'%';
EOF
- name: Run tests against MariaDB
env:
GO_TEST_DB_ENGINE: mysql
GO_TEST_DB_DSN: twitch-bot:twitch-bot-pass@tcp(mariadb:3306)/integration?charset=utf8mb4&parseTime=True
run: make short_test
...

View file

@ -1,57 +0,0 @@
---
if: ${{ github.ref == 'refs/heads/master' }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8
env:
MYSQL_PASSWORD: twitch-bot-pass
MYSQL_ROOT_PASSWORD: root-pass
MYSQL_USER: twitch-bot
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Install required packages
run: |
pacman -Syy --noconfirm \
mariadb-clients
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Set up MySQL service
run: |
mariadb --skip-ssl -h mysql -u root --password=root-pass <<EOF
CREATE DATABASE integration DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
GRANT ALL ON integration.* TO 'twitch-bot'@'%';
EOF
- name: Run tests against MySQL
env:
GO_TEST_DB_ENGINE: mysql
GO_TEST_DB_DSN: twitch-bot:twitch-bot-pass@tcp(mysql:3306)/integration?charset=utf8mb4&parseTime=True
run: make short_test
...

View file

@ -1,43 +0,0 @@
---
if: ${{ github.ref == 'refs/heads/master' }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: twitch-bot-pass
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Run tests against PostgreSQL
env:
GO_TEST_DB_ENGINE: postgres
GO_TEST_DB_DSN: host=postgres user=postgres password=twitch-bot-pass dbname=postgres port=5432 sslmode=disable timezone=UTC
run: make short_test
...

View file

@ -1,49 +0,0 @@
---
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [test]
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: |
git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Build release
run: make publish
- name: Extract changelog
run: 'awk "/^#/ && ++c==2{exit}; /^#/f" "History.md" | tail -n +2 >release_changelog.md'
- name: Update stable branch
run: |
git branch -f stable ${GITHUB_SHA}
git push -f origin stable
- name: Release
uses: ncipollo/release-action@v1
with:
artifacts: '.build/*'
bodyFile: release_changelog.md
draft: false
generateReleaseNotes: false
...

View file

@ -1,35 +0,0 @@
---
if: ${{ github.ref != 'refs/heads/stable' }}
defaults:
run:
shell: bash
container:
image: luzifer/gh-arch-env
env:
CGO_ENABLED: 0
GOPATH: /go
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Marking workdir safe
run: |
git config --global --add safe.directory /__w/twitch-bot/twitch-bot
- name: Lint and test code
run: make lint test frontend_lint
- name: Build release (quick local for compile)
run: make build_prod
- name: Execute Trivy scan
run: make trivy
...

View file

@ -216,7 +216,7 @@ func writeConfigToYAML(filename, authorName, authorEmail, summary string, obj *c
}
if err = yaml.NewEncoder(tmpFile).Encode(obj); err != nil {
tmpFile.Close() //nolint:errcheck,gosec,revive
tmpFile.Close() //nolint:errcheck,gosec
return errors.Wrap(err, "encoding config")
}

View file

@ -84,6 +84,23 @@ Triggers the creation of a Clip from the given channel owned by the creator (sub
add_delay: false
```
## Create Marker
Creates a marker on the currently running stream of the given channel. The marker will be created on behalf of the channel owner and requires matching scope. (Subsequent actions can use variable `marker` to access marker details.)
```yaml
- type: marker
attributes:
# Channel to create the marker in, defaults to the channel of the event / message
# Optional: true
# Type: string (Supports Templating)
channel: ""
# Description of the marker to create (up to 140 chars)
# Optional: true
# Type: string (Supports Templating)
description: ""
```
## Custom Event
Create a custom event

View file

@ -165,6 +165,19 @@ Example:
* 1 6
```
### `currentVOD`
Returns the VOD of the currently running stream in the given channel (causes an error if no current stream / VOD is found)
Syntax: `currentVOD <username>`
Example:
```
# {{ currentVOD .channel }}
* https://www.twitch.tv/videos/123456789
```
### `displayName`
Returns the display name the specified user set for themselves
@ -379,6 +392,32 @@ Example:
< @user @user @user
```
### `parseDuration`
Parses a duration (i.e. 1h25m10s) into a time.Duration
Syntax: `parseDuration <duration>`
Example:
```
# {{ parseDuration "1h30s" }}
< 1h0m30s
```
### `parseDurationToSeconds`
Parses a duration (i.e. 1h25m10s) into a number of seconds
Syntax: `parseDurationToSeconds <duration>`
Example:
```
# {{ parseDurationToSeconds "1h25m10s" }}
< 5110
```
### `pow`
Returns float from calculation: `float1 ** float2`
@ -467,7 +506,7 @@ Example:
```
# Your int this hour: {{ printf "%.0f" (mulf (seededRandom (list "int" .username (now | date "2006-01-02 15") | join ":")) 100) }}%
< Your int this hour: 41%
< Your int this hour: 24%
```
### `spotifyCurrentPlaying`

View file

@ -116,7 +116,7 @@ SocketMessage received for every event and passed to the new `(eventObj) => { ..
| Name | Type | Description |
| --- | --- | --- |
| [event_id] | <code>Number</code> | UID of the event used to re-trigger an event |
| [event_id] | <code>String</code> | UID of the event used to re-trigger an event |
| [is_live] | <code>Boolean</code> | Whether the event was sent through a replay (false) or occurred live (true) |
| [reason] | <code>String</code> | Reason of this message (one of `bulk-replay`, `live-event`, `single-replay`) |
| [time] | <code>String</code> | RFC3339 timestamp of the event |

View file

@ -15,7 +15,7 @@ To use it
- generate an API token with the `overlays` permission and note it in a secure place
- add a Browser-Source to your OBS scenes with at least 1×1 px in size
- set the URL to `https://your-bot.example.com/overlays/sounds.html?token=[your-token]&channel=[your-channel]`
- set the URL to `https://your-bot.example.com/overlays/sounds.html#token=[your-token]&channel=[your-channel]`
After you've done this you're already done with the setup inside your OBS.

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 13 KiB

Before After
Before After

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 77 KiB

Before After
Before After

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 67 KiB

Before After
Before After

Binary file not shown.

Before

(image error) Size: 130 B

After

(image error) Size: 61 KiB

Before After
Before After

102
go.mod
View file

@ -1,77 +1,76 @@
module github.com/Luzifer/twitch-bot/v3
go 1.22
go 1.23.0
toolchain go1.22.1
toolchain go1.25.0
require (
github.com/Luzifer/go-openssl/v4 v4.2.2
github.com/Luzifer/go-openssl/v4 v4.2.4
github.com/Luzifer/go_helpers/v2 v2.25.0
github.com/Luzifer/korvike/functions v1.0.1
github.com/Luzifer/rconfig/v2 v2.5.0
github.com/getsentry/sentry-go v0.27.0
github.com/Luzifer/korvike/functions v1.0.2
github.com/Luzifer/rconfig/v2 v2.6.0
github.com/getsentry/sentry-go v0.35.1
github.com/glebarez/sqlite v1.11.0
github.com/go-git/go-git/v5 v5.12.0
github.com/go-sql-driver/mysql v1.8.1
github.com/go-git/go-git/v5 v5.16.2
github.com/go-sql-driver/mysql v1.9.3
github.com/gofrs/uuid v4.4.0+incompatible
github.com/gofrs/uuid/v3 v3.1.2
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.1
github.com/itchyny/gojq v0.12.15
github.com/gorilla/websocket v1.5.3
github.com/itchyny/gojq v0.12.17
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/orandin/sentrus v1.0.0
github.com/pkg/errors v0.9.1
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.11.0
github.com/wzshiming/openapi v0.0.0-20200703171632-c7220b3c9cfb
golang.org/x/crypto v0.23.0
golang.org/x/net v0.25.0
golang.org/x/oauth2 v0.20.0
golang.org/x/crypto v0.41.0
golang.org/x/net v0.43.0
golang.org/x/oauth2 v0.30.0
gopkg.in/irc.v4 v4.0.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.6
gorm.io/driver/postgres v1.5.7
gorm.io/gorm v1.25.10
gorm.io/driver/mysql v1.6.0
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.30.1
)
require (
dario.cat/mergo v1.0.0 // indirect
dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.6 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.6 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/hashicorp/vault/api v1.13.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
github.com/hashicorp/vault/api v1.16.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.4 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
@ -82,27 +81,26 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.11.0 // indirect
gopkg.in/validator.v2 v2.0.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.50.5 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.29.9 // indirect
modernc.org/libc v1.62.1 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.9.1 // indirect
modernc.org/sqlite v1.37.0 // indirect
)

333
go.sum
View file

@ -1,145 +1,127 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Luzifer/go-openssl/v4 v4.2.2 h1:wKF/GhSKGJtHFQYTkN61wXig7mPvDj/oPpW6MmnBpjc=
github.com/Luzifer/go-openssl/v4 v4.2.2/go.mod h1:+kAwI4NpyYXoWil85gKSCEJNoCQlMeFikEMn2f+5ffc=
github.com/Luzifer/go_helpers/v2 v2.24.0 h1:abACOhsn6a6c6X22jq42mZM1wuOM0Ihfa6yzssrjrOg=
github.com/Luzifer/go_helpers/v2 v2.24.0/go.mod h1:KSVUdAJAav5cWGyB5oKGxmC27HrKULVTOxwPS/Kr+pc=
github.com/Luzifer/go-openssl/v4 v4.2.4 h1:3Eu3gSeZpr8Ha+IofVnSWttCL1xejRr/lda4l4TZRWk=
github.com/Luzifer/go-openssl/v4 v4.2.4/go.mod h1:ykquxaR0R1Vor83/FAtGBJZZO5zswuSQTVx1FQc1bJY=
github.com/Luzifer/go_helpers/v2 v2.25.0 h1:k1J4gd1+BfuokTDoWgcgib9P5mdadjzKEgbtKSVe46k=
github.com/Luzifer/go_helpers/v2 v2.25.0/go.mod h1:KSVUdAJAav5cWGyB5oKGxmC27HrKULVTOxwPS/Kr+pc=
github.com/Luzifer/korvike/functions v1.0.1 h1:9O9PQL7O8J3nBwR4XLyx4COC430QbnvueM+itA2HEto=
github.com/Luzifer/korvike/functions v1.0.1/go.mod h1:8U01t/IM4wmZcaEf7u/szQrbLvBGMPOTLzJI/l7baWI=
github.com/Luzifer/rconfig/v2 v2.5.0 h1:zx5lfQbNX3za4VegID97IeY+M+BmfgHxWJTYA94sxok=
github.com/Luzifer/rconfig/v2 v2.5.0/go.mod h1:eGWUPQeCPv/Pr/p0hjmwFgI20uqvwi/Szen69hUzGzU=
github.com/Luzifer/korvike/functions v1.0.2 h1:Higwd9CVI03MioXYL8mttAsNBWUfAheKJx1ECaGIcAY=
github.com/Luzifer/korvike/functions v1.0.2/go.mod h1:4cNc+vPr4Ag83P5ASdk5QDnPOJLGxhbcBqj5UMVeVVs=
github.com/Luzifer/rconfig/v2 v2.6.0 h1:ZKgsO2Wt/XZXawuAZCDkW7xszxZ8hQDTV1Wm63Jvnqk=
github.com/Luzifer/rconfig/v2 v2.6.0/go.mod h1:CxISRwCV2WjO5gnUnaRGDq17u1M3TvmFgzJLr87ejtc=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid/v3 v3.1.2 h1:V3IBv1oU82x6YIr5txe3azVHgmOKYdyKQTowm9moBlY=
github.com/gofrs/uuid/v3 v3.1.2/go.mod h1:xPwMqoocQ1L5G6pXX5BcE7N5jlzn2o19oqAKxwZW/kI=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I=
github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.6 h1:TwRYfx2z2C4cLbXmT8I5PgP/xmuqASDyiVuGYfs9GZM=
github.com/hashicorp/go-retryablehttp v0.7.6/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0=
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
github.com/hashicorp/go-sockaddr v1.0.6 h1:RSG8rKU28VTUTvEKghe5gIhIQpv8evvNpnDEyqO4u9I=
github.com/hashicorp/go-sockaddr v1.0.6/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI=
github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/vault/api v1.13.0 h1:RTCGpE2Rgkn9jyPcFlc7YmNocomda44k5ck8FKMH41Y=
github.com/hashicorp/vault/api v1.13.0/go.mod h1:0cb/uZUv1w2cVu9DIvuW1SMlXXC6qtATJt+LXJRx+kg=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/itchyny/gojq v0.12.15 h1:WC1Nxbx4Ifw5U2oQWACYz32JK8G9qxNtHzrvW4KEcqI=
github.com/itchyny/gojq v0.12.15/go.mod h1:uWAHCbCIla1jiNxmeT5/B5mOjSdfkCq6p8vxWg+BM10=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=
github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg=
github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY=
github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@ -159,7 +141,6 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -168,19 +149,18 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/orandin/sentrus v1.0.0 h1:rMZKTUdwuhIaC7C6VbvhQPQeO9hBpliODrj7o/NmipM=
github.com/orandin/sentrus v1.0.0/go.mod h1:Mqa1Dcat0IcuD/XPMXUolzuZ74NWptnnX8eRq3gLaSU=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -190,123 +170,76 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/wzshiming/openapi v0.0.0-20200703171632-c7220b3c9cfb h1:G0Rrif8QdbAz7Xy53H4Xumy6TuyKHom8pu8z/jdLwwM=
github.com/wzshiming/openapi v0.0.0-20200703171632-c7220b3c9cfb/go.mod h1:398xiAftMV/w8frjipnUzjr/WQ+E2fnGRv9yXobxyyk=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
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/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@ -324,39 +257,33 @@ 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
modernc.org/cc/v4 v4.21.0 h1:D/gLKtcztomvWbsbvBKo3leKQv+86f+DdqEZBBXhnag=
modernc.org/cc/v4 v4.21.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.17.2 h1:rg8qg9Rxq7AtL29N0Ar5LyNmH/fQGV0LhphfcTJ5zRQ=
modernc.org/ccgo/v4 v4.17.2/go.mod h1:1FCbAtWYJoKuc+AviS+dH+vGNtYmFJqBeRWjmnDWsIg=
modernc.org/ccgo/v4 v4.17.3 h1:t2CQci84jnxKw3GGnHvjGKjiNZeZqyQx/023spkk4hU=
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.30.1 h1:lSHg33jJTBxs2mgJRfRZeLDG+WZaHYCk3Wtfl6Ngzo4=
gorm.io/gorm v1.30.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/libc v1.50.3 h1:rxS4sOeGFzwiuDShZh0agxIRJnan/8vLsBomE50+OT4=
modernc.org/libc v1.50.3/go.mod h1:ZkNjeLQOsIbpUQhrp7H6dQVuxXPsCZKjTb0/nE/jQjU=
modernc.org/libc v1.50.5 h1:ZzeUd0dIc/sUtoPTCYIrgypkuzoGzNu6kbEWj2VuEmk=
modernc.org/libc v1.50.5/go.mod h1:rhzrUx5oePTSTIzBgM0mTftwWHK8tiT9aNFUt1mldl0=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.29.8 h1:nGKglNx9K5v0As+zF0/Gcl1kMkmaU1XynYyq92PbsC8=
modernc.org/sqlite v1.29.8/go.mod h1:lQPm27iqa4UNZpmr4Aor0MH0HkCLbt1huYDfWylLZFk=
modernc.org/sqlite v1.29.9 h1:9RhNMklxJs+1596GNuAX+O/6040bvOwacTxuFcRuQow=
modernc.org/sqlite v1.29.9/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View file

@ -0,0 +1,114 @@
// Package marker contains an actor to create markers on the current
// running stream
package marker
import (
"context"
"fmt"
"strings"
"github.com/Luzifer/go_helpers/v2/fieldcollection"
"github.com/Luzifer/twitch-bot/v3/internal/helpers"
"github.com/Luzifer/twitch-bot/v3/pkg/twitch"
"github.com/Luzifer/twitch-bot/v3/plugins"
"gopkg.in/irc.v4"
)
const actorName = "marker"
var (
formatMessage plugins.MsgFormatter
hasPerm plugins.ChannelPermissionCheckFunc
tcGetter func(string) (*twitch.Client, error)
)
// Register provides the plugins.RegisterFunc
func Register(args plugins.RegistrationArguments) error {
formatMessage = args.FormatMessage
hasPerm = args.HasPermissionForChannel
tcGetter = args.GetTwitchClientForChannel
args.RegisterActor(actorName, func() plugins.Actor { return &actor{} })
args.RegisterActorDocumentation(plugins.ActionDocumentation{
Description: "Creates a marker on the currently running stream of the given channel. The marker will be created on behalf of the channel owner and requires matching scope. (Subsequent actions can use variable `marker` to access marker details.)",
Name: "Create Marker",
Type: actorName,
Fields: []plugins.ActionDocumentationField{
{
Description: "Channel to create the marker in, defaults to the channel of the event / message",
Key: "channel",
Name: "Channel",
Optional: true,
SupportTemplate: true,
Type: plugins.ActionDocumentationFieldTypeString,
},
{
Description: "Description of the marker to create (up to 140 chars)",
Key: "description",
Name: "Description",
Optional: true,
SupportTemplate: true,
Type: plugins.ActionDocumentationFieldTypeString,
},
},
})
return nil
}
type actor struct{}
func (actor) Execute(_ *irc.Client, m *irc.Message, r *plugins.Rule, eventData *fieldcollection.FieldCollection, attrs *fieldcollection.FieldCollection) (preventCooldown bool, err error) {
channel := plugins.DeriveChannel(m, eventData)
if channel, err = formatMessage(attrs.MustString("channel", &channel), m, r, eventData); err != nil {
return false, fmt.Errorf("parsing channel: %w", err)
}
var description string
if description, err = formatMessage(attrs.MustString("description", &description), m, r, eventData); err != nil {
return false, fmt.Errorf("parsing description: %w", err)
}
channel = strings.TrimLeft(channel, "#")
canCreate, err := hasPerm(channel, twitch.ScopeChannelManageBroadcast)
if err != nil {
return false, fmt.Errorf("checking for required permission: %w", err)
}
if !canCreate {
return false, fmt.Errorf("creator has not given %s permission", twitch.ScopeChannelManageBroadcast)
}
tc, err := tcGetter(channel)
if err != nil {
return false, fmt.Errorf("getting Twitch client for %q: %w", channel, err)
}
var marker twitch.StreamMarkerInfo
if marker, err = tc.CreateStreamMarker(context.TODO(), description); err != nil {
return false, fmt.Errorf("creating marker: %w", err)
}
eventData.Set("marker", marker)
return false, nil
}
func (actor) IsAsync() bool { return false }
func (actor) Name() string { return actorName }
func (actor) Validate(tplValidator plugins.TemplateValidatorFunc, attrs *fieldcollection.FieldCollection) (err error) {
if err = attrs.ValidateSchema(
fieldcollection.CanHaveField(fieldcollection.SchemaField{Name: "channel", NonEmpty: true, Type: fieldcollection.SchemaFieldTypeString}),
fieldcollection.CanHaveField(fieldcollection.SchemaField{Name: "description", NonEmpty: true, Type: fieldcollection.SchemaFieldTypeString}),
fieldcollection.MustHaveNoUnknowFields,
helpers.SchemaValidateTemplateField(tplValidator, "channel", "description"),
); err != nil {
return fmt.Errorf("validating attributes: %w", err)
}
return nil
}

View file

@ -85,11 +85,11 @@ func getQuote(db database.Connector, channel string, quote int) (int, string, er
func getQuoteRaw(db database.Connector, channel string, quoteIdx int) (int, int64, string, error) {
if quoteIdx == 0 {
max, err := getMaxQuoteIdx(db, channel)
maxQuoteIdx, err := getMaxQuoteIdx(db, channel)
if err != nil {
return 0, 0, "", errors.Wrap(err, "getting max quote idx")
}
quoteIdx = rand.Intn(max) + 1 // #nosec G404 // no need for cryptographic safety
quoteIdx = rand.Intn(maxQuoteIdx) + 1 // #nosec G404 // no need for cryptographic safety
}
var q quote

View file

@ -181,7 +181,7 @@ func handleDeleteQuote(w http.ResponseWriter, r *http.Request) {
func handleListQuotes(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.Header.Get("Accept"), "text/html") {
w.Header().Set("Content-Type", "text/html")
w.Write(listFrontend) //nolint:errcheck,gosec,revive
w.Write(listFrontend) //nolint:errcheck,gosec
return
}
@ -218,7 +218,7 @@ func handleReplaceQuotes(w http.ResponseWriter, r *http.Request) {
func handleScript(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/javascript")
w.Write(listScript) //nolint:errcheck,gosec,revive
w.Write(listScript) //nolint:errcheck,gosec
}
func handleUpdateQuote(w http.ResponseWriter, r *http.Request) {

View file

@ -18,23 +18,23 @@ func testGenerateRaffe() raffle {
}
// Now lets generate 132 non-followers taking part
for i := 0; i < 132; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: uint64(i), Multiplier: 1})
for i := uint64(0); i < 132; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: i, Multiplier: 1})
}
// Now lets generate 500 followers taking part
for i := 0; i < 500; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 10000 + uint64(i), Multiplier: r.MultiFollower})
for i := uint64(0); i < 500; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 10000 + i, Multiplier: r.MultiFollower})
}
// Now lets generate 200 subscribers taking part
for i := 0; i < 200; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 20000 + uint64(i), Multiplier: r.MultiSubscriber})
for i := uint64(0); i < 200; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 20000 + i, Multiplier: r.MultiSubscriber})
}
// Now lets generate 5 VIPs taking part
for i := 0; i < 5; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 30000 + uint64(i), Multiplier: r.MultiVIP})
for i := uint64(0); i < 5; i++ {
r.Entries = append(r.Entries, raffleEntry{ID: 30000 + i, Multiplier: r.MultiVIP})
}
// They didn't join in order so lets shuffle them

View file

@ -57,13 +57,12 @@ func TestScanForLinks(t *testing.T) {
t.SkipNow()
}
c := New()
for _, testCase := range []struct {
Heuristic bool
Message string
ExpectedLinks []string
ExpectedContains bool
TraceStack bool
}{
// Case: full URL is present in the message
{
@ -162,7 +161,7 @@ func TestScanForLinks(t *testing.T) {
{
Heuristic: true,
Message: "Hey btw. es kann sein, dass",
ExpectedLinks: []string{"https://trusted.evo-media.eu/btw.es"},
ExpectedLinks: []string{"https://trusted.domainseller.site/btw.es"},
},
// Case: Multiple spaces in the link
{
@ -183,6 +182,13 @@ func TestScanForLinks(t *testing.T) {
{Heuristic: false, Message: "Hey btw. es kann sein, dass", ExpectedLinks: nil},
} {
t.Run(fmt.Sprintf("h:%v lc:%d m:%s", testCase.Heuristic, len(testCase.ExpectedLinks), testCase.Message), func(t *testing.T) {
var c *Checker
if testCase.TraceStack {
c = New(withResolver(newResolver(resolverPoolSize, withTesting(t))))
} else {
c = New()
}
var linksFound []string
if testCase.Heuristic {
linksFound = c.HeuristicScanForLinks(testCase.Message)
@ -209,23 +215,3 @@ func TestScanForLinks(t *testing.T) {
})
}
}
func TestUserAgentListNotEmpty(t *testing.T) {
if len(defaultUserAgents) == 0 {
t.Fatal("found empty user-agent list")
}
}
func TestUserAgentRandomizer(t *testing.T) {
uas := map[string]int{}
for i := 0; i < 10; i++ {
uas[defaultResolver.userAgent()]++
}
for _, c := range uas {
assert.Less(t, c, 10)
}
assert.Equal(t, 0, uas[""]) // there should be no empty UA
}

View file

@ -2,16 +2,14 @@ package linkcheck
import (
"context"
"crypto/rand"
_ "embed"
"io"
"math/big"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
"sync"
"testing"
"time"
"github.com/sirupsen/logrus"
@ -30,6 +28,8 @@ type (
resolver struct {
resolverC chan resolverQueueEntry
skipValidation bool
t *testing.T
}
resolverQueueEntry struct {
@ -40,20 +40,12 @@ type (
)
var (
defaultUserAgents = []string{}
linkTest = regexp.MustCompile(`(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]`)
numericHost = regexp.MustCompile(`^(?:[0-9]+\.)*[0-9]+(?::[0-9]+)?$`)
//go:embed user-agents.txt
uaList string
defaultResolver = newResolver(resolverPoolSize)
)
func init() {
defaultUserAgents = strings.Split(strings.TrimSpace(uaList), "\n")
}
func newResolver(poolSize int, opts ...func(*resolver)) *resolver {
r := &resolver{
resolverC: make(chan resolverQueueEntry),
@ -74,6 +66,10 @@ func withSkipVerify() func(*resolver) {
return func(r *resolver) { r.skipValidation = true }
}
func withTesting(t *testing.T) func(*resolver) {
return func(r *resolver) { r.t = t }
}
func (r resolver) Resolve(qe resolverQueueEntry) {
qe.WaitGroup.Add(1)
r.resolverC <- qe
@ -88,7 +84,7 @@ func (resolver) getJar() *cookiejar.Jar {
// that link after all redirects were followed
//
//nolint:gocyclo
func (r resolver) resolveFinal(link string, cookieJar *cookiejar.Jar, callStack *stack, userAgent string) string {
func (r resolver) resolveFinal(link string, cookieJar *cookiejar.Jar, callStack *stack) string {
if !linkTest.MatchString(link) && !r.skipValidation {
return ""
}
@ -131,12 +127,19 @@ func (r resolver) resolveFinal(link string, cookieJar *cookiejar.Jar, callStack
// Sanitize host: Trailing dots are valid but not required
u.Host = strings.TrimRight(u.Host, ".")
if r.t != nil {
r.t.Logf("resolving link: link=%q jar_c=%#v stack_c=%d stack_h=%d",
link, len(cookieJar.Cookies(u)), callStack.Count(link), callStack.Height())
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil {
return ""
}
req.Header.Set("User-Agent", userAgent)
for k, v := range generateUserAgentHeaders() {
req.Header.Set(k, v)
}
resp, err := client.Do(req)
if err != nil {
@ -156,7 +159,7 @@ func (r resolver) resolveFinal(link string, cookieJar *cookiejar.Jar, callStack
}
target := r.resolveReference(u, tu)
callStack.Visit(link)
return r.resolveFinal(target, cookieJar, callStack, userAgent)
return r.resolveFinal(target, cookieJar, callStack)
}
// We got a response, it's no redirect, lets check for in-document stuff
@ -173,14 +176,14 @@ func (r resolver) resolveFinal(link string, cookieJar *cookiejar.Jar, callStack
}
target := r.resolveReference(u, tu)
callStack.Visit(link)
return r.resolveFinal(target, cookieJar, callStack, userAgent)
return r.resolveFinal(target, cookieJar, callStack)
}
if resp.Header.Get("Set-Cookie") != "" {
// A new cookie was set, lets refresh the page once to see if stuff
// changes with that new cookie
callStack.Visit(link)
return r.resolveFinal(u.String(), cookieJar, callStack, userAgent)
return r.resolveFinal(u.String(), cookieJar, callStack)
}
// We had no in-document redirects: we count this as a success
@ -226,14 +229,9 @@ func (resolver) resolveReference(origin *url.URL, loc *url.URL) string {
func (r resolver) runResolver() {
for qe := range r.resolverC {
if link := r.resolveFinal(qe.Link, r.getJar(), &stack{}, r.userAgent()); link != "" {
if link := r.resolveFinal(qe.Link, r.getJar(), &stack{}); link != "" {
qe.Callback(link)
}
qe.WaitGroup.Done()
}
}
func (resolver) userAgent() string {
n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(defaultUserAgents))))
return defaultUserAgents[n.Int64()]
}

View file

@ -1,43 +0,0 @@
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/95.0.0.0
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.41
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.56
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.1264.37
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Whale/3.19.166.16 Safari/537.36
Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76
Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.46
Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.192.400 QQBrowser/11.5.5250.400
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.78
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/95.0.0.0
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763
Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.61
Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/110.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70

View file

@ -0,0 +1,38 @@
package linkcheck
import (
"fmt"
)
const (
chromeMajor = 128
webkitMajor = 537
webkitMinor = 36
)
// generateUserAgent resembles the Chrome user agent generation as
// closely as possible in order to blend into the crowd of browsers
//
// https://github.com/chromium/chromium/blob/58e23d958ee8d2bb4b085c843a18eb28b9da17da/content/common/user_agent.cc
func generateUserAgentHeaders() map[string]string {
return map[string]string{
// New UA hints method
"Sec-CH-UA": fmt.Sprintf(
`"Chromium";v="%[1]d", "Not;A=Brand";v="24", "Google Chrome";v="%[1]d"`,
chromeMajor,
),
// Not a mobile browser
"Sec-CH-UA-Mobile": "?0",
// We're always Windows
"Sec-CH-UA-Platform": "Windows",
// "old" user-agent
"User-Agent": fmt.Sprintf(
"Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) %s Safari/537.36",
"Windows NT 10.0; Win64; x64", // We're always Windows 10 / 11 on x64
fmt.Sprintf("Chrome/%d.0.0.0", chromeMajor), // UA-Reduction enabled
),
}
}

View file

@ -2,6 +2,9 @@
package date
import (
"fmt"
"time"
"github.com/Luzifer/twitch-bot/v3/plugins"
)
@ -27,5 +30,37 @@ func Register(args plugins.RegistrationArguments) error {
},
})
args.RegisterTemplateFunction("parseDuration", plugins.GenericTemplateFunctionGetter(func(duration string) (time.Duration, error) {
d, err := time.ParseDuration(duration)
if err != nil {
return 0, fmt.Errorf("parsing duration: %w", err)
}
return d, nil
}), plugins.TemplateFuncDocumentation{
Description: `Parses a duration (i.e. 1h25m10s) into a time.Duration`,
Syntax: "parseDuration <duration>",
Example: &plugins.TemplateFuncDocumentationExample{
Template: `{{ parseDuration "1h30s" }}`,
ExpectedOutput: "1h0m30s",
},
})
args.RegisterTemplateFunction("parseDurationToSeconds", plugins.GenericTemplateFunctionGetter(func(duration string) (int64, error) {
d, err := time.ParseDuration(duration)
if err != nil {
return 0, fmt.Errorf("parsing duration: %w", err)
}
return int64(d / time.Second), nil
}), plugins.TemplateFuncDocumentation{
Description: `Parses a duration (i.e. 1h25m10s) into a number of seconds`,
Syntax: "parseDurationToSeconds <duration>",
Example: &plugins.TemplateFuncDocumentationExample{
Template: `{{ parseDurationToSeconds "1h25m10s" }}`,
ExpectedOutput: "5110",
},
})
return nil
}

View file

@ -13,7 +13,6 @@ import (
//go:embed tzdata
var tzDataEuropeBerlin []byte
//nolint:funlen // This is just a collection of test cases
func TestNewInterval(t *testing.T) {
tz, err := time.LoadLocationFromTZData("Europe/Berlin", tzDataEuropeBerlin)
require.NoError(t, err)

View file

@ -0,0 +1,50 @@
package twitch
import (
"context"
"fmt"
"strings"
"github.com/Luzifer/twitch-bot/v3/pkg/twitch"
"github.com/Luzifer/twitch-bot/v3/plugins"
)
func init() {
regFn = append(
regFn,
tplTwitchCurrentVOD,
)
}
func tplTwitchCurrentVOD(args plugins.RegistrationArguments) {
args.RegisterTemplateFunction("currentVOD", plugins.GenericTemplateFunctionGetter(func(username string) (string, error) {
si, err := args.GetTwitchClient().GetCurrentStreamInfo(context.Background(), strings.TrimLeft(username, "#"))
if err != nil {
return "", fmt.Errorf("getting stream info: %w", err)
}
vids, err := args.GetTwitchClient().GetVideos(context.TODO(), twitch.GetVideoOpts{
UserID: si.UserID,
})
if err != nil {
return "", fmt.Errorf("getting videos: %w", err)
}
for _, v := range vids {
if v.StreamID == nil || *v.StreamID != si.ID {
continue
}
return v.URL, nil
}
return "", fmt.Errorf("no matching VOD found")
}), plugins.TemplateFuncDocumentation{
Description: "Returns the VOD of the currently running stream in the given channel (causes an error if no current stream / VOD is found)",
Syntax: "currentVOD <username>",
Example: &plugins.TemplateFuncDocumentationExample{
Template: `{{ currentVOD .channel }}`,
FakedOutput: "https://www.twitch.tv/videos/123456789",
},
})
}

2
irc.go
View file

@ -63,7 +63,7 @@ func newIRCHandler() (*ircHandler, error) {
h.ctx, h.ctxCancelFn = context.WithCancel(context.Background())
conn, err := tls.Dial("tcp", "irc.chat.twitch.tv:6697", nil)
conn, err := tls.Dial("tcp", "irc.chat.twitch.tv:6697", nil) //nolint:noctx // Would use background context
if err != nil {
return nil, errors.Wrap(err, "connect to IRC server")
}

View file

@ -265,7 +265,7 @@ func main() {
if config.HTTPListen != "" {
// If listen address is configured start HTTP server
listener, err := net.Listen("tcp", config.HTTPListen)
listener, err := net.Listen("tcp", config.HTTPListen) //nolint:noctx // Would use background context
if err != nil {
log.WithError(err).Fatal("Unable to open http_listen port")
}

1597
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,24 @@
{
"devDependencies": {
"@babel/eslint-parser": "^7.21.3",
"esbuild": "^0.17.13",
"esbuild-vue": "^1.2.2",
"eslint": "^8.36.0",
"eslint-plugin-vue": "^9.10.0",
"vue-template-compiler": "^2.7.14"
"@babel/eslint-parser": "7.28.0",
"esbuild": "0.25.9",
"esbuild-vue": "1.2.2",
"eslint": "8.57.1",
"eslint-plugin-vue": "9.33.0",
"vue-template-compiler": "2.7.16"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/vue-fontawesome": "^2.0.10",
"axios": "^1.3.4",
"bootstrap": "^4.6.2",
"bootstrap-vue": "^2.23.1",
"bootswatch": "^4.6.2",
"codejar": "^3.7.0",
"prismjs": "^1.29.0",
"vue": "^2.7.16",
"vue-router": "^3.6.5"
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-brands-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/vue-fontawesome": "2.0.10",
"axios": "1.11.0",
"bootstrap": "4.6.2",
"bootstrap-vue": "2.23.1",
"bootswatch": "4.6.2",
"codejar": "3.7.0",
"prismjs": "1.30.0",
"vue": "2.7.16",
"vue-router": "3.6.5"
}
}

View file

@ -127,7 +127,6 @@ type (
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
BroadcasterUserName string `json:"broadcaster_user_name"`
Level int64 `json:"level"`
Total int64 `json:"total"`
Progress int64 `json:"progress"` // Only Beginn, Progress
Goal int64 `json:"goal"` // Only Beginn, Progress
@ -138,17 +137,22 @@ type (
Type string `json:"type"`
Total int64 `json:"total"`
} `json:"top_contributions"`
LastContribution *struct { // Only Begin, Progress
UserID string `json:"user_id"`
UserLogin string `json:"user_login"`
UserName string `json:"user_name"`
Type string `json:"type"`
Total int64 `json:"total"`
} `json:"last_contribution,omitempty"`
Level int64 `json:"level"`
AllTimeHighLevel int64 `json:"all_time_high_level"` // Only Begin
AllTimeHighTotal int64 `json:"all_time_high_total"` // Only Begin
StartedAt time.Time `json:"started_at"`
CooldownEndsAt *time.Time `json:"cooldown_ends_at,omitempty"` // Only End
ExpiresAt *time.Time `json:"expires_at,omitempty"` // Only Begin, Progress
EndedAt *time.Time `json:"ended_at,omitempty"` // Only End
CooldownEndsAt *time.Time `json:"cooldown_ends_at,omitempty"` // Only End
Type string `json:"type"` // treasure, golden_kappa, regular
// Feature: Shared Trains, all events
IsSharedTrain bool `json:"is_shared_train"`
SharedTrainParticipants []struct {
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
BroadcasterUserName string `json:"broadcaster_user_name"`
} `json:"shared_train_participants"`
}
// EventSubEventPoll contains the payload for a poll change event

View file

@ -36,7 +36,7 @@ func (c *Client) SearchCategories(ctx context.Context, name string) ([]Category,
for {
if err := c.Request(ctx, ClientRequestOpts{
AuthType: AuthTypeBearerToken,
AuthType: AuthTypeAppAccessToken,
Method: http.MethodGet,
OKStatus: http.StatusOK,
Out: &resp,

View file

@ -1,7 +1,9 @@
package twitch
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
@ -27,12 +29,59 @@ type (
TagIds []string `json:"tag_ids"` //revive:disable-line:var-naming // Disabled to prevent breaking change
IsMature bool `json:"is_mature"`
}
// StreamMarkerInfo contains information about a marker on a stream
StreamMarkerInfo struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
Description string `json:"description"`
PositionSeconds int64 `json:"position_seconds"`
}
)
// ErrNoStreamsFound allows to differntiate between an HTTP error and
// the fact there just is no stream found
var ErrNoStreamsFound = errors.New("no streams found")
// CreateStreamMarker creates a marker for the currently running stream.
// The stream must be live, no VoD, no upload and no re-run.
// The description may be up to 140 chars and can be omitted.
func (c *Client) CreateStreamMarker(ctx context.Context, description string) (marker StreamMarkerInfo, err error) {
body := new(bytes.Buffer)
userID, _, err := c.GetAuthorizedUser(ctx)
if err != nil {
return marker, fmt.Errorf("getting ID for current user: %w", err)
}
if err = json.NewEncoder(body).Encode(struct {
UserID string `json:"user_id"`
Description string `json:"description,omitempty"`
}{
UserID: userID,
Description: description,
}); err != nil {
return marker, fmt.Errorf("encoding payload: %w", err)
}
var payload struct {
Data []StreamMarkerInfo `json:"data"`
}
if err := c.Request(ctx, ClientRequestOpts{
AuthType: AuthTypeBearerToken,
Body: body,
Method: http.MethodPost,
OKStatus: http.StatusOK,
Out: &payload,
URL: "https://api.twitch.tv/helix/streams/markers",
}); err != nil {
return marker, fmt.Errorf("creating marker: %w", err)
}
return payload.Data[0], nil
}
// GetCurrentStreamInfo returns the StreamInfo of the currently running
// stream of the given username
func (c *Client) GetCurrentStreamInfo(ctx context.Context, username string) (*StreamInfo, error) {

150
pkg/twitch/videos.go Normal file
View file

@ -0,0 +1,150 @@
package twitch
import (
"context"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"github.com/mitchellh/hashstructure/v2"
)
type (
// GetVideoOpts contain the query parameter for the GetVideos query
//
// See https://dev.twitch.tv/docs/api/reference/#get-videos for details
GetVideoOpts struct {
ID string // Required: Exactly one of ID, UserID, GameID
UserID string // Required: Exactly one of ID, UserID, GameID
GameID string // Required: Exactly one of ID, UserID, GameID
Language string // Optional: Use only with GameID
Period GetVideoOptsPeriod // Optional: Use only with GameID or UserID
Sort GetVideoOptsSort // Optional: Use only with GameID or UserID
Type GetVideoOptsType // Optional: Use only with GameID or UserID
First int64 // Optional: Use only with GameID or UserID
After string // Optional: Use only with UserID
Before string // Optional: Use only with UserID
}
// GetVideoOptsPeriod represents a filter used to filter the list of
// videos by when they were published
GetVideoOptsPeriod string
// GetVideoOptsSort represents the order to sort the returned videos in
GetVideoOptsSort string
// GetVideoOptsType represents a filter used to filter the list of
// videos by the video's type
GetVideoOptsType string
// Video contains information about a published video
Video struct {
ID string `json:"id"`
StreamID *string `json:"stream_id"`
UserID string `json:"user_id"`
UserLogin string `json:"user_login"`
UserName string `json:"user_name"`
Title string `json:"title"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
URL string `json:"url"`
ThumbnailURL string `json:"thumbnail_url"`
Viewable string `json:"viewable"`
ViewCount int64 `json:"view_count"`
Language string `json:"language"`
Type string `json:"type"`
Duration string `json:"duration"`
MutedSegments []struct {
Duration int64 `json:"duration"`
Offset int64 `json:"offset"`
} `json:"muted_segments"`
}
)
// List of filters for GetVideoOpts.Period
const (
GetVideoOptsPeriodAll GetVideoOptsPeriod = "all"
GetVideoOptsPeriodDay GetVideoOptsPeriod = "day"
GetVideoOptsPeriodMonth GetVideoOptsPeriod = "month"
GetVideoOptsPeriodWeek GetVideoOptsPeriod = "week"
)
// List of sort options for GetVideoOpts.Sort
const (
GetVideoOptsSortTime GetVideoOptsSort = "time"
GetVideoOptsSortTrending GetVideoOptsSort = "trending"
GetVideoOptsSortViews GetVideoOptsSort = "views"
)
// List of types for GetVideoOpts.Type
const (
GetVideoOptsTypeAll GetVideoOptsType = "all"
GetVideoOptsTypeArchive GetVideoOptsType = "archive"
GetVideoOptsTypeHighlight GetVideoOptsType = "highlight"
GetVideoOptsTypeUpload GetVideoOptsType = "upload"
)
// GetVideos fetches information about one or more published videos
func (c *Client) GetVideos(ctx context.Context, opts GetVideoOpts) (videos []Video, err error) {
optsCacheKey, err := opts.cacheKey()
if err != nil {
return nil, fmt.Errorf("getting opts cache key: %w", err)
}
cacheKey := []string{"currentVideos", optsCacheKey}
if vids := c.apiCache.Get(cacheKey); vids != nil {
return vids.([]Video), nil
}
var payload struct {
Data []Video `json:"data"`
}
if err := c.Request(ctx, ClientRequestOpts{
AuthType: AuthTypeAppAccessToken,
Method: http.MethodGet,
OKStatus: http.StatusOK,
Out: &payload,
URL: fmt.Sprintf("https://api.twitch.tv/helix/videos?%s", opts.queryParams()),
}); err != nil {
return nil, fmt.Errorf("requesting videos: %w", err)
}
// Videos can be changed at any moment, cache for a short period of time
c.apiCache.Set(cacheKey, twitchMinCacheTime, payload.Data)
return payload.Data, nil
}
func (g GetVideoOpts) cacheKey() (string, error) {
h, err := hashstructure.Hash(g, hashstructure.FormatV2, nil)
if err != nil {
return "", fmt.Errorf("hashing opts: %w", err)
}
return strconv.FormatUint(h, 10), nil
}
func (g GetVideoOpts) queryParams() string {
params := url.Values{}
for k, v := range map[string]string{
"id": g.ID,
"user_id": g.UserID,
"game_id": g.GameID,
"language": g.Language,
"period": string(g.Period),
"sort": string(g.Sort),
"type": string(g.Type),
"first": strconv.FormatInt(g.First, 10),
"after": g.After,
"before": g.Before,
} {
if v != "" && v != "0" {
params.Set(k, v)
}
}
return params.Encode()
}

View file

@ -25,6 +25,7 @@ import (
"github.com/Luzifer/twitch-bot/v3/internal/actors/linkdetector"
"github.com/Luzifer/twitch-bot/v3/internal/actors/linkprotect"
logActor "github.com/Luzifer/twitch-bot/v3/internal/actors/log"
"github.com/Luzifer/twitch-bot/v3/internal/actors/marker"
"github.com/Luzifer/twitch-bot/v3/internal/actors/messagehook"
"github.com/Luzifer/twitch-bot/v3/internal/actors/modchannel"
"github.com/Luzifer/twitch-bot/v3/internal/actors/nuke"
@ -78,6 +79,7 @@ var (
linkdetector.Register,
linkprotect.Register,
logActor.Register,
marker.Register,
messagehook.Register,
modchannel.Register,
nuke.Register,

16
renovate.json Normal file
View file

@ -0,0 +1,16 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"https://git.luzifer.io/luzifer/renovate-config/raw/branch/master/default.json"
],
"packageRules": [
{
"matchFileNames": [
"(^|/).github/workflows/.*"
],
"schedule": [
"* 21 * * 0"
]
}
]
}

View file

@ -5,7 +5,7 @@ import "github.com/Luzifer/twitch-bot/v3/pkg/twitch"
var (
channelExtendedScopes = map[string]string{
twitch.ScopeChannelEditCommercial: "run commercial",
twitch.ScopeChannelManageBroadcast: "modify category / title",
twitch.ScopeChannelManageBroadcast: "modify category / title, create markers",
twitch.ScopeChannelManagePolls: "manage polls",
twitch.ScopeChannelManagePredictions: "manage predictions",
twitch.ScopeChannelManageRaids: "start raids",

View file

@ -1127,7 +1127,7 @@ export default {
},
validateRaffleChannel() {
if (!/^[a-zA-Z0-9]{4,25}$/.test(this.models.raffle.channel)) {
if (!constants.REGEXP_USER.test(this.models.raffle.channel)) {
return false
}
return null

22
tools/go.mod Normal file
View file

@ -0,0 +1,22 @@
module tools
go 1.23.1
require gotest.tools/gotestsum v1.12.3
require (
github.com/bitfield/gotestdox v0.2.2 // indirect
github.com/dnephin/pflag v1.0.7 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/tools v0.34.0 // indirect
)

35
tools/go.sum Normal file
View file

@ -0,0 +1,35 @@
github.com/bitfield/gotestdox v0.2.2 h1:x6RcPAbBbErKLnapz1QeAlf3ospg8efBsedU93CDsnE=
github.com/bitfield/gotestdox v0.2.2/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY=
github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
gotest.tools/gotestsum v1.12.3 h1:jFwenGJ0RnPkuKh2VzAYl1mDOJgbhobBDeL2W1iEycs=
gotest.tools/gotestsum v1.12.3/go.mod h1:Y1+e0Iig4xIRtdmYbEV7K7H6spnjc1fX4BOuUhWw2Wk=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=

7
tools/tools.go Normal file
View file

@ -0,0 +1,7 @@
//go:build tools
package tools
import (
_ "gotest.tools/gotestsum"
)

View file

@ -133,7 +133,7 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
},
{
Topic: twitch.EventSubEventTypeChannelHypetrainBegin,
Version: twitch.EventSubTopicVersion1,
Version: twitch.EventSubTopicVersion2,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainBegin),
@ -141,7 +141,7 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
},
{
Topic: twitch.EventSubEventTypeChannelHypetrainEnd,
Version: twitch.EventSubTopicVersion1,
Version: twitch.EventSubTopicVersion2,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainEnd),
@ -149,7 +149,7 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
},
{
Topic: twitch.EventSubEventTypeChannelHypetrainProgress,
Version: twitch.EventSubTopicVersion1,
Version: twitch.EventSubTopicVersion2,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainProgress),