|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "strings" |
| 6 | + "time" |
| 7 | + |
| 8 | + "github.com/bwmarrin/discordgo" |
| 9 | +) |
| 10 | + |
| 11 | +var msgs = make(map[string]*msgsEntry, 60) |
| 12 | +var msgCh = make(chan (*map[string]*stream)) |
| 13 | + |
| 14 | +type msgsEntry struct { |
| 15 | + stream *stream |
| 16 | + msgID string |
| 17 | +} |
| 18 | + |
| 19 | +type command struct { |
| 20 | + action rune |
| 21 | + user string |
| 22 | + stream *stream |
| 23 | +} |
| 24 | + |
| 25 | +func msgInit() chan (bool) { |
| 26 | + res := make(chan (bool), 1) |
| 27 | + go func() { |
| 28 | + // load message history |
| 29 | + history, err := discord.ChannelMessages(env["CHANNEL_ID"], 50, "", "", "") |
| 30 | + exitIfError(err) |
| 31 | + // decode + register green messages |
| 32 | + for _, msg := range history { |
| 33 | + if len(msg.Embeds) == 1 && msg.Embeds[0].Color == 0x00ff00 { |
| 34 | + user := msg.Embeds[0].Title[:strings.IndexByte(msg.Embeds[0].Title, ' ')] |
| 35 | + startTime, err := time.Parse("2006-01-02T15:04:05-07:00", msg.Embeds[0].Timestamp) |
| 36 | + exitIfError(err) |
| 37 | + stream := stream{ |
| 38 | + UserName: user, |
| 39 | + Title: msg.Embeds[0].Description, |
| 40 | + StartedAt: startTime, |
| 41 | + } |
| 42 | + msgs[strings.ToLower(user)] = &msgsEntry{&stream, msg.ID} |
| 43 | + } |
| 44 | + } |
| 45 | + fmt.Printf("m | init [%d]\n", len(msgs)) |
| 46 | + res <- true |
| 47 | + }() |
| 48 | + return res |
| 49 | +} |
| 50 | + |
| 51 | +func msg() { |
| 52 | + for { |
| 53 | + new := *<-msgCh |
| 54 | + commands := make([]command, 0) |
| 55 | + |
| 56 | + // generate command queue from new data |
| 57 | + for user := range msgs { |
| 58 | + _, isInNew := new[user] |
| 59 | + if !isInNew { // remove |
| 60 | + commands = append(commands, command{'r', user, nil}) |
| 61 | + fmt.Printf("m | - %s\n", user) |
| 62 | + } |
| 63 | + } |
| 64 | + for user := range new { |
| 65 | + streamNew := new[user] |
| 66 | + _, isInOld := msgs[user] |
| 67 | + if isInOld && streamNew.Title != msgs[user].stream.Title { // update |
| 68 | + commands = append(commands, command{'e', user, streamNew}) |
| 69 | + fmt.Printf("m | ~ %s\n", user) |
| 70 | + } else if !isInOld { // add |
| 71 | + commands = append(commands, command{'a', user, streamNew}) |
| 72 | + fmt.Printf("m | + %s\n", user) |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + // process command queue |
| 77 | + for _, cmd := range commands { |
| 78 | + switch cmd.action { |
| 79 | + case 'a': |
| 80 | + msgID := msgAdd() |
| 81 | + msgEdit(msgID, cmd.stream, true) |
| 82 | + msgs[cmd.user] = &msgsEntry{cmd.stream, msgID} |
| 83 | + case 'e': |
| 84 | + msgEdit(msgs[cmd.user].msgID, cmd.stream, true) |
| 85 | + msgs[cmd.user].stream = cmd.stream |
| 86 | + case 'r': |
| 87 | + // calc swap ID of closing msg with oldest open msg (so open msgs stay grouped at bottom) |
| 88 | + user, msgID := cmd.user, msgs[cmd.user].msgID |
| 89 | + minUser, minID := user, msgID |
| 90 | + for userTest := range msgs { |
| 91 | + if strings.Compare(msgs[userTest].msgID, minID) == -1 { |
| 92 | + minUser, minID = userTest, msgs[userTest].msgID |
| 93 | + } |
| 94 | + } |
| 95 | + if minID != msgID { |
| 96 | + fmt.Printf("m | %s ↔ %s\n", user, minUser) |
| 97 | + msgs[user].msgID, msgs[minUser].msgID = minID, msgID |
| 98 | + msgEdit(msgs[minUser].msgID, msgs[minUser].stream, true) |
| 99 | + } |
| 100 | + msgEdit(msgs[user].msgID, msgs[user].stream, false) |
| 101 | + // update messages at new IDs |
| 102 | + delete(msgs, user) |
| 103 | + } |
| 104 | + } |
| 105 | + fmt.Printf("m | ok [%d]\n", len(msgs)) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +func msgAdd() (msgID string) { |
| 110 | + for { |
| 111 | + msgOut, err := discord.ChannelMessageSendComplex( |
| 112 | + env["CHANNEL_ID"], |
| 113 | + &discordgo.MessageSend{Embed: &discordgo.MessageEmbed{Color: 0xffff00}}, |
| 114 | + ) |
| 115 | + time.Sleep(time.Second) |
| 116 | + if err != nil { |
| 117 | + fmt.Printf("x | m+: %s\n", err) |
| 118 | + } else { |
| 119 | + return msgOut.ID |
| 120 | + } |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +func msgEdit(msgID string, stream *stream, active bool) { |
| 125 | + for { |
| 126 | + _, err := discord.ChannelMessageEditComplex(&discordgo.MessageEdit{ |
| 127 | + Channel: env["CHANNEL_ID"], |
| 128 | + ID: msgID, |
| 129 | + Embed: generateMsg(stream, active), |
| 130 | + }) |
| 131 | + time.Sleep(time.Second) |
| 132 | + if err != nil { |
| 133 | + fmt.Printf("x | m~: %s\n", err) |
| 134 | + } else { |
| 135 | + return |
| 136 | + } |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +func generateMsg(s *stream, live bool) *discordgo.MessageEmbed { |
| 141 | + var colour int |
| 142 | + var postText, thumbnail string |
| 143 | + if live { |
| 144 | + colour = 0x00ff00 |
| 145 | + postText = " is live" |
| 146 | + if len(s.ThumbnailURL) >= 20 { |
| 147 | + thumbnail = s.ThumbnailURL[:len(s.ThumbnailURL)-20] + "440x248.jpg" |
| 148 | + } |
| 149 | + } else { |
| 150 | + colour = 0xff0000 |
| 151 | + postText = " was live" |
| 152 | + } |
| 153 | + return &discordgo.MessageEmbed{ |
| 154 | + Title: s.UserName + postText, |
| 155 | + Description: s.Title, |
| 156 | + URL: "https://twitch.tv/" + s.UserName, |
| 157 | + Color: colour, |
| 158 | + Thumbnail: &discordgo.MessageEmbedThumbnail{URL: thumbnail}, |
| 159 | + Timestamp: s.StartedAt.Format("2006-01-02T15:04:05Z"), |
| 160 | + Footer: &discordgo.MessageEmbedFooter{IconURL: "https://www.mariowiki.com/images/thumb/b/be/SMS_Shine_Sprite_Artwork.png/805px-SMS_Shine_Sprite_Artwork.png"}, |
| 161 | + } |
| 162 | +} |
0 commit comments