예제 #1
0
        public async Task LastFmTracks(ICommand command)
        {
            try
            {
                var(settings, user) = await GetLastFmSettings(command["User"], (IGuildUser)command.Author);

                var period = command["Period"].HasValue ? ParseStatsPeriod(command["Period"]) : LastFmDataPeriod.Overall;
                var client = new LastFmClient(settings.LastFmUsername, _integrationOptions.Value.LastFmKey);

                const int NumDisplayed  = 100;
                var       playcountTask = client.GetTotalPlaycount(period);
                var       results       = (await client.GetTrackScores(period, NumDisplayed, playcountTask)).ToList();
                if (!results.Any())
                {
                    throw new AbortException(GetNoScrobblesTimePeriodMessage((await command["User"].AsGuildUserOrName)?.Item2));
                }

                var pages = new PageCollectionBuilder();
                var place = 1;
                foreach (var entry in results.Take(NumDisplayed))
                {
                    pages.AppendLine($"`#{place++}` **{FormatTrackLink(entry.Entity, true)}** by **{FormatArtistLink(entry.Entity.Artist, true)}**_ – {FormatPercent(entry.Score)} ({entry.Entity.Playcount} plays)_");
                }

                var playsTotal   = await playcountTask;
                var embedFactory = new Func <EmbedBuilder>(() =>
                {
                    var author = new EmbedAuthorBuilder()
                                 .WithIconUrl(_websiteWalker.LfIconUrl)
                                 .WithName($"{user}'s top tracks {FormatStatsPeriod(period)}");

                    if (!settings.Anonymous)
                    {
                        author.WithUrl($"https://www.last.fm/user/{settings.LastFmUsername}");
                    }

                    return(new EmbedBuilder()
                           .WithColor(0xd9, 0x23, 0x23)
                           .WithAuthor(author)
                           .WithFooter($"{playsTotal} plays in total"));
                });

                await command.Reply(pages.BuildEmbedCollection(embedFactory, 10), true);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
            {
                ThrowUserNotFound((await command["User"].AsGuildUserOrName)?.Item2);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.Forbidden)
            {
                throw new CommandException("The bot can't access your recently listened tracks. \n\nPlease make sure you don't have `Hide recent listening information` checked in your Last.fm settings (Settings -> Privacy -> Recent listening).");
            }
            catch (WebException e)
            {
                await command.Reply($"Last.fm is down (error {(e.Response as HttpWebResponse)?.StatusCode.ToString() ?? e.Status.ToString()}). Please try again in a few seconds.");
            }
        }
예제 #2
0
        public async Task Say10()
        {
            if (119019602574442497 != Context.User.Id)
            {
                // Secrurity check
                await ReplyAsync("This is a debug command, you cannot use it!");

                return;
            }
            EmbedBuilder MyEmbedBuilder = new EmbedBuilder();

            MyEmbedBuilder.WithColor(new Color(43, 234, 152));
            MyEmbedBuilder.WithTitle("Your title");

            MyEmbedBuilder.WithUrl("http://www.google.com");
            //MyEmbedBuilder.WithDescription("My description");
            MyEmbedBuilder.WithDescription("[Google](http://www.google.com)");

            MyEmbedBuilder.WithThumbnailUrl("https://forum.codingwithstorm.com/Themes/Modern/images/vertex_image/social_twitter_icon.png");
            MyEmbedBuilder.WithImageUrl("https://forum.codingwithstorm.com/Themes/Modern/images/vertex_image/social_facebook_icon.png");

            //Footer
            EmbedFooterBuilder MyFooterBuilder = new EmbedFooterBuilder();

            MyFooterBuilder.WithText("Your text");
            MyFooterBuilder.WithIconUrl("https://forum.codingwithstorm.com/Smileys/Koloboks/wink3.gif");
            MyEmbedBuilder.WithFooter(MyFooterBuilder);

            //Author
            EmbedAuthorBuilder MyAuthorBuilder = new EmbedAuthorBuilder();

            MyAuthorBuilder.WithName("Your Name");
            MyAuthorBuilder.WithUrl("http://www.google.com");
            MyEmbedBuilder.WithAuthor(MyAuthorBuilder);

            //EmbedField
            EmbedFieldBuilder MyEmbedField = new EmbedFieldBuilder();

            MyEmbedField.WithIsInline(true);
            MyEmbedField.WithName("Your Field Name");
            MyEmbedField.WithValue("Your value");
            MyEmbedField.WithValue("[Youtube](http://www.youtube.com)");

            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);
            MyEmbedBuilder.AddField(MyEmbedField);

            await ReplyAsync("Swaaaag:", false, MyEmbedBuilder);
        }
예제 #3
0
        /// <summary>
        /// Generates a Discord Embed for the given <paramref name="stream"/>
        /// </summary>
        /// <param name="stream"></param>
        /// <returns>Discord Embed with Stream Information</returns>
        public static Embed GetStreamEmbed(ILiveBotStream stream, ILiveBotUser user, ILiveBotGame game)
        {
            // Build the Author of the Embed
            EmbedAuthorBuilder authorBuilder = new EmbedAuthorBuilder();

            authorBuilder.WithName(user.DisplayName);
            authorBuilder.WithIconUrl(user.AvatarURL);
            authorBuilder.WithUrl(user.ProfileURL);

            // Build the Footer of the Embed
            EmbedFooterBuilder footerBuilder = new EmbedFooterBuilder();

            footerBuilder.WithText("Stream start time");

            // Add Basic information to EmbedBuilder
            EmbedBuilder builder = new EmbedBuilder();

            builder.WithColor(Color.DarkPurple);

            builder.WithAuthor(authorBuilder);
            builder.WithFooter(footerBuilder);

            builder.WithTimestamp(stream.StartTime);
            builder.WithDescription(stream.Title);
            builder.WithUrl(stream.StreamURL);
            builder.WithThumbnailUrl(user.AvatarURL);

            // Add Status Field
            //EmbedFieldBuilder statusBuilder = new EmbedFieldBuilder();
            //statusBuilder.WithIsInline(false);
            //statusBuilder.WithName("Status");
            //statusBuilder.WithValue("");
            //builder.AddField(statusBuilder);

            // Add Game field
            EmbedFieldBuilder gameBuilder = new EmbedFieldBuilder();

            gameBuilder.WithIsInline(true);
            gameBuilder.WithName("Game");
            gameBuilder.WithValue(game.Name);
            builder.AddField(gameBuilder);

            // Add Stream URL field
            EmbedFieldBuilder streamURLField = new EmbedFieldBuilder();

            streamURLField.WithIsInline(true);
            streamURLField.WithName("Stream");
            streamURLField.WithValue(stream.StreamURL);
            builder.AddField(streamURLField);

            return(builder.Build());
        }
예제 #4
0
        public static Embed GetEmbed(string desc, string title = null, object color = null, string footer = null, string url = null, string authorname = null, string authoriconurl = null, string authorurl = null)
        {
            var embed = new EmbedBuilder()
                        .WithDescription(desc);

            if (title != null)
            {
                embed.WithTitle(title);
            }
            if (color != null)
            {
                embed.WithColor((Color)color);
            }
            else
            {
                embed.WithColor(new Color(200, 0, 0));
            }
            if (footer != null)
            {
                embed.WithFooter(new EmbedFooterBuilder()
                                 .WithText(footer));
            }
            if (url != null)
            {
                embed.WithUrl(url);
            }
            if (authorname != null)
            {
                var author = new EmbedAuthorBuilder()
                             .WithName(authorname);
                if (authoriconurl != null)
                {
                    author.WithIconUrl(authoriconurl);
                }
                if (authorurl != null)
                {
                    author.WithUrl(authorurl);
                }
                embed.WithAuthor(author);
            }
            return(embed.Build());
        }
예제 #5
0
        /// <summary>
        /// Builds the author embed and returns a Discord.Net embed author object.
        /// </summary>
        /// <returns>A Discord.Net embed author object.</returns>
        public EmbedAuthorBuilder Build()
        {
            if (string.IsNullOrWhiteSpace(Name))
            {
                return(null);
            }

            EmbedAuthorBuilder embAuth = new EmbedAuthorBuilder().WithName(Name);

            if (IsUrl(Url))
            {
                embAuth.WithUrl(Url);
            }
            if (IsUrl(IconUrl))
            {
                embAuth.WithIconUrl(IconUrl);
            }

            return(embAuth);
        }
예제 #6
0
        public static EmbedAuthorBuilder SetAuthor(String icon = null, String name = null, String url = null)
        {
            var iconExists            = !String.IsNullOrWhiteSpace(icon);
            var nameExists            = !String.IsNullOrWhiteSpace(name);
            var urlExists             = !String.IsNullOrWhiteSpace(url);
            EmbedAuthorBuilder author = new EmbedAuthorBuilder();

            if (iconExists)
            {
                try { author.WithIconUrl(icon); } catch (Exception) { }
            }
            ;
            if (nameExists)
            {
                author.WithName(name);
            }
            if (urlExists)
            {
                try { author.WithUrl(url); } catch (Exception) { }
            }
            ;
            return(author);
        }
예제 #7
0
        public async Task UserAbout(IUser user = null)
        {
            var userSpecified = user as SocketGuildUser ?? Context.User as SocketGuildUser;

            if (userSpecified == null)
            {
                await ReplyAsync("User not found, please try again.");

                return;
            }

            EmbedAuthorBuilder eab = new EmbedAuthorBuilder();

            if (!String.IsNullOrEmpty(userSpecified.Nickname))
            {
                eab.WithName("About " + userSpecified.Nickname);
            }
            else
            {
                eab.WithName("About " + userSpecified.Username);
            }

            eab.WithUrl(Configuration.Load().PROFILE_URL_ID_TAGGED + userSpecified.Id);

            EmbedFooterBuilder efb = new EmbedFooterBuilder();

            if (userSpecified.IsTeamMember())
            {
                eab.WithIconUrl(userSpecified.GetEmbedAuthorBuilderIconUrl());
            }
            if (!String.IsNullOrEmpty(userSpecified.GetFooterText()))
            {
                efb.WithText(userSpecified.GetFooterText());
                efb.WithIconUrl(userSpecified.GetEmbedFooterBuilderIconUrl());
            }

            EmbedBuilder eb = new EmbedBuilder()
                              .WithAuthor(eab)
                              .WithFooter(efb)
                              .WithThumbnailUrl(userSpecified.GetAvatarUrl())
                              .WithDescription(User.Load(userSpecified.Id).About)
                              .WithColor(userSpecified.GetCustomRGB());

            if (!String.IsNullOrEmpty(userSpecified.GetName()))
            {
                eb.AddField("Name", userSpecified.GetName(), true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetGender()))
            {
                eb.AddField("Gender", userSpecified.GetGender(), true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetPronouns()))
            {
                eb.AddField("Pronouns", userSpecified.GetPronouns(), true);
            }

            eb.AddField("Level", userSpecified.GetLevel(), true);
            eb.AddField("EXP", userSpecified.GetEXP() + " (" + (Math.Round(userSpecified.EXPToLevelUp()) - userSpecified.GetEXP()) + " EXP to level up)", true);
            eb.AddField("Account Created", userSpecified.UserCreateDate(), true);
            eb.AddField("Joined Guild", userSpecified.GuildJoinDate(), true);

            if (!String.IsNullOrEmpty(userSpecified.GetMinecraftUsername()))
            {
                eb.AddField("Minecraft Username", userSpecified.GetMinecraftUsername(), true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetWebsiteUrl()))
            {
                eb.AddField(StringConfiguration.Load().DefaultWebsiteName,
                            "[" + (userSpecified.GetWebsiteName() ?? StringConfiguration.Load().DefaultWebsiteName) + "](" +
                            userSpecified.GetWebsiteUrl() + ")", true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetInstagramUsername()))
            {
                eb.AddField("Instagram",
                            "[" + userSpecified.GetInstagramUsername() + "](https://www.instagram.com/" +
                            userSpecified.GetInstagramUsername() + "/)", true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetSnapchatUsername()))
            {
                eb.AddField("Snapchat",
                            "[" + userSpecified.GetSnapchatUsername() + "](https://www.snapchat.com/add/" +
                            userSpecified.GetSnapchatUsername() + "/)", true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetGitHubUsername()))
            {
                eb.AddField("GitHub",
                            "[" + userSpecified.GetGitHubUsername() + "](https://github.com/" +
                            userSpecified.GetGitHubUsername() + "/)", true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetPokemonGoFriendCode()))
            {
                eb.AddField("Pokémon Go Friend Code",
                            "[" + userSpecified.GetPokemonGoFriendCode() +
                            "](https://chart.googleapis.com/chart?chs=300x300&cht=qr&" +
                            userSpecified.GetPokemonGoFriendCode().Replace(" ", "") + "&choe=UTF-8)", true);
            }

            if (!String.IsNullOrEmpty(userSpecified.GetCustomPrefix()))
            {
                eb.AddField("Custom Prefix", userSpecified.GetCustomPrefix(), true);
            }

            eb.AddField("Profile", "[Online Profile](" + Configuration.Load().PROFILE_URL_ID_TAGGED + userSpecified.Id + ")", true);

            await ReplyAsync("", false, eb.Build());
        }
예제 #8
0
        public async Task LastFmArtist(ICommand command)
        {
            try
            {
                var(settings, user) = await GetLastFmSettings(command["User"].HasValue?await command["User"].AsGuildUser : (IGuildUser)command.Author, command["User"].HasValue);

                var period = command["Period"].HasValue ? ParseStatsPeriod(command["Period"]) : LastFmDataPeriod.Overall;
                if (period == LastFmDataPeriod.Day)
                {
                    throw new IncorrectParametersCommandException("The `day` value can't be used with this command.", false);
                }

                var client = new LastFmClient(settings.LastFmUsername, _integrationOptions.Value.LastFmKey);

                const int NumDisplayed = 10;
                var       info         = await client.GetArtistDetail(command["Artist"], period);

                if (info == null)
                {
                    await command.ReplyError("Can't find this artist or user. Make sure you're using the same spelling as the artist's page on Last.fm.");

                    return;
                }

                var author = new EmbedAuthorBuilder()
                             .WithIconUrl(_websiteWalker.LfIconUrl)
                             .WithName($"{user}'s stats for {info.Name}");

                if (!settings.Anonymous)
                {
                    author.WithUrl($"https://www.last.fm/user/{settings.LastFmUsername}");
                }

                var description = new StringBuilder();
                description.AppendLine($"You've listened to this artist **{info.Playcount}** times.");
                description.AppendLine($"You've heard **{info.AlbumsListened}** of their albums and **{info.TracksListened}** of their tracks.");

                var embed = new EmbedBuilder()
                            .WithDescription(description.ToString())
                            .WithColor(0xd9, 0x23, 0x23)
                            .WithAuthor(author)
                            .WithFooter($"Based on {FormatStatsDataPeriod(period)}");

                if (info.ImageUri != null)
                {
                    embed.WithThumbnailUrl(info.ImageUri.AbsoluteUri);
                }

                if (info.TopAlbums.Any())
                {
                    var topList = new StringBuilder();
                    var place   = 1;
                    foreach (var entry in info.TopAlbums.Take(NumDisplayed))
                    {
                        topList.TryAppendLineLimited($"`#{place++}` **{FormatAlbumLink(entry, true)}**_ – {entry.Playcount} plays_", DiscordHelpers.MaxEmbedFieldLength);
                    }

                    embed.AddField("Top albums", topList.ToString());
                }

                if (info.TopTracks.Any())
                {
                    var topList = new StringBuilder();
                    var place   = 1;
                    foreach (var entry in info.TopTracks.Take(NumDisplayed))
                    {
                        topList.TryAppendLineLimited($"`#{place++}` **{FormatTrackLink(entry, true)}**_ – {entry.Playcount} plays_", DiscordHelpers.MaxEmbedFieldLength);
                    }

                    embed.AddField("Top tracks", topList.ToString());
                }

                await command.Reply(embed.Build());
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
            {
                ThrowUserNotFound((await command["User"].AsGuildUserOrName)?.Item2);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.Forbidden)
            {
                throw new CommandException("The bot can't access your recently listened tracks. \n\nPlease make sure you don't have `Hide recent listening information` checked in your Last.fm settings (Settings -> Privacy -> Recent listening).");
            }
            catch (WebException e)
            {
                await command.Reply($"Last.fm is down (error {(e.Response as HttpWebResponse)?.StatusCode.ToString() ?? e.Status.ToString()}). Please try again in a few seconds.");
            }
        }
예제 #9
0
        public async Task LastFmRecent(ICommand command)
        {
            try
            {
                var(settings, user) = await GetLastFmSettings(command["User"], (IGuildUser)command.Author);

                var client = new LastFmClient(settings.LastFmUsername, _integrationOptions.Value.LastFmKey);

                const int NumDisplayed = 100;
                var       userInfoTask = client.GetUserInfo();
                var       results      = await client.GetRecentTracks(count : NumDisplayed);

                if (!results.Any())
                {
                    throw new AbortException("This user hasn't scrobbled anything recently.");
                }

                var nowPlaying = results.First().NowPlaying;
                var pages      = new PageCollectionBuilder();
                var place      = 1;
                foreach (var track in results.Take(NumDisplayed))
                {
                    string when = null;
                    if (nowPlaying)
                    {
                        nowPlaying = false;
                        when       = "now playing";
                    }
                    else if (track.Timestamp.HasValue)
                    {
                        when = (track.Timestamp.Value - DateTimeOffset.UtcNow).SimpleFormat();
                    }

                    pages.AppendLine($"`{place++}>` **{FormatTrackLink(track.ToTrack(), true)}** by **{FormatArtistLink(track.Artist, true)}**" + (when != null ? $"_ – {when}_" : string.Empty));
                }

                var userInfo     = await userInfoTask;
                var embedFactory = new Func <EmbedBuilder>(() =>
                {
                    var author = new EmbedAuthorBuilder()
                                 .WithIconUrl(_websiteWalker.LfIconUrl)
                                 .WithName($"{user} last listened to...");

                    if (!settings.Anonymous)
                    {
                        author.WithUrl($"https://www.last.fm/user/{settings.LastFmUsername}");
                    }

                    var embed = new EmbedBuilder()
                                .WithColor(0xd9, 0x23, 0x23)
                                .WithAuthor(author);

                    if (userInfo?.Playcount != null)
                    {
                        embed.WithFooter($"{userInfo.Playcount} plays in total");
                    }

                    return(embed);
                });

                await command.Reply(pages.BuildEmbedCollection(embedFactory, 10), true);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
            {
                ThrowUserNotFound((await command["User"].AsGuildUserOrName)?.Item2);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.Forbidden)
            {
                throw new CommandException("The bot can't access your recently listened tracks. \n\nPlease make sure you don't have `Hide recent listening information` checked in your Last.fm settings (Settings -> Privacy -> Recent listening).");
            }
            catch (WebException e)
            {
                await command.Reply($"Last.fm is down (error {(e.Response as HttpWebResponse)?.StatusCode.ToString() ?? e.Status.ToString()}). Please try again in a few seconds.");
            }
        }
예제 #10
0
        public async Task NowPlaying(ICommand command)
        {
            try
            {
                var(settings, user) = await GetLastFmSettings(command["User"], (IGuildUser)command.Author);

                var client        = new LastFmClient(settings.LastFmUsername, _integrationOptions.Value.LastFmKey);
                var topTracksTask = client.GetTopTracks(LastFmDataPeriod.Month, 100);
                var tracks        = (await client.GetRecentTracks(count: 1)).ToList();

                if (!tracks.Any())
                {
                    await command.Reply(GetNoScrobblesMessage((await command["User"].AsGuildUserOrName)?.Item2));

                    return;
                }

                var nowPlaying = tracks[0].NowPlaying;
                var current    = await client.GetTrackInfo(tracks[0].Artist.Name, tracks[0].Name);

                // Description
                var description = new StringBuilder();
                description.AppendLine($"**{FormatTrackLink(current ?? tracks[0].ToTrack())}** by **{FormatArtistLink(current?.Artist ?? tracks[0].Artist)}**");
                if (!string.IsNullOrEmpty(current?.Album?.Name))
                {
                    description.AppendLine($"On {DiscordHelpers.BuildMarkdownUri(current.Album.Name, current.Album.Url)}");
                }
                else if (!string.IsNullOrEmpty(tracks[0].Album?.Name))
                {
                    description.AppendLine($"On {tracks[0].Album.Name}");
                }

                var embed = new EmbedBuilder()
                            .WithDescription(description.ToString())
                            .WithColor(0xd9, 0x23, 0x23);

                // Image
                var imageUri = current?.Album?.ImageUri ?? tracks[0]?.Album?.ImageUri;
                if (imageUri != null)
                {
                    embed.WithThumbnailUrl(imageUri.AbsoluteUri);
                }

                // Title
                var author = new EmbedAuthorBuilder().WithIconUrl(_websiteWalker.LfIconUrl);
                if (!settings.Anonymous)
                {
                    author.WithUrl($"https://www.last.fm/user/{settings.LastFmUsername}");
                }

                if (nowPlaying)
                {
                    author.WithName($"{user} is now listening to...");
                }
                else
                {
                    author.WithName($"{user} last listened to...");
                }

                embed.WithAuthor(author);

                // Playcount
                var playCount = (current?.Playcount ?? 0) + (nowPlaying ? 1 : 0);
                if (playCount == 1 && current?.Playcount != null)
                {
                    embed.WithFooter($"First listen");
                }
                else if (playCount > 1)
                {
                    embed.WithFooter($"{playCount.ToEnglishOrdinal()} listen");
                }

                // Month placement
                {
                    var topTracks = await topTracksTask;

                    int counter = 0, placement = 0, placementPlaycount = int.MaxValue;
                    foreach (var track in topTracks)
                    {
                        counter++;
                        if (placementPlaycount > track.Playcount)
                        {
                            placementPlaycount = track.Playcount.Value;
                            placement          = counter;
                        }

                        if (string.Compare(track.Url, (string)(current?.Url ?? tracks[0].Url), true) == 0)
                        {
                            var footer = placement == 1 ? "Most played track this month" : $"{placement.ToEnglishOrdinal()} most played this month";
                            if (embed.Footer != null)
                            {
                                embed.Footer.Text += " • " + footer;
                            }
                            else
                            {
                                embed.WithFooter(footer);
                            }

                            break;
                        }
                    }
                }

                // Previous
                if (nowPlaying && tracks.Count > 1)
                {
                    var previous = tracks[1];
                    embed.AddField(x => x.WithName("Previous").WithValue($"{FormatTrackLink(previous?.ToTrack())} by {FormatArtistLink(previous?.Artist)}"));
                }

                await command.Reply(embed.Build());
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
            {
                ThrowUserNotFound((await command["User"].AsGuildUserOrName)?.Item2);
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.Forbidden)
            {
                throw new CommandException("The bot can't access your recently listened tracks. \n\nPlease make sure you don't have `Hide recent listening information` checked in your Last.fm settings (Settings -> Privacy -> Recent listening).");
            }
            catch (WebException e)
            {
                await command.Reply($"Last.fm is down (error {(e.Response as HttpWebResponse)?.StatusCode.ToString() ?? e.Status.ToString()}). Please try again in a few seconds.");
            }
        }
예제 #11
0
        public static EmbedBuilder BuildMediaEmbed(
            string title,
            IEnumerable <string> media,
            string url               = null,
            string caption           = null,
            Thumbnail thumbnail      = null,
            string footer            = null,
            string captionFooter     = null,
            DateTimeOffset?timestamp = null,
            string iconUrl           = null,
            int maxCaptionLength     = 400,
            int maxCaptionLines      = 8)
        {
            var author = new EmbedAuthorBuilder()
                         .WithName(title);

            if (!string.IsNullOrEmpty(url))
            {
                author.WithUrl(url);
            }

            if (!string.IsNullOrEmpty(iconUrl))
            {
                author.WithIconUrl(iconUrl);
            }

            var embed = new EmbedBuilder()
                        .WithAuthor(author)
                        .WithFooter(footer);

            if (timestamp != null)
            {
                embed.WithTimestamp(timestamp.Value);
            }

            var       buttons          = "";
            const int minCaptionSpace  = 100;
            var       maxButtonsLength = EmbedBuilder.MaxDescriptionLength - minCaptionSpace - (captionFooter?.Length ?? 0);

            if (media.Skip(1).Any())
            {
                // Add only as many buttons as will fit
                var builder = new StringBuilder();
                foreach (var button in media.Take(Math.Min(EmbedMediaCutoff, 9)).Select((y, i) => $"[{(i + 1).ToKeycapEmoji()}]({y})"))
                {
                    var item = button + " ";
                    if (builder.Length + item.Length > maxButtonsLength)
                    {
                        break;
                    }

                    builder.Append(item);
                }

                buttons = builder.ToString();
            }
            else if (thumbnail?.IsVideo ?? false)
            {
                buttons = $"[▶️ Play]({thumbnail.VideoUrl})";
            }

            var       description      = new StringBuilder();
            const int lineBreaksBuffer = 5;
            var       captionSpace     = EmbedBuilder.MaxDescriptionLength - buttons.Length - (captionFooter?.Length ?? 0) - lineBreaksBuffer;

            if (!string.IsNullOrEmpty(caption))
            {
                description.Append(caption.Truncate(Math.Min(maxCaptionLength, captionSpace)).TruncateLines(maxCaptionLines, trim: true) + "\n\n");
            }

            if (!string.IsNullOrEmpty(captionFooter))
            {
                description.AppendLine(captionFooter);
            }

            description.Append(buttons);

            embed.WithDescription(description.ToString());

            if (thumbnail != null)
            {
                embed.WithImageUrl(thumbnail.Url);
            }

            return(embed);
        }