diff --git a/assets/preview.png b/assets/preview.png index ad70144..ae075ce 100644 Binary files a/assets/preview.png and b/assets/preview.png differ diff --git a/discordo.go b/discordo.go index 76d13a6..ea8211d 100644 --- a/discordo.go +++ b/discordo.go @@ -56,13 +56,13 @@ func main() { messageInputField = ui.NewMessageInputField(onMessageInputFieldInputCapture, config.Theme) mainFlex = ui.NewMainFlex(guildsTreeView, messagesTextView, messageInputField) - token := util.GetItem(kr, "token") - if token != "" { + if t := util.GetItem(kr, "token"); t != "" { app. SetRoot(mainFlex, true). SetFocus(guildsTreeView) - discordSession = newSession("", "", token) + discordSession = newSession("", "", t) + defer discordSession.Close() } else { loginForm = ui.NewLoginForm(onLoginFormLoginButtonSelected) app.SetRoot(loginForm, true) @@ -88,8 +88,8 @@ func onAppInputCapture(e *tcell.EventKey) *tcell.EventKey { return e } -func onMessageInputFieldInputCapture(event *tcell.EventKey) *tcell.EventKey { - switch event.Key() { +func onMessageInputFieldInputCapture(e *tcell.EventKey) *tcell.EventKey { + switch e.Key() { case tcell.KeyEnter: t := strings.TrimSpace(messageInputField.GetText()) if t == "" { @@ -104,69 +104,68 @@ func onMessageInputFieldInputCapture(event *tcell.EventKey) *tcell.EventKey { messageInputField.SetText(text) } - return event + return e } -func newSession(email string, password string, token string) *session.Session { +func newSession(email string, password string, token string) (s *session.Session) { api.UserAgent = "" + "Mozilla/5.0 (X11; Linux x86_64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + - "Chrome/91.0.4472.164 Safari/537.36" + "Chrome/92.0.4515.131 Safari/537.36" gateway.DefaultIdentity.Browser = "Chrome" gateway.DefaultIdentity.OS = "Linux" gateway.DefaultIdentity.Device = "" - var sess *session.Session var err error if email != "" && password != "" { - sess, err = session.Login(email, password, "") + s, err = session.Login(email, password, "") } else if token != "" { - sess, err = session.New(token) + s, err = session.New(token) } if err != nil { panic(err) } - sess.AddHandler(onSessionReady) - sess.AddHandler(func(m *gateway.MessageCreateEvent) { - if currentChannel.ID == m.ChannelID { - util.WriteMessage(messagesTextView, clientID, m.Message) - } - }) - if err = sess.Open(context.Background()); err != nil { + s.AddHandler(onSessionReady) + s.AddHandler(onSessionMessageCreate) + if err = s.Open(context.Background()); err != nil { panic(err) } - return sess + return +} + +func onSessionMessageCreate(m *gateway.MessageCreateEvent) { + if currentChannel.ID == m.ChannelID { + util.WriteMessage(messagesTextView, clientID, m.Message) + } } func onSessionReady(r *gateway.ReadyEvent) { clientID = r.User.ID - for i := range r.Guilds { - g := r.Guilds[i] - gNode := tview.NewTreeNode(g.Name). + for _, g := range r.Guilds { + gn := tview.NewTreeNode(g.Name). SetReference(g). Collapse() - guildsTreeView.GetRoot().AddChild(gNode) + guildsTreeView.GetRoot().AddChild(gn) sort.Slice(g.Channels, func(i, j int) bool { return g.Channels[i].Position < g.Channels[j].Position }) - for i := range g.Channels { - c := g.Channels[i] + for _, c := range g.Channels { switch c.Type { case discord.GuildCategory: cNode := tview.NewTreeNode(c.Name). SetReference(c) - gNode.AddChild(cNode) + gn.AddChild(cNode) case discord.GuildText, discord.GuildNews: if c.ParentID == 0 || c.ParentID == discord.NullChannelID { cNode := tview.NewTreeNode("[::d]#" + c.Name + "[-:-:-]"). SetReference(c) - gNode.AddChild(cNode) + gn.AddChild(cNode) } } } @@ -174,37 +173,62 @@ func onSessionReady(r *gateway.ReadyEvent) { } func onGuildsTreeViewSelected(n *tview.TreeNode) { - switch ref := n.GetReference().(type) { + switch r := n.GetReference().(type) { case gateway.GuildCreateEvent: - currentGuild = ref - + currentGuild = r n.SetExpanded(!n.IsExpanded()) case discord.Channel: - switch ref.Type { + switch r.Type { case discord.GuildCategory: if len(n.GetChildren()) == 0 { - for i := range currentGuild.Channels { - c := currentGuild.Channels[i] - if (c.Type == discord.GuildText || c.Type == discord.GuildNews) && c.ParentID == ref.ID { - cNode := tview.NewTreeNode("[::d]#" + c.Name + "[-:-:-]"). + for _, c := range currentGuild.Channels { + if (c.Type == discord.GuildText || c.Type == discord.GuildNews) && c.ParentID == r.ID { + cn := tview.NewTreeNode("[::d]#" + c.Name + "[-:-:-]"). SetReference(c) - n.AddChild(cNode) + n.AddChild(cn) } } } else { n.SetExpanded(!n.IsExpanded()) } case discord.GuildText, discord.GuildNews: - currentChannel = ref + if len(n.GetChildren()) == 0 { + currentChannel = r + + app.SetFocus(messageInputField) + messagesTextView.Clear() + messagesTextView.SetTitle(r.Name) + + go func() { + for _, t := range currentGuild.Threads { + if t.ParentID == currentChannel.ID { + cn := tview.NewTreeNode("[::d]🗨 " + t.Name + "[::-]"). + SetReference(t) + n.AddChild(cn) + } + } + }() + + go func() { + msgs, _ := discordSession.Messages(r.ID, config.GetMessagesLimit) + for _, m := range msgs { + util.WriteMessage(messagesTextView, clientID, m) + } + }() + } else { + n.SetExpanded(!n.IsExpanded()) + } + case discord.GuildNewsThread, discord.GuildPrivateThread, discord.GuildPublicThread: + currentChannel = r app.SetFocus(messageInputField) messagesTextView.Clear() - messagesTextView.SetTitle(ref.Name) + messagesTextView.SetTitle(r.Name) go func() { - messages, _ := discordSession.Messages(ref.ID, config.GetMessagesLimit) - for i := len(messages) - 1; i >= 0; i-- { - util.WriteMessage(messagesTextView, clientID, messages[i]) + msgs, _ := discordSession.Messages(r.ID, config.GetMessagesLimit) + for _, m := range msgs { + util.WriteMessage(messagesTextView, clientID, m) } }() } @@ -223,6 +247,7 @@ func onLoginFormLoginButtonSelected() { SetFocus(guildsTreeView) discordSession = newSession(email, password, "") + defer discordSession.Close() go util.SetItem(kr, "token", discordSession.Token) } diff --git a/ui/app.go b/ui/app.go index 0773bcf..45fa929 100644 --- a/ui/app.go +++ b/ui/app.go @@ -5,8 +5,8 @@ import ( "github.com/rivo/tview" ) -func NewApp(onAppInputCapture func(*tcell.EventKey) *tcell.EventKey) *tview.Application { - app := tview.NewApplication(). +func NewApp(onAppInputCapture func(*tcell.EventKey) *tcell.EventKey) (app *tview.Application) { + app = tview.NewApplication(). EnableMouse(true). SetInputCapture(onAppInputCapture) diff --git a/ui/dropdowns.go b/ui/dropdowns.go index 6c23653..8da69ff 100644 --- a/ui/dropdowns.go +++ b/ui/dropdowns.go @@ -6,10 +6,9 @@ import ( "github.com/rivo/tview" ) -func NewGuildsDropDown(onGuildsDropDownSelected func(string, int), theme *util.Theme) *tview.DropDown { - guildsDropDown := tview.NewDropDown() - - guildsDropDown. +func NewGuildsDropDown(onGuildsDropDownSelected func(string, int), theme *util.Theme) (d *tview.DropDown) { + d = tview.NewDropDown() + d. SetLabel("Guild: "). SetSelectedFunc(onGuildsDropDownSelected). SetFieldBackgroundColor(tcell.GetColor(theme.DropDownBackground)). @@ -17,5 +16,5 @@ func NewGuildsDropDown(onGuildsDropDownSelected func(string, int), theme *util.T SetBorder(true). SetBorderPadding(0, 0, 1, 1) - return guildsDropDown + return } diff --git a/ui/flex.go b/ui/flex.go index c619049..0c585de 100644 --- a/ui/flex.go +++ b/ui/flex.go @@ -4,13 +4,13 @@ import ( "github.com/rivo/tview" ) -func NewMainFlex(treeV *tview.TreeView, textV *tview.TextView, i *tview.InputField) *tview.Flex { +func NewMainFlex(treeV *tview.TreeView, textV *tview.TextView, i *tview.InputField) (mainFlex *tview.Flex) { rightFlex := tview.NewFlex(). SetDirection(tview.FlexRow). AddItem(textV, 0, 1, false). AddItem(i, 3, 1, false) - mainFlex := tview.NewFlex(). - AddItem(treeV, 25, 1, false). + mainFlex = tview.NewFlex(). + AddItem(treeV, 30, 1, false). AddItem(rightFlex, 0, 1, false) return mainFlex diff --git a/ui/forms.go b/ui/forms.go index aea28eb..a93cbbc 100644 --- a/ui/forms.go +++ b/ui/forms.go @@ -5,9 +5,8 @@ import ( "github.com/rivo/tview" ) -func NewLoginForm(onLoginFormLoginButtonSelected func()) *tview.Form { - f := tview.NewForm() - +func NewLoginForm(onLoginFormLoginButtonSelected func()) (f *tview.Form) { + f = tview.NewForm() f. AddInputField("Email", "", 0, nil, nil). AddPasswordField("Password", "", 0, 0, nil). diff --git a/ui/inputfields.go b/ui/inputfields.go index 493d18f..8bb925b 100644 --- a/ui/inputfields.go +++ b/ui/inputfields.go @@ -6,8 +6,8 @@ import ( "github.com/rivo/tview" ) -func NewMessageInputField(onMessageInputFieldInputCapture func(*tcell.EventKey) *tcell.EventKey, theme *util.Theme) *tview.InputField { - i := tview.NewInputField() +func NewMessageInputField(onMessageInputFieldInputCapture func(*tcell.EventKey) *tcell.EventKey, theme *util.Theme) (i *tview.InputField) { + i = tview.NewInputField() i. SetPlaceholder("Message..."). SetPlaceholderTextColor(tcell.ColorWhite). @@ -17,5 +17,5 @@ func NewMessageInputField(onMessageInputFieldInputCapture func(*tcell.EventKey) SetBorderPadding(0, 0, 1, 1). SetInputCapture(onMessageInputFieldInputCapture) - return i + return } diff --git a/ui/textviews.go b/ui/textviews.go index 346c909..acb4d91 100644 --- a/ui/textviews.go +++ b/ui/textviews.go @@ -6,10 +6,9 @@ import ( "github.com/rivo/tview" ) -func NewMessagesTextView(app *tview.Application, theme *util.Theme) *tview.TextView { - messagesTextView := tview.NewTextView() - - messagesTextView. +func NewMessagesTextView(app *tview.Application, theme *util.Theme) (textV *tview.TextView) { + textV = tview.NewTextView() + textV. SetDynamicColors(true). SetWordWrap(true). ScrollToEnd(). @@ -20,5 +19,5 @@ func NewMessagesTextView(app *tview.Application, theme *util.Theme) *tview.TextV SetBorder(true). SetBorderPadding(0, 0, 1, 1) - return messagesTextView + return } diff --git a/ui/treeviews.go b/ui/treeviews.go index 18e9b43..092be6e 100644 --- a/ui/treeviews.go +++ b/ui/treeviews.go @@ -6,19 +6,18 @@ import ( "github.com/rivo/tview" ) -func NewGuildsTreeView(onGuildsTreeViewSelected func(*tview.TreeNode), theme *util.Theme) *tview.TreeView { - guildsTreeView := tview.NewTreeView() - guildsTreeNode := tview.NewTreeNode("") - - guildsTreeView. +func NewGuildsTreeView(onGuildsTreeViewSelected func(*tview.TreeNode), theme *util.Theme) (treeV *tview.TreeView) { + treeV = tview.NewTreeView() + treeN := tview.NewTreeNode("") + treeV. SetTopLevel(1). - SetRoot(guildsTreeNode). - SetCurrentNode(guildsTreeNode). + SetRoot(treeN). + SetCurrentNode(treeN). SetSelectedFunc(onGuildsTreeViewSelected). SetBackgroundColor(tcell.GetColor(theme.TreeViewBackground)). SetTitle("Guilds"). SetBorder(true). SetBorderPadding(0, 0, 1, 1) - return guildsTreeView + return } diff --git a/util/config.go b/util/config.go index c796537..ca7b1c7 100644 --- a/util/config.go +++ b/util/config.go @@ -23,23 +23,23 @@ func NewConfig() *Config { panic(err) } - var config Config = Config{ + var c Config = Config{ GetMessagesLimit: 50, Theme: &Theme{}, } configPath := userHomeDir + "/.config/discordo/config.json" if _, err := os.Stat(configPath); os.IsNotExist(err) { - return &config + return &c } - data, err := os.ReadFile(configPath) + d, err := os.ReadFile(configPath) if err != nil { panic(err) } - if err = json.Unmarshal(data, &config); err != nil { + if err = json.Unmarshal(d, &c); err != nil { panic(err) } - return &config + return &c } diff --git a/util/discord.go b/util/discord.go index 5f056bd..a3e6990 100644 --- a/util/discord.go +++ b/util/discord.go @@ -9,31 +9,35 @@ import ( ) func WriteMessage(v *tview.TextView, clientID discord.UserID, m discord.Message) { - m.Content = parseMessageMentions(m.Content, m.Mentions, clientID) + switch m.Type { + case discord.DefaultMessage, discord.InlinedReplyMessage: + var b strings.Builder + // $ ╭ AUTHOR_USERNAME (BOT) MESSAGE_CONTENT*linebreak* + writeReferencedMessage(&b, clientID, m.ReferencedMessage) + // $ AUTHOR_USERNAME (BOT)*spacee* + writeAuthor(&b, clientID, m.Author) + // $ MESSAGE_CONTENT + if m.Content != "" { + m.Content = parseMessageMentions(m.Content, m.Mentions, clientID) + b.WriteString(m.Content) + } + // $ *space*(edited) + if m.EditedTimestamp.IsValid() { + b.WriteString(" [::d](edited)[::-]") + } + // $ *linebreak*EMBED + writeEmbeds(&b, m.Embeds) + // $ *linebreak*ATTACHMENT_URL + writeAttachments(&b, m.Attachments) - var b strings.Builder - // $ ╭ AUTHOR_USERNAME (BOT) MESSAGE_CONTENT*linebreak* - writeReferencedMessage(&b, clientID, m.ReferencedMessage) - // $ AUTHOR_USERNAME (BOT)*spacee* - writeAuthor(&b, clientID, m.Author) - // $ MESSAGE_CONTENT - b.WriteString(m.Content) - // $ *space*(edited) - if m.EditedTimestamp.IsValid() { - b.WriteString(" [::d](edited)[::-]") + fmt.Fprintln(v, b.String()) + case discord.ThreadStarterMessage: + WriteMessage(v, clientID, *m.ReferencedMessage) } - // $ *linebreak*EMBED - writeEmbeds(&b, m.Embeds) - // $ *linebreak*ATTACHMENT_URL - writeAttachments(&b, m.Attachments) - - fmt.Fprintln(v, b.String()) } func parseMessageMentions(content string, mentions []discord.GuildUser, clientID discord.UserID) string { - for i := range mentions { - mUser := mentions[i] - + for _, mUser := range mentions { var color string if mUser.ID == clientID { color = "[#000000:#FEE75C]" @@ -61,8 +65,7 @@ func writeEmbeds(b *strings.Builder, embeds []discord.Embed) { } func writeAttachments(b *strings.Builder, attachments []discord.Attachment) { - for i := range attachments { - a := attachments[i] + for _, a := range attachments { b.WriteString("\n[" + a.Filename + "]: ") b.WriteString(a.URL) } @@ -100,7 +103,9 @@ func writeReferencedMessage(b *strings.Builder, clientID discord.UserID, rm *dis b.WriteString("[#EB459E]BOT[-] ") } - rm.Content = parseMessageMentions(rm.Content, rm.Mentions, clientID) - b.WriteString(rm.Content + "[::-]\n") + if rm.Content != "" { + rm.Content = parseMessageMentions(rm.Content, rm.Mentions, clientID) + b.WriteString(rm.Content + "[::-]\n") + } } } diff --git a/util/keyring.go b/util/keyring.go index 93fa318..5246632 100644 --- a/util/keyring.go +++ b/util/keyring.go @@ -4,22 +4,22 @@ import ( "github.com/99designs/keyring" ) -func OpenKeyringBackend() keyring.Keyring { +func OpenKeyringBackend() (kr keyring.Keyring) { kr, err := keyring.Open(keyring.Config{}) if err != nil { panic(err) } - return kr + return } func GetItem(kr keyring.Keyring, k string) string { - item, err := kr.Get(k) + i, err := kr.Get(k) if err != nil { return "" } - return string(item.Data) + return string(i.Data) } func SetItem(kr keyring.Keyring, k string, d string) {