Compare commits

..

27 Commits

Author SHA1 Message Date
JustArchi
e2999e256a Translations update 2018-05-23 15:42:40 +02:00
JustArchi
f80c23ac7d Misc 2018-05-23 15:29:15 +02:00
JustArchi
a6b802fbc8 Closes #795 2018-05-23 15:28:02 +02:00
JustArchi
4915baa7cf Improve requests utilizing absolute profile URL
In very rare case it's possible that this request could be executed when we don't have SteamID initialized.
2018-05-20 14:42:48 +02:00
JustArchi
b2bca86998 AppVeyor hardening
1:0 for bash
2018-05-19 21:48:26 +02:00
JustArchi
f118ca592e Fix broken comments 2018-05-19 21:47:04 +02:00
JustArchi
4b24227d3f Fix build 2018-05-19 20:54:11 +02:00
JustArchi
75a93a3baa Misc
This is no longer a digit.
2018-05-19 20:53:49 +02:00
JustArchi
ed2a068c51 Cleanup after #794
@vital7

Steam.cs:
- Add missing constructor for json deserialization
- Change name into UserPrivacy since we use it for both request and response, no longer response only
- Move ECommentPermission one level above, it's not internal member of PrivacySettings
- Make UserPrivacy constructor accept PrivacySettings, since PrivacySettings is internal and not private.
- Make ECommentPermission underlying type of byte

ArchiWebHandler.cs:
- Put function in proper place alphabetically
- Cast CommentPermission to new underlying type of byte
- Remove mapping, AWH should not be in charge of correcting a caller, unless that caller can't be corrected earlier (e.g. direct Steam response). Since Bot is in charge of calling AWH, Bot should do the correction, not AWH.

Bot.cs:
- Change command to !privacy bot n,n,n,n,n,n, this makes it possible for mixing it with enum members (such as !privacy bot public,private,friendsonly,public,public), which would be preferred way of execution instead of cryptic numbers.
- Make appropriate mapping between general and comments, since userspace is in charge of that.
- Add comments and correct creating UserPrivacy object.
- Make the default option private and let user skip extra options if he wants to edit e.g. only profile to public.

Apart from that, general error handling and a lot of other misc fixed, including renaming NonZeroResponse to NumberResponse, which makes more sense.
2018-05-19 20:50:26 +02:00
Vital7
9b7dfd065d Change privacy settings feature (#794)
* Change privacy settings feature

* Fixes

* Little fix

* More fixes

* Fix little fuckup
2018-05-19 19:52:14 +02:00
JustArchi
7c133a799b Extend debug to databases too 2018-05-18 21:12:33 +02:00
JustArchi
3d80a1b6ac Bump 2018-05-17 11:36:12 +02:00
JustArchi
494370a226 Re-implement stage 2 of deprecation 2018-05-17 11:11:03 +02:00
JustArchi
7f80728d18 Misc 2018-05-17 09:55:38 +02:00
JustArchi
0d66480562 Misc logging improvements 2018-05-17 09:54:22 +02:00
JustArchi
fb5b778a66 Bump 2018-05-16 23:09:51 +02:00
JustArchi
7ffc7a724d Translations update 2018-05-16 22:48:00 +02:00
JustArchi
e8336ee984 Packages update 2018-05-16 22:37:33 +02:00
JustArchi
69f768acff Improve command args parsing
Previously ASF joined out-of-range arguments in string commands (input, nickname, owns) using a normal space, now original whitespace is preserved, which is especially useful for including custom whitespace characters in nickname command.
2018-05-16 22:35:32 +02:00
Łukasz Domeradzki
797db71e62 Update CONTRIBUTING.md 2018-05-16 01:23:00 +02:00
JustArchi
2357729ca4 Stage 2 of deprecation for IsBotAccount, --server and --service 2018-05-13 20:59:05 +02:00
JustArchi
a7df090225 Misc 2018-05-13 20:43:22 +02:00
JustArchi
1857fec906 Misc 2018-05-13 20:33:44 +02:00
JustArchi
ab19b00dfd Bump 2018-05-13 20:07:36 +02:00
JustArchi
a5791cb7d4 Translations update 2018-05-13 19:30:54 +02:00
JustArchi
cbfc7d0e42 Accelerate initial bots startup
Files can be read in parallel after all
2018-05-13 19:19:27 +02:00
JustArchi
db3cfbe7d2 Bump 2018-05-12 21:10:37 +02:00
44 changed files with 987 additions and 529 deletions

View File

@@ -6,6 +6,8 @@ Before making an issue or pull request, you should carefully read **[ASF wiki](h
GitHub **[issues](https://github.com/JustArchi/ArchiSteamFarm/issues)** page is being used for ASF "Todo" list, regarding both features and bugs. It has rather **strict policy** that applies to everybody - GitHub is **NOT** technical support - it's a place **only** for ASF bugs and suggestions. It's **not** proper place for technical issues, general discussion or questions (unless related to development). In short, GitHub is for **development** part of the ASF, and all issues should be **development-oriented**. You have **[ASF chat](https://discord.gg/hSQgt8j)** and **[Steam group](http://steamcommunity.com/groups/ascfarm/discussions/1/)** for general discussion, questions, technical issues and everything else that is not related to ASF development. If you decide to use GitHub issues, please make sure that you're in fact dealing with a bug, or your suggestion makes sense, preferably by asking on chat/steam group first. Invalid issues will be closed immediately and won't be answered - if you're not sure if your issue is valid, then most likely it's not, and it should be posted on **[ASF chat](https://discord.gg/hSQgt8j)** or **[Steam group](http://steamcommunity.com/groups/ascfarm/discussions/1/)**, instead, like pointed out above. Valid bugs/suggestions will be forwarded and added as GitHub issues by us, if needed.
In short, **you shouldn't use ASF's GitHub issues if your issue does not benefit ASF development in any way**. Posting a bug report or a suggestion benefits ASF development, asking how to install the program or how to solve the technical issue you're having, does not.
All issues related to wiki, especially correcting mistakes, getting rid of outdated stuff or posting suggestions, are welcome.
---

View File

@@ -41,7 +41,7 @@ script:
set -e
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -o 'out/source' /nologo
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -o 'out/source'
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -o 'out/source' /nologo
publish() {
if [ "$1" = 'generic' ]; then

View File

@@ -188,8 +188,23 @@ namespace ArchiSteamFarm {
// Before attempting to connect, initialize our configuration
await Bot.InitializeSteamConfiguration(Program.GlobalConfig.SteamProtocols, Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false);
foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName)) {
await Bot.RegisterBot(botName).ConfigureAwait(false);
try {
IEnumerable<Task> tasks = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName).Select(Bot.RegisterBot);
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
foreach (Task task in tasks) {
await task.ConfigureAwait(false);
}
break;
default:
await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return;
}
if (Bot.Bots.Count == 0) {

View File

@@ -53,7 +53,7 @@ namespace ArchiSteamFarm {
// Otherwise, we ran into fatal exception before logging module could even get initialized, so activate fallback logging that involves file and console
string message = string.Format(DateTime.Now + Strings.ErrorEarlyFatalExceptionInfo + Environment.NewLine, SharedInfo.Version);
string message = string.Format(DateTime.Now + " " + Strings.ErrorEarlyFatalExceptionInfo + Environment.NewLine, SharedInfo.Version);
try {
await File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);

View File

@@ -2,14 +2,14 @@
<PropertyGroup>
<ApplicationIcon>ASF.ico</ApplicationIcon>
<AssemblyVersion>3.1.2.8</AssemblyVersion>
<AssemblyVersion>3.1.3.2</AssemblyVersion>
<Authors>JustArchi</Authors>
<Company>JustArchi</Company>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
<Copyright>Copyright © ArchiSteamFarm 2015-2018</Copyright>
<Description>ASF is an application that allows you to farm steam cards using multiple steam accounts simultaneously.</Description>
<ErrorReport>none</ErrorReport>
<FileVersion>3.1.2.8</FileVersion>
<FileVersion>3.1.3.2</FileVersion>
<LangVersion>7.2</LangVersion>
<NoWarn />
<OutputType>Exe</OutputType>
@@ -41,7 +41,7 @@
<PackageReference Include="ILLink.Tasks" Version="0.1.5-preview-1461378" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NLog" Version="4.5.4" />
<PackageReference Include="protobuf-net" Version="2.3.7" />
<PackageReference Include="protobuf-net" Version="2.3.8-alpha1" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.5.0-rc1" />
</ItemGroup>

View File

@@ -119,6 +119,39 @@ namespace ArchiSteamFarm {
return htmlDocument?.DocumentNode.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
}
internal async Task<bool> ChangePrivacySettings(Steam.UserPrivacy userPrivacy) {
if (userPrivacy == null) {
Bot.ArchiLogger.LogNullError(nameof(userPrivacy));
return false;
}
string profileURL = await GetAbsoluteProfileURL().ConfigureAwait(false);
if (string.IsNullOrEmpty(profileURL)) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
string request = profileURL + "/ajaxsetprivacy";
// Extra entry for sessionID
Dictionary<string, string> data = new Dictionary<string, string>(3) {
{ "eCommentPermission", ((byte) userPrivacy.CommentPermission).ToString() },
{ "Privacy", JsonConvert.SerializeObject(userPrivacy.Settings) }
};
Steam.NumberResponse response = await UrlPostToJsonObjectWithSession<Steam.NumberResponse>(SteamCommunityURL, request, data).ConfigureAwait(false);
if (response == null) {
return false;
}
if (!response.Success) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
return true;
}
internal async Task<bool> ClearFromDiscoveryQueue(uint appID) {
if (appID == 0) {
Bot.ArchiLogger.LogNullError(nameof(appID));
@@ -1080,7 +1113,13 @@ namespace ArchiSteamFarm {
return false;
}
string request = GetAbsoluteProfileURL() + "/ajaxunpackbooster";
string profileURL = await GetAbsoluteProfileURL().ConfigureAwait(false);
if (string.IsNullOrEmpty(profileURL)) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
string request = profileURL + "/ajaxunpackbooster";
// Extra entry for sessionID
Dictionary<string, string> data = new Dictionary<string, string>(3) {
@@ -1092,7 +1131,20 @@ namespace ArchiSteamFarm {
return response?.Result == EResult.OK;
}
private string GetAbsoluteProfileURL() => !string.IsNullOrEmpty(VanityURL) ? "/id/" + VanityURL : "/profiles/" + SteamID;
private async Task<string> GetAbsoluteProfileURL() {
if (SteamID == 0) {
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return null;
}
}
return string.IsNullOrEmpty(VanityURL) ? "/profiles/" + SteamID : "/id/" + VanityURL;
}
private async Task<string> GetApiKey() {
if (CachedApiKey != null) {
@@ -1280,39 +1332,45 @@ namespace ArchiSteamFarm {
// This json is encoded as html attribute, don't forget to decode it
json = WebUtility.HtmlDecode(json);
Steam.PrivacyResponse privacyResponse;
Steam.UserPrivacy userPrivacy;
try {
privacyResponse = JsonConvert.DeserializeObject<Steam.PrivacyResponse>(json);
userPrivacy = JsonConvert.DeserializeObject<Steam.UserPrivacy>(json);
} catch (JsonException e) {
Bot.ArchiLogger.LogGenericException(e);
return null;
}
if (privacyResponse == null) {
Bot.ArchiLogger.LogNullError(nameof(privacyResponse));
if (userPrivacy == null) {
Bot.ArchiLogger.LogNullError(nameof(userPrivacy));
return null;
}
switch (privacyResponse.Settings.Inventory) {
case Steam.PrivacyResponse.PrivacySettings.EPrivacySetting.FriendsOnly:
case Steam.PrivacyResponse.PrivacySettings.EPrivacySetting.Private:
switch (userPrivacy.Settings.Inventory) {
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly:
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private:
return false;
case Steam.PrivacyResponse.PrivacySettings.EPrivacySetting.Public:
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public:
return true;
default:
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(privacyResponse.Settings.Inventory), privacyResponse.Settings.Inventory));
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userPrivacy.Settings.Inventory), userPrivacy.Settings.Inventory));
return null;
}
}
private bool IsProfileUri(Uri uri) {
private async Task<bool> IsProfileUri(Uri uri) {
if (uri == null) {
ASF.ArchiLogger.LogNullError(nameof(uri));
return false;
}
return uri.AbsolutePath.Equals(GetAbsoluteProfileURL());
string profileURL = await GetAbsoluteProfileURL().ConfigureAwait(false);
if (string.IsNullOrEmpty(profileURL)) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
return uri.AbsolutePath.Equals(profileURL);
}
private static bool IsSessionExpiredUri(Uri uri) {
@@ -1465,7 +1523,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UnlockParentalAccountForService(serviceURL, parentalPin, --maxTries).ConfigureAwait(false);
}
@@ -1489,14 +1547,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
}
}
WebBrowser.HtmlDocumentResponse response = await WebLimitRequest(host, async () => await WebBrowser.UrlGetToHtmlDocument(host + request).ConfigureAwait(false)).ConfigureAwait(false);
@@ -1515,7 +1575,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlGetToHtmlDocumentWithSession(host, request, --maxTries).ConfigureAwait(false);
}
@@ -1539,14 +1599,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return default;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return default;
}
}
WebBrowser.ObjectResponse<T> response = await WebLimitRequest(host, async () => await WebBrowser.UrlGetToJsonObject<T>(host + request).ConfigureAwait(false)).ConfigureAwait(false);
@@ -1565,7 +1627,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlGetToJsonObjectWithSession<T>(host, request, --maxTries).ConfigureAwait(false);
}
@@ -1589,14 +1651,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
}
}
WebBrowser.XmlDocumentResponse response = await WebLimitRequest(host, async () => await WebBrowser.UrlGetToXmlDocument(host + request).ConfigureAwait(false)).ConfigureAwait(false);
@@ -1615,7 +1679,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlGetToXmlDocumentWithSession(host, request, --maxTries).ConfigureAwait(false);
}
@@ -1639,14 +1703,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return false;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return false;
}
}
WebBrowser.BasicResponse response = await WebLimitRequest(host, async () => await WebBrowser.UrlHead(host + request).ConfigureAwait(false)).ConfigureAwait(false);
@@ -1665,7 +1731,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlHeadWithSession(host, request, --maxTries).ConfigureAwait(false);
}
@@ -1689,14 +1755,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
}
}
if (session != ESession.None) {
@@ -1744,7 +1812,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlPostToHtmlDocumentWithSession(host, request, data, referer, session, --maxTries).ConfigureAwait(false);
}
@@ -1768,14 +1836,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
}
}
if (session != ESession.None) {
@@ -1823,7 +1893,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlPostToJsonObjectWithSession<T>(host, request, data, referer, session, --maxTries).ConfigureAwait(false);
}
@@ -1847,14 +1917,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return null;
}
}
if (session != ESession.None) {
@@ -1905,7 +1977,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlPostToJsonObjectWithSession<T>(host, request, data, referer, session, --maxTries).ConfigureAwait(false);
}
@@ -1929,14 +2001,16 @@ namespace ArchiSteamFarm {
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
SessionSemaphore.Release();
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return false;
for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) {
await Task.Delay(1000).ConfigureAwait(false);
}
if (SteamID == 0) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request));
return false;
}
}
if (session != ESession.None) {
@@ -1984,7 +2058,7 @@ namespace ArchiSteamFarm {
}
// Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case
if (IsProfileUri(response.FinalUri)) {
if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri)));
return await UrlPostWithSession(host, request, data, referer, session, --maxTries).ConfigureAwait(false);
}

View File

@@ -154,9 +154,9 @@ namespace ArchiSteamFarm {
private string TwoFactorCode;
private byte TwoFactorCodeFailures;
private Bot(string botName) {
if (string.IsNullOrEmpty(botName)) {
throw new ArgumentNullException(nameof(botName));
private Bot(string botName, BotConfig botConfig, BotDatabase botDatabase) {
if (string.IsNullOrEmpty(botName) || (botConfig == null) || (botDatabase == null)) {
throw new ArgumentNullException(nameof(botName) + " || " + nameof(botConfig) + " || " + nameof(botDatabase));
}
if (Bots.ContainsKey(botName)) {
@@ -164,24 +164,11 @@ namespace ArchiSteamFarm {
}
BotName = botName;
BotConfig = botConfig;
BotDatabase = botDatabase;
ArchiLogger = new ArchiLogger(botName);
BotConfig = BotConfig.Load(ConfigFilePath);
if (BotConfig == null) {
ArchiLogger.LogGenericError(string.Format(Strings.ErrorBotConfigInvalid, ConfigFilePath));
return;
}
if (Debugging.IsUserDebugging) {
ArchiLogger.LogGenericDebug(nameof(BotConfig) + ": " + JsonConvert.SerializeObject(BotConfig, Formatting.Indented));
}
BotDatabase = BotDatabase.Load(DatabaseFilePath);
if (BotDatabase == null) {
ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, DatabaseFilePath));
return;
}
// Register bot as available for ASF
if (!Bots.TryAdd(botName, this)) {
throw new ArgumentException(string.Format(Strings.ErrorIsInvalid, nameof(botName)));
@@ -785,7 +772,7 @@ namespace ArchiSteamFarm {
return;
}
BotConfig botConfig = BotConfig.Load(ConfigFilePath);
BotConfig botConfig = await BotConfig.Load(ConfigFilePath).ConfigureAwait(false);
if (botConfig == null) {
Destroy();
@@ -877,6 +864,32 @@ namespace ArchiSteamFarm {
return;
}
string botPath = Path.Combine(SharedInfo.ConfigDirectory, botName);
string configFilePath = botPath + SharedInfo.ConfigExtension;
BotConfig botConfig = await BotConfig.Load(botPath + SharedInfo.ConfigExtension).ConfigureAwait(false);
if (botConfig == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorBotConfigInvalid, configFilePath));
return;
}
if (Debugging.IsUserDebugging) {
ASF.ArchiLogger.LogGenericDebug(configFilePath + ": " + JsonConvert.SerializeObject(botConfig, Formatting.Indented));
}
string databaseFilePath = botPath + SharedInfo.DatabaseExtension;
BotDatabase botDatabase = await BotDatabase.Load(databaseFilePath).ConfigureAwait(false);
if (botDatabase == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, databaseFilePath));
return;
}
if (Debugging.IsUserDebugging) {
ASF.ArchiLogger.LogGenericDebug(databaseFilePath + ": " + JsonConvert.SerializeObject(botDatabase, Formatting.Indented));
}
Bot bot;
await BotsSemaphore.WaitAsync().ConfigureAwait(false);
try {
@@ -884,11 +897,12 @@ namespace ArchiSteamFarm {
return;
}
Bot bot = new Bot(botName);
bot.InitStart();
bot = new Bot(botName, botConfig, botDatabase);
} finally {
BotsSemaphore.Release();
}
bot.InitStart();
}
internal void RequestPersonaStateUpdate() {
@@ -981,36 +995,36 @@ namespace ArchiSteamFarm {
default:
switch (args[0].ToUpperInvariant()) {
case "2FA":
return await Response2FA(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await Response2FA(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "2FANO":
return await Response2FAConfirm(steamID, Utilities.GetArgsString(args, 1, ","), false).ConfigureAwait(false);
return await Response2FAConfirm(steamID, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false);
case "2FAOK":
return await Response2FAConfirm(steamID, Utilities.GetArgsString(args, 1, ","), true).ConfigureAwait(false);
return await Response2FAConfirm(steamID, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false);
case "ADDLICENSE":
if (args.Length > 2) {
return await ResponseAddLicense(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseAddLicense(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseAddLicense(steamID, args[1]).ConfigureAwait(false);
case "BL":
return await ResponseBlacklist(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseBlacklist(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "BLADD":
if (args.Length > 2) {
return await ResponseBlacklistAdd(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseBlacklistAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseBlacklistAdd(steamID, args[1]).ConfigureAwait(false);
case "BLRM":
if (args.Length > 2) {
return await ResponseBlacklistRemove(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseBlacklistRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseBlacklistRemove(steamID, args[1]).ConfigureAwait(false);
case "FARM":
return await ResponseFarm(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseFarm(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "INPUT":
if (args.Length > 3) {
return await ResponseInput(steamID, args[1], args[2], Utilities.GetArgsString(args, 3)).ConfigureAwait(false);
return await ResponseInput(steamID, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false);
}
if (args.Length > 2) {
@@ -1019,44 +1033,44 @@ namespace ArchiSteamFarm {
goto default;
case "IB":
return await ResponseIdleBlacklist(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseIdleBlacklist(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "IBADD":
if (args.Length > 2) {
return await ResponseIdleBlacklistAdd(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseIdleBlacklistAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseIdleBlacklistAdd(steamID, args[1]).ConfigureAwait(false);
case "IBRM":
if (args.Length > 2) {
return await ResponseIdleBlacklistRemove(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseIdleBlacklistRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseIdleBlacklistRemove(steamID, args[1]).ConfigureAwait(false);
case "IQ":
return await ResponseIdleQueue(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseIdleQueue(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "IQADD":
if (args.Length > 2) {
return await ResponseIdleQueueAdd(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseIdleQueueAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseIdleQueueAdd(steamID, args[1]).ConfigureAwait(false);
case "IQRM":
if (args.Length > 2) {
return await ResponseIdleQueueRemove(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseIdleQueueRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseIdleQueueRemove(steamID, args[1]).ConfigureAwait(false);
case "LEAVE":
if (chatID > 0) {
return await ResponseLeave(steamID, Utilities.GetArgsString(args, 1, ","), chatID).ConfigureAwait(false);
return await ResponseLeave(steamID, Utilities.GetArgsAsText(args, 1, ","), chatID).ConfigureAwait(false);
}
goto default;
case "LOOT":
return await ResponseLoot(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseLoot(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "LOOT^":
if (args.Length > 3) {
return await ResponseAdvancedLoot(steamID, args[1], args[2], Utilities.GetArgsString(args, 3, ",")).ConfigureAwait(false);
return await ResponseAdvancedLoot(steamID, args[1], args[2], Utilities.GetArgsAsText(args, 3, ",")).ConfigureAwait(false);
}
if (args.Length > 2) {
@@ -1065,50 +1079,56 @@ namespace ArchiSteamFarm {
goto default;
case "LOOT&":
return await ResponseLootSwitch(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseLootSwitch(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "NICKNAME":
if (args.Length > 2) {
return await ResponseNickname(steamID, args[1], Utilities.GetArgsString(args, 2)).ConfigureAwait(false);
return await ResponseNickname(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
}
return ResponseNickname(steamID, args[1]);
case "OA":
return await ResponseOwns(steamID, SharedInfo.ASF, Utilities.GetArgsString(args, 1)).ConfigureAwait(false);
return await ResponseOwns(steamID, SharedInfo.ASF, Utilities.GetArgsAsText(message, 1)).ConfigureAwait(false);
case "OWNS":
if (args.Length > 2) {
return await ResponseOwns(steamID, args[1], Utilities.GetArgsString(args, 2)).ConfigureAwait(false);
return await ResponseOwns(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
}
return (await ResponseOwns(steamID, args[1]).ConfigureAwait(false)).Response;
case "PASSWORD":
return await ResponsePassword(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponsePassword(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "PAUSE":
return await ResponsePause(steamID, Utilities.GetArgsString(args, 1, ","), true).ConfigureAwait(false);
return await ResponsePause(steamID, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false);
case "PAUSE~":
return await ResponsePause(steamID, Utilities.GetArgsString(args, 1, ","), false).ConfigureAwait(false);
return await ResponsePause(steamID, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false);
case "PAUSE&":
if (args.Length > 2) {
return await ResponsePause(steamID, args[1], true, Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponsePause(steamID, args[1], true, Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponsePause(steamID, true, args[1]).ConfigureAwait(false);
case "PLAY":
if (args.Length > 2) {
return await ResponsePlay(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponsePlay(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponsePlay(steamID, args[1]).ConfigureAwait(false);
case "PRIVACY":
if (args.Length > 2) {
return await ResponsePrivacy(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponsePrivacy(steamID, args[1]).ConfigureAwait(false);
case "R":
case "REDEEM":
if (args.Length > 2) {
return await ResponseRedeem(steamID, args[1], Utilities.GetArgsString(args, 2, ",")).ConfigureAwait(false);
return await ResponseRedeem(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
}
return await ResponseRedeem(steamID, args[1]).ConfigureAwait(false);
case "R^":
case "REDEEM^":
if (args.Length > 3) {
return await ResponseAdvancedRedeem(steamID, args[1], args[2], Utilities.GetArgsString(args, 3, ",")).ConfigureAwait(false);
return await ResponseAdvancedRedeem(steamID, args[1], args[2], Utilities.GetArgsAsText(args, 3, ",")).ConfigureAwait(false);
}
if (args.Length > 2) {
@@ -1117,18 +1137,18 @@ namespace ArchiSteamFarm {
goto default;
case "REJOINCHAT":
return await ResponseRejoinChat(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseRejoinChat(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "RESUME":
return await ResponseResume(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseResume(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "START":
return await ResponseStart(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseStart(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "STATUS":
return await ResponseStatus(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseStatus(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "STOP":
return await ResponseStop(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseStop(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
case "TRANSFER":
if (args.Length > 3) {
return await ResponseTransfer(steamID, args[1], args[2], Utilities.GetArgsString(args, 3, ",")).ConfigureAwait(false);
return await ResponseTransfer(steamID, args[1], args[2], Utilities.GetArgsAsText(args, 3, ",")).ConfigureAwait(false);
}
if (args.Length > 2) {
@@ -1137,7 +1157,7 @@ namespace ArchiSteamFarm {
goto default;
case "UNPACK":
return await ResponseUnpackBoosters(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
return await ResponseUnpackBoosters(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
default:
return ResponseUnknown(steamID);
}
@@ -1391,7 +1411,7 @@ namespace ArchiSteamFarm {
ArchiLogger.LogGenericInfo(Strings.BotAuthenticatorConverting);
try {
MobileAuthenticator authenticator = JsonConvert.DeserializeObject<MobileAuthenticator>(File.ReadAllText(maFilePath));
MobileAuthenticator authenticator = JsonConvert.DeserializeObject<MobileAuthenticator>(await File.ReadAllTextAsync(maFilePath).ConfigureAwait(false));
await BotDatabase.SetMobileAuthenticator(authenticator).ConfigureAwait(false);
File.Delete(maFilePath);
} catch (Exception e) {
@@ -1509,10 +1529,6 @@ namespace ArchiSteamFarm {
}
private void InitStart() {
if ((BotConfig == null) || (BotDatabase == null)) {
return;
}
if (!BotConfig.Enabled) {
ArchiLogger.LogGenericInfo(Strings.BotInstanceNotStartingBecauseDisabled);
return;
@@ -1697,10 +1713,16 @@ namespace ArchiSteamFarm {
if (File.Exists(SentryFilePath)) {
try {
byte[] sentryFileContent = File.ReadAllBytes(SentryFilePath);
byte[] sentryFileContent = await File.ReadAllBytesAsync(SentryFilePath).ConfigureAwait(false);
sentryFileHash = SteamKit2.CryptoHelper.SHAHash(sentryFileContent);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
try {
File.Delete(SentryFilePath);
} catch {
// Ignored, we can only try to delete faulted file at best
}
}
}
@@ -2216,6 +2238,13 @@ namespace ArchiSteamFarm {
}
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
try {
File.Delete(SentryFilePath);
} catch {
// Ignored, we can only try to delete faulted file at best
}
return;
}
@@ -4091,6 +4120,136 @@ namespace ArchiSteamFarm {
return responses.Count > 0 ? string.Join("", responses) : null;
}
private async Task<string> ResponsePrivacy(ulong steamID, string privacySettingsText) {
if ((steamID == 0) || string.IsNullOrEmpty(privacySettingsText)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(privacySettingsText));
return null;
}
if (!IsMaster(steamID)) {
return null;
}
if (!IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.BotNotConnected);
}
string[] privacySettingsArgs = privacySettingsText.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// There are only 6 privacy settings
if (privacySettingsArgs.Length > 6) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(privacySettingsArgs)));
}
Steam.UserPrivacy.PrivacySettings.EPrivacySetting profile = Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private;
Steam.UserPrivacy.PrivacySettings.EPrivacySetting ownedGames = Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private;
Steam.UserPrivacy.PrivacySettings.EPrivacySetting playtime = Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private;
Steam.UserPrivacy.PrivacySettings.EPrivacySetting inventory = Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private;
Steam.UserPrivacy.PrivacySettings.EPrivacySetting inventoryGifts = Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private;
Steam.UserPrivacy.ECommentPermission comments = Steam.UserPrivacy.ECommentPermission.Private;
// Converting digits to enum
for (byte index = 0; index < privacySettingsArgs.Length; index++) {
if (!Enum.TryParse(privacySettingsArgs[index], true, out Steam.UserPrivacy.PrivacySettings.EPrivacySetting privacySetting) || (privacySetting == Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Unknown) || !Enum.IsDefined(typeof(Steam.UserPrivacy.PrivacySettings.EPrivacySetting), privacySetting)) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(privacySettingsArgs)));
}
// Child setting can't be less restrictive than its parent
switch (index) {
case 0: // Profile
profile = privacySetting;
break;
case 1: // OwnedGames, child of Profile
if (profile < privacySetting) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(ownedGames)));
}
ownedGames = privacySetting;
break;
case 2: // Playtime, child of OwnedGames
if (ownedGames < privacySetting) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(playtime)));
}
playtime = privacySetting;
break;
case 3: // Inventory, child of Profile
if (profile < privacySetting) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(inventory)));
}
inventory = privacySetting;
break;
case 4: // InventoryGifts, child of Inventory
if (inventory < privacySetting) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(inventoryGifts)));
}
inventoryGifts = privacySetting;
break;
case 5: // Comments, child of Profile
if (profile < privacySetting) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(comments)));
}
// Comments use different numbers than everything else, but we want to have this command consistent for end-user, so we'll map them
switch (privacySetting) {
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly:
comments = Steam.UserPrivacy.ECommentPermission.FriendsOnly;
break;
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private:
comments = Steam.UserPrivacy.ECommentPermission.Private;
break;
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public:
comments = Steam.UserPrivacy.ECommentPermission.Public;
break;
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(privacySetting), privacySetting));
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(privacySetting)));
}
break;
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(index), index));
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(index)));
}
}
Steam.UserPrivacy userPrivacy = new Steam.UserPrivacy(new Steam.UserPrivacy.PrivacySettings(profile, ownedGames, playtime, inventory, inventoryGifts), comments);
return FormatBotResponse(await ArchiWebHandler.ChangePrivacySettings(userPrivacy).ConfigureAwait(false) ? Strings.Success : Strings.WarningFailed);
}
private async Task<string> ResponsePrivacy(ulong steamID, string botNames, string privacySettingsText) {
if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(privacySettingsText)) {
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(privacySettingsText));
return null;
}
HashSet<Bot> bots = GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
}
IEnumerable<Task<string>> tasks = bots.Select(bot => bot.ResponsePrivacy(steamID, privacySettingsText));
ICollection<string> results;
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
results = new List<string>(bots.Count);
foreach (Task<string> task in tasks) {
results.Add(await task.ConfigureAwait(false));
}
break;
default:
results = await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
return responses.Count > 0 ? string.Join("", responses) : null;
}
[SuppressMessage("ReSharper", "FunctionComplexityOverflow")]
private async Task<string> ResponseRedeem(ulong steamID, string keys, ERedeemFlags redeemFlags = ERedeemFlags.None) {
if ((steamID == 0) || string.IsNullOrEmpty(keys)) {

View File

@@ -41,6 +41,9 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal readonly bool AutoSteamSaleEvent;
[JsonProperty(Required = Required.DisallowNull)]
internal readonly EBotBehaviour BotBehaviour = EBotBehaviour.None;
[JsonProperty]
internal readonly string CustomGamePlayedWhileFarming;
@@ -114,9 +117,6 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal readonly bool UseLoginKeys = true;
[JsonProperty(Required = Required.DisallowNull)]
internal EBotBehaviour BotBehaviour { get; private set; } = EBotBehaviour.None;
[JsonProperty]
internal string SteamLogin { get; set; }
@@ -131,20 +131,6 @@ namespace ArchiSteamFarm {
private bool ShouldSerializeSensitiveDetails = true;
[JsonProperty(Required = Required.DisallowNull)]
private bool IsBotAccount {
set {
// TODO: Deprecate further in the next version
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningDeprecated, nameof(IsBotAccount), nameof(BotBehaviour)));
if (value) {
BotBehaviour |= EBotBehaviour.RejectInvalidFriendInvites;
BotBehaviour |= EBotBehaviour.RejectInvalidTrades;
BotBehaviour |= EBotBehaviour.RejectInvalidGroupInvites;
}
}
}
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamMasterClanID), Required = Required.DisallowNull)]
private string SSteamMasterClanID {
get => SteamMasterClanID.ToString();
@@ -162,7 +148,7 @@ namespace ArchiSteamFarm {
public bool ShouldSerializeSteamParentalPIN() => ShouldSerializeSensitiveDetails;
public bool ShouldSerializeSteamPassword() => ShouldSerializeSensitiveDetails;
internal static BotConfig Load(string filePath) {
internal static async Task<BotConfig> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
@@ -175,7 +161,7 @@ namespace ArchiSteamFarm {
BotConfig botConfig;
try {
botConfig = JsonConvert.DeserializeObject<BotConfig>(File.ReadAllText(filePath));
botConfig = JsonConvert.DeserializeObject<BotConfig>(await File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;

View File

@@ -185,7 +185,7 @@ namespace ArchiSteamFarm {
return IdlingPriorityAppIDs.Contains(appID);
}
internal static BotDatabase Load(string filePath) {
internal static async Task<BotDatabase> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
@@ -198,7 +198,7 @@ namespace ArchiSteamFarm {
BotDatabase botDatabase;
try {
botDatabase = JsonConvert.DeserializeObject<BotDatabase>(File.ReadAllText(filePath));
botDatabase = JsonConvert.DeserializeObject<BotDatabase>(await File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;

View File

@@ -244,7 +244,7 @@ namespace ArchiSteamFarm {
public bool ShouldSerializeWebProxyPassword() => ShouldSerializeSensitiveDetails;
internal static GlobalConfig Load(string filePath) {
internal static async Task<GlobalConfig> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
@@ -257,7 +257,7 @@ namespace ArchiSteamFarm {
GlobalConfig globalConfig;
try {
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(File.ReadAllText(filePath));
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(await File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;

View File

@@ -77,7 +77,7 @@ namespace ArchiSteamFarm {
return new HashSet<uint>(PackagesData.Where(package => package.Value.AppIDs?.Contains(appID) == true).Select(package => package.Key));
}
internal static GlobalDatabase Load(string filePath) {
internal static async Task<GlobalDatabase> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
@@ -90,7 +90,7 @@ namespace ArchiSteamFarm {
GlobalDatabase globalDatabase;
try {
globalDatabase = JsonConvert.DeserializeObject<GlobalDatabase>(File.ReadAllText(filePath));
globalDatabase = JsonConvert.DeserializeObject<GlobalDatabase>(await File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;

View File

@@ -795,7 +795,7 @@ namespace ArchiSteamFarm {
string argument = WebUtility.UrlDecode(string.Join("", arguments.Skip(argumentsIndex)));
string directory = Path.Combine(SharedInfo.WebsiteDirectory, argument);
string directory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.WebsiteDirectory, argument);
if (!Directory.Exists(directory)) {
await ResponseJsonObject(request, response, new GenericResponse<HashSet<string>>(false, string.Format(Strings.ErrorIsInvalid, nameof(directory))), HttpStatusCode.BadRequest).ConfigureAwait(false);
return true;
@@ -837,7 +837,7 @@ namespace ArchiSteamFarm {
return false;
}
string filePath = SharedInfo.WebsiteDirectory + Path.DirectorySeparatorChar + absolutePath.Replace("/", Path.DirectorySeparatorChar.ToString());
string filePath = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.WebsiteDirectory) + Path.DirectorySeparatorChar + absolutePath.Replace('/', Path.DirectorySeparatorChar);
if (Directory.Exists(filePath)) {
filePath = Path.Combine(filePath, "index.html");
}

View File

@@ -338,6 +338,7 @@ namespace ArchiSteamFarm.Json {
Generic,
Trade,
Market,
// We're missing information about definition of number 4 type
ChangePhoneNumber = 5
}
@@ -353,7 +354,7 @@ namespace ArchiSteamFarm.Json {
}
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal sealed class InventoryResponse : NonZeroResponse {
internal sealed class InventoryResponse : NumberResponse {
[JsonProperty(PropertyName = "assets", Required = Required.DisallowNull)]
internal readonly HashSet<Asset> Assets;
@@ -444,7 +445,7 @@ namespace ArchiSteamFarm.Json {
}
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal class NonZeroResponse {
internal class NumberResponse {
internal bool Success { get; private set; }
[JsonProperty(PropertyName = "success", Required = Required.Always)]
@@ -465,32 +466,7 @@ namespace ArchiSteamFarm.Json {
}
// Deserialized from JSON
protected NonZeroResponse() { }
}
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal sealed class PrivacyResponse {
[JsonProperty(PropertyName = "PrivacySettings", Required = Required.Always)]
internal readonly PrivacySettings Settings;
// Deserialized from JSON
private PrivacyResponse() { }
internal sealed class PrivacySettings {
[JsonProperty(PropertyName = "PrivacyInventory", Required = Required.Always)]
internal readonly EPrivacySetting Inventory;
// Deserialized from JSON
private PrivacySettings() { }
[SuppressMessage("ReSharper", "UnusedMember.Global")]
internal enum EPrivacySetting : byte {
Unknown,
Private,
FriendsOnly,
Public
}
}
protected NumberResponse() { }
}
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
@@ -628,5 +604,69 @@ namespace ArchiSteamFarm.Json {
internal readonly HashSet<Asset> Assets = new HashSet<Asset>();
}
}
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal sealed class UserPrivacy {
[JsonProperty(PropertyName = "eCommentPermission", Required = Required.Always)]
internal readonly ECommentPermission CommentPermission;
[JsonProperty(PropertyName = "PrivacySettings", Required = Required.Always)]
internal readonly PrivacySettings Settings;
// Constructed from privacy change request
internal UserPrivacy(PrivacySettings settings, ECommentPermission commentPermission) {
Settings = settings ?? throw new ArgumentNullException(nameof(settings));
CommentPermission = commentPermission;
}
// Deserialized from JSON
private UserPrivacy() { }
internal sealed class PrivacySettings {
[JsonProperty(PropertyName = "PrivacyInventory", Required = Required.Always)]
internal readonly EPrivacySetting Inventory;
[JsonProperty(PropertyName = "PrivacyInventoryGifts", Required = Required.Always)]
internal readonly EPrivacySetting InventoryGifts;
[JsonProperty(PropertyName = "PrivacyOwnedGames", Required = Required.Always)]
internal readonly EPrivacySetting OwnedGames;
[JsonProperty(PropertyName = "PrivacyPlaytime", Required = Required.Always)]
internal readonly EPrivacySetting Playtime;
[JsonProperty(PropertyName = "PrivacyProfile", Required = Required.Always)]
internal readonly EPrivacySetting Profile;
// Constructed from privacy change request
internal PrivacySettings(EPrivacySetting profile, EPrivacySetting ownedGames, EPrivacySetting playtime, EPrivacySetting inventory, EPrivacySetting inventoryGifts) {
if ((profile == EPrivacySetting.Unknown) || (ownedGames == EPrivacySetting.Unknown) || (playtime == EPrivacySetting.Unknown) || (inventory == EPrivacySetting.Unknown) || (inventoryGifts == EPrivacySetting.Unknown)) {
throw new ArgumentNullException(nameof(profile) + " || " + nameof(ownedGames) + " || " + nameof(playtime) + " || " + nameof(inventory) + " || " + nameof(inventoryGifts));
}
Profile = profile;
OwnedGames = ownedGames;
Playtime = playtime;
Inventory = inventory;
InventoryGifts = inventoryGifts;
}
// Deserialized from JSON
private PrivacySettings() { }
internal enum EPrivacySetting : byte {
Unknown,
Private,
FriendsOnly,
Public
}
}
internal enum ECommentPermission : byte {
FriendsOnly,
Public,
Private
}
}
}
}

View File

@@ -503,7 +503,10 @@
<value>Вече се притежава: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Ограничението надвишено, ще повторим след {0} на "отброяване"...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Повторно свързване…</value>
</data>
@@ -651,7 +654,16 @@
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>Обновяване на пакети данни...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>Използването на {0} е непрепоръчително и ще бъде премахнато в бъдещи версии на програмата. Моля, използвайте {1} вместо това.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Приети дарения: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Заобикалянето на {0} бъг е задействано.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -505,7 +505,10 @@ StackTrace:
<value>Ejes allerede: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Rate limit er blevet overskredet, vi prøver igen efter cooldown på {0}...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Forbinder igen...</value>
</data>
@@ -653,7 +656,16 @@ StackTrace:
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>Opdaterer pakkedata...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>Anvendelse af {0} er forældet og vil blive fjernet i fremtidige versioner af programmet. Brug venligst {1} i stedet.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Accepterede donationshandel: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Workaround for fejlen {0} er blevet aktiveret.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -664,5 +664,8 @@ StackTrace:
<value>Akzeptierter Geschenk-Handel: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Der Workaround für den {0} Bug wurde ausgelöst.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -665,5 +665,8 @@ StackTrace:
<value>Akzeptierter Geschenk-Handel: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Der Workaround für den {0} Bug wurde ausgelöst.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -505,7 +505,10 @@ StackTrace:
<value>Omistetut {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Yritysmäärä on ylitetty, yritetään uudelleen {0} jälkeen...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Yhdistetään uudelleen...</value>
</data>
@@ -646,11 +649,20 @@ StackTrace:
<value>Steamin discovery-jono #{0} tyhjennetty.</value>
<comment>{0} will be replaced by queue number</comment>
</data>
<data name="BotOwnsOverviewPerGame" xml:space="preserve">
<value>{0}/{1} bottia omistaa jo pelin {2}.</value>
<comment>{0} will be replaced by number of bots that already own particular game being checked, {1} will be replaced by total number of bots that were checked during the process, {2} will be replaced by game's ID (number)</comment>
</data>
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>Päivitetään pakettien tietoja...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>{0}:n käyttö on vanhentunut ja poistetaan tulevissa versioissa. Käytä sen sijaan {1}.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Hyväksyttiin lahjoitus: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
</root>

View File

@@ -166,11 +166,11 @@ StackTrace:
<value>אין בוטים מוגדרים. שכחת להגדיר את ASF?</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} הוא null!</value>
<value>{0} הוא ריק!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorParsingObject" xml:space="preserve">
<value>פירסור {0} נכשל!</value>
<value>ניתוח {0} נכשל!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
@@ -181,7 +181,7 @@ StackTrace:
<value>לא ניתן לבדוק את הגירסה העדכנית ביותר!</value>
</data>
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
<value>לא היה ניתן להמשיך עם העידכון כיוון שאין קובץ המיוחס לגרסה שרצה! עידכון אוטומטי לגרסה זו אינו אפשרי.</value>
<value>לא היה ניתן להמשיך עם העדכון כיוון שאין קובץ המיוחס לגרסה הפועלת כעת! עדכון אוטומטי לגרסה זו אינו אפשרי.</value>
</data>
<data name="ErrorUpdateNoAssets" xml:space="preserve">
<value>לא יכולנו להמשיך עם עדכון כי גירסה זו אינה מכילה אף נכס!</value>
@@ -248,7 +248,10 @@ StackTrace:
<value>גירסה מקומית: {0} | הגירסה המרוחקת: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceID" xml:space="preserve">
<value>הכנס את מזהה המכשיר שלך בבקשה (הכולל ": android:"): </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>אנא הכנס את קוד האימות מאפליקציית המאמת של Steam: </value>
<comment>Please note that this translation should end with space</comment>
@@ -392,8 +395,14 @@ StackTrace:
<data name="BotAccountLimited" xml:space="preserve">
<value>חשבון זה הוא מוגבל, התהליך אינו זמין עד להסרת ההגבלה!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>מזהה: {0} | סטטוס: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string</comment>
</data>
<data name="BotAddLicenseWithItems" xml:space="preserve">
<value>מזהה: {0} | סטטוס: {1} | פריטים: {2}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma</comment>
</data>
<data name="BotAlreadyRunning" xml:space="preserve">
<value>בוט זה כבר פועל!</value>
</data>
@@ -442,7 +451,10 @@ StackTrace:
<data name="BotInstanceNotStartingBecauseDisabled" xml:space="preserve">
<value>לא מריץ את הבוט הזה כי הוא אינו מופעל בקובץ ההגדרה!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>קיבל קוד שגיאה {0} TwoFactorCodeMismatch פעמים ברציפות, זה כמעט תמיד מציין אישורי ASF 2FA לא חוקיים, הפלה!</value>
<comment>{0} will be replaced by maximum allowed number of failed 2FA attempts</comment>
</data>
<data name="BotLoggedOff" xml:space="preserve">
<value>ניתוק מסטים: {0}</value>
<comment>{0} will be replaced by logging off reason (string)</comment>
@@ -480,7 +492,9 @@ StackTrace:
<data name="BotSendingTradeToYourself" xml:space="preserve">
<value>את לא יכול לשלוח בקשות החלפה לעצמך!</value>
</data>
<data name="BotNoASFAuthenticator" xml:space="preserve">
<value>לבוט זה אין ASF 2FA מופעל! האם שכחת להכניס את המאמת שלך כ- ASF 2FA?</value>
</data>
<data name="BotNotConnected" xml:space="preserve">
<value>מופע בוט זה לא מחובר!</value>
</data>
@@ -492,12 +506,21 @@ StackTrace:
<value>בבעלותך כבר: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>חרגת מגבלת התעריפים, ננסה שוב לאחר {0} שניות/דקות...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>מתחבר מחדש...</value>
</data>
<data name="BotRedeem" xml:space="preserve">
<value>מפתח: {0} | סטטוס: {1}</value>
<comment>{0} will be replaced by cd-key (string), {1} will be replaced by status string</comment>
</data>
<data name="BotRedeemWithItems" xml:space="preserve">
<value>מפתח: {0} | סטטוס: {1} | פריטים: {2}</value>
<comment>{0} will be replaced by cd-key (string), {1} will be replaced by status string, {2} will be replaced by list of key-value pairs, separated by a comma</comment>
</data>
<data name="BotRemovedExpiredLoginKey" xml:space="preserve">
<value>הוסר מפתח התחברות שתוקפו פג!</value>
</data>
@@ -553,12 +576,20 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>לא ניתן לנתק את התוכנה. נוטש את בוט זה!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>לא ניתן לאתחל את SteamDirectory: התחברות לרשת הסטים עשויה להימשך זמן רב מהרגיל!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>עוצר...</value>
</data>
<data name="ErrorBotConfigInvalid" xml:space="preserve">
<value>הגדרות הבוט שלך אינם נכונות. אמת את התוכן של {0} ונסה שוב!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorDatabaseInvalid" xml:space="preserve">
<value>לא ניתן לטעון את מסד הנתונים התמידי, אם הבעיה נמשכת, הסר את {0} כדי ליצור מחדש את מסד הנתונים!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="Initializing" xml:space="preserve">
<value>מאתחל {0}...</value>
<comment>{0} will be replaced by service name that is being initialized</comment>
@@ -569,21 +600,34 @@ StackTrace:
<data name="Welcome" xml:space="preserve">
<value>זה נראה שזו הפעם הראשונה שאתה מריץ את התוכנה, ברוך הבא!</value>
</data>
<data name="ErrorInvalidCurrentCulture" xml:space="preserve">
<value>ה- CurrentCulture המסופק שלך אינו חוקי, ASF ימשיך לפעול עם אפשרות ברירת המחדל!</value>
</data>
<data name="TranslationIncomplete" xml:space="preserve">
<value>ASF ינסה להשתמש בתרבות המועדפת עליך {0}, אך התרגום בשפה זו הושלם רק ב {1}. אולי אתה יכול לעזור לנו לשפר את התרגום ASF עבור השפה שלך?</value>
<comment>{0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%"</comment>
</data>
<data name="IdlingGameNotPossible" xml:space="preserve">
<value>הרצת {0} ({1}) אינו זמין באופן זמני, כיוון שASF לא מסוגל להריץ את המשחק הזה כרגע.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningIdlingGameMismatch" xml:space="preserve">
<value>ASF זיהה חוסר התאמה של מזהה עבור {0} ({1}) והשתמש במזהה {2} במקום זאת.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number)</comment>
</data>
<data name="BotVersion" xml:space="preserve">
<value>{0} גרסה {1}</value>
<comment>{0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages.</comment>
</data>
<data name="BotAccountLocked" xml:space="preserve">
<value>חשבון זה נעול, תהליך ההרצה אינו זמין לצמיתות!</value>
</data>
<data name="BotStatusLocked" xml:space="preserve">
<value>הבוט מוגבל ולא יפיק קלפים בזמן ההרצה.</value>
</data>
<data name="ErrorFunctionOnlyInHeadlessMode" xml:space="preserve">
<value>פונקציה זו זמינה רק במצב ללא ראש!</value>
</data>
<data name="BotOwnedAlready" xml:space="preserve">
<value>בבעלותך כבר: {0}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
@@ -598,14 +642,31 @@ StackTrace:
<value>השימוש בזיכרון הנוכחי: {0} MB.</value>
<comment>{0} will be replaced by number (in megabytes) of memory being used</comment>
</data>
<data name="ClearingDiscoveryQueue" xml:space="preserve">
<value>ניקוי תור גילוי סטים #{0}...</value>
<comment>{0} will be replaced by queue number</comment>
</data>
<data name="DoneClearingDiscoveryQueue" xml:space="preserve">
<value>סיים לנקות את רשימת הגילוי.#{0}.</value>
<comment>{0} will be replaced by queue number</comment>
</data>
<data name="BotOwnsOverviewPerGame" xml:space="preserve">
<value>{0} / {1} הבוטים כבר בעלים של משחק זה {2}.</value>
<comment>{0} will be replaced by number of bots that already own particular game being checked, {1} will be replaced by total number of bots that were checked during the process, {2} will be replaced by game's ID (number)</comment>
</data>
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>מרענן נתוני חבילות...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>השימוש ב- {0} הוצא משימוש ויוסר בגרסאות עתידיות של התוכנית. במקום זאת, השתמש ב {1}.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>סחר תרומה מקובל: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>הדרך לעקיפת הבעיה עבור {0} באגים הופעלה.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -504,7 +504,10 @@
<value>Già posseduto: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Superato il numero massimo di tentativi; nuovo tentativo tra {0}...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Riconnessione...</value>
</data>
@@ -652,7 +655,16 @@
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>Aggiornamento informazioni pacchetti...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>L'utilizzo di {0} è obsoleto e verrà rimosso nelle versioni future del programma. Utilizzare {1} in alternativa.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Accettata donazione: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>La soluzione temporanea per il bug {0} è stato utilizzata.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -506,7 +506,10 @@ StackTrace:
<value>이미 보유: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>등록 활성화 제한을 초과했습니다. {0} 의 대기 시간 이후 다시 시도합니다...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>다시 연결 중...</value>
</data>
@@ -654,7 +657,16 @@ StackTrace:
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>게임에 관한 데이터 갱신중...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>{0} 은(는) 더이상 사용되지 않아 향후 버전에서 제거될 예정입니다. {1} 을 대신 사용하여 주시기 바랍니다.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>기부 거래 수락: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>{0} 버그의 우회법이 발동했습니다.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -665,5 +665,8 @@ StackTrace:
<value>Donatieaanbod geaccepteerd: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Tijdelijke oplossing voor {0} bug is geactiveerd.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -665,5 +665,8 @@ StackTrace:
<value>Donatieaanbod geaccepteerd: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Tijdelijke oplossing voor {0} bug is geactiveerd.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -665,5 +665,8 @@
<value>Принято пожертвование в обмене: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Сработал обход ошибки {0}.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -506,7 +506,10 @@ Yığın izleme:
<value>Zaten sahip olunan: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Hız sınırııldı, {0} bekledikten sonra yeniden deneyeceğiz...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Yeniden bağlanılıyor...</value>
</data>
@@ -662,5 +665,8 @@ Yığın izleme:
<value>Kabul edilen takas bağışı: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>{0} hatası için geçici çözüm harekete geçirildi.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -665,5 +665,8 @@
<value>Прийнято пожертвування у обміні: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Використано тимчасове рішення для помилки {0}.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -657,7 +657,16 @@ StackTrace:
<data name="BotRefreshingPackagesData" xml:space="preserve">
<value>Đang làm mới các gói dữ liệu...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>Việc sử dụng {0} bị vô hiệu hoá và sẽ bị loại bỏ trong các phiên bản tương lai của chương trình. Xin vui lòng sử dụng {1} thay thế.</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Chấp nhận giao dịch tài trợ: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Giải pháp cho lỗi {0} đã được kích hoạt.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -662,5 +662,8 @@
<value>已接受捐赠交易︰{0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>{0} 漏洞的解决措施已触发</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -662,5 +662,8 @@
<value>接受的捐贈交易: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>已觸發 {0} 錯誤的解決方法。</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
</root>

View File

@@ -58,12 +58,10 @@ namespace ArchiSteamFarm {
return;
}
ConfigurationItemFactory.Default.ParseMessageTemplates = false;
LoggingConfiguration config = new LoggingConfiguration();
ColoredConsoleTarget coloredConsoleTarget = new ColoredConsoleTarget("ColoredConsole") {
DetectConsoleAvailable = false,
Layout = GeneralLayout
};
ColoredConsoleTarget coloredConsoleTarget = new ColoredConsoleTarget("ColoredConsole") { Layout = GeneralLayout };
config.AddTarget(coloredConsoleTarget);
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, coloredConsoleTarget));
@@ -106,11 +104,16 @@ namespace ArchiSteamFarm {
return;
}
bool reconfig = false;
foreach (LoggingRule consoleLoggingRule in ConsoleLoggingRules.Where(consoleLoggingRule => !LogManager.Configuration.LoggingRules.Contains(consoleLoggingRule))) {
LogManager.Configuration.LoggingRules.Add(consoleLoggingRule);
reconfig = true;
}
LogManager.ReconfigExistingLoggers();
if (reconfig) {
LogManager.ReconfigExistingLoggers();
}
}
internal static void OnUserInputStart() {
@@ -120,15 +123,22 @@ namespace ArchiSteamFarm {
return;
}
bool reconfig = false;
foreach (LoggingRule consoleLoggingRule in ConsoleLoggingRules) {
LogManager.Configuration.LoggingRules.Remove(consoleLoggingRule);
if (LogManager.Configuration.LoggingRules.Remove(consoleLoggingRule)) {
reconfig = true;
}
}
LogManager.ReconfigExistingLoggers();
if (reconfig) {
LogManager.ReconfigExistingLoggers();
}
}
private static void InitConsoleLoggers() {
ConsoleLoggingRules.Clear();
foreach (LoggingRule loggingRule in LogManager.Configuration.LoggingRules.Where(loggingRule => loggingRule.Targets.Any(target => target is ColoredConsoleTarget || target is ConsoleTarget))) {
ConsoleLoggingRules.Add(loggingRule);
}
@@ -147,6 +157,7 @@ namespace ArchiSteamFarm {
}
HistoryTarget historyTarget = (HistoryTarget) LogManager.Configuration.AllTargets.FirstOrDefault(target => target is HistoryTarget);
if (historyTarget != null) {
IPC.OnNewHistoryTarget(historyTarget);
}

View File

@@ -209,24 +209,21 @@ namespace ArchiSteamFarm {
}
private static void InitCore(IReadOnlyCollection<string> args) {
string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
if (!string.IsNullOrEmpty(homeDirectory)) {
Directory.SetCurrentDirectory(homeDirectory);
Directory.SetCurrentDirectory(SharedInfo.HomeDirectory);
// Allow loading configs from source tree if it's a debug build
if (Debugging.IsDebugBuild) {
// Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up
for (byte i = 0; i < 4; i++) {
Directory.SetCurrentDirectory("..");
if (Directory.Exists(SharedInfo.ConfigDirectory)) {
break;
}
// Allow loading configs from source tree if it's a debug build
if (Debugging.IsDebugBuild) {
// Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up
for (byte i = 0; i < 4; i++) {
Directory.SetCurrentDirectory("..");
if (Directory.Exists(SharedInfo.ConfigDirectory)) {
break;
}
}
// If config directory doesn't exist after our adjustment, abort all of that
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Directory.SetCurrentDirectory(homeDirectory);
}
// If config directory doesn't exist after our adjustment, abort all of that
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Directory.SetCurrentDirectory(SharedInfo.HomeDirectory);
}
}
@@ -241,7 +238,7 @@ namespace ArchiSteamFarm {
private static async Task InitGlobalConfigAndLanguage() {
string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName);
GlobalConfig = GlobalConfig.Load(globalConfigFile);
GlobalConfig = await GlobalConfig.Load(globalConfigFile).ConfigureAwait(false);
if (GlobalConfig == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorGlobalConfigNotLoaded, globalConfigFile));
await Task.Delay(5 * 1000).ConfigureAwait(false);
@@ -250,7 +247,7 @@ namespace ArchiSteamFarm {
}
if (Debugging.IsUserDebugging) {
ASF.ArchiLogger.LogGenericDebug(nameof(GlobalConfig) + ": " + JsonConvert.SerializeObject(GlobalConfig, Formatting.Indented));
ASF.ArchiLogger.LogGenericDebug(SharedInfo.GlobalConfigFileName + ": " + JsonConvert.SerializeObject(GlobalConfig, Formatting.Indented));
}
if (GlobalConfig.BackgroundGCPeriod > 0) {
@@ -318,7 +315,7 @@ namespace ArchiSteamFarm {
await Task.Delay(5 * 1000).ConfigureAwait(false);
}
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
GlobalDatabase = await GlobalDatabase.Load(globalDatabaseFile).ConfigureAwait(false);
if (GlobalDatabase == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, globalDatabaseFile));
await Task.Delay(5 * 1000).ConfigureAwait(false);
@@ -326,6 +323,10 @@ namespace ArchiSteamFarm {
return;
}
if (Debugging.IsUserDebugging) {
ASF.ArchiLogger.LogGenericDebug(SharedInfo.GlobalDatabaseFileName + ": " + JsonConvert.SerializeObject(GlobalDatabase, Formatting.Indented));
}
// If debugging is on, we prepare debug directory prior to running
if (GlobalConfig.Debug) {
Logging.EnableTraceLogging();
@@ -445,24 +446,6 @@ namespace ArchiSteamFarm {
case "--process-required" when !cryptKeyNext:
ProcessRequired = true;
break;
case "--server" when !cryptKeyNext:
// TODO: Deprecate further in the next version
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningDeprecated, "--server", "GlobalConfig.IPC"));
ProcessRequired = true;
if (GlobalConfig.IPCPrefixes.Count > 0) {
IPC.Start(GlobalConfig.IPCPrefixes);
}
break;
case "--service" when !cryptKeyNext:
// TODO: Deprecate further in the next version
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningDeprecated, "--service", "--no-restart --process-required --system-required"));
RestartAllowed = false;
ProcessRequired = true;
SystemRequired = true;
break;
case "--system-required" when !cryptKeyNext:
SystemRequired = true;
break;

View File

@@ -21,6 +21,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
namespace ArchiSteamFarm {
@@ -48,6 +49,7 @@ namespace ArchiSteamFarm {
internal const string UpdateDirectory = "_old";
internal const string WebsiteDirectory = "www";
internal static string HomeDirectory => Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
internal static Guid ModuleVersion => Assembly.GetEntryAssembly().ManifestModule.ModuleVersionId;
internal static string PublicIdentifier => AssemblyName + (BuildInfo.IsCustomBuild ? "-custom" : "");
internal static Version Version => Assembly.GetEntryAssembly().GetName().Version;

View File

@@ -35,13 +35,23 @@ namespace ArchiSteamFarm {
// Normally we wouldn't need to use this singleton, but we want to ensure decent randomness across entire program's lifetime
private static readonly Random Random = new Random();
internal static string GetArgsString(string[] args, byte argsToSkip, string delimiter = " ") {
if ((args == null) || (args.Length < argsToSkip) || string.IsNullOrEmpty(delimiter)) {
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(delimiter));
internal static string GetArgsAsText(string[] args, byte argsToSkip, string delimiter) {
if ((args == null) || (args.Length <= argsToSkip) || string.IsNullOrEmpty(delimiter)) {
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(argsToSkip) + " || " + nameof(delimiter));
return null;
}
return string.Join(delimiter, GetArgs(args, argsToSkip));
return string.Join(delimiter, args.Skip(argsToSkip));
}
internal static string GetArgsAsText(string text, byte argsToSkip) {
if (string.IsNullOrEmpty(text)) {
ASF.ArchiLogger.LogNullError(nameof(text));
return null;
}
string[] args = text.Split((char[]) null, argsToSkip + 1, StringSplitOptions.RemoveEmptyEntries);
return args[args.Length - 1];
}
internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) {
@@ -175,21 +185,5 @@ namespace ArchiSteamFarm {
}
internal static string ToHumanReadable(this TimeSpan timeSpan) => timeSpan.Humanize(3, maxUnit: TimeUnit.Year, minUnit: TimeUnit.Second);
private static string[] GetArgs(string[] args, byte argsToSkip) {
if ((args == null) || (args.Length < argsToSkip)) {
ASF.ArchiLogger.LogNullError(nameof(args));
return null;
}
byte argsToCopy = (byte) (args.Length - argsToSkip);
string[] result = new string[argsToCopy];
if (argsToCopy > 0) {
Array.Copy(args, argsToSkip, result, 0, argsToCopy);
}
return result;
}
}
}

View File

@@ -1,43 +1,43 @@
{
"bots-delete": "",
"bots-hide": "",
"bots-hide-offline": "",
"bots-hide-online": "",
"bots-key": "",
"bots-simple": "",
"bots-title": "",
"command-auto-clear": "",
"commands-title": "",
"editor-change": "",
"editor-current": "",
"editor-save": "",
"editor-title": "",
"generator-change": "",
"generator-current": "",
"bots-delete": "Vis sletknap",
"bots-hide": "Skjul bots",
"bots-hide-offline": "Offline bots",
"bots-hide-online": "Online bots",
"bots-key": "Vis nøgleknap",
"bots-simple": "Simpel farminginformation",
"bots-title": "ASF | Bots",
"command-auto-clear": "Autoslet",
"commands-title": "ASF | Kommandoer",
"editor-change": "Skift bot",
"editor-current": "I øjeblikket redigeres:",
"editor-save": "Gem",
"editor-title": "ASF | Konfigurations Editor",
"generator-change": "Ændr modus",
"generator-current": "Nuværende modus:",
"generator-download": "Download",
"generator-title": "",
"global-bots": "",
"global-boxed": "",
"global-boxed-description": "",
"global-change": "",
"global-changelog": "",
"global-commands": "",
"global-config": "",
"global-control-panel": "",
"global-editor": "",
"global-generator": "",
"generator-title": "ASF | Konfigurationsgenerator",
"global-bots": "Bots",
"global-boxed": "Boxed Layout",
"global-boxed-description": "Vis\/Skjul boxed layout",
"global-change": "Ændr",
"global-changelog": "Ændringslog",
"global-commands": "Kommandoer",
"global-config": "Konfiguration",
"global-control-panel": "Kontrolpanel",
"global-editor": "Redigeringsværktøj",
"global-generator": "Generator",
"global-home": "Hjem",
"global-information": "",
"global-language": "",
"global-layout": "",
"global-log": "",
"global-navigation": "",
"global-nightmode": "",
"global-nightmode-description": "",
"global-ram-usage": "",
"global-skins": "",
"global-uptime": "",
"global-version": "",
"global-wiki": "",
"log-title": ""
"global-information": "Information",
"global-language": "Sprog",
"global-layout": "Layout",
"global-log": "Log",
"global-navigation": "Vis\/Skjul navigation",
"global-nightmode": "Nattilstand",
"global-nightmode-description": "Vis\/Skjul nattilstand",
"global-ram-usage": "RAM-forbrug",
"global-skins": "Udseende",
"global-uptime": "Oppetid",
"global-version": "Version",
"global-wiki": "Wiki",
"log-title": "ASF | Log"
}

View File

@@ -1,43 +1,43 @@
{
"bots-delete": "",
"bots-hide": "",
"bots-hide-offline": "",
"bots-hide-online": "",
"bots-key": "",
"bots-simple": "",
"bots-title": "",
"command-auto-clear": "",
"commands-title": "",
"editor-change": "",
"editor-current": "",
"editor-save": "",
"editor-title": "",
"generator-change": "",
"generator-current": "",
"bots-delete": "Näytä poisto painike",
"bots-hide": "Piilota botit",
"bots-hide-offline": "Offline botit",
"bots-hide-online": "Online botit",
"bots-key": "Näytä avain painike",
"bots-simple": "Simppeli farmaus info",
"bots-title": "ASF |Botit",
"command-auto-clear": "Automaattinen tyhjennys",
"commands-title": "ASF | Komennot",
"editor-change": "Vaihda bottia",
"editor-current": "Tällä hetkellä muokataan:",
"editor-save": "Tallenna",
"editor-title": "ASF |Asetus editori",
"generator-change": "Vaihda tilaa",
"generator-current": "Tämänhetkinen tila:",
"generator-download": "Lataa",
"generator-title": "",
"global-bots": "",
"generator-title": "ASF |Asetus generaattori",
"global-bots": "Botit",
"global-boxed": "",
"global-boxed-description": "",
"global-change": "",
"global-changelog": "",
"global-commands": "",
"global-config": "",
"global-control-panel": "",
"global-editor": "",
"global-generator": "",
"global-change": "Vaihda",
"global-changelog": "Päivityshistoria",
"global-commands": "Komennot",
"global-config": "Asetukset",
"global-control-panel": "Ohjauspaneli",
"global-editor": "Editori",
"global-generator": "Generaattori",
"global-home": "Aloitus",
"global-information": "",
"global-language": "",
"global-layout": "",
"global-log": "",
"global-navigation": "",
"global-nightmode": "",
"global-nightmode-description": "",
"global-ram-usage": "",
"global-skins": "",
"global-uptime": "",
"global-version": "",
"global-wiki": "",
"log-title": ""
"global-information": "Tiedot",
"global-language": "Kieli",
"global-layout": "Asettelu",
"global-log": "Loki",
"global-navigation": "Näytä\/piilota navigointi",
"global-nightmode": "Yötila",
"global-nightmode-description": "Vaihda yötilaa",
"global-ram-usage": "RAM:in käyttö",
"global-skins": "Skinit",
"global-uptime": "Käynnissäoloaika",
"global-version": "Versio",
"global-wiki": "Wiki",
"log-title": "ASF | Loki"
}

View File

@@ -1,43 +1,43 @@
{
"bots-delete": "",
"bots-hide": "",
"bots-hide-offline": "",
"bots-hide-online": "",
"bots-key": "",
"bots-simple": "",
"bots-title": "",
"command-auto-clear": "",
"commands-title": "",
"editor-change": "",
"editor-current": "",
"editor-save": "",
"editor-title": "",
"generator-change": "",
"generator-current": "",
"generator-download": "",
"generator-title": "",
"global-bots": "",
"global-boxed": "",
"global-boxed-description": "",
"global-change": "",
"global-changelog": "",
"global-commands": "",
"global-config": "",
"global-control-panel": "",
"global-editor": "",
"global-generator": "",
"global-home": "",
"global-information": "",
"global-language": "",
"global-layout": "",
"global-log": "",
"global-navigation": "",
"global-nightmode": "",
"global-nightmode-description": "",
"global-ram-usage": "",
"global-skins": "",
"global-uptime": "",
"global-version": "",
"global-wiki": "",
"log-title": ""
"bots-delete": "הצג לחצן מחיקה",
"bots-hide": "להחביא בוטים",
"bots-hide-offline": "בוטים לא מקוונים",
"bots-hide-online": "בוטים מופעלים",
"bots-key": "הצג לחצן מפתח",
"bots-simple": "מידע פשוט על חקלאות קלפים",
"bots-title": "ASF | בוטים",
"command-auto-clear": "מחיקה אוטומטית",
"commands-title": "ASF | פקודות",
"editor-change": "שינוי בוט",
"editor-current": "כעת עריכה:",
"editor-save": "שמירה",
"editor-title": "ASF | שינוי הגדרות",
"generator-change": "שינוי מצב",
"generator-current": "מצב נוכחי:",
"generator-download": "הורדה",
"generator-title": "ASF | יוצר הגדרות",
"global-bots": "בוטים",
"global-boxed": "פריסת מסגרת",
"global-boxed-description": "להחליף את פריסת מסגרת",
"global-change": "שינוי",
"global-changelog": "יומן שינוים",
"global-commands": "פקודות",
"global-config": "הגדרות",
"global-control-panel": "לוח הבקרה",
"global-editor": "עורך",
"global-generator": "יוצר",
"global-home": "דף בית",
"global-information": "מידע",
"global-language": "שפה",
"global-layout": "פריסה",
"global-log": "יומן",
"global-navigation": "הפעלה\/כיבוי ניווט",
"global-nightmode": "מצב לילה",
"global-nightmode-description": "החלף את מצב הלילה",
"global-ram-usage": "שימוש בזיכרון",
"global-skins": "סקינים (מעטפות)",
"global-uptime": "זמן פעולה תקינה",
"global-version": "גירסה",
"global-wiki": "Wiki",
"log-title": "ASF | יומן"
}

View File

@@ -3,34 +3,34 @@
"bots-hide": "Nascondi bot",
"bots-hide-offline": "Bot offline",
"bots-hide-online": "Bot online",
"bots-key": "",
"bots-key": "Mostra il pulsante chiave",
"bots-simple": "",
"bots-title": "ASF | Bot",
"command-auto-clear": "",
"command-auto-clear": "Cancellazione automatica",
"commands-title": "ASF | Comandi",
"editor-change": "Cambia bot",
"editor-current": "",
"editor-save": "Salva",
"editor-title": "ASF | Editor di configurazione",
"generator-change": "",
"generator-current": "",
"generator-change": "Cambia modalità",
"generator-current": "Modalità attuale:",
"generator-download": "Scarica",
"generator-title": "",
"generator-title": "ASF | Generatore di configurazione",
"global-bots": "Bot",
"global-boxed": "",
"global-boxed-description": "",
"global-change": "",
"global-changelog": "",
"global-change": "Cambia",
"global-changelog": "Registro delle modifiche",
"global-commands": "Comandi",
"global-config": "",
"global-control-panel": "",
"global-editor": "",
"global-generator": "",
"global-config": "Configurazione",
"global-control-panel": "Pannello di controllo",
"global-editor": "Editor",
"global-generator": "Generatore",
"global-home": "Homepage",
"global-information": "",
"global-language": "",
"global-information": "Informazioni",
"global-language": "Lingua",
"global-layout": "",
"global-log": "",
"global-log": "Log",
"global-navigation": "",
"global-nightmode": "Modalità notturna",
"global-nightmode-description": "Attiva\/disattiva la modalità notturna",
@@ -39,5 +39,5 @@
"global-uptime": "",
"global-version": "Versione",
"global-wiki": "Wiki",
"log-title": ""
"log-title": "ASF | Log"
}

View File

@@ -9,8 +9,8 @@
"command-auto-clear": "自動クリア",
"commands-title": "",
"editor-change": "",
"editor-current": "",
"editor-save": "",
"editor-current": "編集中:",
"editor-save": "保存",
"editor-title": "",
"generator-change": "モード変更",
"generator-current": "現在のモード:",
@@ -22,7 +22,7 @@
"global-change": "変更",
"global-changelog": "チェンジログ",
"global-commands": "コマンド",
"global-config": "コンフィグ",
"global-config": "設定",
"global-control-panel": "コントロールパネル",
"global-editor": "",
"global-generator": "ジェネレーター",

View File

@@ -5,39 +5,39 @@
"bots-hide-online": "",
"bots-key": "",
"bots-simple": "",
"bots-title": "",
"command-auto-clear": "",
"commands-title": "",
"editor-change": "",
"editor-current": "",
"editor-save": "",
"bots-title": "ASF | Bot",
"command-auto-clear": "Tự động xóa",
"commands-title": "ASF | Lệnh",
"editor-change": "Thay đổi bot",
"editor-current": "Hiện đang chỉnh sửa:",
"editor-save": "Lưu",
"editor-title": "",
"generator-change": "",
"generator-current": "",
"generator-change": "Chuyển chế độ",
"generator-current": "Chế độ hiện tại:",
"generator-download": "Tải về",
"generator-title": "",
"global-bots": "",
"global-bots": "Bot",
"global-boxed": "",
"global-boxed-description": "",
"global-change": "",
"global-change": "Thay đổi",
"global-changelog": "Các thay đổi",
"global-commands": "",
"global-commands": "Lệnh",
"global-config": "Cấu hình",
"global-control-panel": "Bảng điều khiển trung tâm",
"global-editor": "Trình biên tập",
"global-generator": "",
"global-generator": "Tạo",
"global-home": "Trang chủ",
"global-information": "",
"global-language": "",
"global-layout": "",
"global-log": "",
"global-navigation": "",
"global-nightmode": "",
"global-nightmode-description": "",
"global-information": "Thông tin",
"global-language": "Ngôn ngữ",
"global-layout": "Bố cục",
"global-log": "Nhật ký",
"global-navigation": "Chuyển đổi điều hướng",
"global-nightmode": "Chế độ ban đêm",
"global-nightmode-description": "Chuyển đổi chế độ ban đêm",
"global-ram-usage": "Bộ nhớ RAM dùng",
"global-skins": "Giao diện",
"global-uptime": "Thời gian hoạt động",
"global-version": "Phiên bản",
"global-wiki": "Wiki",
"log-title": ""
"log-title": "ASF | Nhật ký"
}

View File

@@ -1,26 +1,26 @@
{
"app.name": "",
"button.advanced": "",
"button.download": "",
"home.topic": "",
"link.asf": "",
"link.bot": "",
"link.home": "",
"schema.access": "",
"schema.advanced": "",
"schema.basic": "",
"schema.bot.SteamLogin.description": "",
"schema.bot.SteamPassword.description": "",
"schema.bot.name": "",
"schema.bot.name.description": "",
"schema.connection": "",
"schema.customization": "",
"schema.farming": "",
"schema.generic.steamid64": "",
"schema.performance": "",
"schema.remote_access": "",
"schema.security": "",
"schema.trading": "",
"schema.updates": "",
"static.add": ""
"app.name": "ASF | יוצר הגדרות",
"button.advanced": "מצב הגדרות מתקדמות",
"button.download": "הורדה",
"home.topic": "ASF Config מחולל הוא כלי כלי קטן נכתב בג'אווה סקריפט, זה מסייע לך ליצור קבצי התצורה שלך ASF. לאחר הורדת config שנוצר, להעבירו לתיקיה <var>config</var> בתוך הספריה הראשית ASF. לתיעוד מלא מתייחסים שלנו wiki <a href=\"https://github.com/JustArchi/ArchiSteamFarm/wiki/Configuration\" target=\"_blank\" rel=\"noopener\"></a>. אנו מקווים כי כלי שלנו יהיה שימושי עבורך.",
"link.asf": "ASF",
"link.bot": "בוט",
"link.home": "דף בית",
"schema.access": "גישה",
"schema.advanced": "מתקדם",
"schema.basic": "בסיסי",
"schema.bot.SteamLogin.description": "הכניסה לחשבון שלך סטים",
"schema.bot.SteamPassword.description": "סיסמת החשבון שלך סטים",
"schema.bot.name": "שם",
"schema.bot.name.description": "השם של בוט",
"schema.connection": "חיבור",
"schema.customization": "התאמה אישית",
"schema.farming": "חקלאות",
"schema.generic.steamid64": "SteamID64 שלך",
"schema.performance": "ביצועים",
"schema.remote_access": "גישה מרוחק",
"schema.security": "אבטחה",
"schema.trading": "מסחר",
"schema.updates": "עדכונים",
"static.add": "הוסף"
}

View File

@@ -29,6 +29,10 @@ before_build:
dotnet --info
if ($LastExitCode -ne 0) {
throw "Command failed."
}
build_script:
- pwsh: >-
Set-StrictMode -Version Latest
@@ -39,6 +43,10 @@ build_script:
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -o 'out\source' /nologo
if ($LastExitCode -ne 0) {
throw "Command failed."
}
test_script:
- pwsh: >-
Set-StrictMode -Version Latest
@@ -48,7 +56,11 @@ test_script:
$ProgressPreference = 'SilentlyContinue'
dotnet test ArchiSteamFarm.Tests -c "$env:CONFIGURATION" -o 'out\source'
dotnet test ArchiSteamFarm.Tests -c "$env:CONFIGURATION" -o 'out\source' /nologo
if ($LastExitCode -ne 0) {
throw "Command failed."
}
after_test:
- pwsh: >-
Set-StrictMode -Version Latest
@@ -73,6 +85,10 @@ after_test:
dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -o "out\$Variant" -r "$Variant" /nologo "/p:ASFVariant=$Variant" "/p:CrossGenDuringPublish=false"
}
if ($LastExitCode -ne 0) {
throw "Command failed."
}
# If we include any helper scripts for this variant, copy them to output directory
if (Test-Path -Path "ArchiSteamFarm\scripts\$Variant" -PathType Container) {
Copy-Item "ArchiSteamFarm\scripts\$Variant\*" -Destination "ArchiSteamFarm\out\$Variant"
@@ -81,6 +97,10 @@ after_test:
# Until https://github.com/dotnet/cli/issues/3267 happens, we'll hack dotnet binary icon on Windows and include .ico file on other platforms
if (Test-Path -Path "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" -PathType Leaf) {
tools\rcedit\rcedit-x64.exe "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" --set-icon 'resources\ASF.ico'
if ($LastExitCode -ne 0) {
throw "Command failed."
}
} else {
Copy-Item 'resources\ASF.ico' -Destination "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.ico"
}
@@ -99,8 +119,17 @@ after_test:
}
7z a -bd -tzip -mm=Deflate64 $zipArgs "ArchiSteamFarm\out\ASF-$Variant.zip" "$env:APPVEYOR_BUILD_FOLDER\ArchiSteamFarm\out\$Variant\*"
if ($LastExitCode -ne 0) {
throw "Command failed."
}
# TODO: Change me to Push-AppveyorArtifact once https://github.com/appveyor/ci/issues/2183 is fixed
appveyor PushArtifact "ArchiSteamFarm\out\ASF-$Variant.zip" -FileName "ASF-$Variant.zip" -DeploymentName "ASF-$Variant.zip"
if ($LastExitCode -ne 0) {
throw "Command failed."
}
}
foreach ($variant in $env:VARIANTS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {

39
cc.sh
View File

@@ -17,13 +17,19 @@ cd "$(dirname "$(readlink -f "$0")")"
for ARG in "$@"; do
case "$ARG" in
release|Release) CONFIGURATION="Release" ;;
debug|Debug) CONFIGURATION="Debug" ;;
release|Release) CONFIGURATION="Release" ;;
--clean) CLEAN=1 ;;
--no-clean) CLEAN=0 ;;
--link-during-publish) LINK_DURING_PUBLISH=1 ;;
--no-link-during-publish) LINK_DURING_PUBLISH=0 ;;
--pull) PULL=1 ;;
--no-pull) PULL=0 ;;
--shared-compilation) SHARED_COMPILATION=1 ;;
--no-shared-compilation) SHARED_COMPILATION=0 ;;
--test) TEST=1 ;;
--no-test) TEST=0 ;;
--help) echo "Usage: $0 [--clean] [--no-link-during-publish] [--no-pull] [--no-shared-compilation] [--no-test] [debug/release]"; exit 0 ;;
*) echo "Usage: $0 [--clean] [--no-link-during-publish] [--no-pull] [--no-shared-compilation] [--no-test] [debug/release]"; exit 1
esac
done
@@ -46,35 +52,26 @@ if [[ ! -f "$SOLUTION" ]]; then
exit 1
fi
SETUP_FLAGS=(-c "$CONFIGURATION" -o "$OUT")
BUILD_FLAGS=(--no-restore '/nologo')
DOTNET_FLAGS=(-c "$CONFIGURATION" -o "$OUT" '/nologo')
if [[ "$LINK_DURING_PUBLISH" -eq 0 ]]; then
BUILD_FLAGS+=('/p:LinkDuringPublish=false')
DOTNET_FLAGS+=('/p:LinkDuringPublish=false')
fi
if [[ "$SHARED_COMPILATION" -eq 0 ]]; then
BUILD_FLAGS+=('/p:UseSharedCompilation=false')
DOTNET_FLAGS+=('/p:UseSharedCompilation=false')
fi
if [[ "$CLEAN" -eq 1 ]]; then
dotnet clean "${DOTNET_FLAGS[@]}"
rm -rf "${MAIN_PROJECT:?}/${OUT}" "${TESTS_PROJECT:?}/${OUT}"
fi
if [[ "$TEST" -eq 1 ]]; then
if [[ "$CLEAN" -eq 1 ]]; then
dotnet clean "${SETUP_FLAGS[@]}"
rm -rf "${MAIN_PROJECT:?}/${OUT}" "${TESTS_PROJECT:?}/${OUT}"
fi
dotnet restore
dotnet publish "${SETUP_FLAGS[@]}" "${BUILD_FLAGS[@]}"
dotnet test "$TESTS_PROJECT" "${SETUP_FLAGS[@]}" --no-build "${BUILD_FLAGS[@]}"
else
if [[ "$CLEAN" -eq 1 ]]; then
dotnet clean "$MAIN_PROJECT" "${SETUP_FLAGS[@]}"
rm -rf "${MAIN_PROJECT:?}/${OUT}"
fi
dotnet restore "$MAIN_PROJECT"
dotnet publish "$MAIN_PROJECT" "${SETUP_FLAGS[@]}" "${BUILD_FLAGS[@]}"
dotnet test "$TESTS_PROJECT" "${DOTNET_FLAGS[@]}"
fi
dotnet publish "$MAIN_PROJECT" "${DOTNET_FLAGS[@]}"
echo
echo "Compilation finished successfully! :)"

10
run.sh
View File

@@ -14,9 +14,15 @@ PARSE_ARG() {
BINARY_ARGS+=("$1")
case "$1" in
--cryptkey|--server|--service) ;;
--path) PATH_NEXT=1 ;;
--path=*) cd "$(echo "$1" | cut -d '=' -f 2-)" ;;
--path=*)
if [[ "$PATH_NEXT" -eq 1 ]]; then
PATH_NEXT=0
cd "$1"
else
cd "$(echo "$1" | cut -d '=' -f 2-)"
fi
;;
*)
if [[ "$PATH_NEXT" -eq 1 ]]; then
PATH_NEXT=0

2
wiki

Submodule wiki updated: fabd7ac65c...aa52423a48