adding spotify integration
This commit is contained in:
parent
4b719e42e3
commit
c536678818
@ -18,12 +18,17 @@
|
||||
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.59.0" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.59.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.59.0">
|
||||
<PackageReference Include="Grpc.Tools" Version="2.60.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="YoutubeExplode" Version="6.3.7" />
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||
<PackageReference Include="SpotifyAPI.Web" Version="7.0.2" />
|
||||
<PackageReference Include="YoutubeExplode" Version="6.3.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Discord;
|
||||
using Discord.Audio;
|
||||
using Kasbot.Services.Internal;
|
||||
using Kasbot.App.Services.Internal;
|
||||
|
||||
namespace Kasbot.Models
|
||||
{
|
||||
|
@ -1,12 +1,14 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Kasbot.App.Internal.Services;
|
||||
using Kasbot.App.Services.Internal;
|
||||
using Kasbot.Services;
|
||||
using Kasbot.Services.Internal;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
|
||||
namespace Kasbot
|
||||
{
|
||||
@ -102,15 +104,23 @@ namespace Kasbot
|
||||
|
||||
private ServiceProvider ConfigureServices()
|
||||
{
|
||||
var logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}")
|
||||
.CreateBootstrapLogger();
|
||||
|
||||
return new ServiceCollection()
|
||||
.AddSingleton(new DiscordSocketConfig
|
||||
{
|
||||
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent,
|
||||
TotalShards = SHARDS
|
||||
})
|
||||
.AddSerilog(logger)
|
||||
.AddSingleton<DiscordShardedClient>()
|
||||
.AddSingleton<CommandService>()
|
||||
.AddSingleton<SpotifyService>()
|
||||
.AddSingleton<YoutubeService>()
|
||||
.AddSingleton<MediaService>()
|
||||
.AddSingleton<AudioService>()
|
||||
.AddSingleton<PlayerService>()
|
||||
.AddSingleton<CommandHandlingService>()
|
||||
|
112
Kasbot.APP/Services/Internal/MediaService.cs
Normal file
112
Kasbot.APP/Services/Internal/MediaService.cs
Normal file
@ -0,0 +1,112 @@
|
||||
using Discord.Rest;
|
||||
using Discord.WebSocket;
|
||||
using Kasbot.Models;
|
||||
using Kasbot.Services.Internal;
|
||||
using Serilog;
|
||||
using YoutubeExplode.Videos;
|
||||
|
||||
namespace Kasbot.App.Services.Internal
|
||||
{
|
||||
public class MediaService
|
||||
{
|
||||
private YoutubeService YoutubeService { get; set; }
|
||||
private SpotifyService SpotifyService { get; set; }
|
||||
private ILogger Logger { get; set; }
|
||||
|
||||
|
||||
public MediaService(YoutubeService youtubeService, SpotifyService spotifyService, ILogger logger)
|
||||
{
|
||||
this.YoutubeService = youtubeService;
|
||||
this.SpotifyService = spotifyService;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public async Task<Media> FetchSingleMedia(Media media, SearchType mediaType)
|
||||
{
|
||||
if (mediaType == SearchType.SpotifyTrack)
|
||||
{
|
||||
Logger.Debug($"Fetching single media: {media.Search}");
|
||||
media = await SpotifyService.FetchSingleMedia(media);
|
||||
}
|
||||
|
||||
Logger.Debug($"Fetching single media (YouTube): {media.Search}");
|
||||
media = await YoutubeService.FetchSingleMedia(media);
|
||||
|
||||
if (media.VideoId == null)
|
||||
{
|
||||
Logger.Error($"No video found for \"{media.Search}\".");
|
||||
throw new Exception($"No video found for \"{media.Search}\".");
|
||||
}
|
||||
|
||||
return media;
|
||||
}
|
||||
|
||||
public async Task<MediaCollection> FetchMediaCollection(Media rawMedia, SearchType mediaType)
|
||||
{
|
||||
var collection = new MediaCollection();
|
||||
|
||||
if (mediaType == SearchType.SpotifyPlaylist)
|
||||
{
|
||||
Logger.Debug($"Fetching playlist from Spotify: {rawMedia.Search}");
|
||||
collection = await SpotifyService.FetchPlaylist(rawMedia);
|
||||
var tasks = collection.Medias.ToList().Select(media => YoutubeService.FetchSingleMedia(media));
|
||||
var results = await Task.WhenAll(tasks);
|
||||
Logger.Debug($"Fetched playlist from Spotify: {rawMedia.Search}");
|
||||
}
|
||||
|
||||
if (mediaType == SearchType.SpotifyAlbum)
|
||||
{
|
||||
Logger.Debug($"Fetching album from Spotify: {rawMedia.Search}");
|
||||
collection = await SpotifyService.FetchAlbum(rawMedia);
|
||||
var tasks = collection.Medias.ToList().Select(media => YoutubeService.FetchSingleMedia(media));
|
||||
var results = await Task.WhenAll(tasks);
|
||||
Logger.Debug($"Fetched album from Spotify: {rawMedia.Search}");
|
||||
}
|
||||
|
||||
if (mediaType == SearchType.YoutubePlaylist)
|
||||
{
|
||||
Logger.Debug($"Fetching playlist from YouTube: {rawMedia.Search}");
|
||||
collection = await YoutubeService.FetchPlaylist(rawMedia);
|
||||
Logger.Debug($"Fetched playlist from YouTube: {rawMedia.Search}");
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public async Task<MemoryStream?> DownloadAudioFromYoutube(Media media)
|
||||
{
|
||||
return await YoutubeService.DownloadAudioFromYoutube(media);
|
||||
}
|
||||
}
|
||||
|
||||
public class Media
|
||||
{
|
||||
public string Search { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public TimeSpan Length { get; set; }
|
||||
public Flags Flags { 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;
|
||||
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>();
|
||||
}
|
||||
}
|
146
Kasbot.APP/Services/Internal/SpotifyService.cs
Normal file
146
Kasbot.APP/Services/Internal/SpotifyService.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using Serilog;
|
||||
using SpotifyAPI.Web;
|
||||
|
||||
namespace Kasbot.App.Services.Internal
|
||||
{
|
||||
public class SpotifyService
|
||||
{
|
||||
private readonly SpotifyClient? spotifyClient = null;
|
||||
private ILogger Logger { get; set; }
|
||||
|
||||
public SpotifyService(ILogger logger)
|
||||
{
|
||||
this.Logger = logger;
|
||||
|
||||
this.spotifyClient = SetupSpotifyClient();
|
||||
}
|
||||
|
||||
private SpotifyClient SetupSpotifyClient()
|
||||
{
|
||||
var spotifyClientId = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID");
|
||||
var spotifyClientSecret = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_SECRET");
|
||||
|
||||
if (spotifyClientId == null || spotifyClientSecret == null)
|
||||
{
|
||||
Logger.Warning("Spotify Token was not found. Will disable Spotify integration.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var config = SpotifyClientConfig.CreateDefault();
|
||||
|
||||
var request = new ClientCredentialsRequest(spotifyClientId, spotifyClientSecret);
|
||||
var response = new OAuthClient(config).RequestToken(request).Result;
|
||||
|
||||
return new SpotifyClient(config.WithToken(response.AccessToken));
|
||||
}
|
||||
|
||||
public async Task<Media> FetchSingleMedia(Media media)
|
||||
{
|
||||
if (spotifyClient == null)
|
||||
{
|
||||
Logger.Warning("Spotify integration is disabled.");
|
||||
throw new Exception("Spotify integration is disabled.");
|
||||
}
|
||||
|
||||
var trackId = UrlResolver.GetSpotifyResourceId(media.Search);
|
||||
var spotifyTrack = await spotifyClient.Tracks.Get(trackId);
|
||||
|
||||
if (spotifyTrack == null)
|
||||
{
|
||||
Logger.Error($"No track found on Spotify for \"{media.Search}\".");
|
||||
throw new Exception($"No track found on Spotify for \"{media.Search}\".");
|
||||
}
|
||||
|
||||
media.Search = spotifyTrack.Name;
|
||||
|
||||
return media;
|
||||
}
|
||||
|
||||
public async Task<MediaCollection> FetchPlaylist(Media rawMedia)
|
||||
{
|
||||
if (spotifyClient == null)
|
||||
{
|
||||
Logger.Warning("Spotify integration is disabled.");
|
||||
throw new Exception("Spotify integration is disabled.");
|
||||
}
|
||||
|
||||
var playlistId = UrlResolver.GetSpotifyResourceId(rawMedia.Search);
|
||||
var spotifyPlaylist = await spotifyClient.Playlists.Get(playlistId);
|
||||
|
||||
if (spotifyPlaylist == null || spotifyPlaylist.Tracks == null)
|
||||
{
|
||||
Logger.Error($"No playlist found on Spotify for \"{rawMedia.Search}\".");
|
||||
throw new Exception($"No playlist found on Spotify for \"{rawMedia.Search}\".");
|
||||
}
|
||||
|
||||
var collection = new MediaCollection();
|
||||
collection.CollectionName = spotifyPlaylist.Name ?? string.Empty;
|
||||
|
||||
if (spotifyPlaylist.Tracks.Items == null || spotifyPlaylist.Tracks.Items.Count == 0)
|
||||
{
|
||||
Logger.Error($"No tracks found for playlist \"{spotifyPlaylist.Name}\".");
|
||||
throw new Exception($"No tracks found for playlist \"{spotifyPlaylist.Name}\".");
|
||||
}
|
||||
|
||||
Logger.Debug($"Found {spotifyPlaylist.Tracks.Items.Count} tracks for playlist \"{spotifyPlaylist.Name}\".");
|
||||
|
||||
foreach (var playlistTrack in spotifyPlaylist.Tracks.Items)
|
||||
{
|
||||
if (playlistTrack.Track is not FullTrack track)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
collection.Medias.Add(new Media
|
||||
{
|
||||
Search = track.Name,
|
||||
Message = rawMedia.Message,
|
||||
Flags = rawMedia.Flags,
|
||||
});
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public async Task<MediaCollection> FetchAlbum(Media rawMedia)
|
||||
{
|
||||
if (spotifyClient == null)
|
||||
{
|
||||
Logger.Warning("Spotify integration is disabled.");
|
||||
throw new Exception("Spotify integration is disabled.");
|
||||
}
|
||||
|
||||
var albumId = UrlResolver.GetSpotifyResourceId(rawMedia.Search);
|
||||
var spotifyAlbum = await spotifyClient.Albums.Get(albumId);
|
||||
|
||||
if (spotifyAlbum == null || spotifyAlbum.Tracks == null)
|
||||
{
|
||||
Logger.Error($"No album found on Spotify for \"{rawMedia.Search}\".");
|
||||
throw new Exception($"No album found on Spotify for \"{rawMedia.Search}\".");
|
||||
}
|
||||
|
||||
var collection = new MediaCollection();
|
||||
collection.CollectionName = spotifyAlbum.Name ?? string.Empty;
|
||||
|
||||
if (spotifyAlbum.Tracks.Items == null || spotifyAlbum.Tracks.Items.Count == 0)
|
||||
{
|
||||
Logger.Error($"No tracks found for album \"{spotifyAlbum.Name}\".");
|
||||
throw new Exception($"No tracks found for album \"{spotifyAlbum.Name}\".");
|
||||
}
|
||||
|
||||
Logger.Debug($"Found {spotifyAlbum.Tracks.Items.Count} tracks for album \"{spotifyAlbum.Name}\".");
|
||||
|
||||
foreach (var track in spotifyAlbum.Tracks.Items)
|
||||
{
|
||||
collection.Medias.Add(new Media
|
||||
{
|
||||
Search = track.Name,
|
||||
Message = rawMedia.Message,
|
||||
Flags = rawMedia.Flags,
|
||||
});
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
}
|
93
Kasbot.APP/Services/Internal/UrlResolver.cs
Normal file
93
Kasbot.APP/Services/Internal/UrlResolver.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Kasbot.App.Services.Internal
|
||||
{
|
||||
public static class UrlResolver
|
||||
{
|
||||
private const string SpotifyUrl = "open.spotify.com";
|
||||
|
||||
public static SearchType GetSearchType(string query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query))
|
||||
return SearchType.None;
|
||||
|
||||
if (IsURL(query))
|
||||
{
|
||||
if (IsSpotifyUrl(query))
|
||||
{
|
||||
if (query.Contains("/track/"))
|
||||
return SearchType.SpotifyTrack;
|
||||
|
||||
if (query.Contains("/album/"))
|
||||
return SearchType.SpotifyAlbum;
|
||||
|
||||
if (query.Contains("/playlist/"))
|
||||
return SearchType.SpotifyPlaylist;
|
||||
|
||||
if (query.Contains("/artist/"))
|
||||
return SearchType.SpotifyArtist;
|
||||
}
|
||||
|
||||
if (query.Contains("playlist?list="))
|
||||
return SearchType.YoutubePlaylist;
|
||||
|
||||
if (query.Contains("list="))
|
||||
return SearchType.VideoPlaylistURL;
|
||||
|
||||
return SearchType.VideoURL;
|
||||
}
|
||||
|
||||
return SearchType.StringSearch;
|
||||
}
|
||||
|
||||
public static string GetVideoId(string url)
|
||||
{
|
||||
if (url.Contains("v="))
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var query = HttpUtility.ParseQueryString(uri.Query);
|
||||
return query["v"] ?? string.Empty;
|
||||
}
|
||||
|
||||
if (url.Contains("youtu.be/"))
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
return uri.Segments[1];
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
public static string GetSpotifyResourceId(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
return string.Empty;
|
||||
|
||||
var uri = new Uri(url);
|
||||
return uri.Segments[uri.Segments.Length - 1];
|
||||
}
|
||||
|
||||
private static bool IsURL(string url)
|
||||
{
|
||||
return url.StartsWith("http://") || url.StartsWith("https://");
|
||||
}
|
||||
|
||||
private static bool IsSpotifyUrl(string url)
|
||||
{
|
||||
return url.Contains(SpotifyUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SearchType
|
||||
{
|
||||
None,
|
||||
StringSearch,
|
||||
VideoURL,
|
||||
VideoPlaylistURL,
|
||||
YoutubePlaylist,
|
||||
SpotifyTrack,
|
||||
SpotifyAlbum,
|
||||
SpotifyPlaylist,
|
||||
SpotifyArtist
|
||||
}
|
||||
}
|
@ -1,34 +1,37 @@
|
||||
using Discord.WebSocket;
|
||||
using YoutubeExplode.Videos;
|
||||
using Kasbot.App.Services.Internal;
|
||||
using Serilog;
|
||||
using YoutubeExplode;
|
||||
using Discord.Rest;
|
||||
using YoutubeExplode.Videos;
|
||||
using YoutubeExplode.Videos.Streams;
|
||||
using Kasbot.Models;
|
||||
|
||||
namespace Kasbot.Services.Internal
|
||||
{
|
||||
public class YoutubeService
|
||||
{
|
||||
public YoutubeService()
|
||||
{
|
||||
private ILogger Logger { get; set; }
|
||||
|
||||
public YoutubeService(ILogger logger)
|
||||
{
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public async Task<MediaCollection> DownloadPlaylistMetadataFromYoutube(SocketUserMessage message, string search)
|
||||
public async Task<MediaCollection> FetchPlaylist(Media rawMedia)
|
||||
{
|
||||
var collection = new MediaCollection();
|
||||
var youtube = new YoutubeClient();
|
||||
|
||||
var playlistInfo = await youtube.Playlists.GetAsync(search);
|
||||
await youtube.Playlists.GetVideosAsync(search).ForEachAsync(videoId =>
|
||||
Logger.Debug($"Fetching playlist from YouTube: {rawMedia.Search}");
|
||||
|
||||
var playlistInfo = await youtube.Playlists.GetAsync(rawMedia.Search);
|
||||
await youtube.Playlists.GetVideosAsync(rawMedia.Search).ForEachAsync(videoId =>
|
||||
{
|
||||
var media = new Media
|
||||
{
|
||||
Name = videoId.Title,
|
||||
Length = videoId.Duration ?? new TimeSpan(0),
|
||||
VideoId = videoId.Id,
|
||||
Message = message,
|
||||
Flags = new Flags()
|
||||
Message = rawMedia.Message,
|
||||
Flags = rawMedia.Flags
|
||||
};
|
||||
|
||||
collection.Medias.Add(media);
|
||||
@ -36,11 +39,15 @@ namespace Kasbot.Services.Internal
|
||||
|
||||
collection.CollectionName = playlistInfo.Title;
|
||||
|
||||
Logger.Debug($"Fetched playlist from YouTube: {rawMedia.Search}");
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public async Task<Media> DownloadMetadataFromYoutube(Media media)
|
||||
public async Task<Media> FetchSingleMedia(Media media)
|
||||
{
|
||||
Logger.Debug($"Fetching single media: {media.Search}");
|
||||
|
||||
var youtube = new YoutubeClient();
|
||||
|
||||
IVideo? videoId;
|
||||
@ -52,9 +59,12 @@ namespace Kasbot.Services.Internal
|
||||
|
||||
if (videoId == null)
|
||||
{
|
||||
Logger.Error($"No video found for \"{media.Search}\".");
|
||||
return media;
|
||||
}
|
||||
|
||||
Logger.Debug($"Found video: {videoId.Title}");
|
||||
|
||||
media.Name = videoId.Title;
|
||||
media.Length = videoId.Duration ?? new TimeSpan(0);
|
||||
media.VideoId = videoId.Id;
|
||||
@ -82,63 +92,5 @@ namespace Kasbot.Services.Internal
|
||||
|
||||
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 Flags Flags { 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;
|
||||
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>();
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,28 @@
|
||||
using Discord;
|
||||
using Discord.Audio;
|
||||
using Discord.Commands;
|
||||
using Kasbot.App.Services.Internal;
|
||||
using Kasbot.Extensions;
|
||||
using Kasbot.Models;
|
||||
using Kasbot.Services.Internal;
|
||||
using Serilog;
|
||||
|
||||
namespace Kasbot.Services
|
||||
{
|
||||
public class PlayerService
|
||||
{
|
||||
public Dictionary<ulong, Connection> Clients { get; set; }
|
||||
public YoutubeService YoutubeService { get; set; }
|
||||
public AudioService AudioService { get; set; }
|
||||
private Dictionary<ulong, Connection> Clients { get; set; }
|
||||
private AudioService AudioService { get; set; }
|
||||
private MediaService MediaService { get; set; }
|
||||
private ILogger Logger { get; set; }
|
||||
|
||||
public PlayerService(YoutubeService youtubeService, AudioService audioService)
|
||||
public PlayerService(AudioService audioService, MediaService mediaService, ILogger logger)
|
||||
{
|
||||
YoutubeService = youtubeService;
|
||||
AudioService = audioService;
|
||||
|
||||
Clients = new Dictionary<ulong, Connection>();
|
||||
|
||||
AudioService = audioService;
|
||||
MediaService = mediaService;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
private async Task<Connection> CreateConnection(ulong guildId, IVoiceChannel voiceChannel)
|
||||
@ -42,9 +46,9 @@ namespace Kasbot.Services
|
||||
var media = new Media()
|
||||
{
|
||||
Message = Context.Message,
|
||||
Search = arguments,
|
||||
Search = arguments.Trim(),
|
||||
Flags = flags,
|
||||
Name = "",
|
||||
Name = string.Empty,
|
||||
};
|
||||
var guildId = Context.Guild.Id;
|
||||
var userVoiceChannel = (Context.User as IVoiceState).VoiceChannel;
|
||||
@ -69,46 +73,49 @@ namespace Kasbot.Services
|
||||
{
|
||||
var startPlay = conn.Queue.Count == 0;
|
||||
|
||||
media.Search.Trim();
|
||||
var mediaType = UrlResolver.GetSearchType(media.Search);
|
||||
|
||||
switch (YoutubeService.GetSearchType(media.Search))
|
||||
Logger.Debug($"Enqueueing {media.Search} as {mediaType}");
|
||||
|
||||
switch (mediaType)
|
||||
{
|
||||
case SearchType.StringSearch:
|
||||
case SearchType.VideoURL:
|
||||
media = await YoutubeService.DownloadMetadataFromYoutube(media);
|
||||
case SearchType.SpotifyTrack:
|
||||
Logger.Debug($"Fetching {media.Search} as {mediaType}");
|
||||
|
||||
if (media.VideoId == null)
|
||||
{
|
||||
await media.Channel.SendTemporaryMessageAsync($"No video found for \"{media.Search}\".");
|
||||
return;
|
||||
}
|
||||
media = await MediaService.FetchSingleMedia(media, mediaType);
|
||||
|
||||
conn.Queue.Enqueue(media);
|
||||
if (startPlay)
|
||||
await PlayNext(guildId);
|
||||
else
|
||||
if (!startPlay && !media.Flags.Silent)
|
||||
{
|
||||
var message = $"Queued **{media.Name}** *({media.Length.TotalMinutes:00}:{media.Length.Seconds:00})*";
|
||||
media.QueueMessage = await media.Channel.SendMessageAsync(message);
|
||||
}
|
||||
|
||||
break;
|
||||
case SearchType.ChannelURL:
|
||||
case SearchType.PlaylistURL:
|
||||
var collection = await YoutubeService.DownloadPlaylistMetadataFromYoutube(media.Message, media.Search);
|
||||
Logger.Debug($"Enqueueing {media.Search} as {mediaType}");
|
||||
|
||||
collection.Medias.ForEach(m => conn.Queue.Enqueue(m));
|
||||
|
||||
await media.Channel.SendMessageAsync($"Queued **{collection.Medias.Count}** items from *{collection.CollectionName}* playlist.");
|
||||
|
||||
if (startPlay)
|
||||
await PlayNext(guildId);
|
||||
conn.Queue.Enqueue(media);
|
||||
|
||||
break;
|
||||
case SearchType.None:
|
||||
default:
|
||||
case SearchType.VideoPlaylistURL:
|
||||
case SearchType.YoutubePlaylist:
|
||||
case SearchType.SpotifyPlaylist:
|
||||
case SearchType.SpotifyAlbum:
|
||||
Logger.Debug($"Fetching {media.Search} as {mediaType}");
|
||||
|
||||
var mediaCollection = await MediaService.FetchMediaCollection(media, mediaType);
|
||||
|
||||
mediaCollection.Medias.ForEach(m => conn.Queue.Enqueue(m));
|
||||
|
||||
Logger.Debug($"Enqueueing {media.Search} as {mediaType}");
|
||||
|
||||
await media.Channel.SendMessageAsync($"Queued **{mediaCollection.Medias.Count}** items from *{mediaCollection.CollectionName}* playlist.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (startPlay)
|
||||
await PlayNext(guildId);
|
||||
}
|
||||
|
||||
private async Task PlayNext(ulong guildId)
|
||||
@ -134,16 +141,23 @@ namespace Kasbot.Services
|
||||
await CreateConnection(guildId, voiceChannel);
|
||||
}
|
||||
|
||||
var mp3Stream = await YoutubeService.DownloadAudioFromYoutube(nextMedia);
|
||||
Logger.Debug($"Downloading {nextMedia.Name}");
|
||||
|
||||
var mp3Stream = await MediaService.DownloadAudioFromYoutube(nextMedia);
|
||||
|
||||
Logger.Debug($"Playing {nextMedia.Name}");
|
||||
|
||||
if (mp3Stream == null)
|
||||
{
|
||||
Logger.Error($"Failed to download {nextMedia.Name}");
|
||||
await Stop(guildId);
|
||||
return;
|
||||
}
|
||||
|
||||
var audioClient = Clients[guildId].AudioClient;
|
||||
|
||||
Logger.Information($"Playing {nextMedia.Name}");
|
||||
|
||||
if (!nextMedia.Flags.Silent)
|
||||
{
|
||||
var message = $"⏯ Playing: **{nextMedia.Name}** *({nextMedia.Length.TotalMinutes:00}:{nextMedia.Length.Seconds:00})*";
|
||||
@ -164,6 +178,7 @@ namespace Kasbot.Services
|
||||
{
|
||||
if (ac.Exception != null)
|
||||
{
|
||||
Logger.Error(ac.Exception, $"Error in stream: {ac.Exception.Message}");
|
||||
await nextMedia.Channel.SendTemporaryMessageAsync("Error in stream: " + ac.Exception.ToString());
|
||||
}
|
||||
});
|
||||
|
6
Kasbot.APP/appsettings.json
Normal file
6
Kasbot.APP/appsettings.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console" ],
|
||||
"MinimumLevel": "Debug"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user