/// <summary> /// Searches for a track from YouTube, Soundcloud, or Spotify /// </summary> /// <param name="context">context for message</param> /// <param name="query">Query for YouTube, Soundcloud, or Spotify</param> /// <returns></returns> public async Task SearchForTrack(SocketCommandContext context, string query) { Victoria.Responses.Rest.SearchResponse search; Regex regex; Match match; if (!SpotifyLogin) { return; } if (!Node.TryGetPlayer(context.Guild, out var player)) { await Node.JoinAsync((context.User as IGuildUser)?.VoiceChannel, context.Channel as ITextChannel); player = Node.GetPlayer(context.Guild); await player.UpdateVolumeAsync(Program.BotConfig.Volume); } if (!query.IsUri(out var uri)) { search = await Node.SearchYouTubeAsync(query.Trim()); await QueueTracksToPlayer(player, search, requester : context.User as IGuildUser); return; } if (uri.Host.ToLower() == "open.spotify.com") { var tracks = await SearchSpotify(context.Channel, query); if (tracks != null) { await QueueSpotifyToPlayer(player, tracks, context.User as IGuildUser); } return; } search = await Node.SearchAsync(query); if (search.LoadStatus is LoadStatus.LoadFailed or LoadStatus.NoMatches) { var msg = await embedHelper.BuildErrorEmbed($"The link `{query}` failed to load.", "Is this a private video or playlist? Double check if the resource is available for public viewing or not region locked."); regex = new Regex(@"(?<vid>(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=[\w-]{11})(?:&list=.+)?"); match = regex.Match(query); if (!match.Success) { await context.Channel.SendAndRemove(embed : msg, timeout : 15000); return; } string type = match.Groups["vid"].Value; search = await Node.SearchYouTubeAsync(type); if (search.LoadStatus == LoadStatus.LoadFailed || search.LoadStatus == LoadStatus.NoMatches) { await context.Channel.SendAndRemove(embed : msg, timeout : 15000); return; } } regex = new Regex(@"https?:\/\/(?:www\.)?(?:youtube|youtu)\.(?:com|be)\/?(?:watch\?v=)?(?:[A-z0-9_-]{1,11})(?:\?t=(?<time>\d+))?(&t=(?<time2>\d+)\w)?"); match = regex.Match(query); double time = match switch { _ when match.Groups["time"].Value != "" => double.Parse(match.Groups["time"].Value), _ when match.Groups["time2"].Value != "" => double.Parse(match.Groups["time2"].Value), _ => - 1 }; TimeSpan?timeSpan = (time == -1) ? (TimeSpan?)null : TimeSpan.FromSeconds(time); await QueueTracksToPlayer(player, search, timeSpan, context.User as IGuildUser); }
/// <summary> /// On Reaction handler /// </summary> /// <param name="message">Cacheable struct from Discord</param> /// <param name="messageChannel">SocketChannel reaction occurred in</param> /// <param name="reaction">Reaction added</param> /// <returns></returns> private async Task OnReactionAdded(Cacheable <IUserMessage, ulong> message, Cacheable <IMessageChannel, ulong> messageChannel, SocketReaction reaction) { var channel = await messageChannel.GetOrDownloadAsync(); if (channel is not IGuildChannel guildChannel) { return; } var msg = await message.GetOrDownloadAsync(); if (channel.Id != Program.BotConfig.ChannelId && msg.Id != Program.BotConfig.MessageId && !Emojis.Contains(reaction.Emote)) { await Task.CompletedTask; return; } _ = Task.Run(async() => { EmojiStates currentState = (EmojiStates)Array.IndexOf(Emojis, reaction.Emote); if (reaction.UserId == discord.CurrentUser.Id) { await Task.CompletedTask; return; } await msg.RemoveReactionAsync(reaction.Emote, reaction.User.Value, options: new RequestOptions { RetryMode = RetryMode.RetryRatelimit }); try { if (!node.HasPlayer(guildChannel.Guild)) { return; } } catch { var error = await embedHelper.BuildErrorEmbed("Guild ID Error", $"Your Guild ID in **{ConfigHelper.ConfigName}** is most likely incorrect."); await channel.SendAndRemove(embed: error, timeout: 15000); } var player = node.GetPlayer(guildChannel.Guild); if (!(player.PlayerState is PlayerState.Playing or PlayerState.Paused) && currentState != EmojiStates.Eject) { return; } switch (currentState) { case EmojiStates.Previous: { await player.PreviousAsync(); break; } case EmojiStates.PlayPause: { await player.PauseResumeAsync(embedHelper, player.PlayerState == PlayerState.Paused); break; } case EmojiStates.Next: { await player.NextTrackAsync(embedHelper); break; } case EmojiStates.Loop: { await player.LoopAsync(audioHelper, embedHelper, channel); break; } case EmojiStates.Shuffle: { await player.ShuffleAsync(audioHelper, embedHelper, channel); break; } case EmojiStates.Eject: { try { await node.EjectAsync(embedHelper, guildChannel.Guild); } catch { // ignored } break; } default: return; } }); }