KasinoBot/Music.cs

165 lines
5.4 KiB
C#
Raw Permalink Normal View History

2022-12-10 18:49:16 +00:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord;
using Discord.Audio;
using Discord.WebSocket;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace KasinoBot
{
public class Music
{
private IAudioClient AudioClient { get; set; }
private ISocketMessageChannel TextChannel { get; set; }
private Queue<MusicInfo> Queue { get; }
private Stream? CurrentMusicStream { get; set; }
private Process? CurrentFFmpeg { get; set; }
private AudioOutStream? CurrentOuAudio { get; set; }
public Music(SocketGuild guild, ISocketMessageChannel channel, IAudioClient audioClient)
{
Queue = new Queue<MusicInfo>();
TextChannel = channel;
AudioClient = audioClient;
}
public async Task Play(string query, SocketUser user, SocketUserMessage message)
{
if (message.Channel != null)
TextChannel = message.Channel;
MusicInfo musicInfo = new MusicInfo(query, user);
//await message.AddReactionAsync(Emoji.Parse("👌"));
await TextChannel.SendMessageAsync($"Enqueued **\"{musicInfo.Title}\"** *({musicInfo.Duration})*");
Queue.Enqueue(musicInfo);
if (Queue.Count == 1)
await PlayNextMusic();
}
public async Task Stop()
{
Queue.Clear();
if (CurrentMusicStream != null)
CurrentMusicStream.Close();
await Task.Delay(10);
}
public async Task Skip()
{
Console.WriteLine("Skipping");
if (CurrentMusicStream != null)
CurrentMusicStream.Close();
await Task.Delay(10);
}
private async Task PlayNextMusic()
{
if (Queue.Count == 0)
return;
try
{
var musicInfo = Queue.Peek();
using (var input = AudioClient.CreatePCMStream(AudioApplication.Music))
using (CurrentFFmpeg = CreateAudioStream(musicInfo.MediaURL))
using (CurrentMusicStream = CurrentFFmpeg.StandardOutput.BaseStream)
{
try
{
await CurrentMusicStream.CopyToAsync(input);
}
catch (Exception ex)
{
Console.WriteLine("Error CopyToAsync: " + ex.ToString());
}
finally
{
Queue.Dequeue();
await input.FlushAsync();
}
}
}
catch (Exception e)
{
await TextChannel.SendMessageAsync($"Error: {e.Message}");
Console.WriteLine(e);
}
await PlayNextMusic();
}
private Process CreateAudioStream(string path)
{
var p = 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,
});
if (p == null)
throw new Exception("Could not start ffmpeg. Please make sure ffmpeg is available.");
else if (p.HasExited)
throw new Exception("ffmpeg exited with code " + p.ExitCode);
return p;
}
}
public class MusicInfo
{
public string Query { get; }
public SocketUser User { get; }
public string Title { get; set; }
public string Duration { get; set; }
public string MediaURL { get; set; }
public string YoutubeURL { get; set; }
public MusicInfo(string query, SocketUser user)
{
Query = query;
User = user;
var p = Process.Start(new ProcessStartInfo
{
FileName = "youtube-dl",
Arguments = $"-f bestaudio --dump-json --default-search \"ytsearch\" -g \"{this.Query}\"",
UseShellExecute = false,
RedirectStandardOutput = true,
});
if (p == null)
throw new Exception("Could not start youtube-dl. Please make sure youtube-dl is available.");
else if (p.HasExited)
throw new Exception("youtube-dl exited with code " + p.ExitCode);
var output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
try
{
JToken json = JObject.Parse(output.Split('\n')[1]);
if (json == null)
throw new Exception("Could not parse youtube-dl output.");
int duration = int.Parse(json["duration"].ToString());
this.MediaURL = output.Split('\n')[0];
this.Title = json["title"].ToString();
this.YoutubeURL = json["webpage_url"].ToString();
this.Duration = $"{Math.Floor((float)duration / 60)}m {duration % 60}s";
}
catch (Exception e)
{
throw new Exception("Error parsing information from Youtube-DL: " + e.Message);
}
}
}
}