| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- package main
- import (
- "encoding/json"
- "fmt"
- "sort"
- "github.com/ayntgl/discordgo"
- "github.com/gen2brain/beeep"
- "github.com/rivo/tview"
- )
- var (
- session *discordgo.Session
- selectedChannel *discordgo.Channel
- selectedMessage *discordgo.Message
- )
- func newSession() *discordgo.Session {
- s, err := discordgo.New()
- if err != nil {
- panic(err)
- }
- s.UserAgent = conf.UserAgent
- s.Identify.Compress = false
- s.Identify.Intents = 0
- s.Identify.LargeThreshold = 0
- s.Identify.Properties.Device = ""
- s.Identify.Properties.Browser = "Chrome"
- s.Identify.Properties.OS = "Linux"
- s.AddHandlerOnce(onSessionReady)
- s.AddHandler(onSessionMessageCreate)
- return s
- }
- func onSessionReady(_ *discordgo.Session, r *discordgo.Ready) {
- dmNode := tview.NewTreeNode("Direct Messages").
- Collapse()
- n := channelsTree.GetRoot()
- n.AddChild(dmNode)
- sort.Slice(r.PrivateChannels, func(i, j int) bool {
- return r.PrivateChannels[i].LastMessageID > r.PrivateChannels[j].LastMessageID
- })
- for _, c := range r.PrivateChannels {
- var tag string
- if isUnread(c) {
- tag = "[::b]"
- } else {
- tag = "[::d]"
- }
- cn := tview.NewTreeNode(tag + generateChannelRepr(c) + "[::-]").
- SetReference(c.ID)
- dmNode.AddChild(cn)
- }
- sort.Slice(r.Guilds, func(a, b int) bool {
- found := false
- for _, gID := range r.Settings.GuildPositions {
- if found {
- if gID == r.Guilds[b].ID {
- return true
- }
- } else {
- if gID == r.Guilds[a].ID {
- found = true
- }
- }
- }
- return false
- })
- for _, g := range r.Guilds {
- gn := tview.NewTreeNode(g.Name).Collapse()
- n.AddChild(gn)
- cs := g.Channels
- sort.Slice(cs, func(i, j int) bool {
- return cs[i].Position < cs[j].Position
- })
- // Top-level channels
- createTopLevelChannelsTreeNodes(gn, cs)
- // Category channels
- createCategoryChannelsTreeNodes(gn, cs)
- // Second-level channels
- createSecondLevelChannelsTreeNodes(cs)
- }
- channelsTree.SetCurrentNode(n)
- }
- func isUnread(c *discordgo.Channel) bool {
- if c.LastMessageID == "" {
- return false
- }
- for _, rs := range session.State.ReadState {
- if c.ID == rs.ID {
- return c.LastMessageID != rs.LastMessageID
- }
- }
- return false
- }
- func onSessionMessageCreate(_ *discordgo.Session, m *discordgo.MessageCreate) {
- c, err := session.State.Channel(m.ChannelID)
- if err != nil {
- return
- }
- if selectedChannel == nil || selectedChannel.ID != m.ChannelID {
- if conf.Notifications {
- for _, u := range m.Mentions {
- if u.ID == session.State.User.ID {
- g, err := session.State.Guild(m.GuildID)
- if err != nil {
- return
- }
- go beeep.Alert(fmt.Sprintf("%s (#%s)", g.Name, c.Name), m.ContentWithMentionsReplaced(), "")
- return
- }
- }
- }
- cn := getTreeNodeByReference(c.ID)
- if cn == nil {
- return
- }
- cn.SetText("[::b]" + generateChannelRepr(c) + "[::-]")
- app.Draw()
- } else {
- selectedChannel.Messages = append(selectedChannel.Messages, m.Message)
- renderMessage(m.Message)
- }
- }
- type loginResponse struct {
- MFA bool `json:"mfa"`
- SMS bool `json:"sms"`
- Ticket string `json:"ticket"`
- Token string `json:"token"`
- }
- func login(email, password string) (*loginResponse, error) {
- data := struct {
- Email string `json:"email"`
- Password string `json:"password"`
- }{email, password}
- resp, err := session.RequestWithBucketID(
- "POST",
- discordgo.EndpointLogin,
- data,
- discordgo.EndpointLogin,
- )
- if err != nil {
- return nil, err
- }
- var lr loginResponse
- err = json.Unmarshal(resp, &lr)
- if err != nil {
- return nil, err
- }
- return &lr, nil
- }
- func totp(code, ticket string) (*loginResponse, error) {
- data := struct {
- Code string `json:"code"`
- Ticket string `json:"ticket"`
- }{code, ticket}
- e := discordgo.EndpointAuth + "mfa/totp"
- resp, err := session.RequestWithBucketID("POST", e, data, e)
- if err != nil {
- return nil, err
- }
- var lr loginResponse
- err = json.Unmarshal(resp, &lr)
- if err != nil {
- return nil, err
- }
- return &lr, nil
- }
|