Esempio n. 1
0
        /// <summary>
        /// Searches Spotify for tracks
        /// </summary>
        /// <param name="channel">Channel in which to send to</param>
        /// <param name="url">Spotify URL</param>
        /// <returns><see cref="List{T}"/> of tracks (track name + artists' name) or null if not found</returns>
        public async Task <List <string> > SearchSpotify(ISocketMessageChannel channel, string url)
        {
            Regex r = new Regex(@"https?:\/\/(?:open\.spotify\.com)\/(?<type>\w+)\/(?<id>[\w-]{22})(?:\?si=(?:[\w-]{22}))?");

            if (!r.Match(url).Success)
            {
                var msg = await embedHelper.BuildMessageEmbed("Invalid Spotify link.");

                await channel.SendAndRemove(embed : msg, timeout : 5000);

                return(null);
            }

            string        type   = r.Match(url).Groups["type"].Value;
            string        id     = r.Match(url).Groups["id"].Value;
            List <string> tracks = new List <string>();

            switch (type)
            {
            case "album":
                await foreach (var item in Spotify.Paginate((await Spotify.Albums.Get(id)).Tracks))
                {
                    tracks.Add($"{item.Name} {string.Join(" ", item.Artists.Select(x => x.Name))}");
                }
                break;

            case "playlist":
                var playlist = await Spotify.Playlists.Get(id);

                await foreach (var item in Spotify.Paginate(playlist.Tracks))
                {
                    if (item.Track is FullTrack track)
                    {
                        tracks.Add($"{track.Name} {string.Join(" ", track.Artists.Select(x => x.Name))}");
                    }
                }
                break;

            case "track":
                var trackItem = await Spotify.Tracks.Get(id);

                tracks.Add($"{trackItem.Name} {string.Join(" ", trackItem.Artists.Select(x => x.Name))}");
                break;

            default:
                var msg = await embedHelper.BuildMessageEmbed("Must be a `track`, `playlist`, or `album`.");

                await channel.SendAndRemove(embed : msg, timeout : 6000);

                return(null);
            }

            return(tracks);
        }
Esempio n. 2
0
        public static async Task ShuffleAsync(
            this LavaPlayer player,
            AudioHelper audioHelper,
            EmbedHelper embedHelper,
            IMessageChannel channel      = null,
            SocketCommandContext context = null)
        {
            if (player.Queue.Count < 2)
            {
                return;
            }

            player.Queue.Shuffle();

            if (context != null && !context.Guild.TextChannels.Where(x => x.Id == Program.BotConfig.ChannelId).Any())
            {
                return;
            }

            channel ??= context?.Channel;
            string newQueue = await AudioHelper.GetNewEmbedQueueString(player);

            await Program.BotConfig.BotEmbedMessage.ModifyAsync(x => x.Content = string.Format(AudioHelper.QueueMayHaveSongs, newQueue));

            if (channel != null)
            {
                var msg = await embedHelper.BuildMessageEmbed("Queue shuffled");

                await channel.SendAndRemove(embed : msg);
            }
        }
Esempio n. 3
0
        public static async Task LoopAsync(this LavaPlayer player, AudioHelper audioHelper, EmbedHelper embedHelper, IMessageChannel channel)
        {
            audioHelper.RepeatFlag  = !audioHelper.RepeatFlag;
            audioHelper.RepeatTrack = audioHelper.RepeatFlag switch
            {
                true => player.Track,
                false => null
            };

            var embed = await embedHelper.BuildMessageEmbed($"Loop set to `{(audioHelper.RepeatFlag ? "enabled" : "disabled")}`");

            await channel.SendAndRemove(embed : embed, timeout : 5000);
        }
Esempio n. 4
0
        public AudioHelper(LavaNode lavanode, EmbedHelper eh)
        {
            Node        = lavanode;
            embedHelper = eh;

            // TODO: Make SpotifyClient own class
            if (Program.BotConfig.SpotifyClientId != "" && Program.BotConfig.SpotifySecret != "")
            {
                var config   = SpotifyClientConfig.CreateDefault();
                var request  = new ClientCredentialsRequest(Program.BotConfig.SpotifyClientId, Program.BotConfig.SpotifySecret);
                var response = new OAuthClient(config).RequestToken(request);
                var spotify  = new SpotifyClient(config.WithToken(response.Result.AccessToken));
                Spotify           = spotify;
                _disconnectTokens = new ConcurrentDictionary <ulong, CancellationTokenSource>();
                SpotifyLogin      = true;
            }


            // Handler for when a LavaTrack is started
            // args: TrackStartEventArgs
            Node.OnTrackStarted += async(args) =>
            {
                var player = args.Player;
                var queue  = await GetNewEmbedQueueString(player);

                var embed = await embedHelper.BuildMusicEmbed(player, Color.DarkTeal);

                //If for some reason Volume is set to 0 (100%) it will set to default volume
                if (player.Volume == 0)
                {
                    await player.UpdateVolumeAsync(Program.BotConfig.Volume);
                }

                var content = queue switch
                {
                    "" => NoSongsInQueue,
                    _ => string.Format(QueueMayHaveSongs, queue)
                };

                await Program.BotConfig.BotEmbedMessage.ModifyAsync(x =>
                {
                    x.Embed   = embed;
                    x.Content = content;
                });

                if (!_disconnectTokens.TryGetValue(args.Player.VoiceChannel.Id, out var value))
                {
                    return;
                }
                if (value.IsCancellationRequested)
                {
                    return;
                }

                value.Cancel(true);
            };

            // Handler for when a LavaTrack is ended, stopped, or skipped
            // args: TrackEndedEventArgs
            Node.OnTrackEnded += async(args) =>
            {
                var player = args.Player;

                if (RepeatFlag)
                {
                    await player.PlayAsync(RepeatTrack);

                    return;
                }

                RepeatFlag = false;

                if (!args.Reason.ShouldPlayNext())
                {
                    return;
                }

                if (!player.Queue.TryDequeue(out var track) && player.Queue.Count == 0)
                {
                    var embed = await EmbedHelper.BuildDefaultEmbed();

                    await Program.BotConfig.BotEmbedMessage.ModifyAsync(x =>
                    {
                        x.Content = NoSongsInQueue;
                        x.Embed   = embed;
                    });

                    if (!StayFlag)
                    {
                        _ = InitiateDisconnectAsync(args.Player, TimeSpan.FromMinutes(15));
                    }
                    return;
                }

                await args.Player.PlayAsync(track);
            };

            // Handler for when a LavaTrack throws an exception
            // args: TrackExceptionEventArgs
            Node.OnTrackException += async(args) =>
            {
                var player       = args.Player;
                var errorMessage = args.ErrorMessage switch
                {
                    "This video cannot be viewed anonymously." => "This video most likely hasn't premiered yet.",
                    "Received unexpected response from YouTube." => "YouTube is most likely down.",
                    _ => "Video might still be processing, try again later."
                };
                var msg = await embedHelper.BuildTrackErrorEmbed($"[{player.Track.Title}]({player.Track.Url})\n{errorMessage}");

                await player.TextChannel.SendAndRemove(embed : msg);

                if (player.Queue.Count == 0)
                {
                    //If no songs in queue it will stop playback to reset the embed
                    await player.StopAsync();

                    return;
                }
                //If queue has any songs it will skip to the next track
                await player.SkipAsync();

                return;
            };

            // Handler for when a LavaTrack gets stuck
            // args: TrackStuckEventArgs
            Node.OnTrackStuck += async(args) =>
            {
                var player = args.Player;
                var msg    = await embedHelper.BuildTrackErrorEmbed($"[{player.Track.Title}]({player.Track.Url})\nTrack got stuck, moving on...");

                await player.TextChannel.SendAndRemove(embed : msg);

                if (player.Queue.Count == 0)
                {
                    //If no songs in queue it will stop playback to reset the embed
                    await player.StopAsync();

                    return;
                }
                //If queue has any songs it will skip to the next track
                await player.SkipAsync();

                return;
            };
        }

        /// <summary>
        /// Initiates a disconnect from the voice channel
        /// </summary>
        /// <param name="player">Instance of LavaPlayer for the guild</param>
        /// <param name="timeSpan">TimeSpan for length before disconnecting</param>
        /// <returns></returns>
        private async Task InitiateDisconnectAsync(LavaPlayer player, TimeSpan timeSpan)
        {
            if (!_disconnectTokens.TryGetValue(player.VoiceChannel.Id, out var value))
            {
                value = new CancellationTokenSource();
                _disconnectTokens.TryAdd(player.VoiceChannel.Id, value);
            }
            else if (value.IsCancellationRequested)
            {
                _disconnectTokens.TryUpdate(player.VoiceChannel.Id, new CancellationTokenSource(), value);
                value = _disconnectTokens[player.VoiceChannel.Id];
            }

            var isCancelled = SpinWait.SpinUntil(() => value.IsCancellationRequested, timeSpan);

            if (isCancelled)
            {
                return;
            }

            await Node.LeaveAsync(player.VoiceChannel);

            var msg = await embedHelper.BuildMessageEmbed("Muse has disconnected due to inactivity.");

            await player.TextChannel.SendAndRemove(embed : msg);
        }