-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit aa9998c
Showing
8 changed files
with
1,518 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Auto detect text files and perform LF normalization | ||
* text=auto eol=lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# If you prefer the allow list template instead of the deny list, see community template: | ||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore | ||
# | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
|
||
# Go workspace file | ||
go.work | ||
|
||
.env | ||
|
||
# created transcripts | ||
transcripts/ |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Yoahtl Trial Recorder | ||
|
||
A simple util to easily record trials with the Yoahtl court system as markdown files for use in other systems, like the [website](https://civyoahtl.github.io/). | ||
|
||
## Usage | ||
|
||
1. Create a Discord bot and invite it to your server. | ||
2. Set the environment variables listed below. | ||
3. Run the bot. | ||
```bash | ||
go run . | ||
``` | ||
or just run the docker image | ||
|
||
The bot will then record the messages in the channel specified by `CHANNEL_ID` from the message with ID `START_MSG_ID` to the message with ID `END_MSG_ID` and save them to a file named `<trial name>.md` in the transcripts folder, where `<trial name>` is the value of the `TRIAL_NAME` environment variable. | ||
|
||
## Environment Variables | ||
|
||
- `DISCORD_TOKEN` - The token to use to connect to Discord. | ||
- `CHANNEL_ID` - The ID of the channel to record from. | ||
- `START_MSG_ID` - The ID of the message to start recording from. This is exclusive, so the message with this ID will not be recorded. | ||
- `END_MSG_ID` - The ID of the message to end recording at. This is inclusive, so the message with this ID will be recorded. | ||
- `TRIAL_NAME` - The name of the trial to record. | ||
|
||
(The bot will also take an .env file in the current directory if it exists.) | ||
|
||
## Go Version | ||
|
||
1.20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
module github.com/CivYoahtl/trial-recorder | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/disgoorg/disgo v0.16.2 | ||
github.com/disgoorg/log v1.2.0 | ||
github.com/disgoorg/snowflake/v2 v2.0.1 | ||
github.com/rotisserie/eris v0.5.4 | ||
github.com/spf13/viper v1.15.0 | ||
) | ||
|
||
require ( | ||
github.com/disgoorg/json v1.0.0 // indirect | ||
github.com/fsnotify/fsnotify v1.6.0 // indirect | ||
github.com/hashicorp/hcl v1.0.0 // indirect | ||
github.com/magiconair/properties v1.8.7 // indirect | ||
github.com/mitchellh/mapstructure v1.5.0 // indirect | ||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect | ||
github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b // indirect | ||
github.com/spf13/afero v1.9.3 // indirect | ||
github.com/spf13/cast v1.5.0 // indirect | ||
github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
github.com/subosito/gotenv v1.4.2 // indirect | ||
golang.org/x/exp v0.0.0-20220325121720-054d8573a5d8 // indirect | ||
golang.org/x/sys v0.3.0 // indirect | ||
golang.org/x/text v0.5.0 // indirect | ||
gopkg.in/ini.v1 v1.67.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/disgoorg/disgo/rest" | ||
"github.com/disgoorg/log" | ||
"github.com/disgoorg/snowflake/v2" | ||
"github.com/rotisserie/eris" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func main() { | ||
// config stuff | ||
viper.AddConfigPath(".") | ||
viper.SetConfigFile(".env") | ||
viper.SetConfigType("env") | ||
err := viper.ReadInConfig() | ||
if err != nil { | ||
err = eris.Wrap(err, "failed to read config") | ||
log.Panic(err) | ||
} | ||
viper.AutomaticEnv() | ||
|
||
log.Infof("Starting %s...", viper.GetString("TRIAL_NAME")) | ||
|
||
// create rest client | ||
client := rest.New(rest.NewClient(viper.GetString("DISCORD_TOKEN"))) | ||
|
||
// create snowflakes for ids | ||
channelId := snowflake.ID(viper.GetUint("CHANNEL_ID")) | ||
startId := snowflake.ID(viper.GetUint("START_MSG_ID")) | ||
endId := snowflake.ID(viper.GetUint("END_MSG_ID")) | ||
|
||
// new transcript manager | ||
transcript := NewTranscript(startId, endId) | ||
|
||
// get messages | ||
messages := client.GetMessagesPage(channelId, startId, 50) | ||
|
||
// add messages to transcript | ||
transcript.AddMessagesPage(messages) | ||
|
||
log.Info("Done getting messages") | ||
|
||
stats := transcript.GetStats() | ||
|
||
log.Info("Stats:") | ||
log.Infof("\tTotal messages: %d", stats.TotalMessages) | ||
log.Infof("\tTotal users: %d", stats.TotalUsers) | ||
log.Infof("\tStart date: %s", stats.StartDate) | ||
log.Infof("\tEnd date: %s", stats.EndDate) | ||
|
||
// // print transcript | ||
// transcript.PrintTranscript() | ||
|
||
// save transcript | ||
transcript.SaveTranscript() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/disgoorg/disgo/discord" | ||
"github.com/disgoorg/disgo/rest" | ||
"github.com/disgoorg/log" | ||
"github.com/disgoorg/snowflake/v2" | ||
"github.com/rotisserie/eris" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
type Msg struct { | ||
Content string | ||
ID snowflake.ID | ||
} | ||
|
||
type MsgBlock struct { | ||
UserId snowflake.ID | ||
Name string | ||
Messages []Msg | ||
} | ||
|
||
type Transcript struct { | ||
Blocks []MsgBlock | ||
StartMsgID snowflake.ID | ||
EndMsgID snowflake.ID | ||
} | ||
|
||
type TranscriptStats struct { | ||
TotalMessages int | ||
TotalUsers int | ||
StartDate string | ||
EndDate string | ||
} | ||
|
||
// Adds a message to the transcript | ||
func (t *Transcript) AddMessage(m discord.Message) { | ||
// we get messages in the reverse order they were send, | ||
// so we need to add them in the reverse order we get them | ||
|
||
// if first block is the same user | ||
if len(t.Blocks) > 0 && t.Blocks[0].UserId == m.Author.ID { | ||
// just put the message in the first block | ||
|
||
// create a new message | ||
message := Msg{ | ||
Content: m.Content, | ||
ID: m.ID, | ||
} | ||
t.Blocks[0].Messages = append([]Msg{message}, t.Blocks[0].Messages...) | ||
|
||
return | ||
} | ||
|
||
msg := Msg{ | ||
Content: m.Content, | ||
ID: m.ID, | ||
} | ||
|
||
// create a new block | ||
msgBlock := MsgBlock{ | ||
UserId: m.Author.ID, | ||
Name: m.Author.Username, | ||
Messages: []Msg{msg}, | ||
} | ||
t.Blocks = append([]MsgBlock{msgBlock}, t.Blocks...) | ||
} | ||
|
||
// Gets messages from a page and adds them to the transcript | ||
func (t *Transcript) AddMessagesPage(messages rest.Page[discord.Message]) { | ||
count := 0 | ||
|
||
// page through messages | ||
for messages.Next() { | ||
log.Infof("Processing page %d...", count+1) | ||
|
||
for _, m := range messages.Items { | ||
t.AddMessage(m) | ||
} | ||
|
||
count++ | ||
} | ||
|
||
// trim excess messages | ||
t.RemoveExcessMessages() | ||
} | ||
|
||
// removes all messages after end message | ||
func (t *Transcript) RemoveExcessMessages() { | ||
atEnd := false | ||
|
||
// remove messages after end id | ||
for i := 0; i < len(t.Blocks); i++ { | ||
|
||
for j := 0; j < len(t.Blocks[i].Messages); j++ { | ||
msg := t.Blocks[i].Messages[j] | ||
|
||
// if found end message | ||
if msg.ID == t.EndMsgID { | ||
atEnd = true | ||
|
||
// if not at end of array, remove all messages after end message | ||
if j+1 < len(t.Blocks[i].Messages) { | ||
t.Blocks[i].Messages = t.Blocks[i].Messages[:j+1] | ||
} | ||
} | ||
} | ||
|
||
// if at end, remove all blocks after end block | ||
if atEnd { | ||
t.Blocks = t.Blocks[:i+1] | ||
} | ||
} | ||
} | ||
|
||
// Gets basic stats about the transcript | ||
func (t *Transcript) GetStats() TranscriptStats { | ||
totalMessages := 0 | ||
seenUsers := []snowflake.ID{} | ||
startTime := t.Blocks[0].Messages[0].ID.Time().Format("Mon, 02 Jan 2006 15:04:05 MST") | ||
endTime := t.Blocks[len(t.Blocks)-1].Messages[len(t.Blocks[len(t.Blocks)-1].Messages)-1].ID.Time().Format("Mon, 02 Jan 2006 15:04:05 MST") | ||
|
||
for _, b := range t.Blocks { | ||
|
||
// check if user has been seen | ||
seenUser := false | ||
for _, u := range seenUsers { | ||
if b.UserId == u { | ||
seenUser = true | ||
continue | ||
} | ||
} | ||
if !seenUser { | ||
seenUsers = append(seenUsers, b.UserId) | ||
} | ||
|
||
// tally up msg stats | ||
totalMessages += len(b.Messages) | ||
} | ||
|
||
return TranscriptStats{ | ||
TotalMessages: totalMessages, | ||
TotalUsers: len(seenUsers), | ||
StartDate: startTime, | ||
EndDate: endTime, | ||
} | ||
} | ||
|
||
// prints transcript to console | ||
func (t *Transcript) PrintTranscript() { | ||
println("----------------- Transcript -----------------") | ||
for _, b := range t.Blocks { | ||
println(b.Name) | ||
for _, m := range b.Messages { | ||
println(m.Content) | ||
} | ||
println("---") | ||
} | ||
} | ||
|
||
// writes transcript to a file | ||
func (t *Transcript) SaveTranscript() { | ||
folderPath := "transcripts" | ||
name := viper.GetString("TRIAL_NAME") | ||
|
||
// check if folder exists | ||
if _, err := os.Stat(folderPath); eris.Is(err, os.ErrNotExist) { | ||
// if eror is that folder doesn't exist, create it | ||
err := os.MkdirAll(folderPath, os.ModePerm) | ||
if err != nil { | ||
// failed to create folder | ||
err := eris.Wrap(err, "failed to create folder") | ||
log.Panic(err) | ||
} | ||
} | ||
|
||
// create file | ||
f, err := os.Create(folderPath + "/" + name + ".md") | ||
if err != nil { | ||
eris.Wrap(err, "failed to create file") | ||
log.Panic(err) | ||
} | ||
|
||
// remember to close the file | ||
defer f.Close() | ||
|
||
// scaffold the file | ||
writeToFile(f, "# "+name) | ||
writeToFile(f, "## Case") | ||
writeToFile(f, "_REPLACE ME: need a sumarry of the case here_") | ||
writeToFile(f, "## Proceedings") | ||
|
||
// write transcript | ||
for _, b := range t.Blocks { | ||
writeToFile(f, "**"+b.Name+"**:") | ||
writeToFile(f, "") | ||
// println(b.Name) | ||
for _, m := range b.Messages { | ||
// println(m) | ||
writeToFile(f, "> "+m.Content) | ||
writeToFile(f, "") | ||
} | ||
writeToFile(f, "") | ||
} | ||
} | ||
|
||
// creates a new transcript | ||
func NewTranscript(startMsgID, endMsgID snowflake.ID) *Transcript { | ||
return &Transcript{StartMsgID: startMsgID, EndMsgID: endMsgID, Blocks: []MsgBlock{}} | ||
} | ||
|
||
// simpe util to append a line to a file | ||
func writeToFile(file *os.File, content string) { | ||
_, err := file.WriteString(content + "\n") | ||
if err != nil { | ||
eris.Wrap(err, "failed to write to file") | ||
log.Panic(err) | ||
} | ||
} |