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

@@ -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 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)
{
Data.CurrentlyRunning.Stop();
Data.CurrentlyRunning = null;
Data.Playlist.ClearQueue();
Data.MusicPlayer.isPlaying = false;
await Data.audioClient.StopAsync();
await Data.voiceChannel.DisconnectAsync();
}

View File

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

View File

@@ -9,110 +9,93 @@ namespace MusicCommands;
internal class MusicPlayer
{
public MusicPlayer(Stream input, Stream output)
private Stream outputStream { get; }
internal bool isPlaying, isPaused;
public MusicPlayer(Stream outputChannel)
{
inputStream = input;
outputStream = output;
outputStream = outputChannel;
}
public MusicPlayer(Stream output)
public async Task Play(Stream source, int byteSize)
{
inputStream = null;
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 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)
isPlaying = true;
while (isPlaying)
{
await Task.Delay(1000);
Console.Title = "Reading data: " + ms.Length + " bytes read of " + bsize * 10;
Console.Write(".");
}
if (isPaused)
continue;
Console.WriteLine("\nDone");
ms.Position = 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
var bits = new byte[byteSize];
var read = await source.ReadAsync(bits, 0, byteSize);
if (read == 0)
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
{
await outputStream.WriteAsync(buffer, 0, bcount);
await outputStream.WriteAsync(bits, 0, read);
}
catch (Exception ex)
catch
{
await outputStream.FlushAsync();
Functions.WriteLogFile(ex.ToString());
break;
}
}
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 Description => "Pause the music";
public string Description => "Pause/Unpause the music that is currently running";
public string Usage => "pause";
@@ -20,6 +20,6 @@ internal class Pause : DBCommand
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.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Discord;
using Discord.Audio;
using Discord.Commands;
@@ -42,28 +41,47 @@ internal class Play : DBCommand
return;
}
string url = splitted[1];
var 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);
{
Data.Playlist.Enqueue(new AudioFile(path, null));
}
else
{
var file = new AudioFile(path, url);
await file.DownloadAudioFile();
Data.Playlist.Enqueue(file);
}
}
else
{
string searchString = Functions.MergeStrings(splitted, 1);
var searchString = splitted.MergeStrings(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);
{
Data.Playlist.Enqueue(new AudioFile(path, null));
}
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);
Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel;
if (Data.voiceChannel == null)
@@ -72,16 +90,29 @@ internal class Play : DBCommand
return;
}
Data.audioClient = await Data.voiceChannel.ConnectAsync(true);
using (var ffmpeg = CreateStream(path))
using (var output = ffmpeg.StandardOutput.BaseStream)
using (var discord = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
if (Data.audioClient is null)
{
if (Data.CurrentlyRunning != null) Data.CurrentlyRunning.Stop();
Data.CurrentlyRunning = new MusicPlayer(output, discord);
await Data.CurrentlyRunning.StartSendAudio();
Data.audioClient = await Data.voiceChannel.ConnectAsync(true);
Data.MusicPlayer = null;
}
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 });
}
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");
}
}
}