From ba1b16c61dc33365612d10cf256a002a8705432e Mon Sep 17 00:00:00 2001 From: Daryl Ronningen Date: Tue, 14 Dec 2021 18:37:03 -0700 Subject: [PATCH] Initial Project --- .gitignore | 2 + BUGS | 1 + Program.cs | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++ TODO | 6 + chord.csproj | 33 +++++ chord.sln | 22 ++++ 6 files changed, 419 insertions(+) create mode 100644 .gitignore create mode 100644 BUGS create mode 100644 Program.cs create mode 100644 TODO create mode 100644 chord.csproj create mode 100644 chord.sln diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1746e32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/BUGS @@ -0,0 +1 @@ + diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..e1714eb --- /dev/null +++ b/Program.cs @@ -0,0 +1,355 @@ +using System.Diagnostics; +using System.Text; +using Discord; +using Discord.WebSocket; +using Microsoft.Extensions.Configuration; +using RestSharp; +using Terminal.Gui; +using Attribute = Terminal.Gui.Attribute; +using Color = Terminal.Gui.Color; + +namespace chord +{ + public class Program + { + private ListView chatBoxList; + private List currentChannelMessages; + private ulong currentSelectedChannel; + private ulong currentSelectedGuild; + private SortedDictionary> guilds; + private Settings settings; + private Window window; + + public static void Main() + { + new Program().Start(); + } + + private async void Start() + { +#if DEBUG + var config = new ConfigurationBuilder() + .AddJsonFile("config.json") + .Build(); +#else + var config = new ConfigurationBuilder() + .AddJsonFile($"{Environment.GetEnvironmentVariable("HOME")}/.config/chord/config.json") + .Build(); +#endif + + settings = config.Get(); + + var client = new DiscordSocketClient(new DiscordSocketConfig + { AlwaysDownloadUsers = true, GatewayIntents = GatewayIntents.All }); + + await client.LoginAsync(TokenType.Bot, settings.Token); + await client.StartAsync(); + + Application.Init(); + + window = new Window("chord") + { + X = 0, + Y = 1, + Width = Dim.Fill(), + Height = Dim.Fill(), + ColorScheme = + { + Normal = new Attribute(Color.White, Color.Black) + } + }; + + client.Ready += () => + { + guilds = new SortedDictionary>(); + + foreach (var guild in client.Guilds) + { + guilds.Add(guild.Id, new List()); + + foreach (var channel in guild.TextChannels) + { + var findGuild = guilds.GetValueOrDefault(guild.Id); + + if (channel.Users.ToList().Find(user => user.Id == client.CurrentUser.Id) == null) continue; + if (findGuild == null) continue; + findGuild.Add(channel.Id); + + findGuild.Sort(); + } + } + + var menuBar = buildMenu(); + var serverList = buildServerList(); + var channelList = buildChannelList(serverList); + var chatBox = buildChatBox(serverList); + var messageBox = buildMessageBox(serverList, chatBox); + var userList = buildUserList(chatBox); + + var serverListList = new ListView + { + X = 0, + Y = 0, + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + var guildNames = guilds.Select(guild => client.GetGuild(guild.Key).Name).ToList(); + + serverListList.SetSource(guildNames); + + var channelListList = new ListView + { + X = 0, + Y = 0, + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + chatBoxList = new ListView + { + X = 0, + Y = 0, + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + var messageBoxText = new TextView + { + X = 0, + Y = 0, + Width = Dim.Percent(95), + Height = Dim.Fill() + }; + + var messageBoxSend = new Button("Send", true) + { + X = Pos.Right(messageBoxText) - 2, + Y = 0 + }; + + var userListList = new ListView + { + X = 0, + Y = 0, + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + serverListList.OpenSelectedItem += args => + { + currentSelectedGuild = guilds.Keys.ToList()[args.Item]; + + var channelNames = guilds.GetValueOrDefault(currentSelectedGuild)! + .Select(channel => client.GetGuild(currentSelectedGuild).GetTextChannel(channel).Name).ToList(); + + channelListList.SetSource(channelNames); + }; + + channelListList.OpenSelectedItem += async args => + { + currentSelectedChannel = guilds.GetValueOrDefault(currentSelectedGuild)!.ToList()[args.Item]; + + var restSharpClient = new RestClient("https://discord.com/api/v9"); + var restSharpReq = new RestRequest($"channels/{currentSelectedChannel}/messages"); + restSharpClient.AddDefaultHeader("Authorization", settings.Token); + + var response = await restSharpClient.GetAsync>(restSharpReq); + + var messages = new List(); + + foreach (var msg in response) + { + var msgNewLines = msg.content.Split("\n").ToList(); + + var firstMsg = msgNewLines[0]; + + msgNewLines.RemoveAt(0); + msgNewLines.Reverse(); + + messages.AddRange(msgNewLines.Select(message => $"{message}")); + + messages.Add($"{msg.author.username}#{msg.author.discriminator} | {firstMsg}"); + + if (msg.embeds.Count != 0) + messages.Add($"{msg.author.username}#{msg.author.discriminator} | [Unable to display embed]"); + + if (msg.attachments.Count == 0) continue; + messages.AddRange(msg.attachments + .Select(attachment => $"{msg.author.username}#{msg.author.discriminator} | {attachment.url}") + .Select(dummy => dummy)); + } + + messages.Reverse(); + + await chatBoxList.SetSourceAsync(messages); + currentChannelMessages = messages; + + chatBoxList.ScrollDown(currentChannelMessages.Count - chatBoxList.Bounds.Height); + chatBoxList.SelectedItem = currentChannelMessages.Count - 1; + + await userListList.SetSourceAsync(client.GetGuild(currentSelectedGuild).GetTextChannel(currentSelectedChannel) + .Users + .ToList()); + }; + + messageBoxSend.Clicked += async () => + { + var restSharpClient = new RestClient("https://discord.com/api/v9"); + var restSharpReq = new RestRequest($"channels/{currentSelectedChannel}/messages"); + restSharpClient.AddDefaultHeader("Authorization", settings.Token); + restSharpReq.AddJsonBody(new { content = Encoding.UTF8.GetString(messageBoxText.Text.ToByteArray()) }); + + await restSharpClient.PostAsync>(restSharpReq); + + messageBoxText.Text = ""; + }; + + chatBoxList.OpenSelectedItem += args => + { + if (currentChannelMessages[args.Item].Split(" | ")[1].Contains("http")) + for (var i = 0; i <= currentChannelMessages[args.Item].Split(" | ")[1].Split(" ").Count(); i++) + if (currentChannelMessages[args.Item].Split(" | ")[1].Split(" ")[i].Contains("http")) + { + var procStartInfo = new ProcessStartInfo("/bin/sh", + $"-c \"xdg-open {currentChannelMessages[args.Item].Split(" | ")[1].Split(" ")[i]}\"") + { + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + UseShellExecute = false + }; + + var proc = new Process(); + proc.StartInfo = procStartInfo; + proc.Start(); + } + }; + + Application.Top.Add(window, menuBar); + window.Add(serverList, channelList, messageBox, chatBox, userList); + serverList.Add(serverListList); + channelList.Add(channelListList); + chatBox.Add(chatBoxList); + messageBox.Add(messageBoxText, messageBoxSend); + userList.Add(userListList); + + return Task.CompletedTask; + }; + + client.MessageReceived += async msg => + { + if (msg.Channel.Id != currentSelectedChannel) return; + + var restSharpClient = new RestClient("https://discord.com/api/v9"); + var restSharpReq = new RestRequest($"channels/{currentSelectedChannel}/messages"); + restSharpReq.AddQueryParameter("limit", "1"); + restSharpClient.AddDefaultHeader("Authorization", settings.Token); + + var response = await restSharpClient.GetAsync>(restSharpReq); + + currentChannelMessages.Add( + $"{response.First().author.username}#{response.First().author.discriminator} | {response.First().content}"); + await chatBoxList.SetSourceAsync(currentChannelMessages); + + chatBoxList.ScrollDown(currentChannelMessages.Count - chatBoxList.Bounds.Height); + chatBoxList.SelectedItem = currentChannelMessages.Count - 1; + }; + + Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), caller => true); + + Application.Run(); + Application.Shutdown(); + } + + private Window buildChatBox(Window serverList) + { + return new Window("Chat Box") + { + X = Pos.Right(serverList), + Y = 0, + Width = Dim.Percent(60), + Height = Dim.Percent(90) + }; + } + + private Window buildChannelList(Window serverList) + { + return new Window("Channel List") + { + X = 0, + Y = Pos.Bottom(serverList), + Width = Dim.Percent(30), + Height = Dim.Percent(50) + }; + } + + private MenuBar buildMenu() + { + return new MenuBar(new[] + { + new MenuBarItem("File", new[] + { + new MenuItem("Quit", "", () => { Application.Top.Running = false; }) + }) + }); + } + + private Window buildMessageBox(Window serverList, Window chatBox) + { + return new Window("Message Box") + { + X = Pos.Right(serverList), + Y = Pos.Bottom(chatBox), + Width = Dim.Percent(60), + Height = Dim.Percent(10) + }; + } + + private Window buildUserList(Window chatBox) + { + return new Window("User List") + { + X = Pos.Right(chatBox), + Y = 0, + Width = Dim.Percent(10), + Height = Dim.Fill() + }; + } + + private Window buildServerList() + { + return new Window("Server List") + { + X = 0, + Y = 0, + Width = Dim.Percent(30), + Height = Dim.Percent(50) + }; + } + } +} + +public class Settings +{ + public string Token { get; set; } +} + +public class GetMessagesResponse +{ + public string content { get; set; } + public MessageAuthor author { get; set; } + public List embeds { get; set; } + public List attachments { get; set; } +} + +public class MessageAuthor +{ + public string username { get; set; } + public string discriminator { get; set; } +} + +public class MessageAttachments +{ + public string url { get; set; } +} diff --git a/TODO b/TODO new file mode 100644 index 0000000..417221b --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ + - Figure out how to bypass discord intents for user list (Currently just using Discord.NET cache) + - Message Conversion + - Convert message attachments to links (DONE) + - Sort Channels by catagories + - DMs + - Loading Screen diff --git a/chord.csproj b/chord.csproj new file mode 100644 index 0000000..fef0ee5 --- /dev/null +++ b/chord.csproj @@ -0,0 +1,33 @@ + + + + Exe + net6.0 + enable + Release;Debug + x64 + false + 0.0.1.0 + 0.0.1.0 + + + + true + None + + + + true + Full + + + + + + + + + + + + diff --git a/chord.sln b/chord.sln new file mode 100644 index 0000000..abb1cf8 --- /dev/null +++ b/chord.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chord", "chord.csproj", "{08889332-CBCB-4FFD-8D45-A3329FC11081}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + Debug|x64 = Debug|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {08889332-CBCB-4FFD-8D45-A3329FC11081}.Debug|x64.ActiveCfg = Debug|x64 + {08889332-CBCB-4FFD-8D45-A3329FC11081}.Debug|x64.Build.0 = Debug|x64 + {08889332-CBCB-4FFD-8D45-A3329FC11081}.Release|x64.ActiveCfg = Release|x64 + {08889332-CBCB-4FFD-8D45-A3329FC11081}.Release|x64.Build.0 = Release|x64 + EndGlobalSection +EndGlobal