Initial Project
This commit is contained in:
commit
ba1b16c61d
6 changed files with 419 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bin
|
||||||
|
obj
|
1
BUGS
Normal file
1
BUGS
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
355
Program.cs
Normal file
355
Program.cs
Normal file
|
@ -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<string> currentChannelMessages;
|
||||||
|
private ulong currentSelectedChannel;
|
||||||
|
private ulong currentSelectedGuild;
|
||||||
|
private SortedDictionary<ulong, List<ulong>> 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<Settings>();
|
||||||
|
|
||||||
|
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<ulong, List<ulong>>();
|
||||||
|
|
||||||
|
foreach (var guild in client.Guilds)
|
||||||
|
{
|
||||||
|
guilds.Add(guild.Id, new List<ulong>());
|
||||||
|
|
||||||
|
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<List<GetMessagesResponse>>(restSharpReq);
|
||||||
|
|
||||||
|
var messages = new List<string>();
|
||||||
|
|
||||||
|
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<List<object>>(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<List<GetMessagesResponse>>(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<object> embeds { get; set; }
|
||||||
|
public List<MessageAttachments> attachments { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageAuthor
|
||||||
|
{
|
||||||
|
public string username { get; set; }
|
||||||
|
public string discriminator { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageAttachments
|
||||||
|
{
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
6
TODO
Normal file
6
TODO
Normal file
|
@ -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
|
33
chord.csproj
Normal file
33
chord.csproj
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Configurations>Release;Debug</Configurations>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<AssemblyVersion>0.0.1.0</AssemblyVersion>
|
||||||
|
<FileVersion>0.0.1.0</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>None</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>Full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Discord.Net.Labs" Version="3.4.9" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Restsharp" Version="106.15.0" />
|
||||||
|
<PackageReference Include="Terminal.Gui" Version="1.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
22
chord.sln
Normal file
22
chord.sln
Normal file
|
@ -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
|
Reference in a new issue