Compare commits

...

381 Commits

Author SHA1 Message Date
Łukasz Domeradzki
4a9ecc52c1 Bump 2025-12-11 20:22:46 +01:00
Łukasz Domeradzki
10fc914ac1 Add Winter Sale 2025 to SalesBlacklist 2025-12-11 20:22:25 +01:00
renovate[bot]
7e9c49cc79 chore(deps): update dependency scalar.aspnetcore to 2.11.5 2025-12-11 06:32:14 +00:00
renovate[bot]
ab58886d29 chore(deps): update asf-ui digest to c703223 2025-12-11 02:38:02 +00:00
ArchiBot
a5740a43db Automatic translations update 2025-12-11 02:30:45 +00:00
renovate[bot]
223f2b98cb chore(deps): update dotnet monorepo to 10.0.1 2025-12-10 06:31:16 +00:00
renovate[bot]
69b150c8a0 chore(deps): update dependency scalar.aspnetcore to 2.11.3 2025-12-10 02:52:39 +00:00
ArchiBot
f4ea1d44ac Automatic translations update 2025-12-10 02:29:24 +00:00
renovate[bot]
d02504b914 chore(deps): update dependency scalar.aspnetcore to 2.11.2 2025-12-09 03:35:28 +00:00
ArchiBot
c363af8c3a Automatic translations update 2025-12-09 02:27:11 +00:00
Łukasz Domeradzki
c06a22ec93 Bump 2025-12-08 23:33:24 +01:00
Łukasz Domeradzki
ed19d7e3bf Misc, bump 2025-12-08 23:32:17 +01:00
Łukasz Domeradzki
4eee2e2ac7 Fix authentication flow when reaching max failures in credentials provider
This one is tricky, previously we've properly handled max failures, and told SK2 to abort the request with operation canceled exception, which we even handled back in bot flow, so it looked OK at first, but the bot didn't do anything with that, which resulted in forced TryAnotherCM disconnection after 1 minute of inactivity.

Since we need to be informed what to do in such case, simple cancellation of flow is not enough, we require a custom exception to handle, which will tell us the precise reason for failure + possible count of them, and that will in result allow us to react accordingly in the bot flow, e.g. by stopping the bot if needed.
2025-12-08 23:25:15 +01:00
Łukasz Domeradzki
90fe1a9448 Bump 2025-12-08 21:55:29 +01:00
Łukasz Domeradzki
8c26dcb7c2 Misc 2025-12-08 21:55:24 +01:00
ArchiBot
ba8150b27a Automatic translations update 2025-12-08 02:28:30 +00:00
ArchiBot
612b3dd3ef Automatic translations update 2025-12-06 02:23:51 +00:00
renovate[bot]
a551568f2b chore(deps): update dependency scalar.aspnetcore to 2.11.1 2025-12-04 20:53:14 +00:00
renovate[bot]
31615ef64d chore(deps): update asf-ui digest to 00bfe2e 2025-12-03 13:05:45 +00:00
renovate[bot]
0f0f1bfcd3 chore(deps): update actions/setup-node action to v6.1.0 2025-12-03 08:41:07 +00:00
renovate[bot]
702e27c466 chore(deps): update asf-ui digest to 93e8a77 2025-12-03 04:40:17 +00:00
renovate[bot]
921263674d chore(deps): update actions/checkout action to v6.0.1 2025-12-02 17:32:57 +00:00
renovate[bot]
5110d6d9f9 chore(deps): update crowdin/github-action action to v2.13.0 2025-12-02 10:40:58 +00:00
ArchiBot
5f622128e4 Automatic translations update 2025-11-30 02:33:42 +00:00
ArchiBot
6eee3fb4d9 Automatic translations update 2025-11-29 02:23:49 +00:00
ArchiBot
0aa777734a Automatic translations update 2025-11-28 02:24:18 +00:00
renovate[bot]
be789d706b chore(deps): update wiki digest to afb2ccd 2025-11-27 15:36:14 +00:00
renovate[bot]
03bfc169bb chore(deps): update dependency jetbrains.annotations.sources to 2025.2.4 2025-11-27 03:43:34 +00:00
ArchiBot
12d26bfd60 Automatic translations update 2025-11-27 02:23:56 +00:00
ArchiBot
cb31836c34 Automatic translations update 2025-11-26 02:25:47 +00:00
renovate[bot]
f091707b0d chore(deps): update dependency markdig.signed to 0.44.0 2025-11-25 09:44:27 +00:00
renovate[bot]
f4467fcd38 chore(deps): update actions/setup-dotnet action to v5.0.1 2025-11-25 05:45:11 +00:00
ArchiBot
f00b6bfdf1 Automatic translations update 2025-11-25 02:25:49 +00:00
Łukasz Domeradzki
bbfe0e40c5 Misc 2025-11-24 12:03:28 +01:00
Łukasz Domeradzki
e1e928c4ca Misc
Thanks @xPaw
2025-11-24 11:12:30 +01:00
Pavel Djundik
29cb094430 Optimize generating totp codes (#3512) 2025-11-24 11:11:46 +01:00
Łukasz Domeradzki
dfd2bd9ac4 Add additional OSes to test CI for 2025-11-24 10:42:52 +01:00
ArchiBot
c65ffa44d9 Automatic translations update 2025-11-24 02:30:30 +00:00
Łukasz Domeradzki
cf84c19a1a Bump 2025-11-23 23:48:18 +01:00
renovate[bot]
252e498d8b chore(deps): update asf-ui digest to e2d9422 2025-11-23 05:43:21 +00:00
ArchiBot
1e3a5a5176 Automatic translations update 2025-11-23 02:35:10 +00:00
ArchiBot
c21ca7dbb3 Automatic translations update 2025-11-22 02:22:37 +00:00
renovate[bot]
f7b5699172 chore(deps): update asf-ui digest to 5456569 2025-11-21 18:35:58 +00:00
renovate[bot]
2793775f26 chore(deps): update asf-ui digest to 64ee4fe 2025-11-20 18:29:23 +00:00
renovate[bot]
ab54040d3b chore(deps): update actions/checkout action to v6 (#3509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 19:28:43 +01:00
renovate[bot]
36225c5b93 chore(deps): update dependency humanizer to 3.0.1 2025-11-20 05:06:44 +00:00
renovate[bot]
647dcb5834 chore(deps): update dependency scalar.aspnetcore to 2.11.0 2025-11-19 21:48:11 +00:00
renovate[bot]
12e59a649a chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.15.0 2025-11-19 09:59:04 +00:00
renovate[bot]
f85c36e8ee chore(deps): update actions/checkout action to v5.0.1 2025-11-19 06:02:04 +00:00
ArchiBot
7e4878a3f1 Automatic translations update 2025-11-19 02:24:20 +00:00
renovate[bot]
35aeee1b63 chore(deps): update asf-ui digest to e0c8543 2025-11-18 13:10:03 +00:00
ArchiBot
6f1dffbc01 Automatic translations update 2025-11-18 02:24:16 +00:00
ArchiBot
f6ae839a2f Automatic translations update 2025-11-17 02:26:06 +00:00
renovate[bot]
4d97862ec8 chore(deps): update wiki digest to 8dfa02f 2025-11-16 18:13:49 +00:00
renovate[bot]
84a0b59aba chore(deps): update opentelemetry-dotnet-contrib monorepo to 1.14.0 2025-11-14 05:02:20 +00:00
ArchiBot
1c9a3dbf36 Automatic translations update 2025-11-14 02:24:47 +00:00
renovate[bot]
4540b4a2da chore(deps): update dependency nlog.web.aspnetcore to 6.1.0 2025-11-13 10:02:31 +00:00
renovate[bot]
1e814a63cc chore(deps): update dependency anglesharp to 1.4.0 2025-11-13 08:03:50 +00:00
ArchiBot
f4f70ec802 Automatic translations update 2025-11-13 02:26:29 +00:00
renovate[bot]
41656011a6 chore(deps): update opentelemetry-dotnet monorepo 2025-11-12 18:46:30 +00:00
renovate[bot]
f061be0798 chore(deps): update asf-ui digest to e91078e 2025-11-12 04:50:09 +00:00
ArchiBot
c0a253213d Automatic translations update 2025-11-12 02:24:45 +00:00
Łukasz Domeradzki
67757178c1 Silence yet another warn 2025-11-11 22:42:07 +01:00
Łukasz Domeradzki
03350ce879 Misc 2025-11-11 22:22:06 +01:00
Łukasz Domeradzki
55bc802d59 Misc Rider improvements 2025-11-11 22:13:13 +01:00
Łukasz Domeradzki
a436c053a3 Bump 2025-11-11 20:30:15 +01:00
Łukasz Domeradzki
8547097e78 Closes #3508 2025-11-11 20:24:03 +01:00
Łukasz Domeradzki
a8d9844b01 JsonSerializerDefaults.Strict improvements 2025-11-11 19:50:44 +01:00
Łukasz Domeradzki
867b7270ec Further misc BGR improvements 2025-11-11 19:50:05 +01:00
Łukasz Domeradzki
970998fb4b Rewrite BGR to new OrderedDictionary<T,V> type 2025-11-11 19:27:10 +01:00
Łukasz Domeradzki
1ac4dfd6c8 Bump 2025-11-11 17:22:05 +01:00
Łukasz Domeradzki
ea2bec2f3e Big bump 2025-11-11 17:11:41 +01:00
Łukasz Domeradzki
ee0eef3761 Merge remote-tracking branch 'origin/renovate/mstest-monorepo' 2025-11-11 17:11:15 +01:00
renovate[bot]
fc7ac69fb1 chore(deps): update dotnet monorepo to 10.0.0 2025-11-11 15:38:40 +00:00
renovate[bot]
a32e7639ed chore(deps): update dependency mstest to 4.0.2 2025-11-11 15:38:37 +00:00
Łukasz Domeradzki
c8e8cd27b8 .NET 10 (#3482)
* Initial .NET 10 bump

* Use KnownIPNetworks

* .NET 10 library updates

* First round of trimming fixes

* Fix docker in .NET 10

* Resolve trimming warning

* Bump packages to rc2
2025-11-11 16:37:43 +01:00
renovate[bot]
245daec72e chore(deps): update dependency nlog.web.aspnetcore to 6.0.6 2025-11-09 21:55:39 +00:00
Łukasz Domeradzki
02d18aecf4 Bump 2025-11-09 22:55:23 +01:00
Łukasz Domeradzki
469dee4595 Bump 2025-11-09 22:55:08 +01:00
Łukasz Domeradzki
2e0df5c82b Change the bot when distributing, not keeping missing games and having invalid key 2025-11-09 22:53:47 +01:00
renovate[bot]
677a5503e2 chore(deps): update dependency scalar.aspnetcore to 2.10.3 2025-11-09 01:56:39 +00:00
renovate[bot]
566195129f chore(deps): update dependency anglesharp to 1.3.1 (#3507)
* chore(deps): update dependency anglesharp to 1.3.1

* Resolve new warnings

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Łukasz Domeradzki <JustArchi@JustArchi.net>
2025-11-08 23:46:36 +01:00
Łukasz Domeradzki
b872340c5d Add more debug logging 2025-11-06 21:02:11 +01:00
renovate[bot]
1c4fba6b2e chore(deps): update dependency humanizer to 3.0.0-rc.30 (#3505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 11:59:28 +00:00
renovate[bot]
2adb552618 chore(deps): update asf-ui digest to 184a7a2 2025-11-05 02:01:53 +00:00
renovate[bot]
59e27bc41d chore(deps): update dependency scalar.aspnetcore to 2.10.1 2025-11-04 22:40:01 +00:00
Vita Chumakova
5d1234e2d6 fix: add workaround for .NET 10 SDK breaking change (#3506) 2025-11-04 23:39:12 +01:00
ArchiBot
1f74f9c721 Automatic translations update 2025-11-04 02:23:52 +00:00
renovate[bot]
fb2dcb04ae chore(deps): update dependency scalar.aspnetcore to 2.10.0 2025-11-03 19:43:09 +00:00
ArchiBot
abdaa38389 Automatic translations update 2025-11-03 02:27:14 +00:00
ArchiBot
0830678526 Automatic translations update 2025-11-02 02:27:42 +00:00
renovate[bot]
cb827c7ab5 chore(deps): update wiki digest to 0b57c9c 2025-11-01 21:51:56 +00:00
renovate[bot]
e7ae287f38 chore(deps): update asf-ui digest to 5d50aca 2025-10-31 20:31:26 +00:00
ArchiBot
ffb5322ecb Automatic translations update 2025-10-30 02:24:56 +00:00
renovate[bot]
1ec78cf6a2 chore(deps): update asf-ui digest to 90434c7 2025-10-29 03:58:27 +00:00
ArchiBot
681bd7abcf Automatic translations update 2025-10-28 02:23:31 +00:00
renovate[bot]
1a906aac74 chore(deps): update asf-ui digest to 78842da 2025-10-27 21:37:33 +00:00
ArchiBot
57553fbbb3 Automatic translations update 2025-10-27 02:28:23 +00:00
Łukasz Domeradzki
738d949f1f Misc 2025-10-26 23:15:38 +01:00
Łukasz Domeradzki
b362408704 Bump 2025-10-26 11:28:36 +01:00
Łukasz Domeradzki
32238ba07c Closes #3483 2025-10-26 11:26:48 +01:00
renovate[bot]
2172f8b9eb chore(deps): update asf-ui digest to 3e71e0a 2025-10-24 20:24:29 +00:00
renovate[bot]
609b4914bd chore(deps): update github artifact actions (#3497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-24 22:23:44 +02:00
Łukasz Domeradzki
e23e507a68 Bump 2025-10-24 21:50:55 +02:00
renovate[bot]
f69ee6364d chore(deps): update asf-ui digest to a46fdc3 2025-10-24 04:45:55 +00:00
renovate[bot]
a468f9301d chore(deps): update opentelemetry-dotnet-contrib monorepo to 1.13.0 2025-10-22 11:11:05 +00:00
renovate[bot]
efa541d68d chore(deps): update dependency markdig.signed to 0.43.0 2025-10-21 11:34:18 +00:00
ArchiBot
068ad1b06a Automatic translations update 2025-10-21 02:23:27 +00:00
renovate[bot]
f3bec05e1f chore(deps): update asf-ui digest to c906498 2025-10-20 18:34:44 +00:00
renovate[bot]
a84dc1b01e chore(deps): update crowdin/github-action action to v2.12.0 2025-10-20 09:46:36 +00:00
renovate[bot]
ca4a3ee972 chore(deps): update dependency scalar.aspnetcore to 2.9.0 2025-10-15 13:53:30 +00:00
Łukasz Domeradzki
1c817426b8 Misc 2025-10-15 13:06:14 +02:00
Łukasz Domeradzki
5ec9bc14a9 Misc 2025-10-15 09:09:46 +02:00
renovate[bot]
67f451069a chore(deps): update dotnet monorepo to 9.0.10 2025-10-15 03:41:02 +00:00
ArchiBot
4eb73af250 Automatic translations update 2025-10-15 02:23:14 +00:00
renovate[bot]
ef60e23a53 chore(deps): update dependency mstest to 4.0.1 2025-10-14 20:09:53 +00:00
renovate[bot]
2b57d0a9e6 chore(deps): update asf-ui digest to 4386078 2025-10-14 14:05:08 +00:00
Łukasz Domeradzki
ae183ae3ad Slightly improve error-reporting related to cross-process semaphore 2025-10-14 13:01:34 +02:00
renovate[bot]
725a3a5106 chore(deps): update actions/setup-node action to v6 (#3494)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 12:30:12 +02:00
ArchiBot
289f573b00 Automatic translations update 2025-10-14 02:22:34 +00:00
renovate[bot]
a8a6e658e2 chore(deps): update wiki digest to da954cf 2025-10-13 21:56:40 +00:00
Łukasz Domeradzki
797bb6fc98 Bump 2025-10-11 17:00:21 +02:00
Łukasz Domeradzki
41f61503fb Misc 2025-10-11 16:59:06 +02:00
ArchiBot
764c979560 Automatic translations update 2025-10-11 02:20:05 +00:00
renovate[bot]
a0531ff1f3 chore(deps): update dependency opentelemetry.exporter.prometheus.aspnetcore to 1.13.1-beta.1 2025-10-10 10:40:31 +00:00
renovate[bot]
30d5a4cdc2 chore(deps): update dependency opentelemetry.extensions.hosting to 1.13.1 2025-10-09 20:56:31 +00:00
renovate[bot]
750ff1a09a chore(deps): update dependency nlog.web.aspnetcore to 6.0.5 2025-10-09 14:30:11 +00:00
renovate[bot]
c5cc247e2d chore(deps): update dependency humanizer to 3.0.0-rc.6 2025-10-09 11:32:16 +00:00
renovate[bot]
813bac5e52 chore(deps): update dependency scalar.aspnetcore to 2.8.11 2025-10-08 21:59:49 +00:00
renovate[bot]
267cf1597e chore(deps): update dependency mstest to v4 (#3493)
* chore(deps): update dependency mstest to v4

* Misc improvement

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Łukasz Domeradzki <JustArchi@JustArchi.net>
2025-10-07 22:12:51 +02:00
Łukasz Domeradzki
4716312c3f Handle super rare login failure 2025-10-07 21:35:01 +02:00
renovate[bot]
31b735c3d3 chore(deps): update dependency scalar.aspnetcore to 2.8.10 2025-10-03 01:33:33 +00:00
renovate[bot]
e9baae4d03 chore(deps): update opentelemetry-dotnet monorepo 2025-10-02 06:26:19 +00:00
ArchiBot
f97142200f Automatic translations update 2025-10-02 02:21:12 +00:00
renovate[bot]
34bc25b023 chore(deps): update dependency mstest to 3.11.0 2025-10-01 21:18:07 +00:00
renovate[bot]
ede24b9fd5 chore(deps): update peter-evans/dockerhub-description action to v5 (#3490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 23:17:07 +02:00
ArchiBot
c656b61ce2 Automatic translations update 2025-10-01 02:25:26 +00:00
renovate[bot]
3fb804fbd1 chore(deps): update dependency mstest to 3.10.5 2025-09-30 15:43:59 +00:00
ArchiBot
eb5f126c76 Automatic translations update 2025-09-30 02:21:04 +00:00
renovate[bot]
815d0732c3 chore(deps): update dependency scalar.aspnetcore to 2.8.8 2025-09-29 20:30:19 +00:00
renovate[bot]
a517cf216d chore(deps): update docker/login-action action to v3.6.0 2025-09-29 11:06:26 +00:00
ArchiBot
e5a6eede24 Automatic translations update 2025-09-29 02:22:48 +00:00
ArchiBot
7a3c28f3f6 Automatic translations update 2025-09-28 02:24:01 +00:00
Łukasz Domeradzki
49381cea84 Bump 2025-09-27 14:28:20 +02:00
renovate[bot]
9afa92a22d chore(deps): update dependency scalar.aspnetcore to 2.8.7 2025-09-26 18:39:59 +00:00
ArchiBot
6719903012 Automatic translations update 2025-09-26 02:21:47 +00:00
ArchiBot
2f0047e6c0 Automatic translations update 2025-09-25 02:23:09 +00:00
Łukasz Domeradzki
71a708b515 Misc 2025-09-24 23:22:16 +02:00
Łukasz Domeradzki
50b9011323 Add hashing unit test 2025-09-24 23:17:25 +02:00
renovate[bot]
e4bd4e2371 chore(deps): update wiki digest to 9a11b24 2025-09-24 13:30:51 +00:00
renovate[bot]
f662dc29ed chore(deps): update asf-ui digest to d3b89fc 2025-09-24 04:56:16 +00:00
renovate[bot]
e4ffd5c6ab chore(deps): update dependency scalar.aspnetcore to 2.8.6 2025-09-24 02:34:56 +00:00
ArchiBot
588bc9e691 Automatic translations update 2025-09-24 02:22:26 +00:00
renovate[bot]
3e98887954 chore(deps): update asf-ui digest to 812f732 2025-09-23 11:02:33 +00:00
renovate[bot]
78319f65eb chore(deps): update wiki digest to 4d6696e 2025-09-23 05:12:49 +00:00
Łukasz Domeradzki
c467fd39c1 Add donation section to README 2025-09-23 04:59:56 +02:00
renovate[bot]
896bd82f97 chore(deps): update asf-ui digest to f671af8 2025-09-20 08:24:51 +00:00
renovate[bot]
3a87d7536b chore(deps): update dependency scalar.aspnetcore to 2.8.5 2025-09-19 22:54:28 +00:00
Łukasz Domeradzki
1b245a568f Apply selected .NET 10 improvements 2025-09-19 23:19:24 +02:00
ArchiBot
95eb6b2c63 Automatic translations update 2025-09-19 02:22:16 +00:00
ArchiBot
616d5d2cdb Automatic translations update 2025-09-18 02:20:49 +00:00
renovate[bot]
9e1edc58ab chore(deps): update asf-ui digest to 65a5f0e 2025-09-16 17:57:48 +00:00
renovate[bot]
7df227b584 chore(deps): update dependency scalar.aspnetcore to 2.8.4 2025-09-16 14:30:09 +00:00
ArchiBot
be0f2ab537 Automatic translations update 2025-09-16 02:20:50 +00:00
ArchiBot
885c679033 Automatic translations update 2025-09-15 02:23:39 +00:00
renovate[bot]
0575e714ae chore(deps): update asf-ui digest to 6797c76 2025-09-14 21:07:28 +00:00
renovate[bot]
d1f3074c90 chore(deps): update dependency markdig.signed to 0.42.0 2025-09-14 13:58:14 +00:00
renovate[bot]
3f3a3b161b chore(deps): update dependency scalar.aspnetcore to 2.8.3 2025-09-14 09:42:27 +00:00
renovate[bot]
c5af29ddde chore(deps): update asf-ui digest to 3d70e36 2025-09-14 03:27:08 +00:00
ArchiBot
40dd6100ab Automatic translations update 2025-09-14 02:22:58 +00:00
ArchiBot
42cd1a85d9 Automatic translations update 2025-09-13 02:21:32 +00:00
ArchiBot
c196b46337 Automatic translations update 2025-09-12 02:20:35 +00:00
renovate[bot]
e5e133475b chore(deps): update dependency nlog.web.aspnetcore to 6.0.4 2025-09-11 09:30:41 +00:00
ArchiBot
67d191bbf3 Automatic translations update 2025-09-11 02:22:07 +00:00
renovate[bot]
c9502f8462 chore(deps): update dependency scalar.aspnetcore to 2.8.1 2025-09-10 21:33:08 +00:00
ArchiBot
3dbc3b1c5a Automatic translations update 2025-09-10 02:20:41 +00:00
renovate[bot]
c54928bb64 chore(deps): update dependency scalar.aspnetcore to 2.8.0 2025-09-09 22:34:05 +00:00
renovate[bot]
d40d7f0566 chore(deps): update dotnet monorepo to 9.0.9 2025-09-09 16:38:08 +00:00
renovate[bot]
b73ddab2e2 chore(deps): update dependency scalar.aspnetcore to 2.7.4 2025-09-09 14:34:49 +00:00
Łukasz Domeradzki
069523adcd Misc 2025-09-09 15:37:36 +02:00
renovate[bot]
fc310ee24c chore(deps): update dependency scalar.aspnetcore to 2.7.3 2025-09-09 03:27:57 +00:00
ArchiBot
b53d9a0f6f Automatic translations update 2025-09-09 02:22:25 +00:00
Łukasz Domeradzki
035ff7dfe7 Bump 2025-09-08 23:42:26 +02:00
Łukasz Domeradzki
2bbf197108 Add extra synchronization to IPC state management
Thanks @ezhevita
2025-09-08 23:39:29 +02:00
Łukasz Domeradzki
5d2665207a Handle one more case of Steam being down
Thanks @ezhevita
2025-09-08 23:30:11 +02:00
Łukasz Domeradzki
8618b01800 Fix for edge case of MatchableTypes being empty
Thanks @ezhevita
2025-09-08 23:17:23 +02:00
Łukasz Domeradzki
d59d51ae33 Bump 2025-09-08 22:51:03 +02:00
Łukasz Domeradzki
a313a19cec Add support for machine name 2025-09-08 22:50:23 +02:00
Łukasz Domeradzki
c5f7565ac0 Misc 2025-09-08 03:42:12 +02:00
Łukasz Domeradzki
f52486528b Cache generated swagger.json by default 2025-09-08 03:29:17 +02:00
Łukasz Domeradzki
d17399d98b Misc 2025-09-08 02:42:33 +02:00
Łukasz Domeradzki
1eadaad9bd Fix rp command not working with badge upgrades
Of course volvo had to use different endpoint for that, it'd be too easy otherwise
2025-09-08 02:41:31 +02:00
ArchiBot
22e424a78c Automatic translations update 2025-09-07 02:22:59 +00:00
renovate[bot]
712b57e46b chore(deps): update asf-ui digest to 96606b8 2025-09-06 08:37:05 +00:00
renovate[bot]
bc914f0a09 chore(deps): update asf-ui digest to 64ee49e 2025-09-05 21:29:58 +00:00
renovate[bot]
1da2ccbb1c chore(deps): update asf-ui digest to 4e72d57 2025-09-05 03:11:25 +00:00
Łukasz Domeradzki
c58d802c30 Enable immutable releases 2025-09-05 00:43:05 +02:00
Łukasz Domeradzki
8cdd5c69e6 Remove workaround after JB fixes 2025-09-04 23:55:41 +02:00
renovate[bot]
2b61e80336 chore(deps): update ncipollo/release-action action to v1.20.0 2025-09-04 20:24:07 +00:00
renovate[bot]
d831c47fcd chore(deps): update crowdin/github-action action to v2.11.0 2025-09-04 17:11:33 +00:00
renovate[bot]
53955cb9d2 chore(deps): update dependency mstest to 3.10.4 2025-09-04 15:59:08 +00:00
renovate[bot]
2d9c68c10a chore(deps): update dependency jetbrains.annotations.sources to 2025.2.2 2025-09-04 15:15:48 +00:00
renovate[bot]
c987db7941 chore(deps): update asf-ui digest to 62ed8b8 2025-09-04 12:33:08 +00:00
Łukasz Domeradzki
b1d4eb5c8c Cleanup obsolete parts (#3471) 2025-09-04 14:32:34 +02:00
renovate[bot]
c929efbf24 chore(deps): update actions/setup-node action to v5 (#3478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-04 14:32:13 +02:00
renovate[bot]
0c3f379fb3 chore(deps): update actions/setup-dotnet action to v5 (#3477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-04 14:32:03 +02:00
Łukasz Domeradzki
2d79ae9e7a Bump 2025-09-04 13:46:33 +02:00
ArchiBot
d0ac9b3a94 Automatic translations update 2025-09-04 02:20:39 +00:00
ArchiBot
719824b518 Automatic translations update 2025-09-01 02:32:04 +00:00
ArchiBot
f6f290878a Automatic translations update 2025-08-31 02:23:59 +00:00
renovate[bot]
4ee9bfc450 chore(deps): update actions/attest-build-provenance action to v3 (#3476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-29 10:38:20 +02:00
Łukasz Domeradzki
d3f45fc33d JetBrains.Annotations.Sources updates 2025-08-29 09:22:54 +02:00
renovate[bot]
ee4cefc813 chore(deps): update dependency mstest to 3.10.3 (#3475)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-27 09:42:40 +02:00
renovate[bot]
4b7f570ba5 chore(deps): update asf-ui digest to 25f5d5e 2025-08-26 06:11:27 +00:00
renovate[bot]
6981018003 chore(deps): update dependency scalar.aspnetcore to 2.7.2 2025-08-26 00:53:57 +00:00
ArchiBot
380f27a0bc Automatic translations update 2025-08-25 02:26:46 +00:00
Łukasz Domeradzki
d489bebb85 Misc 2025-08-24 19:09:03 +02:00
Łukasz Domeradzki
2df1c439c4 Misc optimization 2025-08-24 15:04:20 +02:00
renovate[bot]
83ac485f19 chore(deps): update asf-ui digest to 75a61d2 2025-08-24 06:15:00 +00:00
ArchiBot
1c6bf2e828 Automatic translations update 2025-08-24 02:30:35 +00:00
renovate[bot]
bfdab76d71 chore(deps): update crowdin/github-action action to v2.10.0 (#3472)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-23 08:42:03 +00:00
ArchiBot
90dba00c07 Automatic translations update 2025-08-23 02:22:51 +00:00
renovate[bot]
1d38521819 chore(deps): update dependency scalar.aspnetcore to 2.7.0 2025-08-22 22:57:31 +00:00
ArchiBot
bc8b56018d Automatic translations update 2025-08-22 02:24:26 +00:00
renovate[bot]
073b22de40 chore(deps): update wiki digest to 44fb363 2025-08-21 19:39:18 +00:00
Łukasz Domeradzki
8bc8efe6c0 Bump 2025-08-21 13:06:33 +02:00
Łukasz Domeradzki
fe80d3029b Add support for GamingDeviceType, kill OnlinePreferences 2025-08-21 13:01:38 +02:00
ArchiBot
86410d4407 Automatic translations update 2025-08-20 02:23:58 +00:00
ArchiBot
aba19cf986 Automatic translations update 2025-08-19 02:25:24 +00:00
renovate[bot]
0a2ca64bf7 chore(deps): update wiki digest to 396caad 2025-08-18 11:30:00 +00:00
ArchiBot
4761393e88 Automatic translations update 2025-08-18 02:35:59 +00:00
renovate[bot]
298026491a chore(deps): update wiki digest to ee43c97 2025-08-17 16:49:10 +00:00
ArchiBot
2fe2c47289 Automatic translations update 2025-08-17 02:34:57 +00:00
Łukasz Domeradzki
2d968c6c14 Don't generate or publish xml documentation files by default 2025-08-16 14:05:06 +02:00
renovate[bot]
0708a4a1e2 chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.14.0 2025-08-16 02:28:43 +00:00
renovate[bot]
d2c234db1f chore(deps): update asf-ui digest to 41d408b 2025-08-15 06:29:07 +00:00
ArchiBot
d2b7ffba3b Automatic translations update 2025-08-15 02:31:09 +00:00
Łukasz Domeradzki
ff2a2a728d Use new C# features for serializable files 2025-08-13 22:15:41 +02:00
ArchiBot
2b43cec8fe Automatic translations update 2025-08-13 02:29:47 +00:00
renovate[bot]
6359014017 chore(deps): update asf-ui digest to 63dc959 2025-08-12 19:12:15 +00:00
renovate[bot]
d305c3d6e5 chore(deps): update dependency mstest to 3.10.2 2025-08-12 09:38:54 +00:00
renovate[bot]
9b5c5f39a4 chore(deps): update asf-ui digest to f3053c2 2025-08-11 20:40:55 +00:00
renovate[bot]
627f88508a chore(deps): update dependency scalar.aspnetcore to 2.6.9 2025-08-11 19:49:36 +00:00
renovate[bot]
6e6f2c5675 chore(deps): update actions/checkout action to v5 (#3465)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 21:49:11 +02:00
renovate[bot]
7d5aaed8fb chore(deps): update actions/checkout action to v4.3.0 2025-08-11 13:07:56 +00:00
renovate[bot]
eac98c4846 chore(deps): update dependency nlog.web.aspnetcore to 6.0.3 2025-08-10 20:55:16 +00:00
Łukasz Domeradzki
f048513338 Misc optimization 2025-08-10 22:02:00 +02:00
Łukasz Domeradzki
4780031b87 Misc 2025-08-10 03:05:24 +02:00
Łukasz Domeradzki
f54d30ff42 Misc 2025-08-10 02:38:37 +02:00
renovate[bot]
17e97afb97 chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.13.1 2025-08-09 04:27:32 +00:00
Łukasz Domeradzki
d79db74385 Clean unused code
It seems this call is pointless, if trade check timer is not null, it's already running, as we never initialize it without enabling it too.
2025-08-09 03:22:48 +02:00
Łukasz Domeradzki
c412a47139 Optimize memory allocations when dealing with Steam items
This removes totally unnecessary allocation of asset and description when we already have it in the response and merely initializing to correct reference.
2025-08-08 23:10:35 +02:00
Łukasz Domeradzki
2387f2462e Update ArchiSteamFarm.sln.DotSettings 2025-08-08 20:51:09 +02:00
Łukasz Domeradzki
6bd2e088fc Misc 2025-08-08 19:37:57 +02:00
Łukasz Domeradzki
b4874a05c6 Code cleanups 2025-08-08 19:32:32 +02:00
Łukasz Domeradzki
a77586ec95 Misc 2025-08-08 17:49:04 +02:00
Łukasz Domeradzki
ed9efe8d72 Misc 2025-08-08 01:05:46 +02:00
Łukasz Domeradzki
f7431b0b10 Bump 2025-08-08 01:04:34 +02:00
Łukasz Domeradzki
a340de9da8 Top commit of all time
This is how you avoid doing breaking changes, kids
2025-08-08 01:02:50 +02:00
renovate[bot]
bf11cf8a7b chore(deps): update asf-ui digest to 5c8cf52 2025-08-06 07:20:38 +00:00
renovate[bot]
b4dc8b493a chore(deps): update actions/download-artifact action to v5 (#3462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 09:19:41 +02:00
renovate[bot]
ce1cf6f4b1 chore(deps): update dependency mstest to 3.10.1 2025-08-05 20:32:28 +00:00
renovate[bot]
8d6422e8b4 chore(deps): update dotnet monorepo to 9.0.8 2025-08-05 01:55:47 +00:00
renovate[bot]
b3c28266cb chore(deps): update docker/login-action action to v3.5.0 2025-08-04 15:28:12 +00:00
Łukasz Domeradzki
074f2e343f Misc optimization 2025-08-03 22:49:50 +02:00
renovate[bot]
8f6f7334a0 chore(deps): update dependency scalar.aspnetcore to 2.6.8 2025-08-03 17:30:21 +00:00
Łukasz Domeradzki
b467c22baa Misc 2025-08-03 15:19:49 +02:00
Łukasz Domeradzki
15d3dd8c74 Bump 2025-08-03 15:12:37 +02:00
Łukasz Domeradzki
2010f3e455 Bump 2025-08-03 15:12:19 +02:00
Łukasz Domeradzki
cc95917d53 Misc cleanups 2025-08-03 15:12:05 +02:00
Łukasz Domeradzki
f918fbb504 Make /Api/NLog/File more flexible in terms of log file location 2025-08-03 15:05:02 +02:00
Łukasz Domeradzki
6d4d644900 Add support for detecting history target in wrapper 2025-08-03 14:24:10 +02:00
ArchiBot
a046af7b8d Automatic translations update 2025-08-03 02:43:27 +00:00
renovate[bot]
bde00df3ad chore(deps): update dependency scalar.aspnetcore to 2.6.7 2025-08-02 19:00:59 +00:00
renovate[bot]
d1080bbb42 chore(deps): update dependency scalar.aspnetcore to 2.6.6 2025-08-02 11:15:01 +00:00
renovate[bot]
875d9be7e5 chore(deps): update asf-ui digest to f6e8455 2025-08-02 04:51:40 +00:00
ArchiBot
e683b3b9ad Automatic translations update 2025-08-02 02:33:10 +00:00
renovate[bot]
199e098704 chore(deps): update asf-ui digest to 73d10a1 2025-08-01 22:26:42 +00:00
renovate[bot]
b4cdfa3011 chore(deps): update crowdin/github-action action to v2.9.1 2025-08-01 10:07:26 +00:00
ArchiBot
92bfeb96e2 Automatic translations update 2025-08-01 02:44:48 +00:00
ArchiBot
f4c9c9de1a Automatic translations update 2025-07-31 02:37:08 +00:00
renovate[bot]
e60293a0ce chore(deps): update dependency scalar.aspnetcore to 2.6.5 2025-07-30 01:14:46 +00:00
renovate[bot]
5659818313 chore(deps): update dependency mstest to 3.10.0 (#3458)
* chore(deps): update dependency mstest to 3.10.0

* Adapt to new analyzers

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Łukasz Domeradzki <JustArchi@JustArchi.net>
2025-07-30 03:14:13 +02:00
renovate[bot]
1de5bfd809 chore(deps): update asf-ui digest to 11faf95 2025-07-29 04:46:21 +00:00
Łukasz Domeradzki
0fa3b25f12 Bump 2025-07-28 12:21:55 +02:00
Łukasz Domeradzki
02f505d962 Change null purchase_receipt_info to BadResponse 2025-07-28 12:17:10 +02:00
Łukasz Domeradzki
abdb303069 Fix for edge case that is more edge than nowadays teenagers 2025-07-28 12:03:45 +02:00
Łukasz Domeradzki
c1e5cd5d59 Add fix against null purchase_receipt_info 2025-07-28 11:57:04 +02:00
renovate[bot]
7ea0dda562 chore(deps): update asf-ui digest to cd42a02 2025-07-26 02:52:18 +00:00
ArchiBot
947e63fc61 Automatic translations update 2025-07-26 02:32:34 +00:00
Łukasz Domeradzki
882e561416 Bump 2025-07-25 13:49:41 +02:00
Łukasz Domeradzki
1e531a7259 Misc reorder 2025-07-25 13:49:12 +02:00
Outzzz
2967ae167b public api (#3456) 2025-07-25 13:47:57 +02:00
ArchiBot
089840438d Automatic translations update 2025-07-25 02:35:53 +00:00
renovate[bot]
bcd9ae047e chore(deps): update dependency opentelemetry.exporter.prometheus.aspnetcore to 1.12.0-beta.1 2025-07-24 15:55:39 +00:00
renovate[bot]
20de66a3be chore(deps): update wiki digest to ecb0e1f 2025-07-24 15:07:18 +00:00
renovate[bot]
7587f5f07a chore(deps): update dependency microsoft.codeanalysis.resxsourcegenerator to v5 (#3454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-24 17:06:40 +02:00
Łukasz Domeradzki
4ad450f0ba Update renovate.json5 2025-07-24 15:22:14 +02:00
Łukasz Domeradzki
2883f42a19 Update renovate.json5
As per https://github.com/renovatebot/renovate/discussions/37142
2025-07-24 15:17:13 +02:00
Łukasz Domeradzki
d788efbaf6 Workaround Jetbrains.Annotations issues 2025-07-24 15:06:58 +02:00
Łukasz Domeradzki
ca0bd87357 Move from JetBrains.Annotations to JetBrains.Annotations.Sources 2025-07-24 14:05:07 +02:00
renovate[bot]
e246d0dfa0 chore(deps): update asf-ui digest to 9869857 2025-07-24 08:46:15 +00:00
renovate[bot]
f93c319427 chore(deps): update asf-ui digest to d9173d5 2025-07-23 23:04:20 +00:00
renovate[bot]
eb591e3b4a chore(deps): update dependency jetbrains.annotations to v2025 (#3448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-23 00:44:38 +02:00
renovate[bot]
37d7f14148 chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.13.0 2025-07-21 23:36:17 +00:00
renovate[bot]
86b1814698 chore(deps): update dependency scalar.aspnetcore to 2.6.4 2025-07-21 13:35:49 +00:00
renovate[bot]
d15fae3674 chore(deps): update dependency nlog.web.aspnetcore to 6.0.2 2025-07-20 17:40:12 +00:00
Łukasz Domeradzki
6d3a6168d2 Bump 2025-07-19 14:41:57 +02:00
Łukasz Domeradzki
0467dc1da3 Make trade message disappear for all non-steam appids 2025-07-19 14:36:03 +02:00
Łukasz Domeradzki
d81e8d2de0 Bump 2025-07-19 13:22:05 +02:00
Łukasz Domeradzki
ec59e2e556 Add support for new trade messages acknowledge 2025-07-18 09:52:31 +02:00
ArchiBot
cfdb8c06f3 Automatic translations update 2025-07-18 02:35:51 +00:00
Łukasz Domeradzki
32bf5cd0a7 Bump 2025-07-17 13:45:20 +02:00
Łukasz Domeradzki
a0401a3962 Improve efficiency of MatchActively
Trade hold duration check made sense, but back when we were fetching inventories ourselves. Now, it's much better to find match first, as we have the full data loaded, and only if match is found, check user next.
2025-07-17 13:40:35 +02:00
renovate[bot]
4def44ed1e chore(deps): update dependency scalar.aspnetcore to 2.6.3 2025-07-17 03:52:21 +00:00
ArchiBot
bd472b68a1 Automatic translations update 2025-07-17 02:34:52 +00:00
renovate[bot]
142bac7275 chore(deps): update asf-ui digest to 1d94b49 2025-07-16 04:44:45 +00:00
ArchiBot
80d4ab1dea Automatic translations update 2025-07-16 02:34:20 +00:00
Outzzz
481c995481 new confirmation type (#3442) 2025-07-15 18:56:19 +02:00
ArchiBot
76e3059b34 Automatic translations update 2025-07-14 02:36:38 +00:00
renovate[bot]
9c6157563e chore(deps): update dependency scalar.aspnetcore to 2.6.1 2025-07-13 18:02:53 +00:00
renovate[bot]
c362900290 chore(deps): update asf-ui digest to 0822736 2025-07-12 03:10:35 +00:00
ArchiBot
1573707d39 Automatic translations update 2025-07-12 02:33:47 +00:00
ArchiBot
acce592f02 Automatic translations update 2025-07-11 02:34:06 +00:00
renovate[bot]
24cc03e4ed chore(deps): update asf-ui digest to 75cb11d 2025-07-10 22:00:47 +00:00
renovate[bot]
aec1f45023 chore(deps): update dependency scalar.aspnetcore to 2.6.0 2025-07-10 18:01:49 +00:00
renovate[bot]
e208a3cce0 chore(deps): update crowdin/github-action action to v2.9.0 2025-07-10 11:33:24 +00:00
ArchiBot
2f275e19bd Automatic translations update 2025-07-10 02:32:36 +00:00
renovate[bot]
ac8f12f438 chore(deps): update asf-ui digest to 7a782d7 2025-07-09 23:58:29 +00:00
renovate[bot]
c14580965f chore(deps): update wiki digest to c122ded 2025-07-09 17:02:47 +00:00
renovate[bot]
436a5ab3f9 chore(deps): update dotnet monorepo to 9.0.7 2025-07-09 04:24:15 +00:00
ArchiBot
3e1fde4515 Automatic translations update 2025-07-09 02:31:52 +00:00
renovate[bot]
9beec69e85 chore(deps): update asf-ui digest to 5c24f54 2025-07-08 05:00:15 +00:00
ArchiBot
a1116a87df Automatic translations update 2025-07-08 02:31:32 +00:00
renovate[bot]
cd4bc01d66 chore(deps): update dependency scalar.aspnetcore to 2.5.6 2025-07-07 20:07:16 +00:00
renovate[bot]
7e30601246 chore(deps): update wiki digest to 70b21c1 2025-07-07 13:06:35 +00:00
ArchiBot
708b3792c9 Automatic translations update 2025-07-07 02:34:03 +00:00
renovate[bot]
3c52408579 chore(deps): update wiki digest to f30f4d5 2025-07-06 12:35:34 +00:00
ArchiBot
ea5f729d58 Automatic translations update 2025-07-06 02:36:06 +00:00
renovate[bot]
4d3f7f0b5a chore(deps): update wiki digest to 522bba8 2025-07-05 14:26:30 +00:00
Łukasz Domeradzki
078f6eabdd Bump 2025-07-05 16:25:46 +02:00
Łukasz Domeradzki
6d6da98e8c Bump 2025-07-05 16:05:31 +02:00
renovate[bot]
49f1910425 chore(deps): update dependency nlog.web.aspnetcore to 6.0.1 2025-07-05 13:40:07 +00:00
renovate[bot]
4ba034f988 chore(deps): update dependency nlog.web.aspnetcore to v6 (#3438)
* chore(deps): update dependency nlog.web.aspnetcore to v6

* Adapt ASF to NLog v6

* Use another approach for NLog file archiving

* Use cached ${currentdir} to improve performance

* Misc fix

* Update suffix format

* Misc

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Łukasz Domeradzki <JustArchi@JustArchi.net>
2025-07-05 15:39:37 +02:00
ArchiBot
e93ea74def Automatic translations update 2025-07-05 02:26:37 +00:00
Łukasz Domeradzki
5dadbe9090 Allow plugins to initialize new configs with some changed properties 2025-07-03 13:12:10 +02:00
renovate[bot]
e3c1a8c5fb chore(deps): update asf-ui digest to 545f9e1 2025-07-02 23:39:29 +00:00
Łukasz Domeradzki
8e50e9553a Misc fix 2025-07-02 16:55:09 +02:00
Łukasz Domeradzki
ed47c8268b Add optional cookies to WebAPI base 2025-07-02 08:57:44 +02:00
Łukasz Domeradzki
e0cdeaf09e Bump 2025-07-01 16:14:16 +02:00
Łukasz Domeradzki
fc198d6eae Update MaxItemsInSingleInventoryRequest 2025-07-01 16:13:47 +02:00
ArchiBot
977816baa9 Automatic translations update 2025-07-01 02:37:39 +00:00
renovate[bot]
758c0a0385 chore(deps): update asf-ui digest to b984a9d 2025-06-30 07:31:35 +00:00
ArchiBot
e4d7e9dda7 Automatic translations update 2025-06-30 02:33:41 +00:00
renovate[bot]
baadfee9e0 chore(deps): update ncipollo/release-action action to v1.18.0 2025-06-29 21:11:10 +00:00
renovate[bot]
25620603b5 chore(deps): update ncipollo/release-action action to v1.17.0 2025-06-29 06:24:51 +00:00
ArchiBot
a5e306ccae Automatic translations update 2025-06-29 02:36:53 +00:00
Łukasz Domeradzki
e09801442e Bump 2025-06-28 13:11:58 +02:00
Łukasz Domeradzki
08fb3ccb76 Fix serializable files not always getting written on change
In some cases, STJ might decide to replace the object rather than populating it. This will work for majority of properties and use cases, however, we actually set up events on some properties to notify us back if they change during runtime. That event registration did not work properly, as the object was replaced with the new, that did not have appropriate listeners set up.

Populate rather than replacing those selected properties, which fixes the problem.
2025-06-28 13:10:13 +02:00
ArchiBot
e9887cf89e Automatic translations update 2025-06-28 02:26:50 +00:00
renovate[bot]
de33bd057f chore(deps): update asf-ui digest to 49b98a8 2025-06-27 04:14:17 +00:00
ArchiBot
e04d37a694 Automatic translations update 2025-06-27 02:29:29 +00:00
renovate[bot]
6e7a1ea09b chore(deps): update dependency scalar.aspnetcore to 2.5.3 2025-06-26 16:37:37 +00:00
Łukasz Domeradzki
08b2c3186d Misc 2025-06-26 14:23:12 +02:00
renovate[bot]
6ca3989635 chore(deps): update dependency scalar.aspnetcore to 2.5.1 2025-06-26 02:58:11 +00:00
ArchiBot
c3019bed16 Automatic translations update 2025-06-26 02:29:26 +00:00
renovate[bot]
7f5615d109 chore(deps): update asf-ui digest to 220a8ec 2025-06-25 18:05:14 +00:00
renovate[bot]
43c76dc1af chore(deps): update crowdin/github-action action to v2.8.0 2025-06-25 07:11:07 +00:00
renovate[bot]
89deff7e06 chore(deps): update dependency markdig.signed to 0.41.3 2025-06-24 11:03:02 +00:00
ArchiBot
d536f7f56c Automatic translations update 2025-06-24 02:29:43 +00:00
renovate[bot]
8f43575a19 chore(deps): pin dependencies (#3439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-22 17:46:37 +02:00
Łukasz Domeradzki
53adc67be1 Misc 2025-06-22 17:46:18 +02:00
Łukasz Domeradzki
e4addcadc8 Update renovate.json5 2025-06-22 16:23:21 +02:00
Łukasz Domeradzki
c48c1e6acd Kill build environment
It causes only unnecessary spam in PRs, the other environments still make sense
2025-06-22 15:47:17 +02:00
ArchiBot
cd2baa25c8 Automatic translations update 2025-06-22 02:35:38 +00:00
renovate[bot]
93e19d0f82 chore(deps): update dependency scalar.aspnetcore to 2.5.0 2025-06-21 17:53:08 +00:00
renovate[bot]
a8527dee70 chore(deps): update asf-ui digest to 622b78e 2025-06-21 10:10:38 +00:00
ArchiBot
b209be1618 Automatic translations update 2025-06-21 02:26:29 +00:00
renovate[bot]
fa55d9f402 chore(deps): update wiki digest to fb78823 2025-06-20 19:56:55 +00:00
renovate[bot]
c1aeb0b0a1 chore(deps): update dependency scalar.aspnetcore to 2.4.22 2025-06-19 22:56:09 +00:00
Łukasz Domeradzki
6e2bd99600 Bump 2025-06-20 00:55:39 +02:00
136 changed files with 2801 additions and 1440 deletions

View File

@@ -1,7 +1,8 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
"config:best-practices",
":assignee(JustArchi)",
":automergeBranch",
":automergeDigest",
@@ -10,7 +11,17 @@
":disableRateLimiting",
":label(🤖 Automatic)"
],
"git-submodules": {
"enabled": true
}
},
"packageRules": [
{
// TODO: Allow updates of selected packages with no stable release (yet) to latest versions
"matchManagers": [ "nuget" ],
"matchPackageNames": [ "Microsoft.CodeAnalysis.ResxSourceGenerator", "OpenTelemetry.Exporter.Prometheus.AspNetCore" ],
"ignoreUnstable": false
}
]
}

View File

@@ -5,7 +5,7 @@ on: [push, pull_request]
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 9.0
DOTNET_SDK_VERSION: 10.0
permissions: {}
@@ -15,19 +15,19 @@ jobs:
fail-fast: false
matrix:
configuration: [Debug, Release]
os: [macos-latest, ubuntu-latest, windows-latest]
os: [macos-latest, macos-15-intel, ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}

View File

@@ -14,13 +14,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Upload latest strings for translation on Crowdin
uses: crowdin/github-action@v2.7.1
uses: crowdin/github-action@60debf382ee245b21794321190ad0501db89d8c1 # v2.13.0
with:
crowdin_branch_name: main
config: '.github/crowdin.yml'

View File

@@ -19,16 +19,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
uses: docker/build-push-action@v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
build-args: CONFIGURATION=${{ matrix.configuration }}
context: .

View File

@@ -18,23 +18,23 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Login to ghcr.io
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -50,7 +50,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile.Service
uses: docker/build-push-action@v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: Dockerfile.Service

View File

@@ -19,23 +19,23 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Login to ghcr.io
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -50,7 +50,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
platforms: ${{ env.PLATFORMS }}
@@ -69,7 +69,7 @@ jobs:
push: true
- name: Update DockerHub repository description
uses: peter-evans/dockerhub-description@v4.0.2
uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

@@ -19,23 +19,23 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Login to ghcr.io
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -51,7 +51,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Lock inactive threads
uses: dessant/lock-threads@v5.0.1
uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
with:
discussion-inactive-days: 90
issue-inactive-days: 60

View File

@@ -6,7 +6,7 @@ env:
CONFIGURATION: Release
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 9.0
DOTNET_SDK_VERSION: 10.0
NODE_JS_VERSION: 'lts/*'
PLUGINS_BUNDLED: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
PLUGINS_INCLUDED: ArchiSteamFarm.OfficialPlugins.Monitoring # Apart from declaring them here, there is certain amount of hardcoding needed below for uploading
@@ -19,13 +19,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
- name: Setup Node.js with npm
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
check-latest: true
node-version: ${{ env.NODE_JS_VERSION }}
@@ -43,8 +43,9 @@ jobs:
run: npm run-script deploy --no-progress --prefix ASF-ui
- name: Upload ASF-ui
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
compression-level: 1
if-no-files-found: error
name: ASF-ui
path: ASF-ui/dist
@@ -73,7 +74,6 @@ jobs:
- os: windows-latest
variant: win-x64
environment: build
runs-on: ${{ matrix.os }}
permissions:
@@ -82,12 +82,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
@@ -95,7 +95,7 @@ jobs:
run: dotnet --info
- name: Download previously built ASF-ui
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ASF-ui
path: ASF-ui/dist
@@ -362,13 +362,14 @@ jobs:
- name: Generate artifact attestation for ASF-${{ matrix.variant }}.zip
if: ${{ github.event_name == 'push' }}
uses: actions/attest-build-provenance@v2.4.0
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: out/ASF-${{ matrix.variant }}.zip
- name: Upload ASF-${{ matrix.variant }}
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
compression-level: 1
if-no-files-found: error
name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
path: out/ASF-${{ matrix.variant }}.zip
@@ -409,14 +410,15 @@ jobs:
- name: Generate artifact attestation for ArchiSteamFarm.OfficialPlugins.Monitoring
if: ${{ github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
uses: actions/attest-build-provenance@v2.4.0
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: out/ArchiSteamFarm.OfficialPlugins.Monitoring.zip
- name: Upload ArchiSteamFarm.OfficialPlugins.Monitoring
if: ${{ matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
compression-level: 1
if-no-files-found: error
name: ArchiSteamFarm.OfficialPlugins.Monitoring
path: out/ArchiSteamFarm.OfficialPlugins.Monitoring.zip
@@ -434,66 +436,66 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
- name: Download ASF-generic artifact from ubuntu-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ubuntu-latest_ASF-generic
path: out
- name: Download ASF-linux-arm artifact from ubuntu-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ubuntu-latest_ASF-linux-arm
path: out
- name: Download ASF-linux-arm64 artifact from ubuntu-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ubuntu-latest_ASF-linux-arm64
path: out
- name: Download ASF-linux-x64 artifact from ubuntu-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ubuntu-latest_ASF-linux-x64
path: out
- name: Download ASF-osx-arm64 artifact from macos-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: macos-latest_ASF-osx-arm64
path: out
- name: Download ASF-osx-x64 artifact from macos-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: macos-latest_ASF-osx-x64
path: out
- name: Download ASF-win-arm64 artifact from windows-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: windows-latest_ASF-win-arm64
path: out
- name: Download ASF-win-x64 artifact from windows-latest
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: windows-latest_ASF-win-x64
path: out
- name: Download ArchiSteamFarm.OfficialPlugins.Monitoring artifact
uses: actions/download-artifact@v4.3.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: ArchiSteamFarm.OfficialPlugins.Monitoring
path: out
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v6.3.0
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
@@ -507,36 +509,39 @@ jobs:
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
- name: Generate artifact attestation for SHA512SUMS
uses: actions/attest-build-provenance@v2.4.0
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: out/SHA512SUMS
- name: Upload SHA512SUMS
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
compression-level: 1
if-no-files-found: error
name: SHA512SUMS
path: out/SHA512SUMS
- name: Generate artifact attestation for SHA512SUMS.sign
uses: actions/attest-build-provenance@v2.4.0
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: out/SHA512SUMS.sign
- name: Upload SHA512SUMS.sign
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
compression-level: 1
if-no-files-found: error
name: SHA512SUMS.sign
path: out/SHA512SUMS.sign
- name: Create ArchiSteamFarm GitHub release
uses: ncipollo/release-action@v1.16.0
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
with:
allowUpdates: true
artifactErrorsFailBuild: true
artifacts: "out/*"
bodyFile: .github/RELEASE_TEMPLATE.md
immutableCreate: true
makeLatest: false
name: ArchiSteamFarm V${{ github.ref_name }}
prerelease: true

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
show-progress: false
submodules: recursive
@@ -31,7 +31,7 @@ jobs:
git reset --hard origin/master
- name: Download latest translations from Crowdin
uses: crowdin/github-action@v2.7.1
uses: crowdin/github-action@60debf382ee245b21794321190ad0501db89d8c1 # v2.13.0
with:
upload_sources: false
download_translations: true
@@ -43,7 +43,7 @@ jobs:
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v6.3.0
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
git_config_global: true

2
ASF-ui

Submodule ASF-ui updated: 6a9af774d8...c703223091

View File

@@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>

View File

@@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>

View File

@@ -5,7 +5,8 @@
<ItemGroup>
<PackageReference Include="AngleSharp" IncludeAssets="compile" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>

View File

@@ -4,11 +4,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
<PackageReference Include="System.Linq.Async" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>

View File

@@ -38,56 +38,54 @@ namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal sealed class BotCache : SerializableFile {
[JsonDisallowNull]
[JsonInclude]
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
internal ConcurrentList<AssetForListing> LastAnnouncedAssetsForListing { get; private init; } = [];
[JsonInclude]
[JsonPropertyName("BackingLastAnnouncedTradeToken")]
internal string? LastAnnouncedTradeToken {
get => BackingLastAnnouncedTradeToken;
get;
set {
if (BackingLastAnnouncedTradeToken == value) {
if (field == value) {
return;
}
BackingLastAnnouncedTradeToken = value;
field = value;
Utilities.InBackground(Save);
}
}
[JsonInclude]
[JsonPropertyName("BackingLastInventoryChecksumBeforeDeduplication")]
internal string? LastInventoryChecksumBeforeDeduplication {
get => BackingLastInventoryChecksumBeforeDeduplication;
get;
set {
if (BackingLastInventoryChecksumBeforeDeduplication == value) {
if (field == value) {
return;
}
BackingLastInventoryChecksumBeforeDeduplication = value;
field = value;
Utilities.InBackground(Save);
}
}
[JsonInclude]
[JsonPropertyName("BackingLastRequestAt")]
internal DateTime? LastRequestAt {
get => BackingLastRequestAt;
get;
set {
if (BackingLastRequestAt == value) {
if (field == value) {
return;
}
BackingLastRequestAt = value;
field = value;
Utilities.InBackground(Save);
}
}
[JsonInclude]
private string? BackingLastAnnouncedTradeToken { get; set; }
[JsonInclude]
private string? BackingLastInventoryChecksumBeforeDeduplication { get; set; }
[JsonInclude]
private DateTime? BackingLastRequestAt { get; set; }
private BotCache(string filePath) : this() {
ArgumentException.ThrowIfNullOrEmpty(filePath);
@@ -97,18 +95,18 @@ internal sealed class BotCache : SerializableFile {
[JsonConstructor]
private BotCache() => LastAnnouncedAssetsForListing.OnModified += OnObjectModified;
[UsedImplicitly]
public bool ShouldSerializeBackingLastAnnouncedTradeToken() => !string.IsNullOrEmpty(BackingLastAnnouncedTradeToken);
[UsedImplicitly]
public bool ShouldSerializeBackingLastInventoryChecksumBeforeDeduplication() => !string.IsNullOrEmpty(BackingLastInventoryChecksumBeforeDeduplication);
[UsedImplicitly]
public bool ShouldSerializeBackingLastRequestAt() => BackingLastRequestAt.HasValue;
[UsedImplicitly]
public bool ShouldSerializeLastAnnouncedAssetsForListing() => LastAnnouncedAssetsForListing.Count > 0;
[UsedImplicitly]
public bool ShouldSerializeLastAnnouncedTradeToken() => !string.IsNullOrEmpty(LastAnnouncedTradeToken);
[UsedImplicitly]
public bool ShouldSerializeLastInventoryChecksumBeforeDeduplication() => !string.IsNullOrEmpty(LastInventoryChecksumBeforeDeduplication);
[UsedImplicitly]
public bool ShouldSerializeLastRequestAt() => LastRequestAt.HasValue;
protected override void Dispose(bool disposing) {
if (disposing) {
// Events we registered

View File

@@ -121,7 +121,7 @@ internal static class Commands {
IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => ResponseMatch(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot)))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result)).Select(static result => result!)];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}

View File

@@ -64,6 +64,10 @@
<value>Matched totalt {0} sæt denne runde.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Annoncerer {0} ({1}) med inventar lavet af {2} varer i alt på listen...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Matchede i alt {0} varer med bot {1} ({2}), sender handelstilbud...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>

View File

@@ -64,4 +64,16 @@
<value>Ο τελικός αριθμός συνόλων που έχουν ταιριάξει είναι {0}, αυτόν τον γύρο.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Ανακοίνωση {0} ({1}) με απογραφή από στοιχεία {2} συνολικά στην καταχώρηση...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Ταίριαξε ένα σύνολο αντικειμένων {0} με bot {1} ({2}), στέλνοντας προσφορά συναλλαγής...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Αποτυχία αποστολής μιας προσφοράς συναλλαγής στο bot {0} ({1}), με κίνηση...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
</root>

View File

@@ -64,6 +64,10 @@
<value>Abbinati un totale di {0} set questo round.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Annuncio {0} ({1}) con inventario fatto di elementi {2} in totale sulla lista...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Abbinato un totale di {0} elementi tramite bot {1} ({2}), inviando un'offerta commerciale...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>

View File

@@ -233,6 +233,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
HashSet<EAssetType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
if (acceptedMatchableTypes.Count == 0) {
// Should never happen, since IsEligibleForListing() check above ensured we have at least one matchable type
throw new InvalidOperationException(nameof(acceptedMatchableTypes));
}
@@ -905,9 +906,8 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
HashSet<EAssetType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
if (acceptedMatchableTypes.Count == 0) {
Bot.ArchiLogger.LogNullError(acceptedMatchableTypes);
return;
// Should never happen, since IsEligibleForMatching() check above ensured we have at least one matchable type
throw new InvalidOperationException(nameof(acceptedMatchableTypes));
}
if (!await MatchActivelySemaphore.WaitAsync(0).ConfigureAwait(false)) {
@@ -1276,20 +1276,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
Bot.ArchiLogger.LogGenericTrace($"{listedUser.SteamID}...");
byte? tradeHoldDuration = await Bot.ArchiWebHandler.GetCombinedTradeHoldDurationAgainstUser(listedUser.SteamID, listedUser.TradeToken).ConfigureAwait(false);
switch (tradeHoldDuration) {
case null:
Bot.ArchiLogger.LogGenericTrace(Strings.FormatErrorIsEmpty(nameof(tradeHoldDuration)));
continue;
case > 0 when (tradeHoldDuration.Value > maxTradeHoldDuration) || (tradeHoldDuration.Value > listedUser.MaxTradeHoldDuration):
Bot.ArchiLogger.LogGenericTrace($"{tradeHoldDuration.Value} > {maxTradeHoldDuration} || {listedUser.MaxTradeHoldDuration}");
continue;
}
HashSet<Asset> theirInventory = listedUser.Assets.Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((tradeHoldDuration.Value == 0) || !(item.Type is EAssetType.FoilTradingCard or EAssetType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).Select(static asset => asset.ToAsset()).ToHashSet();
HashSet<Asset> theirInventory = listedUser.Assets.Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity))).Select(static asset => asset.ToAsset()).ToHashSet();
if (theirInventory.Count == 0) {
continue;
@@ -1297,6 +1284,8 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
skippedSetsThisUser.Clear();
byte? tradeHoldDuration = null;
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> theirTradableState = MatchingUtilities.GetTradableInventoryState(theirInventory);
for (byte i = 0; i < Trading.MaxTradesPerAccount; i++) {
@@ -1335,6 +1324,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
match = false;
foreach ((ulong ourItem, uint ourFullAmount) in ourFullSet.Where(static item => item.Value > 1).OrderByDescending(static item => item.Value)) {
if ((tradeHoldDuration > maxTradeHoldDuration) || (tradeHoldDuration > listedUser.MaxTradeHoldDuration)) {
break;
}
if (!ourTradableSet.TryGetValue(ourItem, out uint ourTradableAmount) || (ourTradableAmount == 0)) {
continue;
}
@@ -1378,6 +1371,29 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
}
// Now that we have a match, check trade hold to ensure user is valid to match against
// Since it involves remote call, we didn't do it previously, to skip checking against users with no matches for us
if (tradeHoldDuration == null) {
tradeHoldDuration = await Bot.ArchiWebHandler.GetCombinedTradeHoldDurationAgainstUser(listedUser.SteamID, listedUser.TradeToken).ConfigureAwait(false);
if (tradeHoldDuration == null) {
Bot.ArchiLogger.LogGenericTrace(Strings.FormatErrorIsEmpty(nameof(tradeHoldDuration)));
break;
}
if ((tradeHoldDuration.Value > maxTradeHoldDuration) || (tradeHoldDuration.Value > listedUser.MaxTradeHoldDuration)) {
Bot.ArchiLogger.LogGenericTrace($"{tradeHoldDuration.Value} > {maxTradeHoldDuration} || {listedUser.MaxTradeHoldDuration}");
break;
}
}
if ((tradeHoldDuration.Value > 0) && set.Type is EAssetType.FoilTradingCard or EAssetType.TradingCard && CardsFarmer.SalesBlacklist.Contains(set.RealAppID)) {
// We're not considering this set for matching due to trade hold
continue;
}
// Skip this set from the remaining of this round
skippedSetsThisTrade.Add(set);

View File

@@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />

View File

@@ -192,7 +192,7 @@ internal static class Commands {
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalize(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result)).Select(static result => result!)];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
@@ -289,7 +289,7 @@ internal static class Commands {
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalized(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result)).Select(static result => result!)];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
@@ -362,7 +362,7 @@ internal static class Commands {
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorInit(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result)).Select(static result => result!)];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}

View File

@@ -5,7 +5,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />

View File

@@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />

View File

@@ -107,7 +107,10 @@
<value>Načítání informací o aplikaci {0} bylo dokončeno.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Dokončeno {0} z {1} požadavků na sklad</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Načítání všech tokenbů úložišť, celkem z {0} aplikací bylo dokončeno.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>

View File

@@ -60,33 +60,115 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="PluginDisabledMissingBuildToken" xml:space="preserve">
<value>{0} er blevet deaktiveret på grund af en manglende build token</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginDisabledInConfig" xml:space="preserve">
<value>{0} er i øjeblikket deaktiveret i henhold til din konfiguration. Hvis du vil hjælpe SteamDB i dataindsendelse, så tjek vores wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} er blevet initialiseret med succes, tak på forhånd for din hjælp. Den første indsendelse vil ske i cirka {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} kunne ikke indlæses, en ny instans vil blive initialiseret...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
</data>
<data name="BotNoAppsToRefresh" xml:space="preserve">
<value>Der er ingen apps, der kræver en opdatering i denne bot instans.</value>
</data>
<data name="BotRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Henter i alt {0} app-adgangstokens...</value>
<comment>{0} will be replaced by the number (total count) of app access tokens being retrieved</comment>
</data>
<data name="BotRetrievingAppAccessTokens" xml:space="preserve">
<value>Henter {0} app-adgangstokens...</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppAccessTokens" xml:space="preserve">
<value>Færdig med at hente {0} app-adgangstegn.</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Færdig med at hente i alt {0} app-adgangstokiner.</value>
<comment>{0} will be replaced by the number (total count) of app access tokens retrieved</comment>
</data>
<data name="BotRetrievingTotalDepots" xml:space="preserve">
<value>Henter alle depoter for i alt {0} apps...</value>
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
</data>
<data name="BotRetrievingAppInfos" xml:space="preserve">
<value>Retrieving {0} app infos...</value>
<comment>{0} will be replaced by the number (count this batch) of app infos being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppInfos" xml:space="preserve">
<value>Færdig med at hente {0} app-info.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Færdig {0} ud af {1} depot nøgleanmodninger.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Færdig med at hente alle depot nøgler for i alt {0} apps.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>Der er ingen nye data at indsende, alt er opdateret.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>Kunne ikke indsende data, da der ikke er noget gyldigt SteamID sæt, som vi kunne klassificere som bidragsyder. Overvej opsætning af {0} egenskab.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionInProgress" xml:space="preserve">
<value>Indsender i alt registrerede apps/pakker/depots: {0}/{1}/{2}...</value>
<comment>{0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>Indsendelsen er mislykkedes på grund af for mange anmodninger, vi vil prøve igen om cirka {0} fra nu.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>Dataene er blevet indsendt. Serveren har registreret i alt nye apps/packages/depots: {0} ({1} verificeret)/{2} ({3} verificeret)/{4} ({5} verificeret).</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>Nye apps: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedApps" xml:space="preserve">
<value>Verificerede apps: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewPackages" xml:space="preserve">
<value>Nye pakker: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedPackages" xml:space="preserve">
<value>Verificerede pakker: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Nye depoter: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Verificerede depot: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} initialiseret, plugin vil ikke løse nogen af dem: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>Indlæser STD global cache...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>Validerer STD global cache integritet...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>Mislykkedes at verificere STD global cache integritet. Dette tyder på en potentiel fil / hukommelse korruption, en ny instans vil blive initialiseret i stedet.</value>
</data>
</root>

View File

@@ -68,7 +68,10 @@
<value>{0} είναι απενεργοποιημένο σύμφωνα με τις ρυθμίσεις σας. Αν θέλετε να βοηθήσετε το SteamDB στην υποβολή δεδομένων, παρακαλώ ελέγξτε το wiki μας.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>Το {0} έχει αρχικοποιηθεί με επιτυχία, σας ευχαριστώ εκ των προτέρων για τη βοήθειά σας. Η πρώτη υποβολή θα γίνει σε περίπου {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} δεν μπόρεσε να φορτωθεί, μια νέα παρουσία θα αρχικοποιηθεί...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
@@ -104,7 +107,10 @@
<value>Ολοκληρώθηκε η ανάκτηση {0} πληροφοριών εφαρμογών.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Ολοκληρώθηκε το {0} από τα αιτήματα κλειδιού depot {1}.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Ολοκληρώθηκε η ανάκτηση όλων των κλειδιών αποθηκών για συνολικά {0} εφαρμογές.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>

View File

@@ -107,7 +107,10 @@
<value>Selesai memuat {0} informasi aplikasi.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Selesai {0} dari {1} depot key yang di minta.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Selesai memuat semua kunci depot untuk total {0} aplikasi.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>

View File

@@ -107,7 +107,10 @@
<value>Hai completato il recupero di {0} informazioni app.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Hai completato le richieste di chiave del deposito {0} su {1}.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Finito il recupero di tutte le chiavi del deposito per un totale di {0} applicazioni.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>

View File

@@ -68,7 +68,10 @@
<value>{0} is momenteel uitgeschakeld volgens uw configuratie. Als je SteamDB wilt helpen bij het indienen van gegevens, bekijk dan onze wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} is met succes geïnitialiseerd. Alvast bedankt voor uw hulp. De eerste uitwerking zal gebeuren in ongeveer {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} kon niet worden geladen, een nieuwe instantie zal worden geïnitialiseerd...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
@@ -104,13 +107,33 @@
<value>Ophalen van {0} app-infos voltooid.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Klaar {0} van {1} depot sleutelverzoeken.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Ophalen van alle depot keys voltooid voor een totaal van {0} apps.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>Er zijn geen nieuwe gegevens om in te dienen, alles is up-to-date.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>Kon de gegevens niet indienen omdat er geen geldige SteamID is die we als bijdrager kunnen classificeren. Overweeg het instellen van {0} property.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionInProgress" xml:space="preserve">
<value>Verzenden van een totaal van geregistreerde apps/packages/depos: {0}/{1}/{2}...</value>
<comment>{0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>De indiening is mislukt door te veel verzonden, we zullen het vanaf nu opnieuw proberen in ongeveer {0}.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>De gegevens zijn succesvol ingediend. De server heeft een totaal van nieuwe apps/pakketten/depots: {0} ({1} geverifieerd)/{2} ({3} geverifieerd)/{4} ({5} geverifieerd).</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>Nieuwe apps: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
@@ -127,10 +150,25 @@
<value>Geverifieerde pakketten: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Nieuwe depoten: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Geverifieerde depot: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} geïnitialiseerd, de plugin zal geen van deze oplossen: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>STD global cache laden...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>Valideren van STD globale cache integriteit...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>Kon de wereldwijde STD cache integriteit niet verifiëren. Dit suggereert een potentiële bestands/geheugencorruptie, een nieuw exemplaar zal in plaats daarvan worden geïnitialiseerd.</value>
</data>
</root>

View File

@@ -60,33 +60,111 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="PluginDisabledMissingBuildToken" xml:space="preserve">
<value>{0} har blitt deaktivert på grunn av et manglende byggetoken</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginDisabledInConfig" xml:space="preserve">
<value>{0} er for øyeblikket deaktivert i henhold til din konfigurasjon. Hvis du vil hjelpe SteamDB med datainnsending, vennligst sjekk ut vår wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} har blitt igangsatt vellykket, takk for din hjelp. Den første innsending vil skje i omtrent {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} kunne ikke lastes inn, en frisk forekomst vil bli initialisert...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
</data>
<data name="BotNoAppsToRefresh" xml:space="preserve">
<value>Det er ingen programmer som krever en oppdatering på denne botthendelsen.</value>
</data>
<data name="BotRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Henter de totale {0} app-tilgangstegener...</value>
<comment>{0} will be replaced by the number (total count) of app access tokens being retrieved</comment>
</data>
<data name="BotRetrievingAppAccessTokens" xml:space="preserve">
<value>Henter {0} app-tilgangstokene...</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppAccessTokens" xml:space="preserve">
<value>Ferdig med å hente {0} app-tilgangsnøkkler.</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Ferdig med å hente totalt {0} app-tilgangsnøkkler.</value>
<comment>{0} will be replaced by the number (total count) of app access tokens retrieved</comment>
</data>
<data name="BotRetrievingTotalDepots" xml:space="preserve">
<value>Henter alle depoter for en total {0} apper...</value>
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
</data>
<data name="BotRetrievingAppInfos" xml:space="preserve">
<value>Retrieving {0} app infos...</value>
<comment>{0} will be replaced by the number (count this batch) of app infos being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppInfos" xml:space="preserve">
<value>Ferdig med å hente {0} app infos.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Ferdig med {0} av {1} lagerets viktigste forespørsler.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Fullførte henting av alle depot-nøkler for totalt {0} apper.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>Det finnes ingen nye data, alt er oppdatert.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>Kunne ikke sende inn data fordi det ikke er gyldig SteamID satt som vi kan klassifisere som bidragsyter. Vurder å sette opp {0} egenskapen.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>Innsendingen mislyktes på grunn av for mange forespørsler sendt, vi prøver igjen om lag {0} nå.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>Dataene har blitt sendt inn. Serveren har registrert totalt nye applikasjoner/pakker/depoter: {0} ({1} verifisert)/{2} ({3} bekreftet)/{4} ({5} verifisert).</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>Nye apper: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedApps" xml:space="preserve">
<value>Verifiserte apper: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewPackages" xml:space="preserve">
<value>Nye pakker: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedPackages" xml:space="preserve">
<value>Verifiserte pakker: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Nye depoter: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Verifiserte depoter: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} initialisert, utvidelsen vil ikke løse noen av disse: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>Laster STD global cache...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>Validerer STD global cache integritet...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>Kan ikke verifisere STD globale cachens integritet. Dette foreslår en potensiell fil-/minnesorpsjon, et frisk eksempel vil bli initialisert i stedet.</value>
</data>
</root>

View File

@@ -68,7 +68,10 @@
<value>{0} está atualmente desativado de acordo com a sua configuração. Se quiser ajudar o SteamDB na submissão de dados, por favor confira o nosso wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} foi inicializado com sucesso, obrigado antecipadamente por sua ajuda. O primeiro envio ocorrerá em aproximadamente {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} não pôde ser carregado, uma instância nova será inicializada...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
@@ -92,24 +95,80 @@
<value>Terminado o recolhimento de um total de {0} tokens de acesso a aplicações.</value>
<comment>{0} will be replaced by the number (total count) of app access tokens retrieved</comment>
</data>
<data name="BotRetrievingTotalDepots" xml:space="preserve">
<value>Recuperando todos os depósitos para um total de apps {0}...</value>
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
</data>
<data name="BotRetrievingAppInfos" xml:space="preserve">
<value>Retrieving {0} app infos...</value>
<comment>{0} will be replaced by the number (count this batch) of app infos being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppInfos" xml:space="preserve">
<value>Informações do aplicativo {0} finalizadas.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>{0} terminou de pedidos chave de depósito {1}.</value>
<comment>{0} will be replaced by the number (count this batch) of depot key requests that were successfully answered, {1} will be replaced by the number (count this batch) of depot key requests that were supposed to be sent</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Terminou de recuperar todas as chaves de depósito para um total de aplicativos {0}.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>Não há novos dados para enviar, tudo está atualizado.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>Não foi possível enviar os dados porque não há um conjunto SteamID válido que possamos classificar como colaborador. Considere configurar a propriedade {0}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionInProgress" xml:space="preserve">
<value>Enviar um total de apps/pacotes/pacotes registrados: {0}/{1}/{2}...</value>
<comment>{0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>O envio falhou devido a muitas solicitações enviadas, tentaremos novamente em aproximadamente {0} a partir de agora.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>Os dados foram enviados com sucesso. O servidor registrou um total de novos aplicativos/pacotes/depósitos: {0} ({1} verificado)/{2} ({3} verificado)/{4} ({5} verificado).</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>Novos aplicativos: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedApps" xml:space="preserve">
<value>Apps verificados: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewPackages" xml:space="preserve">
<value>Novos pacotes: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedPackages" xml:space="preserve">
<value>Pacotes verificados: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Novos depósitos: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Depósitos verificados: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} inicializado, o plugin não resolverá nenhum desses: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>Carregando cache global STD...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>Validando integridade de cache global STD...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>Falha ao verificar a integridade do cache global STD. Isso sugere uma potencial corrupção de arquivo/memória, uma instância nova será inicializada em vez disso.</value>
</data>
</root>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} başarıyla başlatıldı, yardımınız için şimdiden teşekkürler. İlk sunum yaklaşık olarak {1} içinde gerçekleşecektir.</value>
<value>{0} başarıyla başlatıldı, yardımınız için şimdiden teşekkürler. İlk gönderim yaklaşık olarak {1} içinde gerçekleşecektir.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -36,7 +36,7 @@ internal sealed class ArchiCryptoHelper {
[DataRow(ECryptoMethod.PlainText)]
[DataRow(ECryptoMethod.AES)]
[DataTestMethod]
[TestMethod]
internal async Task CanEncryptDecrypt(ECryptoMethod cryptoMethod) {
if (!Enum.IsDefined(cryptoMethod)) {
throw new InvalidEnumArgumentException(nameof(cryptoMethod), (int) cryptoMethod, typeof(ECryptoMethod));
@@ -54,12 +54,28 @@ internal sealed class ArchiCryptoHelper {
[TestMethod]
internal async Task CanEncryptDecryptProtectedDataForCurrentUser() {
// Not supported on other platforms than Windows
if (!OperatingSystem.IsWindows()) {
// Not supported on other platforms than Windows
return;
Assert.Inconclusive($"!{nameof(OperatingSystem.IsWindows)}");
}
await CanEncryptDecrypt(ECryptoMethod.ProtectedDataForCurrentUser).ConfigureAwait(false);
}
[DataRow(EHashingMethod.PlainText, TestPassword)]
[DataRow(EHashingMethod.Pbkdf2, "WlS48GNrs1hAhcNHPfV09TPTLhf03gExb6zpaKiwX5A=")]
[DataRow(EHashingMethod.SCrypt, "9LjhjyugakDQ7Haq/ufyTZDfIGeeWbLcE+/9IeKm8gc=")]
[TestMethod]
internal void CanHash(EHashingMethod hashingMethod, string expectedHash) {
if (!Enum.IsDefined(hashingMethod)) {
throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(EHashingMethod));
}
ArgumentException.ThrowIfNullOrEmpty(expectedHash);
string hashed = Hash(hashingMethod, TestPassword);
Assert.AreEqual(expectedHash, hashed);
}
}
#pragma warning restore CA1812 // False positive, the class is used during MSTest

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="MSTest" />
</ItemGroup>

View File

@@ -471,7 +471,7 @@ internal sealed class Bot {
HashSet<Asset> itemsToSend = GetItemsForFullBadge(items, 2, appID);
Assert.IsTrue(itemsToSend.Count <= Steam.Exchange.Trading.MaxItemsPerTrade);
Assert.IsLessThanOrEqualTo(Steam.Exchange.Trading.MaxItemsPerTrade, itemsToSend.Count);
}
[TestMethod]
@@ -495,7 +495,7 @@ internal sealed class Bot {
HashSet<Asset> itemsToSend = GetItemsForFullBadge(items, itemsPerSet);
Assert.IsTrue(itemsToSend.Count <= Steam.Exchange.Trading.MaxItemsPerTrade);
Assert.IsLessThanOrEqualTo(Steam.Exchange.Trading.MaxItemsPerTrade, itemsToSend.Count);
}
[TestMethod]
@@ -526,7 +526,7 @@ internal sealed class Bot {
ArgumentNullException.ThrowIfNull(itemsToSend);
Dictionary<(uint RealAppID, ulong ContextID, ulong ClassID), long> realResult = itemsToSend.GroupBy(static asset => (asset.RealAppID, asset.ContextID, asset.ClassID)).ToDictionary(static group => group.Key, static group => group.Sum(static asset => asset.Amount));
Assert.AreEqual(expectedResult.Count, realResult.Count);
Assert.HasCount(expectedResult.Count, realResult);
Assert.IsTrue(expectedResult.All(expectation => realResult.TryGetValue(expectation.Key, out long reality) && (expectation.Value == reality)));
}

View File

@@ -22,6 +22,7 @@
// limitations under the License.
using System;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Localization;
@@ -30,6 +31,7 @@ using ArchiSteamFarm.Storage;
using ArchiSteamFarm.Web;
using ArchiSteamFarm.Web.GitHub;
using ArchiSteamFarm.Web.GitHub.Data;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ArchiSteamFarm.Tests;
@@ -40,6 +42,17 @@ internal sealed class IGitHubPluginUpdates {
private const string PluginName = "ArchiSteamFarm.OfficialPlugins.Monitoring";
private const string Repository = "JustArchiNET/ArchiSteamFarm";
private readonly TestContext TestContext;
private CancellationToken CancellationToken => TestContext.CancellationToken;
[UsedImplicitly]
public IGitHubPluginUpdates(TestContext testContext) {
ArgumentNullException.ThrowIfNull(testContext);
TestContext = testContext;
}
[TestCategory("Manual")]
[TestMethod]
internal async Task DoesNotOfferPointlessUpdatesWhenMultipleAssetsAreFound() {
@@ -47,7 +60,7 @@ internal sealed class IGitHubPluginUpdates {
typeof(ASF).GetProperty(nameof(ASF.WebBrowser))?.SetValue(null, webBrowser);
ReleaseResponse? response = await GitHubService.GetLatestRelease(Repository).ConfigureAwait(false);
ReleaseResponse? response = await GitHubService.GetLatestRelease(Repository, cancellationToken: CancellationToken).ConfigureAwait(false);
if (response == null) {
Assert.Inconclusive(Strings.FormatWarningFailedWithError(nameof(response)));

View File

@@ -36,7 +36,7 @@ internal sealed class MobileAuthenticator {
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1337, "mYbCKs8ZvsVN2odCMxpvidrIu1c=", "conf")]
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1723332288, "hiEx+JBqJqFJnSSL+dEthPHOmsc=")]
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1723332288, "hpZUxyNgwBvtKPROvedjuvVPQiE=", "conf")]
[DataTestMethod]
[TestMethod]
internal void GenerateConfirmationHash(string identitySecret, ulong time, string expectedCode, string? tag = null) {
ArgumentException.ThrowIfNullOrEmpty(identitySecret);
ArgumentOutOfRangeException.ThrowIfZero(time);
@@ -58,7 +58,7 @@ internal sealed class MobileAuthenticator {
[DataRow("KDHC3rsY8+CmiswnXJcE5e5dRfd=", (ulong) 1337, "47J4D")]
[DataRow("KDHC3rsY8+CmiswnXJcE5e5dRfd=", (ulong) 1723332288, "JQ3HQ")]
[DataTestMethod]
[TestMethod]
internal void GenerateTokenForTime(string sharedSecret, ulong time, string expectedCode) {
ArgumentException.ThrowIfNullOrEmpty(sharedSecret);
ArgumentOutOfRangeException.ThrowIfZero(time);

View File

@@ -25,7 +25,9 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static ArchiSteamFarm.Steam.Integration.SteamChatMessage;
@@ -34,6 +36,17 @@ namespace ArchiSteamFarm.Tests;
#pragma warning disable CA1812 // False positive, the class is used during MSTest
[TestClass]
internal sealed class SteamChatMessage {
private readonly TestContext TestContext;
private CancellationToken CancellationToken => TestContext.CancellationToken;
[UsedImplicitly]
public SteamChatMessage(TestContext testContext) {
ArgumentNullException.ThrowIfNull(testContext);
TestContext = testContext;
}
[TestMethod]
internal async Task CanSplitEvenWithStupidlyLongPrefix() {
string prefix = new('x', MaxMessagePrefixBytes);
@@ -41,9 +54,9 @@ internal sealed class SteamChatMessage {
const string emoji = "😎";
const string message = $"{emoji}{emoji}{emoji}{emoji}";
List<string> output = await GetMessageParts(message, prefix, true).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, prefix, true).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(4, output.Count);
Assert.HasCount(4, output);
Assert.AreEqual($"{prefix}{emoji}{ContinuationCharacter}", output[0]);
Assert.AreEqual($"{prefix}{ContinuationCharacter}{emoji}{ContinuationCharacter}", output[1]);
@@ -58,15 +71,15 @@ internal sealed class SteamChatMessage {
internal async Task DoesntSkipEmptyNewlines() {
string message = $"asdf{Environment.NewLine}{Environment.NewLine}asdf";
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual(message, output.First());
}
[DataRow(false)]
[DataRow(true)]
[DataTestMethod]
[TestMethod]
internal async Task DoesntSplitInTheMiddleOfMultiByteChar(bool isAccountLimited) {
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
@@ -76,9 +89,9 @@ internal sealed class SteamChatMessage {
string longSequence = new('a', longLineLength - 1);
string message = $"{longSequence}{emoji}";
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(2, output.Count);
Assert.HasCount(2, output);
Assert.AreEqual($"{longSequence}{ContinuationCharacter}", output[0]);
Assert.AreEqual($"{ContinuationCharacter}{emoji}", output[1]);
@@ -89,15 +102,15 @@ internal sealed class SteamChatMessage {
const string message = "abcdef[";
const string escapedMessage = @"abcdef\[";
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual(escapedMessage, output.First());
}
[DataRow(false)]
[DataRow(true)]
[DataTestMethod]
[TestMethod]
internal async Task DoesntSplitOnBackslashNotUsedForEscaping(bool isAccountLimited) {
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
@@ -105,15 +118,15 @@ internal sealed class SteamChatMessage {
string longLine = new('a', longLineLength - 2);
string message = $@"{longLine}\";
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual($@"{message}\", output.First());
}
[DataRow(false)]
[DataRow(true)]
[DataTestMethod]
[TestMethod]
internal async Task DoesntSplitOnEscapeCharacter(bool isAccountLimited) {
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
@@ -121,9 +134,9 @@ internal sealed class SteamChatMessage {
string longLine = new('a', longLineLength - 1);
string message = $"{longLine}[";
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(2, output.Count);
Assert.HasCount(2, output);
Assert.AreEqual($"{longLine}{ContinuationCharacter}", output[0]);
Assert.AreEqual($@"{ContinuationCharacter}\[", output[1]);
@@ -133,9 +146,9 @@ internal sealed class SteamChatMessage {
internal async Task NoNeedForAnySplittingWithNewlines() {
string message = $"abcdef{Environment.NewLine}ghijkl{Environment.NewLine}mnopqr";
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual(message, output.First());
}
@@ -143,23 +156,23 @@ internal sealed class SteamChatMessage {
internal async Task NoNeedForAnySplittingWithoutNewlines() {
const string message = "abcdef";
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual(message, output.First());
}
[TestMethod]
internal void ParagraphCharacterSizeIsLessOrEqualToContinuationCharacterSize() => Assert.IsTrue(ContinuationCharacterBytes >= Encoding.UTF8.GetByteCount(ParagraphCharacter.ToString()));
internal void ParagraphCharacterSizeIsLessOrEqualToContinuationCharacterSize() => Assert.IsGreaterThanOrEqualTo(Encoding.UTF8.GetByteCount(ParagraphCharacter.ToString()), ContinuationCharacterBytes);
[TestMethod]
internal async Task ProperlyEscapesCharacters() {
const string message = @"[b]bold[/b] \n";
const string escapedMessage = @"\[b]bold\[/b] \\n";
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual(escapedMessage, output.First());
}
@@ -170,15 +183,15 @@ internal sealed class SteamChatMessage {
const string message = "asdf";
List<string> output = await GetMessageParts(message, prefix).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, prefix).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(1, output.Count);
Assert.HasCount(1, output);
Assert.AreEqual($"{escapedPrefix}{message}", output.First());
}
[DataRow(false)]
[DataRow(true)]
[DataTestMethod]
[TestMethod]
internal async Task ProperlySplitsLongSingleLine(bool isAccountLimited) {
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
@@ -186,9 +199,9 @@ internal sealed class SteamChatMessage {
string longLine = new('a', longLineLength);
string message = $"{longLine}{longLine}{longLine}{longLine}";
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(4, output.Count);
Assert.HasCount(4, output);
Assert.AreEqual($"{longLine}{ContinuationCharacter}", output[0]);
Assert.AreEqual($"{ContinuationCharacter}{longLine}{ContinuationCharacter}", output[1]);
@@ -260,9 +273,9 @@ internal sealed class SteamChatMessage {
<ASF> 1/1 ботов уже имеют игру app/304930 | Unturned.
""";
List<string> output = await GetMessageParts(message, prefix).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, prefix).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(2, output.Count);
Assert.HasCount(2, output);
foreach (string messagePart in output) {
if ((messagePart.Length <= prefix.Length) || !messagePart.StartsWith(prefix, StringComparison.Ordinal)) {
@@ -285,7 +298,7 @@ internal sealed class SteamChatMessage {
[DataRow(false)]
[DataRow(true)]
[DataTestMethod]
[TestMethod]
internal async Task SplitsOnNewlinesWithParagraphCharacter(bool isAccountLimited) {
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
@@ -304,9 +317,9 @@ internal sealed class SteamChatMessage {
string newlinePart = newlinePartBuilder.ToString();
string message = $"{newlinePart}{Environment.NewLine}{newlinePart}{Environment.NewLine}{newlinePart}{Environment.NewLine}{newlinePart}";
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync().ConfigureAwait(false);
List<string> output = await GetMessageParts(message, isAccountLimited: isAccountLimited).ToListAsync(CancellationToken).ConfigureAwait(false);
Assert.AreEqual(4, output.Count);
Assert.HasCount(4, output);
Assert.AreEqual($"{newlinePart}{ParagraphCharacter}", output[0]);
Assert.AreEqual($"{newlinePart}{ParagraphCharacter}", output[1]);
@@ -320,7 +333,7 @@ internal sealed class SteamChatMessage {
const string message = "asdf";
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await GetMessageParts(message, prefix).ToListAsync().ConfigureAwait(false)).ConfigureAwait(false);
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await GetMessageParts(message, prefix).ToListAsync(CancellationToken).ConfigureAwait(false)).ConfigureAwait(false);
}
[TestMethod]
@@ -329,7 +342,7 @@ internal sealed class SteamChatMessage {
const string message = "asdf";
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await GetMessageParts(message, prefix).ToListAsync().ConfigureAwait(false)).ConfigureAwait(false);
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await GetMessageParts(message, prefix).ToListAsync(CancellationToken).ConfigureAwait(false)).ConfigureAwait(false);
}
}
#pragma warning restore CA1812 // False positive, the class is used during MSTest

View File

@@ -45,6 +45,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTrailingCommaInSinglelineLists/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeMemberModifiers/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeModifiers/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AsyncVoidEventHandlerMethod/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AsyncVoidMethod/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=BadAttributeBracketsSpaces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=BadBracesSpaces/@EntryIndexedValue">WARNING</s:String>
@@ -187,6 +188,9 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToConstant_002ELocal/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToExpressionBodyWhenPossible/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToLambdaExpressionWhenPossible/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicatedChainedIfBodies/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicatedSequentialIfBodies/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicatedSwitchExpressionArms/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicatedSwitchSectionBodies/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicateResource/@EntryIndexedValue">DO_NOT_SHOW</s:String>
@@ -239,6 +243,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MissingSpace/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MoveLocalFunctionAfterJumpStatement/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MoveToExistingPositionalDeconstructionPattern/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MoveToExtensionBlock/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MultipleSpaces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MultipleStatementsOnOneLine/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MultipleTypeMembersOnOneLine/@EntryIndexedValue">WARNING</s:String>
@@ -256,6 +261,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PatternAlwaysMatches/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PatternAlwaysOfType/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PlaceAssignmentExpressionIntoBlock/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PreferExplicitlyProvidedTupleComponentName/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PrimaryConstructorParameterCaptureDisallowed/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PropertyNotResolved/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RawStringCanBeSimplified/@EntryIndexedValue">SUGGESTION</s:String>

View File

@@ -4,11 +4,16 @@
<OutputType>Exe</OutputType>
</PropertyGroup>
<!-- TODO: It seems CA1515 is no longer respected inside editorconfig, might be possible to remove later -->
<PropertyGroup>
<NoWarn>$(NoWarn),CA1515</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AngleSharp" />
<PackageReference Include="CryptSharpStandard" />
<PackageReference Include="Humanizer" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
<PackageReference Include="Markdig.Signed" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
@@ -18,7 +23,6 @@
<PackageReference Include="Scalar.AspNetCore" />
<PackageReference Include="SteamKit2" />
<PackageReference Include="System.Composition" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
</ItemGroup>

View File

@@ -355,8 +355,8 @@ public static class ASF {
}
ArchiLogger.LogGenericInfo(Strings.IPCConfigChanged);
await ArchiKestrel.Stop().ConfigureAwait(false);
await ArchiKestrel.Start().ConfigureAwait(false);
await ArchiKestrel.Restart().ConfigureAwait(false);
}
private static async Task OnChangedFile(string name, string fullPath) {
@@ -843,8 +843,7 @@ public static class ASF {
BinaryResponse? response;
try {
// ReSharper disable once MethodSupportsCancellation - the token initialized above is not meant to be passed here
response = await WebBrowser.UrlGetToBinary(binaryAsset.DownloadURL, progressReporter: progressReporter).ConfigureAwait(false);
response = await WebBrowser.UrlGetToBinary(binaryAsset.DownloadURL, progressReporter: progressReporter, cancellationToken: CancellationToken.None).ConfigureAwait(false);
} finally {
progressReporter.ProgressChanged -= onProgressChanged;
}
@@ -888,10 +887,12 @@ public static class ASF {
MemoryStream memoryStream = new(responseBytes);
await using (memoryStream.ConfigureAwait(false)) {
using ZipArchive zipArchive = new(memoryStream);
ZipArchive zipArchive = new(memoryStream);
if (!await UpdateFromArchive(newVersion, channel.Value, updateOverride, forced, zipArchive).ConfigureAwait(false)) {
ArchiLogger.LogGenericError(Strings.WarningFailed);
await using (zipArchive.ConfigureAwait(false)) {
if (!await UpdateFromArchive(newVersion, channel.Value, updateOverride, forced, zipArchive).ConfigureAwait(false)) {
ArchiLogger.LogGenericError(Strings.WarningFailed);
}
}
}
} catch (Exception e) {

View File

@@ -169,18 +169,6 @@ public static class Utilities {
}
}
[PublicAPI]
public static bool IsClientErrorCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.BadRequest and < HttpStatusCode.InternalServerError;
[PublicAPI]
public static bool IsRedirectionCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.Ambiguous and < HttpStatusCode.BadRequest;
[PublicAPI]
public static bool IsServerErrorCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.InternalServerError and < (HttpStatusCode) 600;
[PublicAPI]
public static bool IsSuccessCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous;
[PublicAPI]
public static bool IsValidCdKey(string key) {
ArgumentException.ThrowIfNullOrEmpty(key);
@@ -313,7 +301,7 @@ public static class Utilities {
// Now extract the zip file to entirely new location, this decreases chance of corruptions if user kills the process during this stage
string updateDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryNew);
zipArchive.ExtractToDirectory(updateDirectory, true);
await zipArchive.ExtractToDirectoryAsync(updateDirectory, true).ConfigureAwait(false);
// Now, critical section begins, we're going to move all files from target directory to a backup directory
string backupDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryOld);
@@ -525,4 +513,20 @@ public static class Utilities {
return prefixes.Any(prefix => !string.IsNullOrEmpty(prefix) && (directory.Length > prefix.Length) && DirectorySeparators.Contains(directory[prefix.Length]) && directory.StartsWith(prefix, StringComparison.Ordinal));
}
#pragma warning disable CA1034 // False positive, there's no other way we can declare this block
extension(HttpStatusCode statusCode) {
[PublicAPI]
public bool IsClientErrorCode() => statusCode is >= HttpStatusCode.BadRequest and < HttpStatusCode.InternalServerError;
[PublicAPI]
public bool IsRedirectionCode() => statusCode is >= HttpStatusCode.Ambiguous and < HttpStatusCode.BadRequest;
[PublicAPI]
public bool IsServerErrorCode() => statusCode is >= HttpStatusCode.InternalServerError and < (HttpStatusCode) 600;
[PublicAPI]
public bool IsSuccessCode() => statusCode is >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous;
}
#pragma warning restore CA1034 // False positive, there's no other way we can declare this block
}

View File

@@ -86,7 +86,11 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
try {
while (true) {
if (!await EnsureFileExists().ConfigureAwait(false)) {
throw new IOException(Strings.FormatWarningFailedWithError(nameof(EnsureFileExists)));
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(EnsureFileExists)));
await Task.Delay(SpinLockDelay * 25, cancellationToken).ConfigureAwait(false);
continue;
}
try {
@@ -103,7 +107,9 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
}
} catch (FileNotFoundException) {
throw;
} catch (IOException) {
} catch (IOException e) {
ASF.ArchiLogger.LogGenericDebuggingException(e);
await Task.Delay(SpinLockDelay, cancellationToken).ConfigureAwait(false);
}
}
@@ -128,7 +134,7 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
try {
stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds >= millisecondsTimeout) {
if (stopwatch.ElapsedMilliseconds > millisecondsTimeout) {
return false;
}
@@ -136,7 +142,18 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
while (true) {
if (!await EnsureFileExists().ConfigureAwait(false)) {
throw new IOException(Strings.FormatWarningFailedWithError(nameof(EnsureFileExists)));
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(EnsureFileExists)));
if (millisecondsTimeout <= 0) {
return false;
}
int sleep = Math.Min(millisecondsTimeout, SpinLockDelay * 25);
await Task.Delay(sleep, cancellationToken).ConfigureAwait(false);
millisecondsTimeout -= sleep;
continue;
}
try {
@@ -153,13 +170,17 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
}
} catch (FileNotFoundException) {
throw;
} catch (IOException) {
if (millisecondsTimeout <= SpinLockDelay) {
} catch (IOException e) {
ASF.ArchiLogger.LogGenericDebuggingException(e);
if (millisecondsTimeout <= 0) {
return false;
}
await Task.Delay(SpinLockDelay, cancellationToken).ConfigureAwait(false);
millisecondsTimeout -= SpinLockDelay;
int sleep = Math.Min(millisecondsTimeout, SpinLockDelay);
await Task.Delay(sleep, cancellationToken).ConfigureAwait(false);
millisecondsTimeout -= sleep;
}
}
} finally {
@@ -184,20 +205,26 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
}
if (!Directory.Exists(directoryPath)) {
if (OperatingSystem.IsWindows()) {
DirectoryInfo directoryInfo = Directory.CreateDirectory(directoryPath);
try {
if (OperatingSystem.IsWindows()) {
DirectoryInfo directoryInfo = Directory.CreateDirectory(directoryPath);
try {
DirectorySecurity directorySecurity = new(directoryPath, AccessControlSections.All);
try {
DirectorySecurity directorySecurity = new(directoryPath, AccessControlSections.All);
directoryInfo.SetAccessControl(directorySecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
directoryInfo.SetAccessControl(directorySecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
// We require global access from all users, as other ASFs might need to put additional files in there
Directory.CreateDirectory(directoryPath, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute | UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
// We require global access from all users, as other ASFs might need to put additional files in there
Directory.CreateDirectory(directoryPath, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute | UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
} catch (IOException e) {
ASF.ArchiLogger.LogGenericException(e);
return false;
}
}
@@ -228,11 +255,21 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
await new FileStream(FilePath, fileStreamOptions).DisposeAsync().ConfigureAwait(false);
}
} catch (IOException e) {
// Ignored, if the file was already created in the meantime by another instance, this is fine
ASF.ArchiLogger.LogGenericDebuggingException(e);
if (i == 0) {
// Ignored, if the file was already created in the meantime by another instance, this is fine
ASF.ArchiLogger.LogGenericDebuggingException(e);
continue;
}
// It's not fine if the same issue happened again
ASF.ArchiLogger.LogGenericException(e);
return false;
}
}
return false;
// It's also not fine if we failed to create the file twice in a row
return File.Exists(FilePath);
}
}

View File

@@ -29,7 +29,7 @@ namespace ArchiSteamFarm.Helpers;
[PublicAPI]
public interface ICrossProcessSemaphore {
void Release();
Task WaitAsync(CancellationToken cancellationToken = default);
Task<bool> WaitAsync(int millisecondsTimeout, CancellationToken cancellationToken = default);
public void Release();
public Task WaitAsync(CancellationToken cancellationToken = default);
public Task<bool> WaitAsync(int millisecondsTimeout, CancellationToken cancellationToken = default);
}

View File

@@ -29,6 +29,7 @@ using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
@@ -39,33 +40,33 @@ namespace ArchiSteamFarm.Helpers.Json;
public static class JsonUtilities {
[PublicAPI]
public static readonly JsonSerializerOptions DefaultJsonSerialierOptions = CreateDefaultJsonSerializerOptions();
public static readonly JsonSerializerOptions DefaultJsonSerializerOptions = CreateDefaultJsonSerializerOptions();
[PublicAPI]
public static readonly JsonSerializerOptions IndentedJsonSerialierOptions = CreateDefaultJsonSerializerOptions(true);
public static readonly JsonSerializerOptions IndentedJsonSerializerOptions = CreateDefaultJsonSerializerOptions(true);
[PublicAPI]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
public static JsonElement ToJsonElement<T>(this T obj) where T : notnull {
ArgumentNullException.ThrowIfNull(obj);
return JsonSerializer.SerializeToElement(obj, DefaultJsonSerialierOptions);
return JsonSerializer.SerializeToElement(obj, DefaultJsonSerializerOptions);
}
[PublicAPI]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
public static T? ToJsonObject<T>(this JsonElement jsonElement) => jsonElement.Deserialize<T>(DefaultJsonSerialierOptions);
public static T? ToJsonObject<T>(this JsonElement jsonElement) => jsonElement.Deserialize<T>(DefaultJsonSerializerOptions);
[PublicAPI]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
public static T? ToJsonObject<T>(this JsonNode jsonNode) => jsonNode.Deserialize<T>(DefaultJsonSerialierOptions);
public static T? ToJsonObject<T>(this JsonNode jsonNode) => jsonNode.Deserialize<T>(DefaultJsonSerializerOptions);
[PublicAPI]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
public static async ValueTask<T?> ToJsonObject<T>(this Stream stream, CancellationToken cancellationToken = default) {
ArgumentNullException.ThrowIfNull(stream);
return await JsonSerializer.DeserializeAsync<T>(stream, DefaultJsonSerialierOptions, cancellationToken).ConfigureAwait(false);
return await JsonSerializer.DeserializeAsync<T>(stream, DefaultJsonSerializerOptions, cancellationToken).ConfigureAwait(false);
}
[PublicAPI]
@@ -73,12 +74,12 @@ public static class JsonUtilities {
public static T? ToJsonObject<T>([StringSyntax(StringSyntaxAttribute.Json)] this string json) {
ArgumentException.ThrowIfNullOrEmpty(json);
return JsonSerializer.Deserialize<T>(json, DefaultJsonSerialierOptions);
return JsonSerializer.Deserialize<T>(json, DefaultJsonSerializerOptions);
}
[PublicAPI]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
public static string ToJsonText<T>(this T obj, bool writeIndented = false) => JsonSerializer.Serialize(obj, writeIndented ? IndentedJsonSerialierOptions : DefaultJsonSerialierOptions);
public static string ToJsonText<T>(this T obj, bool writeIndented = false) => JsonSerializer.Serialize(obj, writeIndented ? IndentedJsonSerializerOptions : DefaultJsonSerializerOptions);
private static void ApplyCustomModifiers(JsonTypeInfo jsonTypeInfo) {
ArgumentNullException.ThrowIfNull(jsonTypeInfo);
@@ -116,12 +117,15 @@ public static class JsonUtilities {
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
private static JsonSerializerOptions CreateDefaultJsonSerializerOptions(bool writeIndented = false) =>
new() {
new(JsonSerializerDefaults.Strict) {
AllowTrailingCommas = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
IndentCharacter = '\t',
IndentSize = 1,
PropertyNamingPolicy = null,
ReadCommentHandling = JsonCommentHandling.Skip,
TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ApplyCustomModifiers } },
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
WriteIndented = writeIndented
};

View File

@@ -67,7 +67,7 @@ public abstract class SerializableFile : IDisposable {
ArgumentNullException.ThrowIfNull(serializableFile);
if (string.IsNullOrEmpty(serializableFile.FilePath)) {
throw new InvalidOperationException(nameof(serializableFile.FilePath));
return;
}
if (serializableFile.ReadOnly) {

View File

@@ -30,6 +30,7 @@ using System.Net;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Helpers.Json;
@@ -55,7 +56,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using NLog.Web;
using Scalar.AspNetCore;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
using IPNetwork = System.Net.IPNetwork;
namespace ArchiSteamFarm.IPC;
@@ -64,6 +65,8 @@ internal static class ArchiKestrel {
internal static HistoryTarget? HistoryTarget { get; private set; }
private static readonly SemaphoreSlim StateSemaphore = new(1, 1);
private static WebApplication? WebApplication;
internal static void OnNewHistoryTarget(HistoryTarget? historyTarget = null) {
@@ -78,43 +81,43 @@ internal static class ArchiKestrel {
}
}
internal static async Task Start() {
if (WebApplication != null) {
return;
}
ASF.ArchiLogger.LogGenericInfo(Strings.IPCStarting);
// Init history logger for /Api/Log usage
Logging.InitHistoryLogger();
WebApplication webApplication = await CreateWebApplication().ConfigureAwait(false);
internal static async Task Restart() {
await StateSemaphore.WaitAsync().ConfigureAwait(false);
try {
// Start the server
await webApplication.StartAsync().ConfigureAwait(false);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
await webApplication.DisposeAsync().ConfigureAwait(false);
await StopInternally().ConfigureAwait(false);
await StartInternally().ConfigureAwait(false);
} finally {
StateSemaphore.Release();
}
}
internal static async Task Start() {
if (IsRunning) {
return;
}
WebApplication = webApplication;
await StateSemaphore.WaitAsync().ConfigureAwait(false);
ASF.ArchiLogger.LogGenericInfo(Strings.IPCReady);
try {
await StartInternally().ConfigureAwait(false);
} finally {
StateSemaphore.Release();
}
}
internal static async Task Stop() {
if (WebApplication == null) {
if (!IsRunning) {
return;
}
await WebApplication.StopAsync().ConfigureAwait(false);
await WebApplication.DisposeAsync().ConfigureAwait(false);
await StateSemaphore.WaitAsync().ConfigureAwait(false);
WebApplication = null;
try {
await StopInternally().ConfigureAwait(false);
} finally {
StateSemaphore.Release();
}
}
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "PathString is a primitive, it's unlikely to be trimmed to the best of our knowledge")]
@@ -248,6 +251,11 @@ internal static class ArchiKestrel {
// Add support for websockets that we use e.g. in /Api/NLog
app.UseWebSockets();
// Add support for output caching
if (ASF.GlobalConfig?.OptimizationMode != GlobalConfig.EOptimizationMode.MinMemoryUsage) {
app.UseOutputCache();
}
// Add additional endpoints provided by plugins
foreach (IWebServiceProvider plugin in PluginsCore.ActivePlugins.OfType<IWebServiceProvider>()) {
try {
@@ -261,7 +269,11 @@ internal static class ArchiKestrel {
app.MapControllers();
// Add support for OpenAPI, responsible for automatic API documentation generation, this should be on the end, once we're done with API
app.MapOpenApi("/swagger/{documentName}/swagger.json");
IEndpointConventionBuilder openApi = app.MapOpenApi("/swagger/{documentName}/swagger.json");
if (ASF.GlobalConfig?.OptimizationMode != GlobalConfig.EOptimizationMode.MinMemoryUsage) {
openApi.CacheOutput();
}
// Add support for swagger UI, this should be after swagger, obviously
app.MapScalarApiReference(
@@ -311,7 +323,7 @@ internal static class ArchiKestrel {
if (knownNetworks != null) {
foreach (IPNetwork knownNetwork in knownNetworks) {
options.KnownNetworks.Add(knownNetwork);
options.KnownIPNetworks.Add(knownNetwork);
}
}
}
@@ -334,6 +346,11 @@ internal static class ArchiKestrel {
services.AddCors(static options => options.AddDefaultPolicy(static policyBuilder => policyBuilder.AllowAnyOrigin()));
}
// Add support for output caching
if (ASF.GlobalConfig?.OptimizationMode != GlobalConfig.EOptimizationMode.MinMemoryUsage) {
services.AddOutputCache();
}
// Add support for OpenAPI, responsible for automatic API documentation generation
services.AddOpenApi(
SharedInfo.ASF, static options => {
@@ -356,7 +373,7 @@ internal static class ArchiKestrel {
}
services.ConfigureHttpJsonOptions(static options => {
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerialierOptions : JsonUtilities.DefaultJsonSerialierOptions;
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerializerOptions : JsonUtilities.DefaultJsonSerializerOptions;
options.SerializerOptions.PropertyNamingPolicy = jsonSerializerOptions.PropertyNamingPolicy;
options.SerializerOptions.TypeInfoResolver = jsonSerializerOptions.TypeInfoResolver;
@@ -381,7 +398,7 @@ internal static class ArchiKestrel {
// Modify default JSON options
mvc.AddJsonOptions(static options => {
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerialierOptions : JsonUtilities.DefaultJsonSerialierOptions;
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerializerOptions : JsonUtilities.DefaultJsonSerializerOptions;
options.JsonSerializerOptions.PropertyNamingPolicy = jsonSerializerOptions.PropertyNamingPolicy;
options.JsonSerializerOptions.TypeInfoResolver = jsonSerializerOptions.TypeInfoResolver;
@@ -505,4 +522,43 @@ internal static class ArchiKestrel {
headers.CacheControl = cacheControl;
}
private static async Task StartInternally() {
if (WebApplication != null) {
return;
}
ASF.ArchiLogger.LogGenericInfo(Strings.IPCStarting);
// Init history logger for /Api/Log usage
Logging.InitHistoryLogger();
WebApplication webApplication = await CreateWebApplication().ConfigureAwait(false);
try {
// Start the server
await webApplication.StartAsync().ConfigureAwait(false);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
await webApplication.DisposeAsync().ConfigureAwait(false);
return;
}
WebApplication = webApplication;
ASF.ArchiLogger.LogGenericInfo(Strings.IPCReady);
}
private static async Task StopInternally() {
if (WebApplication == null) {
return;
}
await WebApplication.StopAsync().ConfigureAwait(false);
await WebApplication.DisposeAsync().ConfigureAwait(false);
WebApplication = null;
}
}

View File

@@ -24,7 +24,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Text.Json;
@@ -227,7 +226,7 @@ public sealed class BotController : ArchiController {
[EndpointSummary("Adds keys to redeem using BGR to given bot")]
[HttpPost("{botNames:required}/GamesToRedeemInBackground")]
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>>((int) HttpStatusCode.OK)]
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, OrderedDictionary<string, string>>>>((int) HttpStatusCode.OK)]
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) {
ArgumentException.ThrowIfNullOrEmpty(botNames);
@@ -243,21 +242,21 @@ public sealed class BotController : ArchiController {
return BadRequest(new GenericResponse(false, Strings.FormatBotNotFound(botNames)));
}
IOrderedDictionary validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground);
Bot.FilterGamesToRedeemInBackground(request.GamesToRedeemInBackground);
if (validGamesToRedeemInBackground.Count == 0) {
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsEmpty(nameof(validGamesToRedeemInBackground))));
if (request.GamesToRedeemInBackground.Count == 0) {
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsEmpty(nameof(request.GamesToRedeemInBackground))));
}
await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.AddGamesToRedeemInBackground(validGamesToRedeemInBackground)))).ConfigureAwait(false);
await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.AddGamesToRedeemInBackground(request.GamesToRedeemInBackground)))).ConfigureAwait(false);
Dictionary<string, IOrderedDictionary> result = new(bots.Count, Bot.BotsComparer);
Dictionary<string, OrderedDictionary<string, string>> result = new(bots.Count, Bot.BotsComparer);
foreach (Bot bot in bots) {
result[bot.BotName] = validGamesToRedeemInBackground;
result[bot.BotName] = request.GamesToRedeemInBackground;
}
return Ok(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(result));
return Ok(new GenericResponse<IReadOnlyDictionary<string, OrderedDictionary<string, string>>>(result));
}
[EndpointSummary("Provides input value to given bot for next usage")]

View File

@@ -70,10 +70,6 @@ public sealed class NLogController : ArchiController {
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsInvalid(nameof(lastAt))));
}
if (!Logging.LogFileExists) {
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsEmpty(nameof(SharedInfo.LogFile))));
}
string[]? lines = await Logging.ReadLogFileLines().ConfigureAwait(false);
if ((lines == null) || (lines.Length == 0)) {

View File

@@ -124,19 +124,19 @@ internal sealed class ApiAuthenticationMiddleware {
return (HttpStatusCode.OK, true);
}
if (ForwardedHeadersOptions.KnownNetworks.Count == 0) {
if (ForwardedHeadersOptions.KnownIPNetworks.Count == 0) {
return (HttpStatusCode.Forbidden, true);
}
if (clientIP.IsIPv4MappedToIPv6) {
IPAddress mappedClientIP = clientIP.MapToIPv4();
if (ForwardedHeadersOptions.KnownNetworks.Any(network => network.Contains(mappedClientIP))) {
if (ForwardedHeadersOptions.KnownIPNetworks.Any(network => network.Contains(mappedClientIP))) {
return (HttpStatusCode.OK, true);
}
}
return (ForwardedHeadersOptions.KnownNetworks.Any(network => network.Contains(clientIP)) ? HttpStatusCode.OK : HttpStatusCode.Forbidden, true);
return (ForwardedHeadersOptions.KnownIPNetworks.Any(network => network.Contains(clientIP)) ? HttpStatusCode.OK : HttpStatusCode.Forbidden, true);
}
if (!context.Request.Headers.TryGetValue(HeadersField, out StringValues passwords) && !context.Request.Query.TryGetValue("password", out passwords)) {

View File

@@ -23,7 +23,7 @@
using System;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.Integration;

View File

@@ -22,8 +22,9 @@
// limitations under the License.
using System;
using System.Globalization;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.Integration;
@@ -45,16 +46,16 @@ public sealed class SwaggerItemsMinMaxAttribute : CustomSwaggerAttribute {
public override void Apply(OpenApiSchema schema) {
ArgumentNullException.ThrowIfNull(schema);
if (schema.Items == null) {
if (schema.Items is not OpenApiSchema items) {
throw new InvalidOperationException(nameof(schema.Items));
}
if (BackingMinimum.HasValue) {
schema.Items.Minimum = BackingMinimum.Value;
items.Minimum = BackingMinimum.Value.ToString(CultureInfo.InvariantCulture);
}
if (BackingMaximum.HasValue) {
schema.Items.Maximum = BackingMaximum.Value;
items.Maximum = BackingMaximum.Value.ToString(CultureInfo.InvariantCulture);
}
}
}

View File

@@ -22,10 +22,9 @@
// limitations under the License.
using System;
using System.Text.Json.Nodes;
using JetBrains.Annotations;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.Integration;
@@ -36,10 +35,20 @@ public sealed class SwaggerSecurityCriticalAttribute : CustomSwaggerAttribute {
public override void Apply(OpenApiSchema schema) {
ArgumentNullException.ThrowIfNull(schema);
if (schema.Items is { Reference: null }) {
schema.Items.AddExtension(ExtensionName, new OpenApiBoolean(true));
} else {
schema.AddExtension(ExtensionName, new OpenApiBoolean(true));
JsonValue value = JsonValue.Create(true);
if (schema.Items != null) {
if (schema.Items is OpenApiSchema items) {
items.AddExtension(ExtensionName, new JsonNodeExtension(value));
} else if (schema.Items.Extensions != null) {
schema.Items.Extensions[ExtensionName] = new JsonNodeExtension(value);
} else {
throw new InvalidOperationException(nameof(schema.Items));
}
return;
}
schema.AddExtension(ExtensionName, new JsonNodeExtension(value));
}
}

View File

@@ -22,8 +22,9 @@
// limitations under the License.
using System;
using System.Globalization;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using SteamKit2;
namespace ArchiSteamFarm.IPC.Integration;
@@ -38,7 +39,7 @@ public sealed class SwaggerSteamIdentifierAttribute : CustomSwaggerAttribute {
public override void Apply(OpenApiSchema schema) {
ArgumentNullException.ThrowIfNull(schema);
schema.Minimum = new SteamID(MinimumAccountID, Universe, AccountType);
schema.Maximum = new SteamID(MaximumAccountID, Universe, AccountType);
schema.Minimum = new SteamID(MinimumAccountID, Universe, AccountType).ConvertToUInt64().ToString(CultureInfo.InvariantCulture);
schema.Maximum = new SteamID(MaximumAccountID, Universe, AccountType).ConvertToUInt64().ToString(CultureInfo.InvariantCulture);
}
}

View File

@@ -22,36 +22,50 @@
// limitations under the License.
using System;
using System.Linq;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using JetBrains.Annotations;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.Integration;
[PublicAPI]
public sealed class SwaggerValidValuesAttribute : CustomSwaggerAttribute {
private const string ExtensionName = "x-valid-values";
public int[]? ValidIntValues { get; init; }
public string[]? ValidStringValues { get; init; }
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We're not creating json values with non-primitive types")]
public override void Apply(OpenApiSchema schema) {
ArgumentNullException.ThrowIfNull(schema);
OpenApiArray validValues = [];
JsonArray validValues = [];
if (ValidIntValues != null) {
validValues.AddRange(ValidIntValues.Select(static type => new OpenApiInteger(type)));
foreach (int value in ValidIntValues) {
validValues.Add(JsonValue.Create(value));
}
}
if (ValidStringValues != null) {
validValues.AddRange(ValidStringValues.Select(static type => new OpenApiString(type)));
foreach (string value in ValidStringValues) {
validValues.Add(JsonValue.Create(value));
}
}
if (schema.Items is { Reference: null }) {
schema.Items.AddExtension("x-valid-values", validValues);
} else {
schema.AddExtension("x-valid-values", validValues);
if (schema.Items != null) {
if (schema.Items is OpenApiSchema items) {
items.AddExtension(ExtensionName, new JsonNodeExtension(validValues));
} else if (schema.Items.Extensions != null) {
schema.Items.Extensions[ExtensionName] = new JsonNodeExtension(validValues);
} else {
throw new InvalidOperationException(nameof(schema.Items));
}
return;
}
schema.AddExtension(ExtensionName, new JsonNodeExtension(validValues));
}
}

View File

@@ -29,7 +29,7 @@ using ArchiSteamFarm.IPC.Integration;
using ArchiSteamFarm.Storage;
using JetBrains.Annotations;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.OpenApi;
@@ -40,7 +40,6 @@ internal sealed class DocumentTransformer : IOpenApiDocumentTransformer {
ArgumentNullException.ThrowIfNull(document);
ArgumentNullException.ThrowIfNull(context);
document.Info ??= new OpenApiInfo();
document.Info.Title = $"{SharedInfo.AssemblyName} API";
document.Info.Version = SharedInfo.Version.ToString();
@@ -53,7 +52,7 @@ internal sealed class DocumentTransformer : IOpenApiDocumentTransformer {
document.Info.License.Url = new Uri(SharedInfo.LicenseURL);
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>(1);
document.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>(1);
document.Components.SecuritySchemes.Add(
nameof(GlobalConfig.IPCPassword), new OpenApiSecurityScheme {

View File

@@ -28,7 +28,7 @@ using System.Threading.Tasks;
using ArchiSteamFarm.Storage;
using JetBrains.Annotations;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.OpenApi;
@@ -45,13 +45,7 @@ internal sealed class OperationTransformer : IOpenApiOperationTransformer {
operation.Security.Add(
new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Id = nameof(GlobalConfig.IPCPassword),
Type = ReferenceType.SecurityScheme
}
},
new OpenApiSecuritySchemeReference(nameof(GlobalConfig.IPCPassword), context.Document),
[]
}
}

View File

@@ -23,14 +23,13 @@
using System;
using System.Globalization;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.IPC.Integration;
using JetBrains.Annotations;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace ArchiSteamFarm.IPC.OpenApi;
@@ -72,9 +71,9 @@ internal sealed class SchemaTransformer : IOpenApiSchemaTransformer {
schema.Format = "flags";
}
OpenApiObject definition = new();
JsonObject definition = new();
foreach (object? enumValue in context.JsonTypeInfo.Type.GetEnumValues()) {
foreach (object? enumValue in context.JsonTypeInfo.Type.GetEnumValuesAsUnderlyingType()) {
if (enumValue == null) {
throw new InvalidOperationException(nameof(enumValue));
}
@@ -95,41 +94,26 @@ internal sealed class SchemaTransformer : IOpenApiSchemaTransformer {
continue;
}
IOpenApiAny enumObject;
if (TryCast(enumValue, out int intValue)) {
enumObject = new OpenApiInteger(intValue);
} else if (TryCast(enumValue, out long longValue)) {
enumObject = new OpenApiLong(longValue);
} else if (TryCast(enumValue, out ulong ulongValue)) {
// OpenApi spec doesn't support ulongs as of now
enumObject = new OpenApiString(ulongValue.ToString(CultureInfo.InvariantCulture));
} else {
throw new InvalidOperationException(nameof(enumValue));
}
definition.Add(enumName, enumObject);
// OpenApi seems to support only int and long from underlying enum types: https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/integral-numeric-types
definition[enumName] = enumValue switch {
sbyte value => JsonValue.Create((int) value),
byte value => JsonValue.Create((int) value),
short value => JsonValue.Create((int) value),
ushort value => JsonValue.Create((int) value),
int value => JsonValue.Create(value),
uint value => JsonValue.Create((long) value),
long value => JsonValue.Create(value),
ulong value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
nint value when nint.Size <= 4 => JsonValue.Create((int) value),
nint value when nint.Size <= 8 => JsonValue.Create((long) value),
nint value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
nuint value when nuint.Size <= 4 => JsonValue.Create((long) value),
nuint value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
_ => throw new InvalidOperationException(nameof(enumValue))
};
}
schema.AddExtension("x-definition", definition);
}
private static bool TryCast<T>(object value, out T typedValue) where T : struct {
ArgumentNullException.ThrowIfNull(value);
try {
typedValue = (T) Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
return true;
} catch (InvalidCastException) {
typedValue = default(T);
return false;
} catch (OverflowException) {
typedValue = default(T);
return false;
}
schema.AddExtension("x-definition", new JsonNodeExtension(definition));
}
}
#pragma warning restore CA1812 // False positive, the class is used internally

View File

@@ -21,7 +21,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Specialized;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
@@ -33,9 +34,10 @@ namespace ArchiSteamFarm.IPC.Requests;
public sealed class BotGamesToRedeemInBackgroundRequest {
[Description("A string-string map that maps cd-key to redeem (key) to its name (value). Key in the map must be a valid and unique Steam cd-key. Value in the map must be a non-null and non-empty name of the key (e.g. game's name, but can be anything)")]
[JsonInclude]
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
[JsonRequired]
[Required]
public OrderedDictionary GamesToRedeemInBackground { get; private init; } = new();
public OrderedDictionary<string, string> GamesToRedeemInBackground { get; private init; } = new(StringComparer.OrdinalIgnoreCase);
[JsonConstructor]
private BotGamesToRedeemInBackgroundRequest() { }

View File

@@ -75,7 +75,6 @@ public sealed class ASFResponse {
internal ASFResponse(string buildVariant, bool canUpdate, GlobalConfig globalConfig, uint memoryUsage, DateTime processStartTime, Version version) {
ArgumentException.ThrowIfNullOrEmpty(buildVariant);
ArgumentNullException.ThrowIfNull(globalConfig);
ArgumentOutOfRangeException.ThrowIfZero(memoryUsage);
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(processStartTime, DateTime.UnixEpoch);
ArgumentNullException.ThrowIfNull(version);

View File

@@ -83,7 +83,9 @@
<value>{0} és invàlid!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>No s'ha definit cap agent. Potser t'ha passat per alt configurar l'ASF? Segueix la guia "posada en marxa" al wiki si tens dificultats.</value>
</data>
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
@@ -148,8 +150,13 @@
<data name="UpdateFinished" xml:space="preserve">
<value>Procés d'actualització finalitzat!</value>
</data>
<data name="UpdateNewVersionAvailable" xml:space="preserve">
<value>Disponible una nova versió de l'ASF! Sospesa una actualització!</value>
</data>
<data name="UpdateVersionInfo" xml:space="preserve">
<value>Versió local: {0} | Versió remota: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
@@ -188,26 +195,64 @@
<data name="CheckingOtherBadgePages" xml:space="preserve">
<value>Comprovant les altres pàgines d'insígnies...</value>
</data>
<data name="ChosenFarmingAlgorithm" xml:space="preserve">
<value>Algorisme de cultiu escollit: {0}</value>
<comment>{0} will be replaced by the name of chosen farming algorithm</comment>
</data>
<data name="Done" xml:space="preserve">
<value>Fet!</value>
</data>
<data name="GamesToIdle" xml:space="preserve">
<value>Hi ha un total de {0} jocs ({1} targetes) restants per cultivar (queden ~{2})...</value>
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinished" xml:space="preserve">
<value>Cultiu finalitzat!</value>
</data>
<data name="IdlingFinishedForGame" xml:space="preserve">
<value>Cultiu finalitzat: {0} ({1}) després de {2} de temps de joc!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingStatusForGame" xml:space="preserve">
<value>Estat del cultiu per {0} ({1}): Queden {2} targetes</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm</comment>
</data>
<data name="IdlingStopped" xml:space="preserve">
<value>Cultiu aturat!</value>
</data>
<data name="NothingToIdle" xml:space="preserve">
<value>No hi ha res per cultivar en aquest compte!</value>
</data>
<data name="NowIdling" xml:space="preserve">
<value>Cultivant en aquest moment: {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="NowIdlingList" xml:space="preserve">
<value>Cultivant en aquest moment: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="StillIdling" xml:space="preserve">
<value>Encara cultivant: {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="StillIdlingList" xml:space="preserve">
<value>Encara cultivant: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="StoppedIdling" xml:space="preserve">
<value>Cultiu aturat: {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="StoppedIdlingList" xml:space="preserve">
<value>Cultiu aturat: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="UnknownCommand" xml:space="preserve">
<value>Ordre desconeguda!</value>
</data>
@@ -228,10 +273,18 @@
</data>
<data name="BotAutomaticIdlingNowPaused" xml:space="preserve">
<value>El cultiu automàtic està en pausa!</value>
</data>
<data name="BotAutomaticIdlingNowResumed" xml:space="preserve">
<value>El cultiu automàtic s'ha reprès!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>El cultiu automàtic ja està en pausa!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>El cultiu automàtic ja s'ha reprès!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Connectat a Steam!</value>
</data>
@@ -305,7 +358,10 @@
<data name="TranslationIncomplete" xml:space="preserve">
<value>L'ASF intentarà utilitzar el teu idioma preferit, {0}, però aquesta traducció està completa en un {1}. Potser t'agradaria ajudar a completar o millorar la traducció de l'ASF a la teva llengua?</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="BotVersion" xml:space="preserve">
@@ -335,21 +391,35 @@
<data name="PluginLoaded" xml:space="preserve">
<value>{0} s'ha carregat correctament!</value>
<comment>{0} will be replaced by the name of the custom ASF plugin</comment>
</data>
<data name="PluginLoading" xml:space="preserve">
<value>Inicialitzant {0} V{1}...</value>
<comment>{0} will be replaced by the name of the custom ASF plugin, {1} will be replaced by its version</comment>
</data>
<data name="PleaseWait" xml:space="preserve">
<value>Si us plau, espera...</value>
</data>
<data name="EnterCommand" xml:space="preserve">
<value>Introdueix l'ordre: </value>
</data>
<data name="Executing" xml:space="preserve">
<value>Executant...</value>
</data>
<data name="InteractiveConsoleEnabled" xml:space="preserve">
<value>La consola interactiva ja està activa, prem "c" per entrar al mode d'introducció d'ordres.</value>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>Fent neteja dels arxius antics després de l'actualització...</value>
</data>
@@ -373,7 +443,9 @@
<data name="PatchingFiles" xml:space="preserve">
<value>Apedaçant els arxius de l'ASF...</value>
</data>

View File

@@ -584,7 +584,10 @@ StackTrace:
<value>Bot má level {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} aktiva</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Srovnávám položky ze Steamu, kolo #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -793,5 +796,8 @@ StackTrace:
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Vlastní zásuvné moduly byly zaregistrovány pro automatické aktualizace. Tým ASF by vám rád připomněl, že pro vaši vlastní bezpečnost byste měli povolit automatické aktualizace pouze od důvěryhodných stran. Pokud jste to nechtěli udělat, můžete aktualizace zásuvných modulů zakázat v globální konfiguraci ASF.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -584,7 +584,10 @@ Processens oppetid: {1}</value>
<value>Bot har niveau {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} aktiver</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Matcher Steam inventar, runde #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -684,21 +687,35 @@ Processens oppetid: {1}</value>
<value>Din krypteringsnøgle er for kort. Vi anbefaler at bruge en, der er mindst {0} bytes (tegn) lang.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>Du bruger {0} indstilling af {1} ejendom, men du har ikke angivet en brugerdefineret --cryptkey. Du kan eventuelt give en brugerdefineret --cryptkey for øget sikkerhed, hvis du gerne vil.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>Du bruger {0} indstilling af {1} ejendom, men du har ikke angivet en brugerdefineret --cryptkey. Dette går helt ud over beskyttelsen, da ASF er tvunget til at bruge sin egen (kendte) nøgle. Du bør give en brugerdefineret --cryptkey til at gøre brug af den sikkerhedsmæssige fordel, som denne indstilling.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>Du forsøger at køre ASF som administrator (root). Dette medfører en betydelig sikkerhedsrisiko for din maskine, og da ASF ikke kræver root-adgang for dens drift, vi anbefaler at køre det som ikke-administrator bruger hvis det er muligt.</value>
</data>
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
<value>Du kører ASF i ikke-understøttet miljø, leverer --ignore-unsupported-environment argument. Bemærk, at vi ikke tilbyder nogen form for støtte til dette scenarie, og du gør det helt på egen risiko. Du er blevet advaret.</value>
</data>
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
<value>Henter checksum fra den eksterne server...</value>
</data>
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
<value>Verificerer checksum af den downloadede binary mod den fra den eksterne server...</value>
</data>
<data name="ChecksumMissing" xml:space="preserve">
<value>Fjernserveren ved ikke noget om den udgivelse, vi opdaterer til. Denne situation er mulig, hvis udgivelsen blev offentliggjort for nylig - nægter at gå videre med opdateringsproceduren med det samme som en yderligere sikkerhedsforanstaltning.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Kunne ikke hente checksum af den downloadede binære - nægter at fortsætte med opdateringsproceduren på dette tidspunkt som en ekstra sikkerhedsforanstaltning.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Fjernserver har svaret med en anden tjeksum, dette kan indikere beskadiget download eller MITM angreb, nægter at fortsætte med opdateringsproceduren!</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>Retter ASF-filer...</value>
</data>
@@ -718,8 +735,13 @@ Processens oppetid: {1}</value>
<value>ASF kan ikke bruge app {0}, da den har regionsrelateret begrænsning for {1} der varer indtil {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Du forsøger at køre officielle {0} plugin i forkert matchet med ASF version: {1} (forventet {2}). Dette tyder på, at du gør noget forfærdeligt forkert, enten lave din opsætning eller forsyning - ignorer-ikke-understøttet miljø-argument, hvis du virkelig ved, hvad du laver.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Din ASF er styrtet for mange gange for nylig, og på grund af at processen initialisering er blevet deaktiveret. Enten undersøge, rette din opsætning, og fjern derefter ASF. udslæt fil fra din config mappe, eller forsyning -- ignore-unsupported-environment argument hvis du virkelig ved, hvad du laver.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Idling {0} ({1}) er deaktiveret, da spillet i øjeblikket er markeret som privat. Hvis du har til hensigt fra ASF til at idle det spil, så overvej at ændre dine privatlivsindstillinger.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
@@ -747,8 +769,14 @@ Processens oppetid: {1}</value>
<value>Fandt {0} plugin opdatering fra version {1} til {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Ingen aktiv tilgængelig for {0} plugin opdatering fra version {1} til {2}, dette betyder normalt, at opdateringen vil være tilgængelig på senere tidspunkt.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Intet aktiv kunne bestemmes for {0} plugin opdatering fra version {1} til {2}. Dette kan ske, hvis udgivelsen ikke er færdig endnu - hvis det bliver ved med at ske, bør du underrette plugin skaberen om det.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Opdaterer {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
@@ -765,6 +793,11 @@ Processens oppetid: {1}</value>
<value>{0} ({1}) plugin er blevet deaktiveret fra automatiske opdateringer, på trods af at den understøtter den funktion.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Tilpassede plugins er blevet registreret til automatiske opdateringer. ASF team vil gerne minde dig om, at for din egen sikkerhed, bør du kun aktivere automatiske opdateringer fra betroede parter. Hvis du ikke har til hensigt at gøre dette, kan du deaktivere plugin opdateringer i ASF global konfiguration.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -206,7 +206,7 @@ StackTrace:
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamParentalCode" xml:space="preserve">
<value>Bitte geben Sie Ihre Steam-Familienansicht-PIN ein: </value>
<value>Bitte geben Sie Ihre Steam-Familienansicht (PIN) ein: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamPassword" xml:space="preserve">
@@ -545,7 +545,7 @@ StackTrace:
<value>Zugriff verweigert!</value>
</data>
<data name="WarningPreReleaseVersion" xml:space="preserve">
<value>Sie verwenden eine Version, die neuer ist als die zuletzt veröffentlichte Version Ihres Aktualisierungskanals. Bitte bedenken Sie, dass Vorabversionen nur für Benutzer gedacht sind, die wissen wie man Fehler meldet, mit Problemen umgeht und Rückmeldung gibt es wird keine technische Unterstützung geben.</value>
<value>Sie verwenden eine Version, die neuer ist als die zuletzt veröffentlichte Version Ihres Aktualisierungskanals. Bitte bedenken Sie, dass Vorabversionen nur an Benutzer gerichtet sind, die bereit sind, Fehlern korrek zu melden, mit Problemen umgehen und Rückmeldungen geben es wird keine technische Unterstützung geben.</value>
</data>
<data name="BotStats" xml:space="preserve">
<value>Aktuelle Speichernutzung: {0} MB.

View File

@@ -584,7 +584,10 @@ StackTrace:
<value>Το bot βρίσκεται στο επίπεδο {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} assets</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Ταίριασμα στοιχείων Steam, γύρος #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -707,7 +710,9 @@ StackTrace:
<data name="ChecksumMissing" xml:space="preserve">
<value>Ο απομακρυσμένος διακομιστής δε γνωρίζει τίποτα σχετικά με την έκδοση στην οποία ενημερώνουμε. Αυτή η κατάσταση είναι πιθανή εάν η νέα έκδοση δημοσιεύτηκε πρόσφατα - Ως πρόσθετο μέτρο ασφαλείας το πρόγραμμα δε θα προβεί στην άμεση διαδικασία ενημέρωσης.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Αποτυχία λήψης του αθροίσματος ελέγχου του ληφθέντος δυαδικού - άρνηση να προχωρήσει με τη διαδικασία ενημέρωσης αυτή τη στιγμή ως πρόσθετο μέτρο ασφαλείας.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Ο απομακρυσμένος διακομιστής απάντησε με ένα διαφορετικό checksum, αυτό μπορεί να υποδεικνύει κατεστραμμένο download ή MITM attack, αρνούμενος να προχωρήσει με τη διαδικασία ενημέρωσης!</value>
</data>
@@ -730,9 +735,17 @@ StackTrace:
<value>Το ASF δεν είναι σε θέση να εκτελέσει την εφαρμογή {0} λόγω γεωγραφικού περιορισμού ως προς τη χώρα {1} που διαρκεί έως {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Προσπαθείτε να εκτελέσετε επίσημο πρόσθετο {0} σε αναντιστοιχία με την έκδοση ASF: {1} (αναμένεται {2}). Αυτό υποδηλώνει ότι κάνετε κάτι τρομερά λάθος, είτε διορθώσετε τις ρυθμίσεις σας είτε παρέχετε την επιλογή --ignore-unsupported-environment αν πραγματικά ξέρετε τι κάνετε.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Το ASF σας συνετρίβη πάρα πολλές φορές πρόσφατα και λόγω αυτού η έναρξη της διαδικασίας έχει απενεργοποιηθεί. Είτε διερευνήσετε, να διορθώσετε την εγκατάστασή σας και, στη συνέχεια, αφαιρέστε το ASF. rash file from your config directory, or supply --ignore-unsupported-environment argument if you really know what you're doing .</value>
</data>
<data name="IdlingGameNotPossiblePrivate" 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="WarningSkipping" xml:space="preserve">
<value>Παράλειψη: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
@@ -748,14 +761,35 @@ StackTrace:
<value>Δεν υπάρχει διαθέσιμη ενημέρωση για το πρόσθετο {0}: {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Νέα έκδοση {0} plugin είναι διαθέσιμη! Σκεφτείτε να ενημερώσετε τον εαυτό σας!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Βρέθηκε ενημέρωση του πρόσθετου {0} από την έκδοση {1} σε {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Ενημέρωση του πρόσθετου {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Επιτυχής ενημέρωση του {0} plugin, οι αλλαγές θα φορτωθούν στην επόμενη εκκίνηση του ASF.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>{0}/{1} plugin έχει καταχωρηθεί και ενεργοποιηθεί για αυτόματες ενημερώσεις.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>{0} ({1}) plugin έχει απενεργοποιηθεί από αυτόματες ενημερώσεις, παρά την υποστήριξη αυτής της δυνατότητας.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Τα προσαρμοσμένα πρόσθετα έχουν καταχωρηθεί για αυτόματες ενημερώσεις. Ομάδα ASF θα ήθελε να σας υπενθυμίσει ότι, για τη δική σας ασφάλεια, θα πρέπει να ενεργοποιήσετε την αυτόματη ενημέρωση μόνο από αξιόπιστα μέρη. Αν δεν προτίθεστε να το κάνετε αυτό, μπορείτε να απενεργοποιήσετε ενημερώσεις plugin σε γενικές ρυθμίσεις ASF.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -582,7 +582,10 @@ Tempo di attività: {1}</value>
<value>Il Bot ha il livello {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} risorse</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Elementi Corrispondenza Steam, round #{0}...</value>
<comment>{0} will be replaced by round number</comment>

View File

@@ -86,7 +86,10 @@ StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>Afsluiten met {0} foutcode!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Verzoek mislukt: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -185,7 +188,10 @@ StackTrace:
<value>Lokale versie: {0} | Externe versie: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceConfirmation" xml:space="preserve">
<value>Controleer je Steam mobiele app, je zou een login goedkeuringsmelding moeten hebben ontvangen. Typ Y als je de melding hebt ontvangen en goedgekeurd, N als je in plaats daarvan code wil invoeren: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>Voer de 2FA code in van je Steam authenticator app: </value>
<comment>Please note that this translation should end with space</comment>
@@ -577,7 +583,10 @@ Proces uptime: {1}</value>
<value>Bot is level {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} activa</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Steam-items matchen, ronde #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -677,7 +686,10 @@ Proces uptime: {1}</value>
<value>Uw encryptiesleutel is te kort. We raden u aan om er één te gebruiken die minstens {0} bytes (tekens) lang is.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>U gebruikt de instelling {0} van {1} eigenschap, maar u heeft geen aangepaste --cryptkey opgegeven. U kunt optioneel een aangepaste --cryptkey geven voor verhoogde beveiliging als u dat wilt.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>U gebruikt {0} instelling van {1} eigenschap, maar u heeft geen aangepaste --cryptkey opgegeven. Dit ondermijnt de bescherming volledig, omdat ASF zijn eigen (bekend) sleutel moet gebruiken. U moet een aangepaste --cryptkey opgeven om gebruik te maken van het beveiligingsvoordeel dat deze instelling biedt.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
@@ -697,7 +709,9 @@ Proces uptime: {1}</value>
<data name="ChecksumMissing" xml:space="preserve">
<value>Externe server weet niets over de release waar we naar bijwerken. Deze situatie is mogelijk als de vrijlating onlangs werd gepubliceerd - door als aanvullende veiligheidsmaatregel de actualiseringsprocedure onmiddellijk te weigeren.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Fout bij het ophalen van een checksum van de gedownloade binary - weigering om verder te gaan met de updateprocedure op dit moment als aanvullende beveiligingsmaatregel.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Externe server heeft geantwoord met een andere checksum, dit kan duiden op corrupte download of MITM aanval, de update procedure zal gestopt worden!</value>
</data>
@@ -716,22 +730,73 @@ Proces uptime: {1}</value>
<value>Je hebt geprobeerd om de betaalde functie {0} te gebruiken, maar je hebt geen geldige LicenseID ingesteld in de ASF global config. Controleer uw configuratie, aangezien de functie niet werkt zonder aanvullende details.</value>
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
</data>
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
<value>ASF kan app {0} niet spelen omdat het een regionale beperking heeft voor {1} land dat duurt tot {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>U probeert de officiële {0} plugin uit te voeren die niet overeenkomt met de ASF-versie: {1} (verwacht {2}) Dit geeft aan dat je iets vreselijk verkeerd doet. Repareer je instellingen of geef --ignore-unsupport-environment argument als je echt weet wat je doet.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Je ASF is de laatste tijd te vaak gecrasht en door het feit dat de initialisatie van de procedure is uitgeschakeld. Ofwel onderzoeken en repareer je installatie, en verwijder ASF. rash bestand vanuit uw config directory, of geef --ignore-unsupported-environment argument als je echt weet wat je aan het doen bent.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Landbouw {0} ({1}) is uitgeschakeld, omdat dat spel momenteel als privé is gemarkeerd. Als je van ASF van plan bent dat spel te bewerken, overweeg dan om de privacy-instellingen te veranderen.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Overslaan: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Controleren op plugin updates...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Controleren van update voor {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Geen update beschikbaar voor {0} plugin: {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Nieuwe versie van {0} plugin is beschikbaar! Overweeg uzelf te updaten!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Gevonden {0} plugin update van versie {1} naar {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Geen asset beschikbaar voor {0} plugin update van versie {1} naar {2}, meestal betekent dit dat de update op een later tijdstip beschikbaar zal zijn.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Er kon geen asset worden bepaald voor {0} plugin update van versie {1} naar {2}. Dit kan gebeuren als de release nog niet klaar is - als het blijft gebeuren, moet je de maker van de plugin hiervan op de hoogte stellen.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Bijwerken {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Bijwerken van de {0} plugin is geslaagd, de wijzigingen worden geladen op de volgende ASF lancering.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>{0}/{1} plugin is geregistreerd en geactiveerd voor automatische updates.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>{0} ({1}) plugin is uitgeschakeld voor automatische updates, ondanks het ondersteunen van deze functie.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Aangepaste plugins zijn geregistreerd voor automatische updates. Het ASF-team wil je eraan herinneren dat je voor je eigen veiligheid alleen automatische updates van vertrouwde partijen inschakelt. Als u niet van plan bent dit te doen, kunt u plugin updates uitschakelen in de ASF globale configuratie.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -185,62 +185,173 @@ StackTrace:
<data name="UpdateNewVersionAvailable" xml:space="preserve">
<value>Ny ASF-versjon er tilgjengelig! Vurder å oppdatere!</value>
</data>
<data name="UpdateVersionInfo" xml:space="preserve">
<value>Lokal versjon: {0} ART Fjernversjon: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceConfirmation" xml:space="preserve">
<value>Vennligst sjekk din Steam mobil app, du bør ha mottatt et varsel om innloggingsgodkjenning. Skriv Y hvis du har mottatt og godkjent varslen, N hvis du ønsker å legge til kode i stedet: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>Vennligst skriv inn 2FA-koden fra Steam-autentiseringsappen din: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamGuard" xml:space="preserve">
<value>Skriv inn SteamGuard auth kode som ble sendt til din e-post: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamLogin" xml:space="preserve">
<value>Vennligst skriv inn din Steam-innlogging: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamParentalCode" xml:space="preserve">
<value>Vennligst legg inn Steam foreldrekode: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamPassword" xml:space="preserve">
<value>Skriv inn ditt Steam-passord: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="WarningUnknownValuePleaseReport" xml:space="preserve">
<value>Mottatt ukjent verdi for {0}, vennligst rapport dette: {1}</value>
<comment>{0} will be replaced by object's name, {1} will be replaced by value for that object</comment>
</data>
<data name="IPCReady" xml:space="preserve">
<value>IPC server klar!</value>
</data>
<data name="IPCStarting" xml:space="preserve">
<value>Starter IPC server...</value>
</data>
<data name="BotAlreadyStopped" xml:space="preserve">
<value>Denne botten har allerede stoppet!</value>
</data>
<data name="BotNotFound" xml:space="preserve">
<value>Kunne ikke finne noen bot som heter {0}!</value>
<comment>{0} will be replaced by bot's name query (string)</comment>
</data>
<data name="BotStatusIdling" xml:space="preserve">
<value>Bot dyrkingsspill: {0} ({1}, {2} kort dråper igjen) fra totalt {3} spill ({4} kort) igjen til gården (~{5} igjen).</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm, {3} will be replaced by total number of games to farm, {4} will be replaced by total number of cards to farm, {5} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="BotStatusIdlingList" xml:space="preserve">
<value>Bot dyrker dyrkingsspill: {0} fra totalt {1} spill ({2} kort) igjen til gården (~{3} igjen).</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), {1} will be replaced by total number of games to farm, {2} will be replaced by total number of cards to farm, {3} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="CheckingFirstBadgePage" xml:space="preserve">
<value>Kontrollerer førstemblemsiden...</value>
</data>
<data name="CheckingOtherBadgePages" xml:space="preserve">
<value>Sjekker andre emblemsider...</value>
</data>
<data name="ChosenFarmingAlgorithm" xml:space="preserve">
<value>Valgt landbruks algoritme: {0}</value>
<comment>{0} will be replaced by the name of chosen farming algorithm</comment>
</data>
<data name="Done" xml:space="preserve">
<value>Utført!</value>
</data>
<data name="GamesToIdle" xml:space="preserve">
<value>Vi har totalt {0} spill ({1} kort) fra gården (~{2} gjenstår)...</value>
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinished" xml:space="preserve">
<value>Jordbruk er ferdig!</value>
</data>
<data name="IdlingFinishedForGame" xml:space="preserve">
<value>Ferdig med drift: {0} ({1}) etter {2} spilletid!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinishedForGames" xml:space="preserve">
<value>Fullførte landbruksspill: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="IdlingStatusForGame" xml:space="preserve">
<value>Gårdsstatus for {0} ({1}): {2} kort gjenstår</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm</comment>
</data>
<data name="IdlingStopped" xml:space="preserve">
<value>Jordbruk stoppet!</value>
</data>
<data name="IgnoredPermanentPauseEnabled" xml:space="preserve">
<value>Å ignorere denne forespørselen, siden permanent pause er aktivert!</value>
</data>
<data name="NothingToIdle" xml:space="preserve">
<value>Vi har ingen ting å dyrke på denne kontoen!</value>
</data>
<data name="NowIdling" xml:space="preserve">
<value>Nærliggende nå: {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="PlayingNotAvailable" xml:space="preserve">
<value>Å spille er utilgjengelig for øyeblikket, vi vil prøve igjen senere!</value>
</data>
<data name="StillIdling" xml:space="preserve">
<value>Fortsatt landing: {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="StillIdlingList" xml:space="preserve">
<value>Fortsatt landing: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="StoppedIdling" xml:space="preserve">
<value>Stoppet drift: {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="StoppedIdlingList" xml:space="preserve">
<value>Stoppet drift: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="UnknownCommand" xml:space="preserve">
<value>Ukjent kommando!</value>
</data>
<data name="WarningCouldNotCheckBadges" xml:space="preserve">
<value>Kunne ikke hente merker,informasjon, vi vil prøve igjen senere!</value>
</data>
<data name="WarningCouldNotCheckCardsStatus" xml:space="preserve">
<value>Kunne ikke sjekke kortstatus for: {0} ({1}), vi skal prøve igjen senere!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotAcceptingGift" xml:space="preserve">
<value>Godta gave: {0}...</value>
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
<value>Denne kontoen er begrenset, driftsprosessen er utilgjengelig inntil begrensningen er fjernet!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>ID: {0} Status: {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>ID: {0} APEXStatus: {1} eventuelle: {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>Denne botten kjører!</value>
</data>
<data name="BotAuthenticatorConverting" xml:space="preserve">
<value>Konverterer .maFile til ASF-format...</value>
</data>
<data name="BotAuthenticatorImportFinished" xml:space="preserve">
<value>Vellykket import av mobilautentisering!</value>
</data>
<data name="BotAuthenticatorToken" xml:space="preserve">
<value>2FA token: {0}</value>
<comment>{0} will be replaced by generated 2FA token (string)</comment>
</data>
<data name="BotAutomaticIdlingNowPaused" xml:space="preserve">
<value>Automatisk jordbruk har pauset!</value>
</data>
<data name="BotAutomaticIdlingNowResumed" xml:space="preserve">
<value>Automatisk jordbruk har gjenopptatt!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>Automatisk jordbruk er midlertidig stanset!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>Automatisk jordbruk er allerede gjenopptatt allerede!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Koblet til Steam!</value>
</data>
@@ -250,37 +361,85 @@ StackTrace:
<data name="BotDisconnecting" xml:space="preserve">
<value>Kobler fra...</value>
</data>
<data name="BotInstanceNotStartingBecauseDisabled" xml:space="preserve">
<value>Ikke start denne bot forekomsten fordi den er deaktivert i config filen!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>Mottok TwoFactorCodeMismatch feilkode {0} ganger på rad. Uansett er 2FA-opplysningene dine ikke lenger gyldig, eller så er klokken din ikke synkronisert, avbryt!</value>
<comment>{0} will be replaced by maximum allowed number of failed 2FA attempts</comment>
</data>
<data name="BotLoggedOff" xml:space="preserve">
<value>Logget av Steam: {0}</value>
<comment>{0} will be replaced by logging off reason (string)</comment>
</data>
<data name="BotLoggedOn" xml:space="preserve">
<value>Vellykket logget på som {0}.</value>
<comment>{0} will be replaced by steam ID (number)</comment>
</data>
<data name="BotLoggingIn" xml:space="preserve">
<value>Logger inn...</value>
</data>
<data name="BotLogonSessionReplaced" xml:space="preserve">
<value>Denne kontoen ser ut til å bli brukt i en annen ASF-forekomst, som er udefinert oppførsel, vil nekte å holde den kjørende!</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>Handelstilbud mislyktes!</value>
</data>
<data name="BotLootingMasterNotDefined" xml:space="preserve">
<value>Handelen kunne ikke sendes fordi det ikke er noen bruker med mestertillatelse definert!</value>
</data>
<data name="BotLootingSuccess" xml:space="preserve">
<value>Handelstilbudet ble sendt!</value>
</data>
<data name="BotSendingTradeToYourself" xml:space="preserve">
<value>Du kan ikke sende en handel til deg selv!</value>
</data>
<data name="BotNoASFAuthenticator" xml:space="preserve">
<value>Denne boten har ikke ASF 2FA aktivert! Har du glemt å importere autentiseringen din som ASF 2FA?</value>
</data>
<data name="BotNotConnected" xml:space="preserve">
<value>Denne robot-forekomsten er ikke tilkoblet!</value>
</data>
<data name="BotNotOwnedYet" xml:space="preserve">
<value>Ikke eid ennå: {0}</value>
<comment>{0} will be replaced by query (string)</comment>
</data>
<data name="BotOwnedAlreadyWithName" xml:space="preserve">
<value>Egnet 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="BotPointsBalance" xml:space="preserve">
<value>Poengsaldo: {0}</value>
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Rammegrensen overskredet, vi vil prøve på nytt etter {0} med kjøling...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Kobler til på nytt...</value>
</data>
<data name="BotRemovedExpiredLoginKey" xml:space="preserve">
<value>Fjernet utgått innloggingsnøkkel!</value>
</data>
<data name="BotStatusNotIdling" xml:space="preserve">
<value>Bot gir ikke noe bruk.</value>
</data>
<data name="BotStatusLimited" xml:space="preserve">
<value>Bot er begrenset og kan ikke slippe alle kort gjennom akk.</value>
</data>
<data name="BotStatusConnecting" xml:space="preserve">
<value>Bot kobler til Steam-nettverket.</value>
</data>
<data name="BotStatusNotRunning" xml:space="preserve">
<value>Bot kjører ikke.</value>
</data>
<data name="BotStatusPaused" xml:space="preserve">
<value>Bot er satt på pause eller kjører i manuell modus.</value>
</data>
<data name="BotStatusPlayingNotAvailable" xml:space="preserve">
<value>Bot er i bruk for øyeblikket.</value>
</data>
<data name="BotUnableToLogin" xml:space="preserve">
<value>Kan ikke logge inn på Steam: {0}/{1}</value>
<comment>{0} will be replaced by failure reason (string), {1} will be replaced by extended failure reason (string)</comment>
@@ -297,103 +456,320 @@ StackTrace:
<value>Mislyktes på grunn av feil: {0}</value>
<comment>{0} will be replaced by failure reason (string)</comment>
</data>
<data name="BotConnectionLost" xml:space="preserve">
<value>Tilkobling til Steam nettverk tapt. Gjenopprettes...</value>
</data>
<data name="BotAccountFree" xml:space="preserve">
<value>Kontoen er ikke lenger brukt: jordbruksprosessen gjenopptatt!</value>
</data>
<data name="BotAccountOccupied" xml:space="preserve">
<value>Konto er for øyeblikket i bruk: ASF vil gjenoppta oppdrett når det er gratis...</value>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>Kobler til...</value>
</data>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Kan ikke koble fra klienten. Forlat denne botten instans!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stopper...</value>
</data>
<data name="ErrorBotConfigInvalid" xml:space="preserve">
<value>Din bot konfigurasjon er ugyldig. Kontroller innholdet i {0} og prøv igjen!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorDatabaseInvalid" xml:space="preserve">
<value>Vedvarende database kunne ikke lastes, hvis problemet vedvarer, fjern {0} for å gjenopprette databasen!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="Initializing" xml:space="preserve">
<value>Initialiserer {0}...</value>
<comment>{0} will be replaced by service name that is being initialized</comment>
</data>
<data name="WarningPrivacyPolicy" xml:space="preserve">
<value>Se gjennom seksjonen om personvern på wikien hvis du er bekymret for hva ASF faktisk gjør!</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>Det ser ut til at det er din første lansering av programmet, velkommen!</value>
</data>
<data name="ErrorInvalidCurrentCulture" xml:space="preserve">
<value>Den angitte nålkulturen er ugyldig, ASF vil fortsette å kjøre med standarden!</value>
</data>
<data name="TranslationIncomplete" xml:space="preserve">
<value>ASF vil forsøke å bruke {0} kulturen, men oversettelse til det språket er bare {1} fullført. Kanskje du kan hjelpe oss med å forbedre ASF-oversettelsen for ditt språk?</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>Jordbruk av {0} ({1}) er midlertidig deaktivert, da ASF ikke kan spille det akkurat nå.</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 oppdaget ID-feil for {0} ({1}), og vil i stedet bruke ID til {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} V{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>Denne kontoen er låst, jordbruksprosessen er permanent utilgjengelig!</value>
</data>
<data name="BotStatusLocked" xml:space="preserve">
<value>Bot er låst og kan ikke slippe noen kort gjennom innhøsting.</value>
</data>
<data name="ErrorFunctionOnlyInHeadlessMode" xml:space="preserve">
<value>Denne funksjonen er bare tilgjengelig i headless modus!</value>
</data>
<data name="BotOwnedAlready" xml:space="preserve">
<value>Egne allerede: {0}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Ingen tilgang!</value>
</data>
<data name="WarningPreReleaseVersion" xml:space="preserve">
<value>Du bruker en versjon som er nyere enn den som ble utgitt nyeste versjonen for oppgraderingskanalen din. Vær oppmerksom på at forhåndslanseringsversjoner er ment for brukere som vet hvordan du skal rapportere feil, behandle problemer og gi tilbakemelding ingen teknisk støtte vil bli gitt.</value>
</data>
<data name="BotStats" xml:space="preserve">
<value>Gjeldende minnebruk: {0} MB.
prosess oppgang: {1}</value>
<comment>{0} will be replaced by number (in megabytes) of memory being used, {1} will be replaced by translated TimeSpan string (such as "25 minutes"). Please note that this string should include newlines for formatting.</comment>
</data>
<data name="BotOwnsOverviewPerGame" xml:space="preserve">
<value>{0}/{1} bots allerede eier spill {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>Oppdaterer pakker data...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>Bruk av {0} er foreldet og vil bli fjernet i fremtidige versjoner av programmet. Vennligst bruk {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>Akseptert donasjons handel: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
<value>Workaround for {0} bug ble utløst.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
<data name="TargetBotNotConnected" xml:space="preserve">
<value>Target bot instans er ikke tilkoblet!</value>
</data>
<data name="BotWalletBalance" xml:space="preserve">
<value>Lommeboksaldo: {0} {1}</value>
<comment>{0} will be replaced by wallet balance value, {1} will be replaced by currency name</comment>
</data>
<data name="BotHasNoWallet" xml:space="preserve">
<value>Bot har ingen lommebok.</value>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} ressurser</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="DoneActivelyMatchingItems" xml:space="preserve">
<value>Samsvarer med Steam-elementer, fra omkring #{0}.</value>
<comment>{0} will be replaced by round number</comment>
</data>
<data name="ErrorAborted" xml:space="preserve">
<value>Avbrutt!</value>
</data>
<data name="WarningExcessiveBotsCount" xml:space="preserve">
<value>Du har flere personlige bot kontoer enn vår øvre anbefalte grense ({0}). Vær oppmerksom på at dette oppsettet ikke støttes og kan forårsake forskjellige Steam-relaterte problemer, inkludert kontosuspensjoner. Sjekk ut FAQ for mer detaljer.</value>
<comment>{0} will be replaced by our maximum recommended bots count (number)</comment>
</data>
<data name="PluginLoading" xml:space="preserve">
<value>Laster {0} V{1}...</value>
<comment>{0} will be replaced by the name of the custom ASF plugin, {1} will be replaced by its version</comment>
</data>
<data name="NothingFound" xml:space="preserve">
<value>Ingenting funnet!</value>
</data>
<data name="PluginsWarning" xml:space="preserve">
<value>Du har lastet en eller flere tilpassede plugins inn i ASF. Siden vi ikke kan tilby støtte for modded oppsett, Ta kontakt med de passende utviklerne av programtilleggene du bestemte deg for å bruke i tilfelle problemer oppstår.</value>
</data>
<data name="PleaseWait" xml:space="preserve">
<value>Vennligst vent...</value>
</data>
<data name="EnterCommand" xml:space="preserve">
<value>Angi kommando: </value>
</data>
<data name="Executing" xml:space="preserve">
<value>Utfører...</value>
</data>
<data name="InteractiveConsoleEnabled" xml:space="preserve">
<value>Interaktiv konsoll er nå aktiv, skriv 'c' for å angi kommando modus.</value>
</data>
<data name="BotGamesToRedeemInBackgroundCount" xml:space="preserve">
<value>Bot har {0} spill igjen i sin bakgrunnkø.</value>
<comment>{0} will be replaced by remaining number of games in BGR's queue</comment>
</data>
<data name="ErrorSingleInstanceRequired" xml:space="preserve">
<value>ASF-prosessen kjører allerede for denne arbeidsmappen, avbryt !</value>
</data>
<data name="BotHandledConfirmations" xml:space="preserve">
<value>{0} ble håndtert bekreftelsene!</value>
<comment>{0} will be replaced by number of confirmations</comment>
</data>
<data name="BotExtraIdlingCooldown" xml:space="preserve">
<value>Venter på {0} for å sikre at vi er fri til å starte gård...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "1 minute")</comment>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>Rydder opp gamle filer etter oppdatering...</value>
</data>
<data name="BotGeneratingSteamParentalCode" xml:space="preserve">
<value>Genererer Steam foreldrekode, dette kan ta en stund, vurder å sette den i config i steden...</value>
</data>
<data name="IPCConfigChanged" xml:space="preserve">
<value>IPC konfigurasjonen har blitt endret!</value>
</data>
<data name="BotTradeOfferResult" xml:space="preserve">
<value>Handelstilbudet {0} er bestemt til å være {1} på grunn av {2}.</value>
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
</data>
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
<value>Mottok feil passord feilkode {0} ganger på rad. Passordet for denne kontoen vil mest sannsynlig bli galt, avbryt!</value>
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
</data>
<data name="Result" xml:space="preserve">
<value>Resultat: {0}</value>
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
</data>
<data name="WarningUnsupportedEnvironment" xml:space="preserve">
<value>Du prøver å kjøre {0} variant av ASF i et miljø som ikke støttes: {1}. Gi tilgang - ignorert miljø argument hvis du virkelig vet hva du gjør.</value>
</data>
<data name="WarningUnknownCommandLineArgument" xml:space="preserve">
<value>Ukjent kommandolinje-argument: {0}</value>
<comment>{0} will be replaced by unrecognized command that has been provided</comment>
</data>
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
<value>Mappe for konfigurasjon ble ikke funnet, avbryt !</value>
</data>
<data name="BotIdlingSelectedGames" xml:space="preserve">
<value>Spiller valgte {0}: {1}</value>
<comment>{0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen</comment>
</data>
<data name="AutomaticFileMigration" xml:space="preserve">
<value>{0} config filen vil bli overført til siste syntaks...</value>
<comment>{0} will be replaced with the relative path to the affected config file</comment>
</data>
<data name="WarningTooShortCryptKey" xml:space="preserve">
<value>Din krypteringsnøkkel er for kort. Vi anbefaler å bruke en som er minst {0} byte (tegn) lang.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>Du bruker {0} innstillinger for {1} egenskaper, men du ga ikke en tilpasset --cryptkey. Du kan eventuelt stille inn en tilpasset --cryptkey for økt sikkerhet hvis du ønsker det.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>Du bruker {0} innstillinger for {1} egenskaper, men du ga ikke en tilpasset --cryptkey. Dette har med seg beskyttelsen helt, ettersom ASF tvinges til å bruke sin egen (kjent) nøkkel. Du bør gi en egendefinert --kryptkey for å gjøre bruk av sikkerhetsfordeler tilbudt av denne innstillingen.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>Du prøver å kjøre ASF som administrator (root). Det gir en betydelig sikkerhetsrisiko for maskinen din, og siden ASF ikke krever root-tilgang for maskinen, vi anbefaler å kjøre det som ikke-administrator bruker hvis mulig.</value>
</data>
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
<value>Du kjører ASF i miljøet som ikke er støttet levere --ignore-unsupported-environment argument. Vær oppmerksom på at vi ikke tilbyr noen form for støtte for dette scenarioet og gjør det helt på egen risiko. Du har blitt advart.</value>
</data>
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
<value>Henter checksum fra ekstern server...</value>
</data>
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
<value>Bekrefter kontrollsummen av de nedlastede binærfilene mot serveren fra serveren...</value>
</data>
<data name="ChecksumMissing" xml:space="preserve">
<value>Ekstern server vet ikke noe om utgivelsen vi oppdaterer til. Denne situasjonen er mulig dersom utgivelsen nylig ble publisert, nekter å gå videre med oppdateringen umiddelbart som et ekstra sikkerhetstiltak.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Kunne ikke hente kontrollsummen av det nedlastede binærsystemet - nekte å fortsette med oppdateringsprosedyren på dette tidspunktet som et ytterligere sikkerhetstiltak.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Fjerntjeneren har svart med en annen sjekk, dette kan indikere ødelagte nedlastinger eller MITM angrep, nekter å fortsette med oppdateringsprosedyren!</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>mønstrer ASF-filer...</value>
</data>
<data name="UserInputCryptkey" xml:space="preserve">
<value>Vennligst skriv inn din krypteringsnøkkel: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="ErrorIPNotBanned" xml:space="preserve">
<value>IP-adressen {0} er ikke utestengt!</value>
<comment>{0} will be replaced by an IP address which was requested to be unbanned from using IPC</comment>
</data>
<data name="WarningNoLicense" xml:space="preserve">
<value>Du har forsøkt å bruke betalt funksjon {0} , men du har ikke en gyldig LicenseID satt i ASF-global konfigurasjonen. Vennligst se gjennom din konfigurasjon, siden funksjonen ikke fungerer uten flere detaljer.</value>
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
</data>
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
<value>ASF kan ikke spille app {0} fordi den har regionrelatert begrensning for {1} land som varer frem til {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Du prøver å kjøre offisiell {0} -plugin i feil matchet med ASF-versjon: {1} (forventet {2}). Dette foreslår at du gjør noe forferdelig feil, enten fikser ditt oppsett eller leveranse - ignorert-ikke støttede omgivelser hvis du vet hva du gjør.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>ASF har krasjet for mange ganger den siste tiden, og på grunn av at prosessinitialisering er deaktivert. Enten undersøk, reparer oppsettet ditt, deretter fjern ASF. utslett filen fra konfigurasjonsmappen, eller tillat --ignorer et argument som ikke støttes hvis du virkelig vet hva du gjør.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Jordbruk {0} ({1}) er deaktivert, siden spillet er merket som privat. Hvis du har tenkt fra ASF til gård som spillet, bør du vurdere å endre personverninnstillingene.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Skilter: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Ser etter tilleggsoppdateringer...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Sjekker oppdatering for {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Ingen oppdatering tilgjengelig for {0} utvidelsen: {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Ny {0} plugin versjon tilgjengelig! Vurder å oppdatere deg selv!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Fant {0} oppdatering for programtillegg fra versjon {1} til {2}-...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Ingen ressurser tilgjengelig for {0} plugin oppdatering fra versjon {1} til {2}, betyr dette vanligvis at den vil være tilgjengelig senere.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Ingen elementer kunne bli bestemt for {0} plugin oppdatering fra versjon {1} til {2}. Dette kan skje hvis utgivelsen ikke er ferdig ennå - hvis den fortsetter å skje, må du varsle skaperen av plugin om det.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Oppdaterer {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Oppdatering av {0} utvidelsen har lyktes, endringene vil bli lastet ved neste ASF lansering.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>{0}/{1} programtillegg er registrert og aktivert for automatiske oppdateringer.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>{0} ({1}) plugin har blitt deaktivert fra automatiske oppdateringer, til tross for støttende slik funksjon.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Egendefinerte programtillegg er registrert for automatiske oppdateringer. ASF-teamet vil minne deg på at for din egen sikkerhet bør du aktivere automatiske oppdateringer bare fra parter du stoler på. Hvis du ikke har tenkt å gjøre dette, kan du deaktivere plugin-oppdateringer i ASF-global konfigurasjon.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -584,7 +584,10 @@ Tempo de execução: {1}</value>
<value>O bot está a nível {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} ativos</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Correspondendo itens da Steam, ronda #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -707,7 +710,9 @@ Tempo de execução: {1}</value>
<data name="ChecksumMissing" xml:space="preserve">
<value>O servidor remoto não sabe nada sobre a versão para a qual estamos a atualizar. Esta situção é possível se a versão foi publicada recentemente - a recusar prosseguir com a atualização imediatamente como uma medida de segurança adicional.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Falha ao buscar a soma de verificação do binário baixado - recusando-se a prosseguir com o procedimento de atualização neste momento como uma medida de segurança adicional.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>O servidor remoto respondeu com uma 'checksum' diferente, isto pode indicar um download corrompido ou um ataque MITM, recusando prosseguir com a atualização!</value>
</data>
@@ -726,22 +731,73 @@ Tempo de execução: {1}</value>
<value>Tentou usar uma funcionalidade paga {0}, mas não tem uma LicenseID válida definida na configuração global do ASF. Por favor, reveja a sua configuração, pois as funcionalidades não funcionarão sem detalhes adicionais.</value>
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
</data>
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
<value>O ASF não pode jogar o app {0} pois tem restrições relacionadas à região para o país {1} que dura até o {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Você está tentando executar o plugin oficial {0} com uma versão incompatível com o ASF: {1} (esperado {2}). Isso sugere que você está fazendo algo terrivelmente errado, corrija sua configuração ou forneça o argumento --ignore-unported-environment se você realmente sabe o que está fazendo.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Seu ASF travou há muitas vezes recentemente, e devido a isso a inicialização do processo ter sido desativada. Investige, corrija sua configuração e, em seguida, remova o ASF. arquivo com erro na pasta config ou fornecer o argumento --ignore-unported-environment se você realmente souber o que está fazendo.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>A coleta {0} ({1}) está desativada, pois esse jogo está marcado como privado. Se você pretende que o ASF colete esse jogo, considere alterar suas configurações de privacidade.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Pulando: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Procurando por atualizações dos plugins...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Verificando atualizações para o plugin {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Nenhuma atualização disponível para o plugin {0} : {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Nova versão do plugin {0} está disponível! Considere atualizá-lo!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Encontrada atualização do plugin {0} da versão {1} para {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Nenhum ativo disponível para atualização do plugin {0} da versão {1} para {2}, isso geralmente significa que a atualização estará disponível mais tarde.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Nenhum ativo pode ser determinado para atualização do plugin {0} da versão {1} para {2}. Isso pode acontecer se a versão ainda não estiver concluída - se isso continuar acontecendo, você deve notificar o criador do plugin sobre isso.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Atualizando plugin {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Atualização do plugin {0} teve sucesso, as alterações serão carregadas na próxima inicialização do ASF.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>Plugin {0}/{1} foi registrado e habilitado para atualizações automáticas.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>O plugin {0} ({1}) foi desativado nas atualizações automáticas, apesar de suportar este recurso.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Plugins personalizados foram registrados para atualizações automáticas. A equipe do ASF quer lembrá-lo de que, para sua própria segurança, você deve ativar atualizações automáticas somente de grupos confiáveis. Se você não pretendia fazer isso, você pode desabilitar as atualizações do plugin na configuração global do ASF.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -585,7 +585,10 @@ Processens drifttid: {1}</value>
<value>Bot har nivå {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} tillgångar</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Matchar Steam-föremål, runda #{0}...</value>
<comment>{0} will be replaced by round number</comment>

View File

@@ -78,7 +78,7 @@
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>ASF V{0}, çekirdek günlük modülü başlatılmadan önce kritik bir hata ile karşılaştı!</value>
<value>ASF V{0}, çekirdek günlük modülü başlatılmadan önce kritik bir hatayla karşılaştı!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
@@ -96,7 +96,7 @@ Yığın Kaydı:
<comment>{0} will be replaced by URL of the request</comment>
</data>
<data name="ErrorGlobalConfigNotLoaded" xml:space="preserve">
<value>Genel yapılandırma yüklenemedi. {0} 'ın var olduğundan ve geçerli olduğundan emin olun! Kafanız karıştıysa wiki'deki 'kurulum' kılavuzunu izleyin.</value>
<value>Genel yapılandırma yüklenemedi. Lütfen {0} dosyasının mevcut ve geçerli olduğundan emin olun! Emin değilseniz Wiki'deki 'Kurulum' rehberini takip edebilirsiniz.</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorIsInvalid" xml:space="preserve">
@@ -104,7 +104,7 @@ Yığın Kaydı:
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>Hiçbir bot tanımlanmamıştır. ASF'nizi yapılandırmayı unuttunuz mu? Kafanız karıştıysa wiki'deki 'kurulum' kılavuzunu izleyin.</value>
<value>Hiçbir bot tanımlanmamış. ASF'yi yapılandırmayı unuttunuz mu? Emin değilseniz Wiki'deki 'Kurulum' rehberini takip edebilirsiniz.</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} boş!</value>
@@ -125,10 +125,10 @@ Yığın Kaydı:
<value>Şu anda çalışan sürüme ait hiçbir dosya olmadığı için güncelleme işlemine devam edilemedi! Bu sürüme otomatik güncelleme yapmak mümkün değil.</value>
</data>
<data name="ErrorUpdateNoAssets" xml:space="preserve">
<value>Bu sürüm herhangi bir varlık içermediğinden güncellemeye devam edilemedi!</value>
<value>Bu sürüm herhangi bir varlık içermediği için güncellemeye devam edilemiyor!</value>
</data>
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
<value>Kullanıcı girişi için bir istek alındı, ancak işlem başsız modunda çalışıyor!</value>
<value>Kullanıcı girişi talep edildi ancak ASF arayüzsüz modda çalışıyor!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>Çıkılıyor...</value>
@@ -176,7 +176,7 @@ Yığın Kaydı:
<value>Yeni sürüm kontrol ediliyor...</value>
</data>
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
<value>Yeni sürüm indiriliyor: {0} ({1} MB)... Beklerken, yapılan işi takdir ediyorsanız bağış yapmayı düşünün! :)</value>
<value>Yeni sürüm indiriliyor: {0} ({1} MB)... Beklerken, emeğimize saygı duyuyorsanız bize bağış yapmayı düşünebilirsiniz! :)</value>
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
</data>
<data name="UpdateFinished" xml:space="preserve">
@@ -206,7 +206,7 @@ Yığın Kaydı:
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamParentalCode" xml:space="preserve">
<value>Lütfen Steam aile kodunu girin: </value>
<value>Lütfen Steam Aile pini kodunuzu girin: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamPassword" xml:space="preserve">
@@ -284,11 +284,11 @@ Yığın Kaydı:
<value>Bu hesapta çalıştırılacak hiçbir şey bulamadık!</value>
</data>
<data name="NowIdling" xml:space="preserve">
<value>Şu an çalıştırılan: {0} ({1})</value>
<value>Şu anda oynanıyor: {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="NowIdlingList" xml:space="preserve">
<value>Şu an çalıştırılan: {0}</value>
<value>Şu anda oynanıyor: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="PlayingNotAvailable" xml:space="preserve">
@@ -314,10 +314,10 @@ Yığın Kaydı:
<value>Bilinmeyen komut!</value>
</data>
<data name="WarningCouldNotCheckBadges" xml:space="preserve">
<value>Rozetlerin bilgilerini alamadık, daha sonra tekrar deneyeceğiz!</value>
<value>Rozet bilgileri alınamadı, daha sonra tekrar denenecek!</value>
</data>
<data name="WarningCouldNotCheckCardsStatus" xml:space="preserve">
<value>{0} ({1}) için kartların durumunu kontrol edemedik, daha sonra tekrar deneyeceğiz!</value>
<value>{0} ({1}) için kart durumu kontrol edilemedi, daha sonra tekrar denenecek!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotAcceptingGift" xml:space="preserve">
@@ -325,7 +325,7 @@ Yığın Kaydı:
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
<value>Bu hesap sınırlıdır, kısıtlama kaldırılana kadar kart düşürmek mümkün değil!</value>
<value>Bu hesap kısıtlıdır, kısıtlama kaldırılana kadar kart düşürmek mümkün değil!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>ID: {0} | Durum: {1}</value>
@@ -339,7 +339,7 @@ Yığın Kaydı:
<value>Bu bot zaten çalışıyor!</value>
</data>
<data name="BotAuthenticatorConverting" xml:space="preserve">
<value>.maFile dosya türü ASF'nin kullanacağı dosya türüne dönüştürülüyor...</value>
<value>.maFile dosyası ASF'nin formatına dönüştürülüyor...</value>
</data>
<data name="BotAuthenticatorImportFinished" xml:space="preserve">
<value>Mobil kimlik doğrulayıcısının aktarılması başarıyla tamamlandı!</value>
@@ -355,10 +355,10 @@ Yığın Kaydı:
<value>Otomatik çalıştırma sürdürülüyor!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>Otomatik kart düşürme zaten duraklatıldı!</value>
<value>Otomatik kart düşürme zaten duraklatılmış!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>Otomatik çalıştırma zaten devam ediyor!</value>
<value>Otomatik kart düşürme zaten devam ediyor!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Steam'e bağlandı!</value>
@@ -373,7 +373,7 @@ Yığın Kaydı:
<value>Bu bot örneği, yapılandırma dosyasında devre dışı bırakıldığından başlatılmıyor!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>Üst üste {0} kez 2AD Kodu Uyuşmazlığı hata kodu alındı (TwoFactorCodeMismatch). Ya 2AD kodlarınız artık geçerli değil ya da cihazınızın saati yanlış, iptal ediliyor!</value>
<value>Giriş sırasında {0} kez 'TwoFactorCodeMismatch' hatası alındı. Ya 2AD kodlarınız geçersiz ya da cihazınızın saati yanlış. İşlem iptal ediliyor!</value>
<comment>{0} will be replaced by maximum allowed number of failed 2FA attempts</comment>
</data>
<data name="BotLoggedOff" xml:space="preserve">
@@ -388,13 +388,13 @@ Yığın Kaydı:
<value>Giriş yapılıyor...</value>
</data>
<data name="BotLogonSessionReplaced" xml:space="preserve">
<value>Bu hesap başka bir ASF işleminde kullanılıyor gibi gözüküyor ve ASF bu durumda ne yapacağını bilmiyor, o yüzden başlatılamıyor!</value>
<value>Bu oturum başka bir konumdan değiştirildi. Büyük ihtimalle bu bot, başka bir ASF örneğinde de çalışıyor. ASF bu durumda kararsız çalışabileceğinden durduruluyor.</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>Takas teklifi başarısız oldu!</value>
</data>
<data name="BotLootingMasterNotDefined" xml:space="preserve">
<value>Ana Steam hesabınız tanımlanmadığı için takas teklifi gönderilemedi!</value>
<value>Ana hesabınız tanımlanmadığı için takas teklifi gönderilemedi!</value>
</data>
<data name="BotLootingSuccess" xml:space="preserve">
<value>Takas teklifi başarıyla gönderildi!</value>
@@ -413,7 +413,7 @@ Yığın Kaydı:
<comment>{0} will be replaced by query (string)</comment>
</data>
<data name="BotOwnedAlreadyWithName" xml:space="preserve">
<value>Zaten buna sahip: {0} | {1}</value>
<value>Zaten şuna sahip: {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="BotPointsBalance" xml:space="preserve">
@@ -421,7 +421,7 @@ Yığın Kaydı:
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>İstek sınırııldı, {0} bekledikten sonra yeniden deneyeceğiz...</value>
<value>İstek sınırııldı, {0} sonra yeniden denenecek...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
@@ -439,7 +439,7 @@ Yığın Kaydı:
<value>Süresi dolmuş giriş anahtarı kaldırıldı!</value>
</data>
<data name="BotStatusNotIdling" xml:space="preserve">
<value>Bot hiçbir şeyi çalıştırmıyor.</value>
<value>Bot herhangi bir oyun oynamıyor.</value>
</data>
<data name="BotStatusLimited" xml:space="preserve">
<value>Bot sınırlı durumda ve çalışarak kart düşüremez.</value>
@@ -476,26 +476,26 @@ Yığın Kaydı:
<value>Steam Ağı bağlantısı kaybedildi. Yeniden bağlanıyor...</value>
</data>
<data name="BotAccountFree" xml:space="preserve">
<value>Hesap artık meşgul değil, çalıştırılmaya devam ediliyor!</value>
<value>Hesap artık meşgul değil, kart düşürmeye devam ediliyor!</value>
</data>
<data name="BotAccountOccupied" xml:space="preserve">
<value>Hesap şu anda kullanılıyor: ASF, hesap kullanılmadığında çalışmaya devam edecektir...</value>
<value>Hesap şu anda kullanılıyor. ASF, hesap boşa çıktığında devam edecek...</value>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>Bağlanılıyor...</value>
</data>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>İstemcinin bağlantısı kesilemedi. Bu bot örneği terk ediliyor!</value>
<value>İstemci bağlantısı sağlıklı bir şekilde sonlandırılamadı. Bu bot örneği terk ediliyor!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Durduruluyor...</value>
</data>
<data name="ErrorBotConfigInvalid" xml:space="preserve">
<value>Bot yapılandırmanız geçersiz. Lütfen {0} içeriğini doğrulayıp tekrar deneyin!</value>
<value>Bot yapılandırmanız geçersiz. Lütfen {0} içeriğini kontrol edip tekrar deneyin!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorDatabaseInvalid" xml:space="preserve">
<value>Kalıcı veritabanı yüklenemedi, sorun devam ederse, lütfen veri tabanını yeniden oluşturmak için {0} kısmını kaldırın!</value>
<value>Kalıcı veritabanı yüklenemedi. Sorun devam ederse, veritabanını yeniden oluşturmak için lütfen {0} dosyasını silin!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="Initializing" xml:space="preserve">
@@ -503,24 +503,24 @@ Yığın Kaydı:
<comment>{0} will be replaced by service name that is being initialized</comment>
</data>
<data name="WarningPrivacyPolicy" xml:space="preserve">
<value>ASF'in aslında ne yaptığından endişeleniyorsanız lütfen wiki'deki gizlilik politikamız bölümünü gözden geçirin!</value>
<value>ASF'nin arka planda ne yaptığı konusunda endişeleriniz varsa, lütfen Wiki'deki Gizlilik Politikası bölümümüzü inceleyin!</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>Görünen o ki programı ilk defa kullanıyorsunuz, hoş geldiniz!</value>
<value>Görünüşe göre programı ilk kez çalıştırıyorsunuz, hoş geldiniz!</value>
</data>
<data name="ErrorInvalidCurrentCulture" xml:space="preserve">
<value>Sağlanan CurrentCulture geçersiz, ASF varsayılan ile çalışmaya devam edecek!</value>
<value>Belirtilen 'CurrentCulture' geçersiz, ASF varsayılan dille devam edecek!</value>
</data>
<data name="TranslationIncomplete" xml:space="preserve">
<value>ASF tercih ettiğiniz {0} kültürünü kullanmaya çalışacak, ancak bu dildeki çeviri yalnızca {1} oranında tamamlanmış. Diliniz için ASF çevirisini geliştirmemize belki de yardımcı olabilirsiniz?</value>
<value>ASF, tercih ettiğiniz {0} dilini kullanmaya çalışacak, ancak bu dildeki çeviri yalnızca %{1} oranında tamamlanmış. Belki ASF'nin dilinize çevrilmesine yardımcı olmak istersiniz?</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>ASF {0} ({1}) oyununu şu anda oynayamadığından, kart düşürmesi geçici olarak devre dışı.</value>
<value>{0} ({1}) oyunu şu anda oynanamadığı için kart düşürme geçici olarak devre dışı bırakıldı.</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}) için bir uyumsuzluk tespit etti ve bunun yerine {2} ID'si kullanılacak.</value>
<value>ASF, {0} ({1}) için bir uyuşmazlık tespit etti ve bunun yerine {2} kimliğini kullanacak.</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">
@@ -528,27 +528,27 @@ Yığın Kaydı:
<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>Bu hesap kilitli, çalıştırma süreci kalıcı olarak kullanılamaz!</value>
<value>Bu hesap kilitli, kart düşürme işlemi kalıcı olarak devre dışı!</value>
</data>
<data name="BotStatusLocked" xml:space="preserve">
<value>Bot kilitli durumda ve çalışarak kart düşüremez.</value>
<value>Bot kilitli ve kart düşüremez.</value>
</data>
<data name="ErrorFunctionOnlyInHeadlessMode" xml:space="preserve">
<value>Bu işlev yalnızca headless modda kullanılabilir!</value>
<value>Bu işlev yalnızca arayüzsüz modda kullanılabilir!</value>
</data>
<data name="BotOwnedAlready" xml:space="preserve">
<value>Zaten buna sahip: {0}</value>
<value>Zaten şuna sahip: {0}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Erişim reddedildi!</value>
</data>
<data name="WarningPreReleaseVersion" xml:space="preserve">
<value>Güncelleme kanalınız için yayınlanmış en son sürümden daha yeni bir sürüm kullanıyorsunuz. Lütfen ön yayın sürümlerinin, hata raporlamayı, sorunlarla başa çıkmayı ve geribildirim yapmayı bilen kişiler için olduğunu unutmayın - teknik destek verilmeyecektir.</value>
<value>Güncelleme kanalınız için yayınlanan son kararlı sürümden daha yeni bir sürüm kullanıyorsunuz. Lütfen ön sürüm derlemelerinin, hata bildirmeyi, sorunları çözmeyi ve geri bildirimde bulunmayı bilen deneyimli kullanıcılar için olduğunu unutmayın - bu sürümler için teknik destek sağlanmayacaktır.</value>
</data>
<data name="BotStats" xml:space="preserve">
<value>Geçerli bellek kullanımı: {0} MB.
Süreç çalışma zamanı: {1}</value>
<value>Mevcut bellek kullanımı: {0} MB.
İşlem çalışma süresi: {1}</value>
<comment>{0} will be replaced by number (in megabytes) of memory being used, {1} will be replaced by translated TimeSpan string (such as "25 minutes"). Please note that this string should include newlines for formatting.</comment>
</data>
<data name="BotOwnsOverviewPerGame" xml:space="preserve">
@@ -559,7 +559,7 @@ Süreç çalışma zamanı: {1}</value>
<value>Paket verileri yenileniyor...</value>
</data>
<data name="WarningDeprecated" xml:space="preserve">
<value>{0} kullanımı önerilmiyor ve programın gelecekteki sürümlerinde kaldırılacak. Bunun yerine {1} kullanın.</value>
<value>{0} kullanımı eskimiştir ve gelecekteki sürümlerde kaldırılacaktır. Lütfen bunun yerine {1} kullanın.</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">
@@ -567,11 +567,11 @@ Süreç çalışma zamanı: {1}</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>
<value>{0} hatası için geçici bir çözüm tetiklendi.</value>
<comment>{0} will be replaced by the bug's name provided by ASF</comment>
</data>
<data name="TargetBotNotConnected" xml:space="preserve">
<value>Hedef bot örneği bağlı değil!</value>
<value>Hedef bot bağlı değil!</value>
</data>
<data name="BotWalletBalance" xml:space="preserve">
<value>Cüzdan bakiyesi: {0} {1}</value>
@@ -581,10 +581,13 @@ Süreç çalışma zamanı: {1}</value>
<value>Botun cüzdanı yok.</value>
</data>
<data name="BotLevel" xml:space="preserve">
<value>Bot seviyesi {0}.</value>
<value>Bot seviyesi: {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} öğe</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Steam eşyaları eşleştiriliyor, tur #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -597,11 +600,11 @@ Süreç çalışma zamanı: {1}</value>
<value>İptal edildi!</value>
</data>
<data name="WarningExcessiveBotsCount" xml:space="preserve">
<value>Önerdiğimiz sınırdan ({0}) daha fazla kişisel bot hesabı kullanıyorsun. Bu yapılandırma desteklenmemektedir ve hesabın kapatılması da dahil Steam ile alakalı sorunlara sebep olabilir. Daha fazla bilgi için SSS'ye bakın.</value>
<value>Önerilen sınırın ({0}) üzerinde kişisel bot hesabı kullanıyorsunuz. Bu yapılandırma desteklenmemektedir ve hesap askıya alınması dahil olmak üzere Steam ile ilgili sorunlara neden olabilir. Daha fazla bilgi için SSS bölümüne bakın.</value>
<comment>{0} will be replaced by our maximum recommended bots count (number)</comment>
</data>
<data name="PluginLoaded" xml:space="preserve">
<value>{0} başarılı şekilde yüklendi!</value>
<value>{0} başarıyla yüklendi!</value>
<comment>{0} will be replaced by the name of the custom ASF plugin</comment>
</data>
<data name="PluginLoading" xml:space="preserve">
@@ -612,7 +615,7 @@ Süreç çalışma zamanı: {1}</value>
<value>Hiçbir şey bulunamadı!</value>
</data>
<data name="PluginsWarning" xml:space="preserve">
<value>ASF'ye bir veya daha fazla özel eklenti yükledin. Modlu kurulumlara destek sunamayacağımız için, bir sorun olduğunda lütfen ilgili geliştiricilerle iletişime geç.</value>
<value>ASF'ye bir veya daha fazla özel eklenti yüklediniz. Değiştirilmiş kurulumlara destek sunamayacağımızı, bu nedenle bir sorunla karşılaşırsanız lütfen ilgili geliştiricilerle iletişime geçmeniz gerektiğini unutmayın.</value>
</data>
<data name="PleaseWait" xml:space="preserve">
<value>Lütfen bekleyin...</value>
@@ -621,41 +624,41 @@ Süreç çalışma zamanı: {1}</value>
<value>Komut girin: </value>
</data>
<data name="Executing" xml:space="preserve">
<value>Çalıştırılıyor...</value>
<value>Yürütülüyor...</value>
</data>
<data name="InteractiveConsoleEnabled" xml:space="preserve">
<value>Etkileşimli konsol şimdi etkin, komut girme moduna girmek için 'c' tuşuna basın.</value>
<value>Etkileşimli konsol etkinleştirildi. Komut girme moduna gmek için 'c' tuşuna basın.</value>
</data>
<data name="BotGamesToRedeemInBackgroundCount" xml:space="preserve">
<value>Bot kuyruğunda {0} oyun kaldı.</value>
<value>Botun arka plan kuyruğunda {0} oyun kaldı.</value>
<comment>{0} will be replaced by remaining number of games in BGR's queue</comment>
</data>
<data name="ErrorSingleInstanceRequired" xml:space="preserve">
<value>ASF süreci, zaten bu dizinde çalıştığından iptal ediliyor!</value>
<value>Bu dizinde zaten bir ASF işlemi çalışıyor, işlem iptal ediliyor!</value>
</data>
<data name="BotHandledConfirmations" xml:space="preserve">
<value>{0} onaylama başarıyla sonuçlandırıldı!</value>
<value>{0} onay başarıyla işlendi!</value>
<comment>{0} will be replaced by number of confirmations</comment>
</data>
<data name="BotExtraIdlingCooldown" xml:space="preserve">
<value>Çalıştırmaya hazır olduğundan emin olabilmek için {0} bekleniyor...</value>
<value>Kart düşürmeye hazır olduğundan emin olmak için {0} bekleniyor...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "1 minute")</comment>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>Güncellemeden sonra eski dosyalar temizleniyor...</value>
<value>Güncelleme sonrası eski dosyalar temizleniyor...</value>
</data>
<data name="BotGeneratingSteamParentalCode" xml:space="preserve">
<value>Steam aile kodu oluşturuluyor. Bu işlem uzun süreceğinden, config dosyasına eklemeniz daha iyi olabilir...</value>
<value>Steam Aile pini oluşturuluyor. Bu işlem uzun sürebileceğinden, pini yapılandırma dosyanıza eklemeniz önerilir...</value>
</data>
<data name="IPCConfigChanged" xml:space="preserve">
<value>IPC yapılandırması değiştirildi!</value>
</data>
<data name="BotTradeOfferResult" xml:space="preserve">
<value>{0} takas teklifi, {2} sebebiyle {1} olarak belirlendi.</value>
<value>{0} numaralı takas teklifi, {2} nedeniyle {1} olarak belirlendi.</value>
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
</data>
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
<value>Arka arkaya {0} kere Yanlış Şifre hata kodu alındı (InvalidPassword). Bu hesap için parolanız muhtemelen yanlış, iptal ediliyor!</value>
<value>{0} kez üst üste 'InvalidPassword' hatası alındı. Bu hesap için şifreniz büyük olasılıkla yanlış. İşlem iptal ediliyor!</value>
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
</data>
<data name="Result" xml:space="preserve">
@@ -663,14 +666,14 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
</data>
<data name="WarningUnsupportedEnvironment" xml:space="preserve">
<value>Desteklenmeyen ortamda {0} ASF varyantını çalıştırmaya çalışıyorsun: {1}. Ne yaptığınızı gerçekten biliyorsan, --ignore-unsupported-environment argümanını sağla.</value>
<value>Desteklenmeyen bir ortamda ({1}) bir ASF varyantı ({0}) çalıştırmaya çalışıyorsunuz. Ne yaptığınızı gerçekten biliyorsanız, --ignore-unsupported-environment argümanını kullanın.</value>
</data>
<data name="WarningUnknownCommandLineArgument" xml:space="preserve">
<value>Bilinmeyen komut satırı argümanı: {0}</value>
<comment>{0} will be replaced by unrecognized command that has been provided</comment>
</data>
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
<value>Config dizini bulunamadı, çıkılıyor!</value>
<value>Yapılandırma dizini bulunamadı, çıkılıyor!</value>
</data>
<data name="BotIdlingSelectedGames" xml:space="preserve">
<value>Seçilen oynanıyor {0}: {1}</value>
@@ -681,7 +684,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced with the relative path to the affected config file</comment>
</data>
<data name="WarningTooShortCryptKey" xml:space="preserve">
<value>Şifreleme anahtarınız çok kısa. En az {0} bayt (karakter) uzunluğunda bir tane kullanmanızı öneririz.</value>
<value>Şifreleme anahtarınız çok kısa. En az {0} bayt (karakter) uzunluğunda bir anahtar kullanmanız önerilir.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
@@ -689,29 +692,29 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>{1} özelliğinin {0} ayarını kullanıyorsunuz, ancak özel bir --cryptkey sağlamadınız. Bu, ASF'nin kendi (bilinen) anahtarını kullanmak zorunda kalması nedeniyle korumayı tamamen ortadan kaldırır. Bu ayarın sunduğu güvenlik avantajından yararlanmak için özel bir --cryptkey sağlamalısınız.</value>
<value>{1} özelliğiin {0} ayarını kullanıyorsunuz, ancak özel bir --cryptkey belirtmediniz. Bu, korumayı tamamen etkisiz hale getirir çünkü ASF kendi (bilinen) anahtarını kullanmak zorunda kalır. Bu ayarın sunduğu güvenlikten yararlanmak için özel bir --cryptkey sağlamalısınız.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>ASF'yi yönetici (root) olarak çalıştırmaya çalışıyorsunuz. Bu, makineniz için önemli bir güvenlik riskine neden olur ve ASF'nin çalışması için yönetici izni gerekmediği için mümkünse yönetici olmadan çalıştırmanızı öneriyoruz.</value>
<value>ASF'yi yönetici (root) olarak çalıştırmaya çalışıyorsunuz. Bu, makineniz için önemli bir güvenlik riski oluşturur ve ASF'nin çalışması için yönetici izni gerekmediğinden, mümkünse yönetici olmadan çalıştırmanız şiddetle önerilir.</value>
</data>
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
<value>ASF'yi desteklenmeyen ortamda çalıştırıyorsunuz ve --ignore-unsupported-environment argümanı sağlıyorsunuz. Lütfen bu senaryo için herhangi bir destek sağlamadığımızı ve bunu tamamen kendi sorumluluğunuzda yaptığınızı unutmayın. Uyarıldınız.</value>
<value>ASF'yi desteklenmeyen bir ortamda --ignore-unsupported-environment argümanı ile çalıştırıyorsunuz. Lütfen bu senaryo için herhangi bir destek sunmadığımızı ve bunu tamamen kendi sorumluluğunuzda yaptığınızı unutmayın. Uyarıldınız.</value>
</data>
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
<value>Uzak sunucudan sağlama toplamı alınıyor...</value>
</data>
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
<value>Uzak sunucudan indirilen ikili dosyanın sağlama toplamı doğrulanıyor...</value>
<value>İndirilen ikili dosyanın sağlama toplamı uzak sunucu ile doğrulanıyor...</value>
</data>
<data name="ChecksumMissing" xml:space="preserve">
<value>Uzak sunucu, güncelleme yaptığımız sürüm hakkında hiçbir şey bilmiyor. Bu durum, sürüm yakın zamanda yayınlandıysa mümkündür - ek bir güvenlik önlemi olarak güncelleme prosedürüne hemen devam etmeyi reddeder.</value>
<value>Uzak sunucu, güncellediğimiz sürüm hakkında bilgiye sahip değil. Bu durum, sürüm yeni yayınlandıysa oluşabilir. Ek bir güvenlik önlemi olarak, güncelleme işlemi hemen devam etmeyecektir.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>İndirilen ikili dosyanın sağlama toplamı alınamadı; ek bir güvenlik önlemi olarak şu anda güncelleme prosedürüne devam etmeyi reddediyoruz.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Uzak sunucu farklı bir sağlama sayısı ile yanıt verdi, bu güncelleme dosyalarının bozuk indiğine veya MITM saldırısına işaret olabilir, güncelleme durduruluyor!</value>
<value>Uzak sunucu farklı bir sağlama toplamı döndürdü. Bu, güncelleme dosyalarının bozulmuş olabileceğine veya bir MITM saldırısına işaret edebilir. Güncelleme durduruluyor!</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>ASF dosyaları yamalanıyor...</value>
@@ -733,7 +736,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Görünüşe göre bir {0} eklentisini çalıştırmaya çalışıyorsunuz, ancak ASF sürümüyle uyuşmuyor: {1} (beklenen {2}). Bu, ya kurulumunuzda ciddi bir hata yaptığınızı gösterir, ya da gerçekten ne yaptığınızı biliyorsanız --ignore-unsupported-environment argümanını kullanarak sorunu çözün.</value>
<value>Bir {0} eklentisini çalıştırmaya çalışıyor gibi görünüyorsunuz, ancak bu eklenti ASF sürümünüzle ({1}, beklenen {2}) uyumlu değil. Bu durum, ya kurulumunuzda ciddi bir hata olduğunu gösterir ya da ne yaptığınızı gerçekten biliyorsanız --ignore-unsupported-environment argümanını kullanarak sorunu çözebilirsiniz.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
@@ -744,14 +747,14 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Atlaniyor:{0}...</value>
<value>Atlanıyor: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Eklenti güncellemeleri denetleniyor...</value>
<value>Eklenti güncellemeleri kontrol ediliyor...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>{0} eklentisi için güncellemesi denetleniyor...</value>
<value>{0} eklentisi için güncelleme kontrol ediliyor...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
@@ -794,7 +797,7 @@ Süreç çalışma zamanı: {1}</value>
<value>Otomatik güncellemeler için özel eklentiler kaydedildi. ASF ekibi, kendi güvenliğiniz için yalnızca güvenilir taraflardan gelen otomatik güncellemeleri etkinleştirmeniz gerektiğini hatırlatmak ister. Bunu yapmayı planlamadıysanız ASF global yapılandırmasında eklenti güncellemelerini devre dışı bırakabilirsiniz.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Veri girişi: {0}</value>
<value>Veri Girişi: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -584,7 +584,10 @@
<value>Рівень бота {0}.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="BotInventory" xml:space="preserve">
<value>{0}/{1} ({2}/{3}): {4} активів</value>
<comment>{0} will be replaced by appID (number), {1} will be replaced by contextID (number), {2} will be replaced by app's name (string), {3} will be replaced by name of the context (string), {4} will be replaced by number of assets in the specified inventory (number).</comment>
</data>
<data name="ActivelyMatchingItems" xml:space="preserve">
<value>Підбір предметів Steam, раунд #{0}...</value>
<comment>{0} will be replaced by round number</comment>
@@ -793,5 +796,8 @@
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Були зареєстровані власні плагіни для автоматичних оновлень. Команда ASF хоче нагадати вам, що з метою вашої безпеки слід увімкнути автоматичні оновлення лише від довірених джерел. Якщо ви не мали на це наміру, ви можете вимкнути оновлення плагінів у загальному конфігураційному файлі ASF.</value>
</data>
<data name="Input" xml:space="preserve">
<value>Input: {0}</value>
<comment>{0} will be replaced by text input from the user.</comment>
</data>
</root>

View File

@@ -38,6 +38,7 @@ using ArchiSteamFarm.Storage;
using NLog;
using NLog.Config;
using NLog.Targets;
using NLog.Targets.Wrappers;
namespace ArchiSteamFarm.NLog;
@@ -48,8 +49,6 @@ internal static class Logging {
private const string GeneralLayout = $@"${{date:format=yyyy-MM-dd HH\:mm\:ss}}|${{processname}}-${{processid}}|${{level:uppercase=true}}|{LayoutMessage}";
private const string LayoutMessage = @"${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}";
internal static bool LogFileExists => File.Exists(SharedInfo.LogFile);
private static readonly ConcurrentHashSet<LoggingRule> ConsoleLoggingRules = [];
private static readonly SemaphoreSlim ConsoleSemaphore = new(1, 1);
@@ -207,6 +206,7 @@ internal static class Logging {
internal static void InitCoreLoggers(bool uniqueInstance) {
try {
// Handle edge case of user using NLog.config in non-standard directory (current directory)
if ((Directory.GetCurrentDirectory() != AppContext.BaseDirectory) && File.Exists(NLogConfigurationFile)) {
IsUsingCustomConfiguration = true;
@@ -224,6 +224,11 @@ internal static class Logging {
}
if (uniqueInstance) {
if (LogManager.Configuration == null) {
// This should never happen, as configuration must be initialized by now (either by user's config, InitEmergencyLoggers() or InitCoreLoggers() above)
throw new InvalidOperationException(nameof(LogManager.Configuration));
}
try {
Directory.CreateDirectory(SharedInfo.ArchivalLogsDirectory);
} catch (Exception e) {
@@ -232,12 +237,10 @@ internal static class Logging {
#pragma warning disable CA2000 // False positive, we're adding this disposable object to the global scope, so we can't dispose it
FileTarget fileTarget = new("File") {
ArchiveFileName = Path.Combine("${currentdir}", SharedInfo.ArchivalLogsDirectory, SharedInfo.ArchivalLogFile),
ArchiveNumbering = ArchiveNumberingMode.Rolling,
ArchiveFileName = Path.Combine("${currentdir:cached=true}", SharedInfo.ArchivalLogsDirectory, SharedInfo.LogFile),
ArchiveOldFileOnStartup = true,
CleanupFileName = false,
DeleteOldFileOnStartup = true,
FileName = Path.Combine("${currentdir}", SharedInfo.LogFile),
ArchiveSuffixFormat = ".{1:yyyyMMdd-HHmmss}",
FileName = Path.Combine("${currentdir:cached=true}", SharedInfo.LogFile),
// Windows OS prevents other apps from reading file when actively holding exclusive (write) lock over it
// We require read access for GET /Api/NLog/File ASF API usage, therefore we shouldn't keep the lock all the time
@@ -265,6 +268,7 @@ internal static class Logging {
// This is a temporary, bare, file-less configuration that must work until we're able to initialize it properly
ConfigurationItemFactory.Default.ParseMessageTemplates = false;
LoggingConfiguration config = new();
#pragma warning disable CA2000 // False positive, we're adding this disposable object to the global scope, so we can't dispose it
@@ -281,7 +285,7 @@ internal static class Logging {
return;
}
HistoryTarget? historyTarget = LogManager.Configuration.AllTargets.OfType<HistoryTarget>().FirstOrDefault();
HistoryTarget? historyTarget = LogManager.Configuration.AllTargets.Select(static target => target is WrapperTargetBase wrapper ? wrapper.WrappedTarget : target).OfType<HistoryTarget>().FirstOrDefault();
if ((historyTarget == null) && !IsUsingCustomConfiguration) {
historyTarget = new HistoryTarget("History") {
@@ -298,13 +302,15 @@ internal static class Logging {
}
internal static async Task<string[]?> ReadLogFileLines() {
try {
return await File.ReadAllLinesAsync(SharedInfo.LogFile).ConfigureAwait(false);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
if (LogManager.Configuration == null) {
return File.Exists(SharedInfo.LogFile) ? await ReadLogFileLines(SharedInfo.LogFile).ConfigureAwait(false) : null;
}
foreach (string fileName in LogManager.Configuration.LoggingRules.OrderBy(static rule => rule.Filters.Count).ThenByDescending(static rule => rule.Levels.Count).SelectMany(static rule => rule.Targets.Select(static target => target is WrapperTargetBase wrapper ? wrapper.WrappedTarget : target).OfType<FileTarget>().Select(static fileTarget => fileTarget.FileName.Render(new LogEventInfo { TimeStamp = DateTime.UtcNow })).Where(File.Exists))) {
return await ReadLogFileLines(fileName).ConfigureAwait(false);
}
return null;
}
internal static void StartInteractiveConsole() {
@@ -536,7 +542,7 @@ internal static class Logging {
OnUserInputStart();
}
HistoryTarget? historyTarget = LogManager.Configuration?.AllTargets.OfType<HistoryTarget>().FirstOrDefault();
HistoryTarget? historyTarget = LogManager.Configuration?.AllTargets.Select(static target => target is WrapperTargetBase wrapper ? wrapper.WrappedTarget : target).OfType<HistoryTarget>().FirstOrDefault();
ArchiKestrel.OnNewHistoryTarget(historyTarget);
}
@@ -576,4 +582,16 @@ internal static class Logging {
LogManager.ReconfigExistingLoggers();
}
}
private static async Task<string[]?> ReadLogFileLines(string filePath) {
ArgumentException.ThrowIfNullOrEmpty(filePath);
try {
return await File.ReadAllLinesAsync(filePath).ConfigureAwait(false);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
}
}

View File

@@ -31,10 +31,8 @@ using NLog.Targets;
namespace ArchiSteamFarm.NLog.Targets;
[Target(TargetName)]
[Target("History")]
internal sealed class HistoryTarget : TargetWithLayout {
internal const string TargetName = "History";
private const byte DefaultMaxCount = 20;
internal IEnumerable<string> ArchivedMessages => HistoryQueue;

View File

@@ -22,7 +22,6 @@
// limitations under the License.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -30,17 +29,14 @@ using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using JetBrains.Annotations;
using NLog;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using SteamKit2;
namespace ArchiSteamFarm.NLog.Targets;
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
[Target(TargetName)]
[Target("Steam")]
internal sealed class SteamTarget : AsyncTaskTarget {
internal const string TargetName = "Steam";
// This is NLog config property, it must have public get() and set() capabilities
[UsedImplicitly]
public Layout? BotName { get; set; }
@@ -50,21 +46,29 @@ internal sealed class SteamTarget : AsyncTaskTarget {
public ulong ChatGroupID { get; set; }
// This is NLog config property, it must have public get() and set() capabilities
[RequiredParameter]
[UsedImplicitly]
public ulong SteamID { get; set; }
// This parameter-less constructor is intentionally public, as NLog uses it for creating targets
// It must stay like this as we want to have our targets defined in our NLog.config
// Keeping date in default layout also doesn't make much sense (Steam offers that), so we remove it by default
[UsedImplicitly]
public SteamTarget() => Layout = "${level:uppercase=true}|${logger}|${message}";
protected override void InitializeTarget() {
base.InitializeTarget();
if ((SteamID == 0) || ((ChatGroupID == 0) && !new SteamID(SteamID).IsIndividualAccount)) {
throw new NLogConfigurationException(Strings.FormatErrorIsInvalid(nameof(SteamID)));
}
}
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken) {
ArgumentNullException.ThrowIfNull(logEvent);
Write(logEvent);
if ((SteamID == 0) || (Bot.Bots == null) || Bot.Bots.IsEmpty) {
if ((Bot.Bots == null) || Bot.Bots.IsEmpty) {
return;
}

View File

@@ -40,5 +40,5 @@ public interface IASF : IPlugin {
/// ASF will call this method right after global config initialization.
/// </summary>
/// <param name="additionalConfigProperties">Extra config properties made out of <see cref="JsonExtensionDataAttribute" />. Can be null if no extra properties are found.</param>
Task OnASFInit(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
public Task OnASFInit(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
}

View File

@@ -40,12 +40,12 @@ public interface IBot : IPlugin {
/// Doing so will allow the garbage collector to dispose the bot afterwards, refraining from doing so will create a "memory leak" by keeping the reference alive.
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
Task OnBotDestroy(Bot bot);
public Task OnBotDestroy(Bot bot);
/// <summary>
/// ASF will call this method after creating the bot object, e.g. after config creation.
/// Bot config is not yet available at this stage. This function will execute only once for every bot object.
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
Task OnBotInit(Bot bot);
public Task OnBotInit(Bot bot);
}

View File

@@ -39,17 +39,17 @@ public interface IBotCardsFarmerInfo : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="farmedSomething">Bool value indicating whether the module has finished successfully, so when there was at least one card to drop, and nothing has interrupted us in the meantime.</param>
Task OnBotFarmingFinished(Bot bot, bool farmedSomething);
public Task OnBotFarmingFinished(Bot bot, bool farmedSomething);
/// <summary>
/// ASF will call this method when cards farming module is started on given bot instance. The module is started only when there are valid cards to drop, so this method won't be called when there is nothing to idle.
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
Task OnBotFarmingStarted(Bot bot);
public Task OnBotFarmingStarted(Bot bot);
/// <summary>
/// ASF will call this method when cards farming module is stopped on given bot instance. The stop could be a result of a natural finish, or other situations (e.g. Steam networking issues, user commands).
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
Task OnBotFarmingStopped(Bot bot);
public Task OnBotFarmingStopped(Bot bot);
}

View File

@@ -44,5 +44,5 @@ public interface IBotCommand2 : IPlugin {
/// <param name="args">Pre-parsed message using standard ASF delimiters.</param>
/// <param name="steamID">Optionally, steamID of the user who executed the command - may not be available with value of 0 (e.g. ASF API).</param>
/// <returns>Response to the command, or null/empty (as the task value) if the command isn't handled by this plugin.</returns>
Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0);
public Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0);
}

View File

@@ -39,11 +39,11 @@ public interface IBotConnection : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="reason">Reason for disconnection, or <see cref="EResult.OK" /> if the disconnection was initiated by ASF (e.g. as a result of a command).</param>
Task OnBotDisconnected(Bot bot, EResult reason);
public Task OnBotDisconnected(Bot bot, EResult reason);
/// <summary>
/// ASF will call this method when bot successfully connects to Steam network.
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
Task OnBotLoggedOn(Bot bot);
public Task OnBotLoggedOn(Bot bot);
}

View File

@@ -41,5 +41,5 @@ public interface IBotCustomMachineInfoProvider : IPlugin {
/// <remarks>This method will be called with very limited amount of bot-related data, as it's used during bot initialization. We recommend to stick with <see cref="Bot.BotName" />, <see cref="Bot.BotConfig" /> and <see cref="Bot.BotDatabase" /> exclusively.</remarks>
/// <param name="bot">Bot object related to this callback.</param>
/// <returns><see cref="IMachineInfoProvider" /> that will be used for the particular bot. You can return null if you want to use default implementation.</returns>
Task<IMachineInfoProvider?> GetMachineInfoProvider(Bot bot);
public Task<IMachineInfoProvider?> GetMachineInfoProvider(Bot bot);
}

View File

@@ -39,5 +39,5 @@ public interface IBotFriendRequest : IPlugin {
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="steamID">64-bit Steam identificator of the user that sent a friend request, or a group that the bot has been invited to.</param>
/// <returns>True if the request should be accepted as part of this plugin, false otherwise.</returns>
Task<bool> OnBotFriendRequest(Bot bot, ulong steamID);
public Task<bool> OnBotFriendRequest(Bot bot, ulong steamID);
}

View File

@@ -41,5 +41,5 @@ public interface IBotIdentity : IPlugin {
/// <param name="data">Full data received by ASF in the callback that relates to this bot (Steam) account.</param>
/// <param name="nickname">Parsed nickname set for this bot (Steam) account.</param>
/// <param name="avatarHash">Parsed hash of the avatar of this bot (Steam) account, as hex.</param>
Task OnSelfPersonaState(Bot bot, SteamFriends.PersonaStateCallback data, string? nickname, string? avatarHash);
public Task OnSelfPersonaState(Bot bot, SteamFriends.PersonaStateCallback data, string? nickname, string? avatarHash);
}

View File

@@ -42,5 +42,5 @@ public interface IBotMessage : IPlugin {
/// <param name="steamID">64-bit long unsigned integer of steamID executing the command.</param>
/// <param name="message">Message in its raw format.</param>
/// <returns>Response to the message, or null/empty (as the task value) for silence.</returns>
Task<string?> OnBotMessage(Bot bot, ulong steamID, string message);
public Task<string?> OnBotMessage(Bot bot, ulong steamID, string message);
}

View File

@@ -42,5 +42,5 @@ public interface IBotModules : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="additionalConfigProperties">Extra config properties made out of <see cref="JsonExtensionDataAttribute" />. Can be null if no extra properties are found.</param>
Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
public Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
}

View File

@@ -40,12 +40,12 @@ public interface IBotSteamClient : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="callbackManager">Callback manager object which can be used for establishing subscriptions to standard and custom callbacks.</param>
Task OnBotSteamCallbacksInit(Bot bot, CallbackManager callbackManager);
public Task OnBotSteamCallbacksInit(Bot bot, CallbackManager callbackManager);
/// <summary>
/// ASF will call this method right after bot initialization in order to allow you hooking custom SK2 client handlers into the SteamClient.
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <returns>Collection of custom client handlers that are supposed to be hooked into the SteamClient by ASF. If you do not require any, just return null or empty collection.</returns>
Task<IReadOnlyCollection<ClientMsgHandler>?> OnBotSteamHandlersInit(Bot bot);
public Task<IReadOnlyCollection<ClientMsgHandler>?> OnBotSteamHandlersInit(Bot bot);
}

View File

@@ -42,5 +42,5 @@ public interface IBotTradeOffer2 : IPlugin {
/// <param name="tradeOffer">Trade offer related to this callback.</param>
/// <param name="asfResult">ASF result in regards to parsing this trade offer, can be useful for determining why it wasn't accepted as part of the core logic.</param>
/// <returns>True if the trade offer should be accepted as part of this plugin, false otherwise.</returns>
Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer, ParseTradeResult.EResult asfResult);
public Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer, ParseTradeResult.EResult asfResult);
}

View File

@@ -40,5 +40,5 @@ public interface IBotTradeOfferResults : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="tradeResults">Trade results related to this callback.</param>
Task OnBotTradeOfferResults(Bot bot, IReadOnlyCollection<ParseTradeResult> tradeResults);
public Task OnBotTradeOfferResults(Bot bot, IReadOnlyCollection<ParseTradeResult> tradeResults);
}

View File

@@ -40,5 +40,5 @@ public interface IBotUserNotifications : IPlugin {
/// </summary>
/// <param name="bot">Bot object related to this callback.</param>
/// <param name="newNotifications">Collection containing those notification types that are new (that is, when new count > previous count of that notification type).</param>
Task OnBotUserNotifications(Bot bot, IReadOnlyCollection<UserNotificationsCallback.EUserNotification> newNotifications);
public Task OnBotUserNotifications(Bot bot, IReadOnlyCollection<UserNotificationsCallback.EUserNotification> newNotifications);
}

View File

@@ -37,5 +37,5 @@ public interface IBotsComparer : IPlugin {
/// Unless you know what you're doing, you should not implement this property yourself and let ASF decide.
/// </summary>
/// <returns>Comparer that will be used for the bots, as well as bot regexes.</returns>
StringComparer BotsComparer => StringComparer.Ordinal;
public StringComparer BotsComparer => StringComparer.Ordinal;
}

View File

@@ -39,5 +39,5 @@ public interface ICrossProcessSemaphoreProvider : IPlugin {
/// </summary>
/// <param name="resourceName">Unique resource name provided by ASF for identification purposes.</param>
/// <returns>Concrete implementation of <see cref="ICrossProcessSemaphore" /> providing required functionality. It's allowed to return null if you want to use ASF's default implementation for specified resource instead.</returns>
Task<ICrossProcessSemaphore?> GetCrossProcessSemaphore(string resourceName);
public Task<ICrossProcessSemaphore?> GetCrossProcessSemaphore(string resourceName);
}

View File

@@ -48,14 +48,14 @@ public interface IGitHubPluginUpdates : IPluginUpdates {
/// Boolean value that determines whether your plugin is able to update at the time of calling. You may provide false if, for example, you're inside a critical section and you don't want to update at this time, despite supporting updates otherwise.
/// This effectively skips unnecessary request to GitHub if you're certain that you're not interested in any updates right now.
/// </summary>
bool CanUpdate => true;
public bool CanUpdate => true;
/// <summary>
/// ASF will use this property as a target for GitHub updates. GitHub repository specified here must have valid releases that will be used for updates.
/// </summary>
/// <returns>Repository name in format of {Author}/{Repository}.</returns>
/// <example>JustArchiNET/ArchiSteamFarm</example>
string RepositoryName { get; }
public string RepositoryName { get; }
Task<Uri?> IPluginUpdates.GetTargetReleaseURL(Version asfVersion, string asfVariant, bool asfUpdate, GlobalConfig.EUpdateChannel updateChannel, bool forced) {
ArgumentNullException.ThrowIfNull(asfVersion);
@@ -104,7 +104,7 @@ public interface IGitHubPluginUpdates : IPluginUpdates {
/// - *.zip, if exactly one match is found
/// </remarks>
/// <returns>Target release asset from those provided that should be used for auto-update. You may return null if the update is unavailable, for example, because ASF version/variant is determined unsupported, or due to any other reason.</returns>
Task<ReleaseAsset?> GetTargetReleaseAsset(Version asfVersion, string asfVariant, Version newPluginVersion, IReadOnlyCollection<ReleaseAsset> releaseAssets) {
public Task<ReleaseAsset?> GetTargetReleaseAsset(Version asfVersion, string asfVariant, Version newPluginVersion, IReadOnlyCollection<ReleaseAsset> releaseAssets) {
ArgumentNullException.ThrowIfNull(asfVersion);
ArgumentException.ThrowIfNullOrEmpty(asfVariant);
ArgumentNullException.ThrowIfNull(newPluginVersion);

View File

@@ -38,7 +38,7 @@ public interface IPlugin {
/// </summary>
/// <returns>String that will be used as the name of this plugin.</returns>
[JsonInclude]
string Name { get; }
public string Name { get; }
/// <summary>
/// ASF will use this property as version indicator of your plugin to the user.
@@ -46,10 +46,10 @@ public interface IPlugin {
/// </summary>
/// <returns>Version that will be shown to the user when plugin is loaded.</returns>
[JsonInclude]
Version Version { get; }
public Version Version { get; }
/// <summary>
/// ASF will call this method right after plugin initialization.
/// </summary>
Task OnLoaded();
public Task OnLoaded();
}

View File

@@ -45,15 +45,15 @@ public interface IPluginUpdates : IPlugin {
/// <param name="updateChannel">ASF update channel specified for this request. This might be different from the one specified in <see cref="GlobalConfig" />, as user might've specified other one for this request.</param>
/// <param name="forced">Boolean value specifying whether user has requested forced plugin update, that is, one that should always execute if possible - even with the same and lower version (downgrade).</param>
/// <returns>Target release asset URL that should be used for auto-update. It's permitted to return null if you want to skip update, e.g. because no new version is available.</returns>
Task<Uri?> GetTargetReleaseURL(Version asfVersion, string asfVariant, bool asfUpdate, GlobalConfig.EUpdateChannel updateChannel, bool forced);
public Task<Uri?> GetTargetReleaseURL(Version asfVersion, string asfVariant, bool asfUpdate, GlobalConfig.EUpdateChannel updateChannel, bool forced);
/// <summary>
/// ASF will call this method after update to the new plugin version has been finished, just before restart of the process.
/// </summary>
Task OnPluginUpdateFinished() => Task.CompletedTask;
public Task OnPluginUpdateFinished() => Task.CompletedTask;
/// <summary>
/// ASF will call this method before proceeding with an update to the new plugin version.
/// </summary>
Task OnPluginUpdateProceeding() => Task.CompletedTask;
public Task OnPluginUpdateProceeding() => Task.CompletedTask;
}

View File

@@ -38,7 +38,7 @@ public interface ISteamPICSChanges : IPlugin {
/// ASF uses this method for determining the point in time from which it should keep history going upon a restart. The actual point in time that will be used is calculated as the lowest change number from all loaded plugins, to guarantee that no plugin will miss any changes, while allowing possible duplicates for those plugins that were already synchronized with newer changes. If you don't care about persistent state and just want to receive the ongoing history, you should return 0 (which is equal to "I'm fine with any"). If there won't be any plugin asking for a specific point in time, ASF will start returning entries since the start of the program.
/// </summary>
/// <returns>The most recent change number from which you're fine to receive <see cref="OnPICSChanges" />.</returns>
Task<uint> GetPreferredChangeNumberToStartFrom();
public Task<uint> GetPreferredChangeNumberToStartFrom();
/// <summary>
/// ASF will call this method upon receiving any app/package PICS changes. The history is guaranteed to be precise and continuous starting from <see cref="GetPreferredChangeNumberToStartFrom" /> until <see cref="OnPICSChangesRestart" /> is called. It's possible for this method to have duplicated calls across different runs, in particular when some other plugin asks for lower <see cref="GetPreferredChangeNumberToStartFrom" />, therefore you should keep that in mind (and refer to change number of standalone apps/packages).
@@ -46,11 +46,11 @@ public interface ISteamPICSChanges : IPlugin {
/// <param name="currentChangeNumber">The change number of current callback.</param>
/// <param name="appChanges">App changes that happened since the previous call of this method. Can be empty.</param>
/// <param name="packageChanges">Package changes that happened since the previous call of this method. Can be empty.</param>
Task OnPICSChanges(uint currentChangeNumber, IReadOnlyDictionary<uint, SteamApps.PICSChangesCallback.PICSChangeData> appChanges, IReadOnlyDictionary<uint, SteamApps.PICSChangesCallback.PICSChangeData> packageChanges);
public Task OnPICSChanges(uint currentChangeNumber, IReadOnlyDictionary<uint, SteamApps.PICSChangesCallback.PICSChangeData> appChanges, IReadOnlyDictionary<uint, SteamApps.PICSChangesCallback.PICSChangeData> packageChanges);
/// <summary>
/// ASF will call this method when it'll be necessary to restart the history of PICS changes. This can happen due to Steam limitation in which we're unable to keep history going if we're too far behind (approx 5k changeNumbers). If you're relying on continuous history of app/package PICS changes sent by <see cref="OnPICSChanges" />, ASF can no longer guarantee that upon calling this method, therefore you should start clean.
/// </summary>
/// <param name="currentChangeNumber">The change number from which we're restarting the PICS history.</param>
Task OnPICSChangesRestart(uint currentChangeNumber);
public Task OnPICSChangesRestart(uint currentChangeNumber);
}

View File

@@ -38,12 +38,12 @@ public interface IUpdateAware : IPlugin {
/// </summary>
/// <param name="currentVersion">The current (old) version of ASF program.</param>
/// <param name="newVersion">The target (new) version of ASF program.</param>
Task OnUpdateFinished(Version currentVersion, Version newVersion);
public Task OnUpdateFinished(Version currentVersion, Version newVersion);
/// <summary>
/// ASF will call this method before proceeding with an update to a particular ASF version.
/// </summary>
/// <param name="currentVersion">The current (old) version of ASF program.</param>
/// <param name="newVersion">The target (new) version of ASF program.</param>
Task OnUpdateProceeding(Version currentVersion, Version newVersion);
public Task OnUpdateProceeding(Version currentVersion, Version newVersion);
}

View File

@@ -35,7 +35,7 @@ public interface IWebInterface : IPlugin {
/// </summary>
/// <example>www</example>
/// <remarks>You'll need to ship this folder together with your plugin for the interface to work.</remarks>
string PhysicalPath => "www";
public string PhysicalPath => "www";
/// <summary>
/// Specifies web path (address) under which ASF should host your static WWW files in <see cref="PhysicalPath" /> directory. Default value of "/" allows you to override default ASF files and gives you full flexibility in your <see cref="PhysicalPath" /> directory. However, you can instead host your files under some other fixed location specified here, such as "/MyPlugin", which is especially useful if you want to have your own default index.html in addition to the one provided by us (ASF-ui).
@@ -43,5 +43,5 @@ public interface IWebInterface : IPlugin {
/// <example>/MyPlugin</example>
/// <remarks>If you're using path other than default, ensure it does NOT end with a slash.</remarks>
[JsonInclude]
string WebPath => "/";
public string WebPath => "/";
}

View File

@@ -37,11 +37,11 @@ public interface IWebServiceProvider : IPlugin {
/// ASF will call this method during configuration of the IPC endpoints.
/// </summary>
/// <param name="app">Application builder related to this callback.</param>
void OnConfiguringEndpoints(IApplicationBuilder app);
public void OnConfiguringEndpoints(IApplicationBuilder app);
/// <summary>
/// ASF will call this method during configuration of the IPC services.
/// </summary>
/// <param name="services">Service collection related to this callback.</param>
void OnConfiguringServices(IServiceCollection services);
public void OnConfiguringServices(IServiceCollection services);
}

Some files were not shown because too many files have changed in this diff Show More