public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var guildUser = (SocketGuildUser)options["username"].Value; var discordUser = guildUser.Nickname ?? guildUser.Username; // Player not exist? -> respond with error (var oldTeam, var player) = Team.FindPlayer(teams, discordUser); if (player == null) { await command.FollowupAsync($"User {discordUser} does not exist in the recruiting table", ephemeral : true); return; } oldTeam.RemovePlayer(player); // Update old team message if (oldTeam.Players.Count > 0) { await recruitingChannel.ModifyMessageAsync(oldTeam.MsgId, (message) => message.Content = oldTeam.ToMessage()); await storageClient.SaveTableRow(Team.TableName, oldTeam.Name, guild.RowKey, oldTeam); } else { await recruitingChannel.DeleteMessageAsync(oldTeam.MsgId); await storageClient.DeleteTableRow(Team.TableName, oldTeam.Name, guild.RowKey); } await command.FollowupAsync($"You have removed user {discordUser} from {oldTeam.Name}", ephemeral : true); }
public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var guildUser = (SocketGuildUser)options["username"].Value; var teamName = String.Empty; if (options.TryGetValue("team", out SocketSlashCommandDataOption teamOption)) { teamName = teamOption.Value.ToString(); } // Construct new player from parameters var newPlayer = new Player(); newPlayer.DiscordUser = guildUser.Nickname ?? guildUser.Username; newPlayer.Platform = (Platform)Enum.Parse(typeof(Platform), options["platform"].Value.ToString()); newPlayer.PlatformId = options["id"].Value.ToString(); if (newPlayer.Platform == Platform.Tracker && !Player.ValidateTrackerLink(newPlayer.PlatformId)) { await command.FollowupAsync($"Your RL tracker link is invalid", ephemeral : true); return; } // Is player just updating tracker link? -> Update link (var team, var existingPlayer) = Team.FindPlayer(teams, newPlayer.DiscordUser); if (existingPlayer != null && !string.Equals(team.Name, teamName, StringComparison.InvariantCultureIgnoreCase)) { await command.FollowupAsync($"Invalid use of add command. Please use the move command to change a user between teams", ephemeral : true); return; } if (team == null) { teamName = string.IsNullOrEmpty(teamName) ? "Free_Agents" : teamName; team = Team.AddPlayer(teams, teamName, newPlayer); } else { existingPlayer.Platform = newPlayer.Platform; existingPlayer.PlatformId = newPlayer.PlatformId; } // Have we added this team message yet? -> Write team message and move to next team if (team.MsgId == 0) { team.MsgId = (await recruitingChannel.SendMessageAsync(team.ToMessage())).Id; } else { // This is an existing team -> Modify old team message await recruitingChannel.ModifyMessageAsync(team.MsgId, (message) => message.Content = team.ToMessage()); } await storageClient.SaveTableRow(Team.TableName, team.Name, guild.RowKey, team); await command.FollowupAsync($"{newPlayer.DiscordUser}'s RL tracker has been added to the recruiting board in channel <#{recruitingChannel.Id}>", ephemeral : true); }
public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var user = command.User as SocketGuildUser; // Construct new player from parameters var newPlayer = new Player(); newPlayer.DiscordUser = user.Nickname ?? user.Username; newPlayer.Platform = (Platform)Enum.Parse(typeof(Platform), options["platform"].Value.ToString()); newPlayer.PlatformId = options["id"].Value.ToString(); if (newPlayer.Platform == Platform.Tracker && !Player.ValidateTrackerLink(newPlayer.PlatformId)) { await command.FollowupAsync($"Your RL tracker link is invalid", ephemeral : true); return; } // Is player just updating tracker link? -> Update link (var team, var existingPlayer) = Team.FindPlayer(teams, newPlayer.DiscordUser); // Is player not on a team? -> Add to FreeAgents if (team == null) { team = Team.AddPlayer(teams, "Free_Agents", newPlayer); } else { existingPlayer.Platform = newPlayer.Platform; existingPlayer.PlatformId = newPlayer.PlatformId; } // Have we added this team message yet? -> Write team message and move to next team if (team.MsgId == 0) { team.MsgId = (await recruitingChannel.SendMessageAsync(team.ToMessage())).Id; } else { // This is an existing team -> Modify old team message await recruitingChannel.ModifyMessageAsync(team.MsgId, (message) => message.Content = team.ToMessage()); } await storageClient.SaveTableRow(Team.TableName, team.Name, guild.RowKey, team); await command.FollowupAsync($"Your RL tracker has been added to the recruiting board in channel <#{recruitingChannel.Id}>", ephemeral : true); }
public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var teamName = options["team"].Value.ToString(); // Player not exist? -> respond with error var team = Team.FindTeam(teams, teamName); if (team == null) { await command.FollowupAsync($"Team {teamName} does not exist in the recruiting table", ephemeral : true); return; } // Remove old team message await recruitingChannel.DeleteMessageAsync(team.MsgId); await storageClient.DeleteTableRow(Team.TableName, team.Name, guild.RowKey); await command.FollowupAsync($"You have removed team {teamName}", ephemeral : true); }
public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var teamName = options["team"].Value.ToString(); var lookingForPlayers = (bool)options["looking"].Value; // Player not exist? -> respond with error var team = Team.FindTeam(teams, teamName); if (team == null) { await command.FollowupAsync($"Team {teamName} does not exist in the recruiting table", ephemeral : true); return; } team.LookingForPlayers = lookingForPlayers; await recruitingChannel.ModifyMessageAsync(team.MsgId, (message) => message.Content = team.ToMessage()); await storageClient.SaveTableRow(Team.TableName, teamName, guild.RowKey, team); await command.FollowupAsync($"You marked team {team.Name} as looking for players {lookingForPlayers}", ephemeral : true); }
public static async Task Print(SocketSlashCommand command) { var data = await WebUtils.DownloadString("https://www.rottentomatoes.com/browse/in-theaters?minTomato=0&maxTomato=100&genres=1;2;4;5;6;8;9;10;11;13;18;14&sortBy=popularity"); data = data.CutBeforeAndAfter("document.getElementById('main-row')", "mps,") .CutBefore("},") .CutBefore("},"); data = data.Substring(0, data.LastIndexOf("]") + 1); dynamic resultItems = JsonConvert.DeserializeObject(data); var result = new StringBuilder(); string icon; for (int i = 0; i < 10; i++) { switch (resultItems[i].tomatoIcon.ToString()) { case "certified_fresh": icon = "<:certified_fresh:737761619375030422>"; break; case "fresh": icon = "<:fresh:737761619299270737>"; break; case "rotten": icon = "<:rotten:737761619299532874>"; break; default: icon = ""; break; } result.AppendLine($"`{i + 1}` {resultItems[i].title} `{resultItems[i].theaterReleaseDate}` {(resultItems[i].tomatoScore == null ? "N/A" : resultItems[i].tomatoScore + "%")} {icon}"); } await command.FollowupAsync(null, embed : new EmbedBuilder() .WithTitle("Top Box Office") .WithColor(EmbedUtils.Red) .WithFooter("Via RottenTomatoes.com") .WithDescription(result.ToString()) .Build()); }
public static async Task Run(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Dictionary <string, SocketSlashCommandDataOption> options, Guild guild, ISocketMessageChannel recruitingChannel, List <Team> teams) { var guildUser = (SocketGuildUser)options["username"].Value; var discordUser = guildUser.Nickname ?? guildUser.Username; var teamName = options["team"].Value.ToString(); var captain = options.ContainsKey("captain") && (bool)options["captain"].Value; // Player not exist? -> respond with error (var oldTeam, var player) = Team.FindPlayer(teams, discordUser); if (player == null) { await command.FollowupAsync($"User {discordUser} does not exist in the recruiting table", ephemeral : true); return; } oldTeam.RemovePlayer(player); var newTeam = Team.AddPlayer(teams, teamName, player, captain); bool isNewTeam = newTeam.MsgId == 0; // Update old team message if (oldTeam.Players.Count > 0) { await recruitingChannel.ModifyMessageAsync(oldTeam.MsgId, (message) => message.Content = oldTeam.ToMessage()); } else { await recruitingChannel.DeleteMessageAsync(oldTeam.MsgId); } // Update new team message if (newTeam.MsgId == 0) { newTeam.MsgId = (await recruitingChannel.SendMessageAsync(newTeam.ToMessage())).Id; } else { await recruitingChannel.ModifyMessageAsync(newTeam.MsgId, (message) => message.Content = newTeam.ToMessage()); } var transactions = new List <(string, TableTransactionActionType, Team, ETag)>(); if (oldTeam.Players.Count > 0) { transactions.Add((oldTeam.Name, TableTransactionActionType.UpdateMerge, oldTeam, oldTeam.etag)); } else { transactions.Add((oldTeam.Name, TableTransactionActionType.Delete, null, oldTeam.etag)); } if (!string.Equals(newTeam.Name, oldTeam.Name, StringComparison.OrdinalIgnoreCase)) { transactions.Add((newTeam.Name, isNewTeam ? TableTransactionActionType.UpsertMerge : TableTransactionActionType.UpdateMerge, newTeam, newTeam.etag)); } // if the transaction fails it should retry, and then the message will be updated to reflect the actual value in storage. await storageClient.ExecuteTransaction(Team.TableName, transactions, guild.RowKey); await command.FollowupAsync($"You have moved user {discordUser} from {oldTeam.Name} -> {newTeam.Name}", ephemeral : true); }
public override async Task HandleCommandAsync(SocketSlashCommand command, DiscordSocketClient client, StorageClient storageClient, Guild guild) { if (guild.RecruitingChannelId == default) { await command.RespondAsync("Channel is not part of a guild that supports recruiting", ephemeral : true); return; } var channel = command.Channel as SocketGuildChannel; var subCommand = command.Data.Options.First(); var options = subCommand.Options.ToDictionary(o => o.Name, o => o); await command.RespondAsync($"Starting Command {command.CommandName} {subCommand.Name}", ephemeral : true); // Get all messages in channel var recruitingChannel = await client.GetChannelAsync(guild.RecruitingChannelId) as ISocketMessageChannel; // What do we do if the policy fails 3 times and the board has values that aren't in the table. We could save values first if we didn't need the message id from new teams, but we do. await Policy.Handle <RequestFailedException>(e => e.Status == 412).RetryAsync(3).ExecuteAsync(async() => { // cache these values eventually as well to improve performance var teams = await storageClient.GetAllRowsAsync <Team>(Team.TableName, guild.Id.ToString()); if (teams.Count == 0) { var messages = await GetAllChannelMessages(recruitingChannel); // Parse messages into teams teams = ParseMessageAsync(messages); if (teams.Count > 0) { await ConvertMessageTeamsToStorage(teams, guild.RowKey, storageClient); } // get etags after for optimistic concurrency teams = await storageClient.GetAllRowsAsync <Team>(Team.TableName, guild.Id.ToString()); } switch (subCommand.Name) { case "add": await AddTrackerCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; case "adminadd": await AdminAddTrackerCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; case "move": await MoveTrackedUserCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; case "remove": await RemoveTrackedUserCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; case "deleteteam": await DeleteTeamTrackerCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; case "lookingforplayers": await LookingForPlayersCommand.Run(command, client, storageClient, options, guild, recruitingChannel, teams); break; default: await command.FollowupAsync($"SubCommand {subCommand} not supported", ephemeral: true); return; } }); }
// Search Rotten Tomatoes for movies and create a selection public static async Task SearchRottenTomatoes(SocketSlashCommand command) { // Get our input from the interaction var search = command.Data.Options.ElementAt(0).Value.ToString(); // Make a list of results var resultItems = new List <SearchResultItem>(); // Get the website html var data = await WebUtils.DownloadString($"https://www.rottentomatoes.com/search?search={search}"); //If there's no result, tell the user and then stop. if (data.Contains("Sorry, no results found for")) { await command.FollowupAsync(embed : new EmbedBuilder() .WithTitle("Rotten Tomatoes Search") .WithDescription($"Sorry, no results were found for \"{search}\"\n\nTry reformatting your search if the title contains colons, hyphens, etc.") .WithColor(EmbedUtils.Red) .Build()); return; } // Slim down the data data = data .CutBefore( "<search-page-result slot=\"movie\" skeleton=\"panel\" type=\"movie\" data-qa=\"search-result\">") .CutBeforeAndAfter("<ul slot=\"list\">", "</ul>"); do { var temp = data.CutAfter("</search-page-media-row>"); resultItems.Add(new SearchResultItem(new Movie(temp))); data = data.CutBefore("</search-page-media-row>"); } while (data.Contains("search-page-media-row")); var buttons = new ComponentBuilder(); for (int i = 0; i < (resultItems.Count <= 5 ? resultItems.Count : 5); i++) { var text = $"{resultItems[i].Movie.CriticScore} {resultItems[i].Movie.Name} ({resultItems[i].Movie.Year})"; // Decode the HTML text = HttpUtility.HtmlDecode(text); // Button Labels can only be 80 characters if (text.Length > 80) { text = $"{text.Substring(0, 77)}..."; } var customId = resultItems[i].Movie.Url.CutBefore("/m/"); // Custom IDs can only be 100 characters (skip it otherwise) if (customId.Length > 100) { continue; } buttons.WithButton(text, customId: customId, ButtonStyle.Danger, row: i, emote: Emote.Parse(resultItems[i].Movie.CriticScoreIcon)); } await command.FollowupAsync("Please select a result or search again.", component : buttons.Build()); }