diff --git a/.idea/.idea.SethDiscordBot/.idea/.gitignore b/.idea/.idea.SethDiscordBot/.idea/.gitignore new file mode 100644 index 0000000..7fa1cfe --- /dev/null +++ b/.idea/.idea.SethDiscordBot/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/contentModel.xml +/.idea.SethDiscordBot.iml +/modules.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/BUILDS/net6.0/MusicCommands.deps.json b/BUILDS/net6.0/MusicCommands.deps.json index bf027a3..1c91428 100644 --- a/BUILDS/net6.0/MusicCommands.deps.json +++ b/BUILDS/net6.0/MusicCommands.deps.json @@ -8,12 +8,25 @@ ".NETCoreApp,Version=v6.0": { "MusicCommands/1.0.0": { "dependencies": { - "PluginManager": "1.0.0" + "PluginManager": "1.0.0", + "YoutubeExplode": "6.2.0" }, "runtime": { "MusicCommands.dll": {} } }, + "AngleSharp/0.17.0": { + "dependencies": { + "System.Buffers": "4.5.1", + "System.Text.Encoding.CodePages": "5.0.0" + }, + "runtime": { + "lib/netstandard2.0/AngleSharp.dll": { + "assemblyVersion": "0.17.0.0", + "fileVersion": "0.17.0.0" + } + } + }, "Discord.Net/3.7.2": { "dependencies": { "Discord.Net.Commands": "3.7.2", @@ -108,6 +121,7 @@ } } }, + "Microsoft.NETCore.Platforms/5.0.0": {}, "Newtonsoft.Json/13.0.1": { "runtime": { "lib/netstandard2.0/Newtonsoft.Json.dll": { @@ -116,6 +130,7 @@ } } }, + "System.Buffers/4.5.1": {}, "System.Collections.Immutable/5.0.0": {}, "System.Interactive.Async/5.0.0": { "dependencies": { @@ -144,7 +159,23 @@ } } }, + "System.Text.Encoding.CodePages/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0" + } + }, "System.ValueTuple/4.5.0": {}, + "YoutubeExplode/6.2.0": { + "dependencies": { + "AngleSharp": "0.17.0" + }, + "runtime": { + "lib/net5.0/YoutubeExplode.dll": { + "assemblyVersion": "6.2.0.0", + "fileVersion": "6.2.0.0" + } + } + }, "PluginManager/1.0.0": { "dependencies": { "Discord.Net": "3.7.2" @@ -161,6 +192,13 @@ "serviceable": false, "sha512": "" }, + "AngleSharp/0.17.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-74haoXINcj4SdMsmiNzk+9VUwIX1U9P61O6AZd5Uao8SGNnJJB8Y/r8VJRc8orn4c7Vk/oURAKSNF9XcSDxbfA==", + "path": "anglesharp/0.17.0", + "hashPath": "anglesharp.0.17.0.nupkg.sha512" + }, "Discord.Net/3.7.2": { "type": "package", "serviceable": true, @@ -217,6 +255,13 @@ "path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0", "hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512" }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, "Newtonsoft.Json/13.0.1": { "type": "package", "serviceable": true, @@ -224,6 +269,13 @@ "path": "newtonsoft.json/13.0.1", "hashPath": "newtonsoft.json.13.0.1.nupkg.sha512" }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, "System.Collections.Immutable/5.0.0": { "type": "package", "serviceable": true, @@ -252,6 +304,13 @@ "path": "system.reactive/5.0.0", "hashPath": "system.reactive.5.0.0.nupkg.sha512" }, + "System.Text.Encoding.CodePages/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NyscU59xX6Uo91qvhOs2Ccho3AR2TnZPomo1Z0K6YpyztBPM/A5VbkzOO19sy3A3i1TtEnTxA7bCe3Us+r5MWg==", + "path": "system.text.encoding.codepages/5.0.0", + "hashPath": "system.text.encoding.codepages.5.0.0.nupkg.sha512" + }, "System.ValueTuple/4.5.0": { "type": "package", "serviceable": true, @@ -259,6 +318,13 @@ "path": "system.valuetuple/4.5.0", "hashPath": "system.valuetuple.4.5.0.nupkg.sha512" }, + "YoutubeExplode/6.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oH5kst4w1QkUwRjJco0alF57JOmFofSGlPkr4OniODB8R6MEyRWn1xFg3JS2wFYd6scZluoXRDhM3/uyUjO9/g==", + "path": "youtubeexplode/6.2.0", + "hashPath": "youtubeexplode.6.2.0.nupkg.sha512" + }, "PluginManager/1.0.0": { "type": "project", "serviceable": false, diff --git a/BUILDS/net6.0/MusicCommands.dll b/BUILDS/net6.0/MusicCommands.dll index 19a1e1a..729722c 100644 Binary files a/BUILDS/net6.0/MusicCommands.dll and b/BUILDS/net6.0/MusicCommands.dll differ diff --git a/BUILDS/net6.0/PluginManager.dll b/BUILDS/net6.0/PluginManager.dll index bb6f20f..b57de9d 100644 Binary files a/BUILDS/net6.0/PluginManager.dll and b/BUILDS/net6.0/PluginManager.dll differ diff --git a/BUILDS/net6.0/Plugins/Commands/MusicCommands.dll b/BUILDS/net6.0/Plugins/Commands/MusicCommands.dll index b690a8c..729722c 100644 Binary files a/BUILDS/net6.0/Plugins/Commands/MusicCommands.dll and b/BUILDS/net6.0/Plugins/Commands/MusicCommands.dll differ diff --git a/MusicCommands/MusicCommands.csproj b/MusicCommands/MusicCommands.csproj index 9bd106b..b7b4a53 100644 --- a/MusicCommands/MusicCommands.csproj +++ b/MusicCommands/MusicCommands.csproj @@ -17,4 +17,8 @@ + + + + diff --git a/MusicCommands/Play.cs b/MusicCommands/Play.cs index 0e9b181..eb6d73d 100644 --- a/MusicCommands/Play.cs +++ b/MusicCommands/Play.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading.Tasks; using Discord; using Discord.Audio; using Discord.Commands; @@ -12,11 +13,11 @@ namespace MusicCommands; internal class Play : DBCommand { - public string Command => "fplay"; + public string Command => "play"; public string Description => "Play music from a file"; - public string Usage => "fplay [name]"; + public string Usage => "fplay [name/url]"; public bool canUseDM => false; @@ -26,14 +27,42 @@ internal class Play : DBCommand public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) { - var path = "./Music"; - var FileName = Functions.GetArguments(message).ToArray().MergeStrings(0); - path += "/" + FileName + ".ogg"; - if (!File.Exists(path)) - { - Console.WriteLine("Unknown path " + path); + Directory.CreateDirectory("Music"); + var path = "./Music/"; + string[] splitted = message.Content.Split(' '); + if (splitted.Length < 2) return; + do + { + if (splitted.Length == 2) + { + if (!splitted[1].Contains("youtube.com")) + { + await context.Channel.SendMessageAsync("Invalid link"); + return; + } + + string url = splitted[1]; + path += $"{Functions.CreateMD5(url)}"; + if (File.Exists(path)) + break; + //await context.Channel.SendMessageAsync("Searching for " + url); + await GetMusicAudio(url, path); + //await context.Channel.SendMessageAsync("Playing: " + url); + } + else + { + string searchString = Functions.MergeStrings(splitted, 1); + path += $"{Functions.CreateMD5(searchString)}"; + + if (File.Exists(path)) + break; + await context.Channel.SendMessageAsync("Searching for " + searchString); + await GetMusicAudio(searchString, path); + await context.Channel.SendMessageAsync("Playing: " + searchString); + } } + while (false); Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel; @@ -59,4 +88,16 @@ internal class Play : DBCommand { return Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1", UseShellExecute = false, RedirectStandardOutput = true }); } + + private async Task GetMusicAudio(string url, string location) + { + Process proc = new Process(); + proc.StartInfo.FileName = "MusicDownloader.exe"; + proc.StartInfo.Arguments = $"{url},{location}"; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.RedirectStandardOutput = true; + + proc.Start(); + await proc.WaitForExitAsync(); + } } diff --git a/MusicCommands/lplay.cs b/MusicCommands/lplay.cs deleted file mode 100644 index 6adb117..0000000 --- a/MusicCommands/lplay.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Discord; -using Discord.Audio; -using Discord.Commands; -using Discord.WebSocket; -using PluginManager.Interfaces; - -namespace MusicCommands; - -internal class lplay : DBCommand -{ - public string Command => "lplay"; - - public string Description => "Play music from a link"; - - public string Usage => "lplay [url]"; - - public bool canUseDM => false; - - public bool canUseServer => false; - - public bool requireAdmin => false; - - public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) - { - var URL = message.Content.Split(' ')[1]; - if (!URL.EndsWith(".mp3") && !URL.EndsWith(".wav") && !URL.EndsWith(".flac") && !URL.EndsWith(".ogg")) - { - await message.Channel.SendMessageAsync("Invalid URL"); - return; - } - - Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel; - if (Data.voiceChannel == null) - { - await context.Channel.SendMessageAsync("User must be in a voice channel, or a voice channel must be passed as an argument."); - return; - } - - Data.audioClient = await Data.voiceChannel.ConnectAsync(); - - using (var discord = Data.audioClient.CreatePCMStream(AudioApplication.Mixed)) - { - await message.Channel.SendMessageAsync("Loading..."); - - Data.CurrentlyRunning = new MusicPlayer(discord); - await Data.CurrentlyRunning.StartSendAudioFromLink(URL); - } - } -} diff --git a/PluginManager/Items/ConsoleCommandsHandler.cs b/PluginManager/Items/ConsoleCommandsHandler.cs index 9e22455..48d5bde 100644 --- a/PluginManager/Items/ConsoleCommandsHandler.cs +++ b/PluginManager/Items/ConsoleCommandsHandler.cs @@ -22,7 +22,7 @@ public class ConsoleCommandsHandler { this.client = client; InitializeBasicCommands(); - Console.WriteLine("Initialized console command handler !"); + //Console.WriteLine("Initialized console command handler !"); } private void InitializeBasicCommands() @@ -128,9 +128,10 @@ public class ConsoleCommandsHandler string path; if (info[0] == "Command" || info[0] == "Event") - path = "./Data/Plugins/" + info[0] + "s/" + name + ".dll"; + path = "./Data/Plugins/" + info[0] + "s/" + name + "." + (info[0] == "Command" ? PluginLoader.pluginCMDExtension : PluginLoader.pluginEVEExtension); else path = $"./{info[1].Split('/')[info[1].Split('/').Length - 1]}"; + //Console.WriteLine("Downloading: " + path + " [" + info[1] + "]"); await ServerCom.DownloadFileAsync(info[1], path); if (info[0] == "Command" || info[0] == "Event") if (info[0] == "Event") @@ -156,27 +157,32 @@ public class ConsoleCommandsHandler await ServerCom.DownloadFileAsync(split[0], "./" + split[1]); Console.WriteLine(); - if (split[0].EndsWith(".zip")) + if (split[0].EndsWith(".zip") || split[0].EndsWith(".pak") || split[0].EndsWith(".pkg")) { Console.WriteLine($"Extracting {split[1]}"); - var proc = 0d; + var proc = 0f; var isExtracting = true; - var bar = new Console_Utilities.ProgressBar { Max = 100, Color = ConsoleColor.Green }; + var bar = new Console_Utilities.ProgressBar { Max = 100f, Color = ConsoleColor.Green }; - IProgress extractProgress = new Progress(value => { proc = value; }); + IProgress extractProgress = new Progress(value => + { + proc = value; + } + ); new Thread(new Task(() => { while (isExtracting) { - bar.Update((int)proc); - if (proc >= 99.9f) break; + bar.Update(proc); + if (proc >= 99.9f) + isExtracting = false; Thread.Sleep(500); } } ).Start ).Start(); - await Functions.ExtractArchive("./" + split[1], "./", extractProgress); - bar.Update(100); + await Functions.ExtractArchive("./" + split[1], "./", extractProgress, UnzipProgressType.PercentageFromTotalSize); + bar.Update(100f); isExtracting = false; await Task.Delay(1000); bar.Update(100); diff --git a/PluginManager/Others/Console Utilities.cs b/PluginManager/Others/Console Utilities.cs index 00dc30a..a3de752 100644 --- a/PluginManager/Others/Console Utilities.cs +++ b/PluginManager/Others/Console Utilities.cs @@ -10,12 +10,12 @@ namespace PluginManager.Others /// public class ProgressBar { - public int Max { get; init; } + public float Max { get; init; } public ConsoleColor Color { get; init; } public bool NoColor { get; init; } - public void Update(int progress, double speed = -1, string? unit = null) + public void Update(float progress, double speed = -1, string? unit = null) { Console.CursorLeft = 0; Console.Write("["); @@ -146,6 +146,9 @@ namespace PluginManager.Others Console.Write(m + " "); } + + Console.CursorLeft--; + if (appendNewLine) Console.Write('\n'); diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index c516802..6ace192 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -26,4 +26,6 @@ public enum OutputLogLevel { NONE, INFO, WARNING, ERROR, CRITICAL } /// /// Plugin Type /// -public enum PluginType { Command, Event, Unknown } \ No newline at end of file +public enum PluginType { Command, Event, Unknown } + +public enum UnzipProgressType { PercentageFromNumberOfFiles, PercentageFromTotalSize } \ No newline at end of file diff --git a/PluginManager/Others/Functions.cs b/PluginManager/Others/Functions.cs index 38bba1d..d88caf3 100644 --- a/PluginManager/Others/Functions.cs +++ b/PluginManager/Others/Functions.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; using System.Linq; using System.Collections.Generic; +using System.Security.Cryptography; using Discord.WebSocket; using PluginManager.Items; using System.Threading; @@ -169,33 +170,69 @@ namespace PluginManager.Others /// /// The zip location /// The target location + /// The progress that is updated as a file is processed + /// The type of progress /// - public static async Task ExtractArchive(string zip, string folder, IProgress progress) + public static async Task ExtractArchive(string zip, string folder, IProgress progress, UnzipProgressType type) { if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); using (ZipArchive archive = ZipFile.OpenRead(zip)) { - int totalZIPFiles = archive.Entries.Count(); - int currentZIPFile = 0; - foreach (ZipArchiveEntry entry in archive.Entries) + if (type == UnzipProgressType.PercentageFromNumberOfFiles) { - if (entry.FullName.EndsWith("/")) - Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); + int totalZIPFiles = archive.Entries.Count(); + int currentZIPFile = 0; + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith("/")) + Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); + + else + try + { + entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}"); + } + + currentZIPFile++; + await Task.Delay(10); + progress.Report((float)currentZIPFile / totalZIPFiles * 100); + } + } + else if (type == UnzipProgressType.PercentageFromTotalSize) + { + ulong zipSize = 0; + + foreach (ZipArchiveEntry entry in archive.Entries) + zipSize += (ulong)entry.CompressedLength; + + ulong currentSize = 0; + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith("/")) + { + Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); + continue; + } - else try { entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); + currentSize += (ulong)entry.CompressedLength; } - catch + catch (Exception ex) { + Console.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}"); } - currentZIPFile++; - await Task.Delay(10); - progress.Report((float)currentZIPFile / totalZIPFiles * 100); + await Task.Delay(10); + progress.Report((float)currentSize / zipSize * 100); + } } } } @@ -303,5 +340,15 @@ namespace PluginManager.Others var data = jsonObject.RootElement.TryGetProperty(codeName, out element); return data; } + + public static string CreateMD5(string input) + { + using (MD5 md5 = MD5.Create()) + { + byte[] inputBytes = Encoding.ASCII.GetBytes(input); + byte[] hashBytes = md5.ComputeHash(inputBytes); + return Convert.ToHexString(hashBytes); + } + } } } diff --git a/YoutubeExtension/Others/Data.cs b/YoutubeExtension/Others/Data.cs deleted file mode 100644 index ef50961..0000000 --- a/YoutubeExtension/Others/Data.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Discord; -using Discord.Audio; - -namespace YoutubeExtension.Downloader; - -internal static class Data -{ - internal static IAudioClient audioClient = null; - internal static IVoiceChannel voiceChannel = null; - - internal static MusicPlayer CurrentlyRunning = null; -} diff --git a/YoutubeExtension/Others/MusicPlayer.cs b/YoutubeExtension/Others/MusicPlayer.cs deleted file mode 100644 index bfbafd9..0000000 --- a/YoutubeExtension/Others/MusicPlayer.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace YoutubeExtension.Downloader; - -internal class MusicPlayer -{ - public MusicPlayer(Stream input, Stream output) - { - inputStream = input; - outputStream = output; - } - - public Stream inputStream { get; } // from outside - public Stream outputStream { get; } // to Voice Channel - - public bool Paused { get; set; } - private bool _stop { get; set; } - - public void Stop() - { - _stop = true; - } - - public async Task StartSendAudio() - { - Paused = false; - _stop = false; - while (!_stop) - { - if (Paused) continue; - var bsize = 512; - var buffer = new byte[bsize]; - var bcount = await inputStream.ReadAsync(buffer, 0, bsize); - if (bcount <= 0) - { - Stop(); - Data.CurrentlyRunning = null; - break; - } - - try - { - await outputStream.WriteAsync(buffer, 0, bcount); - } - catch (Exception ex) - { - await outputStream.FlushAsync(); - PluginManager.Others.Functions.WriteLogFile(ex.ToString()); - } - } - } -} diff --git a/YoutubeExtension/Others/YTVideo.cs b/YoutubeExtension/Others/YTVideo.cs deleted file mode 100644 index 36bc4f9..0000000 --- a/YoutubeExtension/Others/YTVideo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MediaToolkit; -using MediaToolkit.Model; -using VideoLibrary; - -namespace YoutubeExtension.Downloader; - -public class YoutubeHandler -{ - - public static async Task GetVideoStream(string videoURL) - { - var youtube = YouTube.Default; - var video = await youtube.GetVideoAsync(videoURL); - - return await video.StreamAsync(); - - } -} diff --git a/YoutubeExtension/YoutubeExtension.csproj b/YoutubeExtension/YoutubeExtension.csproj deleted file mode 100644 index eb2460e..0000000 --- a/YoutubeExtension/YoutubeExtension.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net6.0 - enable - enable - - - diff --git a/YoutubeExtension/ytPlay.cs b/YoutubeExtension/ytPlay.cs deleted file mode 100644 index 8e71e2a..0000000 --- a/YoutubeExtension/ytPlay.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace YoutubeExtension; - -public class ytPlay -{ - -}