Compare commits
	
		
			2 Commits
		
	
	
		
			f7924261de
			...
			2dd919a08f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2dd919a08f | |||
| 59da01b0e5 | 
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -25,3 +25,8 @@ go.work.sum
 | 
				
			|||||||
# env file
 | 
					# env file
 | 
				
			||||||
.env
 | 
					.env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# config files
 | 
				
			||||||
 | 
					*.cue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# database
 | 
				
			||||||
 | 
					data.db
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								go.mod
									
									
									
									
									
								
							@ -3,19 +3,28 @@ module dev.justinjudd.com/discord_bots
 | 
				
			|||||||
go 1.24.1
 | 
					go 1.24.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/bwmarrin/discordgo v0.29.0 // indirect
 | 
						cuelang.org/go v0.13.2
 | 
				
			||||||
 | 
						github.com/bwmarrin/discordgo v0.29.0
 | 
				
			||||||
 | 
						github.com/joho/godotenv v1.5.1
 | 
				
			||||||
 | 
						modernc.org/sqlite v1.38.0
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require (
 | 
				
			||||||
 | 
						github.com/cockroachdb/apd/v3 v3.2.1 // indirect
 | 
				
			||||||
	github.com/dustin/go-humanize v1.0.1 // indirect
 | 
						github.com/dustin/go-humanize v1.0.1 // indirect
 | 
				
			||||||
	github.com/google/uuid v1.6.0 // indirect
 | 
						github.com/google/uuid v1.6.0 // indirect
 | 
				
			||||||
	github.com/gorilla/websocket v1.4.2 // indirect
 | 
						github.com/gorilla/websocket v1.4.2 // indirect
 | 
				
			||||||
	github.com/joho/godotenv v1.5.1 // indirect
 | 
					 | 
				
			||||||
	github.com/mattn/go-isatty v0.0.20 // indirect
 | 
						github.com/mattn/go-isatty v0.0.20 // indirect
 | 
				
			||||||
	github.com/ncruces/go-strftime v0.1.9 // indirect
 | 
						github.com/ncruces/go-strftime v0.1.9 // indirect
 | 
				
			||||||
 | 
						github.com/pelletier/go-toml/v2 v2.2.4 // indirect
 | 
				
			||||||
	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 | 
						github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
 | 
						golang.org/x/crypto v0.37.0 // indirect
 | 
				
			||||||
	golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
 | 
						golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/net v0.39.0 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.33.0 // indirect
 | 
						golang.org/x/sys v0.33.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/text v0.24.0 // indirect
 | 
				
			||||||
 | 
						gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
				
			||||||
	modernc.org/libc v1.65.10 // indirect
 | 
						modernc.org/libc v1.65.10 // indirect
 | 
				
			||||||
	modernc.org/mathutil v1.7.1 // indirect
 | 
						modernc.org/mathutil v1.7.1 // indirect
 | 
				
			||||||
	modernc.org/memory v1.11.0 // indirect
 | 
						modernc.org/memory v1.11.0 // indirect
 | 
				
			||||||
	modernc.org/sqlite v1.38.0 // indirect
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										69
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								go.sum
									
									
									
									
									
								
							@ -1,37 +1,102 @@
 | 
				
			|||||||
 | 
					cuelabs.dev/go/oci/ociregistry v0.0.0-20250304105642-27e071d2c9b1 h1:Dmbd5Q+ENb2C6carvwrMsrOUwJ9X9qfL5JdW32gYAHo=
 | 
				
			||||||
 | 
					cuelabs.dev/go/oci/ociregistry v0.0.0-20250304105642-27e071d2c9b1/go.mod h1:dqrnoZx62xbOZr11giMPrWbhlaV8euHwciXZEy3baT8=
 | 
				
			||||||
 | 
					cuelang.org/go v0.13.2 h1:SagzeEASX4E2FQnRbItsqa33sSelrJjQByLqH9uZCE8=
 | 
				
			||||||
 | 
					cuelang.org/go v0.13.2/go.mod h1:8MoQXu+RcXsa2s9mebJN1HJ1orVDc9aI9/yKi6Dzsi4=
 | 
				
			||||||
github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
 | 
					github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
 | 
				
			||||||
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
 | 
					github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
 | 
				
			||||||
 | 
					github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
 | 
				
			||||||
 | 
					github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
 | 
				
			||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 | 
					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/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 | 
				
			||||||
 | 
					github.com/emicklei/proto v1.14.0 h1:WYxC0OrBuuC+FUCTZvb8+fzEHdZMwLEF+OnVfZA3LXU=
 | 
				
			||||||
 | 
					github.com/emicklei/proto v1.14.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
 | 
				
			||||||
 | 
					github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
 | 
				
			||||||
 | 
					github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
 | 
				
			||||||
 | 
					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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 | 
				
			||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
					github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 | 
					github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 | 
				
			||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
					github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
				
			||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
					github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
				
			||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
					github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
				
			||||||
 | 
					github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 | 
				
			||||||
 | 
					github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 | 
				
			||||||
 | 
					github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 | 
				
			||||||
 | 
					github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 | 
				
			||||||
 | 
					github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
 | 
				
			||||||
 | 
					github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 | 
				
			||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 | 
					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/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 | 
				
			||||||
 | 
					github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
 | 
				
			||||||
 | 
					github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
 | 
				
			||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
 | 
					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/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
 | 
				
			||||||
 | 
					github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 | 
				
			||||||
 | 
					github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 | 
				
			||||||
 | 
					github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
 | 
				
			||||||
 | 
					github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 | 
				
			||||||
 | 
					github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
 | 
				
			||||||
 | 
					github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
 | 
				
			||||||
 | 
					github.com/protocolbuffers/txtpbfmt v0.0.0-20250129171521-feedd8250727 h1:A8EM8fVuYc0qbVMw9D6EiKdKTIm1SmLvAWcCc2mipGY=
 | 
				
			||||||
 | 
					github.com/protocolbuffers/txtpbfmt v0.0.0-20250129171521-feedd8250727/go.mod h1:VmWrOlMnBZNtToCWzRlZlIXcJqjo0hS5dwQbRD62gL8=
 | 
				
			||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 | 
					github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 | 
				
			||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 | 
					github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
 | 
					github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
 | 
				
			||||||
 | 
					github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
					golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
 | 
					golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
 | 
					golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
 | 
				
			||||||
 | 
					golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
 | 
				
			||||||
 | 
					golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 | 
				
			||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
					golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
 | 
					golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
 | 
				
			||||||
 | 
					golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
 | 
				
			||||||
 | 
					golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
 | 
				
			||||||
 | 
					golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
 | 
				
			||||||
 | 
					golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
 | 
				
			||||||
 | 
					golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					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 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
 | 
				
			||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 | 
					golang.org/x/sys v0.33.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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
					golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
 | 
					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.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
 | 
					golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
 | 
				
			||||||
 | 
					golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
 | 
				
			||||||
 | 
					gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
				
			||||||
 | 
					gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 | 
				
			||||||
 | 
					gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
				
			||||||
 | 
					gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
				
			||||||
 | 
					gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
				
			||||||
 | 
					modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
 | 
				
			||||||
 | 
					modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
 | 
				
			||||||
 | 
					modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
 | 
				
			||||||
 | 
					modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
 | 
				
			||||||
 | 
					modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
 | 
				
			||||||
 | 
					modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
 | 
				
			||||||
 | 
					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.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc=
 | 
					modernc.org/libc v1.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc=
 | 
				
			||||||
modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po=
 | 
					modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po=
 | 
				
			||||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
 | 
					modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
 | 
				
			||||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
 | 
					modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
 | 
				
			||||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
 | 
					modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
 | 
				
			||||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
 | 
					modernc.org/memory v1.11.0/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.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
 | 
					modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
 | 
				
			||||||
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
 | 
					modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
 | 
				
			||||||
 | 
					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=
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										225
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								main.go
									
									
									
									
									
								
							@ -4,50 +4,98 @@ import (
 | 
				
			|||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/fs"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"math/rand/v2"
 | 
						"math/rand/v2"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/signal"
 | 
						"os/signal"
 | 
				
			||||||
	"strconv"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"cuelang.org/go/cue"
 | 
				
			||||||
 | 
						"cuelang.org/go/cue/cuecontext"
 | 
				
			||||||
	"github.com/bwmarrin/discordgo"
 | 
						"github.com/bwmarrin/discordgo"
 | 
				
			||||||
	"github.com/joho/godotenv"
 | 
						"github.com/joho/godotenv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_ "embed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_ "modernc.org/sqlite"
 | 
						_ "modernc.org/sqlite"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var botToken string
 | 
					var botToken string
 | 
				
			||||||
var announceChannelName string
 | 
					 | 
				
			||||||
var cleanDelay = 30
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
var confFile string
 | 
					var confFile string
 | 
				
			||||||
var dbFile string
 | 
					var dbFile string
 | 
				
			||||||
 | 
					var dataPath string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	flag.StringVar(&confFile, "conf", ".env", ".env file w/ config variables")
 | 
						flag.StringVar(&confFile, "conf", ".env", ".env file w/ config variables")
 | 
				
			||||||
	flag.StringVar(&dbFile, "db", "data.db", "db to store logs of events in")
 | 
						flag.StringVar(&dbFile, "db", "data.db", "db to store logs of events in")
 | 
				
			||||||
 | 
						flag.StringVar(&dataPath, "data", "./", "file path for storing data")
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:embed schema.cue
 | 
				
			||||||
 | 
					var schemaFile string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Config struct {
 | 
				
			||||||
 | 
						Server            string
 | 
				
			||||||
 | 
						VoiceChatAnnounce struct {
 | 
				
			||||||
 | 
							Enable          bool
 | 
				
			||||||
 | 
							AnnounceChannel string
 | 
				
			||||||
 | 
							JoinMessages    []string
 | 
				
			||||||
 | 
							CleanUpDelay    int
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						BirthdayAnnounce struct {
 | 
				
			||||||
 | 
							Enable          bool
 | 
				
			||||||
 | 
							AnnounceChannel string
 | 
				
			||||||
 | 
							Birthdays       []Birthday
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Config) String() string {
 | 
				
			||||||
 | 
						s := strings.Builder{}
 | 
				
			||||||
 | 
						s.WriteString(fmt.Sprintf("Guild ID: %s\n", c.Server))
 | 
				
			||||||
 | 
						if c.VoiceChatAnnounce.Enable {
 | 
				
			||||||
 | 
							s.WriteString("\tVoice Chat Accounce: ✅ \n")
 | 
				
			||||||
 | 
							s.WriteString(fmt.Sprintf("\t\tTo Channel: %s\n", c.VoiceChatAnnounce.AnnounceChannel))
 | 
				
			||||||
 | 
							s.WriteString(fmt.Sprintf("\t\t %d Custom messages\n", len(c.VoiceChatAnnounce.JoinMessages)))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							s.WriteString("\tVoice Chat Accounce: ❌ \n")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.BirthdayAnnounce.Enable {
 | 
				
			||||||
 | 
							s.WriteString("\tBirthday Accounce: ✅ \n")
 | 
				
			||||||
 | 
							s.WriteString(fmt.Sprintf("\t\tTo Channel: %s\n", c.BirthdayAnnounce.AnnounceChannel))
 | 
				
			||||||
 | 
							s.WriteString(fmt.Sprintf("\t\t %d Birthdays to Announce\n", len(c.BirthdayAnnounce.Birthdays)))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							s.WriteString("\tBirthday Accounce: ❌ \n")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Birthday struct {
 | 
				
			||||||
 | 
						Name   string //Optional
 | 
				
			||||||
 | 
						Member string
 | 
				
			||||||
 | 
						Date   string // Format MM/DD
 | 
				
			||||||
 | 
						server string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var joinMessages = []string{
 | 
					var joinMessages = []string{
 | 
				
			||||||
	"<@%s> has joined <#%s>",
 | 
						"<@%s> has joined <#%s>",
 | 
				
			||||||
	"<@%s> has joined <#%s>; Join in for some nerd talk",
 | 
					 | 
				
			||||||
	"<#%[2]s> is the place to be! <@%[1]s> just joined",
 | 
						"<#%[2]s> is the place to be! <@%[1]s> just joined",
 | 
				
			||||||
	"<#%[2]s> just got a bit cooler, <@%[1]s> is now in",
 | 
						"<#%[2]s> just got a bit cooler, <@%[1]s> is now in",
 | 
				
			||||||
	"<@%s> is hanging out in <#%s>",
 | 
						"<@%s> is hanging out in <#%s>",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Channel struct {
 | 
					 | 
				
			||||||
	GuildID, ChannelID string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Server struct {
 | 
					type Server struct {
 | 
				
			||||||
	*sql.DB
 | 
						*sql.DB
 | 
				
			||||||
 | 
						configs map[string]Config
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewServer(dbFile string) (*Server, error) {
 | 
					func NewServer(dbFile string) (*Server, error) {
 | 
				
			||||||
	db, err := sql.Open("sqlite", dbFile+"?_time_format=sqlite")
 | 
						db, err := sql.Open("sqlite", filepath.Join(dataPath, dbFile)+"?_time_format=sqlite")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("unable to open db %q: %w", dbFile, err)
 | 
							return nil, fmt.Errorf("unable to open db %q: %w", dbFile, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -70,28 +118,74 @@ func NewServer(dbFile string) (*Server, error) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("unable to create table: %w", err)
 | 
							return nil, fmt.Errorf("unable to create table: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	s := Server{DB: db}
 | 
						s := Server{DB: db, configs: map[string]Config{}}
 | 
				
			||||||
	return &s, nil
 | 
						return &s, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *Server) AddConfig(c Config) {
 | 
				
			||||||
 | 
						s.configs[c.Server] = c
 | 
				
			||||||
 | 
						log.Printf("Added server: \n%s\n", c)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	envs, err := godotenv.Read(confFile)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatalf("Unable to get environment variables: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	s, err := NewServer(dbFile)
 | 
						s, err := NewServer(dbFile)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalf("can't create server: %v", err)
 | 
							log.Fatalf("can't create server: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx := cuecontext.New()
 | 
				
			||||||
 | 
						schema := ctx.CompileString(schemaFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vfs := os.DirFS(dataPath)
 | 
				
			||||||
 | 
						err = fs.WalkDir(vfs, ".", func(path string, d fs.DirEntry, err error) error {
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if filepath.Ext(d.Name()) != ".cue" {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if d.Name() == "schema.cue" {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							f, err := vfs.Open(path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data, err := io.ReadAll(f)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							conf := ctx.CompileBytes(data, cue.Scope(schema))
 | 
				
			||||||
 | 
							if err := conf.Validate(); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("unable to validate config %q: %w", path, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cfg := Config{}
 | 
				
			||||||
 | 
							fields, err := conf.Fields()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fields.Next()
 | 
				
			||||||
 | 
							if err := fields.Value().Decode(&cfg); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("unable to decode config %q: %w", path, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							s.AddConfig(cfg)
 | 
				
			||||||
 | 
							fmt.Printf("Loaded conf from %q\n", path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Error(s) loading conf files: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						time.Sleep(500 * time.Millisecond)
 | 
				
			||||||
 | 
						envs, err := godotenv.Read(filepath.Join(dataPath, confFile))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("Unable to get environment variables: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// set values from env
 | 
						// set values from env
 | 
				
			||||||
	botToken = envs["BOT_TOKEN"]
 | 
						botToken = envs["BOT_TOKEN"]
 | 
				
			||||||
	announceChannelName = envs["ANNOUNCE_CHANNEL"]
 | 
					 | 
				
			||||||
	if delay, ok := envs["CLEAN_DELAY"]; ok {
 | 
					 | 
				
			||||||
		if d2, err := strconv.Atoi(delay); err == nil {
 | 
					 | 
				
			||||||
			cleanDelay = d2
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ds, err := discordgo.New("Bot " + botToken)
 | 
						ds, err := discordgo.New("Bot " + botToken)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -116,6 +210,10 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	defer ds.Close()
 | 
						defer ds.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = s.setupBirthdayWatch(ds); err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("can't setup birthday watcher: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stop := make(chan os.Signal, 1)
 | 
						stop := make(chan os.Signal, 1)
 | 
				
			||||||
	signal.Notify(stop, os.Interrupt)
 | 
						signal.Notify(stop, os.Interrupt)
 | 
				
			||||||
	<-stop
 | 
						<-stop
 | 
				
			||||||
@ -135,6 +233,11 @@ func (s VoiceState) String() string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Handle for when someone joins a voice channel - send notification about them joining.
 | 
					// Handle for when someone joins a voice channel - send notification about them joining.
 | 
				
			||||||
func (s *Server) voiceStatus(ds *discordgo.Session, m *discordgo.VoiceStateUpdate) {
 | 
					func (s *Server) voiceStatus(ds *discordgo.Session, m *discordgo.VoiceStateUpdate) {
 | 
				
			||||||
 | 
						guild, _ := ds.Guild(m.VoiceState.GuildID)
 | 
				
			||||||
 | 
						server := s.configs[guild.ID]
 | 
				
			||||||
 | 
						if !server.VoiceChatAnnounce.Enable {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	var state VoiceState
 | 
						var state VoiceState
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case len(m.ChannelID) == 0:
 | 
						case len(m.ChannelID) == 0:
 | 
				
			||||||
@ -147,8 +250,6 @@ func (s *Server) voiceStatus(ds *discordgo.Session, m *discordgo.VoiceStateUpdat
 | 
				
			|||||||
		state = Switching
 | 
							state = Switching
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	guild, _ := ds.Guild(m.VoiceState.GuildID)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch state {
 | 
						switch state {
 | 
				
			||||||
	case Leaving, Switching:
 | 
						case Leaving, Switching:
 | 
				
			||||||
		channel, _ := ds.Channel(m.BeforeUpdate.ChannelID)
 | 
							channel, _ := ds.Channel(m.BeforeUpdate.ChannelID)
 | 
				
			||||||
@ -176,33 +277,85 @@ func (s *Server) voiceStatus(ds *discordgo.Session, m *discordgo.VoiceStateUpdat
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	channels, err := ds.GuildChannels(m.GuildID)
 | 
						ch, err := ds.Channel(server.VoiceChatAnnounce.AnnounceChannel)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("Unable to get channels for Guild: %s", m.GuildID)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var announceChannel *discordgo.Channel
 | 
					 | 
				
			||||||
	for _, c := range channels {
 | 
					 | 
				
			||||||
		if c.Name == announceChannelName {
 | 
					 | 
				
			||||||
			announceChannel = c
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if announceChannel == nil {
 | 
					 | 
				
			||||||
		log.Printf("Unable to get announce channel for Guild: %s", m.GuildID)
 | 
							log.Printf("Unable to get announce channel for Guild: %s", m.GuildID)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msg := fmt.Sprintf(joinMessages[rand.IntN(len(joinMessages))], m.UserID, m.ChannelID)
 | 
						messages := append(joinMessages, server.VoiceChatAnnounce.JoinMessages...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg := fmt.Sprintf(messages[rand.IntN(len(messages))], m.UserID, m.ChannelID)
 | 
				
			||||||
	switch state {
 | 
						switch state {
 | 
				
			||||||
	case Switching:
 | 
						case Switching:
 | 
				
			||||||
		msg = fmt.Sprintf("<@%s> has left <#%s> to join <#%s>", m.UserID, m.BeforeUpdate.ChannelID, m.ChannelID)
 | 
							msg = fmt.Sprintf("<@%s> has left <#%s> to join <#%s>", m.UserID, m.BeforeUpdate.ChannelID, m.ChannelID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sent, err := ds.ChannelMessageSend(announceChannel.ID, msg)
 | 
						sent, err := ds.ChannelMessageSend(ch.ID, msg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("unable to send message: %s", err)
 | 
							log.Printf("unable to send message: %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	time.AfterFunc(time.Second*time.Duration(cleanDelay), func() {
 | 
						time.AfterFunc(time.Second*time.Duration(server.VoiceChatAnnounce.CleanUpDelay), func() {
 | 
				
			||||||
		ds.ChannelMessageDelete(sent.ChannelID, sent.ID)
 | 
							ds.ChannelMessageDelete(sent.ChannelID, sent.ID)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *Server) setupBirthdayWatch(ds *discordgo.Session) error {
 | 
				
			||||||
 | 
						birthdays := map[string][]Birthday{} // Use a list in case there are collisions (See birthday paradox)
 | 
				
			||||||
 | 
						for _, guild := range s.configs {
 | 
				
			||||||
 | 
							if !guild.BirthdayAnnounce.Enable {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, b := range guild.BirthdayAnnounce.Birthdays {
 | 
				
			||||||
 | 
								b.server = guild.Server
 | 
				
			||||||
 | 
								birthdays[b.Date] = append(birthdays[b.Date], b)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						targetHour := 7
 | 
				
			||||||
 | 
						targetMinute := 35
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
						location, err := time.LoadLocation("America/Los_Angeles")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("unable to get timezone data: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						targetTime := time.Date(now.Year(), now.Month(), now.Day(), targetHour, targetMinute, 0, 0, location)
 | 
				
			||||||
 | 
						if now.After(targetTime) {
 | 
				
			||||||
 | 
							targetTime = targetTime.Add(24 * time.Hour)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						initialDelay := targetTime.Sub(now)
 | 
				
			||||||
 | 
						log.Printf("Waiting for %s for starting birthday watcher", initialDelay)
 | 
				
			||||||
 | 
						birthdayMatcher := func(ds *discordgo.Session) {
 | 
				
			||||||
 | 
							dateString := time.Now().Format("01/02")
 | 
				
			||||||
 | 
							log.Printf("Looking for matching birthdays on %s", dateString)
 | 
				
			||||||
 | 
							if bd, ok := birthdays[dateString]; ok {
 | 
				
			||||||
 | 
								for _, b := range bd {
 | 
				
			||||||
 | 
									log.Printf("It is %q's birthday today (%s)", b.Member, b.Date)
 | 
				
			||||||
 | 
									if err := announceBirthday(ds, b.server, s.configs[b.server].BirthdayAnnounce.AnnounceChannel, b.Member); err != nil {
 | 
				
			||||||
 | 
										log.Printf("Error w/ announcing: %v", err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						time.AfterFunc(initialDelay, func() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.Printf("Birthday watcher initiated")
 | 
				
			||||||
 | 
							// Run now, but also set up a daily job
 | 
				
			||||||
 | 
							birthdayMatcher(ds)
 | 
				
			||||||
 | 
							c := time.Tick(24 * time.Hour)
 | 
				
			||||||
 | 
							for range c {
 | 
				
			||||||
 | 
								birthdayMatcher(ds)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func announceBirthday(ds *discordgo.Session, guildID, channelID, userId string) error {
 | 
				
			||||||
 | 
						_, err := ds.ChannelMessageSend(channelID, fmt.Sprintf("Happy Birthday to <@%s>!!", userId))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("unable to send message: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								schema.cue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								schema.cue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					// Initially generated by cue get go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//cue:generate cue get go dev.justinjudd.com/discord_bots
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Config: {
 | 
				
			||||||
 | 
						Server: string
 | 
				
			||||||
 | 
						VoiceChatAnnounce?: {
 | 
				
			||||||
 | 
							Enable:          bool | *false
 | 
				
			||||||
 | 
							AnnounceChannel: string | *""
 | 
				
			||||||
 | 
							JoinMessages: [...string] @go(,[]string)
 | 
				
			||||||
 | 
							CleanUpDelay: int | *30
 | 
				
			||||||
 | 
						} @go(,struct{Enable bool; AnnounceChannel string; JoinMessages []string; CleanUpDelay int})
 | 
				
			||||||
 | 
						BirthdayAnnounce?: {
 | 
				
			||||||
 | 
							Enable:          bool | *false
 | 
				
			||||||
 | 
							AnnounceChannel: string | *""
 | 
				
			||||||
 | 
							Birthdays: [...#Birthday] @go(,[]Birthday)
 | 
				
			||||||
 | 
						} @go(,struct{Enable bool; AnnounceChannel string; Birthdays []Birthday})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Birthday: {
 | 
				
			||||||
 | 
						Name:   string
 | 
				
			||||||
 | 
						Member: string
 | 
				
			||||||
 | 
						Date:   string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Enabled: {
 | 
				
			||||||
 | 
					    Enable: true
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user