public static void Reload(CommandArguments command) { Reload(); command.ReplyAsNotice = true; CommandHandler.ReplyToCommand(command, "Reloaded {0} token overrides", SecretTokens.Count); }
public override async void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} ugc <ugcid>", Colors.OLIVE); return; } ulong ugcId; if (!ulong.TryParse(command.Message, out ugcId)) { CommandHandler.ReplyToCommand(command, "Invalid UGC ID"); return; } var callback = await Cloud.RequestUGCDetails(ugcId); if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(command, "Unable to request UGC info: {0}{1}", Colors.RED, callback.Result); return; } CommandHandler.ReplyToCommand(command, "Creator: {0}{1}{2}, App: {3}{4}{5}, File: {6}{7}{8}, Size: {9}{10}{11} -{12} {13}", Colors.BLUE, callback.Creator.Render(true), Colors.NORMAL, Colors.BLUE, callback.AppID, Colors.NORMAL, Colors.BLUE, callback.FileName, Colors.NORMAL, Colors.BLUE, GetByteSizeString(callback.FileSize), Colors.NORMAL, Colors.DARKBLUE, callback.URL ); }
public override void OnCommand(CommandArguments command) { BlogPost post; using (var db = Database.GetConnection()) { if (command.Message.Length > 0) { post = db.Query<BlogPost>("SELECT `ID`, `Slug`, `Title` FROM `Blog` WHERE `IsHidden` = 0 AND (`Slug` = @Slug OR `ID` = @Slug) LIMIT 1", new { Slug = command.Message }).SingleOrDefault(); } else { post = db.Query<BlogPost>("SELECT `ID`, `Slug`, `Title` FROM `Blog` WHERE `IsHidden` = 0 ORDER BY `Time` DESC LIMIT 1").SingleOrDefault(); } } if (post.ID == 0) { CommandHandler.ReplyToCommand(command, "No blog post found."); return; } CommandHandler.ReplyToCommand( command, command.Message.Length > 0 ? "Blog post:{0} {1}{2} -{3} {4}" : "Latest blog post:{0} {1}{2} -{3} {4}", Colors.BLUE, post.Title, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetBlogURL(post.Slug.Length > 0 ? post.Slug : post.ID.ToString()) ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} gid <globalid>", Colors.OLIVE); return; } ulong uGid; if (!ulong.TryParse(command.Message, out uGid)) { CommandHandler.ReplyToCommand(command, "Invalid GlobalID."); return; } GlobalID gid = uGid; CommandHandler.ReplyToCommand(command, "{0} (SeqCount: {1}{2}{3}, StartTime: {4}{5}{6}, ProcessID: {7}{8}{9}, BoxID: {10}{11}{12})", (ulong)gid, Colors.LIGHTGRAY, gid.SequentialCount, Colors.NORMAL, Colors.LIGHTGRAY, gid.StartTime, Colors.NORMAL, Colors.LIGHTGRAY, gid.ProcessID, Colors.NORMAL, Colors.LIGHTGRAY, gid.BoxID, Colors.NORMAL ); }
public static void ReplyToCommand(CommandArguments command, string message, params object[] args) { message = string.Format(message, args); switch (command.CommandType) { case ECommandType.IRC: { var isChannelMessage = IRC.IsRecipientChannel(command.Recipient); if (isChannelMessage) { message = string.Format("{0}{1}{2}: {3}", Colors.OLIVE, command.SenderIdentity.Nickname, Colors.NORMAL, message); } IRC.Instance.SendReply(isChannelMessage ? command.Recipient : command.SenderIdentity.Nickname.ToString(), message); break; } case ECommandType.SteamChatRoom: { Steam.Instance.Friends.SendChatRoomMessage(command.ChatRoomID, EChatEntryType.ChatMsg, string.Format(":dsham: {0}: {1}", Steam.Instance.Friends.GetFriendPersonaName(command.SenderID), Colors.StripColors(message))); break; } case ECommandType.SteamIndividual: { Steam.Instance.Friends.SendChatMessage(command.SenderID, EChatEntryType.ChatMsg, Colors.StripColors(message)); break; } } }
public override async Task OnCommand(CommandArguments command) { uint subID; if (command.Message.Length == 0 || !uint.TryParse(command.Message, out subID)) { command.Reply("Usage:{0} sub <subid>", Colors.OLIVE); return; } var job = await Steam.Instance.Apps.PICSGetProductInfo(null, subID, false, false); var callback = job.Results.First(x => !x.ResponsePending); if (!callback.Packages.ContainsKey(subID)) { command.Reply("Unknown SubID: {0}{1}{2}", Colors.BLUE, subID, LicenseList.OwnedSubs.ContainsKey(subID) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Packages[subID]; info.KeyValues.SaveToFile(Path.Combine(Application.Path, "sub", string.Format("{0}.vdf", info.ID)), false); command.Reply("{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, Steam.GetPackageName(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawPackageURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedSubs.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} ugc <ugcid>", Colors.OLIVE); return; } ulong ugcId; if (!ulong.TryParse(command.Message, out ugcId)) { CommandHandler.ReplyToCommand(command, "Invalid UGC ID"); return; } JobManager.AddJob( () => Cloud.RequestUGCDetails(ugcId), new JobManager.IRCRequest { Command = command } ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} servers <filter> - See https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol", Colors.OLIVE); return; } if (command.Message.IndexOf('\\') == -1) { CommandHandler.ReplyToCommand(command, "That doesn't look like a filter."); return; } var request = new CGameServers_GetServerList_Request { filter = command.Message, limit = 5000, }; JobManager.AddJob( () => GameServers.SendMessage(api => api.GetServerList(request)), new JobManager.IRCRequest { Type = JobManager.IRCRequestType.TYPE_GAMESERVERS, Command = command } ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} app <appid or partial game name>", Colors.OLIVE); return; } var count = PICSProductInfo.ProcessedApps.Count; if (count > 100) { CommandHandler.ReplyToCommand(command, "There are currently {0} apps awaiting to be processed, try again later.", count); return; } uint appID; if (!uint.TryParse(command.Message, out appID)) { string name = command.Message; if (!Utils.ConvertUserInputToSQLSearch(ref name)) { CommandHandler.ReplyToCommand(command, "Your request is invalid or too short."); return; } using (var db = Database.GetConnection()) { appID = db.ExecuteScalar<uint>("SELECT `AppID` FROM `Apps` WHERE `Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name OR `Apps`.`LastKnownName` LIKE @Name ORDER BY `LastUpdated` DESC LIMIT 1", new { Name = name }); } if (appID == 0) { CommandHandler.ReplyToCommand(command, "Nothing was found matching your request."); return; } } var apps = new List<uint>(); apps.Add(appID); JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(apps, Enumerable.Empty<uint>()), new JobManager.IRCRequest { Target = appID, Type = JobManager.IRCRequestType.TYPE_APP, Command = command } ); }
public static void OnChannelMessage(object sender, IrcEventArgs e) { if (e.Data.Message[0] != '!') { return; } if (e.Data.Message == "!relogin" && IRC.IsSenderOp(e.Data.Channel, e.Data.Nick)) { if (Steam.Instance.Client.IsConnected) { Steam.Instance.Client.Disconnect(); } foreach (var idler in Program.GCIdlers) { if (idler.Client.IsConnected) { idler.Client.Disconnect(); } } Log.WriteInfo("IRC", "Relogin forced by user {0} in channel {1}", e.Data.Nick, e.Data.Channel); IRC.Send(e.Data.Channel, "You're responsible for death of everything and everyone now."); } Action<CommandArguments> callbackFunction; if (Commands.TryGetValue(e.Data.MessageArray[0], out callbackFunction)) { var command = new CommandArguments { Channel = e.Data.Channel, Nickname = e.Data.Nick, MessageArray = e.Data.MessageArray }; if (!Steam.Instance.Client.IsConnected) { ReplyToCommand(command, "{0}{1}{2}: Not connected to Steam.", Colors.OLIVE, command.Nickname, Colors.NORMAL); return; } if (SteamDB.IsBusy()) { ReplyToCommand(command, "{0}{1}{2}: The bot is currently busy.", Colors.OLIVE, command.Nickname, Colors.NORMAL); return; } Log.WriteInfo("IRC", "Handling command {0} for user {1} in channel {2}", e.Data.MessageArray[0], e.Data.Nick, e.Data.Channel); callbackFunction(command); } }
public override void OnCommand(CommandArguments command) { if (command.Message.Length > 0) { return; } CommandHandler.ReplyToCommand(command, "Available commands: {0}{1}", Colors.OLIVE, Commands); }
public static void ReplyToCommand(CommandArguments command, string message, params object[] args) { if (command.IsChatRoomCommand) { Steam.Instance.Friends.SendChatRoomMessage(command.ChatRoomID, EChatEntryType.ChatMsg, Colors.StripColors(string.Format(message, args))); } else { IRC.Send(command.Channel, message, args); } }
private static void PrintBinary(CommandArguments command, KeyValue kv, string key) { if (kv[key].Children.Count == 0) { return; } kv = kv[key]; CommandHandler.ReplyToCommand(command, "{0}{1} {2}({3} MB)", CDN, kv["file"].AsString(), Colors.DARKGRAY, (kv["size"].AsLong() / 1048576.0).ToString("0.###")); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} !app <appid or partial game name>", Colors.OLIVE); return; } uint appID; if (!uint.TryParse(command.Message, out appID)) { string name = command.Message; if (!Utils.ConvertUserInputToSQLSearch(ref name)) { CommandHandler.ReplyToCommand(command, "Your request is too short."); return; } using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `Apps` WHERE `Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name ORDER BY `LastUpdated` DESC LIMIT 1", new MySqlParameter("Name", name))) { if (Reader.Read()) { appID = Reader.GetUInt32("AppID"); } else { CommandHandler.ReplyToCommand(command, "Nothing was found matching your request."); return; } } } var apps = new List<uint>(); apps.Add(appID); JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(apps, Enumerable.Empty<uint>()), new JobManager.IRCRequest { Target = appID, Type = JobManager.IRCRequestType.TYPE_APP, Command = command } ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length > 0) { return; } // TODO: Correctly include commands for admins if an admin uses the command var commands = Commands .Where(cmd => !cmd.IsAdminCommand && cmd != this) .Select(cmd => cmd.Trigger); CommandHandler.ReplyToCommand(command, true, "Available commands: {0}{1}", Colors.OLIVE, string.Join(string.Format("{0}, {1}", Colors.NORMAL, Colors.OLIVE), commands)); }
public static void AddJob(Func<JobID> action, CommandArguments command) { var jobID = action(); var job = new JobAction { Action = action, Command = command }; // Chat rooms don't have full message saved Log.WriteDebug("Job Manager", "New chat job: {0} ({1})", jobID, command.Message); Jobs.TryAdd(jobID, job); }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} servers <filter> - See https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol", Colors.OLIVE); return; } if (command.Message.IndexOf('\\') == -1) { command.Reply("That doesn't look like a filter."); return; } var request = new CGameServers_GetServerList_Request { filter = command.Message, limit = 5000, }; var callback = await GameServers.SendMessage(api => api.GetServerList(request)); var response = callback.GetDeserializedResponse<CGameServers_GetServerList_Response>(); var servers = response.servers; if (!servers.Any()) { command.Reply("No servers."); return; } if (servers.Count == 1) { var server = servers.First(); command.Reply("{0} - {1} - {2}/{3} - Map: {4} - AppID: {5} - Version: {6} - Dir: {7} - Tags: {8} - Name: {9}", server.addr, new SteamID(server.steamid).Render(true), server.players, server.max_players, server.map, server.appid, server.version, server.gamedir, server.gametype, server.name ); return; } var serv = servers.Take(5).Select(x => string.Format("{0} ({1})", x.addr, x.players)); command.Reply("{0}{1}", string.Join(", ", serv), servers.Count > 5 ? string.Format(", and {0}{1} more", servers.Count == 5000 ? ">" : "", servers.Count - 5) : ""); }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.Message.Length > 0) { return; } // TODO: Correctly include commands for admins if an admin uses the command var commands = Commands .Where(cmd => !cmd.IsAdminCommand && cmd != this) .Select(cmd => cmd.Trigger); command.Notice("Available commands: {0}{1}", Colors.OLIVE, string.Join(string.Format("{0}, {1}", Colors.NORMAL, Colors.OLIVE), commands)); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} !players <appid or partial game name>", Colors.OLIVE); return; } uint appID; if (!uint.TryParse(command.Message, out appID)) { string name = command.Message; if (!Utils.ConvertUserInputToSQLSearch(ref name)) { CommandHandler.ReplyToCommand(command, "Your request is too short."); return; } using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `Apps` LEFT JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE `AppsTypes`.`Name` IN ('game', 'application') AND (`Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name) ORDER BY `LastUpdated` DESC LIMIT 1", new MySqlParameter("Name", name))) { if (Reader.Read()) { appID = Reader.GetUInt32("AppID"); } else { CommandHandler.ReplyToCommand(command, "Nothing was found matching your request."); return; } } } JobManager.AddJob( () => Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID), new JobManager.IRCRequest { Target = appID, Command = command } ); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} players <appid or partial game name>", Colors.OLIVE); CommandHandler.ReplyToCommand(command, true, "Use {0}^{1} and {2}${3} just like in regex to narrow down your match, e.g:{4} !players Portal$", Colors.BLUE, Colors.NORMAL, Colors.BLUE, Colors.NORMAL, Colors.OLIVE); return; } uint appID; if (!uint.TryParse(command.Message, out appID)) { string name = command.Message; if (!Utils.ConvertUserInputToSQLSearch(ref name)) { CommandHandler.ReplyToCommand(command, "Your request is invalid or too short."); return; } using (var db = Database.GetConnection()) { appID = db.ExecuteScalar<uint>("SELECT `AppID` FROM `Apps` LEFT JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE (`AppsTypes`.`Name` IN ('game', 'application') AND (`Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name)) OR (`AppsTypes`.`Name` = 'unknown' AND `Apps`.`LastKnownName` LIKE @Name) ORDER BY `LastUpdated` DESC LIMIT 1", new { Name = name }); } if (appID == 0) { CommandHandler.ReplyToCommand(command, "Nothing was found matching your request."); return; } } JobManager.AddJob( () => Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID), new JobManager.IRCRequest { Target = appID, Command = command } ); }
public override async void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} bins <{1}> [stable (returns publicbeta by default)]", Colors.OLIVE, string.Join("/", Systems)); return; } var args = command.Message.Split(' '); string os = args[0]; if (os == "windows") { os = "win32"; } else if (os == "linux") { os = "ubuntu12"; } if (!Systems.Contains(os)) { CommandHandler.ReplyToCommand(command, "Invalid OS. Valid ones are: {0}", string.Join(", ", Systems)); return; } using (var webClient = new WebClient()) { var isStable = args.Length > 1 && args[1].Equals("stable"); string data = await webClient.DownloadStringTaskAsync(new Uri(string.Format("{0}steam_client_{1}{2}?_={3}", CDN, isStable ? "" : "publicbeta_", os, DateTime.UtcNow.Ticks))); var kv = KeyValue.LoadFromString(data); if (kv == null) { throw new Exception("Failed to parse downloaded client manifest."); } PrintBinary(command, kv, string.Concat("bins_", os)); PrintBinary(command, kv, string.Concat("bins_client_", os)); } }
private static void OnCommandApp(CommandArguments command) { uint appID; if (command.MessageArray.Length == 2 && uint.TryParse(command.MessageArray[1], out appID)) { var jobID = Steam.Instance.Apps.PICSGetProductInfo(appID, null, false, false); SteamProxy.Instance.IRCRequests.Add(new SteamProxy.IRCRequest { JobID = jobID, Target = appID, Type = SteamProxy.IRCRequestType.TYPE_APP, Command = command }); } else { ReplyToCommand(command, "Usage:{0} !app <appid>", Colors.OLIVE); } }
public override void OnCommand(CommandArguments command) { using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ID`, `Slug`, `Title` FROM `Blog` WHERE `IsHidden` = 0 ORDER BY `ID` DESC LIMIT 1")) { if (Reader.Read()) { var slug = Reader.GetString("Slug"); if (slug.Length == 0) { slug = Reader.GetString("ID"); } CommandHandler.ReplyToCommand( command, "Latest blog post:{0} {1}{2} -{3} {4}", Colors.GREEN, Reader.GetString("Title"), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetBlogURL(slug) ); } } }
public override void OnCommand(CommandArguments command) { using (var webClient = new WebClient()) { webClient.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e) { var kv = new KeyValue(); using (var ms = new MemoryStream(e.Result)) { try { kv.ReadAsText(ms); } catch { CommandHandler.ReplyToCommand(command, "Something went horribly wrong and keyvalue parser died."); return; } } if (kv["bins_osx"].Children.Count == 0) { CommandHandler.ReplyToCommand(command, "Failed to find binaries in parsed response."); return; } kv = kv["bins_osx"]; CommandHandler.ReplyToCommand(command, "You're on your own:{0} {1}{2} {3}({4} MB)", Colors.DARKBLUE, CDN, kv["file"].AsString(), Colors.DARKGRAY, (kv["size"].AsLong() / 1048576.0).ToString("0.###")); }; webClient.DownloadDataAsync(new Uri(string.Format("{0}steam_client_publicbeta_osx?_={1}", CDN, DateTime.UtcNow.Ticks))); } }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.Message.Equals("list", StringComparison.CurrentCultureIgnoreCase)) { command.Reply(string.Join(", ", SteamKitEnums.Select(@enum => @enum.Name))); return; } if (command.Message.Length == 0) { command.Reply("Usage:{0} enum <enumname> [value or substring [deprecated]]", Colors.OLIVE); return; } var args = command.Message.Split(' '); var enumType = args[0].Replace("SteamKit2.", ""); var matchingEnumType = SteamKitEnums .FirstOrDefault(x => x.Name.Equals(enumType, StringComparison.OrdinalIgnoreCase) || GetDottedTypeName(x).IndexOf(enumType, StringComparison.OrdinalIgnoreCase) != -1); if (matchingEnumType == null) { command.Reply("No such enum type."); return; } bool includeDeprecated = args.Length > 2 && args[2].Equals("deprecated", StringComparison.OrdinalIgnoreCase); GetType().GetMethod("RunForEnum", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(matchingEnumType) .Invoke(this, new object[] { args.Length > 1 ? args[1] : string.Empty, command, includeDeprecated }); }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} ugc <ugcid>", Colors.OLIVE); return; } if (!ulong.TryParse(command.Message, out var ugcId)) { command.Reply("Invalid UGC ID"); return; } var task = Cloud.RequestUGCDetails(ugcId); task.Timeout = TimeSpan.FromSeconds(10); var callback = await task; if (callback.Result != EResult.OK) { command.Reply("Unable to request UGC info: {0}{1}", Colors.RED, callback.Result); return; } command.Reply("Creator: {0}{1}{2}, App: {3}{4}{5}, File: {6}{7}{8}, Size: {9}{10}{11} -{12} {13}", Colors.BLUE, callback.Creator.Render(), Colors.NORMAL, Colors.BLUE, callback.AppID, Colors.NORMAL, Colors.BLUE, callback.FileName, Colors.NORMAL, Colors.BLUE, GetByteSizeString(callback.FileSize), Colors.NORMAL, Colors.DARKBLUE, callback.URL ); }
private void HandleSteamMessage(CommandArguments commandData) { var message = commandData.Message; var i = message.IndexOf(' '); var inputCommand = i == -1 ? message.Substring(1) : message.Substring(1, i - 1); var command = RegisteredCommands.FirstOrDefault(cmd => cmd.Trigger.Equals(inputCommand)); if (command == null) { return; } commandData.Message = i == -1 ? string.Empty : message.Substring(i).Trim(); if (command.IsAdminCommand && !Settings.Current.SteamAdmins.Contains(commandData.SenderID.ConvertToUInt64())) { commandData.Reply("You're not an admin!"); return; } TryCommand(command, commandData); }
public void OnSteamChatMessage(SteamFriends.ChatMsgCallback callback) { if (callback.ChatMsgType != EChatEntryType.ChatMsg || callback.ChatterID == Steam.Instance.Client.SteamID) { return; } var commandData = new CommandArguments { CommandType = ECommandType.SteamChatRoom, SenderID = callback.ChatterID, ChatRoomID = callback.ChatRoomID, Message = callback.Message }; if (callback.Message[0] != Settings.Current.IRC.CommandPrefix || callback.Message.Contains('\n')) { return; } Log.WriteInfo("CommandHandler", "Handling Steam command \"{0}\" for {1}", callback.Message, commandData); HandleSteamMessage(commandData); }
public void OnSteamChatMessage(SteamFriends.ChatMsgCallback callback) { if (callback.ChatMsgType != EChatEntryType.ChatMsg || callback.ChatterID == Steam.Instance.Client.SteamID) { return; } var commandData = new CommandArguments { CommandType = ECommandType.SteamChatRoom, SenderID = callback.ChatterID, ChatRoomID = callback.ChatRoomID, Message = callback.Message }; PubFileHandler.OnMessage(commandData); LinkExpander.OnMessage(commandData); if (callback.Message[0] != Settings.Current.IRC.CommandPrefix || callback.Message.Contains('\n')) { return; } Log.WriteInfo("CommandHandler", "Handling Steam command \"{0}\" for {1}", callback.Message, commandData); HandleSteamMessage(commandData); }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} steamid <steamid> [individual/group/gamegroup]", Colors.OLIVE); return; } var args = command.Message.Split(' '); var urlType = EVanityURLType.Default; if (args.Length > 1) { switch (args[1]) { case "individual": urlType = EVanityURLType.Individual; break; case "group": urlType = EVanityURLType.Group; break; case "game": case "gamegroup": urlType = EVanityURLType.OfficialGameGroup; break; default: CommandHandler.ReplyToCommand(command, "Invalid vanity url type."); return; } } SteamID steamID; if (urlType != EVanityURLType.Default || !TrySetSteamID(args[0], out steamID)) { if (urlType == EVanityURLType.Default) { urlType = EVanityURLType.Individual; } var eResult = ResolveVanityURL(args[0], urlType, out steamID); if (eResult != EResult.OK) { CommandHandler.ReplyToCommand(command, "Failed to resolve vanity url: {0}{1}", Colors.RED, eResult.ToString()); return; } } CommandHandler.ReplyToCommand(command, ExpandSteamID(steamID)); if (!steamID.IsValid || (!steamID.IsIndividualAccount && !steamID.IsClanAccount)) { return; } JobAction job; if (JobManager.TryRemoveJob(new JobID(steamID), out job) && job.IsCommand) { CommandHandler.ReplyToCommand(job.CommandRequest.Command, true, "Your !steamid request was lost in space."); } JobManager.AddJob( () => FakePersonaStateJob(steamID), new JobManager.IRCRequest { Command = command } ); }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} app <appid or partial game name>", Colors.OLIVE); return; } string name; if (!uint.TryParse(command.Message, out var appID)) { name = command.Message; if (!Utils.ConvertUserInputToSQLSearch(ref name)) { command.Reply("Your request is invalid or too short."); return; } using (var db = Database.GetConnection()) { appID = db.ExecuteScalar <uint>("SELECT `AppID` FROM `Apps` WHERE `Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name OR `Apps`.`LastKnownName` LIKE @Name ORDER BY `LastUpdated` DESC LIMIT 1", new { Name = name }); } if (appID == 0) { command.Reply("Nothing was found matching your request."); return; } } var tokenCallback = await Steam.Instance.Apps.PICSGetAccessTokens(appID, null); SteamApps.PICSRequest request; if (tokenCallback.AppTokens.ContainsKey(appID)) { request = Utils.NewPICSRequest(appID, tokenCallback.AppTokens[appID]); } else { request = Utils.NewPICSRequest(appID); } var job = await Steam.Instance.Apps.PICSGetProductInfo(new List <SteamApps.PICSRequest> { request }, Enumerable.Empty <SteamApps.PICSRequest>()); var callback = job.Results.FirstOrDefault(x => x.Apps.ContainsKey(appID)); if (callback == null) { command.Reply("Unknown AppID: {0}{1}{2}", Colors.BLUE, appID, LicenseList.OwnedApps.ContainsKey(appID) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Apps[appID]; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString()); } else { name = Steam.GetAppName(info.ID); } info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", string.Format("{0}.vdf", info.ID)), false); command.Reply("{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawAppURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); if (command.IsUserAdmin && !LicenseList.OwnedApps.ContainsKey(info.ID)) { JobManager.AddJob(() => Steam.Instance.Apps.RequestFreeLicense(info.ID)); } }
public static async Task <uint> TrySearchAppId(CommandArguments command) { uint appID = 0; var name = command.Message; Uri uri; var query = new Dictionary <string, string> { { "hitsPerPage", "1" }, { "attributesToHighlight", "null" }, { "attributesToSnippet", "null" }, { "attributesToRetrieve", "[\"objectID\"]" }, { "facetFilters", "[[\"appType:Game\",\"appType:Application\"]]" }, { "advancedSyntax", "true" }, { "query", name } }; using (var content = new FormUrlEncodedContent(query)) { uri = new UriBuilder("https://94he6yatei-dsn.algolia.net/1/indexes/steamdb/") { Query = await content.ReadAsStringAsync() }.Uri; } using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri)) { requestMessage.Headers.Add("Referer", "https://github.com/SteamDatabase/SteamDatabaseBackend"); requestMessage.Headers.Add("X-Algolia-Application-Id", "94HE6YATEI"); requestMessage.Headers.Add("X-Algolia-API-Key", "2414d3366df67739fe6e73dad3f51a43"); try { var response = await Utils.HttpClient.SendAsync(requestMessage); var data = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject <AlgoliaSearchAppHits>(data); if (json.Hits.Length > 0) { appID = json.Hits[0].AppID; } } catch (Exception e) { ErrorReporter.Notify("Algolia search", e); } } if (appID > 0) { return(appID); } await using (var db = await Database.GetConnectionAsync()) { appID = await db.ExecuteScalarAsync <uint>("SELECT `AppID` FROM `Apps` LEFT JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE (`AppsTypes`.`Name` IN ('game', 'application', 'video', 'hardware') AND (`Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name)) OR (`AppsTypes`.`Name` = 'unknown' AND `Apps`.`LastKnownName` LIKE @Name) ORDER BY `LastUpdated` DESC LIMIT 1", new { Name = name }); } if (appID == 0) { command.Reply("Nothing was found matching your request."); } return(appID); }
public static void Reload(CommandArguments command) { Reload(); command.Notice($"Reloaded {AppTokens.Count} app tokens and {PackageTokens.Count} package tokens"); }
public override async Task OnCommand(CommandArguments command) { if (command.CommandType != ECommandType.IRC || !IRC.IsRecipientChannel(command.Recipient)) { command.Reply("This command is only available in channels."); return; } var channel = command.Recipient; var s = command.Message.Split(' '); var count = s.Length; if (count > 0) { uint id; switch (s[0]) { case "reload": await Application.ReloadImportant(command); PICSTokens.Reload(command); return; case "add": if (count < 3) { break; } if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": var exists = Application.ImportantApps.TryGetValue(id, out var channels); if (exists && channels.Contains(channel)) { command.Reply($"App {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetAppName(id)}) is already important in {Colors.BLUE}{channel}{Colors.NORMAL}."); } else { if (exists) { Application.ImportantApps[id].Add(channel); } else { Application.ImportantApps.Add(id, new List <string> { channel }); } await using (var db = await Database.GetConnectionAsync()) { await db.ExecuteAsync("INSERT INTO `ImportantApps` (`AppID`, `Channel`) VALUES (@AppID, @Channel)", new { AppID = id, Channel = channel }); } command.Reply($"Marked app {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetAppName(id)}) as important in {Colors.BLUE}{channel}{Colors.NORMAL}."); } return; case "sub": if (Application.ImportantSubs.ContainsKey(id)) { command.Reply($"Package {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetPackageName(id)}) is already important."); } else { Application.ImportantSubs.Add(id, 1); await using (var db = await Database.GetConnectionAsync()) { await db.ExecuteAsync("INSERT INTO `ImportantSubs` (`SubID`) VALUES (@SubID)", new { SubID = id }); } command.Reply($"Marked package {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetPackageName(id)}) as important."); } return; } break; case "remove": if (count < 3) { break; } if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": if (!Application.ImportantApps.TryGetValue(id, out var channels) || !channels.Contains(channel)) { command.Reply($"App {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetAppName(id)}) is not important in {Colors.BLUE}{channel}{Colors.NORMAL}."); } else { if (channels.Count > 1) { Application.ImportantApps[id].Remove(channel); } else { Application.ImportantApps.Remove(id); } await using (var db = await Database.GetConnectionAsync()) { await db.ExecuteAsync("DELETE FROM `ImportantApps` WHERE `AppID` = @AppID AND `Channel` = @Channel", new { AppID = id, Channel = channel }); } command.Reply($"Removed app {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetAppName(id)}) from the important list in {Colors.BLUE}{channel}{Colors.NORMAL}."); } return; case "sub": if (!Application.ImportantSubs.ContainsKey(id)) { command.Reply($"Package {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetPackageName(id)}) is not important."); } else { Application.ImportantSubs.Remove(id); await using (var db = await Database.GetConnectionAsync()) { await db.ExecuteAsync("DELETE FROM `ImportantSubs` WHERE `SubID` = @SubID", new { SubID = id }); } command.Reply($"Removed package {Colors.BLUE}{id}{Colors.NORMAL} ({Steam.GetPackageName(id)}) from the important list."); } return; } break; } } command.Reply($"Usage:{Colors.OLIVE} important reload {Colors.NORMAL}or{Colors.OLIVE} important <add/remove> <app/sub> <id>"); }
public void OnMessage(CommandArguments command) { var matches = SteamLinkMatch.Matches(command.Message); foreach (Match match in matches) { var page = match.Groups["page"].Value; // Ignore sub pages, easier to do it here rather than in regex if (!string.IsNullOrEmpty(page)) { continue; } var appType = string.Empty; var id = uint.Parse(match.Groups["id"].Value); var isPackage = match.Groups["type"].Value == "sub"; string name; if (isPackage) { name = Steam.GetPackageName(id); } else { App data; using (var db = Database.GetConnection()) { data = db.Query <App>("SELECT `AppID`, `Apps`.`Name`, `LastKnownName`, `AppsTypes`.`DisplayName` as `AppTypeString` FROM `Apps` JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE `AppID` = @AppID", new { AppID = id }).SingleOrDefault(); } if (data.AppID == 0) { continue; } name = string.IsNullOrEmpty(data.LastKnownName) ? data.Name : data.LastKnownName; name = Utils.RemoveControlCharacters(name); appType = data.AppTypeString; } if (command.Message.IndexOf(name, StringComparison.CurrentCultureIgnoreCase) >= 0) { continue; } string priceInfo = isPackage ? string.Empty : GetFormattedPrices(id); if (command.CommandType == ECommandType.SteamChatRoom) { Steam.Instance.Friends.SendChatRoomMessage(command.ChatRoomID, EChatEntryType.ChatMsg, string.Format("» {0} {1} — {2}{3}", isPackage ? "Package" : "App", id, Colors.StripColors(name), priceInfo)); continue; } if (!isPackage && command.Recipient == "#steamlug" && (appType == "Game" || appType == "Application")) { using (var db = Database.GetConnection()) { var status = db.ExecuteScalar <string>("SELECT `Status` FROM `LinuxSupport` WHERE `AppID` = @AppID", new { AppID = id }); switch (status) { case "working": priceInfo += " (✓ Confirmed for Linux)"; break; case "beta": priceInfo += " (Has a public Linux βeta)"; break; default: priceInfo += " (✘ Unknown Linux status)"; break; } } } IRC.Instance.SendReply(command.Recipient, string.Format("{0}» {1}{2} {3} —{4} {5}{6}{7}", Colors.OLIVE, Colors.NORMAL, isPackage ? "Package" : appType, id, Colors.BLUE, name, Colors.LIGHTGRAY, priceInfo ), false ); } }
public abstract void OnCommand(CommandArguments command);
public async void OnMessage(CommandArguments command) { var matches = SharedFileMatch.Matches(command.Message); foreach (Match match in matches) { if (!ulong.TryParse(match.Groups["pubfileid"].Value, out var pubFileId)) { continue; } Log.WriteInfo("Link Expander", "Will look up pubfile {0} for {1}", pubFileId, command); var pubFileRequest = new CPublishedFile_GetDetails_Request { includevotes = true, }; pubFileRequest.publishedfileids.Add(pubFileId); PublishedFileDetails details; try { var callback = await PublishedFiles.SendMessage(api => api.GetDetails(pubFileRequest)); var response = callback.GetDeserializedResponse <CPublishedFile_GetDetails_Response>(); details = response.publishedfiledetails.FirstOrDefault(); } catch (Exception e) { Log.WriteError("Link Expander", "Failed to get pubfile details: {0}", e.Message); continue; } if (details == null || (EResult)details.result != EResult.OK) { continue; } string title; if (!string.IsNullOrWhiteSpace(details.title)) { title = details.title; } else if (!string.IsNullOrEmpty(details.file_description)) { title = details.file_description; } else { title = details.filename; } if (title.Length > 49) { title = title.Substring(0, 49) + "…"; } var votesUp = details.vote_data?.votes_up ?? 0; var votesDown = details.vote_data?.votes_down ?? 0; if (command.CommandType == ECommandType.SteamChatRoom) { Steam.Instance.Friends.SendChatRoomMessage(command.ChatRoomID, EChatEntryType.ChatMsg, string.Format("» {0}: {1} for {2} ({3:N0} views, {4:N0} \ud83d\udc4d, {5:N0} \ud83d\udc4e){6}", (EWorkshopFileType)details.file_type, title, details.app_name, details.views, votesUp, votesDown, details.spoiler_tag ? " :retreat: SPOILER" : "" ) ); } else { IRC.Instance.SendReply(command.Recipient, string.Format("{0}» {1}{2} {3}{4}{5} for {6}{7}{8} ({9:N0} views, {10:N0} \ud83d\udc4d, {11:N0} \ud83d\udc4e)", Colors.OLIVE, Colors.NORMAL, (EWorkshopFileType)details.file_type, Colors.BLUE, title, Colors.NORMAL, Colors.BLUE, details.app_name, Colors.LIGHTGRAY, details.views, votesUp, votesDown ), false ); } } }
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply("Usage:{0} app <appid or partial game name>", Colors.OLIVE); return; } string name; if (!uint.TryParse(command.Message, out var appID)) { appID = await TrySearchAppId(command); if (appID == 0) { return; } } var tokenCallback = await Steam.Instance.Apps.PICSGetAccessTokens(appID, null); SteamApps.PICSRequest request; if (tokenCallback.AppTokens.ContainsKey(appID)) { request = Utils.NewPICSRequest(appID, tokenCallback.AppTokens[appID]); } else { request = Utils.NewPICSRequest(appID); } var job = await Steam.Instance.Apps.PICSGetProductInfo(new List <SteamApps.PICSRequest> { request }, Enumerable.Empty <SteamApps.PICSRequest>()); var callback = job.Results.FirstOrDefault(x => x.Apps.ContainsKey(appID)); if (callback == null) { command.Reply("Unknown AppID: {0}{1}{2}", Colors.BLUE, appID, LicenseList.OwnedApps.ContainsKey(appID) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Apps[appID]; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString()); } else { name = Steam.GetAppName(info.ID); } info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", string.Format("{0}.vdf", info.ID)), false); command.Reply("{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawAppURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); if (command.IsUserAdmin && !LicenseList.OwnedApps.ContainsKey(info.ID)) { JobManager.AddJob(() => Steam.Instance.Apps.RequestFreeLicense(info.ID)); } }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} players <appid or partial game name>", Colors.OLIVE); return; } uint appID; string name; if (!uint.TryParse(command.Message, out appID)) { name = command.Message; using (var webClient = new WebClient()) { webClient.QueryString.Add("x-algolia-application-id", "94HE6YATEI"); webClient.QueryString.Add("x-algolia-api-key", "2414d3366df67739fe6e73dad3f51a43"); webClient.QueryString.Add("hitsPerPage", "1"); webClient.QueryString.Add("attributesToHighlight", "null"); webClient.QueryString.Add("attributesToSnippet", "null"); webClient.QueryString.Add("attributesToRetrieve", "[\"objectID\"]"); webClient.QueryString.Add("facetFilters", "[[\"appType:Game\",\"appType:Application\"]]"); webClient.QueryString.Add("advancedSyntax", "true"); webClient.QueryString.Add("query", name); var data = await webClient.DownloadStringTaskAsync("https://94he6yatei-dsn.algolia.net/1/indexes/steamdb/"); dynamic json = JsonConvert.DeserializeObject(data); if (json.hits != null && json.hits.Count > 0) { appID = json.hits[0].objectID; } } if (appID == 0) { if (!Utils.ConvertUserInputToSQLSearch(ref name)) { command.Reply("Your request is invalid or too short."); return; } using (var db = Database.GetConnection()) { appID = db.ExecuteScalar <uint>("SELECT `AppID` FROM `Apps` LEFT JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE (`AppsTypes`.`Name` IN ('game', 'application', 'video', 'hardware') AND (`Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name)) OR (`AppsTypes`.`Name` = 'unknown' AND `Apps`.`LastKnownName` LIKE @Name) ORDER BY `LastUpdated` DESC LIMIT 1", new { Name = name }); } } if (appID == 0) { command.Reply("Nothing was found matching your request."); return; } } var callback = await Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID); if (appID == 0) { appID = 753; } string appType, type = "playing"; name = Steam.GetAppName(appID, out appType); if (callback.Result != EResult.OK) { command.Reply("Unable to request player count for {0}{1}{2}: {3}{4}", Colors.BLUE, name, Colors.NORMAL, Colors.RED, callback.Result); return; } switch (appType) { case "Tool": case "Config": case "Application": type = "using"; break; case "Legacy Media": case "Video": type = "watching"; break; case "Guide": type = "reading"; break; case "Hardware": type = "bricking"; break; } command.Reply( "People {0} {1}{2}{3} right now: {4}{5:N0}{6} -{7} {8}", type, Colors.BLUE, name, Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(appID, "graphs") ); }
public override void OnCommand(CommandArguments command) { if (command.CommandType != ECommandType.IRC || !IRC.IsRecipientChannel(command.Recipient)) { CommandHandler.ReplyToCommand(command, "This command is only available in channels."); return; } var channel = command.Recipient; var s = command.Message.Split(' '); var count = s.Length; if (count > 0) { switch (s[0]) { case "reload": { Application.ReloadImportant(command); PICSTokens.Reload(command); FileDownloader.ReloadFileList(); return; } case "add": { if (count < 3) { break; } uint id; if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": { List <string> channels; var exists = Application.ImportantApps.TryGetValue(id, out channels); if (exists && channels.Contains(channel)) { CommandHandler.ReplyToCommand(command, "App {0}{1}{2} ({3}) is already important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } else { if (exists) { Application.ImportantApps[id].Add(channel); } else { Application.ImportantApps.Add(id, new List <string> { channel }); } using (var db = Database.GetConnection()) { db.Execute("INSERT INTO `ImportantApps` (`AppID`, `Channel`) VALUES (@AppID, @Channel)", new { AppID = id, Channel = channel }); } CommandHandler.ReplyToCommand(command, "Marked app {0}{1}{2} ({3}) as important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } return; } case "sub": { if (Application.ImportantSubs.ContainsKey(id)) { CommandHandler.ReplyToCommand(command, "Package {0}{1}{2} ({3}) is already important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } else { Application.ImportantSubs.Add(id, 1); using (var db = Database.GetConnection()) { db.Execute("INSERT INTO `ImportantSubs` (`SubID`) VALUES (@SubID)", new { SubID = id }); } CommandHandler.ReplyToCommand(command, "Marked package {0}{1}{2} ({3}) as important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } return; } } break; } case "remove": { if (count < 3) { break; } uint id; if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": { List <string> channels; if (!Application.ImportantApps.TryGetValue(id, out channels) || !channels.Contains(channel)) { CommandHandler.ReplyToCommand(command, "App {0}{1}{2} ({3}) is not important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } else { if (channels.Count > 1) { Application.ImportantApps[id].Remove(channel); } else { Application.ImportantApps.Remove(id); } using (var db = Database.GetConnection()) { db.Execute("DELETE FROM `ImportantApps` WHERE `AppID` = @AppID AND `Channel` = @Channel", new { AppID = id, Channel = channel }); } CommandHandler.ReplyToCommand(command, "Removed app {0}{1}{2} ({3}) from the important list in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } return; } case "sub": { if (!Application.ImportantSubs.ContainsKey(id)) { CommandHandler.ReplyToCommand(command, "Package {0}{1}{2} ({3}) is not important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } else { Application.ImportantSubs.Remove(id); using (var db = Database.GetConnection()) { db.Execute("DELETE FROM `ImportantSubs` WHERE `SubID` = @SubID", new { SubID = id }); } CommandHandler.ReplyToCommand(command, "Removed package {0}{1}{2} ({3}) from the important list.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } return; } } break; } case "queue": { if (count < 3) { break; } uint id; if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": { string name; using (var db = Database.GetConnection()) { name = db.ExecuteScalar <string>("SELECT `Name` FROM `Apps` WHERE `AppID` = @AppID", new { AppID = id }); } if (!string.IsNullOrEmpty(name)) { StoreQueue.AddAppToQueue(id); CommandHandler.ReplyToCommand(command, "App {0}{1}{2} ({3}) has been added to the store update queue.", Colors.BLUE, id, Colors.NORMAL, Utils.RemoveControlCharacters(name)); return; } CommandHandler.ReplyToCommand(command, "This app is not in the database."); return; } case "sub": { if (id == 0) { CommandHandler.ReplyToCommand(command, "Sub 0 can not be queued."); return; } string name; using (var db = Database.GetConnection()) { name = db.ExecuteScalar <string>("SELECT `Name` FROM `Subs` WHERE `SubID` = @SubID", new { SubID = id }); } if (!string.IsNullOrEmpty(name)) { StoreQueue.AddPackageToQueue(id); CommandHandler.ReplyToCommand(command, "Package {0}{1}{2} ({3}) has been added to the store update queue.", Colors.BLUE, id, Colors.NORMAL, Utils.RemoveControlCharacters(name)); return; } CommandHandler.ReplyToCommand(command, "This package is not in the database."); return; } } break; } } } CommandHandler.ReplyToCommand(command, "Usage:{0} important reload {1}or{2} important <add/remove/queue> <app/sub> <id>", Colors.OLIVE, Colors.NORMAL, Colors.OLIVE); }
public static void ReloadImportant(CommandArguments command) { ReloadImportant(); command.ReplyAsNotice = true; CommandHandler.ReplyToCommand(command, "Reloaded {0} important apps and {1} packages", ImportantApps.Count, ImportantSubs.Count); }
public static void Reload(CommandArguments command) { Reload(); command.Notice("Reloaded {0} token overrides", SecretTokens.Count); }
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply($"Usage:{Colors.OLIVE} players <appid or partial game name>"); return; } if (!uint.TryParse(command.Message, out var appID)) { appID = await AppCommand.TrySearchAppId(command); if (appID == 0) { return; } } var task = Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID); task.Timeout = TimeSpan.FromSeconds(10); var callback = await task; if (appID == 0) { appID = 753; } var name = Steam.GetAppName(appID, out var appType); if (callback.Result != EResult.OK) { command.Reply($"Unable to request player count for {Colors.BLUE}{name}{Colors.NORMAL}: {Colors.RED}{callback.Result}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetAppUrl(appID, "graphs")}"); return; } var numPlayers = callback.NumPlayers; uint dailyPlayers; await using (var db = await Database.GetConnectionAsync()) { dailyPlayers = await db.ExecuteScalarAsync <uint>("SELECT `MaxDailyPlayers` FROM `OnlineStats` WHERE `AppID` = @appID", new { appID }); if (appID == 753 && numPlayers == 0) { numPlayers = await db.ExecuteScalarAsync <uint>("SELECT `CurrentPlayers` FROM `OnlineStats` WHERE `AppID` = @appID", new { appID }); } } if (dailyPlayers < numPlayers) { dailyPlayers = numPlayers; } var type = "playing"; switch (appType) { case EAppType.Tool: case EAppType.Config: case EAppType.Application: type = "using"; break; case EAppType.Media: case EAppType.Series: case EAppType.Video: type = "watching"; break; case EAppType.Demo: type = "demoing"; break; case EAppType.Guide: case EAppType.Comic: type = "reading"; break; case EAppType.Hardware: type = "bricking"; break; } command.Reply( $"{Colors.OLIVE}{numPlayers:N0}{Colors.NORMAL} {type} {Colors.BLUE}{name}{Colors.NORMAL} - 24h:{Colors.GREEN} {dailyPlayers:N0}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetAppUrl(appID, "graphs")}" ); }
public abstract Task OnCommand(CommandArguments command);
public void OnMessage(CommandArguments command) { var matches = SteamLinkMatch.Matches(command.Message); foreach (Match match in matches) { var page = match.Groups["page"].Value; // Ignore sub pages, easier to do it here rather than in regex if (!string.IsNullOrEmpty(page)) { continue; } var appType = string.Empty; var id = uint.Parse(match.Groups["id"].Value); var isPackage = match.Groups["type"].Value == "sub"; string name; if (isPackage) { name = Steam.GetPackageName(id); } else { App data; using (var db = Database.Get()) { data = db.Query <App>("SELECT `AppID`, `Apps`.`Name`, `LastKnownName`, `AppsTypes`.`DisplayName` as `AppTypeString` FROM `Apps` JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE `AppID` = @AppID", new { AppID = id }).SingleOrDefault(); } if (data.AppID == 0) { continue; } name = string.IsNullOrEmpty(data.LastKnownName) ? data.Name : data.LastKnownName; name = Utils.RemoveControlCharacters(name); appType = data.AppTypeString; } if (command.Message.IndexOf(name, StringComparison.CurrentCultureIgnoreCase) >= 0) { continue; } string priceInfo = isPackage ? string.Empty : GetFormattedPrices(id); IRC.Instance.SendReply(command.Recipient, string.Format("{0}» {1}{2} {3} —{4} {5}{6}{7}", Colors.OLIVE, Colors.NORMAL, isPackage ? "Package" : appType, id, Colors.BLUE, name, Colors.LIGHTGRAY, priceInfo ), false ); } }
private void HandleSteamMessage(CommandArguments commandData) { var message = commandData.Message; var i = message.IndexOf(' '); var inputCommand = i == -1 ? message.Substring(1) : message[1..i];
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply($"Usage:{Colors.OLIVE} app <appid or partial game name>"); return; } string name; if (!uint.TryParse(command.Message, out var appID)) { appID = await TrySearchAppId(command); if (appID == 0) { return; } } var tokenTask = Steam.Instance.Apps.PICSGetAccessTokens(appID, null); tokenTask.Timeout = TimeSpan.FromSeconds(10); var tokenCallback = await tokenTask; SteamApps.PICSRequest request; if (tokenCallback.AppTokens.ContainsKey(appID)) { request = PICSTokens.NewAppRequest(appID, tokenCallback.AppTokens[appID]); } else { request = PICSTokens.NewAppRequest(appID); } var infoTask = Steam.Instance.Apps.PICSGetProductInfo(new List <SteamApps.PICSRequest> { request }, Enumerable.Empty <SteamApps.PICSRequest>()); infoTask.Timeout = TimeSpan.FromSeconds(10); var job = await infoTask; var callback = job.Results?.FirstOrDefault(x => x.Apps.ContainsKey(appID)); if (callback == null) { command.Reply($"Unknown AppID: {Colors.BLUE}{appID}{(LicenseList.OwnedApps.ContainsKey(appID) ? SteamDB.StringCheckmark : string.Empty)}"); return; } var info = callback.Apps[appID]; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.LimitStringLength(Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString())); } else { name = Steam.GetAppName(info.ID); } info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", $"{info.ID}.vdf"), false); command.Reply($"{Colors.BLUE}{name}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetAppUrl(info.ID)}{Colors.NORMAL} - Dump:{Colors.DARKBLUE} {SteamDB.GetRawAppUrl(info.ID)}{Colors.NORMAL}{(info.MissingToken ? SteamDB.StringNeedToken : string.Empty)}{(LicenseList.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty)}"); if (command.IsUserAdmin && !LicenseList.OwnedApps.ContainsKey(info.ID)) { JobManager.AddJob(() => Steam.Instance.Apps.RequestFreeLicense(info.ID)); } }
private static async void TryCommand(Command command, CommandArguments commandData) { try { await command.OnCommand(commandData); } catch (TaskCanceledException) { commandData.Reply("Your command timed out."); } catch (AsyncJobFailedException) { commandData.Reply("Steam says this job failed, unable to execute your command."); } catch (Exception e) { commandData.Reply("Exception: {0}", e.Message); ErrorReporter.Notify(e); } }
public override async Task OnCommand(CommandArguments command) { var s = command.Message.Split(' '); if (s.Length < 2) { command.Reply("Usage:{0} queue <app/sub> <id>", Colors.OLIVE); return; } if (!uint.TryParse(s[1], out var id)) { command.Reply("Your ID does not look like a number."); return; } string name; switch (s[0]) { case "app": using (var db = Database.Get()) { name = await db.ExecuteScalarAsync <string>("SELECT `Name` FROM `Apps` WHERE `AppID` = @AppID", new { AppID = id }); } if (!string.IsNullOrEmpty(name)) { await StoreQueue.AddAppToQueue(id); command.Reply("App {0}{1}{2} ({3}) has been added to the store update queue.", Colors.BLUE, id, Colors.NORMAL, Utils.RemoveControlCharacters(name)); return; } command.Reply("This app is not in the database."); return; case "package": case "sub": if (id == 0) { command.Reply("Sub 0 can not be queued."); return; } using (var db = Database.Get()) { name = await db.ExecuteScalarAsync <string>("SELECT `Name` FROM `Subs` WHERE `SubID` = @SubID", new { SubID = id }); } if (!string.IsNullOrEmpty(name)) { await StoreQueue.AddPackageToQueue(id); command.Reply("Package {0}{1}{2} ({3}) has been added to the store update queue.", Colors.BLUE, id, Colors.NORMAL, Utils.RemoveControlCharacters(name)); return; } command.Reply("This package is not in the database."); return; default: command.Reply("You can only queue apps and packages."); return; } }
public static void ReloadImportant(CommandArguments command) { ReloadImportant(); command.Notice("Reloaded {0} important apps and {1} packages", ImportantApps.Count, ImportantSubs.Count); }
public void OnIRCMessage(object sender, ChatMessageEventArgs e) { var commandData = new CommandArguments { CommandType = ECommandType.IRC, SenderIdentity = e.Sender, Recipient = e.Recipient, Message = e.Message }; if (Steam.Instance.Client.IsConnected) { PubFileHandler.OnMessage(commandData); } LinkExpander.OnMessage(commandData); if (e.Message[0] != Settings.Current.IRC.CommandPrefix) { return; } var message = (string)e.Message; var messageArray = message.Split(' '); var trigger = messageArray[0]; if (trigger.Length < 2) { return; } trigger = trigger.Substring(1); var command = RegisteredCommands.FirstOrDefault(cmd => cmd.Trigger.Equals(trigger)); if (command == null) { return; } commandData.Message = message.Substring(messageArray[0].Length).Trim(); if (command.IsSteamCommand && !Steam.Instance.Client.IsConnected) { commandData.Reply("Not connected to Steam."); return; } if (command.IsAdminCommand) { var ident = string.Format("{0}@{1}", e.Sender.Username, e.Sender.Hostname); if (!Settings.Current.IRC.Admins.Contains(ident)) { return; } } Log.WriteInfo("CommandHandler", "Handling IRC command \"{0}\" for {1}", message, commandData); TryCommand(command, commandData); }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.Message.Length == 0) { command.Reply("Usage:{0} steamid <steamid> [individual/group/gamegroup]", Colors.OLIVE); return; } var args = command.Message.Split(' '); var urlType = EVanityURLType.Default; if (args.Length > 1) { switch (args[1]) { case "individual": urlType = EVanityURLType.Individual; break; case "group": urlType = EVanityURLType.Group; break; case "game": case "gamegroup": urlType = EVanityURLType.OfficialGameGroup; break; default: command.Reply("Invalid vanity url type."); return; } } SteamID steamID; if (urlType != EVanityURLType.Default || !TrySetSteamID(args[0], out steamID)) { if (urlType == EVanityURLType.Default) { urlType = EVanityURLType.Individual; } var eResult = ResolveVanityURL(args[0], urlType, out steamID); if (eResult != EResult.OK) { command.Reply("Failed to resolve vanity url: {0}{1}", Colors.RED, eResult.ToString()); return; } } command.Reply(ExpandSteamID(steamID)); if (!steamID.IsValid || (!steamID.IsIndividualAccount && !steamID.IsClanAccount)) { return; } JobManager.TryRemoveJob(new JobID(steamID)); // Remove previous "job" if any JobManager.AddJob( () => FakePersonaStateJob(steamID), command ); }
public void OnSteamFriendMessage(SteamFriends.FriendMsgCallback callback) { if (callback.EntryType != EChatEntryType.ChatMsg // Is chat message || callback.Sender == Steam.Instance.Client.SteamID // Is not sent by the bot || callback.Message[0] != Settings.Current.IRC.CommandPrefix || callback.Message.Contains('\n') // Does not contain new lines ) { return; } var commandData = new CommandArguments { CommandType = ECommandType.SteamIndividual, SenderID = callback.Sender, Message = callback.Message }; Log.WriteInfo("CommandHandler", "Handling Steam friend command \"{0}\" for {1}", callback.Message, commandData); HandleSteamMessage(commandData); }
public async void OnMessage(CommandArguments command) { var matches = SharedFileMatch.Matches(command.Message); foreach (Match match in matches) { if (!ulong.TryParse(match.Groups["pubfileid"].Value, out var pubFileId)) { continue; } Log.WriteInfo("Link Expander", "Will look up pubfile {0} for {1}", pubFileId, command); var pubFileRequest = new CPublishedFile_GetDetails_Request { includevotes = true, }; pubFileRequest.publishedfileids.Add(pubFileId); PublishedFileDetails details; try { var task = PublishedFiles.SendMessage(api => api.GetDetails(pubFileRequest)); task.Timeout = TimeSpan.FromSeconds(10); var callback = await task; var response = callback.GetDeserializedResponse <CPublishedFile_GetDetails_Response>(); details = response.publishedfiledetails.FirstOrDefault(); } catch (Exception e) { Log.WriteError("Link Expander", "Failed to get pubfile details: {0}", e.Message); continue; } if (details == null || (EResult)details.result != EResult.OK) { continue; } string title; if (!string.IsNullOrWhiteSpace(details.title)) { title = details.title; } else if (!string.IsNullOrEmpty(details.file_description)) { title = details.file_description; } else { title = details.filename; } if (title.Length > 49) { title = title.Substring(0, 49) + "…"; } var votesUp = details.vote_data?.votes_up ?? 0; var votesDown = details.vote_data?.votes_down ?? 0; IRC.Instance.SendReply(command.Recipient, string.Format("{0}» {1}{2} {3}{4}{5} for {6}{7}{8} ({9:N0} views, {10:N0} \ud83d\udc4d, {11:N0} \ud83d\udc4e)", Colors.OLIVE, Colors.NORMAL, (EWorkshopFileType)details.file_type, Colors.BLUE, Utils.RemoveControlCharacters(title), Colors.NORMAL, Colors.BLUE, Utils.LimitStringLength(Utils.RemoveControlCharacters(details.app_name)), Colors.LIGHTGRAY, details.views, votesUp, votesDown ), false ); } }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0 || !uint.TryParse(command.Message, out var subID)) { command.Reply("Usage:{0} sub <subid>", Colors.OLIVE); return; } var tokenTask = Steam.Instance.Apps.PICSGetAccessTokens(null, subID); tokenTask.Timeout = TimeSpan.FromSeconds(10); var tokenCallback = await tokenTask; SteamApps.PICSRequest request; if (tokenCallback.PackageTokens.ContainsKey(subID)) { request = PICSTokens.NewPackageRequest(subID, tokenCallback.PackageTokens[subID]); } else { request = PICSTokens.NewPackageRequest(subID); } var infoTask = Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty <SteamApps.PICSRequest>(), new List <SteamApps.PICSRequest> { request }); infoTask.Timeout = TimeSpan.FromSeconds(10); var job = await infoTask; var callback = job.Results?.FirstOrDefault(x => x.Packages.ContainsKey(subID)); if (callback == null) { command.Reply("Unknown SubID: {0}{1}{2}", Colors.BLUE, subID, LicenseList.OwnedSubs.ContainsKey(subID) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Packages[subID]; if (!info.KeyValues.Children.Any()) { command.Reply("No package info returned for SubID: {0}{1}{2}{3}", Colors.BLUE, subID, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedSubs.ContainsKey(subID) ? SteamDB.StringCheckmark : string.Empty ); return; } info.KeyValues.SaveToFile(Path.Combine(Application.Path, "sub", string.Format("{0}.vdf", info.ID)), false); command.Reply("{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, Steam.GetPackageName(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageUrl(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawPackageUrl(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedSubs.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} pubfile <pubfileid>", Colors.OLIVE); return; } if (!ulong.TryParse(command.Message, out var pubFileId)) { command.Reply("Invalid Published File ID"); return; } var pubFileRequest = new CPublishedFile_GetDetails_Request { includeadditionalpreviews = true, includechildren = true, includetags = true, includekvtags = true, includevotes = true, includeforsaledata = true, includemetadata = true, }; pubFileRequest.publishedfileids.Add(pubFileId); var task = PublishedFiles.SendMessage(api => api.GetDetails(pubFileRequest)); task.Timeout = TimeSpan.FromSeconds(10); var callback = await task; var response = callback.GetDeserializedResponse <CPublishedFile_GetDetails_Response>(); var details = response.publishedfiledetails.FirstOrDefault(); if (details == null) { command.Reply("Unable to make service request for published file info: the server returned no info"); return; } var result = (EResult)details.result; if (result != EResult.OK) { command.Reply("Unable to get published file info: {0}{1}", Colors.RED, result); return; } var json = JsonConvert.SerializeObject(details, Formatting.Indented); File.WriteAllText(Path.Combine(Application.Path, "ugc", string.Format("{0}.json", details.publishedfileid)), json, Encoding.UTF8); command.Reply("{0}, Title: {1}{2}{3}, Creator: {4}{5}{6}, App: {7}{8}{9}{10}, File UGC: {11}{12}{13}, Preview UGC: {14}{15}{16} -{17} {18}", (EWorkshopFileType)details.file_type, Colors.BLUE, string.IsNullOrWhiteSpace(details.title) ? "[no title]" : details.title, Colors.NORMAL, Colors.BLUE, new SteamID(details.creator).Render(true), Colors.NORMAL, Colors.BLUE, details.creator_appid, details.creator_appid == details.consumer_appid ? "" : string.Format(" (consumer {0})", details.consumer_appid), Colors.NORMAL, Colors.BLUE, details.hcontent_file, Colors.NORMAL, Colors.BLUE, details.hcontent_preview, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetUGCURL(details.publishedfileid) ); command.Notice("{0} - https://steamcommunity.com/sharedfiles/filedetails/?id={1}", details.file_url, details.publishedfileid); }
public void OnIRCMessage(object sender, ChatMessageEventArgs e) { var commandData = new CommandArguments { CommandType = ECommandType.IRC, SenderIdentity = e.Sender, Nickname = e.Sender.Nickname.ToString(), Recipient = e.Recipient, Message = e.Message }; if (commandData.SenderIdentity.Hostname == "steamdb/discord-relay") { var match = DiscordRelayMessageRegex.Match(commandData.Message); if (!match.Success) { return; } // Remove IRC colors, remove control characters, remove zero width space, add @ and a space commandData.Nickname = $"@{Utils.RemoveControlCharacters(Colors.StripColors(match.Groups["name"].Value.Replace("\u200B", "")))} "; commandData.Message = match.Groups["message"].Value; } if (commandData.Message[0] != Settings.Current.IRC.CommandPrefix) { return; } var message = commandData.Message; var messageArray = message.Split(' '); var trigger = messageArray[0]; if (trigger.Length < 2) { return; } trigger = trigger.Substring(1); var command = RegisteredCommands.Find(cmd => cmd.Trigger == trigger); if (command == null) { return; } commandData.Message = message.Substring(messageArray[0].Length).Trim(); if (command.IsSteamCommand && !Steam.Instance.Client.IsConnected) { commandData.Reply("Not connected to Steam."); return; } var ident = $"{e.Sender.Username}@{e.Sender.Hostname}"; commandData.IsUserAdmin = Settings.Current.IRC.Admins.Contains(ident); if (command.IsAdminCommand && !commandData.IsUserAdmin) { return; } Log.WriteInfo(nameof(CommandHandler), $"Handling IRC command \"{Utils.RemoveControlCharacters(Colors.StripColors(message))}\" for {commandData}"); TryCommand(command, commandData); }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.CommandType != ECommandType.IRC || !IRC.IsRecipientChannel(command.Recipient)) { command.Reply("This command is only available in channels."); return; } var channel = command.Recipient; var s = command.Message.Split(' '); var count = s.Length; uint id; if (count > 0) { switch (s[0]) { case "reload": Application.ReloadImportant(command); PICSTokens.Reload(command); FileDownloader.ReloadFileList(); return; case "add": if (count < 3) { break; } if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": List <string> channels; var exists = Application.ImportantApps.TryGetValue(id, out channels); if (exists && channels.Contains(channel)) { command.Reply("App {0}{1}{2} ({3}) is already important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } else { if (exists) { Application.ImportantApps[id].Add(channel); } else { Application.ImportantApps.Add(id, new List <string> { channel }); } using (var db = Database.GetConnection()) { db.Execute("INSERT INTO `ImportantApps` (`AppID`, `Channel`) VALUES (@AppID, @Channel)", new { AppID = id, Channel = channel }); } command.Reply("Marked app {0}{1}{2} ({3}) as important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } return; case "sub": if (Application.ImportantSubs.ContainsKey(id)) { command.Reply("Package {0}{1}{2} ({3}) is already important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } else { Application.ImportantSubs.Add(id, 1); using (var db = Database.GetConnection()) { db.Execute("INSERT INTO `ImportantSubs` (`SubID`) VALUES (@SubID)", new { SubID = id }); } command.Reply("Marked package {0}{1}{2} ({3}) as important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } return; } break; case "remove": if (count < 3) { break; } if (!uint.TryParse(s[2], out id)) { break; } switch (s[1]) { case "app": List <string> channels; if (!Application.ImportantApps.TryGetValue(id, out channels) || !channels.Contains(channel)) { command.Reply("App {0}{1}{2} ({3}) is not important in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } else { if (channels.Count > 1) { Application.ImportantApps[id].Remove(channel); } else { Application.ImportantApps.Remove(id); } using (var db = Database.GetConnection()) { db.Execute("DELETE FROM `ImportantApps` WHERE `AppID` = @AppID AND `Channel` = @Channel", new { AppID = id, Channel = channel }); } command.Reply("Removed app {0}{1}{2} ({3}) from the important list in {4}{5}{6}.", Colors.BLUE, id, Colors.NORMAL, Steam.GetAppName(id), Colors.BLUE, channel, Colors.NORMAL); } return; case "sub": if (!Application.ImportantSubs.ContainsKey(id)) { command.Reply("Package {0}{1}{2} ({3}) is not important.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } else { Application.ImportantSubs.Remove(id); using (var db = Database.GetConnection()) { db.Execute("DELETE FROM `ImportantSubs` WHERE `SubID` = @SubID", new { SubID = id }); } command.Reply("Removed package {0}{1}{2} ({3}) from the important list.", Colors.BLUE, id, Colors.NORMAL, Steam.GetPackageName(id)); } return; } break; } } command.Reply("Usage:{0} important reload {1}or{2} important <add/remove> <app/sub> <id>", Colors.OLIVE, Colors.NORMAL, Colors.OLIVE); }