Removed music plugin
This commit is contained in:
@@ -1,94 +0,0 @@
|
||||
|
||||
using Discord;
|
||||
using DiscordBotCore.Networking;
|
||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.Commands;
|
||||
|
||||
public class AddMelody: IDbCommand
|
||||
{
|
||||
public string Command => "add_melody";
|
||||
|
||||
public List<string>? Aliases => new()
|
||||
{
|
||||
"madd"
|
||||
};
|
||||
|
||||
public string Description => "Add a custom melody to the database";
|
||||
public string Usage => "add_melody [title],[description?],[aliases],[byteSize]";
|
||||
public bool RequireAdmin => false;
|
||||
|
||||
public async void ExecuteServer(IDbCommandExecutingArgument args)
|
||||
{
|
||||
var arguments = string.Join(" ", args.Arguments);
|
||||
string[] split = arguments.Split(',');
|
||||
|
||||
if (split.Length < 4)
|
||||
{
|
||||
var message = "";
|
||||
message += "Invalid arguments given. Please use the following format:\n";
|
||||
message += "add_melody [title],[description?],[aliases],[byteSize]\n";
|
||||
message += "title: The title of the melody\n";
|
||||
message += "description: The description of the melody\n";
|
||||
message += "aliases: The aliases of the melody. Use | to separate them\n";
|
||||
message += "byteSize: The byte size of the melody. Default is 1024. ( & will use default)\n";
|
||||
|
||||
await args.Context.Channel.SendMessageAsync(message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Context.Message.Attachments.Count == 0)
|
||||
{
|
||||
await args.Context.Channel.SendMessageAsync("You must upload a valid .mp3 audio or .mp4 video file !!");
|
||||
return;
|
||||
}
|
||||
|
||||
var file = args.Context.Message.Attachments.FirstOrDefault();
|
||||
if (!(file.Filename.EndsWith(".mp3") || file.Filename.EndsWith(".mp4")))
|
||||
{
|
||||
await args.Context.Channel.SendMessageAsync("Invalid file format !!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var title = split[0];
|
||||
var description = split[1];
|
||||
string[]? aliases = split[2]?.Split('|') ?? null;
|
||||
var byteSize = split[3];
|
||||
int bsize;
|
||||
if (!int.TryParse(byteSize, out bsize))
|
||||
bsize = 1024;
|
||||
|
||||
|
||||
var msg = await args.Context.Channel.SendMessageAsync("Saving melody ...");
|
||||
Console.WriteLine("Saving melody");
|
||||
|
||||
IProgress<float> downloadProgress = new Progress<float>();
|
||||
|
||||
var melodiesDirectory = Path.Combine(args.PluginBaseDirectory.FullName, "Music/Melodies");
|
||||
var fileLocation = Path.Combine(melodiesDirectory, $"{title}.mp3");
|
||||
Directory.CreateDirectory(melodiesDirectory);
|
||||
FileDownloader downloader = new FileDownloader(file.Url, fileLocation);
|
||||
await downloader.DownloadFile(downloadProgress.Report);
|
||||
|
||||
args.Logger.Log($"Melody downloaded. Saved at {fileLocation}", this);
|
||||
await msg.ModifyAsync(a => a.Content = "Done");
|
||||
|
||||
|
||||
var info = MusicInfoExtensions.CreateMusicInfo(title, fileLocation, description ?? "Unknown", aliases.ToList(), bsize);
|
||||
|
||||
Variables._MusicDatabase.Add(title, info);
|
||||
|
||||
var builder = new EmbedBuilder();
|
||||
builder.Title = "A new music was successfully added !";
|
||||
builder.AddField("Title", info.Title);
|
||||
builder.AddField("Description", info.Description);
|
||||
builder.AddField("Aliases", string.Join(" | ", aliases));
|
||||
await args.Context.Channel.SendMessageAsync(embed: builder.Build());
|
||||
|
||||
await Variables._MusicDatabase.SaveToFile();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace MusicPlayer.Commands;
|
||||
|
||||
public class AddMelodyYoutube: IDbCommand
|
||||
{
|
||||
public string Command => "add_melody_youtube";
|
||||
|
||||
public List<string>? Aliases => new()
|
||||
{
|
||||
"madd-yt"
|
||||
};
|
||||
|
||||
public string Description => "Add melody to the database from a youtube link";
|
||||
public string Usage => "add_melody_youtube [URL] <alias1|alias2|...>";
|
||||
public bool RequireAdmin => true;
|
||||
|
||||
public async void ExecuteServer(DbCommandExecutingArguments args)
|
||||
{
|
||||
|
||||
if(Variables._MusicDatabase is null)
|
||||
{
|
||||
await args.Context.Channel.SendMessageAsync("Music Database is not loaded !");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Arguments is null)
|
||||
{
|
||||
await args.Context.Channel.SendMessageAsync("Invalid arguments given. Please use the following format:\nadd_melody_youtube [URL]");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var url = args.Arguments[0];
|
||||
|
||||
if (!url.StartsWith("https://www.youtube.com/watch?v=") && !url.StartsWith("https://youtu.be/"))
|
||||
{
|
||||
await args.Context.Channel.SendMessageAsync("Invalid URL given. Please use the following format:\nadd_melody_youtube [URL]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Arguments.Length <= 1)
|
||||
{
|
||||
await args.Channel.SendMessageAsync("Please specify at least one alias for the melody !");
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = await args.Context.Channel.SendMessageAsync("Saving melody ...");
|
||||
|
||||
string musicId = Guid.NewGuid().ToString();
|
||||
string? title = await YoutubeDlp.GetMusicTitle(url);
|
||||
|
||||
if(title is null)
|
||||
{
|
||||
await msg.ModifyAsync(x => x.Content = "Failed to retrieve music title from the provided URL.");
|
||||
return;
|
||||
}
|
||||
|
||||
await YoutubeDlp.DownloadMelody(url, musicId);
|
||||
|
||||
var joinedAliases = string.Join(" ", args.Arguments.Skip(1));
|
||||
List<string> aliases = joinedAliases.Split('|').ToList();
|
||||
|
||||
|
||||
if (Variables._MusicDatabase.GetMusicInfoWithTitleOrAlias(title).Any())
|
||||
{
|
||||
await msg.ModifyAsync(x => x.Content = "Melody already exists !");
|
||||
return;
|
||||
}
|
||||
|
||||
Variables._MusicDatabase.Add(title, new MusicInfo()
|
||||
{
|
||||
Aliases = aliases,
|
||||
ByteSize = 1024,
|
||||
Description = "Melody added from youtube link",
|
||||
Location = Application.GetResourceFullPath($"Music/Melodies/{musicId}.mp3"),
|
||||
Title = title
|
||||
}
|
||||
);
|
||||
|
||||
await Variables._MusicDatabase.SaveToFile();
|
||||
await msg.ModifyAsync(x => x.Content = "Melody saved !");
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using Discord;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace MusicPlayer.Commands;
|
||||
|
||||
public class SearchMelody: IDbCommand
|
||||
{
|
||||
|
||||
public string Command => "search_melody";
|
||||
public List<string>? Aliases => null;
|
||||
public string Description => "Search for a melody in the database";
|
||||
public string Usage => "search_melody [melody name OR one of its aliases]";
|
||||
public bool RequireAdmin => false;
|
||||
|
||||
public void ExecuteServer(DbCommandExecutingArguments args)
|
||||
{
|
||||
|
||||
if(Variables._MusicDatabase is null)
|
||||
{
|
||||
args.Context.Channel.SendMessageAsync("Music Database is not loaded !");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Arguments is null || args.Arguments.Length == 0)
|
||||
{
|
||||
args.Context.Channel.SendMessageAsync("You need to specify a melody name");
|
||||
return;
|
||||
}
|
||||
|
||||
var title = string.Join(" ", args.Arguments);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(title))
|
||||
{
|
||||
args.Context.Channel.SendMessageAsync("You need to specify a melody name");
|
||||
return;
|
||||
}
|
||||
|
||||
List<MusicInfo> info = Variables._MusicDatabase.GetMusicInfoWithTitleOrAlias(title);
|
||||
if (!info.Any())
|
||||
{
|
||||
args.Context.Channel.SendMessageAsync("No melody with that name or alias was found");
|
||||
return;
|
||||
}
|
||||
|
||||
args.Context.Channel.SendMessageAsync(embed: info.Count > 1 ? info.ToEmbed(Color.DarkOrange) : info[0].ToEmbed(Color.DarkOrange));
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Discord.WebSocket;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.Events;
|
||||
|
||||
public class OnLoad: IDbEvent
|
||||
{
|
||||
private static readonly string _DefaultMusicPath = "Music/";
|
||||
private static readonly string _DefaultSaveLocation = "Music/Melodies/";
|
||||
private static readonly string _DefaultMusicDB = "Music/music_db.json";
|
||||
public string Name => "Music Commands";
|
||||
public string Description => "The default music commands event loader";
|
||||
|
||||
public async void Start(DiscordSocketClient client)
|
||||
{
|
||||
var path1 = Application.GetResourceFullPath(_DefaultMusicPath);
|
||||
var path2 = Application.GetResourceFullPath(_DefaultSaveLocation);
|
||||
var path3 = Application.GetResourceFullPath(_DefaultMusicDB);
|
||||
Directory.CreateDirectory(path1);
|
||||
Directory.CreateDirectory(path2);
|
||||
Variables._MusicDatabase = new MusicDatabase(path3);
|
||||
await Variables._MusicDatabase.LoadFromFile();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace MusicPlayer.Events;
|
||||
|
||||
public class OnVoiceRemoved: IDbEvent
|
||||
{
|
||||
|
||||
public string Name => "Event: OnVoiceRemoved";
|
||||
public string Description => "Called when bot leaves a voice channel";
|
||||
|
||||
public void Start(DiscordSocketClient client)
|
||||
{
|
||||
client.UserVoiceStateUpdated += async (user, oldState, newState) =>
|
||||
{
|
||||
if (user.Id == client.CurrentUser.Id && newState.VoiceChannel == null)
|
||||
{
|
||||
Variables._MusicPlayer?.MusicQueue.Clear();
|
||||
Variables._MusicPlayer?.Skip();
|
||||
Variables._MusicPlayer?.Stop();
|
||||
await Variables.audioClient!.StopAsync();
|
||||
Variables.audioClient = null;
|
||||
Variables._MusicPlayer = null;
|
||||
|
||||
Application.CurrentApplication.Logger.Log("Bot left voice channel.", this, LogType.Info);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Settings;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MusicPlayer;
|
||||
|
||||
public class MusicDatabase: CustomSettingsDictionaryBase<string, MusicInfo>
|
||||
{
|
||||
public MusicDatabase(string diskLocation): base(diskLocation)
|
||||
{
|
||||
}
|
||||
|
||||
public List<MusicInfo> GetMusicInfoWithTitleOrAlias(string searchQuery)
|
||||
{
|
||||
List<MusicInfo> musicInfos = new List<MusicInfo>();
|
||||
foreach (var (title, musicInfo) in _InternalDictionary)
|
||||
{
|
||||
|
||||
if(title.StartsWith(searchQuery))
|
||||
{
|
||||
musicInfos.Add(musicInfo);
|
||||
}
|
||||
|
||||
if (musicInfo.Aliases is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (musicInfo.Aliases.Contains(searchQuery) || musicInfo.Aliases.Any(x => x.Contains(searchQuery)))
|
||||
{
|
||||
musicInfos.Add(musicInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return musicInfos;
|
||||
}
|
||||
|
||||
public override async Task SaveToFile()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(_InternalDictionary, Formatting.Indented);
|
||||
await File.WriteAllTextAsync(_DiskLocation, json);
|
||||
}
|
||||
|
||||
public override async Task LoadFromFile()
|
||||
{
|
||||
if(!File.Exists(_DiskLocation))
|
||||
{
|
||||
await SaveToFile();
|
||||
return;
|
||||
}
|
||||
|
||||
string jsonContent = await File.ReadAllTextAsync(_DiskLocation);
|
||||
var jObject = JsonConvert.DeserializeObject<JObject>(jsonContent);
|
||||
_InternalDictionary.Clear();
|
||||
foreach (var (key,value) in jObject)
|
||||
{
|
||||
if (value is null || value.Type == JTokenType.Null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MusicInfo? info = value.ToObject<MusicInfo>();
|
||||
if (info is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_InternalDictionary[key] = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace MusicPlayer;
|
||||
|
||||
public class MusicInfo
|
||||
{
|
||||
public string Title { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public string Location { get; init; }
|
||||
public List<string>? Aliases { get; init; }
|
||||
public int? ByteSize { get; init; } = 1024;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using Discord;
|
||||
|
||||
namespace MusicPlayer;
|
||||
|
||||
public static class MusicInfoExtensions
|
||||
{
|
||||
public static void AddAlias(this MusicInfo musicInfo, string alias)
|
||||
{
|
||||
musicInfo.Aliases.Add(alias);
|
||||
}
|
||||
|
||||
public static void RemoveAlias(this MusicInfo musicInfo, string alias)
|
||||
{
|
||||
musicInfo.Aliases.Remove(alias);
|
||||
}
|
||||
|
||||
public static MusicInfo CreateMusicInfo(string title, string fileLocation, string? Description = "Unknown", List<string>? aliases = null, int? byteSize = 1024)
|
||||
{
|
||||
return new MusicInfo()
|
||||
{
|
||||
Title = title,
|
||||
Aliases = aliases,
|
||||
Description = Description,
|
||||
Location = fileLocation,
|
||||
ByteSize = byteSize
|
||||
};
|
||||
}
|
||||
|
||||
public static Embed ToEmbed(this MusicInfo musicInfo, Color? embedColor = null)
|
||||
{
|
||||
var builder = new EmbedBuilder();
|
||||
builder.Color = embedColor ?? Color.Default;
|
||||
builder.WithTitle(musicInfo.Title);
|
||||
builder.WithDescription(musicInfo.Description);
|
||||
if (musicInfo.Aliases != null)
|
||||
builder.AddField("Aliases", string.Join(", ", musicInfo.Aliases));
|
||||
else
|
||||
builder.AddField("Aliases", "None");
|
||||
builder.AddField("Location", musicInfo.Location);
|
||||
builder.AddField("ByteSize", musicInfo.ByteSize);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public static Embed ToEmbed(this List<MusicInfo> musicInfo, Color? embedColor = null)
|
||||
{
|
||||
var builder = new EmbedBuilder();
|
||||
builder.Color = embedColor ?? Color.Default;
|
||||
builder.WithTitle("Search results");
|
||||
builder.WithDescription("Found " + musicInfo.Count + " results");
|
||||
builder.AddField("Results", string.Join("\n", musicInfo.Select(item => item.Title)));
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using Discord.Audio;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace MusicPlayer;
|
||||
|
||||
public class MusicPlayer
|
||||
{
|
||||
private static int defaultByteSize = 1024;
|
||||
|
||||
public Queue<MusicInfo> MusicQueue { get; private set; }
|
||||
|
||||
public bool isPaused { get; private set; }
|
||||
public bool isPlaying { get; private set; }
|
||||
|
||||
private bool isQueueRunning;
|
||||
public int ByteSize { get; private set; }
|
||||
|
||||
public MusicInfo? CurrentlyPlaying { get; private set; }
|
||||
|
||||
public MusicPlayer()
|
||||
{
|
||||
MusicQueue = new Queue<MusicInfo>();
|
||||
}
|
||||
|
||||
public async Task PlayQueue()
|
||||
{
|
||||
if (isQueueRunning)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log("Another queue is running !", typeof(MusicPlayer), LogType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Variables.audioClient is null)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log("Audio Client is null", typeof(MusicPlayer), LogType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
isQueueRunning = true;
|
||||
|
||||
string? ffmpegPath = await Application.CurrentApplication.PluginManager.GetDependencyLocation("FFMPEG");
|
||||
if(ffmpegPath is null)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log("FFMPEG is missing. Please install it and try again.", typeof(MusicPlayer), LogType.Error);
|
||||
isQueueRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ffmpegPath = ffmpegPath.Replace("\\", "/");
|
||||
ffmpegPath = Path.GetFullPath(ffmpegPath);
|
||||
while (MusicQueue.TryDequeue(out var dequeuedMusic))
|
||||
{
|
||||
CurrentlyPlaying = dequeuedMusic;
|
||||
await using var dsAudioStream = Variables.audioClient.CreatePCMStream(AudioApplication.Mixed);
|
||||
using var ffmpeg = CreateStream(ffmpegPath, CurrentlyPlaying.Location);
|
||||
if (ffmpeg is null)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log($"Failed to start ffmpeg process. FFMPEG is missing or the {CurrentlyPlaying.Location} has an invalid format.", typeof(MusicPlayer), LogType.Error);
|
||||
continue;
|
||||
}
|
||||
await using var ffmpegOut = ffmpeg.StandardOutput.BaseStream;
|
||||
await PlayCurrentTrack(dsAudioStream, ffmpegOut, CurrentlyPlaying.ByteSize ?? defaultByteSize);
|
||||
}
|
||||
isQueueRunning = false;
|
||||
CurrentlyPlaying = null;
|
||||
}
|
||||
|
||||
public void Loop(int numberOfTimes)
|
||||
{
|
||||
if (CurrentlyPlaying is null) return;
|
||||
|
||||
Queue<MusicInfo> tempQueue = new();
|
||||
for (var i = 0; i < numberOfTimes; i++)
|
||||
{
|
||||
tempQueue.Enqueue(CurrentlyPlaying);
|
||||
}
|
||||
|
||||
foreach (var musicInfo in MusicQueue)
|
||||
{
|
||||
tempQueue.Enqueue(musicInfo);
|
||||
}
|
||||
|
||||
MusicQueue = tempQueue;
|
||||
}
|
||||
|
||||
private async Task PlayCurrentTrack(Stream discordVoiceChannelStream, Stream fileStreamFfmpeg, int byteSize)
|
||||
{
|
||||
if (isPlaying) return;
|
||||
ByteSize = byteSize;
|
||||
|
||||
isPlaying = true;
|
||||
isPaused = false;
|
||||
|
||||
while (isPlaying)
|
||||
{
|
||||
if (isPaused) continue;
|
||||
|
||||
var bits = new byte[byteSize];
|
||||
var read = await fileStreamFfmpeg.ReadAsync(bits, 0, ByteSize);
|
||||
if (read == 0) break;
|
||||
|
||||
try
|
||||
{
|
||||
await discordVoiceChannelStream.WriteAsync(bits, 0, read);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Application.CurrentApplication.Logger.LogException(ex, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
await discordVoiceChannelStream.FlushAsync();
|
||||
await fileStreamFfmpeg.FlushAsync();
|
||||
|
||||
isPlaying = false;
|
||||
isPaused = false;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
public void Unpause()
|
||||
{
|
||||
isPaused = false;
|
||||
}
|
||||
|
||||
public bool Enqueue(MusicInfo music)
|
||||
{
|
||||
MusicQueue.Enqueue(music);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Skip()
|
||||
{
|
||||
isPlaying = false;
|
||||
}
|
||||
|
||||
private static Process? CreateStream(string? fileName, string path)
|
||||
{
|
||||
return Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
MusicQueue.Clear();
|
||||
isPlaying = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore\DiscordBotCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="libs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="libs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="libs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,54 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.SlashCommands;
|
||||
|
||||
public class Loop: IDbSlashCommand
|
||||
{
|
||||
|
||||
public string Name => "loop";
|
||||
public string Description => "Loop the current song for a certain amount of times. If no times are specified, it will loop once";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
|
||||
public List<SlashCommandOptionBuilder> Options => new()
|
||||
{
|
||||
new()
|
||||
{
|
||||
Type = ApplicationCommandOptionType.Integer,
|
||||
Name = "times",
|
||||
Description = "How many times to loop the song",
|
||||
IsRequired = false
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public void ExecuteServer(SocketSlashCommand context)
|
||||
{
|
||||
if (Variables._MusicPlayer.CurrentlyPlaying == null)
|
||||
{
|
||||
context.RespondAsync("There is nothing playing right now");
|
||||
return;
|
||||
}
|
||||
|
||||
var times = context.Data.Options.FirstOrDefault()?.Value.ToString() ?? "1";
|
||||
|
||||
if (!int.TryParse(times, out var timesToLoop))
|
||||
{
|
||||
context.RespondAsync("Invalid number");
|
||||
return;
|
||||
}
|
||||
|
||||
if (timesToLoop < 1)
|
||||
{
|
||||
context.RespondAsync("You need to specify a number greater than 0");
|
||||
return;
|
||||
}
|
||||
|
||||
Variables._MusicPlayer.Loop(timesToLoop);
|
||||
|
||||
context.RespondAsync($"Looping {Variables._MusicPlayer.CurrentlyPlaying.Title} {timesToLoop} times. Check the queue to see the progress");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace MusicPlayer.SlashCommands;
|
||||
|
||||
public class Play: IDbSlashCommand
|
||||
{
|
||||
public string Name => "play";
|
||||
public string Description => "Play music command";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
|
||||
public List<SlashCommandOptionBuilder> Options => new()
|
||||
{
|
||||
new()
|
||||
{
|
||||
IsRequired = true,
|
||||
Description = "The music name to be played",
|
||||
Name = "music-name",
|
||||
Type = ApplicationCommandOptionType.String
|
||||
}
|
||||
};
|
||||
|
||||
public async void ExecuteServer(SocketSlashCommand context)
|
||||
{
|
||||
if(Variables._MusicDatabase is null)
|
||||
{
|
||||
await context.RespondAsync("Music Database is not loaded !");
|
||||
return;
|
||||
}
|
||||
|
||||
var melodyName = context.Data.Options.First().Value as string;
|
||||
|
||||
if (melodyName is null)
|
||||
{
|
||||
await context.RespondAsync("Failed to retrieve melody with name " + melodyName);
|
||||
return;
|
||||
}
|
||||
|
||||
var melody = Variables._MusicDatabase.GetMusicInfoWithTitleOrAlias(melodyName);
|
||||
if (!melody.Any())
|
||||
{
|
||||
await context.RespondAsync("The searched melody does not exists in the database. Sorry :(");
|
||||
return;
|
||||
}
|
||||
|
||||
var user = context.User as IGuildUser;
|
||||
if (user is null)
|
||||
{
|
||||
await context.RespondAsync("Failed to get user data from channel ! Check error log at " + DateTime.Now.ToLongTimeString());
|
||||
Application.CurrentApplication.Logger.Log("User is null while trying to convert from context.User to IGuildUser.", typeof(Play), LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var voiceChannel = user.VoiceChannel;
|
||||
if (voiceChannel is null)
|
||||
{
|
||||
await context.RespondAsync("Unknown voice channel. Maybe I do not have permission to join it ?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Variables.audioClient is null)
|
||||
{
|
||||
Variables.audioClient = await voiceChannel.ConnectAsync(true); // self deaf
|
||||
}
|
||||
|
||||
Variables._MusicPlayer ??= new MusicPlayer();
|
||||
|
||||
if (!Variables._MusicPlayer.Enqueue(melody.First()))
|
||||
{
|
||||
await context.RespondAsync("Failed to enqueue your request. Something went wrong !");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.RespondAsync("Enqueued your request");
|
||||
|
||||
await Variables._MusicPlayer.PlayQueue(); //start queue
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.SlashCommands;
|
||||
|
||||
public class Queue: IDbSlashCommand
|
||||
{
|
||||
public string Name => "queue";
|
||||
public string Description => "Queue a melody to play";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
public List<SlashCommandOptionBuilder> Options => null;
|
||||
|
||||
|
||||
public async void ExecuteServer(SocketSlashCommand context)
|
||||
{
|
||||
if (Variables._MusicPlayer is null)
|
||||
{
|
||||
await context.RespondAsync("No music is currently playing.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Variables._MusicPlayer.MusicQueue.Count == 0 && Variables._MusicPlayer.CurrentlyPlaying == null)
|
||||
{
|
||||
await context.RespondAsync("No music is currently playing");
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = new EmbedBuilder()
|
||||
{
|
||||
Title = "Music Queue",
|
||||
Description = "Here is the current music queue",
|
||||
Color = Color.Blue
|
||||
};
|
||||
|
||||
if (Variables._MusicPlayer.CurrentlyPlaying != null)
|
||||
builder.AddField("Current music", Variables._MusicPlayer.CurrentlyPlaying.Title);
|
||||
|
||||
var i = 1;
|
||||
foreach (var melody in Variables._MusicPlayer.MusicQueue)
|
||||
{
|
||||
builder.AddField($"#{i}", melody.Title);
|
||||
i++;
|
||||
}
|
||||
|
||||
await context.RespondAsync(embed: builder.Build());
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.SlashCommands;
|
||||
|
||||
public class Skip: IDbSlashCommand
|
||||
{
|
||||
public string Name => "skip";
|
||||
public string Description => "Skip the current melody";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
public List<SlashCommandOptionBuilder> Options => null;
|
||||
|
||||
public async void ExecuteServer(SocketSlashCommand context)
|
||||
{
|
||||
if (Variables._MusicPlayer is null)
|
||||
{
|
||||
await context.RespondAsync("No music is currently playing.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Variables._MusicPlayer.MusicQueue.Count == 0 && Variables._MusicPlayer.CurrentlyPlaying == null)
|
||||
{
|
||||
await context.RespondAsync("No music is currently playing");
|
||||
return;
|
||||
}
|
||||
|
||||
var melodyTitle = Variables._MusicPlayer.CurrentlyPlaying.Title;
|
||||
|
||||
await context.RespondAsync($"Skipping {melodyTitle} ...");
|
||||
Variables._MusicPlayer.Skip();
|
||||
await context.ModifyOriginalResponseAsync(x => x.Content = $"Skipped {melodyTitle}");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using Discord.Audio;
|
||||
|
||||
namespace MusicPlayer;
|
||||
|
||||
public class Variables
|
||||
{
|
||||
public static Dictionary<string, MusicInfo> _MusicDatabase;
|
||||
public static MusicPlayer _MusicPlayer;
|
||||
|
||||
public static IAudioClient audioClient;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MusicPlayer;
|
||||
|
||||
public class YoutubeDlp
|
||||
{
|
||||
public static async Task DownloadMelody(string url, string downloadId)
|
||||
{
|
||||
var process = new Process();
|
||||
var baseMusicDirectory = DiscordBotCore.Application.GetResourceFullPath("Music/Melodies/");
|
||||
|
||||
process.StartInfo.FileName = await DiscordBotCore.Application.CurrentApplication.PluginManager.GetDependencyLocation("yt-dlp");
|
||||
process.StartInfo.Arguments = $"-x --force-overwrites -o \"{baseMusicDirectory}/{downloadId}.%(ext)s\" --audio-quality 3 --audio-format mp3 {url}";
|
||||
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
process.OutputDataReceived += (_, args) =>
|
||||
{
|
||||
if (args.Data != null)
|
||||
{
|
||||
Console.WriteLine(args.Data);
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
await process.WaitForExitAsync();
|
||||
}
|
||||
|
||||
|
||||
public static async Task<string?> GetMusicTitle(string youtubeUrl)
|
||||
{
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName=await DiscordBotCore.Application.CurrentApplication.PluginManager.GetDependencyLocation("yt-dlp");
|
||||
p.StartInfo.Arguments = $"--print \"%(title)s\" {youtubeUrl}";
|
||||
p.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
p.Start();
|
||||
string output = await p.StandardOutput.ReadToEndAsync();
|
||||
await p.WaitForExitAsync();
|
||||
|
||||
output = Regex.Replace(output, @"[\p{L}-[a-zA-Z]]+", "");
|
||||
output = output.TrimEnd();
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# Plugins
|
||||
Here is a list of plugins that are available for the bot. You can find the source code for each plugin in the `Plugins` folder.
|
||||
1. [Leveling System](./LevelingSystem) - a plugin that allows users to level up by sending messages.
|
||||
2. [Music Player](./MusicPlayer) - a plugin that allows users to play music in a voice channel.
|
||||
3. [CppWrapper](./CppWrapper) - a plugin that allows users to run C++ code. This is a HELPER plugin and has no use on its own.
|
||||
4. [DiscordBotUI](./DiscordBotUI) - a plugin that allows users to interact with the bot using a graphical user interface.
|
||||
@@ -2,8 +2,8 @@
|
||||
services:
|
||||
discord-bot:
|
||||
build:
|
||||
context: ./WebUI
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: ./WebUI/Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
|
||||
Reference in New Issue
Block a user