refactor
This commit is contained in:
parent
79b1a0e15e
commit
c0f7c8cc1d
18
Extensions/RestMessageExtensions.cs
Normal file
18
Extensions/RestMessageExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Rest;
|
||||||
|
|
||||||
|
namespace Kasbot.Extensions
|
||||||
|
{
|
||||||
|
public static class RestMessageExtensions
|
||||||
|
{
|
||||||
|
public static async Task TryDeleteAsync(this RestMessage message, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await message.DeleteAsync(options);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
25
Extensions/SocketMessageExtensions.cs
Normal file
25
Extensions/SocketMessageExtensions.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
namespace Kasbot.Extensions
|
||||||
|
{
|
||||||
|
public static class SocketMessageExtensions
|
||||||
|
{
|
||||||
|
private const int MessageDelay = 3_000; // in ms
|
||||||
|
|
||||||
|
public static async Task SendTemporaryMessageAsync(this ISocketMessageChannel channel, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None)
|
||||||
|
{
|
||||||
|
var message = await channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags);
|
||||||
|
await Task.Delay(MessageDelay);
|
||||||
|
await message.DeleteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task SendTemporaryMessageAsync(this IMessageChannel channel, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None)
|
||||||
|
{
|
||||||
|
var message = await channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags);
|
||||||
|
await Task.Delay(MessageDelay);
|
||||||
|
await message.DeleteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
24
Program.cs
24
Program.cs
@ -9,8 +9,15 @@ namespace TextCommandFramework
|
|||||||
{
|
{
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
|
private static string TOKEN = Environment.GetEnvironmentVariable("TOKEN");
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
if (TOKEN == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Discord Bot Token was not found.");
|
||||||
|
}
|
||||||
|
|
||||||
new Program().MainAsync().GetAwaiter().GetResult();
|
new Program().MainAsync().GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,12 +25,6 @@ namespace TextCommandFramework
|
|||||||
{
|
{
|
||||||
using (var services = ConfigureServices())
|
using (var services = ConfigureServices())
|
||||||
{
|
{
|
||||||
var token = Environment.GetEnvironmentVariable("TOKEN");
|
|
||||||
|
|
||||||
if (token == null)
|
|
||||||
{
|
|
||||||
throw new Exception("Discord Bot Token was not found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var client = services.GetRequiredService<DiscordSocketClient>();
|
var client = services.GetRequiredService<DiscordSocketClient>();
|
||||||
|
|
||||||
@ -32,8 +33,8 @@ namespace TextCommandFramework
|
|||||||
client.Ready += () => Client_Ready(client);
|
client.Ready += () => Client_Ready(client);
|
||||||
services.GetRequiredService<CommandService>().Log += LogAsync;
|
services.GetRequiredService<CommandService>().Log += LogAsync;
|
||||||
|
|
||||||
await client.LoginAsync(TokenType.Bot, token);
|
await Connect(client);
|
||||||
await client.StartAsync();
|
client.Disconnected += async (ex) => await Connect(client);
|
||||||
|
|
||||||
await services.GetRequiredService<CommandHandlingService>().InitializeAsync();
|
await services.GetRequiredService<CommandHandlingService>().InitializeAsync();
|
||||||
|
|
||||||
@ -41,6 +42,12 @@ namespace TextCommandFramework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Connect(DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
await client.LoginAsync(TokenType.Bot, TOKEN);
|
||||||
|
await client.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Client_Ready(DiscordSocketClient client)
|
private async Task Client_Ready(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
var announceLoginGuild = ulong.Parse(Environment.GetEnvironmentVariable("ANNOUNCE_LOGIN_GUILD") ?? "0");
|
var announceLoginGuild = ulong.Parse(Environment.GetEnvironmentVariable("ANNOUNCE_LOGIN_GUILD") ?? "0");
|
||||||
@ -85,6 +92,7 @@ namespace TextCommandFramework
|
|||||||
})
|
})
|
||||||
.AddSingleton<DiscordSocketClient>()
|
.AddSingleton<DiscordSocketClient>()
|
||||||
.AddSingleton<CommandService>()
|
.AddSingleton<CommandService>()
|
||||||
|
.AddSingleton<YoutubeService>()
|
||||||
.AddSingleton<PlayerService>()
|
.AddSingleton<PlayerService>()
|
||||||
.AddSingleton<CommandHandlingService>()
|
.AddSingleton<CommandHandlingService>()
|
||||||
.AddSingleton<HttpClient>()
|
.AddSingleton<HttpClient>()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
using Kasbot.Extensions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -57,11 +58,7 @@ namespace TextCommandFramework.Services
|
|||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var message = await context.Channel.SendMessageAsync($"error: {result}");
|
await context.Channel.SendTemporaryMessageAsync($"Error: {result}");
|
||||||
|
|
||||||
await Task.Delay(5_000);
|
|
||||||
|
|
||||||
await message.DeleteAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,102 +1,37 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Audio;
|
using Discord.Audio;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.Rest;
|
using Kasbot.Extensions;
|
||||||
using Discord.WebSocket;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using YoutubeExplode;
|
|
||||||
using YoutubeExplode.Videos;
|
|
||||||
using YoutubeExplode.Videos.Streams;
|
|
||||||
|
|
||||||
namespace Kasbot.Services
|
namespace Kasbot.Services
|
||||||
{
|
{
|
||||||
public class PlayerService
|
public class PlayerService
|
||||||
{
|
{
|
||||||
public Dictionary<ulong, Connection> Clients { get; set; }
|
public Dictionary<ulong, Connection> Clients { get; set; }
|
||||||
|
public YoutubeService YoutubeService { get; set; }
|
||||||
|
|
||||||
public PlayerService()
|
public PlayerService(YoutubeService youtubeService)
|
||||||
{
|
{
|
||||||
|
this.YoutubeService = youtubeService;
|
||||||
|
|
||||||
Clients = new Dictionary<ulong, Connection>();
|
Clients = new Dictionary<ulong, Connection>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<Media>> DownloadPlaylistMetadataFromYoutube(SocketUserMessage message, string search)
|
private async Task<Connection> CreateConnection(SocketCommandContext Context)
|
||||||
{
|
{
|
||||||
var list = new List<Media>();
|
IVoiceChannel channel = (Context.User as IVoiceState).VoiceChannel;
|
||||||
var youtube = new YoutubeClient();
|
var conn = new Connection();
|
||||||
|
IAudioClient audioClient = await channel.ConnectAsync();
|
||||||
|
|
||||||
var playlistInfo = await youtube.Playlists.GetAsync(search);
|
audioClient.Disconnected += (ex) => Stop(Context.Guild.Id);
|
||||||
await youtube.Playlists.GetVideosAsync(search).ForEachAsync(videoId =>
|
|
||||||
{
|
|
||||||
var media = new Media();
|
|
||||||
|
|
||||||
media.Name = videoId.Title;
|
|
||||||
media.Length = videoId.Duration ?? new TimeSpan(0);
|
|
||||||
media.VideoId = videoId.Id;
|
|
||||||
media.Message = message;
|
|
||||||
|
|
||||||
list.Add(media);
|
|
||||||
});
|
|
||||||
|
|
||||||
await message.Channel.SendMessageAsync($"Queued **{list.Count}** items from *{playlistInfo.Title}* playlist.");
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<Media> DownloadMetadataFromYoutube(Media media)
|
|
||||||
{
|
|
||||||
var youtube = new YoutubeClient();
|
|
||||||
|
|
||||||
IVideo? videoId;
|
|
||||||
|
|
||||||
if (media.Search.StartsWith("http://") || media.Search.StartsWith("https://"))
|
|
||||||
videoId = await youtube.Videos.GetAsync(media.Search);
|
|
||||||
else
|
|
||||||
videoId = await youtube.Search.GetVideosAsync(media.Search).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (videoId == null)
|
|
||||||
{
|
|
||||||
return media;
|
|
||||||
}
|
|
||||||
|
|
||||||
media.Name = videoId.Title;
|
|
||||||
media.Length = videoId.Duration ?? new TimeSpan(0);
|
|
||||||
media.VideoId = videoId.Id;
|
|
||||||
|
|
||||||
return media;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<MemoryStream?> DownloadAudioFromYoutube(Media media)
|
|
||||||
{
|
|
||||||
if (media.VideoId == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
var youtube = new YoutubeClient();
|
|
||||||
|
|
||||||
var streamInfoSet = await youtube.Videos.Streams.GetManifestAsync((VideoId) media.VideoId);
|
|
||||||
var streamInfo = streamInfoSet.GetAudioOnlyStreams().GetWithHighestBitrate();
|
|
||||||
var streamVideo = await youtube.Videos.Streams.GetAsync(streamInfo);
|
|
||||||
streamVideo.Position = 0;
|
|
||||||
|
|
||||||
streamVideo.CopyTo(memoryStream);
|
conn.AudioClient = audioClient;
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
return memoryStream;
|
if (Clients.ContainsKey(Context.Guild.Id))
|
||||||
}
|
Clients.Remove(Context.Guild.Id);
|
||||||
|
|
||||||
private Connection CreateConnection(IAudioClient audioClient, ulong guildId)
|
Clients.Add(Context.Guild.Id, conn);
|
||||||
{
|
|
||||||
var conn = new Connection()
|
|
||||||
{
|
|
||||||
AudioClient = audioClient,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Clients.ContainsKey(guildId))
|
|
||||||
Clients.Remove(guildId);
|
|
||||||
|
|
||||||
Clients.Add(guildId, conn);
|
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
@ -116,51 +51,51 @@ namespace Kasbot.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IVoiceChannel channel = (Context.User as IVoiceState).VoiceChannel;
|
conn = await CreateConnection(Context);
|
||||||
|
|
||||||
var audioClient = await channel.ConnectAsync();
|
|
||||||
audioClient.Disconnected += (ex) => AudioClient_ClientDisconnected(Context.Guild.Id);
|
|
||||||
|
|
||||||
conn = CreateConnection(audioClient, Context.Guild.Id);
|
|
||||||
await Enqueue(Context.Guild.Id, conn, media);
|
await Enqueue(Context.Guild.Id, conn, media);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Enqueue(ulong guildId, Connection conn, Media media)
|
private async Task Enqueue(ulong guildId, Connection conn, Media media)
|
||||||
{
|
{
|
||||||
if (media.Search.StartsWith("https://") && media.Search.Contains("playlist?list="))
|
var startPlay = conn.Queue.Count == 0;
|
||||||
|
|
||||||
|
switch (YoutubeService.GetSearchType(media.Search))
|
||||||
{
|
{
|
||||||
var startPlay = conn.Queue.Count == 0;
|
case SearchType.StringSearch:
|
||||||
var medias = await DownloadPlaylistMetadataFromYoutube(media.Message, media.Search);
|
case SearchType.VideoURL:
|
||||||
|
media = await YoutubeService.DownloadMetadataFromYoutube(media);
|
||||||
|
|
||||||
medias.ForEach(m => conn.Queue.Enqueue(m));
|
if (media.VideoId == null)
|
||||||
|
{
|
||||||
|
await media.Channel.SendTemporaryMessageAsync($"No video found for \"{media.Search}\".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (startPlay)
|
conn.Queue.Enqueue(media);
|
||||||
{
|
if (startPlay)
|
||||||
await PlayNext(guildId);
|
await PlayNext(guildId);
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
var message = $"Queued **{media.Name}** *({media.Length.TotalMinutes:00}:{media.Length.Seconds:00})*";
|
||||||
|
media.QueueMessage = await media.Channel.SendMessageAsync(message);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
break;
|
||||||
}
|
case SearchType.ChannelURL:
|
||||||
|
case SearchType.PlaylistURL:
|
||||||
|
var collection = await YoutubeService.DownloadPlaylistMetadataFromYoutube(media.Message, media.Search);
|
||||||
|
|
||||||
media = await DownloadMetadataFromYoutube(media);
|
collection.Medias.ForEach(m => conn.Queue.Enqueue(m));
|
||||||
|
|
||||||
|
await media.Channel.SendMessageAsync($"Queued **{collection.Medias.Count}** items from *{collection.CollectionName}* playlist.");
|
||||||
|
|
||||||
if (media.VideoId == null)
|
if (startPlay)
|
||||||
{
|
await PlayNext(guildId);
|
||||||
var message = await media.Message.Channel.SendMessageAsync($"No video found for \"{media.Search}\".");
|
|
||||||
await Task.Delay(3_000);
|
|
||||||
await message.DeleteAsync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.Queue.Enqueue(media);
|
break;
|
||||||
if (conn.Queue.Count == 1)
|
case SearchType.None:
|
||||||
{
|
default:
|
||||||
await PlayNext(guildId);
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var message = $"Queued **{media.Name}** *({media.Length.TotalMinutes:00}:{media.Length.Seconds:00})*";
|
|
||||||
media.QueueMessage = await media.Message.Channel.SendMessageAsync(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,12 +110,11 @@ namespace Kasbot.Services
|
|||||||
|
|
||||||
if (nextMedia == null)
|
if (nextMedia == null)
|
||||||
{
|
{
|
||||||
Clients[guildId].Queue.Clear();
|
|
||||||
await Stop(guildId);
|
await Stop(guildId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mp3Stream = await DownloadAudioFromYoutube(nextMedia);
|
var mp3Stream = await YoutubeService.DownloadAudioFromYoutube(nextMedia);
|
||||||
|
|
||||||
if (mp3Stream == null)
|
if (mp3Stream == null)
|
||||||
{
|
{
|
||||||
@ -192,11 +126,11 @@ namespace Kasbot.Services
|
|||||||
var ffmpeg = CreateStream();
|
var ffmpeg = CreateStream();
|
||||||
|
|
||||||
var message = $"⏯ Playing: **{nextMedia.Name}** *({nextMedia.Length.TotalMinutes:00}:{nextMedia.Length.Seconds:00})*";
|
var message = $"⏯ Playing: **{nextMedia.Name}** *({nextMedia.Length.TotalMinutes:00}:{nextMedia.Length.Seconds:00})*";
|
||||||
nextMedia.PlayMessage = await nextMedia.Message.Channel.SendMessageAsync(message);
|
nextMedia.PlayMessage = await nextMedia.Channel.SendMessageAsync(message);
|
||||||
|
|
||||||
if (nextMedia.QueueMessage != null)
|
if (nextMedia.QueueMessage != null)
|
||||||
{
|
{
|
||||||
await nextMedia.QueueMessage.DeleteAsync();
|
await nextMedia.QueueMessage.TryDeleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Task stdin = new Task(() =>
|
Task stdin = new Task(() =>
|
||||||
@ -239,11 +173,26 @@ namespace Kasbot.Services
|
|||||||
stdin.Start();
|
stdin.Start();
|
||||||
stdout.Start();
|
stdout.Start();
|
||||||
|
|
||||||
|
await stdin.ContinueWith(async ac =>
|
||||||
|
{
|
||||||
|
if (ac.Exception != null)
|
||||||
|
{
|
||||||
|
await nextMedia.Channel.SendTemporaryMessageAsync("Error in input stream: " + ac.Exception.ToString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await stdout.ContinueWith(async ac =>
|
||||||
|
{
|
||||||
|
if (ac.Exception!= null)
|
||||||
|
{
|
||||||
|
await nextMedia.Channel.SendTemporaryMessageAsync("Error while playing: " + ac.Exception.ToString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Task.WaitAll(stdin, stdout);
|
Task.WaitAll(stdin, stdout);
|
||||||
|
|
||||||
ffmpeg.Close();
|
ffmpeg.Close();
|
||||||
|
|
||||||
await nextMedia.PlayMessage.DeleteAsync();
|
await nextMedia.PlayMessage.TryDeleteAsync();
|
||||||
|
|
||||||
if (Clients[guildId].Queue.Count > 0)
|
if (Clients[guildId].Queue.Count > 0)
|
||||||
Clients[guildId].Queue.Dequeue();
|
Clients[guildId].Queue.Dequeue();
|
||||||
@ -251,11 +200,6 @@ namespace Kasbot.Services
|
|||||||
await PlayNext(guildId);
|
await PlayNext(guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AudioClient_ClientDisconnected(ulong arg)
|
|
||||||
{
|
|
||||||
await Stop(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Process CreateStream()
|
private Process CreateStream()
|
||||||
{
|
{
|
||||||
var process = Process.Start(new ProcessStartInfo
|
var process = Process.Start(new ProcessStartInfo
|
||||||
@ -299,7 +243,7 @@ namespace Kasbot.Services
|
|||||||
|
|
||||||
foreach (var v in media.Queue.Skip(1))
|
foreach (var v in media.Queue.Skip(1))
|
||||||
{
|
{
|
||||||
await RemoveMediaMessages(v);
|
await v.PlayMessage.TryDeleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
media.Queue.Clear();
|
media.Queue.Clear();
|
||||||
@ -308,16 +252,6 @@ namespace Kasbot.Services
|
|||||||
media.CurrentAudioStream.Close();
|
media.CurrentAudioStream.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveMediaMessages(Media media)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (media.PlayMessage != null)
|
|
||||||
await media.PlayMessage.DeleteAsync();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Leave(ulong guildId)
|
public async Task Leave(ulong guildId)
|
||||||
{
|
{
|
||||||
if (!Clients.ContainsKey(guildId))
|
if (!Clients.ContainsKey(guildId))
|
||||||
@ -339,17 +273,4 @@ namespace Kasbot.Services
|
|||||||
public Stream? CurrentAudioStream { get; set; }
|
public Stream? CurrentAudioStream { get; set; }
|
||||||
public Queue<Media> Queue { get; set; } = new Queue<Media>();
|
public Queue<Media> Queue { get; set; } = new Queue<Media>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Media
|
|
||||||
{
|
|
||||||
public string Search { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
public TimeSpan Length { get; set; }
|
|
||||||
|
|
||||||
public VideoId? VideoId { get; set; }
|
|
||||||
public SocketUserMessage Message { get; set; }
|
|
||||||
public RestUserMessage PlayMessage { get; set; }
|
|
||||||
public RestUserMessage? QueueMessage { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
140
Services/YoutubeService.cs
Normal file
140
Services/YoutubeService.cs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using YoutubeExplode.Videos;
|
||||||
|
using YoutubeExplode;
|
||||||
|
using Discord.Rest;
|
||||||
|
using YoutubeExplode.Videos.Streams;
|
||||||
|
|
||||||
|
namespace Kasbot.Services
|
||||||
|
{
|
||||||
|
public class YoutubeService
|
||||||
|
{
|
||||||
|
public YoutubeService()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MediaCollection> DownloadPlaylistMetadataFromYoutube(SocketUserMessage message, string search)
|
||||||
|
{
|
||||||
|
var collection = new MediaCollection();
|
||||||
|
var youtube = new YoutubeClient();
|
||||||
|
|
||||||
|
var playlistInfo = await youtube.Playlists.GetAsync(search);
|
||||||
|
await youtube.Playlists.GetVideosAsync(search).ForEachAsync(videoId =>
|
||||||
|
{
|
||||||
|
var media = new Media();
|
||||||
|
|
||||||
|
media.Name = videoId.Title;
|
||||||
|
media.Length = videoId.Duration ?? new TimeSpan(0);
|
||||||
|
media.VideoId = videoId.Id;
|
||||||
|
media.Message = message;
|
||||||
|
|
||||||
|
collection.Medias.Add(media);
|
||||||
|
});
|
||||||
|
|
||||||
|
collection.CollectionName = playlistInfo.Title;
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Media> DownloadMetadataFromYoutube(Media media)
|
||||||
|
{
|
||||||
|
var youtube = new YoutubeClient();
|
||||||
|
|
||||||
|
IVideo? videoId;
|
||||||
|
|
||||||
|
if (media.Search.StartsWith("http://") || media.Search.StartsWith("https://"))
|
||||||
|
videoId = await youtube.Videos.GetAsync(media.Search);
|
||||||
|
else
|
||||||
|
videoId = await youtube.Search.GetVideosAsync(media.Search).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (videoId == null)
|
||||||
|
{
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
|
media.Name = videoId.Title;
|
||||||
|
media.Length = videoId.Duration ?? new TimeSpan(0);
|
||||||
|
media.VideoId = videoId.Id;
|
||||||
|
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MemoryStream?> DownloadAudioFromYoutube(Media media)
|
||||||
|
{
|
||||||
|
if (media.VideoId == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
var youtube = new YoutubeClient();
|
||||||
|
|
||||||
|
var streamInfoSet = await youtube.Videos.Streams.GetManifestAsync((VideoId)media.VideoId);
|
||||||
|
var streamInfo = streamInfoSet.GetAudioOnlyStreams().GetWithHighestBitrate();
|
||||||
|
var streamVideo = await youtube.Videos.Streams.GetAsync(streamInfo);
|
||||||
|
streamVideo.Position = 0;
|
||||||
|
|
||||||
|
streamVideo.CopyTo(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchType GetSearchType(string query)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(query))
|
||||||
|
return SearchType.None;
|
||||||
|
|
||||||
|
if (query.StartsWith("http://") || query.StartsWith("https://"))
|
||||||
|
{
|
||||||
|
if (query.Contains("playlist?list="))
|
||||||
|
return SearchType.PlaylistURL;
|
||||||
|
|
||||||
|
// need to add 'else if' for ChannelURL
|
||||||
|
|
||||||
|
return SearchType.VideoURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchType.StringSearch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SearchType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
StringSearch,
|
||||||
|
VideoURL,
|
||||||
|
PlaylistURL,
|
||||||
|
ChannelURL
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Media
|
||||||
|
{
|
||||||
|
public string Search { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public TimeSpan Length { get; set; }
|
||||||
|
|
||||||
|
public VideoId? VideoId { get; set; }
|
||||||
|
public RestUserMessage PlayMessage { get; set; }
|
||||||
|
public RestUserMessage? QueueMessage { get; set; }
|
||||||
|
|
||||||
|
private SocketUserMessage message;
|
||||||
|
public SocketUserMessage Message
|
||||||
|
{
|
||||||
|
get => message;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
message = value;
|
||||||
|
this.Channel = value.Channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ISocketMessageChannel Channel { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MediaCollection
|
||||||
|
{
|
||||||
|
public string CollectionName { get; set; }
|
||||||
|
public List<Media> Medias { get; set; } = new List<Media>();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user