public async Task StartMovie(int movieNightId) { GuildMovieNight movieNight = await GetGuildMovieNightAsync(movieNightId); if (movieNight.WinningMovieImdbId == null) { throw new Exception("The Winning Movie IMDb ID was null at the point in time of the Start Movie."); } (DiscordClient _, DiscordGuild guild, DiscordChannel channel) = await this.GetCommonDiscordObjects(movieNight); DiscordMember host = await guild.GetMemberAsync(movieNight.HostId); OmdbMovie movieInfo = await this.omdbClient.GetByImdbIdAsync(movieNight.WinningMovieImdbId, omdbPlotOption : OmdbPlotOption.SHORT); DiscordEmbedBuilder announceWinnerEmbed = movieInfo.ToDiscordEmbedBuilder() .WithAuthor(host.DisplayName, iconUrl: host.AvatarUrl); DiscordMessageBuilder announceWinnerMessage = new DiscordMessageBuilder() .WithContent($"@everyone, the movie below is starting now!") .WithEmbed(announceWinnerEmbed.Build()); await channel.SendMessageAsync(announceWinnerMessage); // Update movie suggestion with the time watched DbResult <GuildMovieSuggestion> getWinningMovieSuggestion = await this.mediator.Send(new GuildMovieSuggestions.GetMovieSuggestion(movieNight.WinningMovieImdbId, guild)); if (!getWinningMovieSuggestion.TryGetValue(out GuildMovieSuggestion? winningMovieSuggestion)) { return; } winningMovieSuggestion.InstantWatched = this.clock.GetCurrentInstant(); await this.mediator.Send(new GuildMovieSuggestions.Update(winningMovieSuggestion)); }
public async Task StartMovieAsync(CommandContext context) { if (options.DevGuildId != context.Guild.Id) { await context.RespondAsync("I'm sorry, but these commands should only be run in the bot dev guild"); return; } GuildMovieNight testMovieNight = await this.AddTestMovieNight(context.Guild, context.Channel, context.User); IEnumerable <GuildMovieSuggestion> testMovieSuggestions = await this.AddTestMovies(context.User, context.Guild); await this.mns.StartVoting(testMovieNight.Id); await Task.Delay(15 * 1000); await this.mns.CalculateVotes(testMovieNight.Id); await Task.Delay(15 * 1000); await this.mns.StartMovie(testMovieNight.Id); await this.DeleteTestMovieNight(testMovieNight); await this.DeleteTestMovieSuggestions(testMovieSuggestions); }
private async Task DeleteTestMovieNight(GuildMovieNight testMovieNight) { RecurringJob.RemoveIfExists(testMovieNight.VotingStartHangfireId); RecurringJob.RemoveIfExists(testMovieNight.VotingEndHangfireId); RecurringJob.RemoveIfExists(testMovieNight.MovieNightStartHangfireId); await this.mediator.Send(new GuildMovieNights.Delete(testMovieNight)); }
private static RecurringJobDto GetMovieNightStartRecurringJobInfo(GuildMovieNight movieNight) { RecurringJobDto?rJobDto = JobStorage.Current.GetConnection().GetRecurringJobs().FirstOrDefault(x => x.Id == movieNight.MovieNightStartHangfireId); if (rJobDto == null || !rJobDto.NextExecution.HasValue) { throw new Exception("That Hangfire Job no longer exists or was never scheduled"); } return(rJobDto); }
public async Task DeleteAsync(CommandContext context) { DbResult <IEnumerable <GuildMovieNight> > getMovieNightsResult = await this.mediator.Send(new GuildMovieNights.GetAllGuildsMovieNights(context.Guild.Id)); if (!getMovieNightsResult.TryGetValue(out IEnumerable <GuildMovieNight>?guildMovieNights)) { throw new Exception("An error occured while retrieving guild movie nights"); } bool hasManageServer = context.Member.Roles.Select(x => x.CheckPermission(Permissions.ManageGuild)).Any(); if (!hasManageServer) { guildMovieNights = guildMovieNights.Where(mn => mn.HostId == context.Member.Id); } List <GuildMovieNight> movieNights = guildMovieNights.ToList(); InteractivityExtension interactivity = context.Client.GetInteractivity(); IEnumerable <Page> pages = await GetGuildMovieNightsPages(context.Guild, movieNights, interactivity, hasManageServer); CustomResult <int> result = await context.WaitForMessageAndPaginateOnMsg(pages, PaginationMessageFunction.CreateWaitForMessageWithIntInRange(context.User, context.Channel, 1, movieNights.Count + 1) ); if (result.TimedOut || result.Cancelled) { await context.RespondAsync("You never gave me a valid input. Please try again if so desired."); return; } Reaction reaction = await interactivity.AddAndWaitForYesNoReaction(await context.Channel.SendMessageAsync($"You want me to do delete movie night {result.Result}?"), context.Member); if (reaction != Reaction.Yes) { await context.Channel.SendMessageAsync("Ok!"); return; } GuildMovieNight chosen = movieNights[result.Result - 1]; RecurringJob.RemoveIfExists(chosen.MovieNightStartHangfireId); RecurringJob.RemoveIfExists(chosen.VotingStartHangfireId); RecurringJob.RemoveIfExists(chosen.VotingEndHangfireId); await this.mediator.Send(new GuildMovieNights.Delete(chosen)); await context.Channel.SendMessageAsync($"{context.Member.Mention}, I have deleted movie night {result.Result}"); }
/// <summary> /// Generate the embed with the randomly selected movies and add emojis to allow for voting /// </summary> /// <param name="movieNightId">ID for the movie night in the data store</param> /// <exception cref="ArgumentException">Thrown when an unknown movie night ID is provided</exception> public async Task StartVoting(int movieNightId) { GuildMovieNight movieNight = await GetGuildMovieNightAsync(movieNightId); (DiscordClient client, DiscordGuild guild, DiscordChannel channel) = await this.GetCommonDiscordObjects(movieNight); DbResult <IEnumerable <GuildMovieSuggestion> > randomSuggestionsResult = await this .mediator.Send(new GuildMovieSuggestions.GetRandomGuildMovieSuggestions(guild, movieNight.NumberOfSuggestions, movieNight.MaximumRating)); if (!randomSuggestionsResult.TryGetValue(out IEnumerable <GuildMovieSuggestion>?randomSuggestions)) { throw new Exception("Something went wrong with getting the random suggestions."); } string description = AddMovieSuggestionsAndGenerateDescription(client, movieNight, randomSuggestions); RecurringJobDto rJobDto = GetMovieNightStartRecurringJobInfo(movieNight); DateTimeZone hostDTZ = await GetUserDateTimeZone(movieNight.HostId); ZonedDateTime zdt = GetJobsZonedDateTime(rJobDto, hostDTZ); DiscordEmbed eBuilder = new DiscordEmbedBuilder() .WithTitle($"Time to vote for a movie!") .WithDescription(description) .AddField("Date and Time of Movie", zdt.ToString("MM/dd/yyyy hh:mm x", null), true) .AddField("Maximum Parental Rating", movieNight.MaximumRating.ToQueryValue(), true); DiscordMessageBuilder mBuilder = new DiscordMessageBuilder() .WithContent("@everyone") .WithEmbed(eBuilder); DiscordMessage votingMessage = await channel.SendMessageAsync(mBuilder); movieNight.VotingMessageId = votingMessage.Id; await this.mediator.Send(new GuildMovieNights.Update(movieNight)); foreach (DiscordEmoji emoji in GetNumberEmojis(client).Take(randomSuggestions.Count())) { await votingMessage.CreateReactionAsync(emoji); } }
/// <summary> /// Determine the number of votes that each movie got and then select the highest ranked movie. /// If there is a tie on more than one of the movies, message the movie night creator with an /// embed where they will break the tie. /// </summary> /// <param name="movieNightId">ID for the movie night in the data store</param> public async Task CalculateVotes(int movieNightId) { GuildMovieNight movieNight = await GetGuildMovieNightAsync(movieNightId); (DiscordClient client, DiscordGuild guild, DiscordChannel channel) = await this.GetCommonDiscordObjects(movieNight); DiscordMessage votingMessage = await channel.GetMessageAsync(movieNight.VotingMessageId ?? throw new Exception("Somehow, some way, the voting message id was null... something done f$*@ed up.")); Dictionary <string, DiscordReaction> mostReactedReactions = GetMostReactedReactons(votingMessage); DiscordMember host = await guild.GetMemberAsync(movieNight.HostId); GuildMovieSuggestion winningSuggestion = await GetWinningSuggestion(client, guild, host, movieNight, mostReactedReactions); movieNight.WinningMovieImdbId = winningSuggestion.ImdbId; DbResult movieNightUpdateResult = await this.mediator.Send(new GuildMovieNights.Update(movieNight)); if (!movieNightUpdateResult.Success) { throw new Exception("An error occurred in updating the movie night with the winning suggestion"); } RecurringJobDto rJobDto = GetMovieNightStartRecurringJobInfo(movieNight); LocalDateTime ldt = LocalDateTime.FromDateTime(rJobDto.NextExecution !.Value); DateTimeZone hostDTZ = await GetUserDateTimeZone(movieNight.HostId); ZonedDateTime zdt = ldt.InUtc(); zdt = zdt.WithZone(hostDTZ); OmdbMovie movieInfo = await this.omdbClient.GetByImdbIdAsync(winningSuggestion.ImdbId, omdbPlotOption : OmdbPlotOption.SHORT); DiscordEmbedBuilder announceWinnerEmbed = movieInfo.ToDiscordEmbedBuilder(true) .WithAuthor(host.DisplayName, iconUrl: host.AvatarUrl); DiscordMessageBuilder announceWinnerMessage = new DiscordMessageBuilder() .WithContent($"@everyone, here's what {host.Mention} is showing {zdt.ToString("MM/dd/yyyy hh:mm x", null)}") .WithEmbed(announceWinnerEmbed.Build()); await channel.SendMessageAsync(announceWinnerMessage); }
// Private Static Methods private static string AddMovieSuggestionsAndGenerateDescription(DiscordClient client, GuildMovieNight movieNight, IEnumerable <GuildMovieSuggestion> suggestions) { if (GetNumberEmojis(client).Count() < suggestions.Count()) { throw new ArgumentException("Attempted to use more suggestions than is allowed by the system"); } StringBuilder descriptionBuilder = new(); foreach ((GuildMovieSuggestion gms, DiscordEmoji emoji) in suggestions.Zip(GetNumberEmojis(client))) { movieNight.MovieNightAndSuggestions.Add(new MovieNightAndSuggestion(movieNight.Id, gms.ImdbId, emoji.Name, gms.GuildId)); descriptionBuilder.AppendLine($"{emoji}. {gms.Title}"); } return(descriptionBuilder.ToString()); }
private static async Task <GuildMovieSuggestion> GetWinningSuggestion(DiscordClient client, DiscordGuild guild, DiscordMember host, GuildMovieNight movieNight, Dictionary <string, DiscordReaction> mostReactedReactions) { GuildMovieSuggestion winningSuggestion; if (mostReactedReactions.Count > 1) { winningSuggestion = await DoTiebreaker(client, host, movieNight, mostReactedReactions); } else { winningSuggestion = movieNight.MovieNightAndSuggestions.First(mns => mns.EmojiId == mostReactedReactions.First().Value.Emoji.Name).MovieSuggestion; } return(winningSuggestion); }
private async Task <(DiscordClient client, DiscordGuild guild, DiscordChannel channel)> GetCommonDiscordObjects(GuildMovieNight movieNight) { DiscordClient client = this.bot.ShardedClient.GetShard(movieNight.GuildId); DiscordGuild guild = await client.GetGuildAsync(movieNight.GuildId); DiscordChannel channel = guild.GetChannel(movieNight.AnnouncementChannelId); return(client, guild, channel); }
// Private Async Methods private static async Task <GuildMovieSuggestion> DoTiebreaker(DiscordClient client, DiscordMember host, GuildMovieNight movieNight, Dictionary <string, DiscordReaction> mostReactedReactions) { StringBuilder descriptionBuilder = new(); var tiedSuggestions = movieNight.MovieNightAndSuggestions.Where(mns => mostReactedReactions.ContainsKey(mns.EmojiId)).Select(mns => mns.MovieSuggestion).ToList().Zip(GetNumberEmojis(client)); DiscordEmbedBuilder tiebreakerEmbed = new DiscordEmbedBuilder().WithTitle("You need to break the tie, vote for your favorite of these options."); descriptionBuilder.AppendLine("If you don't respond within 10 minutes, a random movie will be selected"); descriptionBuilder.AppendLine(); foreach ((GuildMovieSuggestion gms, DiscordEmoji emoji) in tiedSuggestions) { descriptionBuilder.AppendLine($"{emoji}. {gms.Title}"); } tiebreakerEmbed.WithDescription(descriptionBuilder.ToString()); DiscordMessage tiebreakerMessage = await host.SendMessageAsync(tiebreakerEmbed); List <DiscordEmoji> emojis = tiedSuggestions.Select(x => x.Second).ToList(); foreach (DiscordEmoji emoji in emojis) { await tiebreakerMessage.CreateReactionAsync(emoji); } HashSet <string> emojiNames = emojis.Select(x => x.Name).ToHashSet(); InteractivityResult <MessageReactionAddEventArgs> tiebreakerReaction = await client .GetInteractivity() .WaitForReactionAsync( x => x.Message.Id == tiebreakerMessage.Id && emojiNames.Contains(x.Emoji.Name), host, TimeSpan.FromMinutes(10) ); if (tiebreakerReaction.TimedOut) { List <GuildMovieSuggestion> tiedList = tiedSuggestions.Select(x => x.First).ToList(); return(tiedList[new Random().Next(tiedList.Count)]); } else { return(tiedSuggestions.First(x => x.Second.Name == tiebreakerReaction.Result.Emoji.Name).First); } }
public Delete(GuildMovieNight movieNight) { this.GuildMovieNight = movieNight; }