Music Commands

This commit is contained in:
2022-07-09 14:57:49 +03:00
parent aa808e950a
commit 47aae730c7
15 changed files with 259 additions and 159 deletions

View File

@@ -6,13 +6,13 @@
"compilationOptions": {}, "compilationOptions": {},
"targets": { "targets": {
".NETCoreApp,Version=v6.0": { ".NETCoreApp,Version=v6.0": {
"MusicCommands/1.0.0": { "Music Commands/1.0.0": {
"dependencies": { "dependencies": {
"PluginManager": "1.0.0", "PluginManager": "1.0.0",
"YoutubeExplode": "6.2.0" "YoutubeExplode": "6.2.0"
}, },
"runtime": { "runtime": {
"MusicCommands.dll": {} "Music Commands.dll": {}
} }
}, },
"AngleSharp/0.17.0": { "AngleSharp/0.17.0": {
@@ -187,7 +187,7 @@
} }
}, },
"libraries": { "libraries": {
"MusicCommands/1.0.0": { "Music Commands/1.0.0": {
"type": "project", "type": "project",
"serviceable": false, "serviceable": false,
"sha512": "" "sha512": ""

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>bin\</BaseOutputPath> <BaseOutputPath></BaseOutputPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1,34 @@
using AngleSharp.Dom;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MusicCommands
{
internal class AudioFile
{
internal string Name { get; set; }
internal string Url { get; set; }
internal AudioFile(string name, string url)
{
Name = name;
Url = url;
}
internal async Task DownloadAudioFile()
{
Process proc = new Process();
proc.StartInfo.FileName = "MusicDownloader.exe";
proc.StartInfo.Arguments = $"{Url},{Name}";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
await proc.WaitForExitAsync();
}
}
}

View File

@@ -8,5 +8,6 @@ internal static class Data
internal static IAudioClient audioClient = null; internal static IAudioClient audioClient = null;
internal static IVoiceChannel voiceChannel = null; internal static IVoiceChannel voiceChannel = null;
internal static MusicPlayer CurrentlyRunning = null; internal static MusicPlayer MusicPlayer = null;
internal static MusicPlaylist Playlist = new();
} }

View File

@@ -22,8 +22,8 @@ internal class Leave : DBCommand
{ {
if (Data.audioClient is not null && Data.voiceChannel is not null) if (Data.audioClient is not null && Data.voiceChannel is not null)
{ {
Data.CurrentlyRunning.Stop(); Data.Playlist.ClearQueue();
Data.CurrentlyRunning = null; Data.MusicPlayer.isPlaying = false;
await Data.audioClient.StopAsync(); await Data.audioClient.StopAsync();
await Data.voiceChannel.DisconnectAsync(); await Data.voiceChannel.DisconnectAsync();
} }

View File

@@ -4,6 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>warnings</Nullable> <Nullable>warnings</Nullable>
<BaseOutputPath>bin\</BaseOutputPath> <BaseOutputPath>bin\</BaseOutputPath>
<AssemblyName>Music Commands</AssemblyName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -9,110 +9,93 @@ namespace MusicCommands;
internal class MusicPlayer internal class MusicPlayer
{ {
public MusicPlayer(Stream input, Stream output) private Stream outputStream { get; }
internal bool isPlaying, isPaused;
public MusicPlayer(Stream outputChannel)
{ {
inputStream = input; outputStream = outputChannel;
outputStream = output;
} }
public MusicPlayer(Stream output) public async Task Play(Stream source, int byteSize)
{ {
inputStream = null; isPlaying = true;
outputStream = output; while (isPlaying)
}
public Stream inputStream { get; } // from FFMPEG
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 StartSendAudioFromLink(string URL)
{
/* using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(URL))
using (var content = response.Content)
{
await (await content.ReadAsStreamAsync()).CopyToAsync(outputStream);
}*/
Stream ms = new MemoryStream();
var bsize = 512;
new Thread(async delegate(object o)
{
var response = await new HttpClient().GetAsync(URL);
using (var stream = await response.Content.ReadAsStreamAsync())
{
var buffer = new byte[bsize];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var pos = ms.Position;
ms.Position = ms.Length;
ms.Write(buffer, 0, read);
ms.Position = pos;
}
}
}
).Start();
Console.Write("Reading data: ");
while (ms.Length < bsize * 10)
{ {
await Task.Delay(1000); if (isPaused)
Console.Title = "Reading data: " + ms.Length + " bytes read of " + bsize * 10; continue;
Console.Write(".");
}
Console.WriteLine("\nDone"); var bits = new byte[byteSize];
ms.Position = 0; var read = await source.ReadAsync(bits, 0, byteSize);
if (read == 0)
_stop = false;
Paused = false;
while (!_stop)
{
if (Paused) continue;
var buffer = new byte[bsize];
var read = await ms.ReadAsync(buffer, 0, buffer.Length);
if (read > 0)
await outputStream.WriteAsync(buffer, 0, read);
else
break; break;
}
}
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 try
{ {
await outputStream.WriteAsync(buffer, 0, bcount); await outputStream.WriteAsync(bits, 0, read);
} }
catch (Exception ex) catch
{ {
await outputStream.FlushAsync(); break;
Functions.WriteLogFile(ex.ToString());
} }
} }
await source.FlushAsync();
await source.DisposeAsync();
source.Close();
await outputStream.FlushAsync();
isPlaying = false;
} }
/*
public MusicPlayer(Stream input, Stream output)
{
inputStream = input;
outputStream = output;
}
public Stream inputStream { get; } // from FFMPEG
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(int bsize)
{
Paused = false;
_stop = false;
while (!_stop)
{
if (Paused) continue;
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();
Functions.WriteLogFile(ex.ToString());
}
}
}*/
} }

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MusicCommands
{
internal class MusicPlaylist
{
internal MusicPlaylist()
{
Console.WriteLine("Initialized playlist.");
}
public Queue<AudioFile> QueueList = new();
public void Enqueue(AudioFile query) => QueueList.Enqueue(query);
public void ClearQueue() => QueueList.Clear();
public int Count => QueueList.Count;
public AudioFile GetNextSong => QueueList.Dequeue();
public AudioFile WhatIsNext => QueueList.Peek();
}
}

View File

@@ -8,7 +8,7 @@ internal class Pause : DBCommand
{ {
public string Command => "pause"; public string Command => "pause";
public string Description => "Pause the music"; public string Description => "Pause/Unpause the music that is currently running";
public string Usage => "pause"; public string Usage => "pause";
@@ -20,6 +20,6 @@ internal class Pause : DBCommand
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{ {
Data.CurrentlyRunning.Paused = true; Data.MusicPlayer.isPaused = !Data.MusicPlayer.isPaused;
} }
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Discord; using Discord;
using Discord.Audio; using Discord.Audio;
using Discord.Commands; using Discord.Commands;
@@ -42,28 +41,47 @@ internal class Play : DBCommand
return; return;
} }
string url = splitted[1]; var url = splitted[1];
path += $"{Functions.CreateMD5(url)}"; path += $"{Functions.CreateMD5(url)}";
if (File.Exists(path)) if (File.Exists(path))
break; {
//await context.Channel.SendMessageAsync("Searching for " + url); Data.Playlist.Enqueue(new AudioFile(path, null));
await GetMusicAudio(url, path); }
//await context.Channel.SendMessageAsync("Playing: " + url); else
{
var file = new AudioFile(path, url);
await file.DownloadAudioFile();
Data.Playlist.Enqueue(file);
}
} }
else else
{ {
string searchString = Functions.MergeStrings(splitted, 1); var searchString = splitted.MergeStrings(1);
path += $"{Functions.CreateMD5(searchString)}"; path += $"{Functions.CreateMD5(searchString)}";
if (File.Exists(path)) if (File.Exists(path))
break; {
await context.Channel.SendMessageAsync("Searching for " + searchString); Data.Playlist.Enqueue(new AudioFile(path, null));
await GetMusicAudio(searchString, path); }
await context.Channel.SendMessageAsync("Playing: " + searchString); else
{
await context.Channel.SendMessageAsync("Searching for " + searchString);
var file = new AudioFile(path, searchString);
await file.DownloadAudioFile();
Data.Playlist.Enqueue(file);
if (Data.MusicPlayer is null)
await context.Channel.SendMessageAsync("Playing: " + searchString);
}
}
if (Data.MusicPlayer is not null)
{
await context.Channel.SendMessageAsync("Enqueued your request");
return;
} }
} }
while (false); while (false);
Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel; Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel;
if (Data.voiceChannel == null) if (Data.voiceChannel == null)
@@ -72,16 +90,29 @@ internal class Play : DBCommand
return; return;
} }
Data.audioClient = await Data.voiceChannel.ConnectAsync(true); if (Data.audioClient is null)
using (var ffmpeg = CreateStream(path))
using (var output = ffmpeg.StandardOutput.BaseStream)
using (var discord = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
{ {
if (Data.CurrentlyRunning != null) Data.CurrentlyRunning.Stop(); Data.audioClient = await Data.voiceChannel.ConnectAsync(true);
Data.CurrentlyRunning = new MusicPlayer(output, discord); Data.MusicPlayer = null;
await Data.CurrentlyRunning.StartSendAudio(); }
using (var discordChanneAudioOutStream = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
{
if (Data.MusicPlayer is null)
Data.MusicPlayer = new MusicPlayer(discordChanneAudioOutStream);
while (Data.Playlist.Count > 0)
{
var nowPlaying = Data.Playlist.GetNextSong;
using (var ffmpeg = CreateStream(nowPlaying.Name))
using (var ffmpegOutputBaseStream = ffmpeg.StandardOutput.BaseStream)
{
await Data.MusicPlayer.Play(ffmpegOutputBaseStream, 1024);
Console.WriteLine("Finished playing from" + nowPlaying.Name);
}
}
Data.MusicPlayer = null;
} }
} }
@@ -89,16 +120,4 @@ 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 }); 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();
}
} }

31
MusicCommands/Skip.cs Normal file
View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands
{
public class Skip : DBCommand
{
public string Command => "skip";
public string Description => "skip the music that is currently running";
public string Usage => "skip";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
Data.MusicPlayer.isPlaying = false;
}
}
}

View File

@@ -1,25 +0,0 @@
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands;
internal class Unpause : DBCommand
{
public string Command => "unpause";
public string Description => "Unpause the music";
public string Usage => "unpause";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
Data.CurrentlyRunning.Paused = false;
}
}

31
MusicCommands/queue.cs Normal file
View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands
{
public class queue : DBCommand
{
public string Command => "queue";
public string Description => "check queue";
public string Usage => "queue";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
await context.Channel.SendMessageAsync($"You have {Data.Playlist.Count} items in queue");
}
}
}