private void PrintImportants(SteamApps.PICSChangesCallback callback) { // Apps var important = callback.AppChanges.Keys.Intersect(Application.ImportantApps.Keys); string appType; string appName; foreach (var app in important) { appName = Steam.GetAppName(app, out appType); IRC.Instance.AnnounceImportantAppUpdate(app, "{0} update: {1}{2}{3} -{4} {5}", appType, Colors.BLUE, appName, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(app, "history")); } // Packages important = callback.PackageChanges.Keys.Intersect(Application.ImportantSubs.Keys); foreach (var package in important) { IRC.Instance.AnnounceImportantPackageUpdate(package, "Package update: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.GetPackageName(package), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(package, "history")); } }
private static void OnNumberOfPlayers(SteamUserStats.NumberOfPlayersCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(request.Command, "Unable to request player count: {0}{1}", Colors.RED, callback.Result); } else if (request.Target == 0) { CommandHandler.ReplyToCommand( request.Command, "{0}{1:N0}{2} people praising lord Gaben right now, influence:{3} {4}", Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(753, "graphs") ); } else { CommandHandler.ReplyToCommand( request.Command, "People playing {0}{1}{2} right now: {3}{4:N0}{5} -{6} {7}", Colors.BLUE, Steam.GetAppName(request.Target), Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(request.Target, "graphs") ); } }
private void PrintImportants(SteamApps.PICSChangesCallback callback) { // Apps var important = callback.AppChanges.Keys.Intersect(Application.ImportantApps.Keys); foreach (var app in important) { var appName = Steam.GetAppName(app, out var appType); IRC.Instance.AnnounceImportantAppUpdate(app, "{0} update: {1}{2}{3} -{4} {5}", appType, Colors.BLUE, appName, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(app, "history")); if (Settings.Current.CanQueryStore) { Steam.Instance.UnifiedMessages.SendMessage("ChatRoom.SendChatMessage#1", new CChatRoom_SendChatMessage_Request { chat_group_id = 1147, chat_id = 10208600, message = $"[Changelist {callback.CurrentChangeNumber}] {appType} update: {appName}\n{SteamDB.GetAppURL(app, "history")}?utm_source=Steam&utm_medium=Steam&utm_campaign=SteamDB%20Group%20Chat" }); } } // Packages important = callback.PackageChanges.Keys.Intersect(Application.ImportantSubs.Keys); foreach (var package in important) { IRC.Instance.AnnounceImportantPackageUpdate(package, "Package update: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.GetPackageName(package), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(package, "history")); } }
public void OnNumberOfPlayers(SteamUserStats.NumberOfPlayersCallback callback, JobID jobID) { var request = IRCRequests.Find(r => r.JobID == jobID); if (request == null) { return; } IRCRequests.Remove(request); if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: Unable to request player count: {3}", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL, callback.Result); } else if (request.Target == 0) { CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: {3}{4:N0}{5} people praising lord Gaben right now, influence:{6} {7}", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetGraphURL(0)); } else { string graphUrl = string.Empty; string name = GetAppName(request.Target); using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `ImportantApps` WHERE (`Graph` = 1 OR `MaxPlayers` > 0) AND `AppID` = @AppID", new MySqlParameter("AppID", request.Target))) { if (Reader.Read()) { graphUrl = string.Format("{0} -{1} {2}", Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetGraphURL(request.Target)); } } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: People playing {3}{4}{5} right now: {6}{7:N0}{8} -{9} {10}{11}", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL, Colors.OLIVE, name, Colors.NORMAL, Colors.GREEN, callback.NumPlayers, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetAppURL(request.Target), graphUrl); } }
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 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 = Utils.NewPICSRequest(appID, tokenCallback.AppTokens[appID]); } else { request = Utils.NewPICSRequest(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: {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)); } }
protected override async Task ProcessData() { ChangeNumber = ProductInfo.ChangeNumber; if (Settings.IsFullRun) { await DbConnection.ExecuteAsync("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeNumber) ON DUPLICATE KEY UPDATE `Date` = `Date`", new { ProductInfo.ChangeNumber }); await DbConnection.ExecuteAsync("INSERT INTO `ChangelistsApps` (`ChangeID`, `AppID`) VALUES (@ChangeNumber, @AppID) ON DUPLICATE KEY UPDATE `AppID` = `AppID`", new { AppID, ProductInfo.ChangeNumber }); } await ProcessKey("root_changenumber", "changenumber", ChangeNumber.ToString()); var app = (await DbConnection.QueryAsync <App>("SELECT `Name`, `AppType` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new { AppID })).SingleOrDefault(); var newAppName = ProductInfo.KeyValues["common"]["name"].AsString(); if (newAppName != null) { var currentType = ProductInfo.KeyValues["common"]["type"].AsString().ToLowerInvariant(); var newAppType = await DbConnection.ExecuteScalarAsync <int?>("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType }) ?? -1; var modifiedNameOrType = false; if (newAppType == -1) { await DbConnection.ExecuteAsync("INSERT INTO `AppsTypes` (`Name`, `DisplayName`) VALUES(@Name, @DisplayName)", new { Name = currentType, DisplayName = ProductInfo.KeyValues["common"]["type"].AsString() }); // We don't need to lower display name Log.WriteInfo("App Processor", "Creating new apptype \"{0}\" (AppID {1})", currentType, AppID); IRC.Instance.SendOps("New app type: {0}{1}{2} - {3}", Colors.BLUE, currentType, Colors.NORMAL, SteamDB.GetAppURL(AppID, "history")); newAppType = await DbConnection.ExecuteScalarAsync <int>("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType }); } if (string.IsNullOrEmpty(app.Name) || app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) { await DbConnection.ExecuteAsync("INSERT INTO `Apps` (`AppID`, `AppType`, `Name`, `LastKnownName`) VALUES (@AppID, @Type, @AppName, @AppName) ON DUPLICATE KEY UPDATE `Name` = VALUES(`Name`), `LastKnownName` = VALUES(`LastKnownName`), `AppType` = VALUES(`AppType`)", new { AppID, Type = newAppType, AppName = newAppName } ); await MakeHistory("created_app"); await MakeHistory("created_info", SteamDB.DATABASE_NAME_TYPE, string.Empty, newAppName); modifiedNameOrType = true; } else if (app.Name != newAppName) { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `Name` = @AppName, `LastKnownName` = @AppName WHERE `AppID` = @AppID", new { AppID, AppName = newAppName }); await MakeHistory("modified_info", SteamDB.DATABASE_NAME_TYPE, app.Name, newAppName); modifiedNameOrType = true; } if (app.AppType == 0 || app.AppType != newAppType) { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new { AppID, Type = newAppType }); if (app.AppType == 0) { await MakeHistory("created_info", SteamDB.DATABASE_APPTYPE, string.Empty, newAppType.ToString()); } else { await MakeHistory("modified_info", SteamDB.DATABASE_APPTYPE, app.AppType.ToString(), newAppType.ToString()); } modifiedNameOrType = true; } if (modifiedNameOrType) { if ((newAppType > 9 && newAppType != 13 && newAppType != 15 && newAppType != 17) || Triggers.Any(newAppName.Contains)) { IRC.Instance.SendOps("New {0}: {1}{2}{3} -{4} {5}", currentType, Colors.BLUE, Utils.LimitStringLength(newAppName), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } } } foreach (var section in ProductInfo.KeyValues.Children) { var sectionName = section.Name.ToLowerInvariant(); if (sectionName == "appid" || sectionName == "public_only" || sectionName == "change_number") { continue; } if (sectionName == "common" || sectionName == "extended") { foreach (var keyvalue in section.Children) { var keyName = string.Format("{0}_{1}", sectionName, keyvalue.Name); if (keyName == "common_type" || keyName == "common_gameid" || keyName == "common_name" || keyName == "extended_order") { // Ignore common keys that are either duplicated or serve no real purpose continue; } if (keyvalue.Children.Count > 0) { await ProcessKey(keyName, keyvalue.Name, Utils.JsonifyKeyValue(keyvalue), keyvalue); } else if (!string.IsNullOrEmpty(keyvalue.Value)) { await ProcessKey(keyName, keyvalue.Name, keyvalue.Value); } } } else { sectionName = string.Format("root_{0}", sectionName); if (await ProcessKey(sectionName, sectionName, Utils.JsonifyKeyValue(section), section) && sectionName == "root_depots") { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `LastDepotUpdate` = CURRENT_TIMESTAMP() WHERE `AppID` = @AppID", new { AppID }); } } } // If app gets hidden but we already have data, do not delete the already existing app info if (newAppName != null) { foreach (var data in CurrentData.Values.Where(data => !data.Processed && !data.KeyName.StartsWith("website", StringComparison.Ordinal))) { await DbConnection.ExecuteAsync("DELETE FROM `AppsInfo` WHERE `AppID` = @AppID AND `Key` = @Key", new { AppID, data.Key }); await MakeHistory("removed_key", data.Key, data.Value); } } else { if (string.IsNullOrEmpty(app.Name)) // We don't have the app in our database yet { await DbConnection.ExecuteAsync("INSERT INTO `Apps` (`AppID`, `Name`) VALUES (@AppID, @AppName) ON DUPLICATE KEY UPDATE `AppType` = `AppType`", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); } else if (!app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) // We do have the app, replace it with default name { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `Name` = @AppName, `AppType` = 0 WHERE `AppID` = @AppID", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); await MakeHistory("deleted_app", 0, app.Name); } } // Close the connection as it's no longer needed going into depot processor DbConnection.Close(); if (ProductInfo.KeyValues["depots"] != null) { await Steam.Instance.DepotProcessor.Process(AppID, ChangeNumber, ProductInfo.KeyValues["depots"]); } if (ProductInfo.MissingToken && PICSTokens.HasAppToken(AppID)) { Log.WriteError(nameof(PICSTokens), $"Overriden token for appid {AppID} is invalid?"); IRC.Instance.SendOps($"[Tokens] Looks like the overriden token for appid {AppID} ({newAppName}) is invalid"); } }
private void PrintLinux() { var name = Steam.GetAppName(AppID, out var appType); if (appType != "Game" && appType != "Application") { return; } if (!Settings.Current.CanQueryStore) { return; } IRC.Instance.SendLinuxAnnouncement($"\U0001F427 {name} now lists Linux{LinkExpander.GetFormattedPrices(AppID)} - {SteamDB.GetAppURL(AppID, "history")} - https://store.steampowered.com/app/{AppID}/"); }
private async Task <bool> ProcessKey(string keyName, string displayName, string value, KeyValue newKv = null) { if (keyName.Length > 90) { Log.WriteError("App Processor", "Key {0} for AppID {1} is too long, not inserting info.", keyName, AppID); return(false); } // All keys in PICS are supposed to be lower case keyName = keyName.ToLowerInvariant().Trim(); if (!CurrentData.ContainsKey(keyName)) { var key = KeyNameCache.GetAppKeyID(keyName); if (key == 0) { var type = newKv != null ? 86 : 0; // 86 is a hardcoded const for the website key = await KeyNameCache.CreateAppKey(keyName, displayName, type); if (key == 0) { // We can't insert anything because key wasn't created Log.WriteError("App Processor", "Failed to create key {0} for AppID {1}, not inserting info.", keyName, AppID); return(false); } IRC.Instance.SendOps("New app keyname: {0}{1} {2}(ID: {3}) ({4}) - {5}", Colors.BLUE, keyName, Colors.LIGHTGRAY, key, displayName, SteamDB.GetAppURL(AppID, "history")); } await DbConnection.ExecuteAsync("INSERT INTO `AppsInfo` (`AppID`, `Key`, `Value`) VALUES (@AppID, @Key, @Value)", new { AppID, Key = key, Value = value }); await MakeHistory("created_key", key, string.Empty, value); if ((keyName == "extended_developer" || keyName == "extended_publisher") && value == "Valve") { IRC.Instance.SendOps("New {0}=Valve app: {1}{2}{3} -{4} {5}", displayName, Colors.BLUE, Steam.GetAppName(AppID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } if (keyName == "common_oslist" && value.Contains("linux")) { PrintLinux(); } return(true); } var data = CurrentData[keyName]; if (data.Processed) { Log.WriteWarn("App Processor", "Duplicate key {0} in AppID {1}", keyName, AppID); return(false); } data.Processed = true; CurrentData[keyName] = data; if (data.Value == value) { return(false); } await DbConnection.ExecuteAsync("UPDATE `AppsInfo` SET `Value` = @Value WHERE `AppID` = @AppID AND `Key` = @Key", new { AppID, data.Key, Value = value }); if (newKv != null) { await MakeHistoryForJson(data.Key, data.Value, newKv); } else { await MakeHistory("modified_key", data.Key, data.Value, value); } if (keyName == "common_oslist" && value.Contains("linux") && !data.Value.Contains("linux")) { PrintLinux(); } return(true); }
public override async Task OnCommand(CommandArguments command) { if (command.Message.Length == 0) { command.Reply("Usage:{0} players <appid or partial game name>", Colors.OLIVE); command.Notice("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; string name; if (!uint.TryParse(command.Message, out 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` 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") ); }
private void PrintLinux() { string appType; var name = Steam.GetAppName(AppID, out appType); if (appType != "Game" && appType != "Application") { return; } IRC.Instance.SendSteamLUG(string.Format( "[oslist][{0}] {1} now lists Linux{2} - {3} - https://store.steampowered.com/app/{4}/", appType, name, LinkExpander.GetFormattedPrices(AppID), SteamDB.GetAppURL(AppID, "history"), AppID )); }
public void OnPICSChanges(SteamApps.PICSChangesCallback callback) { // Print any apps importants first var important = callback.AppChanges.Keys.Intersect(ImportantApps); if (important.Count() > 5) { IRC.SendMain("{0}{1}{2} important apps updated -{3} {4}", Colors.OLIVE, important.Count(), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(callback.CurrentChangeNumber)); } else { foreach (var app in important) { IRC.SendMain("Important app update: {0}{1}{2} -{3} {4}", Colors.OLIVE, GetAppName(app), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetAppURL(app, "history")); } } // And then important packages important = callback.PackageChanges.Keys.Intersect(ImportantSubs); if (important.Count() > 5) { IRC.SendMain("{0}{1}{2} important packages updated -{3} {4}", Colors.OLIVE, important.Count(), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(callback.CurrentChangeNumber)); } else { foreach (var package in important) { IRC.SendMain("Important package update: {0}{1}{2} -{3} {4}", Colors.OLIVE, GetPackageName(package), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetPackageURL(package, "history")); } } // Group apps and package changes by changelist, this will seperate into individual changelists var appGrouping = callback.AppChanges.Values.GroupBy(a => a.ChangeNumber); var packageGrouping = callback.PackageChanges.Values.GroupBy(p => p.ChangeNumber); // Join apps and packages back together based on changelist number var changeLists = Utils.FullOuterJoin(appGrouping, packageGrouping, a => a.Key, p => p.Key, (a, p, key) => new { ChangeNumber = key, Apps = a.ToList(), Packages = p.ToList(), }, new EmptyGrouping <uint, SteamApps.PICSChangesCallback.PICSChangeData>(), new EmptyGrouping <uint, SteamApps.PICSChangesCallback.PICSChangeData>()) .OrderBy(c => c.ChangeNumber); foreach (var changeList in changeLists) { var appCount = changeList.Apps.Count; var packageCount = changeList.Packages.Count; string Message = string.Format("Changelist {0}{1}{2} {3}({4:N0} apps and {5:N0} packages){6} -{7} {8}", Colors.OLIVE, changeList.ChangeNumber, Colors.NORMAL, Colors.DARK_GRAY, appCount, packageCount, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(changeList.ChangeNumber) ); var changesCount = appCount + packageCount; if (changesCount >= 50) { IRC.SendMain(Message); } IRC.SendAnnounce("{0}»{1} {2}", Colors.RED, Colors.NORMAL, Message); // If this changelist is very big, freenode will hate us forever if we decide to print all that stuff if (changesCount > 500) { IRC.SendAnnounce("{0} This changelist is too big to be printed in IRC, please view it on our website", Colors.RED); continue; } string name; if (appCount > 0) { foreach (var app in changeList.Apps) { name = GetAppName(app.ID, true); if (string.IsNullOrEmpty(name)) { name = string.Format("{0}{1}{2}", Colors.GREEN, app.ID, Colors.NORMAL); } else { name = string.Format("{0}{1}{2} - {3}", Colors.LIGHT_GRAY, app.ID, Colors.NORMAL, name); } IRC.SendAnnounce(" App: {0}{1}", name, app.NeedsToken ? StringNeedToken : string.Empty); } } if (packageCount > 0) { foreach (var package in changeList.Packages) { name = GetPackageName(package.ID, true); if (string.IsNullOrEmpty(name)) { name = string.Format("{0}{1}{2}", Colors.GREEN, package.ID, Colors.NORMAL); } else { name = string.Format("{0}{1}{2} - {3}", Colors.LIGHT_GRAY, package.ID, Colors.NORMAL, name); } IRC.SendAnnounce(" Package: {0}{1}{2}", name, package.NeedsToken ? StringNeedToken : string.Empty, Steam.Instance.OwnedPackages.Contains(package.ID) ? StringCheckmark : string.Empty ); } } } }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.Message.Length == 0) { command.Reply("Usage:{0} players <appid or partial game name>", Colors.OLIVE); command.Notice("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; string name; if (!uint.TryParse(command.Message, out 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` 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; } } KeyValue result; using (dynamic userStats = WebAPI.GetInterface("ISteamUserStats")) { userStats.Timeout = (int)TimeSpan.FromSeconds(5).TotalMilliseconds; try { result = userStats.GetNumberOfCurrentPlayers( appid: appID ); } catch (WebException e) { if (e.Status == WebExceptionStatus.Timeout) { throw new TaskCanceledException(); } var response = (HttpWebResponse)e.Response; command.Reply("Unable to request player count: {0}{1}", Colors.RED, response.StatusDescription); return; } } var eResult = (EResult)result["result"].AsInteger(); if (eResult != EResult.OK) { command.Reply("Unable to request player count: {0}{1}", Colors.RED, eResult); return; } if (appID == 0) { appID = 753; } string appType, type = "playing"; name = Steam.GetAppName(appID, out appType); 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, result["player_count"].AsInteger(), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(appID, "graphs") ); }
public override async 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; } } var callback = await Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID); if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(command, "Unable to request player count: {0}{1}", Colors.RED, callback.Result); } else if (appID == 0) { CommandHandler.ReplyToCommand( command, "{0}{1:N0}{2} people praising lord Gaben right now, influence:{3} {4}", Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(753, "graphs") ); } else { CommandHandler.ReplyToCommand( command, "People playing {0}{1}{2} right now: {3}{4:N0}{5} -{6} {7}", Colors.BLUE, Steam.GetAppName(appID), Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(appID, "graphs") ); } }
private void TryProcess(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Value` FROM `AppsInfo` INNER JOIN `KeyNames` ON `AppsInfo`.`Key` = `KeyNames`.`ID` WHERE `AppID` = @AppID", new MySqlParameter("AppID", AppID))) { while (Reader.Read()) { CurrentData.Add(DbWorker.GetString("Name", Reader), DbWorker.GetString("Value", Reader)); } } string appName = string.Empty; string appType = "0"; using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `AppType` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new MySqlParameter("AppID", AppID))) { if (Reader.Read()) { appName = DbWorker.GetString("Name", Reader); appType = DbWorker.GetString("AppType", Reader); } } if (productInfo.KeyValues["common"]["name"].Value != null) { string newAppType = "0"; string currentType = productInfo.KeyValues["common"]["type"].AsString().ToLower(); using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new MySqlParameter("Type", currentType))) { if (Reader.Read()) { newAppType = DbWorker.GetString("AppType", Reader); } else { // TODO: Create it? Log.WriteError("App Processor", "AppID {0} - unknown app type: {1}", AppID, currentType); // TODO: This is debuggy just so we are aware of new app types IRC.SendAnnounce("Unknown app type \"{0}\" for appid {1}, cc Alram and xPaw", currentType, AppID); } } if (string.IsNullOrEmpty(appName) || appName.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) { DbWorker.ExecuteNonQuery("INSERT INTO `Apps` (`AppID`, `AppType`, `Name`) VALUES (@AppID, @Type, @AppName) ON DUPLICATE KEY UPDATE `Name` = @AppName, `AppType` = @Type", new MySqlParameter("@AppID", AppID), new MySqlParameter("@Type", newAppType), new MySqlParameter("@AppName", productInfo.KeyValues["common"]["name"].Value) ); MakeHistory("created_app"); MakeHistory("created_info", DATABASE_NAME_TYPE, string.Empty, productInfo.KeyValues["common"]["name"].Value); // TODO: Testy testy if (!Settings.IsFullRun && Settings.Current.ChatRooms.Count > 0 && !appName.StartsWith("SteamApp", StringComparison.Ordinal) && !appName.StartsWith("ValveTest", StringComparison.Ordinal)) { Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg, string.Format( ":retreat: New {0} was published: {1}\nSteamDB: {2}\nSteam: http://store.steampowered.com/app/{3}/", currentType, productInfo.KeyValues["common"]["name"].AsString(), SteamDB.GetAppURL(AppID), AppID ) ); } } else if (!appName.Equals(productInfo.KeyValues["common"]["name"].Value)) { string newAppName = productInfo.KeyValues["common"]["name"].AsString(); DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `Name` = @AppName WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@AppName", newAppName) ); MakeHistory("modified_info", DATABASE_NAME_TYPE, appName, newAppName); // TODO: Testy testy if (!Settings.IsFullRun && Settings.Current.ChatRooms.Count > 0 && !string.Equals(appName, newAppName, StringComparison.OrdinalIgnoreCase) && !newAppName.StartsWith("SteamApp", StringComparison.Ordinal) && !newAppName.StartsWith("ValveTest", StringComparison.Ordinal)) { Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg, string.Format( ":retreat: {0} name was changed - {1}\n« {2}\n» {3}", currentType, SteamDB.GetAppURL(AppID, "history"), appName, newAppName ) ); } } if (appType.Equals("0")) { DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@Type", newAppType) ); MakeHistory("created_info", DATABASE_APPTYPE, string.Empty, newAppType); } else if (!appType.Equals(newAppType)) { DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@Type", newAppType) ); MakeHistory("modified_info", DATABASE_APPTYPE, appType, newAppType); } } // If we are full running, process depots too bool depotsSectionModified = Settings.IsFullRun && productInfo.KeyValues["depots"].Children.Count > 0; foreach (KeyValue section in productInfo.KeyValues.Children) { string sectionName = section.Name.ToLower(); if (sectionName == "appid" || sectionName == "public_only") { continue; } if (sectionName == "change_number") // Carefully handle change_number { sectionName = "root_change_number"; // TODO: Remove this key, move it to Apps table itself ProcessKey(sectionName, "change_number", productInfo.ChangeNumber.ToString()); //section.AsString()); } else if (sectionName == "common" || sectionName == "extended") { string keyName; foreach (KeyValue keyvalue in section.Children) { keyName = string.Format("{0}_{1}", sectionName, keyvalue.Name); if (keyName.Equals("common_type") || keyName.Equals("common_gameid") || keyName.Equals("common_name") || keyName.Equals("extended_order")) { // Ignore common keys that are either duplicated or serve no real purpose continue; } if (keyvalue.Children.Count > 0) { if (keyName.Equals("common_languages")) { ProcessKey(keyName, keyvalue.Name, string.Join(",", keyvalue.Children.Select(x => x.Name))); } else { ProcessKey(keyName, keyvalue.Name, DbWorker.JsonifyKeyValue(keyvalue), true); } } else if (!string.IsNullOrEmpty(keyvalue.Value)) { ProcessKey(keyName, keyvalue.Name, keyvalue.Value); } } } else { sectionName = string.Format("root_{0}", sectionName); if (ProcessKey(sectionName, sectionName, DbWorker.JsonifyKeyValue(section), true) && sectionName.Equals("root_depots")) { depotsSectionModified = true; } } } foreach (string keyName in CurrentData.Keys) { if (!keyName.StartsWith("website", StringComparison.Ordinal)) { uint ID = GetKeyNameID(keyName); DbWorker.ExecuteNonQuery("DELETE FROM AppsInfo WHERE `AppID` = @AppID AND `Key` = @KeyNameID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@KeyNameID", ID) ); MakeHistory("removed_key", ID, CurrentData[keyName]); } } if (productInfo.KeyValues["common"]["name"].Value == null) { if (string.IsNullOrEmpty(appName)) // We don't have the app in our database yet { DbWorker.ExecuteNonQuery("INSERT INTO `Apps` (`AppID`, `Name`) VALUES (@AppID, @AppName) ON DUPLICATE KEY UPDATE `AppType` = `AppType`", new MySqlParameter("@AppID", AppID), new MySqlParameter("@AppName", string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID)) ); } else if (!appName.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) // We do have the app, replace it with default name { DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `Name` = @AppName, `AppType` = 0 WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@AppName", string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID)) ); MakeHistory("deleted_app", 0, appName); } } if (depotsSectionModified) { DepotProcessor.Process(AppID, ChangeNumber, productInfo.KeyValues["depots"]); } }
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") ); }
private bool ProcessKey(string keyName, string displayName, string value, bool isJSON = false) { if (keyName.Length > 90) { Log.WriteError("App Processor", "Key {0} for AppID {1} is too long, not inserting info.", keyName, AppID); return(false); } // All keys in PICS are supposed to be lower case keyName = keyName.ToLower().Trim(); if (!CurrentData.ContainsKey(keyName)) { uint key = GetKeyNameID(keyName); if (key == 0) { var type = isJSON ? 86 : 0; // 86 is a hardcoded const for the website DbConnection.Execute("INSERT INTO `KeyNames` (`Name`, `Type`, `DisplayName`) VALUES(@Name, @Type, @DisplayName)", new { Name = keyName, DisplayName = displayName, Type = type }); key = GetKeyNameID(keyName); if (key == 0) { // We can't insert anything because key wasn't created Log.WriteError("App Processor", "Failed to create key {0} for AppID {1}, not inserting info.", keyName, AppID); return(false); } IRC.Instance.SendOps("New app keyname: {0}{1} {2}(ID: {3}) ({4}) - {5}", Colors.BLUE, keyName, Colors.LIGHTGRAY, key, displayName, SteamDB.GetAppURL(AppID, "history")); } DbConnection.Execute("INSERT INTO `AppsInfo` (`AppID`, `Key`, `Value`) VALUES (@AppID, @Key, @Value)", new { AppID, Key = key, Value = value }); MakeHistory("created_key", key, string.Empty, value); if ((keyName == "extended_developer" || keyName == "extended_publisher") && value == "Valve") { IRC.Instance.SendOps("New {0}=Valve app: {1}{2}{3} -{4} {5}", displayName, Colors.BLUE, Steam.GetAppName(AppID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } if (keyName == "common_oslist" && value.Contains("linux")) { PrintLinux(); } return(true); } var data = CurrentData[keyName]; if (data.Processed) { Log.WriteWarn("App Processor", "Duplicate key {0} in AppID {1}", keyName, AppID); return(false); } data.Processed = true; CurrentData[keyName] = data; if (!data.Value.Equals(value)) { DbConnection.Execute("UPDATE `AppsInfo` SET `Value` = @Value WHERE `AppID` = @AppID AND `Key` = @Key", new { AppID, Key = data.Key, Value = value }); MakeHistory("modified_key", data.Key, data.Value, value); if (keyName == "common_oslist" && value.Contains("linux") && !data.Value.Contains("linux")) { PrintLinux(); } return(true); } return(false); }
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply("Usage:{0} players <appid or partial game name>", Colors.OLIVE); 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 "Tool": case "Config": case "Application": type = "using"; break; case "Legacy Media": case "Series": case "Video": type = "watching"; break; case "Demo": type = "demoing"; break; case "Guide": type = "reading"; break; case "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 void Process(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { ChangeNumber = productInfo.ChangeNumber; if (Settings.IsFullRun) { Log.WriteDebug("App Processor", "AppID: {0}", AppID); DbConnection.Execute("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeNumber) ON DUPLICATE KEY UPDATE `Date` = `Date`", new { productInfo.ChangeNumber }); DbConnection.Execute("INSERT INTO `ChangelistsApps` (`ChangeID`, `AppID`) VALUES (@ChangeNumber, @AppID) ON DUPLICATE KEY UPDATE `AppID` = `AppID`", new { AppID, productInfo.ChangeNumber }); } var app = DbConnection.Query <App>("SELECT `Name`, `AppType` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new { AppID }).SingleOrDefault(); var newAppName = productInfo.KeyValues["common"]["name"].AsString(); if (newAppName != null) { int newAppType = -1; string currentType = productInfo.KeyValues["common"]["type"].AsString().ToLower(); using (var reader = DbConnection.ExecuteReader("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType })) { if (reader.Read()) { newAppType = reader.GetInt32(reader.GetOrdinal("AppType")); } } if (newAppType == -1) { DbConnection.Execute("INSERT INTO `AppsTypes` (`Name`, `DisplayName`) VALUES(@Name, @DisplayName)", new { Name = currentType, DisplayName = productInfo.KeyValues["common"]["type"].AsString() }); // We don't need to lower display name Log.WriteInfo("App Processor", "Creating new apptype \"{0}\" (AppID {1})", currentType, AppID); IRC.Instance.SendOps("New app type: {0}{1}{2} - {3}", Colors.BLUE, currentType, Colors.NORMAL, SteamDB.GetAppURL(AppID, "history")); newAppType = DbConnection.ExecuteScalar <int>("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType }); } if (string.IsNullOrEmpty(app.Name) || app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) { DbConnection.Execute("INSERT INTO `Apps` (`AppID`, `AppType`, `Name`, `LastKnownName`) VALUES (@AppID, @Type, @AppName, @AppName) ON DUPLICATE KEY UPDATE `Name` = VALUES(`Name`), `LastKnownName` = VALUES(`LastKnownName`), `AppType` = VALUES(`AppType`)", new { AppID, Type = newAppType, AppName = newAppName } ); MakeHistory("created_app"); MakeHistory("created_info", SteamDB.DATABASE_NAME_TYPE, string.Empty, newAppName); // TODO: Testy testy if (!Settings.IsFullRun && Settings.Current.ChatRooms.Count > 0) { Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg, string.Format( "New {0} was published: {1}\nSteamDB: {2}\nSteam: https://store.steampowered.com/app/{3}/", currentType, newAppName, SteamDB.GetAppURL(AppID), AppID ) ); } if ((newAppType > 9 && newAppType != 13) || Triggers.Any(newAppName.Contains)) { IRC.Instance.SendOps("New {0}: {1}{2}{3} -{4} {5}", currentType, Colors.BLUE, newAppName, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } } else if (!app.Name.Equals(newAppName)) { DbConnection.Execute("UPDATE `Apps` SET `Name` = @AppName, `LastKnownName` = @AppName WHERE `AppID` = @AppID", new { AppID, AppName = newAppName }); MakeHistory("modified_info", SteamDB.DATABASE_NAME_TYPE, app.Name, newAppName); } if (app.AppType == 0 || app.AppType != newAppType) { DbConnection.Execute("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new { AppID, Type = newAppType }); if (app.AppType == 0) { MakeHistory("created_info", SteamDB.DATABASE_APPTYPE, string.Empty, newAppType.ToString()); } else { MakeHistory("modified_info", SteamDB.DATABASE_APPTYPE, app.AppType.ToString(), newAppType.ToString()); } } } foreach (var section in productInfo.KeyValues.Children) { string sectionName = section.Name.ToLower(); if (sectionName == "appid" || sectionName == "public_only") { continue; } if (sectionName == "change_number") // Carefully handle change_number { sectionName = "root_change_number"; // TODO: Remove this key, move it to Apps table itself ProcessKey(sectionName, "change_number", productInfo.ChangeNumber.ToString()); //section.AsString()); } else if (sectionName == "common" || sectionName == "extended") { string keyName; foreach (KeyValue keyvalue in section.Children) { keyName = string.Format("{0}_{1}", sectionName, keyvalue.Name); if (keyName.Equals("common_type") || keyName.Equals("common_gameid") || keyName.Equals("common_name") || keyName.Equals("extended_order")) { // Ignore common keys that are either duplicated or serve no real purpose continue; } if (keyvalue.Children.Count > 0) { ProcessKey(keyName, keyvalue.Name, Utils.JsonifyKeyValue(keyvalue), true); } else if (!string.IsNullOrEmpty(keyvalue.Value)) { ProcessKey(keyName, keyvalue.Name, keyvalue.Value); } } } else { sectionName = string.Format("root_{0}", sectionName); if (ProcessKey(sectionName, sectionName, Utils.JsonifyKeyValue(section), true) && sectionName.Equals("root_depots")) { DbConnection.Execute("UPDATE `Apps` SET `LastDepotUpdate` = CURRENT_TIMESTAMP() WHERE `AppID` = @AppID", new { AppID }); } } } foreach (var data in CurrentData.Values) { if (!data.Processed && !data.KeyName.StartsWith("website", StringComparison.Ordinal)) { DbConnection.Execute("DELETE FROM `AppsInfo` WHERE `AppID` = @AppID AND `Key` = @Key", new { AppID, data.Key }); MakeHistory("removed_key", data.Key, data.Value); if (newAppName != null && data.Key.Equals("common_section_type") && data.Value.Equals("ownersonly")) { IRC.Instance.SendMain("Removed ownersonly from: {0}{1}{2} -{3} {4}", Colors.BLUE, app.Name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } } } if (newAppName == null) { if (string.IsNullOrEmpty(app.Name)) // We don't have the app in our database yet { DbConnection.Execute("INSERT INTO `Apps` (`AppID`, `Name`) VALUES (@AppID, @AppName) ON DUPLICATE KEY UPDATE `AppType` = `AppType`", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); } else if (!app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) // We do have the app, replace it with default name { IRC.Instance.SendMain("App deleted: {0}{1}{2} -{3} {4}", Colors.BLUE, app.Name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); DbConnection.Execute("UPDATE `Apps` SET `Name` = @AppName, `AppType` = 0 WHERE `AppID` = @AppID", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); MakeHistory("deleted_app", 0, app.Name); } } if (productInfo.KeyValues["depots"] != null) { Steam.Instance.DepotProcessor.Process(AppID, ChangeNumber, productInfo.KeyValues["depots"]); } }
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply("Usage:{0} players <appid or partial game name>", Colors.OLIVE); return; } string name; if (!uint.TryParse(command.Message, out var appID)) { appID = await AppCommand.TrySearchAppId(command); if (appID == 0) { return; } } var callback = await Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID); if (appID == 0) { appID = 753; } 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 type = "playing"; switch (appType) { case "Tool": case "Config": case "Application": type = "using"; break; case "Legacy Media": case "Series": case "Video": type = "watching"; break; case "Demo": type = "demoing"; break; case "Guide": type = "reading"; break; case "Hardware": type = "bricking"; break; } command.Reply( "{0}{1:N0}{2} {3} {4}{5}{6} -{7} {8}", Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, type, Colors.BLUE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(appID, "graphs") ); }
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)); } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (request.Type == JobManager.IRCRequestType.TYPE_SUB) { if (!callback.Packages.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown SubID: {0}{1}{2}", Colors.BLUE, request.Target, LicenseList.OwnedSubs.ContainsKey(request.Target) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Packages[request.Target]; var kv = info.KeyValues.Children.FirstOrDefault(); string name; if (kv["name"].Value != null) { name = Utils.RemoveControlCharacters(kv["name"].AsString()); } else { name = Steam.GetPackageName(info.ID); } try { kv.SaveToFile(Path.Combine(Application.Path, "sub", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, name, 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 ); } else if (request.Type == JobManager.IRCRequestType.TYPE_APP) { if (!callback.Apps.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown AppID: {0}{1}{2}", Colors.BLUE, request.Target, LicenseList.OwnedApps.ContainsKey(request.Target) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Apps[request.Target]; string name; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString()); } else { name = Steam.GetAppName(info.ID); } try { info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{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 ); } else { CommandHandler.ReplyToCommand(request.Command, "I have no idea what happened here!"); } }