46 Commits
Author SHA1 Message Date
Stone_Red 2b0765997a Update .gitignore 2021-08-06 21:46:23 +02:00
Stone-Red-Code 361859d2bc Remove debug files 2021-08-06 19:43:51 +02:00
Stone-Red-Code 881299c2d2 Preparation for the release of 0.0.5.0 step 2 2021-08-06 19:26:33 +02:00
Stone-Red-Code 4231256bfe Preparation for the release of 0.0.5.0 2021-08-06 19:25:52 +02:00
Stone-Red-Code 5bf354a22a Fixed update URL in update info path 2021-08-06 19:23:30 +02:00
Stone-Red-Code c7e4e89e17 Fixed version numbers in update info files 2021-08-06 19:19:00 +02:00
Stone-Red-Code 6186779115 Auto updater cross platform support test2 2021-08-06 19:17:21 +02:00
Stone-Red-Code 49d62348c8 Auto updater cross platform support test1 2021-08-06 18:57:20 +02:00
Stone-Red-Code db75f856ff Make userinfo command more reliable and some bug fixes 2021-08-03 23:05:43 +02:00
Stone-Red-Code 3d8d1d4709 Multiple bug fixes
Fixed:
URL detection regex
Application crashes when a message is sent in the read-only channel
Application does not exit correctly
2021-08-01 18:08:44 +02:00
Stone-Red-Code a1609916c2 Fixed mention higlighting and channels are now correctly sorted by chategory. 2021-08-01 17:18:26 +02:00
Stone-Red-Code d162cc0056 Updated AlwaysUpToDate to 1.0.04 2021-06-30 08:42:41 +02:00
Stone-Red-Code c63a480fe5 Added OnException Handler to the updater 2021-06-26 17:15:12 +02:00
Stone-Red-Code 45d5b51bab Cleanup 2021-06-18 08:59:26 +02:00
Stone-Red-Code 5a09767dbc Merge branch 'develop' of https://github.com/Stone-Red-Code/DiscordCLI into develop 2021-05-29 18:28:49 +02:00
Stone-Red-Code f900292d86 Added auto update 2021-05-29 18:27:50 +02:00
Stone_Red 95d3c4e476 Add files via upload 2021-05-29 18:19:12 +02:00
Stone_Red fb55a909f0 Add files via upload 2021-05-29 18:16:05 +02:00
Stone_Red b758cdab49 Update updateInfo.json 2021-05-29 18:04:45 +02:00
Stone_Red e9cde21189 Update updateInfo.json 2021-05-29 17:58:34 +02:00
Stone_Red d518f79263 Add files via upload 2021-05-29 17:54:57 +02:00
Stone-Red-Code 7fbfd85ff4 Auto update [Test 1] 2021-05-29 17:45:59 +02:00
Stone-Red-Code 16cee9413b Merge branch 'main' into develop 2021-05-28 19:57:31 +02:00
Stone-Red-Code 2265b044cc Added commands history
- Added commands history
- Added "clear" command
- Small code improvements
2021-05-28 19:54:42 +02:00
Stone-Red-Code d9143457a7 Updated file structure 2021-05-28 18:00:22 +02:00
Stone_Red 35db02685b Update issue templates 2021-05-28 17:52:23 +02:00
Stone-Red-Code af721731ea Better mention syntax highlighting and more
- Better mention syntax highlighting
- Added "userinfo" command
2021-05-28 16:47:56 +02:00
Stone_Red 652c81defa Update README.md 2021-05-27 18:13:05 +02:00
Stone-Red-Code 07ff5a6d4a Replaced .rar files through .zip files 2021-05-27 08:02:12 +02:00
Stone-Red-Code 57215db498 #2 DiscordCLI not sending capital letters. 2021-05-27 07:53:54 +02:00
Stone_Red 76845b9ae0 Update README.md 2021-05-01 20:41:58 +02:00
Stone_Red 31b4f9cc44 Update README.md 2021-04-16 12:00:23 +02:00
Stone_Red 524ed14b1f Update README.md 2021-04-14 14:36:49 +02:00
Stone_Red 8d93a9de2c Update README.md 2021-04-14 14:36:20 +02:00
Stone_Red c6ba3a434d Merge pull request #1 from Stone-Red-Code/develop
Develop
2021-04-14 12:06:08 +02:00
Stone-Red-Code fc3d170e07 Added new releases 2021-04-14 12:03:24 +02:00
Stone-Red-Code ce4fb237b3 Update Program.cs 2021-04-14 11:54:10 +02:00
Stone-Red-Code f0fcbc03c5 Made more code async and added request cooldown 2021-04-14 11:53:53 +02:00
Stone_Red f53d614fca Added Limitations sections to README 2021-04-13 21:18:09 +02:00
Stone_Red 74f40593ba Added exclamation mark 2021-04-13 11:51:41 +02:00
Stone_Red 7521d9053d Update README.md 2021-04-13 11:48:58 +02:00
Stone_Red b38433badc Updated User Token link in README 2021-04-13 11:12:55 +02:00
Stone_Red 890625e6da Added description to README 2021-04-13 11:09:58 +02:00
Stone-Red-Code 433a71e838 Merge branch 'main' of https://github.com/Stone-Red-Code/DiscordCLI into main 2021-04-13 10:18:15 +02:00
Stone-Red-Code 1ddd35e5a4 Added DM support
- Added DM support
- Improved Token input
- Put the Commands class in its own file
2021-04-13 10:18:10 +02:00
Stone_Red 12271b760b Update README.md 2021-04-12 22:50:44 +02:00
273 changed files with 11346 additions and 2545 deletions
+32
View File
@@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+365 -1
View File
@@ -1 +1,365 @@
*.txt ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# DiscordCLI-specific files
token.txt
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
Binary file not shown.
-207
View File
@@ -1,207 +0,0 @@
using DSharpPlus.Entities;
using DSharpPlus;
using Stone_Red_Utilities.ColorConsole;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System;
namespace DiscordCLI
{
internal class CommandsManager : Commands
{
private readonly DiscordClient client;
private readonly Dictionary<string, (string, Action<string>)> CommandsList;
public CommandsManager(DiscordClient dicordClient, OutputManager outputManager) : base(dicordClient, outputManager)
{
client = dicordClient;
CommandsList = new()
{
{ "exit", ("exits application", null) },
{ "logout", ("deletes auth token and exits application", DeleteToken) },
{ "guilds", ("lists all guilds you are in", ListGuilds) },
{ "dms", ("lists all private channels (Not implemented yet)", ListDms) },
{ "channels", ("lists all channels of guild args:<guild name/index>", ListGuildChannels) },
{ "enterg", ("enter guild args:<guild name/index>", ListGuildChannels) },
{ "enterc", ("enter chat args:<channel name/index>", EnterChannel) },
};
}
public bool CheckCommand(string input)
{
input = input.Trim().ToLower().Replace('\n', '\0');
if (string.IsNullOrWhiteSpace(input))
return false;
if (input.StartsWith('<'))
{
input = input.Remove(0, 1);
}
else if (GlobalInformation.currentTextChannel != null)
{
Console.CursorTop--;
Console.Write("\r" + new string(' ', Console.WindowWidth));
GlobalInformation.currentTextChannel.SendMessageAsync(input);
return false;
}
Console.WriteLine();
if (input == "exit" || input is null)
return true;
string args = input.Contains(" ") ? input[input.IndexOf(" ")..].Trim() : null;
input = input.Contains(" ") ? input.Substring(0, input.IndexOf(" ")) : input;
if (input == "help")
{
for (int i = 0; i < CommandsList.Count; i++)
{
Console.Write($"{i + 1}. {CommandsList.Keys.ElementAt(i)}".PadRight(15));
Console.WriteLine(CommandsList.Values.ElementAt(i).Item1);
}
}
else if (CommandsList.ContainsKey(input))
{
CommandsList[input].Item2(args);
}
else
{
ConsoleExt.WriteLine("Command does not exist!", ConsoleColor.Red);
}
return false;
}
}
internal class Commands
{
private IReadOnlyDictionary<ulong, DiscordGuild> socketGuildsCache;
private readonly DiscordClient client;
private readonly OutputManager outputManager;
public Commands(DiscordClient dicordClient, OutputManager outputMan)
{
client = dicordClient;
outputManager = outputMan;
}
protected void ListGuilds(string args)
{
socketGuildsCache ??= client.Guilds;
int index = 1;
foreach (DiscordGuild guild in socketGuildsCache.Values)
{
Console.WriteLine($"{index}. {guild.Name}");
index++;
}
}
protected void ListDms(string args)
{
throw new NotImplementedException();
}
protected void ListGuildChannels(string args)
{
IReadOnlyCollection<DiscordChannel> textChannels;
DiscordGuild guild;
if (args != null)
{
if (int.TryParse(args, out int ind))
{
guild = socketGuildsCache?.Values.ElementAtOrDefault(ind - 1);
}
else
{
guild = socketGuildsCache?.FirstOrDefault(x => x.Value.Name == args).Value;
}
GlobalInformation.currentTextChannel = null;
}
else
{
guild = GlobalInformation.currentGuild;
}
if (guild is null)
{
ConsoleExt.WriteLine("Guild not found!", ConsoleColor.Red);
GlobalInformation.currentTextChannel = null;
return;
}
GlobalInformation.currentGuild = guild;
textChannels = guild.Channels;
int index = 1;
foreach (DiscordChannel channel in textChannels)
{
switch (channel.Type)
{
case ChannelType.Category:
//Console.WriteLine($"[{channel.Name}]");
break;
case ChannelType.Text:
Console.WriteLine($" {index}. {channel.Name}");
index++;
break;
}
}
}
protected async void EnterChannel(string args)
{
DiscordChannel textChannel;
if (GlobalInformation.currentGuild is null)
{
ConsoleExt.WriteLine("You are not in a guild!", ConsoleColor.Red);
return;
}
if (int.TryParse(args, out int ind))
{
textChannel = GlobalInformation.currentGuild?.Channels.Where(x => x.Type == ChannelType.Text).ElementAtOrDefault(ind - 1);
}
else
{
textChannel = GlobalInformation.currentGuild?.Channels.Where(x => x.Type == ChannelType.Text).FirstOrDefault(x => x.Name == args);
}
GlobalInformation.currentTextChannel = textChannel;
if (textChannel is null)
{
ConsoleExt.WriteLine("Channel not found!", ConsoleColor.Red);
return;
}
foreach (DiscordMessage message in (await textChannel.GetMessagesAsync(10)).Reverse())
{
try
{
await outputManager.WriteMessage(message, textChannel, GlobalInformation.currentGuild);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
protected void DeleteToken(string args)
{
File.Delete(Program.tokenPath);
Environment.Exit(0);
}
}
}
-60
View File
@@ -1,60 +0,0 @@
using DSharpPlus;
using System.Threading.Tasks;
using System;
namespace DiscordCLI
{
internal class InputManager
{
private readonly CommandsManager commandsManager;
private readonly DiscordClient client;
public string Input { get; private set; } = "<";
public InputManager(DiscordClient dicordClient, CommandsManager commandsMan)
{
client = dicordClient;
commandsManager = commandsMan;
}
public async Task ReadInput()
{
await Task.Run(() =>
{
bool exit = false;
while (!exit)
{
string infoString = $"\r[{client.CurrentUser.Username}#{client.CurrentUser.Discriminator}] [{GlobalInformation.currentGuild?.Name}/{GlobalInformation.currentTextChannel?.Name}] ==> ";
if (Input.StartsWith('<'))
Console.Write(Environment.NewLine + infoString);
Input = string.Empty;
ConsoleKeyInfo keyInfo;
do
{
keyInfo = Console.ReadKey(true);
if (!char.IsControl(keyInfo.KeyChar))
Input += keyInfo.KeyChar.ToString();
if (keyInfo.Key == ConsoleKey.Backspace && Input.Length > 0)
{
Input = Input.Remove(Input.Length - 1);
}
Console.Write(keyInfo.KeyChar);
if (keyInfo.Key == ConsoleKey.Backspace)
Console.Write(" ");
Console.CursorLeft = infoString.Length + Input.Length - 1;
} while (keyInfo.Key != ConsoleKey.Enter);
if (GlobalInformation.currentTextChannel == null && !Input.StartsWith('<'))
Input = "<" + Input;
exit = commandsManager.CheckCommand(Input);
}
Environment.Exit(0);
});
}
}
}
-183
View File
@@ -1,183 +0,0 @@
using ColorMine.ColorSpaces.Comparisons;
using ColorMine.ColorSpaces;
using DSharpPlus.Entities;
using DSharpPlus;
using Stone_Red_Utilities.ColorConsole;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System;
namespace DiscordCLI
{
internal class OutputManager
{
private readonly DiscordClient client;
public InputManager InputManager { get; set; }
public OutputManager(DiscordClient discordClient)
{
client = discordClient;
}
public async Task WriteMessage(DiscordMessage message, DiscordChannel channel, DiscordGuild guild)
{
try
{
if (channel.Id != GlobalInformation.currentTextChannel?.Id)
return;
DiscordUser user = message.Author;
DiscordMember discordMember = await guild.GetMemberAsync(user.Id);
DiscordColor discordColor = discordMember.Color;
Color color = Color.FromArgb(discordColor.R, discordColor.G, discordColor.B);
WriteTop($"[{discordMember.DisplayName}]", color, message, true, true, $"{discordMember.Username}#{discordMember.Discriminator} {message.Timestamp.LocalDateTime}");
if (!string.IsNullOrWhiteSpace(message.Content))
WriteTop(message.Content, Color.White, message);
foreach (DiscordAttachment attachment in message.Attachments)
{
WriteTop($"{attachment.Url}", Color.White, message, true, true, attachment.FileName);
}
foreach (DiscordEmbed embed in message.Embeds)
{
if (!string.IsNullOrWhiteSpace(embed.Title))
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{{{embed.Title}}}", Color.White, message, false);
}
if (!string.IsNullOrWhiteSpace(embed.Description))
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{embed.Description}", Color.White, message, false);
}
foreach (DiscordEmbedField field in embed.Fields)
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{field.Name}{Environment.NewLine}{field.Value}", Color.White, message, false);
}
//WriteTop($"{string.Join(Environment.NewLine, embed.Fields.Select(x => $"> {x.Name}{Environment.NewLine}{x.Value}"))}", Color.White, message);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
WriteTop(string.Empty, Color.White, message);
Console.Write($"[{client.CurrentUser.Username}#{client.CurrentUser.Discriminator}] [{GlobalInformation.currentGuild?.Name}/{GlobalInformation.currentTextChannel?.Name}] ==> ");
Console.Write(InputManager.Input);
}
private void WriteTop(string message, Color color, DiscordMessage discordMessage, bool removeText = true, bool newLine = true, string info = null)
{
ConsoleColor consoleColor = ClosestConsoleColor(color);
if (consoleColor == Console.BackgroundColor || consoleColor == ConsoleColor.DarkGray)
consoleColor = ConsoleColor.White;
if (removeText)
Console.Write('\r' + new string(' ', Console.WindowWidth) + '\r');
string[] words = message.Split(' ');
for (int i = 0; i < words.Length; i++)
{
ConsoleColor mentionColor = ConsoleColor.Black;
if (IsUri(words[i]))
{
mentionColor = ConsoleColor.DarkCyan;
}
foreach (DiscordUser user in discordMessage.MentionedUsers)
{
if (user?.Mention is not null)
{
if (words[i].Contains(user.Mention))
{
words[i] = words[i].Replace(user.Mention, $"@{user.Username}#{user.Discriminator}");
mentionColor = ConsoleColor.Blue;
}
}
else
{
if (words[i].Contains("<@") && words[i].Contains('>'))
mentionColor = ConsoleColor.Blue;
}
}
foreach (DiscordChannel channel in discordMessage.MentionedChannels)
{
if (channel?.Mention is not null)
if (words[i].Contains(channel.Mention))
{
words[i] = words[i].Replace(channel.Mention, $"#{channel.Name}");
mentionColor = ConsoleColor.Blue;
}
}
foreach (DiscordRole role in discordMessage.MentionedRoles)
{
if (role?.Mention is not null)
if (words[i].Contains(role.Mention))
{
words[i] = words[i].Replace(role.Mention, $"@{role.Name}");
DiscordColor discordColor = role.Color;
mentionColor = ClosestConsoleColor(Color.FromArgb(discordColor.R, discordColor.G, discordColor.B));
}
}
ConsoleExt.Write(words[i] + " ", mentionColor == ConsoleColor.Black ? consoleColor : mentionColor);
}
ConsoleExt.Write(info, ConsoleColor.DarkGray);
if (newLine)
Console.WriteLine();
}
private bool IsUri(string input)
{
return Uri.TryCreate(input, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
}
private ConsoleColor ClosestConsoleColor(Color targetColor)
{
double minDif = double.MaxValue;
ConsoleColor bestColor = ConsoleColor.White;
foreach (ConsoleColor consoleColor in Enum.GetValues(typeof(ConsoleColor)))
{
Color color = Color.FromName(consoleColor.ToString());
var colorA = new Rgb
{
R = targetColor.R,
G = targetColor.G,
B = targetColor.B
};
var colorB = new Rgb
{
R = color.R,
G = color.G,
B = color.B
};
double diff = colorA.Compare(colorB, new Cie1976Comparison());
if (diff < minDif)
{
minDif = diff;
bestColor = consoleColor;
}
}
return bestColor;
}
}
}
-72
View File
@@ -1,72 +0,0 @@
using DSharpPlus;
using Stone_Red_Utilities.ColorConsole;
using System.IO;
using System.Threading.Tasks;
using System;
namespace DiscordCLI
{
internal class Program
{
public static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
private DiscordClient client;
private InputManager inputManager;
private OutputManager outputManager;
private CommandsManager commandsManager;
public const string tokenPath = "token.txt";
public async Task MainAsync()
{
Console.ForegroundColor = ConsoleColor.White;
Console.OutputEncoding = System.Text.Encoding.UTF8;
string token = string.Empty;
if (File.Exists(tokenPath))
token = File.ReadAllText(tokenPath);
while (string.IsNullOrEmpty(token))
{
Console.Write("Enter auth token: ");
token = Console.ReadLine();
}
File.WriteAllText(tokenPath, token);
try
{
client = new DiscordClient(new DiscordConfiguration()
{
Token = token,
TokenType = TokenType.User,
});
client.MessageCreated += Client_MessageCreated;
await client.ConnectAsync();
}
catch (Exception ex)
{
ConsoleExt.WriteLine(ex, ConsoleColor.Red);
if (ex.Message.Contains("Authentication failed"))
File.Delete(tokenPath);
return;
}
outputManager = new OutputManager(client);
commandsManager = new CommandsManager(client, outputManager);
inputManager = new InputManager(client, commandsManager);
outputManager.InputManager = inputManager;
await inputManager.ReadInput();
}
private async Task Client_MessageCreated(DSharpPlus.EventArgs.MessageCreateEventArgs e)
{
await outputManager.WriteMessage(e.Message, e.Channel, e.Guild);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
@@ -1,9 +0,0 @@
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
{
"runtimeOptions": {
"additionalProbingPaths": [
"C:\\Users\\David\\.dotnet\\store\\|arch|\\|tfm|",
"C:\\Users\\David\\.nuget\\packages",
"C:\\Microsoft\\Xamarin\\NuGet"
]
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
c330ac1ec415f28e8dfa881f69ac743ee03b156f
Binary file not shown.
@@ -1 +0,0 @@
3e2c7be251ce3e62a6541dac29e1895e802a69f2
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
b19e6f37bddcbdb1df945fddaf2581ec8ab2932c
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
f577cd7c0c9371a4e25c13c1586e47e82f16d417
Binary file not shown.
@@ -1 +0,0 @@
3e2c7be251ce3e62a6541dac29e1895e802a69f2
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
8dbf5d9b5cf6fb65f2290f681f68bfa7a21560cd
@@ -1 +0,0 @@
c27366fe7586ce3c313a2245960fd7296c163460
@@ -1 +0,0 @@
70e9524befa3e92045c7c316dc8b56aab9375e23
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
8dbf5d9b5cf6fb65f2290f681f68bfa7a21560cd
+84 -1
View File
@@ -1,4 +1,87 @@
# DiscordCLI # DiscordCLI
> Use Discord in the terminal > Use Discord in the terminal
# README coming soon ## Warning
**Use this software at your own risk!**\
This isn't directly a selfbot, but Discord may count it as User account automation and this is against their TOS.\
I guess everything should be fine as long as you don't behave conspicuously but still proceed with caution!\
Currently there are no known cases where a user got banned for using this Discord client but that doesn't mean it will never happen.\
Don't blame me if you get banned!\
I will update the above if anything changes!
## Usage
1. [Download]("https://github.com/Stone-Red-Code/DiscordCLI/releases
) one of the releases
2. Execute the `DiscordCLI` file
3. Enter your [User Token](https://github.com/Tyrrrz/DiscordChatExporter/wiki/Obtaining-Token-and-Channel-IDs#how-to-get-a-user-token">)
4. Enter one of the commands below
## Commands
### help
- lists all commands
### exit
- exits application
### logout
- deletes auth token and exits application
### clear
- clears the console
### guilds
- lists all guilds you are in
### dms
- lists all private channels
### channels
- lists all channels of guild
- args: \<guild name/index>
### enterg
- enter guild
- args: \<guild name/index>
### enterc
- enter channel
- args: \<channel name/index>
### enterd
- enter DM channel
- args: \<channel name/index>
### userinfo
- gets information about a user
- args: \<user name>
## Limitations
DiscordCLI doesn't support everything the official Discord app does.
If you find a missing feature in DiscordCLI that is not listed below please tell me or create a pull request and update the list below.
### Current limitation
- No voice support
- Mentions can't be created easily
- You can't add/remove guilds
- You can't create/accept friend requests
- Discord online status not updating
And probably more.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+266
View File
@@ -0,0 +1,266 @@
using DSharpPlus.Entities;
using DSharpPlus;
using Stone_Red_Utilities.ConsoleExtentions;
using Stone_Red_Utilities.StringExtentions;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
using System.Threading.Tasks;
namespace DiscordCLI
{
internal class Commands
{
private readonly DiscordClient client;
private readonly OutputManager outputManager;
public Commands(DiscordClient dicordClient, OutputManager outputMan)
{
client = dicordClient;
outputManager = outputMan;
}
protected async Task ListGuilds(string args)
{
int index = 1;
foreach (DiscordGuild guild in client.Guilds.Values)
{
Console.WriteLine($"{index}. {guild.Name}");
index++;
}
await Task.CompletedTask;
}
protected async Task ListDms(string args)
{
int index = 1;
foreach (DiscordDmChannel dmChannel in client.PrivateChannels)
{
Console.WriteLine($"{index}. {string.Join(", ", dmChannel.Recipients.Select(x => x.Username))}");
index++;
}
await Task.CompletedTask;
}
protected async Task ListGuildChannels(string args)
{
IReadOnlyCollection<DiscordChannel> discordChannels;
DiscordGuild guild;
if (args != null)
{
if (int.TryParse(args, out int ind))
{
guild = client.Guilds?.Values.ElementAtOrDefault(ind - 1);
}
else
{
guild = client.Guilds?.FirstOrDefault(x => x.Value.Name == args).Value;
}
GlobalInformation.currentTextChannel = null;
}
else
{
guild = GlobalInformation.currentGuild;
}
if (guild is null)
{
ConsoleExt.WriteLine("Guild not found!", ConsoleColor.Red);
GlobalInformation.currentTextChannel = null;
return;
}
GlobalInformation.currentGuild = guild;
discordChannels = guild.Channels;
int index = 0;
foreach (DiscordChannel channel in discordChannels.OrderBy(x => x.Position))
{
if (channel.Type == ChannelType.Category)
{
Console.WriteLine();
Console.WriteLine($"--- {channel.Name} ---");
foreach (DiscordChannel child in channel.Children.OrderBy(x => x.Position))
{
if (child.Type == ChannelType.Text)
{
index++;
Console.WriteLine($"{index}. {child.Name}");
}
else
{
ConsoleExt.WriteLine($"-. {child.Name}", ConsoleColor.DarkGray);
}
}
}
}
await Task.CompletedTask;
}
protected async Task EnterChannel(string args)
{
DiscordChannel textChannel;
if (GlobalInformation.currentGuild is null)
{
ConsoleExt.WriteLine("You are not in a guild!", ConsoleColor.Red);
return;
}
if (int.TryParse(args, out int ind))
{
textChannel = GlobalInformation.currentGuild?.Channels.Where(x => x.Type == ChannelType.Text).OrderBy(x => x.Position).ElementAtOrDefault(ind - 1);
}
else
{
textChannel = GlobalInformation.currentGuild?.Channels.Where(x => x.Type == ChannelType.Text).OrderBy(x => x.Position).FirstOrDefault(x => x.Name == args);
}
GlobalInformation.currentTextChannel = textChannel;
if (textChannel is null)
{
ConsoleExt.WriteLine("Channel not found!", ConsoleColor.Red);
return;
}
try
{
foreach (DiscordMessage message in (textChannel.GetMessagesAsync(10).Result).Reverse())
{
await outputManager.WriteMessage(message, textChannel, false);
}
Console.CursorTop--;
}
catch (Exception ex)
{
ConsoleExt.WriteLine(ex.Message, ConsoleColor.Red);
GlobalInformation.currentTextChannel = null;
}
await Task.CompletedTask;
}
protected async Task EnterDmChannel(string args)
{
DiscordDmChannel dmChannel;
GlobalInformation.currentGuild = null;
if (int.TryParse(args, out int ind))
{
dmChannel = client.PrivateChannels.ElementAtOrDefault(ind - 1);
}
else
{
dmChannel = client.PrivateChannels.FirstOrDefault(x => x.Name == args);
}
GlobalInformation.currentTextChannel = dmChannel;
if (dmChannel is null)
{
ConsoleExt.WriteLine("Channel not found!", ConsoleColor.Red);
return;
}
try
{
foreach (DiscordMessage message in (await dmChannel.GetMessagesAsync(10)).Reverse())
{
await outputManager.WriteMessage(message, dmChannel, false);
}
}
catch (Exception ex)
{
ConsoleExt.WriteLine(ex.Message, ConsoleColor.Red);
GlobalInformation.currentTextChannel = null;
}
}
protected async Task DeleteToken(string args)
{
File.Delete(Program.tokenPath);
Environment.Exit(0);
await Task.CompletedTask;
}
protected async Task UserInfo(string userName)
{
if (GlobalInformation.currentGuild is null)
{
ConsoleExt.WriteLine("You are not in a guild!", ConsoleColor.Red);
return;
}
if (userName is null)
{
ConsoleExt.WriteLine("User not found!", ConsoleColor.Red);
return;
}
DiscordUser discordUser = await GetDiscordUser(userName);
string status = discordUser?.Presence?.Status.ToString();
status ??= "N/A";
if (discordUser is DiscordMember discordMember)
{
string infoString =
$"Username: {discordMember.Username}#{discordMember.Discriminator}" + Environment.NewLine +
$"Nickname: {discordMember.Nickname ?? "N/A"}" + Environment.NewLine +
$"Roles: {string.Join(", ", discordMember.Roles.Select(x => x.Name))}" + Environment.NewLine +
$"Status: {status}" + Environment.NewLine +
$"Created at: {discordMember.CreationTimestamp}" + Environment.NewLine +
$"ID: {discordMember.Id}" + Environment.NewLine +
$"Bot: {discordMember.IsBot}";
Console.WriteLine(infoString);
}
else if (discordUser is not null)
{
string infoString =
$"Username: {discordUser.Username}#{discordUser.Discriminator}" + Environment.NewLine +
$"Status: {status}" + Environment.NewLine +
$"Created at: {discordUser.CreationTimestamp}" + Environment.NewLine +
$"ID: {discordUser.Id}" + Environment.NewLine +
$"Bot: {discordUser.IsBot}";
Console.WriteLine(infoString);
}
else
{
ConsoleExt.WriteLine("User not found!", ConsoleColor.Red);
}
async Task<DiscordUser> GetDiscordUser(string name)
{
DiscordUser discordUser = GlobalInformation.currentGuild?.Members?.FirstOrDefault(user => user.Username.EqualsIgnoreSpacesAndCase(userName));
discordUser ??= GlobalInformation.currentGuild?.Members?.FirstOrDefault(user => $"{user.Username}#{user.Discriminator}".EqualsIgnoreSpacesAndCase(userName));
discordUser ??= GlobalInformation.currentGuild?.Members?.FirstOrDefault(user => $"{user.Username}".EqualsIgnoreSpacesAndCase(userName));
discordUser ??= GlobalInformation.currentGuild?.Members?.FirstOrDefault(user => $"{user.Nickname}".EqualsIgnoreSpacesAndCase(userName));
if (discordUser is null)
{
IReadOnlyList<DiscordUser> users = await GlobalInformation.currentGuild.GetAllMembersAsync();
discordUser ??= users.FirstOrDefault(user => user.Username.EqualsIgnoreSpacesAndCase(userName));
discordUser ??= users.FirstOrDefault(user => $"{user.Username}#{user.Discriminator}".EqualsIgnoreSpacesAndCase(userName));
discordUser ??= users.FirstOrDefault(user => $"{user.Username}".EqualsIgnoreSpacesAndCase(userName));
}
return discordUser;
}
}
protected async Task Clear(string args)
{
Console.Clear();
await Task.CompletedTask;
}
}
}
+124
View File
@@ -0,0 +1,124 @@
using DSharpPlus;
using Stone_Red_Utilities.ConsoleExtentions;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Timers;
using System.Threading.Tasks;
namespace DiscordCLI
{
internal class CommandsManager : Commands
{
private readonly DiscordClient client;
private readonly Dictionary<string, (string, Func<string, Task>)> CommandsList;
private int cooldown = 0;
public CommandsManager(DiscordClient dicordClient, OutputManager outputManager) : base(dicordClient, outputManager)
{
client = dicordClient;
CommandsList = new()
{
{ "exit", ("exits application", null) },
{ "logout", ("deletes auth token and exits application", DeleteToken) },
{ "clear", ("clears the console", Clear) },
{ "guilds", ("lists all guilds you are in", ListGuilds) },
{ "dms", ("lists all private channels", ListDms) },
{ "channels", ("lists all channels of guild args:<guild name/index>", ListGuildChannels) },
{ "enterg", ("enter guild args:<guild name/index>", ListGuildChannels) },
{ "enterc", ("enter channel args:<channel name/index>", EnterChannel) },
{ "enterd", ("enter DM channel args:<channel name/index>", EnterDmChannel) },
{ "userinfo", ("gets information about a user args:<username>", UserInfo) },
};
Timer cooldownTimer = new Timer(1000);
cooldownTimer.Elapsed += CooldownTimer_Elapsed;
cooldownTimer.Start();
}
private void CooldownTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (cooldown > 0)
cooldown--;
}
/// <summary>
/// Check the command and return true if the program should exit
/// </summary>
/// <param name="input"></param>
/// <returns>exit bool and write override bool</returns>
public async Task<(bool, bool)> CheckCommand(string rawInput)
{
string input = rawInput.Trim().ToLower().Replace('\n', '\0');
if (string.IsNullOrWhiteSpace(input.StartsWith(InputManager.Prefix) ? input.Remove(0, 1) : input))
{
Console.CursorTop--;
return (false, false);
}
cooldown++;
if (cooldown > 1)
{
Console.WriteLine();
ConsoleExt.WriteLine("You are beeing rate limited!", ConsoleColor.Yellow);
ConsoleExt.WriteLine("Wait a few seconds before making another request!", ConsoleColor.Yellow);
return (false, true);
}
if (input.StartsWith(InputManager.Prefix))
{
input = input.Remove(0, 1);
}
else if (GlobalInformation.currentTextChannel != null)
{
cooldown++;
try
{
await GlobalInformation.currentTextChannel.SendMessageAsync(rawInput);
Console.CursorTop--;
Console.Write("\r" + new string(' ', Console.WindowWidth));
}
catch (Exception ex)
{
Console.WriteLine();
ConsoleExt.WriteLine(ex.Message, ConsoleColor.Red);
}
return (false, true);
}
Console.WriteLine();
if (input == "exit" || input is null)
return (true, false);
string args = input.Contains(" ") ? input[input.IndexOf(" ")..].Trim() : null;
input = input.Contains(" ") ? input.Substring(0, input.IndexOf(" ")) : input;
if (input == "help" || input == "?")
{
Console.WriteLine($"Prefix: '{InputManager.Prefix}' (Only required in text channels)");
Console.WriteLine();
for (int i = 0; i < CommandsList.Count; i++)
{
Console.Write($"{i + 1}. {CommandsList.Keys.ElementAt(i)}".PadRight(15));
Console.WriteLine(CommandsList.Values.ElementAt(i).Item1);
}
}
else if (CommandsList.ContainsKey(input))
{
await CommandsList[input].Item2(args);
}
else
{
ConsoleExt.WriteLine("Command does not exist!", ConsoleColor.Red);
}
return (false, false);
}
}
}
@@ -1,14 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>0.0.5.0</AssemblyVersion>
<FileVersion>0.0.5.0</FileVersion>
<Version>0.0.5.0</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AlwaysUpToDate" Version="1.0.0.4" />
<PackageReference Include="ColorMineStandard" Version="1.0.0" /> <PackageReference Include="ColorMineStandard" Version="1.0.0" />
<PackageReference Include="DSharpPlus" Version="3.2.3" /> <PackageReference Include="DSharpPlus" Version="3.2.3" />
<PackageReference Include="Stone_Red-C-Sharp-Utilities" Version="1.0.0.2" /> <PackageReference Include="Stone_Red-C-Sharp-Utilities" Version="1.0.2.1" />
</ItemGroup> </ItemGroup>
</Project> <ItemGroup>
<Folder Include="Properties\PublishProfiles\" />
</ItemGroup>
</Project>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<_LastSelectedProfileId>C:\Users\David\Google Drive\Programmieren\DiscordCLI\DiscordCLI\Properties\PublishProfiles\Linux-x64.pubxml</_LastSelectedProfileId> <_LastSelectedProfileId>C:\Users\David\Programmieren\DiscordCLI\src\DiscordCLI\Properties\PublishProfiles\Linux-ARM.pubxml</_LastSelectedProfileId>
</PropertyGroup> </PropertyGroup>
</Project> </Project>
+99
View File
@@ -0,0 +1,99 @@
using DSharpPlus;
using System.Threading.Tasks;
using System;
using DSharpPlus.Entities;
using System.Linq;
using System.Collections.Generic;
namespace DiscordCLI
{
internal class InputManager
{
private readonly CommandsManager commandsManager;
private readonly DiscordClient client;
private readonly List<string> previousInputs = new List<string>();
public const string Prefix = ">";
public string Input { get; private set; } = string.Empty;
public InputManager(DiscordClient dicordClient, CommandsManager commandsMan)
{
client = dicordClient;
commandsManager = commandsMan;
}
public async Task ReadInput()
{
int inputListIndex = 0;
bool exit = false;
bool printOverride = false;
string lastInput = Prefix;
while (!exit)
{
DiscordDmChannel dmChannel = GlobalInformation.currentTextChannel as DiscordDmChannel;
string infoString = $"\r[{client.CurrentUser.Username}#{client.CurrentUser.Discriminator}] [{(dmChannel is null ? GlobalInformation.currentGuild?.Name : "DMs")}/{(dmChannel is null ? GlobalInformation.currentTextChannel?.Name : string.Join(", ", dmChannel.Recipients.Select(x => x.Username)))}] ==> ";
if (lastInput.StartsWith(Prefix) || printOverride)
Console.Write(Environment.NewLine + infoString);
printOverride = false;
ConsoleKeyInfo keyInfo;
do
{
keyInfo = Console.ReadKey(true);
if (!char.IsControl(keyInfo.KeyChar))
Input += keyInfo.KeyChar.ToString();
if (keyInfo.Key == ConsoleKey.Backspace && Input.Length > 0)
{
Input = Input.Remove(Input.Length - 1);
}
else if (keyInfo.Key == ConsoleKey.UpArrow)
{
if (previousInputs.Count > 0)
Input = previousInputs[previousInputs.Count - inputListIndex - 1];
if (inputListIndex < previousInputs.Count - 1)
inputListIndex++;
Console.CursorLeft = infoString.Length - 1;
Console.Write(Input + new string(' ', Console.WindowWidth - infoString.Length - 1));
}
else if (keyInfo.Key == ConsoleKey.DownArrow)
{
if (previousInputs.Count > 0)
Input = previousInputs[previousInputs.Count - inputListIndex - 1];
if (inputListIndex > 0)
inputListIndex--;
Console.CursorLeft = infoString.Length - 1;
Console.Write(Input + new string(' ', Console.WindowWidth - infoString.Length - 1));
}
Console.Write(keyInfo.KeyChar);
if (keyInfo.Key == ConsoleKey.Backspace)
Console.Write(" ");
Console.CursorLeft = infoString.Length + Input.Length - 1;
} while (keyInfo.Key != ConsoleKey.Enter);
if (GlobalInformation.currentTextChannel == null)
{
Input = Input.Trim();
if (!Input.StartsWith(Prefix))
Input = Prefix + Input;
if (previousInputs.Count > 10)
previousInputs.RemoveAt(0);
if (previousInputs.Count == 0 || previousInputs[previousInputs.Count - 1] != Input)
previousInputs.Add(new string(Input));
}
inputListIndex = 0;
lastInput = new string(Input);
Input = string.Empty;
(exit, printOverride) = await commandsManager.CheckCommand(lastInput);
}
}
}
}
+227
View File
@@ -0,0 +1,227 @@
using ColorMine.ColorSpaces.Comparisons;
using ColorMine.ColorSpaces;
using DSharpPlus.Entities;
using DSharpPlus;
using Stone_Red_Utilities.ConsoleExtentions;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace DiscordCLI
{
internal class OutputManager
{
private readonly DiscordClient client;
public InputManager InputManager { get; set; }
public OutputManager(DiscordClient discordClient)
{
client = discordClient;
}
public async Task WriteMessage(DiscordMessage message, DiscordChannel channel, bool writeInfo = true)
{
try
{
if (message.ChannelId != GlobalInformation.currentTextChannel?.Id)
return;
DiscordUser user = message.Author;
if (GlobalInformation.currentGuild is not null)
{
DiscordMember discordMember = await channel.Guild.GetMemberAsync(user.Id);
DiscordColor discordColor = discordMember.Color;
Color color = Color.FromArgb(discordColor.R, discordColor.G, discordColor.B);
WriteTop($"[{discordMember.DisplayName}]", color, message, true, true, $"{discordMember.Username}#{discordMember.Discriminator} {message.Timestamp.LocalDateTime}");
}
else
{
WriteTop($"[{user.Username}]", Color.White, message, true, true, $"{user.Username}#{user.Discriminator} {message.Timestamp.LocalDateTime}");
}
if (!string.IsNullOrWhiteSpace(message.Content))
WriteTop(message.Content, Color.White, message);
foreach (DiscordAttachment attachment in message.Attachments)
{
WriteTop($"{attachment.Url}", Color.White, message, true, true, attachment.FileName);
}
foreach (DiscordEmbed embed in message.Embeds)
{
if (!string.IsNullOrWhiteSpace(embed.Title))
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{{{embed.Title}}}", Color.White, message, false);
}
if (!string.IsNullOrWhiteSpace(embed.Description))
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{embed.Description}", Color.White, message, false);
}
if (embed.Fields is not null)
{
foreach (DiscordEmbedField field in embed.Fields)
{
WriteTop(">>> ", Color.FromArgb(embed.Color.Value), message, true, false);
WriteTop($"{field.Name}{Environment.NewLine}{field.Value}", Color.White, message, false);
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
WriteTop(string.Empty, Color.White, message);
DiscordDmChannel dmChannel = GlobalInformation.currentTextChannel as DiscordDmChannel;
if (writeInfo)
{
string infoString = $"\r[{client.CurrentUser.Username}#{client.CurrentUser.Discriminator}] [{(dmChannel is null ? GlobalInformation.currentGuild?.Name : "DMs")}/{(dmChannel is null ? GlobalInformation.currentTextChannel?.Name : string.Join(", ", dmChannel.Recipients.Select(x => x.Username)))}] ==> ";
Console.Write(infoString);
Console.Write(InputManager.Input);
}
}
private void WriteTop(string message, Color color, DiscordMessage discordMessage, bool removeText = true, bool newLine = true, string info = null)
{
if (removeText)
Console.Write('\r' + new string(' ', Console.WindowWidth) + '\r');
foreach (Match match in Regex.Matches(message, "<@(.*?)>"))
{
foreach (DiscordUser user in discordMessage.MentionedUsers)
{
if (user?.Mention is not null)
{
if (match.Value == user.Mention.Replace("!", string.Empty))
{
message = message.Replace(match.Value, $"\0<C{(int)ConsoleColor.Blue}C>@{user.Username}#{user.Discriminator}\0");
}
}
else
{
if (ulong.TryParse(match.Value.Replace("!", string.Empty).Replace("<@", string.Empty).Replace(">", string.Empty), out ulong id))
{
DiscordUser discordUser = client.GetUserAsync(id).Result;
message = message.Replace(match.Value, $"\0<C{(int)ConsoleColor.Blue}C>@{discordUser.Username}#{discordUser.Discriminator}\0");
}
}
}
}
foreach (Match match in Regex.Matches(message, "<#(.*?)>"))
{
foreach (DiscordChannel channel in discordMessage.MentionedChannels)
{
if (channel?.Mention is not null)
{
if (match.Value == channel.Mention)
{
message = message.Replace(match.Value, $"\0<C{(int)ConsoleColor.Blue}C>#{channel.Name}\0");
}
}
else
{
if (ulong.TryParse(match.Value.Replace("<#", string.Empty).Replace(">", string.Empty), out ulong id))
{
DiscordChannel discordChannel = client.GetChannelAsync(id).Result;
message = message.Replace(match.Value, $"\0<C{(int)ConsoleColor.Blue}C>#{discordChannel.Name}\0");
}
}
}
}
foreach (Match match in Regex.Matches(message, @"<@&(.*?)>"))
{
foreach (DiscordRole role in discordMessage.MentionedRoles)
{
if (role?.Mention is not null)
{
if (match.Value == role.Mention)
{
DiscordColor discordColor = role.Color;
message = message.Replace(match.Value, $"\0<C{(int)ClosestConsoleColor(Color.FromArgb(discordColor.R, discordColor.G, discordColor.B))}C>@{role.Name}\0");
}
}
}
}
foreach (Match match in Regex.Matches(message, @"((https?)\:\/\/|www.)[A-Za-z0-9\.\-\&\#\?\/]*", RegexOptions.IgnoreCase))
{
message = message.Replace(match.Value, $"\0<C{(int)ConsoleColor.Blue}C>{match.Value}\0");
}
foreach (string part in message.Split("\0"))
{
ConsoleColor consoleColor;
string messagePart = part;
string stringColor = Regex.Match(messagePart, "(?<=(<C))(.*)(?=C>)").Value;
bool succ = int.TryParse(stringColor, out int colorIndex);
if (succ && colorIndex >= 0 && colorIndex < 16)
{
messagePart = messagePart.Replace($"<C{stringColor}C>", string.Empty);
consoleColor = (ConsoleColor)colorIndex;
}
else
{
consoleColor = ClosestConsoleColor(color);
}
if (consoleColor == Console.BackgroundColor || consoleColor == ConsoleColor.DarkGray)
consoleColor = ConsoleColor.White;
ConsoleExt.Write(messagePart, consoleColor);
}
ConsoleExt.Write($" {info}", ConsoleColor.DarkGray);
if (newLine)
Console.WriteLine();
}
private ConsoleColor ClosestConsoleColor(Color targetColor)
{
double minDif = double.MaxValue;
ConsoleColor closestColor = ConsoleColor.White;
foreach (ConsoleColor consoleColor in Enum.GetValues(typeof(ConsoleColor)))
{
Color color = Color.FromName(consoleColor.ToString());
var colorA = new Rgb
{
R = targetColor.R,
G = targetColor.G,
B = targetColor.B
};
var colorB = new Rgb
{
R = color.R,
G = color.G,
B = color.B
};
double diff = colorA.Compare(colorB, new Cie1976Comparison());
if (diff < minDif)
{
minDif = diff;
closestColor = consoleColor;
}
}
return closestColor;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiscordCLI
{
internal enum PlatformType
{
Windows,
Linux,
LinuxARM
}
}
+151
View File
@@ -0,0 +1,151 @@
using DSharpPlus;
using System.IO;
using System.Threading.Tasks;
using System;
using DSharpPlus.Exceptions;
using Stone_Red_Utilities.ConsoleExtentions;
using AlwaysUpToDate;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DiscordCLI
{
internal class Program
{
public const string tokenPath = "token.txt";
private DiscordClient client;
private CommandsManager commandsManager;
private InputManager inputManager;
private OutputManager outputManager;
private Updater updater;
public static void Main() => new Program().Setup().GetAwaiter().GetResult();
private async Task Setup()
{
Console.ForegroundColor = ConsoleColor.White;
Console.OutputEncoding = System.Text.Encoding.UTF8;
PlatformType platformType;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm || RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
platformType = PlatformType.LinuxARM;
}
else
{
platformType = PlatformType.Linux;
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
platformType = PlatformType.Windows;
}
else
{
throw new PlatformNotSupportedException("DiscordCLI only supports Windows and Linux!");
}
#if DEBUG
updater = new Updater(new TimeSpan(0), $"https://raw.githubusercontent.com/Stone-Red-Code/DiscordCLI/develop/update/updateInfo{platformType}.json", "./", true);
#else
updater = new Updater(new TimeSpan(0), $"https://raw.githubusercontent.com/Stone-Red-Code/DiscordCLI/main/update/updateInfo{platformType}.json", "./", true);
#endif
updater.UpdateAvailible += Updater_UpdateAvailible;
updater.NoUpdateAvailible += Updater_NoUpdateAvailible;
updater.ProgressChanged += Updater_ProgressChanged;
updater.OnException += Updater_OnException;
updater.Start();
await Task.Delay(-1);
}
private async Task Start()
{
string token = string.Empty;
if (File.Exists(tokenPath))
token = File.ReadAllText(tokenPath);
tokenInput:
while (string.IsNullOrWhiteSpace(token))
{
Console.Write("Enter auth token: ");
token = Console.ReadLine();
}
File.WriteAllText(tokenPath, token);
try
{
client = new DiscordClient(new DiscordConfiguration()
{
Token = token,
TokenType = TokenType.User,
});
client.MessageCreated += Client_MessageCreated;
await client.ConnectAsync();
ConsoleExt.WriteLine("Welcome to DiscordCLI", ConsoleColor.Green);
}
catch (Exception ex)
{
ConsoleExt.WriteLine(ex.Message, ConsoleColor.Red);
if (ex.InnerException is UnauthorizedException)
{
File.Delete(tokenPath);
token = string.Empty;
goto tokenInput;
}
return;
}
outputManager = new OutputManager(client);
commandsManager = new CommandsManager(client, outputManager);
inputManager = new InputManager(client, commandsManager);
outputManager.InputManager = inputManager;
await inputManager.ReadInput();
Environment.Exit(0);
}
private async void Updater_NoUpdateAvailible()
{
await Start();
}
private void Updater_ProgressChanged(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage)
{
Console.CursorLeft = 0;
ConsoleExt.WriteLine($"Downloading update: {progressPercentage}% {totalBytesDownloaded}/{totalFileSize}", ConsoleColor.Yellow);
}
private void Updater_UpdateAvailible(string version, string additionalInformation)
{
Console.WriteLine($"New version avalible! {version}");
updater.Update();
}
private void Updater_OnException(Exception exception)
{
ConsoleExt.WriteLine("Update failed!", ConsoleColor.Red);
ConsoleExt.WriteLine(exception.Message, ConsoleColor.Red);
Environment.Exit(-1);
}
private async Task Client_MessageCreated(DSharpPlus.EventArgs.MessageCreateEventArgs e)
{
try
{
await outputManager.WriteMessage(e.Message, e.Channel);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net5.0\publish\Linux-ARM</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>linux-arm</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
</PropertyGroup>
</Project>
@@ -3,4 +3,7 @@
https://go.microsoft.com/fwlink/?LinkID=208121. https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<History>True|2021-08-06T17:06:56.0342838Z;</History>
</PropertyGroup>
</Project> </Project>
@@ -3,4 +3,7 @@
https://go.microsoft.com/fwlink/?LinkID=208121. https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<History>True|2021-08-06T17:03:25.0377279Z;</History>
</PropertyGroup>
</Project> </Project>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<History>True|2021-08-06T17:08:23.2338085Z;True|2021-08-06T19:06:28.4841484+02:00;True|2021-05-29T18:25:28.6698849+02:00;True|2021-05-29T17:53:55.7039453+02:00;True|2021-05-29T17:07:22.9610987+02:00;True|2021-05-29T16:21:45.0240481+02:00;</History>
</PropertyGroup>
</Project>
Binary file not shown.
@@ -6,16 +6,28 @@
"compilationOptions": {}, "compilationOptions": {},
"targets": { "targets": {
".NETCoreApp,Version=v5.0": { ".NETCoreApp,Version=v5.0": {
"DiscordCLI/1.0.0": { "DiscordCLI/0.0.5.0": {
"dependencies": { "dependencies": {
"AlwaysUpToDate": "1.0.0.4",
"ColorMineStandard": "1.0.0", "ColorMineStandard": "1.0.0",
"DSharpPlus": "3.2.3", "DSharpPlus": "3.2.3",
"Stone_Red-C-Sharp-Utilities": "1.0.0.2" "Stone_Red-C-Sharp-Utilities": "1.0.2.1"
}, },
"runtime": { "runtime": {
"DiscordCLI.dll": {} "DiscordCLI.dll": {}
} }
}, },
"AlwaysUpToDate/1.0.0.4": {
"dependencies": {
"System.Text.Json": "5.0.2"
},
"runtime": {
"lib/netstandard2.1/AlwaysUpToDate.dll": {
"assemblyVersion": "1.0.0.4",
"fileVersion": "1.0.0.4"
}
}
},
"ColorMineStandard/1.0.0": { "ColorMineStandard/1.0.0": {
"runtime": { "runtime": {
"lib/netstandard2.0/ColorMineStandard.dll": { "lib/netstandard2.0/ColorMineStandard.dll": {
@@ -186,11 +198,11 @@
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {}, "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {},
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {}, "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {},
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {}, "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.2": {},
"Stone_Red-C-Sharp-Utilities/1.0.0.2": { "Stone_Red-C-Sharp-Utilities/1.0.2.1": {
"runtime": { "runtime": {
"lib/netstandard2.1/Stone_Red-C-Sharp-Utilities.dll": { "lib/netstandard2.1/Stone_Red-C-Sharp-Utilities.dll": {
"assemblyVersion": "1.0.0.2", "assemblyVersion": "1.0.2.1",
"fileVersion": "1.0.0.2" "fileVersion": "1.0.2.1"
} }
} }
}, },
@@ -903,6 +915,14 @@
"System.Text.Encoding": "4.3.0" "System.Text.Encoding": "4.3.0"
} }
}, },
"System.Text.Json/5.0.2": {
"runtime": {
"lib/netcoreapp3.0/System.Text.Json.dll": {
"assemblyVersion": "5.0.0.0",
"fileVersion": "5.0.521.16609"
}
}
},
"System.Text.RegularExpressions/4.3.0": { "System.Text.RegularExpressions/4.3.0": {
"dependencies": { "dependencies": {
"System.Runtime": "4.3.0" "System.Runtime": "4.3.0"
@@ -993,11 +1013,18 @@
} }
}, },
"libraries": { "libraries": {
"DiscordCLI/1.0.0": { "DiscordCLI/0.0.5.0": {
"type": "project", "type": "project",
"serviceable": false, "serviceable": false,
"sha512": "" "sha512": ""
}, },
"AlwaysUpToDate/1.0.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-A/9hqxN8bKsambpkv6klWlRNFZ4gt5bQeO0ciBSx/tYrD6guTU8KzNNdjuvKV7AEBTObbchbEpr+kbC1/JpqYA==",
"path": "alwaysuptodate/1.0.0.4",
"hashPath": "alwaysuptodate.1.0.0.4.nupkg.sha512"
},
"ColorMineStandard/1.0.0": { "ColorMineStandard/1.0.0": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
@@ -1173,12 +1200,12 @@
"path": "runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl/4.3.2", "path": "runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl/4.3.2",
"hashPath": "runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.2.nupkg.sha512" "hashPath": "runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.2.nupkg.sha512"
}, },
"Stone_Red-C-Sharp-Utilities/1.0.0.2": { "Stone_Red-C-Sharp-Utilities/1.0.2.1": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
"sha512": "sha512-/oH1XweI6G2VjeXuutq3XhHAPiSpotfPnsRMK0n8BXFOqG85y0AXQGaKiEdhCZZOpLHFrNY8rtLepMgLJrsY9w==", "sha512": "sha512-QzwH0QvsDiBvCJTFroZBhN/pMEIiz0C8TNkQci+pxCbnjfTtVkxAYsgmlshCl5oHFJh7VYDLcGAULcMBARSb+w==",
"path": "stone_red-c-sharp-utilities/1.0.0.2", "path": "stone_red-c-sharp-utilities/1.0.2.1",
"hashPath": "stone_red-c-sharp-utilities.1.0.0.2.nupkg.sha512" "hashPath": "stone_red-c-sharp-utilities.1.0.2.1.nupkg.sha512"
}, },
"System.AppContext/4.3.0": { "System.AppContext/4.3.0": {
"type": "package", "type": "package",
@@ -1614,6 +1641,13 @@
"path": "system.text.encoding.extensions/4.3.0", "path": "system.text.encoding.extensions/4.3.0",
"hashPath": "system.text.encoding.extensions.4.3.0.nupkg.sha512" "hashPath": "system.text.encoding.extensions.4.3.0.nupkg.sha512"
}, },
"System.Text.Json/5.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==",
"path": "system.text.json/5.0.2",
"hashPath": "system.text.json.5.0.2.nupkg.sha512"
},
"System.Text.RegularExpressions/4.3.0": { "System.Text.RegularExpressions/4.3.0": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
"additionalProbingPaths": [ "additionalProbingPaths": [
"C:\\Users\\David\\.dotnet\\store\\|arch|\\|tfm|", "C:\\Users\\David\\.dotnet\\store\\|arch|\\|tfm|",
"C:\\Users\\David\\.nuget\\packages", "C:\\Users\\David\\.nuget\\packages",
"C:\\Microsoft\\Xamarin\\NuGet" "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
] ]
} }
} }

Some files were not shown because too many files have changed in this diff Show More