public async Task Command([Remainder] string text) { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); IEnumerable <Quote> quotes = server.Quotes; int quoteCount = quotes?.Count() ?? 0; if (quoteCount > 0) { if (server.Quotes.Any(x => x.Text.Equals(text))) { var cEmbed = new KaguyaEmbedBuilder(EmbedColor.YELLOW) { Description = "A quote with the same text already exists. Do you want to create this one anyway?" }; var data = new ReactionCallbackData("", cEmbed.Build(), true, true, TimeSpan.FromSeconds(120)); data.AddCallBack(GlobalProperties.CheckMarkEmoji(), async(c, r) => { await InsertQuote(Context, server, text); }); data.AddCallBack(GlobalProperties.NoEntryEmoji(), async(c, r) => { await SendBasicErrorEmbedAsync("Okay, no action will be taken."); }); await InlineReactionReplyAsync(data); return; } } await InsertQuote(Context, server, text); }
public async Task Command() { User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <Fish> userFish = await DatabaseQueries.GetAllForUserAsync <Fish>(user.UserId); var countFishDicts = new List <Dictionary <FishType, int> >(); if (userFish.Count == 0) { await SendBasicErrorEmbedAsync($"You have never fished before. Try it out with " + $"`{server.CommandPrefix}fish`!"); return; } string ownedFishString = ""; int curFishValue = 0; int allTimeFishValue = 0; foreach (FishType type in Enum.GetValues(typeof(FishType))) { // Creates a new dictionary of how many unsold fish the user has of the given type. var dic = new Dictionary <FishType, int>(); List <Fish> fishMatchingType = await DatabaseQueries.GetUnsoldFishForUserAsync(user.UserId); fishMatchingType = fishMatchingType.Where(x => x.FishType == type).ToList(); // Filter the fish. if (userFish.Count == 0) { ownedFishString = $"You currently don't own any fish, go catch some!"; goto StatsEmbed; } // We don't care about BAIT_STOLEN because it's not actually a fish. if (fishMatchingType.Count != 0) { dic.Add(type, fishMatchingType.Count); countFishDicts.Add(dic); } } foreach (Fish fish in userFish) { allTimeFishValue += fish.Value; if (!fish.Sold) { curFishValue += Fish.GetPayoutForFish(fish, user.FishExp); } } foreach (Dictionary <FishType, int> dic in countFishDicts) { ownedFishString += $"Fish: `{dic.Keys.First().ToString()}` - Count: `{dic.Values.First():N0}` - " + $"Value: `{Fish.GetPayoutForFish(userFish.Where(x => x.FishType == dic.Keys.First() && !x.Sold).ToList(), user.FishExp):N0}` points\n"; } if (ownedFishString.IsNullOrEmpty()) { ownedFishString = "`No fish currently owned.`"; } StatsEmbed: string rarestFish = null; if (userFish.Count(x => !x.Sold && x.FishType != FishType.BAIT_STOLEN) != 0) { rarestFish = userFish .OrderBy(x => x.FishType) .First(x => x.Sold == false && x.FishType != FishType.BAIT_STOLEN) .FishType .ToString(); } var embed = new KaguyaEmbedBuilder { Title = $"Kaguya Fishing - Stats for {Context.User}", Fields = new List <EmbedFieldBuilder> { new EmbedFieldBuilder { Name = "Fish Level", Value = $"Fish Exp: `{user.FishExp:N0}` exp.\n" + $"Fish Level: `{(int) FishHandler.GetFishLevel(user.FishExp):N0}`\n" + $"{FishHandler.GetRewardString(user.FishExp, user, false)}" }, new EmbedFieldBuilder { Name = "Statistics", Value = $"Bait stolen: `{userFish.Count(x => x.FishType == FishType.BAIT_STOLEN):N0} times`\n" + $"All-time fish count: `{userFish.Count(x => x.FishType != FishType.BAIT_STOLEN):N0}`\n" + $"All-time fish value: `{allTimeFishValue:N0}` points\n" + $"Unsold fish value: `{curFishValue:N0}` points\n" + $"Total fish sold: `{userFish.Count(x => x.Sold && x.FishType != FishType.BAIT_STOLEN):N0}`\n" + $"Rarest owned fish: `{rarestFish ?? "No fish currently owned."}`\n" + $"Number of owned, unsold fish: `{userFish.Count(x => x.FishType != FishType.BAIT_STOLEN && !x.Sold):N0}`" }, new EmbedFieldBuilder { Name = "Currently Owned Fish", Value = ownedFishString } }, Footer = new EmbedFooterBuilder { Text = $"React with a checkmark if you would like all of your Fish IDs DM'd to you!" } }; // If they don't have any fish, we don't need to show them. if (rarestFish != null && rarestFish.ToLower().Contains("no fish")) { embed.Fields.RemoveAt(1); } await InlineReactionReplyAsync(new ReactionCallbackData("", embed.Build(), true, true, TimeSpan.FromSeconds(90)) .AddCallBack(GlobalProperties.CheckMarkEmoji(), async(c, r) => { using (var stream = new MemoryStream()) { var writer = new StreamWriter(stream); foreach (Fish fish in userFish.Where(x => x.FishType != FishType.BAIT_STOLEN && !x.Sold)) { await writer.WriteLineAsync($"Fish ID: {fish.FishId} - " + $"Fish Type: {fish.FishType.ToString()} - " + $"Value: {fish.Value}"); } await writer.FlushAsync(); stream.Seek(0, SeekOrigin.Begin); await c.User.SendFileAsync(stream, $"Fish for {c.User}.txt"); await c.Channel.SendBasicSuccessEmbedAsync($"{c.User.Mention} Alright, I've gone ahead " + $"and DM'd you all of your fish!"); } }) .AddCallBack(GlobalProperties.NoEntryEmoji(), async(c, r) => { await SendBasicErrorEmbedAsync("Okay, no action will be taken."); })); }
/// <summary> /// Searches the specified <see cref="SearchProvider" /> for the provided <see cref="query" />. /// This method also adds the song to the guild's player queue and will even join the user's voice /// channel automatically. /// </summary> /// <param name="context"></param> /// <param name="query">The song to search for, user input.</param> /// <param name="playFirst"></param> /// <param name="provider"></param> /// <returns></returns> public async Task <ReactionCallbackData> SearchAndPlayAsync(ShardedCommandContext context, string query, bool playFirst = false, SearchProvider provider = SearchProvider.YOU_TUBE) { User user = await DatabaseQueries.GetOrCreateUserAsync(context.User.Id); Server server = await DatabaseQueries.GetOrCreateServerAsync(context.Guild.Id); LavaNode node = ConfigProperties.LavaNode; SocketVoiceChannel curVc = (context.User as SocketGuildUser).VoiceChannel; await ConsoleLogger.LogAsync($"Found node and voice channel for guild {context.Guild.Id}.", LogLvl.TRACE); if (curVc == null) { await context.Channel.SendMessageAsync($"{context.User.Mention} You must be in a voice " + "channel to use this command."); await ConsoleLogger.LogAsync("User was not in voice channel, cancelling music search operation.", LogLvl.TRACE); return(null); } SearchResponse result = provider switch { SearchProvider.YOU_TUBE => await node.SearchYouTubeAsync(query), SearchProvider.SOUNDCLOUD => await node.SearchSoundCloudAsync(query), _ => await node.SearchAsync(query) }; if (provider == SearchProvider.TWITCH) { const string PROVIDER_URL = "www.twitch.tv"; string errorString = "Your search returned no results. Ensure you are only " + "typing the name of the streamer who you want to watch or a direct link to their stream.\n\n" + "Note: The streamer must be live for this feature to work."; if (!query.ToLower().Contains(PROVIDER_URL)) { result = await node.SearchAsync($"https://{PROVIDER_URL}/{query}"); if (result.Tracks.Count == 0) { await context.Channel.SendBasicErrorEmbedAsync(errorString); await ConsoleLogger.LogAsync($"No livestream found for search {query} in guild {context.Guild.Id}.", LogLvl.TRACE); return(null); } } else { if ((await node.SearchAsync($"https://{PROVIDER_URL}/{query.Split('\\').Last()}")).Tracks.Count == 0 && (await node.SearchAsync(query)).Tracks.Count == 0) { await context.Channel.SendBasicErrorEmbedAsync(errorString); await ConsoleLogger.LogAsync($"No livestream found for search {query} in guild {context.Guild.Id}.", LogLvl.TRACE); return(null); } } } var tracks = new List <LavaTrack>(); if (user.IsPremium || server.IsPremium) { if (result.Tracks.Any()) { tracks.AddRange(result.Tracks); } } else { // Limit track duration to 10 minutes for non-premium servers/users. if (result.Tracks.Any()) { tracks.AddRange(result.Tracks.Where(x => x.Duration.TotalMinutes < 10).ToList()); } } if (!tracks.Any()) { string suppString = user.IsPremium ? "" : "If you are " + $"not a [Kaguya Premium Subscriber]({ConfigProperties.KAGUYA_STORE_URL}), " + "you are only limited to playing songs less than `10 minutes` in duration."; await context.Channel.SendBasicErrorEmbedAsync($"Your requested search returned no results. {suppString}"); await ConsoleLogger.LogAsync("Search request returned no usable " + $"results in guild {Context.Guild.Id} for query {query}", LogLvl.TRACE); } var fields = new List <EmbedFieldBuilder>(); var callbacks = new List <(IEmote, Func <SocketCommandContext, SocketReaction, Task>)>(); Emoji[] emojiNums = GlobalProperties.EmojisOneThroughNine(); LavaPlayer player = node.HasPlayer(context.Guild) ? node.GetPlayer(context.Guild) : await node.JoinAsync(curVc); await ConsoleLogger.LogAsync($"Player found for guild {context.Guild.Id}. Connected to voice channel.", LogLvl.TRACE); #region If the track is a livestream: if (tracks.Any(x => x.IsStream)) { LavaTrack trackSel = tracks.First(x => x.IsStream); // Gathers the first stream from the collection. string twitchName = (await ConfigProperties.TwitchApi.V5.Users.GetUserByNameAsync(trackSel.Author)).Matches[0].DisplayName; string playString = player.PlayerState == PlayerState.Playing ? $"Queued stream into position {player.Queue.Count}." : $"Now playing `{twitchName}`'s stream."; if (player.PlayerState == PlayerState.Playing) { try { player.Queue.Enqueue(trackSel); await ConsoleLogger.LogAsync($"Enqueued livestream {trackSel.Title} in guild {context.Guild.Id}", LogLvl.TRACE); } catch (Exception e) { await ConsoleLogger.LogAsync("An exception was thrown when trying to enqueue the livestream " + $"{trackSel.Title} in guild {Context.Guild.Id}.\n" + $"Exception Message: {e.Message}\n" + $"Stack Trace: {e.StackTrace}", LogLvl.WARN); } } else { try { await player.PlayAsync(trackSel); await ConsoleLogger.LogAsync($"Playing livestream {trackSel.Title} in guild {context.Guild.Id}", LogLvl.TRACE); } catch (Exception e) { await ConsoleLogger.LogAsync("An exception was thrown when trying to play track " + $"{trackSel.Title} in guild {Context.Guild.Id}.\n" + $"Exception Message: {e.Message}\n" + $"Stack Trace: {e.StackTrace}", LogLvl.WARN); } } var field = new EmbedFieldBuilder { Name = $"`{twitchName}`'s Stream", Value = $"{playString}\n" // We get rid of backticks for formatting. }; var embed = new KaguyaEmbedBuilder { Fields = new List <EmbedFieldBuilder> { field } }; await context.Channel.SendEmbedAsync(embed); return(null); } #endregion #region If we have chosen to only play the default track (via $play). if (playFirst && tracks.Any()) { LavaTrack trackSel = tracks[0]; var field = new EmbedFieldBuilder { Name = "Track #1.", Value = $"Title: `{trackSel.Title.Replace("`", "")}`\n" + // We get rid of backticks for formatting. $"Duration: `{trackSel.Duration.Humanize(minUnit: TimeUnit.Second, maxUnit: TimeUnit.Hour, precision: 3)}`\n" + $"Uploader: `{trackSel.Author}`" }; string playString = player.PlayerState == PlayerState.Playing && !player.Track.IsStream ? $"Queued track #1 into position {player.Queue.Count + 1}." : "Now playing track #1."; if (player.PlayerState == PlayerState.Playing) { if (player.Queue.Count() == 50 && !server.IsPremium) { await ConsoleLogger.LogAsync($"Queue is full in {context.Guild.Id}, sending error.", LogLvl.TRACE); await SendBasicErrorEmbedAsync("Your queue is full! `50 songs` is the maximum " + $"for non [Kaguya Premium]({ConfigProperties.KAGUYA_STORE_URL}) " + "servers."); } else { player.Queue.Enqueue(trackSel); await ConsoleLogger.LogAsync($"Enqueued track {trackSel.Title} in guild {context.Guild.Id}.", LogLvl.TRACE); if (player.Track.IsStream) { await player.SkipAsync(); await ConsoleLogger.LogAsync($"Skipped livestream to play incoming track in guild {context.Guild.Id}.", LogLvl.TRACE); } } } else { try { await player.PlayAsync(trackSel); await ConsoleLogger.LogAsync($"Playing track {trackSel.Title} in guild {context.Guild.Id}", LogLvl.TRACE); } catch (Exception e) { await ConsoleLogger.LogAsync("An exception was thrown when trying to play track " + $"{trackSel.Title} in guild {Context.Guild.Id}.\n" + $"Exception Message: {e.Message}\n" + $"Stack Trace: {e.StackTrace}", LogLvl.WARN); } } if (player.Volume == 0 && player.PlayerState == PlayerState.Playing) { await player.UpdateVolumeAsync(75); // Sets the volume back to default if it is muted. await ConsoleLogger.LogAsync($"Automatically set player volume to 75 in guild {context.Guild.Id}.", LogLvl.TRACE); } var embed = new KaguyaEmbedBuilder { Title = $"Kaguya Music {Centvrio.Emoji.Music.Notes}", Description = playString, ThumbnailUrl = await trackSel.FetchArtworkAsync(), Fields = new List <EmbedFieldBuilder> { field } }; await SendEmbedAsync(embed, context); return(null); } #endregion int h = tracks.Count; for (int i = 0; i < (h < 7 ? h : 7); i++) { int i1 = i; LavaTrack trackSel = tracks[i]; var field = new EmbedFieldBuilder { Name = $"Track {i1 + 1}.", Value = $"Title: `{trackSel.Title.Replace("`", "")}`\n" + // We get rid of backticks for formatting. $"Duration: `{trackSel.Duration.Humanize(minUnit: TimeUnit.Second, maxUnit: TimeUnit.Hour, precision: 3)}`\n" + $"Uploader: `{trackSel.Author}`" }; fields.Add(field); callbacks.Add((emojiNums[i], async(c, r) => { string playString = player.PlayerState == PlayerState.Playing && !player.Track.IsStream ? $"Queued track #{i1 + 1} into position {player.Queue.Count + 1}." : $"Now playing track #{i1 + 1}."; if (player.PlayerState == PlayerState.Playing) { if (player.Queue.Count() == 50 && !server.IsPremium) { await ConsoleLogger.LogAsync($"Queue was full in guild {context.Guild.Id}. Sending error message.", LogLvl.TRACE); await SendBasicErrorEmbedAsync("Your queue is full! `50 songs` is the maximum " + $"for non [Kaguya Premium]({ConfigProperties.KAGUYA_STORE_URL}) " + "servers."); return; } player.Queue.Enqueue(trackSel); await ConsoleLogger.LogAsync($"Enqueued track {trackSel} in guild {context.Guild.Id}", LogLvl.TRACE); if (player.Track.IsStream) { await player.SkipAsync(); await ConsoleLogger.LogAsync("Automatically skipped livestream to play" + $" incoming track in guild {context.Guild.Id}", LogLvl.TRACE); } } else { try { await player.PlayAsync(trackSel); await ConsoleLogger.LogAsync($"Playing track {trackSel.Title} in guild {context.Guild.Id}", LogLvl.TRACE); } catch (Exception e) { await ConsoleLogger.LogAsync("An exception was thrown when trying to play track " + $"{trackSel.Title} in guild {Context.Guild.Id}.\n" + $"Exception Message: {e.Message}\n" + $"Stack Trace: {e.StackTrace}", LogLvl.WARN); } } if (player.Volume == 0 && player.PlayerState == PlayerState.Playing) { await player.UpdateVolumeAsync(75); // Sets the volume back to default if it is muted. await ConsoleLogger.LogAsync($"Automatically set volume to 75 in guild {context.Guild.Id}", LogLvl.TRACE); } var embed = new KaguyaEmbedBuilder { Title = $"Kaguya Music {Centvrio.Emoji.Music.Notes}", Description = playString, ThumbnailUrl = await trackSel.FetchArtworkAsync(), Fields = new List <EmbedFieldBuilder> { field } }; await SendEmbedAsync(embed); } )); } callbacks.Add((GlobalProperties.NoEntryEmoji(), async(c, r) => { await c.Message.DeleteAsync(); await r.Message.Value.DeleteAsync(); })); string s = tracks.Count == 1 ? "" : "s"; var songDisplayEmbed = new KaguyaEmbedBuilder { Title = "Kaguya Music Search Results", Description = $" I found {tracks.Count} track{s} from {provider}, " + $"{(tracks.Count > 5 ? "but here are the top 5" : "here they are")}. " + "Please select a track to play.", Fields = fields }; var data = new ReactionCallbackData("", songDisplayEmbed.Build(), false, false, TimeSpan.FromSeconds(60)); data.SetCallbacks(callbacks); return(data); } }