package main import ( "encoding/json" "fmt" "io" "net/http" "os" "time" "github.com/bwmarrin/discordgo" ) type BattleSchedudleSub struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Rule struct { Key string `json:"key"` Name string `json:"name"` } `json:"rule"` Stages []struct { ID int `json:"id"` Name string `json:"name"` Image string `json:"image"` } `json:"stages"` IsFest bool `json:"is_fest"` } type BattleSchedule struct { Result struct { Regular []BattleSchedudleSub `json:"regular"` BankaraChallenge []BattleSchedudleSub `json:"bankara_challenge"` BankaraOpen []BattleSchedudleSub `json:"bankara_open"` X []BattleSchedudleSub `json:"x"` Event []struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Rule struct { Key string `json:"key"` Name string `json:"name"` } `json:"rule"` Stages []struct { ID int `json:"id"` Name string `json:"name"` Image string `json:"image"` } `json:"stages"` Event struct { ID string `json:"id"` Name string `json:"name"` Desc string `json:"desc"` } `json:"event"` IsFest bool `json:"is_fest"` } `json:"event"` Fest []struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Rule any `json:"rule"` Stages any `json:"stages"` IsFest bool `json:"is_fest"` IsTricolor bool `json:"is_tricolor"` TricolorStages any `json:"tricolor_stages"` } `json:"fest"` FestChallenge []struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Rule any `json:"rule"` Stages any `json:"stages"` IsFest bool `json:"is_fest"` IsTricolor bool `json:"is_tricolor"` TricolorStages any `json:"tricolor_stages"` } `json:"fest_challenge"` } `json:"result"` } type SalmonRunSchedule struct { Results []struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Boss struct { ID string `json:"id"` Name string `json:"name"` } `json:"boss"` Stage struct { ID int `json:"id"` Name string `json:"name"` Image string `json:"image"` } `json:"stage"` Weapons []struct { Name string `json:"name"` Image string `json:"image"` } `json:"weapons"` IsBigRun bool `json:"is_big_run"` } `json:"results"` } type msgidstore struct { filepath string } func NewMsgIDStore() *msgidstore { return &msgidstore{filepath: os.Getenv("MSGIDSTORE_FILEPATH")} } func (s *msgidstore) Set(id string) error { // Open file for writing file, err := os.OpenFile(s.filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return err } defer file.Close() // Write the message ID to the file _, err = file.WriteString(id) if err != nil { return err } return nil } func (s *msgidstore) Exist() bool { // Check if the file exists _, err := os.Stat(s.filepath) if os.IsNotExist(err) { return false } return err == nil } func (s *msgidstore) Get() (string, error) { // Open file for reading file, err := os.Open(s.filepath) if err != nil { return "", err } defer file.Close() // Read the message ID from the file var id string _, err = fmt.Fscanf(file, "%s", &id) if err != nil { return "", err } return id, nil } func battleScheduleSub(schedSub []BattleSchedudleSub) string { var output string for _, v := range schedSub { output += fmt.Sprintf("%d/%d %2d:%02d- ", v.StartTime.Month(), v.StartTime.Day(), v.StartTime.Hour(), v.StartTime.Minute()) output += v.Rule.Name /* length := utf8.RuneCountInString(v.Rule.Name) fill := (13 - length) for range fill { output += " " } for _, stage := range v.Stages { output += fmt.Sprintf("%s ", stage.Name) length := utf8.RuneCountInString(stage.Name) fill := (11 - length) for range fill { output += " " } } */ output += fmt.Sprintln() } if output == "" { output = "現在、スケジュールはありません。\n" } return output } func battleSchedule() string { url := "https://spla3.yuu26.com/api/schedule" resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() byteArray, _ := io.ReadAll(resp.Body) var data BattleSchedule err = json.Unmarshal(byteArray, &data) if err != nil { panic(err) } output := "バンカラオープン スケジュール\n" output += "```\n" output += battleScheduleSub(data.Result.BankaraOpen) output += "```\n" output += "バンカラチャレンジ スケジュール\n" output += "```\n" output += battleScheduleSub(data.Result.BankaraChallenge) output += "```\n" output += "Xマッチ スケジュール\n" output += "```\n" output += battleScheduleSub(data.Result.X) output += "```\n" return output } func salmonRunSchedule() string { url := "https://spla3.yuu26.com/api/coop-grouping/schedule" resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() byteArray, _ := io.ReadAll(resp.Body) var data SalmonRunSchedule err = json.Unmarshal(byteArray, &data) if err != nil { panic(err) } output := "サーモンラン スケジュール\n" output += "```\n" for _, v := range data.Results { output += fmt.Sprintf("%d/%d %2d:%02d- ", v.StartTime.Month(), v.StartTime.Day(), v.StartTime.Hour(), v.StartTime.Minute()) output += v.Stage.Name + " " output += v.Boss.Name + "\n " for c, weapon := range v.Weapons { output += weapon.Name + " " if c == 1 { output += "\n " } } output += "\n" } output += "```\n" return output } func main() { discordChannelId := os.Getenv("DISCORD_CHANNEL_ID") discordToken := os.Getenv("DISCORD_TOKEN") discord, err := discordgo.New("Bot " + discordToken) if err != nil { panic(err) } output := battleSchedule() output += salmonRunSchedule() jst, err := time.LoadLocation("Asia/Tokyo") if err != nil { panic(err) } output += "updated at " + time.Now().In(jst).Format("1/2 15:04") + "\n" print(output) msgidstore := NewMsgIDStore() if msgidstore.Exist() { id, err := msgidstore.Get() if err != nil { panic(err) } // If the message ID exists, edit the message _, err = discord.ChannelMessageEdit(discordChannelId, id, output) if err != nil { panic(err) } } else { msg, err := discord.ChannelMessageSend(discordChannelId, output) if err != nil { panic(err) } // Store msg ID err = msgidstore.Set(msg.ID) if err != nil { panic(err) } } }