private static 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, $"{appType} update: {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 = $"{appType} update: {appName}\n<{SteamDB.GetAppUrl(app, "history")}?changeid={callback.CurrentChangeNumber}>" }); } } // Packages important = callback.PackageChanges.Keys.Intersect(Application.ImportantSubs.Keys); foreach (var package in important) { IRC.Instance.SendMain($"Package update: {Colors.BLUE}{Steam.GetPackageName(package)}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetPackageUrl(package, "history")}"); } }
public override async Task OnCommand(CommandArguments command) { if (string.IsNullOrWhiteSpace(command.Message)) { command.Reply($"Usage:{Colors.OLIVE} app <appid or partial game name>"); return; } if (!uint.TryParse(command.Message, out var appID)) { appID = await TrySearchAppId(command); if (appID == 0) { return; } } var info = await GetAppData(appID); if (info == null) { command.Reply($"Unknown AppID: {Colors.BLUE}{appID}{(LicenseList.OwnedApps.ContainsKey(appID) ? SteamDB.StringCheckmark : string.Empty)}"); return; } string name; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.LimitStringLength(Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString())); } else { name = Steam.GetAppName(info.ID); } var filename = $"{Utils.ByteArrayToString(info.SHAHash)}.vdf"; info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", filename), false); command.Reply($"{Colors.BLUE}{name}{Colors.NORMAL} -{Colors.DARKBLUE} <{SteamDB.GetAppUrl(info.ID)}>{Colors.NORMAL} - Dump:{Colors.DARKBLUE} <{SteamDB.GetRawAppUrl(filename)}>{Colors.NORMAL}{(info.MissingToken ? SteamDB.StringNeedToken : string.Empty)}{(LicenseList.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty)}"); if (command.Recipient == Settings.Current.IRC.Channel.Ops && !LicenseList.OwnedApps.ContainsKey(info.ID)) { JobManager.AddJob(() => Steam.Instance.Apps.RequestFreeLicense(info.ID)); } }
private static void PrintImportants(SteamApps.PICSChangesCallback callback) { // Apps var important = callback.AppChanges.Keys.Intersect(Application.ImportantApps); foreach (var app in important) { var changeNumber = callback.AppChanges[app].ChangeNumber; TaskManager.Run(async() => await Utils.SendWebhook(new { Type = "ImportantAppUpdate", AppID = app, ChangeNumber = changeNumber, Url = $"{SteamDB.GetAppUrl(app, "history")}?changeid={changeNumber}", })); var appName = Steam.GetAppName(app, out var appType); IRC.Instance.SendAnnounce($"{appType} update: {Colors.BLUE}{appName}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetAppUrl(app, "history")}"); } // Packages important = callback.PackageChanges.Keys.Intersect(Application.ImportantSubs); foreach (var package in important) { var changeNumber = callback.PackageChanges[package].ChangeNumber; TaskManager.Run(async() => await Utils.SendWebhook(new { Type = "ImportantSubUpdate", SubID = package, ChangeNumber = changeNumber, Url = $"{SteamDB.GetPackageUrl(package, "history")}?changeid={changeNumber}", })); var subName = Steam.GetPackageName(package); IRC.Instance.SendAnnounce($"Package update: {Colors.BLUE}{subName}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetPackageUrl(package, "history")}"); } }
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)); } }
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")}" ); }
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(); var newAppType = -1; if (newAppName != null) { var currentType = ProductInfo.KeyValues["common"]["type"].AsString().ToLowerInvariant(); 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(nameof(AppProcessor), $"Creating new apptype \"{currentType}\" (AppID {AppID})"); IRC.Instance.SendOps($"New app type: {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.UnknownAppName, 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.DatabaseNameType, 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.DatabaseNameType, 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.DatabaseAppType, string.Empty, newAppType.ToString()); } else { await MakeHistory("modified_info", SteamDB.DatabaseAppType, app.AppType.ToString(), newAppType.ToString()); } modifiedNameOrType = true; } if (modifiedNameOrType) { if ((newAppType > 9 && newAppType != 13 && newAppType != 15 && newAppType != 17 && newAppType != 18) || Triggers.Any(newAppName.Contains)) { IRC.Instance.SendOps($"New {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 == "change_number") { continue; } if (sectionName == "common" || sectionName == "extended") { foreach (var keyvalue in section.Children) { var keyName = $"{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 if (sectionName == "public_only") { await ProcessKey($"root_{sectionName}", section.Name, section.Value); } else { sectionName = $"root_{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 = $"{SteamDB.UnknownAppName} {AppID}" }); } else if (!app.Name.StartsWith(SteamDB.UnknownAppName, 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 = $"{SteamDB.UnknownAppName} {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"].Children.Any()) { await Steam.Instance.DepotProcessor.Process(AppID, ChangeNumber, ProductInfo.KeyValues["depots"]); } if (ProductInfo.MissingToken && PICSTokens.HasAppToken(AppID)) { Log.WriteError(nameof(PICSTokens), $"Overridden token for appid {AppID} is invalid?"); IRC.Instance.SendOps($"[Tokens] Looks like the overridden token for appid {AppID} ({newAppName}) is invalid"); } if (Settings.IsMillhaven && app.AppType == 0 && newAppType == 18) { var betaAppId = ProductInfo.KeyValues["extended"]["betaforappid"].AsUnsignedInteger(); if (betaAppId == 0) { betaAppId = ProductInfo.KeyValues["common"]["parent"].AsUnsignedInteger(); } Log.WriteDebug(nameof(AppProcessor), $"Requesting beta access for {AppID} ({betaAppId})"); var response = await WebAuth.PerformRequest( HttpMethod.Post, new Uri($"https://store.steampowered.com/ajaxrequestplaytestaccess/{betaAppId}"), new List <KeyValuePair <string, string> > { new KeyValuePair <string, string>("sessionid", nameof(SteamDatabaseBackend)) } ); var data = await response.Content.ReadAsStringAsync(); Log.WriteDebug(nameof(AppProcessor), $"Beta {AppID}: {data}"); } }
private void PrintLinux() { var name = Steam.GetAppName(AppID, out var appType); if (appType != "Game" && appType != "Application") { return; } if (!Settings.IsMillhaven) { return; } IRC.Instance.SendLinuxAnnouncement($"\U0001F427 {name} now lists Linux - {SteamDB.GetAppUrl(AppID, "history")}"); }
private async Task <bool> ProcessKey(string keyName, string displayName, string value, KeyValue newKv = null) { if (keyName.Length > 90) { Log.WriteError(nameof(AppProcessor), $"Key {keyName} for AppID {AppID} is too long, not inserting info."); return(false); } // All keys in PICS are supposed to be lower case keyName = keyName.ToLowerInvariant().Trim(); if (!CurrentData.ContainsKey(keyName)) { CurrentData[keyName] = new PICSInfo { Processed = true, }; 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(nameof(AppProcessor), $"Failed to create key {keyName} for AppID {AppID}, not inserting info."); return(false); } IRC.Instance.SendOps($"New app keyname: {Colors.BLUE}{keyName} {Colors.LIGHTGRAY}(ID: {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 {displayName}=Valve app: {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(nameof(AppProcessor), $"Duplicate key {keyName} in AppID {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); }
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 isPublicOnly = false; var newAppName = ProductInfo.KeyValues["common"]["name"].AsString(); var newAppType = EAppType.Invalid; if (newAppName != null) { var currentType = ProductInfo.KeyValues["common"]["type"].AsString().ToLowerInvariant(); newAppType = Utils.GetAppType(currentType); var modifiedNameOrType = false; if (string.IsNullOrEmpty(app.Name) || app.Name.StartsWith(SteamDB.UnknownAppName, 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 = (int)newAppType, AppName = newAppName } ); await MakeHistory("created_app"); await MakeHistory("created_info", SteamDB.DatabaseNameType, 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.DatabaseNameType, app.Name, newAppName); modifiedNameOrType = true; } if (app.AppType != newAppType) { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new { AppID, Type = (int)newAppType }); if (app.AppType == EAppType.Invalid) { await MakeHistory("created_info", SteamDB.DatabaseAppType, string.Empty, newAppType.ToString("d")); } else { await MakeHistory("modified_info", SteamDB.DatabaseAppType, app.AppType.ToString(), newAppType.ToString("d")); } modifiedNameOrType = true; } if (modifiedNameOrType && Triggers.Any(newAppName.Contains)) { IRC.Instance.SendOps($"New {newAppType}: {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 == "change_number") { continue; } if (sectionName == "common" || sectionName == "extended") { foreach (var keyvalue in section.Children) { var keyName = $"{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.Value != null) { await ProcessKey(keyName, keyvalue.Name, keyvalue.Value); } else { await ProcessKey(keyName, keyvalue.Name, Utils.JsonifyKeyValue(keyvalue), keyvalue); } } } else if (sectionName == "public_only") { isPublicOnly = section.Value == "1"; await ProcessKey($"root_{sectionName}", section.Name, section.Value); } else { sectionName = $"root_{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) { // This key still exists in appinfo and was correctly processed above if (data.Processed) { continue; } // This is a key that is created and handled by steamdb.info; not in appinfo if (data.KeyName.StartsWith("website", StringComparison.Ordinal)) { continue; } // If this app requires a token, but previously was public and we had stored data, keep it around if (isPublicOnly && !data.KeyName.StartsWith("common", StringComparison.Ordinal)) { continue; } 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 = $"{SteamDB.UnknownAppName} {AppID}" }); } else if (!app.Name.StartsWith(SteamDB.UnknownAppName, StringComparison.Ordinal)) // We do have the app, replace it with default name { await DbConnection.ExecuteAsync("UPDATE `Apps` SET `Name` = @AppName, `AppType` = @AppType WHERE `AppID` = @AppID", new { AppID, AppType = (int)EAppType.Invalid, AppName = $"{SteamDB.UnknownAppName} {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"].Children.Any()) { await Steam.Instance.DepotProcessor.Process(AppID, ChangeNumber, ProductInfo.KeyValues["depots"]); } if (ProductInfo.MissingToken && PICSTokens.HasAppToken(AppID)) { Log.WriteError(nameof(PICSTokens), $"Overridden token for appid {AppID} is invalid?"); IRC.Instance.SendOps($"[Tokens] Looks like the overridden token for appid {AppID} ({newAppName}) is invalid"); } if (Settings.IsMillhaven && newAppType == EAppType.Beta && !LicenseList.OwnedApps.ContainsKey(AppID)) { var betaAppId = ProductInfo.KeyValues["extended"]["betaforappid"].AsUnsignedInteger(); if (betaAppId == 0) { betaAppId = ProductInfo.KeyValues["common"]["parent"].AsUnsignedInteger(); } Log.WriteDebug(nameof(AppProcessor), $"Adding beta access request for app {AppID} ({betaAppId})"); Steam.Instance.FreeLicense.AddBeta(betaAppId); } }