mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-22 17:28:37 +00:00
Compare commits
322 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3dbfc5e9e | ||
|
|
30c84efb57 | ||
|
|
3ba8602156 | ||
|
|
9d2aacab58 | ||
|
|
c7b9751e0e | ||
|
|
9cfbc35ac4 | ||
|
|
ba618dc2b6 | ||
|
|
f3c870b8c7 | ||
|
|
46ec3e51b0 | ||
|
|
4ca93c3c45 | ||
|
|
7ab499e2c0 | ||
|
|
102f3de120 | ||
|
|
01fd6f3ad6 | ||
|
|
cca465d30d | ||
|
|
dc7f2acc50 | ||
|
|
79a15ad781 | ||
|
|
4e6905d562 | ||
|
|
03a5853a91 | ||
|
|
f3fae74bde | ||
|
|
8bbff388d2 | ||
|
|
40d5fe75e7 | ||
|
|
cdbabc0a0b | ||
|
|
97ecfc03c8 | ||
|
|
70d35bfeb8 | ||
|
|
a11866c544 | ||
|
|
5aaf5476e0 | ||
|
|
7e78922056 | ||
|
|
e7dad02c63 | ||
|
|
da5fb391a4 | ||
|
|
3b48b79997 | ||
|
|
30e887a85b | ||
|
|
c737c792f6 | ||
|
|
64f4853b13 | ||
|
|
0c890e590c | ||
|
|
b664b85495 | ||
|
|
3894a6a2d1 | ||
|
|
ae8224b734 | ||
|
|
bd5739d7a0 | ||
|
|
3a8a8efbd1 | ||
|
|
4fc1f4c60e | ||
|
|
079bbc8e78 | ||
|
|
70bfbd7d8e | ||
|
|
f0c7222055 | ||
|
|
7b1b3d4d8e | ||
|
|
7d6b4b7a23 | ||
|
|
a4d0b7d1cb | ||
|
|
62e786b9b8 | ||
|
|
38ae309285 | ||
|
|
f87b63d6ee | ||
|
|
3b3f1caf84 | ||
|
|
724be4c1cf | ||
|
|
b4ab287994 | ||
|
|
19d17940c0 | ||
|
|
aa46079ed4 | ||
|
|
5e81e3a6a6 | ||
|
|
e2f2b6aa5d | ||
|
|
a7c67b04ca | ||
|
|
465207034d | ||
|
|
93b9cf4b76 | ||
|
|
dc57860f0d | ||
|
|
f71b0bc945 | ||
|
|
1c9132627b | ||
|
|
b14d5de641 | ||
|
|
530743cf97 | ||
|
|
d1ab859621 | ||
|
|
fe76ada8d0 | ||
|
|
e096f4f081 | ||
|
|
0d8f7b854d | ||
|
|
b9beb6ec16 | ||
|
|
7afcf82c32 | ||
|
|
b27dd345af | ||
|
|
9fdf8c6a75 | ||
|
|
1010f270a0 | ||
|
|
0db051a251 | ||
|
|
890a431e24 | ||
|
|
173e0ea157 | ||
|
|
4c99ce4ab2 | ||
|
|
6f98228c41 | ||
|
|
95d15aa107 | ||
|
|
2f09e74f1a | ||
|
|
f30fcb3941 | ||
|
|
06254a9afc | ||
|
|
fd95c6cac7 | ||
|
|
2196bccda5 | ||
|
|
b0ac2b4147 | ||
|
|
5322321944 | ||
|
|
2f951e0ef6 | ||
|
|
1e6dcc88d2 | ||
|
|
8bbcfc40dc | ||
|
|
811ea46523 | ||
|
|
c37e54cf9b | ||
|
|
4c095e8eb5 | ||
|
|
c580ec7b92 | ||
|
|
0c45d3c5ba | ||
|
|
2bc8a4cefd | ||
|
|
92d28adb07 | ||
|
|
cc2b1dbbaa | ||
|
|
bd98cadab3 | ||
|
|
c417f88e3b | ||
|
|
b26a9af49b | ||
|
|
e4b00b35f2 | ||
|
|
11bab46b8b | ||
|
|
7eb24d7bd6 | ||
|
|
9a26366ff8 | ||
|
|
0058bc6fa5 | ||
|
|
ca3f3e0cab | ||
|
|
cf51ca454d | ||
|
|
35c3c2a2b3 | ||
|
|
12bb61c23d | ||
|
|
2e5a2a1393 | ||
|
|
4259bb088e | ||
|
|
0768765f21 | ||
|
|
dc7ee7fadc | ||
|
|
7665a1c339 | ||
|
|
6015cd5cb7 | ||
|
|
08aa8f2136 | ||
|
|
c27e447f57 | ||
|
|
9f1a3a0304 | ||
|
|
7714478fdc | ||
|
|
91bca33a54 | ||
|
|
c67b967817 | ||
|
|
150ed2c733 | ||
|
|
1c23e4b5b3 | ||
|
|
77c4dee6a8 | ||
|
|
d6fe8eec38 | ||
|
|
c12d83bbf0 | ||
|
|
0e6b75aa5c | ||
|
|
dd1dfdcf34 | ||
|
|
792d8dab34 | ||
|
|
4f23434f81 | ||
|
|
7797c4e0b0 | ||
|
|
6463a2be2d | ||
|
|
972a46ac2e | ||
|
|
db3091b21b | ||
|
|
476733ca19 | ||
|
|
d0c302c1f1 | ||
|
|
164deb1096 | ||
|
|
b39ea679e7 | ||
|
|
062a5f470c | ||
|
|
48fb388da2 | ||
|
|
a23cdc9605 | ||
|
|
1c7eb0f5a1 | ||
|
|
58050c9ec3 | ||
|
|
5908cc40a8 | ||
|
|
bffb5e53bf | ||
|
|
4a0b79f1a1 | ||
|
|
3ddb77e9f8 | ||
|
|
16f7bccb11 | ||
|
|
ecec5cdde2 | ||
|
|
cf4fca9836 | ||
|
|
e5d61b2796 | ||
|
|
fc493ea510 | ||
|
|
7983dc01f1 | ||
|
|
09f914cecd | ||
|
|
9968b0ac36 | ||
|
|
969a5f711c | ||
|
|
ccb4601c85 | ||
|
|
25aabe7553 | ||
|
|
13755d4d06 | ||
|
|
1d6e87d103 | ||
|
|
8673ef8420 | ||
|
|
ab1fb70f4c | ||
|
|
31fe6923ff | ||
|
|
0b07b7c4a7 | ||
|
|
0abe05b7bd | ||
|
|
45ff19f9ae | ||
|
|
d25883ff1b | ||
|
|
d2f43e4e50 | ||
|
|
792167a71c | ||
|
|
f2586d7cb0 | ||
|
|
c37846b4cd | ||
|
|
17c4ec6790 | ||
|
|
7023040882 | ||
|
|
8c38de1b26 | ||
|
|
1917c9da95 | ||
|
|
668bf5009b | ||
|
|
e9ca1e3537 | ||
|
|
ebdb412adf | ||
|
|
e73c72d148 | ||
|
|
d1d843c583 | ||
|
|
464e375529 | ||
|
|
2b12f8a294 | ||
|
|
b305e98519 | ||
|
|
5431e49c2a | ||
|
|
6098cdc31d | ||
|
|
308d7c2c1c | ||
|
|
454f40ffb9 | ||
|
|
dd3b3dec33 | ||
|
|
bc2831c066 | ||
|
|
905d2acdbd | ||
|
|
54c2b6b6d5 | ||
|
|
b6a4ccac7f | ||
|
|
3fce1cc934 | ||
|
|
375a888a37 | ||
|
|
0d62034f32 | ||
|
|
f7d722aaf0 | ||
|
|
56759bc710 | ||
|
|
d27b5c28ef | ||
|
|
a0d1cada54 | ||
|
|
ca7e1da585 | ||
|
|
5f097c4002 | ||
|
|
203dc6daf6 | ||
|
|
e895850f17 | ||
|
|
f776e7947c | ||
|
|
416ec920cb | ||
|
|
b5da72eb40 | ||
|
|
3dde77608e | ||
|
|
a0407553ec | ||
|
|
8d594fe0b6 | ||
|
|
e68e87d388 | ||
|
|
4cabd42c0b | ||
|
|
df33f7d0fc | ||
|
|
d6b5e3981c | ||
|
|
6aa0300c85 | ||
|
|
264ca84513 | ||
|
|
816306872d | ||
|
|
13aced705a | ||
|
|
95d0f879ca | ||
|
|
f37d2297bb | ||
|
|
0d90a53b8e | ||
|
|
f91dfe7efa | ||
|
|
ec757e3ef8 | ||
|
|
3b2ca10b05 | ||
|
|
b438e38268 | ||
|
|
bb405f2824 | ||
|
|
1d640fbec0 | ||
|
|
ecc820333e | ||
|
|
9cc227aa61 | ||
|
|
93420eebc0 | ||
|
|
6014b3bdc6 | ||
|
|
81789c717f | ||
|
|
dfa6330821 | ||
|
|
1d5d9c12a7 | ||
|
|
2cbbbe7359 | ||
|
|
4706cedbf9 | ||
|
|
a11b955a9d | ||
|
|
e1366f6267 | ||
|
|
6bff839821 | ||
|
|
0b37acf16e | ||
|
|
70c39eef0a | ||
|
|
1988b18053 | ||
|
|
67f87396e8 | ||
|
|
3734721c58 | ||
|
|
0f6a3f2ec8 | ||
|
|
ab9ca4b9c3 | ||
|
|
c05cffbd88 | ||
|
|
0e3f3d1143 | ||
|
|
ff02a4a8d4 | ||
|
|
c8c35b5bf7 | ||
|
|
18daa6a8c7 | ||
|
|
c95b58852c | ||
|
|
80ccceb9b0 | ||
|
|
eaa308d3ce | ||
|
|
d05ac7e10d | ||
|
|
a80aef16a0 | ||
|
|
338560fedb | ||
|
|
632830278f | ||
|
|
8b614bd3c4 | ||
|
|
657354c2e8 | ||
|
|
7a0d9f2325 | ||
|
|
ae45c0c7ae | ||
|
|
c3b0e31a0a | ||
|
|
f7207c1326 | ||
|
|
9a9817c6b3 | ||
|
|
1b4ac9da8b | ||
|
|
d98310fc0e | ||
|
|
3240fca63e | ||
|
|
f1631b7f06 | ||
|
|
30e5c5f91b | ||
|
|
257026144d | ||
|
|
9f786dce97 | ||
|
|
c2f582164c | ||
|
|
464ed3b614 | ||
|
|
5bb9494ecc | ||
|
|
0fb583a094 | ||
|
|
358b1a7dbe | ||
|
|
bd91f439c8 | ||
|
|
4181ada887 | ||
|
|
32d116d106 | ||
|
|
30c27f9faf | ||
|
|
b332d576ab | ||
|
|
9def43cef0 | ||
|
|
0820b39a35 | ||
|
|
2a0be85d14 | ||
|
|
efb7262113 | ||
|
|
1a732bbb93 | ||
|
|
b8fe380b61 | ||
|
|
8670cea7a3 | ||
|
|
e2a5ec3616 | ||
|
|
d013366c9a | ||
|
|
e9093cda6d | ||
|
|
0f30a0ef3d | ||
|
|
b1a64e346c | ||
|
|
c524a89c5e | ||
|
|
e73d90e697 | ||
|
|
ee470d9ce9 | ||
|
|
aab5b3aaab | ||
|
|
86281b5fdb | ||
|
|
ddabf7db49 | ||
|
|
1c7523e98e | ||
|
|
120d084b12 | ||
|
|
1e69ec4634 | ||
|
|
31a680ce1c | ||
|
|
3bad19530e | ||
|
|
10986289e6 | ||
|
|
656c1b8d5d | ||
|
|
ef0037aa25 | ||
|
|
af02ccbd6f | ||
|
|
978f3f63bd | ||
|
|
e550cc0f43 | ||
|
|
5894226e93 | ||
|
|
d50fa8eeb7 | ||
|
|
6efd333684 | ||
|
|
05701b60c1 | ||
|
|
f8e7e55a00 | ||
|
|
20663f0226 | ||
|
|
ad175ba2ac | ||
|
|
bdf90a5e51 | ||
|
|
49618534ce | ||
|
|
f2bb2a6bee | ||
|
|
ba4f3aea7b | ||
|
|
b30068103b |
4
.github/FUNDING.yml
vendored
4
.github/FUNDING.yml
vendored
@@ -1,4 +1,2 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: JustArchi
|
||||
custom: ["https://paypal.me/JustArchi", "https://pay.revolut.com/justarchi", "https://commerce.coinbase.com/checkout/0c23b844-c51b-45f4-9135-8db7c6fcf98e", "https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_"]
|
||||
custom: ["https://paypal.me/JustArchi", "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4", "https://pay.revolut.com/justarchi", "https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_"]
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,8 +7,8 @@ contact_links:
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization
|
||||
about: Please use our crowdin platform
|
||||
- name: ❓ Support question or technical issue
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/blob/main/.github/SUPPORT.md
|
||||
about: Please review our support guidelines
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/discussions/categories/support-english
|
||||
about: Please use GitHub discussions or other support channels
|
||||
- name: 🗯️ Negative feedback, complaints and demands
|
||||
url: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
||||
about: We're taking those very seriously
|
||||
|
||||
4
.github/RELEASE_TEMPLATE.md
vendored
4
.github/RELEASE_TEMPLATE.md
vendored
@@ -14,4 +14,6 @@ This is automated GitHub deployment, human-readable changelog should be availabl
|
||||
|
||||
ASF is available for free, this release was made possible thanks to the people that decided to support the project. If you're grateful for what we're doing, please consider a donation. Developing ASF requires massive amount of time and knowledge, especially when it comes to Steam (and its problems). Even $1 is highly appreciated and shows that you care. Thank you!
|
||||
|
||||
[](https://github.com/sponsors/JustArchi) [](https://commerce.coinbase.com/checkout/0c23b844-c51b-45f4-9135-8db7c6fcf98e) [](https://paypal.me/JustArchi) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://pay.revolut.com/justarchi) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
|
||||
[](https://github.com/sponsors/JustArchi) [](https://paypal.me/JustArchi) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://pay.revolut.com/justarchi) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
|
||||
|
||||
[](https://www.blockchain.com/explorer/addresses/btc/3HwcgZbtoF5vSxJkNUvThVSJipKi7r5EqU) [](https://www.blockchain.com/explorer/addresses/eth/0xA1F7Ba62C5a3A8b93Fe6656936192432F328a366) [](https://live.blockcypher.com/ltc/address/MJCeBEZUsNgDhRhqbLFfPiDcf7CSrdvmZ3) [](https://etherscan.io/address/0xCf42D9F53F974CBd7c304eF0243CAe8e029885A8) [](https://etherscan.io/address/0x985FDdD3AD00838A2049B07A33b783104d60f776)
|
||||
|
||||
0
qodana.yaml → .github/qodana.yaml
vendored
0
qodana.yaml → .github/qodana.yaml
vendored
10
.github/renovate.json5
vendored
10
.github/renovate.json5
vendored
@@ -12,13 +12,5 @@
|
||||
],
|
||||
"git-submodules": {
|
||||
"enabled": true
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
// TODO: <= 1.7.0-rc.1 for invalid response on monitoring endpoint, last failed version 1.8.0-rc.1 - https://github.com/open-telemetry/opentelemetry-dotnet/issues/5506
|
||||
"allowedVersions": "<= 1.7.0-rc.1",
|
||||
"matchManagers": [ "nuget" ],
|
||||
"matchPackageNames": [ "OpenTelemetry.Exporter.Prometheus.AspNetCore" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -21,13 +21,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
uses: actions/setup-dotnet@v4.0.1
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
||||
|
||||
@@ -39,12 +39,3 @@ jobs:
|
||||
|
||||
- name: Run ${{ matrix.configuration }} ArchiSteamFarm.Tests
|
||||
run: dotnet test ArchiSteamFarm.Tests -c "${{ matrix.configuration }}" -p:ContinuousIntegrationBuild=true -p:UseAppHost=false --nologo
|
||||
|
||||
- name: Upload latest strings for translation on Crowdin
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.configuration == 'Release' && startsWith(matrix.os, 'ubuntu-') }}
|
||||
uses: crowdin/github-action@v1.20.2
|
||||
with:
|
||||
crowdin_branch_name: main
|
||||
config: '.github/crowdin.yml'
|
||||
project_id: ${{ secrets.ASF_CROWDIN_PROJECT_ID }}
|
||||
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
|
||||
|
||||
24
.github/workflows/code-quality.yml
vendored
24
.github/workflows/code-quality.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: ASF-code-quality
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
- push
|
||||
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
@@ -14,32 +15,25 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
environment: qa-qodana
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Checkout code (for PR)
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
fetch-depth: 100 # History is required for pull request analysis
|
||||
ref: ${{ github.event.pull_request.head.sha }} # To check out the actual pull request commit, not the merge commit
|
||||
show-progress: false
|
||||
|
||||
- name: Run Qodana scan
|
||||
uses: JetBrains/qodana-action@v2023.3.2
|
||||
uses: JetBrains/qodana-action@v2024.1.8
|
||||
with:
|
||||
args: --property=idea.headless.enable.statistics=false
|
||||
args: --config,.github/qodana.yaml,--property=idea.headless.enable.statistics=false
|
||||
pr-mode: false
|
||||
upload-result: true
|
||||
env:
|
||||
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
|
||||
|
||||
- name: Report Qodana results to GitHub
|
||||
uses: github/codeql-action/upload-sarif@v3.24.10
|
||||
uses: github/codeql-action/upload-sarif@v3.25.15
|
||||
with:
|
||||
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
|
||||
|
||||
28
.github/workflows/crowdin-ci.yml
vendored
Normal file
28
.github/workflows/crowdin-ci.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: ASF-crowdin-ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
environment: dev-crowdin
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Upload latest strings for translation on Crowdin
|
||||
uses: crowdin/github-action@v2.1.1
|
||||
with:
|
||||
crowdin_branch_name: main
|
||||
config: '.github/crowdin.yml'
|
||||
project_id: ${{ secrets.ASF_CROWDIN_PROJECT_ID }}
|
||||
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
|
||||
12
.github/workflows/docker-ci.yml
vendored
12
.github/workflows/docker-ci.yml
vendored
@@ -19,20 +19,20 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
uses: docker/build-push-action@v6.5.0
|
||||
with:
|
||||
build-args: CONFIGURATION=${{ matrix.configuration }}
|
||||
context: .
|
||||
file: ${{ matrix.file }}
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: |
|
||||
CONFIGURATION=${{ matrix.configuration }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
|
||||
27
.github/workflows/docker-publish-latest.yml
vendored
27
.github/workflows/docker-publish-latest.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
types: [released]
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: latest
|
||||
|
||||
@@ -14,40 +13,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -59,12 +50,16 @@ 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@v5.3.0
|
||||
uses: docker/build-push-action@v6.5.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.Service
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ env.FIXED_TAG }}
|
||||
|
||||
29
.github/workflows/docker-publish-main.yml
vendored
29
.github/workflows/docker-publish-main.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
- main
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: main
|
||||
|
||||
@@ -15,40 +14,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -59,11 +50,15 @@ 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@v5.3.0
|
||||
uses: docker/build-push-action@v6.5.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ github.sha }}
|
||||
@@ -77,6 +72,6 @@ jobs:
|
||||
uses: peter-evans/dockerhub-description@v4.0.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
repository: ${{ env.DH_REPOSITORY }}
|
||||
short-description: ${{ github.event.repository.description }}
|
||||
|
||||
27
.github/workflows/docker-publish-released.yml
vendored
27
.github/workflows/docker-publish-released.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: released
|
||||
|
||||
@@ -15,40 +14,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -60,11 +51,15 @@ 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@v5.3.0
|
||||
uses: docker/build-push-action@v6.5.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ env.FIXED_TAG }}
|
||||
|
||||
86
.github/workflows/publish.yml
vendored
86
.github/workflows/publish.yml
vendored
@@ -19,13 +19,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Node.js with npm
|
||||
uses: actions/setup-node@v4.0.2
|
||||
uses: actions/setup-node@v4.0.3
|
||||
with:
|
||||
check-latest: true
|
||||
node-version: ${{ env.NODE_JS_VERSION }}
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
run: npm run-script deploy --no-progress --prefix ASF-ui
|
||||
|
||||
- name: Upload ASF-ui
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ASF-ui
|
||||
@@ -73,16 +73,21 @@ jobs:
|
||||
- os: windows-latest
|
||||
variant: win-x64
|
||||
|
||||
environment: build
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
uses: actions/setup-dotnet@v4.0.1
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
||||
|
||||
@@ -90,7 +95,7 @@ jobs:
|
||||
run: dotnet --info
|
||||
|
||||
- name: Download previously built ASF-ui
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ASF-ui
|
||||
path: ASF-ui/dist
|
||||
@@ -355,8 +360,14 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
- name: Generate artifact attestation for ASF-${{ matrix.variant }}.zip
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/attest-build-provenance@v1.4.0
|
||||
with:
|
||||
subject-path: out/ASF-${{ matrix.variant }}.zip
|
||||
|
||||
- name: Upload ASF-${{ matrix.variant }}
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
|
||||
@@ -396,9 +407,15 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- 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@v1.4.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.3.1
|
||||
uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
@@ -407,71 +424,73 @@ jobs:
|
||||
release:
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
needs: publish-asf
|
||||
environment: release-github
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
attestations: write
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Download ASF-generic artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-generic
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-arm artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-arm
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-arm64 artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-x64 artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-x64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-osx-arm64 artifact from macos-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: macos-latest_ASF-osx-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-osx-x64 artifact from macos-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: macos-latest_ASF-osx-x64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-win-arm64 artifact from windows-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: windows-latest_ASF-win-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-win-x64 artifact from windows-latest
|
||||
uses: actions/download-artifact@v4.1.4
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: windows-latest_ASF-win-x64
|
||||
path: out
|
||||
|
||||
# TODO: Enable me when documentation is ready and plugin is stable for usage
|
||||
# - name: Download ArchiSteamFarm.OfficialPlugins.Monitoring artifact
|
||||
# uses: actions/download-artifact@v4.1.4
|
||||
# with:
|
||||
# name: ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
# path: out
|
||||
- name: Download ArchiSteamFarm.OfficialPlugins.Monitoring artifact
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
path: out
|
||||
|
||||
- name: Import GPG key for signing
|
||||
uses: crazy-max/ghaction-import-gpg@v6.1.0
|
||||
@@ -480,25 +499,32 @@ jobs:
|
||||
|
||||
- name: Generate SHA-512 checksums and signature
|
||||
shell: sh
|
||||
working-directory: out
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
(
|
||||
cd "out"
|
||||
sha512sum *.zip > SHA512SUMS
|
||||
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
|
||||
|
||||
sha512sum *.zip > SHA512SUMS
|
||||
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
|
||||
)
|
||||
- name: Generate artifact attestation for SHA512SUMS
|
||||
uses: actions/attest-build-provenance@v1.4.0
|
||||
with:
|
||||
subject-path: out/SHA512SUMS
|
||||
|
||||
- name: Upload SHA512SUMS
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: SHA512SUMS
|
||||
path: out/SHA512SUMS
|
||||
|
||||
- name: Generate artifact attestation for SHA512SUMS.sign
|
||||
uses: actions/attest-build-provenance@v1.4.0
|
||||
with:
|
||||
subject-path: out/SHA512SUMS.sign
|
||||
|
||||
- name: Upload SHA512SUMS.sign
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: SHA512SUMS.sign
|
||||
|
||||
11
.github/workflows/translations.yml
vendored
11
.github/workflows/translations.yml
vendored
@@ -10,11 +10,12 @@ permissions:
|
||||
|
||||
jobs:
|
||||
update:
|
||||
environment: dev-crowdin
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.1.7
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
@@ -22,16 +23,15 @@ jobs:
|
||||
|
||||
- name: Reset wiki to follow origin
|
||||
shell: sh
|
||||
working-directory: wiki
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
cd wiki
|
||||
|
||||
git fetch --depth=1 origin master
|
||||
git reset --hard origin/master
|
||||
|
||||
- name: Download latest translations from Crowdin
|
||||
uses: crowdin/github-action@v1.20.2
|
||||
uses: crowdin/github-action@v2.1.1
|
||||
with:
|
||||
upload_sources: false
|
||||
download_translations: true
|
||||
@@ -52,11 +52,10 @@ jobs:
|
||||
|
||||
- name: Commit the changes to wiki
|
||||
shell: sh
|
||||
working-directory: wiki
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
cd wiki
|
||||
|
||||
git add -A "locale"
|
||||
|
||||
if ! git diff --cached --quiet; then
|
||||
|
||||
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: d3082d36c1...29854276ef
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
|
||||
@@ -34,6 +34,7 @@ using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
@@ -45,7 +46,7 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
// If you do not want to handle a particular action (e.g. OnBotMessage that is offered in IBotMessage), it's the best idea to not inherit it at all
|
||||
// This will keep your code compact, efficient and less dependent. You can always add additional interfaces when you'll need them, this example project will inherit quite a bit of them to show you potential usage
|
||||
[SuppressMessage("ReSharper", "MemberCanBeFileLocal")]
|
||||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer {
|
||||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer2 {
|
||||
// This is used for identification purposes, typically you want to use a friendly name of your plugin here, such as the name of your main class
|
||||
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
|
||||
[JsonInclude]
|
||||
@@ -180,7 +181,7 @@ internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection,
|
||||
// It allows you not only to analyze such trades, but generate a response whether ASF should accept it (true), or proceed like usual (false)
|
||||
// Thanks to that, you can implement custom rules for all trades that aren't handled by ASF, for example cross-set trading on your own custom rules
|
||||
// You'd implement your own logic here, as an example we'll allow all trades to be accepted if the bot's name starts from "TrashBot"
|
||||
public Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer) => Task.FromResult(bot.BotName.StartsWith("TrashBot", StringComparison.OrdinalIgnoreCase));
|
||||
public Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer, ParseTradeResult.EResult asfResult) => Task.FromResult(bot.BotName.StartsWith("TrashBot", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// This is the earliest method that will be called, right after loading the plugin, long before any bot initialization takes place
|
||||
// It's a good place to initialize all potential (non-bot-specific) structures that you will need across lifetime of your plugin, such as global timers, concurrent dictionaries and alike
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp.XPath" IncludeAssets="compile" />
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
|
||||
|
||||
@@ -64,6 +64,18 @@
|
||||
<value>{0} sets ont été matché pendant ce round.</value>
|
||||
<comment>{0} will be replaced by number of sets traded</comment>
|
||||
</data>
|
||||
<data name="ListingAnnouncing" xml:space="preserve">
|
||||
<value>Annonce de {0} ({1}) avec l'inventaire réalisé à partir de {2} au total sur la liste...</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>Correspondance totale de {0} éléments avec le bot {1} ({2}), envoi de l'offre d'échange...</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>Impossible d'envoyer une offre d'échange au bot {0} ({1}), en cours ...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
|
||||
</data>
|
||||
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
|
||||
<value>Certaines confirmations ont échoué, environ {0} sur les transactions {1} ont été envoyées avec succès.</value>
|
||||
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
|
||||
|
||||
@@ -64,4 +64,20 @@
|
||||
<value>Potivim un total de {0} in această rundă.</value>
|
||||
<comment>{0} will be replaced by number of sets traded</comment>
|
||||
</data>
|
||||
<data name="ListingAnnouncing" xml:space="preserve">
|
||||
<value>Anunțând {0} ({1}) cu inventarul făcut din {2} articole în total pe listă...</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>Se potrivește cu un total de {0} elemente cu botul {1} ({2}), se trimite oferta de schimb...</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>Nu s-a putut trimite o cerere de schimb bot-ului {0} ({1}), trecem peste...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
|
||||
</data>
|
||||
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
|
||||
<value>Unele confirmări au eșuat, aproximativ {0} din {1} de schimburi au fost trimise cu succes.</value>
|
||||
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1164,7 +1164,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> MatchActively(IReadOnlyCollection<ListedUser> listedUsers, IReadOnlyCollection<Asset> ourAssets, IReadOnlyCollection<EAssetType> acceptedMatchableTypes) {
|
||||
private async Task<bool> MatchActively(ImmutableHashSet<ListedUser> listedUsers, HashSet<Asset> ourAssets, HashSet<EAssetType> acceptedMatchableTypes) {
|
||||
if ((listedUsers == null) || (listedUsers.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(listedUsers));
|
||||
}
|
||||
@@ -1439,7 +1439,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}");
|
||||
|
||||
(bool success, HashSet<ulong>? tradeOfferIDs, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
|
||||
(bool success, HashSet<ulong>? tradeOfferIDs, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, nameof(MatchActively), true).ConfigureAwait(false);
|
||||
|
||||
if (tradeOfferIDs?.Count > 0) {
|
||||
matchActivelyTradeOfferIDs.UnionWith(tradeOfferIDs);
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
|
||||
@@ -251,7 +251,11 @@ internal static class Commands {
|
||||
if (!string.IsNullOrEmpty(activationCode)) {
|
||||
string? generatedCode = await mobileAuthenticator.GenerateToken().ConfigureAwait(false);
|
||||
|
||||
if (generatedCode != activationCode) {
|
||||
if (string.IsNullOrEmpty(generatedCode)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(generatedCode)));
|
||||
}
|
||||
|
||||
if (!generatedCode.Equals(activationCode, StringComparison.OrdinalIgnoreCase)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{generatedCode} != {activationCode}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);overlay/**</DefaultItemExcludes>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
@@ -18,4 +18,12 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="overlay\all\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
@@ -35,6 +37,7 @@ using ArchiSteamFarm.IPC.Integration;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -45,7 +48,7 @@ namespace ArchiSteamFarm.OfficialPlugins.Monitoring;
|
||||
|
||||
[Export(typeof(IPlugin))]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeFileLocal")]
|
||||
internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IGitHubPluginUpdates, IDisposable {
|
||||
internal sealed class MonitoringPlugin : OfficialPlugin, IDisposable, IOfficialGitHubPluginUpdates, IWebInterface, IWebServiceProvider, IBotTradeOfferResults {
|
||||
private const string MeterName = SharedInfo.AssemblyName;
|
||||
|
||||
private const string MetricNamePrefix = "asf";
|
||||
@@ -67,6 +70,8 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
|
||||
private static bool Enabled => ASF.GlobalConfig?.IPC ?? GlobalConfig.DefaultIPC;
|
||||
|
||||
private static FrozenSet<Measurement<int>>? PluginMeasurements;
|
||||
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override string Name => nameof(MonitoringPlugin);
|
||||
@@ -77,10 +82,25 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
[Required]
|
||||
public override Version Version => typeof(MonitoringPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
private readonly ConcurrentDictionary<Bot, TradeStatistics> TradeStatistics = new();
|
||||
|
||||
private Meter? Meter;
|
||||
|
||||
public void Dispose() => Meter?.Dispose();
|
||||
|
||||
public Task OnBotTradeOfferResults(Bot bot, IReadOnlyCollection<ParseTradeResult> tradeResults) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
ArgumentNullException.ThrowIfNull(tradeResults);
|
||||
|
||||
TradeStatistics statistics = TradeStatistics.GetOrAdd(bot, static _ => new TradeStatistics());
|
||||
|
||||
foreach (ParseTradeResult result in tradeResults) {
|
||||
statistics.Include(result);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void OnConfiguringEndpoints(IApplicationBuilder app) {
|
||||
ArgumentNullException.ThrowIfNull(app);
|
||||
|
||||
@@ -119,6 +139,12 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
return;
|
||||
}
|
||||
|
||||
PluginMeasurements = new HashSet<Measurement<int>>(3) {
|
||||
new(PluginsCore.ActivePlugins.Count),
|
||||
new(PluginsCore.ActivePlugins.Count(static plugin => plugin is OfficialPlugin), new KeyValuePair<string, object?>(TagNames.PluginType, "official")),
|
||||
new(PluginsCore.ActivePlugins.Count(static plugin => plugin is not OfficialPlugin), new KeyValuePair<string, object?>(TagNames.PluginType, "custom"))
|
||||
}.ToFrozenSet();
|
||||
|
||||
Meter = new Meter(MeterName, Version.ToString());
|
||||
|
||||
Meter.CreateObservableGauge(
|
||||
@@ -141,7 +167,7 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
|
||||
Meter.CreateObservableGauge(
|
||||
$"{MetricNamePrefix}_active_plugins",
|
||||
static () => PluginsCore.ActivePluginsCount,
|
||||
static () => PluginMeasurements,
|
||||
description: "Number of plugins currently loaded in ASF"
|
||||
);
|
||||
|
||||
@@ -198,7 +224,7 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
$"{MetricNamePrefix}_bot_farming_time_remaining_{Units.Minutes}", static () => {
|
||||
IEnumerable<Bot> bots = Bot.Bots?.Values ?? [];
|
||||
|
||||
return bots.Select(static bot => new Measurement<double>(bot.CardsFarmer.TimeRemaining.TotalMinutes, new KeyValuePair<string, object?>(TagNames.BotName, bot.BotName), new KeyValuePair<string, object?>(TagNames.SteamID, bot.SteamID)));
|
||||
return bots.Where(static bot => bot.IsConnectedAndLoggedOn).Select(static bot => new Measurement<double>(bot.CardsFarmer.TimeRemaining.TotalMinutes, new KeyValuePair<string, object?>(TagNames.BotName, bot.BotName), new KeyValuePair<string, object?>(TagNames.SteamID, bot.SteamID)));
|
||||
},
|
||||
Units.Minutes,
|
||||
"Approximate number of minutes remaining until each bot has finished farming all cards"
|
||||
@@ -230,5 +256,53 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IWebServiceProvider, IG
|
||||
},
|
||||
description: "Remaining games to redeem in background per bot"
|
||||
);
|
||||
|
||||
Meter.CreateObservableCounter(
|
||||
$"{MetricNamePrefix}_bot_trades", () => TradeStatistics.SelectMany<KeyValuePair<Bot, TradeStatistics>, Measurement<int>>(
|
||||
static kv => [
|
||||
new Measurement<int>(
|
||||
kv.Value.AcceptedOffers,
|
||||
new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName),
|
||||
new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID),
|
||||
new KeyValuePair<string, object?>(TagNames.TradeOfferResult, "accepted")
|
||||
),
|
||||
new Measurement<int>(
|
||||
kv.Value.RejectedOffers,
|
||||
new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName),
|
||||
new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID),
|
||||
new KeyValuePair<string, object?>(TagNames.TradeOfferResult, "rejected")
|
||||
),
|
||||
new Measurement<int>(
|
||||
kv.Value.IgnoredOffers,
|
||||
new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName),
|
||||
new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID),
|
||||
new KeyValuePair<string, object?>(TagNames.TradeOfferResult, "ignored")
|
||||
),
|
||||
new Measurement<int>(
|
||||
kv.Value.BlacklistedOffers,
|
||||
new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName),
|
||||
new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID),
|
||||
new KeyValuePair<string, object?>(TagNames.TradeOfferResult, "blacklisted")
|
||||
),
|
||||
new Measurement<int>(
|
||||
kv.Value.ConfirmedOffers,
|
||||
new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName),
|
||||
new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID),
|
||||
new KeyValuePair<string, object?>(TagNames.TradeOfferResult, "confirmed")
|
||||
)
|
||||
]
|
||||
),
|
||||
description: "Trade offers per bot and action taken by ASF"
|
||||
);
|
||||
|
||||
Meter.CreateObservableCounter(
|
||||
$"{MetricNamePrefix}_bot_items_given", () => TradeStatistics.Select(static kv => new Measurement<int>(kv.Value.ItemsGiven, new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName), new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID))),
|
||||
description: "Items given per bot"
|
||||
);
|
||||
|
||||
Meter.CreateObservableCounter(
|
||||
$"{MetricNamePrefix}_bot_items_received", () => TradeStatistics.Select(static kv => new Measurement<int>(kv.Value.ItemsReceived, new KeyValuePair<string, object?>(TagNames.BotName, kv.Key.BotName), new KeyValuePair<string, object?>(TagNames.SteamID, kv.Key.SteamID))),
|
||||
description: "Items received per bot"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@ internal static class TagNames {
|
||||
internal const string CurrencyCode = "currency";
|
||||
internal const string Framework = "framework";
|
||||
internal const string OS = "operating_system";
|
||||
internal const string PluginType = "type";
|
||||
internal const string Runtime = "runtime";
|
||||
internal const string SteamID = "steamid";
|
||||
internal const string TradeOfferResult = "result";
|
||||
internal const string Variant = "variant";
|
||||
internal const string Version = "version";
|
||||
}
|
||||
|
||||
71
ArchiSteamFarm.OfficialPlugins.Monitoring/TradeStatistics.cs
Normal file
71
ArchiSteamFarm.OfficialPlugins.Monitoring/TradeStatistics.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.Monitoring;
|
||||
|
||||
internal sealed class TradeStatistics {
|
||||
private readonly object Lock = new();
|
||||
|
||||
internal int AcceptedOffers { get; private set; }
|
||||
internal int BlacklistedOffers { get; private set; }
|
||||
internal int ConfirmedOffers { get; private set; }
|
||||
internal int IgnoredOffers { get; private set; }
|
||||
internal int ItemsGiven { get; private set; }
|
||||
internal int ItemsReceived { get; private set; }
|
||||
internal int RejectedOffers { get; private set; }
|
||||
|
||||
internal void Include(ParseTradeResult result) {
|
||||
ArgumentNullException.ThrowIfNull(result);
|
||||
|
||||
lock (Lock) {
|
||||
switch (result.Result) {
|
||||
case ParseTradeResult.EResult.Accepted when result.Confirmed:
|
||||
ConfirmedOffers++;
|
||||
|
||||
ItemsGiven += result.ItemsToGive?.Count ?? 0;
|
||||
ItemsReceived += result.ItemsToReceive?.Count ?? 0;
|
||||
|
||||
goto case ParseTradeResult.EResult.Accepted;
|
||||
case ParseTradeResult.EResult.Accepted:
|
||||
AcceptedOffers++;
|
||||
|
||||
break;
|
||||
case ParseTradeResult.EResult.Rejected:
|
||||
RejectedOffers++;
|
||||
|
||||
break;
|
||||
case ParseTradeResult.EResult.Blacklisted:
|
||||
BlacklistedOffers++;
|
||||
|
||||
break;
|
||||
case ParseTradeResult.EResult.Ignored:
|
||||
IgnoredOffers++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
|
||||
|
||||
@@ -327,11 +327,17 @@ internal sealed class GlobalCache : SerializableFile {
|
||||
|
||||
StreamResponse? response = await ASF.WebBrowser.UrlGetToStream(request, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (response?.Content == null) {
|
||||
if (response == null) {
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
HashSet<uint> result;
|
||||
|
||||
await using (response.ConfigureAwait(false)) {
|
||||
if (response.Content == null) {
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
try {
|
||||
using StreamReader reader = new(response.Content);
|
||||
|
||||
@@ -343,7 +349,7 @@ internal sealed class GlobalCache : SerializableFile {
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
HashSet<uint> result = new(count);
|
||||
result = new HashSet<uint>(count);
|
||||
|
||||
while (await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false) is { Length: > 0 } line) {
|
||||
if (!uint.TryParse(line, out uint depotID) || (depotID == 0)) {
|
||||
@@ -354,13 +360,13 @@ internal sealed class GlobalCache : SerializableFile {
|
||||
|
||||
result.Add(depotID);
|
||||
}
|
||||
|
||||
return (result.Count > 0, result.ToFrozenSet());
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
|
||||
return (result.Count > 0, result.ToFrozenSet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,28 +60,80 @@
|
||||
<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} a fost dezactivat din cauza unui build token lipsă</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} este momentan dezactivat în funcție de configurația ta. Dacă doriți să ajutați SteamDB în transmiterea de date, vă rugăm să consultați wiki-ul.</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} a fost inițializat cu succes, mulțumim anticipat pentru ajutor. Prima depunere se va întâmpla în aproximativ {1} de acum.</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} nu a putut fi încărcat, o nouă instanță va fi inițializată...</value>
|
||||
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
|
||||
</data>
|
||||
<data name="BotNoAppsToRefresh" xml:space="preserve">
|
||||
<value>Nu există aplicații care să necesite o reîmprospătare la acest bot.</value>
|
||||
</data>
|
||||
<data name="BotRetrievingTotalAppAccessTokens" xml:space="preserve">
|
||||
<value>Preluarea unui total de {0} tokeni de acces...</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>Preluarea unui total de {0} tokeni de acces...</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>S-a terminat preluarea a {0} tokene de acces ale aplicației.</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>S-a terminat preluarea a {0} tokene de acces ale aplicației.</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>Se obțin toate depozitele pentru un total de {0} aplicații</value>
|
||||
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
|
||||
</data>
|
||||
<data name="BotRetrievingAppInfos" xml:space="preserve">
|
||||
<value>Se preiau {0} informații despre aplicații...</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>S-a terminat preluarea a {0} informații despre aplicații.</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} din {1} chei de depozit au fost recuperate cu succes.</value>
|
||||
<comment>{0} will be replaced by the number (count this batch) of depot keys that were successfully retrieved, {1} will be replaced by the number (count this batch) of depot keys that were supposed to be retrieved</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
|
||||
<value>S-a terminat preluarea tuturor depot keys pentru un total de {0} aplicații.</value>
|
||||
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
|
||||
</data>
|
||||
<data name="SubmissionNoNewData" xml:space="preserve">
|
||||
<value>Nu există date noi de trimis, totul este actualizat.</value>
|
||||
</data>
|
||||
<data name="SubmissionNoContributorSet" xml:space="preserve">
|
||||
<value>Nu s-au putut trimite datele deoarece nu există un set SteamID valid pe care să îl putem clasifica ca contributor. Luați în considerare configurarea proprietății {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>Trimiterea unui total de aplicații/pachete/depot-uri înregistrate: {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>Trimiterea a eșuat din cauza numărului prea mare de cereri trimise, vom încerca din nou în aproximativ {0} de acum.</value>
|
||||
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
|
||||
</data>
|
||||
<data name="SubmissionSuccessful" xml:space="preserve">
|
||||
<value>Datele au fost trimise cu succes. Serverul a înregistrat un total de aplicații/pachete/depot-uri noi: {0} ({1} verificat)/{2} ({3} verificat)/{4} ({5} verificat).</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>Aplicații noi: {0}</value>
|
||||
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
|
||||
@@ -102,9 +154,21 @@
|
||||
<value>Depozite noi: {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>Depot-uri verificate: {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} inițializat, plugin-ul nu va rezolva niciuna dintre acestea: {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>Se încarcă cache-ul global STD...</value>
|
||||
</data>
|
||||
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
|
||||
<value>Se validează integritatea globală STD...</value>
|
||||
</data>
|
||||
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
|
||||
<value>Nu s-a putut verifica integritatea globală STD a cache-ului. Acest lucru sugerează o potențială corupție de fișiere/memorie, o nouă instanță va fi inițializată în schimb.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="MSTest" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -25,4 +25,5 @@ using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: DiscoverInternals]
|
||||
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
@@ -30,10 +31,11 @@ using static ArchiSteamFarm.Steam.Bot;
|
||||
|
||||
namespace ArchiSteamFarm.Tests;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during MSTest
|
||||
[TestClass]
|
||||
public sealed class Bot {
|
||||
internal sealed class Bot {
|
||||
[TestMethod]
|
||||
public void MaxItemsBarelyEnoughForOneSet() {
|
||||
internal void MaxItemsBarelyEnoughForOneSet() {
|
||||
const uint relevantAppID = 42;
|
||||
|
||||
Dictionary<uint, byte> itemsPerSet = new() {
|
||||
@@ -57,7 +59,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MaxItemsTooSmall() {
|
||||
internal void MaxItemsTooSmall() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -69,7 +71,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MoreCardsThanNeeded() {
|
||||
internal void MoreCardsThanNeeded() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -91,7 +93,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultipleSets() {
|
||||
internal void MultipleSets() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -112,7 +114,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultipleSetsDifferentAmount() {
|
||||
internal void MultipleSetsDifferentAmount() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -132,7 +134,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MutliRarityAndType() {
|
||||
internal void MutliRarityAndType() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -173,7 +175,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NotAllCardsPresent() {
|
||||
internal void NotAllCardsPresent() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -188,7 +190,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OneSet() {
|
||||
internal void OneSet() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -207,7 +209,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherAppIDFullSets() {
|
||||
internal void OtherAppIDFullSets() {
|
||||
const uint appID0 = 42;
|
||||
const uint appID1 = 43;
|
||||
|
||||
@@ -232,7 +234,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherAppIDNoSets() {
|
||||
internal void OtherAppIDNoSets() {
|
||||
const uint appID0 = 42;
|
||||
const uint appID1 = 43;
|
||||
|
||||
@@ -254,7 +256,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherAppIDOneSet() {
|
||||
internal void OtherAppIDOneSet() {
|
||||
const uint appID0 = 42;
|
||||
const uint appID1 = 43;
|
||||
const uint appID2 = 44;
|
||||
@@ -286,7 +288,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherRarityFullSets() {
|
||||
internal void OtherRarityFullSets() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -304,7 +306,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherRarityNoSets() {
|
||||
internal void OtherRarityNoSets() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -320,7 +322,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherRarityOneSet() {
|
||||
internal void OtherRarityOneSet() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -343,7 +345,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherTypeFullSets() {
|
||||
internal void OtherTypeFullSets() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -361,7 +363,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherTypeNoSets() {
|
||||
internal void OtherTypeNoSets() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -377,7 +379,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherTypeOneSet() {
|
||||
internal void OtherTypeOneSet() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -400,7 +402,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TooHighAmount() {
|
||||
internal void TooHighAmount() {
|
||||
const uint appID0 = 42;
|
||||
|
||||
HashSet<Asset> items = [
|
||||
@@ -419,7 +421,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TooManyCardsForSingleTrade() {
|
||||
internal void TooManyCardsForSingleTrade() {
|
||||
const uint appID = 42;
|
||||
|
||||
HashSet<Asset> items = [];
|
||||
@@ -435,7 +437,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TooManyCardsForSingleTradeMultipleAppIDs() {
|
||||
internal void TooManyCardsForSingleTradeMultipleAppIDs() {
|
||||
const uint appID0 = 42;
|
||||
const uint appID1 = 43;
|
||||
|
||||
@@ -459,7 +461,7 @@ public sealed class Bot {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TooManyCardsPerSet() {
|
||||
internal void TooManyCardsPerSet() {
|
||||
const uint appID0 = 42;
|
||||
const uint appID1 = 43;
|
||||
const uint appID2 = 44;
|
||||
@@ -482,7 +484,7 @@ public sealed class Bot {
|
||||
);
|
||||
}
|
||||
|
||||
private static void AssertResultMatchesExpectation(IReadOnlyDictionary<(uint RealAppID, ulong ContextID, ulong ClassID), uint> expectedResult, IReadOnlyCollection<Asset> itemsToSend) {
|
||||
private static void AssertResultMatchesExpectation(Dictionary<(uint RealAppID, ulong ContextID, ulong ClassID), uint> expectedResult, IReadOnlyCollection<Asset> itemsToSend) {
|
||||
ArgumentNullException.ThrowIfNull(expectedResult);
|
||||
ArgumentNullException.ThrowIfNull(itemsToSend);
|
||||
|
||||
@@ -495,9 +497,10 @@ public sealed class Bot {
|
||||
|
||||
private static HashSet<Asset> GetItemsForFullBadge(IReadOnlyCollection<Asset> inventory, byte cardsPerSet, uint appID, ushort maxItems = Steam.Exchange.Trading.MaxItemsPerTrade) => GetItemsForFullBadge(inventory, new Dictionary<uint, byte> { { appID, cardsPerSet } }, maxItems);
|
||||
|
||||
private static HashSet<Asset> GetItemsForFullBadge(IReadOnlyCollection<Asset> inventory, IDictionary<uint, byte> cardsPerSet, ushort maxItems = Steam.Exchange.Trading.MaxItemsPerTrade) {
|
||||
private static HashSet<Asset> GetItemsForFullBadge(IReadOnlyCollection<Asset> inventory, [SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] Dictionary<uint, byte> cardsPerSet, ushort maxItems = Steam.Exchange.Trading.MaxItemsPerTrade) {
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), List<uint>> inventorySets = Steam.Exchange.Trading.GetInventorySets(inventory);
|
||||
|
||||
return GetItemsForFullSets(inventory, inventorySets.ToDictionary(static kv => kv.Key, kv => (SetsToExtract: inventorySets[kv.Key][0], cardsPerSet[kv.Key.RealAppID])), maxItems).ToHashSet();
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1812 // False positive, the class is used during MSTest
|
||||
|
||||
@@ -31,10 +31,11 @@ using static ArchiSteamFarm.Steam.Integration.SteamChatMessage;
|
||||
|
||||
namespace ArchiSteamFarm.Tests;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during MSTest
|
||||
[TestClass]
|
||||
public sealed class SteamChatMessage {
|
||||
internal sealed class SteamChatMessage {
|
||||
[TestMethod]
|
||||
public async Task CanSplitEvenWithStupidlyLongPrefix() {
|
||||
internal async Task CanSplitEvenWithStupidlyLongPrefix() {
|
||||
string prefix = new('x', MaxMessagePrefixBytes);
|
||||
|
||||
const string emoji = "😎";
|
||||
@@ -51,10 +52,10 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ContinuationCharacterSizeIsProperlyCalculated() => Assert.AreEqual(ContinuationCharacterBytes, Encoding.UTF8.GetByteCount(ContinuationCharacter.ToString()));
|
||||
internal void ContinuationCharacterSizeIsProperlyCalculated() => Assert.AreEqual(ContinuationCharacterBytes, Encoding.UTF8.GetByteCount(ContinuationCharacter.ToString()));
|
||||
|
||||
[TestMethod]
|
||||
public async Task DoesntSkipEmptyNewlines() {
|
||||
internal async Task DoesntSkipEmptyNewlines() {
|
||||
string message = $"asdf{Environment.NewLine}{Environment.NewLine}asdf";
|
||||
|
||||
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
|
||||
@@ -66,7 +67,7 @@ public sealed class SteamChatMessage {
|
||||
[DataRow(false)]
|
||||
[DataRow(true)]
|
||||
[DataTestMethod]
|
||||
public async Task DoesntSplitInTheMiddleOfMultiByteChar(bool isAccountLimited) {
|
||||
internal async Task DoesntSplitInTheMiddleOfMultiByteChar(bool isAccountLimited) {
|
||||
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
|
||||
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
|
||||
|
||||
@@ -84,7 +85,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task DoesntSplitJustBecauseOfLastEscapableCharacter() {
|
||||
internal async Task DoesntSplitJustBecauseOfLastEscapableCharacter() {
|
||||
const string message = "abcdef[";
|
||||
const string escapedMessage = @"abcdef\[";
|
||||
|
||||
@@ -97,7 +98,7 @@ public sealed class SteamChatMessage {
|
||||
[DataRow(false)]
|
||||
[DataRow(true)]
|
||||
[DataTestMethod]
|
||||
public async Task DoesntSplitOnBackslashNotUsedForEscaping(bool isAccountLimited) {
|
||||
internal async Task DoesntSplitOnBackslashNotUsedForEscaping(bool isAccountLimited) {
|
||||
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
|
||||
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
|
||||
|
||||
@@ -113,7 +114,7 @@ public sealed class SteamChatMessage {
|
||||
[DataRow(false)]
|
||||
[DataRow(true)]
|
||||
[DataTestMethod]
|
||||
public async Task DoesntSplitOnEscapeCharacter(bool isAccountLimited) {
|
||||
internal async Task DoesntSplitOnEscapeCharacter(bool isAccountLimited) {
|
||||
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
|
||||
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
|
||||
|
||||
@@ -129,7 +130,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task NoNeedForAnySplittingWithNewlines() {
|
||||
internal async Task NoNeedForAnySplittingWithNewlines() {
|
||||
string message = $"abcdef{Environment.NewLine}ghijkl{Environment.NewLine}mnopqr";
|
||||
|
||||
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
|
||||
@@ -139,7 +140,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task NoNeedForAnySplittingWithoutNewlines() {
|
||||
internal async Task NoNeedForAnySplittingWithoutNewlines() {
|
||||
const string message = "abcdef";
|
||||
|
||||
List<string> output = await GetMessageParts(message).ToListAsync().ConfigureAwait(false);
|
||||
@@ -149,10 +150,10 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ParagraphCharacterSizeIsLessOrEqualToContinuationCharacterSize() => Assert.IsTrue(ContinuationCharacterBytes >= Encoding.UTF8.GetByteCount(ParagraphCharacter.ToString()));
|
||||
internal void ParagraphCharacterSizeIsLessOrEqualToContinuationCharacterSize() => Assert.IsTrue(ContinuationCharacterBytes >= Encoding.UTF8.GetByteCount(ParagraphCharacter.ToString()));
|
||||
|
||||
[TestMethod]
|
||||
public async Task ProperlyEscapesCharacters() {
|
||||
internal async Task ProperlyEscapesCharacters() {
|
||||
const string message = @"[b]bold[/b] \n";
|
||||
const string escapedMessage = @"\[b]bold\[/b] \\n";
|
||||
|
||||
@@ -163,7 +164,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ProperlyEscapesSteamMessagePrefix() {
|
||||
internal async Task ProperlyEscapesSteamMessagePrefix() {
|
||||
const string prefix = "/pre []";
|
||||
const string escapedPrefix = @"/pre \[]";
|
||||
|
||||
@@ -178,7 +179,7 @@ public sealed class SteamChatMessage {
|
||||
[DataRow(false)]
|
||||
[DataRow(true)]
|
||||
[DataTestMethod]
|
||||
public async Task ProperlySplitsLongSingleLine(bool isAccountLimited) {
|
||||
internal async Task ProperlySplitsLongSingleLine(bool isAccountLimited) {
|
||||
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
|
||||
int longLineLength = maxMessageBytes - ReservedContinuationMessageBytes;
|
||||
|
||||
@@ -196,10 +197,10 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReservedSizeForEscapingIsProperlyCalculated() => Assert.AreEqual(ReservedEscapeMessageBytes, Encoding.UTF8.GetByteCount(@"\") + 4); // Maximum amount of bytes per single UTF-8 character is 4, not 6 as from Encoding.UTF8.GetMaxByteCount(1)
|
||||
internal void ReservedSizeForEscapingIsProperlyCalculated() => Assert.AreEqual(ReservedEscapeMessageBytes, Encoding.UTF8.GetByteCount(@"\") + 4); // Maximum amount of bytes per single UTF-8 character is 4, not 6 as from Encoding.UTF8.GetMaxByteCount(1)
|
||||
|
||||
[TestMethod]
|
||||
public async Task RyzhehvostInitialTestForSplitting() {
|
||||
internal async Task RyzhehvostInitialTestForSplitting() {
|
||||
const string prefix = "/me ";
|
||||
|
||||
const string message = """
|
||||
@@ -285,7 +286,7 @@ public sealed class SteamChatMessage {
|
||||
[DataRow(false)]
|
||||
[DataRow(true)]
|
||||
[DataTestMethod]
|
||||
public async Task SplitsOnNewlinesWithParagraphCharacter(bool isAccountLimited) {
|
||||
internal async Task SplitsOnNewlinesWithParagraphCharacter(bool isAccountLimited) {
|
||||
int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts;
|
||||
|
||||
StringBuilder newlinePartBuilder = new();
|
||||
@@ -314,7 +315,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ThrowsOnTooLongNewlinesPrefix() {
|
||||
internal async Task ThrowsOnTooLongNewlinesPrefix() {
|
||||
string prefix = new('\n', (MaxMessagePrefixBytes / NewlineWeight) + 1);
|
||||
|
||||
const string message = "asdf";
|
||||
@@ -323,7 +324,7 @@ public sealed class SteamChatMessage {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ThrowsOnTooLongPrefix() {
|
||||
internal async Task ThrowsOnTooLongPrefix() {
|
||||
string prefix = new('x', MaxMessagePrefixBytes + 1);
|
||||
|
||||
const string message = "asdf";
|
||||
@@ -331,3 +332,4 @@ public sealed class SteamChatMessage {
|
||||
await Assert.ThrowsExceptionAsync<ArgumentOutOfRangeException>(async () => await GetMessageParts(message, prefix).ToListAsync().ConfigureAwait(false)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1812 // False positive, the class is used during MSTest
|
||||
|
||||
@@ -28,10 +28,11 @@ using static ArchiSteamFarm.Steam.Exchange.Trading;
|
||||
|
||||
namespace ArchiSteamFarm.Tests;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during MSTest
|
||||
[TestClass]
|
||||
public sealed class Trading {
|
||||
internal sealed class Trading {
|
||||
[TestMethod]
|
||||
public void ExploitingNewSetsIsFairButNotNeutral() {
|
||||
internal void ExploitingNewSetsIsFairButNotNeutral() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 40),
|
||||
CreateItem(2, amount: 10),
|
||||
@@ -53,7 +54,31 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MismatchRarityIsNotFair() {
|
||||
internal void Issue3203() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2),
|
||||
CreateItem(2, amount: 6),
|
||||
CreateItem(3),
|
||||
CreateItem(4)
|
||||
];
|
||||
|
||||
HashSet<Asset> itemsToGive = [
|
||||
CreateItem(1),
|
||||
CreateItem(2, amount: 2)
|
||||
];
|
||||
|
||||
HashSet<Asset> itemsToReceive = [
|
||||
CreateItem(5),
|
||||
CreateItem(6),
|
||||
CreateItem(7)
|
||||
];
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
internal void MismatchRarityIsNotFair() {
|
||||
HashSet<Asset> itemsToGive = [
|
||||
CreateItem(1, rarity: EAssetRarity.Rare)
|
||||
];
|
||||
@@ -66,7 +91,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MismatchRealAppIDsIsNotFair() {
|
||||
internal void MismatchRealAppIDsIsNotFair() {
|
||||
HashSet<Asset> itemsToGive = [
|
||||
CreateItem(1, realAppID: 570)
|
||||
];
|
||||
@@ -79,7 +104,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MismatchTypesIsNotFair() {
|
||||
internal void MismatchTypesIsNotFair() {
|
||||
HashSet<Asset> itemsToGive = [
|
||||
CreateItem(1, type: EAssetType.Emoticon)
|
||||
];
|
||||
@@ -92,7 +117,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultiGameMultiTypeBadReject() {
|
||||
internal void MultiGameMultiTypeBadReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 9),
|
||||
CreateItem(3, amount: 9, realAppID: 730, type: EAssetType.Emoticon),
|
||||
@@ -114,7 +139,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultiGameMultiTypeNeutralAccept() {
|
||||
internal void MultiGameMultiTypeNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 9),
|
||||
CreateItem(3, realAppID: 730, type: EAssetType.Emoticon)
|
||||
@@ -135,7 +160,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultiGameSingleTypeBadReject() {
|
||||
internal void MultiGameSingleTypeBadReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 9),
|
||||
CreateItem(3, realAppID: 730),
|
||||
@@ -157,7 +182,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultiGameSingleTypeNeutralAccept() {
|
||||
internal void MultiGameSingleTypeNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2),
|
||||
CreateItem(3, realAppID: 730)
|
||||
@@ -178,7 +203,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameAbrynosWasWrongNeutralAccept() {
|
||||
internal void SingleGameAbrynosWasWrongNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2, amount: 2),
|
||||
@@ -200,7 +225,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameDonationAccept() {
|
||||
internal void SingleGameDonationAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1)
|
||||
];
|
||||
@@ -219,7 +244,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameMultiTypeBadReject() {
|
||||
internal void SingleGameMultiTypeBadReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 9),
|
||||
CreateItem(3, amount: 9, type: EAssetType.Emoticon),
|
||||
@@ -241,7 +266,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameMultiTypeNeutralAccept() {
|
||||
internal void SingleGameMultiTypeNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 9),
|
||||
CreateItem(3, type: EAssetType.Emoticon)
|
||||
@@ -262,7 +287,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameQuantityBadReject() {
|
||||
internal void SingleGameQuantityBadReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2),
|
||||
@@ -284,7 +309,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameQuantityBadReject2() {
|
||||
internal void SingleGameQuantityBadReject2() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2, amount: 2)
|
||||
@@ -304,7 +329,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameQuantityNeutralAccept() {
|
||||
internal void SingleGameQuantityNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2),
|
||||
CreateItem(2)
|
||||
@@ -324,7 +349,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeBadReject() {
|
||||
internal void SingleGameSingleTypeBadReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2)
|
||||
@@ -343,7 +368,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeBadWithOverpayingReject() {
|
||||
internal void SingleGameSingleTypeBadWithOverpayingReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2),
|
||||
CreateItem(2, amount: 2),
|
||||
@@ -364,7 +389,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeBigDifferenceAccept() {
|
||||
internal void SingleGameSingleTypeBigDifferenceAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2, amount: 5),
|
||||
@@ -384,7 +409,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeBigDifferenceReject() {
|
||||
internal void SingleGameSingleTypeBigDifferenceReject() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1),
|
||||
CreateItem(2, amount: 2),
|
||||
@@ -408,7 +433,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeGoodAccept() {
|
||||
internal void SingleGameSingleTypeGoodAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2)
|
||||
];
|
||||
@@ -426,7 +451,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeNeutralAccept() {
|
||||
internal void SingleGameSingleTypeNeutralAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1)
|
||||
];
|
||||
@@ -444,7 +469,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameSingleTypeNeutralWithOverpayingAccept() {
|
||||
internal void SingleGameSingleTypeNeutralWithOverpayingAccept() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 2),
|
||||
CreateItem(2, amount: 2)
|
||||
@@ -464,7 +489,7 @@ public sealed class Trading {
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TakingExcessiveAmountOfSingleCardCanStillBeFairAndNeutral() {
|
||||
internal void TakingExcessiveAmountOfSingleCardCanStillBeFairAndNeutral() {
|
||||
HashSet<Asset> inventory = [
|
||||
CreateItem(1, amount: 52),
|
||||
CreateItem(2, amount: 73),
|
||||
@@ -491,3 +516,4 @@ public sealed class Trading {
|
||||
|
||||
private static Asset CreateItem(ulong classID, ulong instanceID = 0, uint amount = 1, bool marketable = false, bool tradable = false, uint realAppID = Asset.SteamAppID, EAssetType type = EAssetType.TradingCard, EAssetRarity rarity = EAssetRarity.Common) => new(Asset.SteamAppID, Asset.SteamCommunityContextID, classID, amount, new InventoryDescription(Asset.SteamAppID, classID, instanceID, marketable, tradable, realAppID, type, rarity));
|
||||
}
|
||||
#pragma warning restore CA1812 // False positive, the class is used during MSTest
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using static ArchiSteamFarm.Core.Utilities;
|
||||
|
||||
namespace ArchiSteamFarm.Tests;
|
||||
|
||||
[TestClass]
|
||||
#pragma warning disable CA1724 // We don't care about the potential conflict, as ASF class name has a priority
|
||||
public sealed class Utilities {
|
||||
[TestMethod]
|
||||
public void AdditionallyForbiddenWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("10chars<!>asdf", new HashSet<string> { "chars<!>" }).IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void ContextSpecificWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("archisteamfarmpassword").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void EasyPasswordsHaveMeaningfulReason() {
|
||||
(bool isWeak, string? reason) = TestPasswordStrength("CorrectHorse");
|
||||
|
||||
Assert.IsTrue(isWeak);
|
||||
Assert.IsTrue(reason?.Contains("Capitalization doesn't help very much", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LongPassphraseIsNotWeak() => Assert.IsFalse(TestPasswordStrength("10chars<!>asdf").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void MemePasswordIsNotWeak() => Assert.IsFalse(TestPasswordStrength("correcthorsebatterystaple").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void RepeatedPasswordsHaveMeaningfulReason() {
|
||||
(bool isWeak, string? reason) = TestPasswordStrength("abcabcabc");
|
||||
|
||||
Assert.IsTrue(isWeak);
|
||||
Assert.IsTrue(reason?.Contains("Avoid repeated words and characters", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RepetitiveCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testaaaatest").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void SequentialCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testabcdtest").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void SequentialDescendingCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testdcbatest").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void ShortPassphraseIsWeak() => Assert.IsTrue(TestPasswordStrength("four").IsWeak);
|
||||
|
||||
[TestMethod]
|
||||
public void StraightRowsPasswordsHaveMeaningfulReason() {
|
||||
(bool isWeak, string? reason) = TestPasswordStrength("`1234567890-=");
|
||||
|
||||
Assert.IsTrue(isWeak);
|
||||
Assert.IsTrue(reason?.Contains("Straight rows of keys are easy to guess", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1724 // We don't care about the potential conflict, as ASF class name has a priority
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.6.30114.105
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm", "ArchiSteamFarm\ArchiSteamFarm.csproj", "{1501FF07-0114-473F-BDF2-7F8BA34C2948}"
|
||||
EndProject
|
||||
|
||||
@@ -166,6 +166,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5384/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5385/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5397/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CanSimplifyStringEscapeSequence/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassCanBeSealed_002EGlobal/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassCanBeSealed_002ELocal/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue">HINT</s:String>
|
||||
@@ -194,6 +195,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EntityFramework_002EModelValidation_002ECircularDependency/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ExtractCommonBranchingCode/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ExtractCommonPropertyPattern/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
@@ -252,7 +254,8 @@
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PlaceAssignmentExpressionIntoBlock/@EntryIndexedValue">DO_NOT_SHOW</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>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexedValue"></s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexRemoved">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantAttributeParentheses/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantBlankLines/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
|
||||
@@ -336,6 +339,9 @@
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=WrongMetadataUse/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=Xaml_002EIgnoredPathHighlighting/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/RunLongAnalysisInSwa/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/UsageOfDefaultStructEquality/CheckNonUserTypes/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/UseCollectionExpression/ConvertEmptyCollection/@EntryValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/UseStringInterpolation/ConvertToStringInterpolationWhenPossible/@EntryValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/FiltersState/=CodeStyle/@EntryIndexedValue">Default</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/FiltersState/=NamingFilter/@EntryIndexedValue">Default</s:String>
|
||||
@@ -518,6 +524,22 @@
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/XmlFormatter/WRAP_LINES/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><?xml version="1.0" encoding="utf-16"?>
|
||||
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
|
||||
<TypePattern DisplayName="Non-reorderable types" Priority="99999999">
|
||||
<TypePattern.Match>
|
||||
<Or>
|
||||
<And>
|
||||
<Kind Is="Interface" />
|
||||
<Or>
|
||||
<HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
|
||||
<HasAttribute Name="System.Runtime.InteropServices.ComImport" />
|
||||
</Or>
|
||||
</And>
|
||||
<Kind Is="Struct" />
|
||||
<HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" />
|
||||
<HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" />
|
||||
</Or>
|
||||
</TypePattern.Match>
|
||||
</TypePattern>
|
||||
<TypePattern DisplayName="ArchiPattern" Priority="150">
|
||||
<Entry DisplayName="Public (Events and Delegates)">
|
||||
<Entry.Match>
|
||||
|
||||
@@ -2,16 +2,11 @@
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);config/**;debug/**;logs/**;overlay/**</DefaultItemExcludes>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
||||
<!-- TODO: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2550 -->
|
||||
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp.XPath" />
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="CryptSharpStandard" />
|
||||
<PackageReference Include="Humanizer" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
@@ -25,7 +20,6 @@
|
||||
<PackageReference Include="System.Composition" />
|
||||
<PackageReference Include="System.Linq.Async" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
|
||||
<PackageReference Include="zxcvbn-core" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -105,6 +105,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
|
||||
}
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
public IEnumerator<T> GetEnumerator() => BackingCollection.Keys.GetEnumerator();
|
||||
|
||||
public void IntersectWith(IEnumerable<T> other) {
|
||||
@@ -207,6 +208,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
|
||||
Add(item);
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
[PublicAPI]
|
||||
|
||||
@@ -113,6 +113,7 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
|
||||
}
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
public IEnumerator<T> GetEnumerator() => new ConcurrentEnumerator<T>(BackingCollection, Lock.ReaderLock());
|
||||
|
||||
public int IndexOf(T item) {
|
||||
@@ -158,6 +159,7 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
|
||||
OnModified?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
[PublicAPI]
|
||||
|
||||
@@ -25,6 +25,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.Collections;
|
||||
|
||||
@@ -51,7 +52,10 @@ internal sealed class FixedSizeConcurrentQueue<T> : IEnumerable<T> where T : not
|
||||
MaxCount = maxCount;
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
public IEnumerator<T> GetEnumerator() => BackingQueue.GetEnumerator();
|
||||
|
||||
[MustDisposeResource]
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
internal void Enqueue(T obj) {
|
||||
|
||||
@@ -124,6 +124,7 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
|
||||
((ICollection<KeyValuePair<TKey, TValue>>) BackingDictionary).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => BackingDictionary.GetEnumerator();
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item) {
|
||||
@@ -162,6 +163,7 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
|
||||
return BackingDictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
[MustDisposeResource]
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
bool IReadOnlyDictionary<TKey, TValue>.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) {
|
||||
|
||||
@@ -25,12 +25,15 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Storage;
|
||||
|
||||
namespace ArchiSteamFarm.Core;
|
||||
|
||||
internal static class Events {
|
||||
internal static async Task OnBotShutdown() {
|
||||
if (Program.ProcessRequired || ((Bot.Bots != null) && Bot.Bots.Values.Any(static bot => bot.KeepRunning))) {
|
||||
bool shutdownIfPossible = ASF.GlobalConfig?.ShutdownIfPossible ?? GlobalConfig.DefaultShutdownIfPossible;
|
||||
|
||||
if (!shutdownIfPossible || (Bot.Bots?.Values.Any(static bot => bot.KeepRunning) == true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +42,7 @@ internal static class Events {
|
||||
// We give user extra 5 seconds for eventual config changes
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
if (Program.ProcessRequired || ((Bot.Bots != null) && Bot.Bots.Values.Any(static bot => bot.KeepRunning))) {
|
||||
if (Bot.Bots?.Values.Any(static bot => bot.KeepRunning) == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,12 +108,10 @@ internal static partial class NativeMethods {
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[SupportedOSPlatform("Windows")]
|
||||
internal struct FlashWindowInfo {
|
||||
#pragma warning disable Reordering // TODO: This silly pragma doesn't do anything, but it stops Rider from reordering, we may be able to get rid of it later
|
||||
public uint StructSize;
|
||||
public nint WindowHandle;
|
||||
public EFlashFlags Flags;
|
||||
public uint Count;
|
||||
public uint TimeoutBetweenFlashes;
|
||||
#pragma warning restore Reordering // TODO: This silly pragma doesn't do anything, but it stops Rider from reordering, we may be able to get rid of it later
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,9 @@ using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using SteamKit2;
|
||||
using Zxcvbn;
|
||||
|
||||
namespace ArchiSteamFarm.Core;
|
||||
|
||||
@@ -57,9 +55,6 @@ public static class Utilities {
|
||||
|
||||
private static readonly FrozenSet<char> DirectorySeparators = new HashSet<char>(2) { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.ToFrozenSet();
|
||||
|
||||
// normally we'd just use words like "steam" and "farm", but the library we're currently using is a bit iffy about banned words, so we need to also add combinations such as "steamfarm"
|
||||
private static readonly FrozenSet<string> ForbiddenPasswordPhrases = new HashSet<string>(10, StringComparer.InvariantCultureIgnoreCase) { "archisteamfarm", "archi", "steam", "farm", "archisteam", "archifarm", "steamfarm", "asf", "asffarm", "password" }.ToFrozenSet(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
[PublicAPI]
|
||||
public static string GenerateChecksumFor(byte[] source) {
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
@@ -293,40 +288,6 @@ public static class Utilities {
|
||||
ASF.ArchiLogger.LogGenericDebug($"{fileName} {progressPercentage}%...");
|
||||
}
|
||||
|
||||
internal static (bool IsWeak, string? Reason) TestPasswordStrength(string password, IEnumerable<string>? additionallyForbiddenPhrases = null) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(password);
|
||||
|
||||
HashSet<string> forbiddenPhrases = ForbiddenPasswordPhrases.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
if (additionallyForbiddenPhrases != null) {
|
||||
forbiddenPhrases.UnionWith(additionallyForbiddenPhrases);
|
||||
}
|
||||
|
||||
Result result = Zxcvbn.Core.EvaluatePassword(password, forbiddenPhrases);
|
||||
|
||||
IList<string>? suggestions = result.Feedback.Suggestions;
|
||||
|
||||
if (!string.IsNullOrEmpty(result.Feedback.Warning)) {
|
||||
suggestions ??= new List<string>(1);
|
||||
|
||||
suggestions.Insert(0, result.Feedback.Warning);
|
||||
}
|
||||
|
||||
if (suggestions != null) {
|
||||
for (byte i = 0; i < suggestions.Count; i++) {
|
||||
string suggestion = suggestions[i];
|
||||
|
||||
if ((suggestion.Length == 0) || (suggestion[^1] == '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
suggestions[i] = $"{suggestion}.";
|
||||
}
|
||||
}
|
||||
|
||||
return (result.Score < 4, suggestions is { Count: > 0 } ? string.Join(' ', suggestions.Where(static suggestion => suggestion.Length > 0)) : null);
|
||||
}
|
||||
|
||||
internal static async Task<bool> UpdateCleanup(string targetDirectory) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(targetDirectory);
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
@@ -47,8 +46,6 @@ public static class ArchiCryptoHelper {
|
||||
|
||||
internal static bool HasDefaultCryptKey { get; private set; } = true;
|
||||
|
||||
private static readonly FrozenSet<string> ForbiddenCryptKeyPhrases = new HashSet<string>(3, StringComparer.InvariantCultureIgnoreCase) { "crypt", "key", "cryptkey" }.ToFrozenSet(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
private static IEnumerable<byte> SteamParentalCharacters => Enumerable.Range('0', 10).Select(static character => (byte) character);
|
||||
|
||||
private static IEnumerable<byte[]> SteamParentalCodes {
|
||||
@@ -127,18 +124,12 @@ public static class ArchiCryptoHelper {
|
||||
throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(EHashingMethod));
|
||||
}
|
||||
|
||||
switch (hashingMethod) {
|
||||
case EHashingMethod.PlainText:
|
||||
return password;
|
||||
case EHashingMethod.SCrypt:
|
||||
return SCrypt.ComputeDerivedKey(password, salt, SteamParentalSCryptIterations, SteamParentalSCryptBlocksCount, 1, null, hashLength);
|
||||
case EHashingMethod.Pbkdf2:
|
||||
using (HMACSHA256 hashAlgorithm = new(password)) {
|
||||
return Pbkdf2.ComputeDerivedKey(hashAlgorithm, salt, SteamParentalPbkdf2Iterations, hashLength);
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException(nameof(hashingMethod));
|
||||
}
|
||||
return hashingMethod switch {
|
||||
EHashingMethod.PlainText => password,
|
||||
EHashingMethod.SCrypt => SCrypt.ComputeDerivedKey(password, salt, SteamParentalSCryptIterations, SteamParentalSCryptBlocksCount, 1, null, hashLength),
|
||||
EHashingMethod.Pbkdf2 => Rfc2898DeriveBytes.Pbkdf2(password, salt, SteamParentalPbkdf2Iterations, HashAlgorithmName.SHA256, hashLength),
|
||||
_ => throw new InvalidOperationException(nameof(hashingMethod))
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool HasTransformation(this ECryptoMethod cryptoMethod) =>
|
||||
@@ -179,16 +170,6 @@ public static class ArchiCryptoHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
Utilities.InBackground(
|
||||
() => {
|
||||
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(key, ForbiddenCryptKeyPhrases);
|
||||
|
||||
if (isWeak) {
|
||||
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningWeakCryptKey, reason));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
byte[] encryptionKey = Encoding.UTF8.GetBytes(key);
|
||||
|
||||
if (encryptionKey.Length < MinimumRecommendedCryptKeyBytes) {
|
||||
|
||||
@@ -123,7 +123,7 @@ internal static class ArchiKestrel {
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
ArgumentNullException.ThrowIfNull(app);
|
||||
|
||||
// The order of dependency injection is super important, doing things in wrong order will break everything
|
||||
// The order of dependency injection is super important, doing things in wrong order will most likely break everything
|
||||
// https://docs.microsoft.com/aspnet/core/fundamentals/middleware
|
||||
|
||||
// This one is easy, it's always in the beginning
|
||||
@@ -134,8 +134,9 @@ internal static class ArchiKestrel {
|
||||
// Add support for proxies, this one comes usually after developer exception page, but could be before
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
// Add support for response caching - must be called before static files as we want to cache those as well
|
||||
if (ASF.GlobalConfig?.OptimizationMode != GlobalConfig.EOptimizationMode.MinMemoryUsage) {
|
||||
// Add support for response caching - must be called before static files as we want to cache those as well
|
||||
// As previously in services, we skip it if memory usage is super important for us
|
||||
app.UseResponseCaching();
|
||||
}
|
||||
|
||||
@@ -157,50 +158,65 @@ internal static class ArchiKestrel {
|
||||
// Add support for default root path redirection (GET / -> GET /index.html), must come before static files
|
||||
app.UseDefaultFiles();
|
||||
|
||||
// Add support for additional default files provided by plugins
|
||||
Dictionary<string, string> pluginPaths = new(StringComparer.Ordinal);
|
||||
|
||||
if (PluginsCore.ActivePlugins.Count > 0) {
|
||||
foreach (IWebInterface plugin in PluginsCore.ActivePlugins.OfType<IWebInterface>()) {
|
||||
if (string.IsNullOrEmpty(plugin.PhysicalPath) || string.IsNullOrEmpty(plugin.WebPath)) {
|
||||
// Invalid path provided
|
||||
continue;
|
||||
foreach (IWebInterface plugin in PluginsCore.ActivePlugins.OfType<IWebInterface>()) {
|
||||
string physicalPath = plugin.PhysicalPath;
|
||||
|
||||
if (string.IsNullOrEmpty(physicalPath)) {
|
||||
// Invalid path provided
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, $"{nameof(physicalPath)} ({plugin.Name})"));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
string webPath = plugin.WebPath;
|
||||
|
||||
if (string.IsNullOrEmpty(webPath)) {
|
||||
// Invalid path provided
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, $"{nameof(webPath)} ({plugin.Name})"));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(physicalPath)) {
|
||||
// Relative path
|
||||
string? assemblyDirectory = Path.GetDirectoryName(plugin.GetType().Assembly.Location);
|
||||
|
||||
if (string.IsNullOrEmpty(assemblyDirectory)) {
|
||||
throw new InvalidOperationException(nameof(assemblyDirectory));
|
||||
}
|
||||
|
||||
string physicalPath = plugin.PhysicalPath;
|
||||
physicalPath = Path.Combine(assemblyDirectory, physicalPath);
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(physicalPath)) {
|
||||
// Relative path
|
||||
string? assemblyDirectory = Path.GetDirectoryName(plugin.GetType().Assembly.Location);
|
||||
if (!Directory.Exists(physicalPath)) {
|
||||
// Non-existing path provided
|
||||
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, $"{nameof(physicalPath)} ({plugin.Name})"));
|
||||
|
||||
if (string.IsNullOrEmpty(assemblyDirectory)) {
|
||||
throw new InvalidOperationException(nameof(assemblyDirectory));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
physicalPath = Path.Combine(assemblyDirectory, plugin.PhysicalPath);
|
||||
}
|
||||
pluginPaths[physicalPath] = webPath;
|
||||
|
||||
if (!Directory.Exists(physicalPath)) {
|
||||
// Non-existing path provided
|
||||
continue;
|
||||
}
|
||||
|
||||
pluginPaths[physicalPath] = plugin.WebPath;
|
||||
|
||||
if (plugin.WebPath != "/") {
|
||||
app.UseDefaultFiles(plugin.WebPath);
|
||||
}
|
||||
if (webPath != "/") {
|
||||
app.UseDefaultFiles(webPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Add support for static files from custom plugins (e.g. HTML, CSS and JS)
|
||||
// Add support for additional static files from custom plugins (e.g. HTML, CSS and JS)
|
||||
foreach ((string physicalPath, string webPath) in pluginPaths) {
|
||||
app.UseStaticFiles(
|
||||
new StaticFileOptions {
|
||||
FileProvider = new PhysicalFileProvider(physicalPath),
|
||||
OnPrepareResponse = OnPrepareResponse,
|
||||
RequestPath = webPath
|
||||
}
|
||||
);
|
||||
StaticFileOptions options = new() {
|
||||
FileProvider = new PhysicalFileProvider(physicalPath),
|
||||
OnPrepareResponse = OnPrepareResponse
|
||||
};
|
||||
|
||||
if (webPath != "/") {
|
||||
options.RequestPath = webPath;
|
||||
}
|
||||
|
||||
app.UseStaticFiles(options);
|
||||
}
|
||||
|
||||
// Add support for static files (e.g. HTML, CSS and JS from IPC GUI)
|
||||
@@ -216,10 +232,10 @@ internal static class ArchiKestrel {
|
||||
// We want to protect our API with IPCPassword and additional security, this should be called after routing, so the middleware won't have to deal with API endpoints that do not exist
|
||||
app.UseWhen(static context => context.Request.Path.StartsWithSegments("/Api", StringComparison.OrdinalIgnoreCase), static appBuilder => appBuilder.UseMiddleware<ApiAuthenticationMiddleware>());
|
||||
|
||||
// Add support for CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API
|
||||
string? ipcPassword = ASF.GlobalConfig != null ? ASF.GlobalConfig.IPCPassword : GlobalConfig.DefaultIPCPassword;
|
||||
|
||||
if (!string.IsNullOrEmpty(ipcPassword)) {
|
||||
// We want to apply CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API, this should be called before response compression, but can't be due to how our flow works
|
||||
// We apply CORS policy only with IPCPassword set as an extra authentication measure
|
||||
app.UseCors();
|
||||
}
|
||||
@@ -227,19 +243,18 @@ internal static class ArchiKestrel {
|
||||
// Add support for websockets that we use e.g. in /Api/NLog
|
||||
app.UseWebSockets();
|
||||
|
||||
// Finally register proper API endpoints once we're done with routing
|
||||
app.UseEndpoints(static endpoints => endpoints.MapControllers());
|
||||
|
||||
if (PluginsCore.ActivePlugins.Count > 0) {
|
||||
foreach (IWebServiceProvider plugin in PluginsCore.ActivePlugins.OfType<IWebServiceProvider>()) {
|
||||
try {
|
||||
plugin.OnConfiguringEndpoints(app);
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
// Add additional endpoints provided by plugins
|
||||
foreach (IWebServiceProvider plugin in PluginsCore.ActivePlugins.OfType<IWebServiceProvider>()) {
|
||||
try {
|
||||
plugin.OnConfiguringEndpoints(app);
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally register proper API endpoints once we're done with routing
|
||||
app.UseEndpoints(static endpoints => endpoints.MapControllers());
|
||||
|
||||
// Add support for swagger, responsible for automatic API documentation generation, this should be on the end, once we're done with API
|
||||
app.UseSwagger();
|
||||
|
||||
@@ -248,6 +263,8 @@ internal static class ArchiKestrel {
|
||||
static options => {
|
||||
options.DisplayRequestDuration();
|
||||
options.EnableDeepLinking();
|
||||
options.EnableTryItOutByDefault();
|
||||
options.ShowCommonExtensions();
|
||||
options.ShowExtensions();
|
||||
options.SwaggerEndpoint($"{SharedInfo.ASF}/swagger.json", $"{SharedInfo.ASF} API");
|
||||
}
|
||||
@@ -259,8 +276,8 @@ internal static class ArchiKestrel {
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
|
||||
// The order of dependency injection is super important, doing things in wrong order will break everything
|
||||
// Order in Configure() method is a good start
|
||||
// The order of dependency injection is super important, doing things in wrong order will most likely break everything
|
||||
// https://docs.microsoft.com/aspnet/core/fundamentals/middleware
|
||||
|
||||
// Prepare knownNetworks that we'll use in a second
|
||||
HashSet<string>? knownNetworksTexts = configuration.GetSection("Kestrel:KnownNetworks").Get<HashSet<string>>();
|
||||
@@ -269,7 +286,7 @@ internal static class ArchiKestrel {
|
||||
|
||||
if (knownNetworksTexts?.Count > 0) {
|
||||
// Use specified known networks
|
||||
knownNetworks = new HashSet<IPNetwork>();
|
||||
knownNetworks = [];
|
||||
|
||||
foreach (string knownNetworkText in knownNetworksTexts) {
|
||||
string[] addressParts = knownNetworkText.Split('/', 3, StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -298,18 +315,19 @@ internal static class ArchiKestrel {
|
||||
}
|
||||
);
|
||||
|
||||
// Add support for response caching
|
||||
if (ASF.GlobalConfig?.OptimizationMode != GlobalConfig.EOptimizationMode.MinMemoryUsage) {
|
||||
// Add support for response caching
|
||||
// We can skip it if memory usage is super important for us
|
||||
services.AddResponseCaching();
|
||||
}
|
||||
|
||||
// Add support for response compression
|
||||
services.AddResponseCompression(static options => options.EnableForHttps = true);
|
||||
|
||||
// Add support for CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API
|
||||
string? ipcPassword = ASF.GlobalConfig != null ? ASF.GlobalConfig.IPCPassword : GlobalConfig.DefaultIPCPassword;
|
||||
|
||||
if (!string.IsNullOrEmpty(ipcPassword)) {
|
||||
// We want to apply CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API
|
||||
// We apply CORS policy only with IPCPassword set as an extra authentication measure
|
||||
services.AddCors(static options => options.AddDefaultPolicy(static policyBuilder => policyBuilder.AllowAnyOrigin()));
|
||||
}
|
||||
@@ -377,30 +395,34 @@ internal static class ArchiKestrel {
|
||||
}
|
||||
);
|
||||
|
||||
// We need MVC for /Api, but we're going to use only a small subset of all available features
|
||||
IMvcBuilder mvc = services.AddControllers();
|
||||
// Add support for optional healtchecks
|
||||
services.AddHealthChecks();
|
||||
|
||||
// Add support for controllers declared in custom plugins
|
||||
if (PluginsCore.ActivePlugins.Count > 0) {
|
||||
HashSet<Assembly>? assemblies = PluginsCore.LoadAssemblies();
|
||||
|
||||
if (assemblies != null) {
|
||||
foreach (Assembly assembly in assemblies) {
|
||||
mvc.AddApplicationPart(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IWebServiceProvider plugin in PluginsCore.ActivePlugins.OfType<IWebServiceProvider>()) {
|
||||
try {
|
||||
plugin.OnConfiguringServices(services);
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
// Add support for additional services provided by plugins
|
||||
foreach (IWebServiceProvider plugin in PluginsCore.ActivePlugins.OfType<IWebServiceProvider>()) {
|
||||
try {
|
||||
plugin.OnConfiguringServices(services);
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// We need MVC for /Api, but we're going to use only a small subset of all available features
|
||||
IMvcBuilder mvc = services.AddControllers();
|
||||
|
||||
// Add support for additional controllers provided by plugins
|
||||
HashSet<Assembly>? assemblies = PluginsCore.LoadAssemblies();
|
||||
|
||||
if (assemblies != null) {
|
||||
foreach (Assembly assembly in assemblies) {
|
||||
mvc.AddApplicationPart(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
// Register discovered controllers
|
||||
mvc.AddControllersAsServices();
|
||||
|
||||
// Modify default JSON options
|
||||
mvc.AddJsonOptions(
|
||||
static options => {
|
||||
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerialierOptions : JsonUtilities.DefaultJsonSerialierOptions;
|
||||
@@ -413,15 +435,25 @@ internal static class ArchiKestrel {
|
||||
}
|
||||
|
||||
private static async Task<WebApplication> CreateWebApplication() {
|
||||
string customDirectory = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.WebsiteDirectory);
|
||||
string websiteDirectory = Directory.Exists(customDirectory) ? customDirectory : Path.Combine(AppContext.BaseDirectory, SharedInfo.WebsiteDirectory);
|
||||
// Try to initialize to custom www folder first
|
||||
string? webRootPath = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.WebsiteDirectory);
|
||||
|
||||
if (!Directory.Exists(webRootPath)) {
|
||||
// Try to initialize to standard www folder next
|
||||
webRootPath = Path.Combine(AppContext.BaseDirectory, SharedInfo.WebsiteDirectory);
|
||||
|
||||
if (!Directory.Exists(webRootPath)) {
|
||||
// Do not attempt to create a new directory, user has explicitly removed it
|
||||
webRootPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
// The order of dependency injection matters, pay attention to it
|
||||
WebApplicationBuilder builder = WebApplication.CreateEmptyBuilder(
|
||||
new WebApplicationOptions {
|
||||
ApplicationName = SharedInfo.AssemblyName,
|
||||
ContentRootPath = SharedInfo.HomeDirectory,
|
||||
WebRootPath = websiteDirectory
|
||||
WebRootPath = webRootPath
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -121,6 +121,10 @@ public sealed class ASFController : ArchiController {
|
||||
request.GlobalConfig.IPCPassword = ASF.GlobalConfig.IPCPassword;
|
||||
}
|
||||
|
||||
if (!request.GlobalConfig.IsLicenseIDSet && ASF.GlobalConfig.IsLicenseIDSet) {
|
||||
request.GlobalConfig.LicenseID = ASF.GlobalConfig.LicenseID;
|
||||
}
|
||||
|
||||
if (!request.GlobalConfig.IsWebProxyPasswordSet && ASF.GlobalConfig.IsWebProxyPasswordSet) {
|
||||
request.GlobalConfig.WebProxyPassword = ASF.GlobalConfig.WebProxyPassword;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,45 @@ using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
[Route("Api/Bot")]
|
||||
public sealed class BotController : ArchiController {
|
||||
/// <summary>
|
||||
/// Adds (free) licenses on given bots.
|
||||
/// </summary>
|
||||
[Consumes("application/json")]
|
||||
[HttpPost("{botNames:required}/AddLicense")]
|
||||
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, BotAddLicenseResponse>>>((int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
|
||||
public async Task<ActionResult<GenericResponse>> AddLicensePost(string botNames, [FromBody] BotAddLicenseRequest request) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(botNames);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
if ((request.Apps?.IsEmpty != false) && (request.Packages?.IsEmpty != false)) {
|
||||
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, $"{nameof(request.Apps)} && {nameof(request.Packages)}")));
|
||||
}
|
||||
|
||||
HashSet<Bot>? bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)));
|
||||
}
|
||||
|
||||
IList<BotAddLicenseResponse> results = await Utilities.InParallel(bots.Select(bot => AddLicense(bot, request))).ConfigureAwait(false);
|
||||
|
||||
Dictionary<string, BotAddLicenseResponse> result = new(bots.Count, Bot.BotsComparer);
|
||||
|
||||
foreach (Bot bot in bots) {
|
||||
result[bot.BotName] = results[result.Count];
|
||||
}
|
||||
|
||||
return Ok(new GenericResponse<IReadOnlyDictionary<string, BotAddLicenseResponse>>(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all files related to given bots.
|
||||
/// </summary>
|
||||
@@ -416,4 +449,46 @@ public sealed class BotController : ArchiController {
|
||||
|
||||
return Ok(new GenericResponse(results.All(static result => result.Success), string.Join(Environment.NewLine, results.Select(static result => result.Message))));
|
||||
}
|
||||
|
||||
private static async Task<BotAddLicenseResponse> AddLicense(Bot bot, BotAddLicenseRequest request) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
Dictionary<uint, AddLicenseResult>? apps = null;
|
||||
Dictionary<uint, AddLicenseResult>? packages = null;
|
||||
|
||||
if (request.Apps != null) {
|
||||
apps = new Dictionary<uint, AddLicenseResult>(request.Apps.Count);
|
||||
|
||||
foreach (uint appID in request.Apps) {
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
apps[appID] = new AddLicenseResult(EResult.Timeout, EPurchaseResultDetail.Timeout);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
(EResult result, IReadOnlyCollection<uint>? grantedApps, IReadOnlyCollection<uint>? grantedPackages) = await bot.Actions.AddFreeLicenseApp(appID).ConfigureAwait(false);
|
||||
|
||||
apps[appID] = new AddLicenseResult(result, (grantedApps?.Count > 0) || (grantedPackages?.Count > 0) ? EPurchaseResultDetail.NoDetail : EPurchaseResultDetail.InvalidData);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.Packages != null) {
|
||||
packages = new Dictionary<uint, AddLicenseResult>(request.Packages.Count);
|
||||
|
||||
foreach (uint subID in request.Packages) {
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
packages[subID] = new AddLicenseResult(EResult.Timeout, EPurchaseResultDetail.Timeout);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
(EResult result, EPurchaseResultDetail purchaseResultDetail) = await bot.Actions.AddFreeLicensePackage(subID).ConfigureAwait(false);
|
||||
|
||||
packages[subID] = new AddLicenseResult(result, purchaseResultDetail);
|
||||
}
|
||||
}
|
||||
|
||||
return new BotAddLicenseResponse(apps, packages);
|
||||
}
|
||||
}
|
||||
|
||||
58
ArchiSteamFarm/IPC/Controllers/Api/HealthCheckController.cs
Normal file
58
ArchiSteamFarm/IPC/Controllers/Api/HealthCheckController.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.IPC.Responses;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Produces("application/json")]
|
||||
[Route("/HealthCheck")]
|
||||
public sealed class HealthCheckController : ControllerBase {
|
||||
private readonly HealthCheckService HealthCheckService;
|
||||
|
||||
public HealthCheckController(HealthCheckService healthCheckService) {
|
||||
ArgumentNullException.ThrowIfNull(healthCheckService);
|
||||
|
||||
HealthCheckService = healthCheckService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(HealthCheckResponse), (int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(HealthCheckResponse), (int) HttpStatusCode.ServiceUnavailable)]
|
||||
public async Task<IActionResult> Get() {
|
||||
CancellationToken cancellationToken = HttpContext.RequestAborted;
|
||||
|
||||
HealthReport report = await HealthCheckService.CheckHealthAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
HealthCheckResponse response = new(report);
|
||||
|
||||
return response.Status == HealthStatus.Healthy ? Ok(response) : StatusCode((int) HttpStatusCode.ServiceUnavailable, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Extensions;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Integration;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class SwaggerSecurityCriticalAttribute : CustomSwaggerAttribute {
|
||||
private const string ExtensionName = "x-security-critical";
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
46
ArchiSteamFarm/IPC/Requests/BotAddLicenseRequest.cs
Normal file
46
ArchiSteamFarm/IPC/Requests/BotAddLicenseRequest.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotAddLicenseRequest {
|
||||
/// <summary>
|
||||
/// A collection (set) of apps (appIDs) to ask license for.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public ImmutableList<uint>? Apps { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection (set) of packages (subIDs) to ask license for.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public ImmutableList<uint>? Packages { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private BotAddLicenseRequest() { }
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public sealed class BotRedeemRequest {
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public ImmutableHashSet<string> KeysToRedeem { get; private init; } = [];
|
||||
public ImmutableList<string> KeysToRedeem { get; private init; } = [];
|
||||
|
||||
[JsonConstructor]
|
||||
private BotRedeemRequest() { }
|
||||
|
||||
55
ArchiSteamFarm/IPC/Responses/AddLicenseResult.cs
Normal file
55
ArchiSteamFarm/IPC/Responses/AddLicenseResult.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
public sealed class AddLicenseResult {
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public EPurchaseResultDetail PurchaseResultDetail { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public EResult Result { get; private init; }
|
||||
|
||||
internal AddLicenseResult(EResult result, EPurchaseResultDetail purchaseResultDetail) {
|
||||
if (!Enum.IsDefined(result)) {
|
||||
throw new InvalidEnumArgumentException(nameof(result), (int) result, typeof(EResult));
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(purchaseResultDetail)) {
|
||||
throw new InvalidEnumArgumentException(nameof(purchaseResultDetail), (int) purchaseResultDetail, typeof(EPurchaseResultDetail));
|
||||
}
|
||||
|
||||
Result = result;
|
||||
PurchaseResultDetail = purchaseResultDetail;
|
||||
}
|
||||
}
|
||||
47
ArchiSteamFarm/IPC/Responses/BotAddLicenseResponse.cs
Normal file
47
ArchiSteamFarm/IPC/Responses/BotAddLicenseResponse.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
public sealed class BotAddLicenseResponse {
|
||||
/// <summary>
|
||||
/// A collection (set) of apps (appIDs) to ask license for.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public ImmutableDictionary<uint, AddLicenseResult>? Apps { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection (set) of packages (subIDs) to ask license for.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public ImmutableDictionary<uint, AddLicenseResult>? Packages { get; private init; }
|
||||
|
||||
internal BotAddLicenseResponse(IReadOnlyDictionary<uint, AddLicenseResult>? apps, IReadOnlyDictionary<uint, AddLicenseResult>? packages) {
|
||||
Apps = apps?.ToImmutableDictionary();
|
||||
Packages = packages?.ToImmutableDictionary();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
@@ -31,16 +32,16 @@ public sealed class GamesToRedeemInBackgroundResponse {
|
||||
/// Keys that were redeemed and not used during the process, if available.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public Dictionary<string, string>? UnusedKeys { get; private init; }
|
||||
public ImmutableDictionary<string, string>? UnusedKeys { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Keys that were redeemed and used during the process, if available.
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public Dictionary<string, string>? UsedKeys { get; private init; }
|
||||
public ImmutableDictionary<string, string>? UsedKeys { get; private init; }
|
||||
|
||||
internal GamesToRedeemInBackgroundResponse(Dictionary<string, string>? unusedKeys = null, Dictionary<string, string>? usedKeys = null) {
|
||||
UnusedKeys = unusedKeys;
|
||||
UsedKeys = usedKeys;
|
||||
internal GamesToRedeemInBackgroundResponse(IReadOnlyDictionary<string, string>? unusedKeys = null, IReadOnlyDictionary<string, string>? usedKeys = null) {
|
||||
UnusedKeys = unusedKeys?.ToImmutableDictionary();
|
||||
UsedKeys = usedKeys?.ToImmutableDictionary();
|
||||
}
|
||||
}
|
||||
|
||||
46
ArchiSteamFarm/IPC/Responses/HealthCheckResponse.cs
Normal file
46
ArchiSteamFarm/IPC/Responses/HealthCheckResponse.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
public sealed class HealthCheckResponse {
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public string StatusText => Status.ToString();
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public HealthStatus Status { get; private init; }
|
||||
|
||||
internal HealthCheckResponse(HealthReport report) {
|
||||
ArgumentNullException.ThrowIfNull(report);
|
||||
|
||||
Status = report.Status;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@@ -35,7 +36,7 @@ public sealed class LogResponse {
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public IReadOnlyList<string> Content { get; private init; }
|
||||
public ImmutableList<string> Content { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of lines of the log file returned, can be used as an index for future requests.
|
||||
@@ -50,6 +51,6 @@ public sealed class LogResponse {
|
||||
ArgumentNullException.ThrowIfNull(content);
|
||||
|
||||
TotalLines = totalLines;
|
||||
Content = content;
|
||||
Content = content.ToImmutableList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
@@ -44,7 +45,7 @@ public sealed class TypeProperties {
|
||||
/// This can be used for determining main enum type if <see cref="BaseType" /> is <see cref="Enum" />.
|
||||
/// </remarks>
|
||||
[JsonInclude]
|
||||
public HashSet<string>? CustomAttributes { get; private init; }
|
||||
public ImmutableHashSet<string>? CustomAttributes { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Underlying type of given type, if available.
|
||||
@@ -55,9 +56,9 @@ public sealed class TypeProperties {
|
||||
[JsonInclude]
|
||||
public string? UnderlyingType { get; private init; }
|
||||
|
||||
internal TypeProperties(string? baseType = null, HashSet<string>? customAttributes = null, string? underlyingType = null) {
|
||||
internal TypeProperties(string? baseType = null, IEnumerable<string>? customAttributes = null, string? underlyingType = null) {
|
||||
BaseType = baseType;
|
||||
CustomAttributes = customAttributes;
|
||||
CustomAttributes = customAttributes?.ToImmutableHashSet();
|
||||
UnderlyingType = underlyingType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@@ -40,7 +41,7 @@ public sealed class TypeResponse {
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public Dictionary<string, string> Body { get; private init; }
|
||||
public ImmutableDictionary<string, string> Body { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of given type.
|
||||
@@ -50,11 +51,11 @@ public sealed class TypeResponse {
|
||||
[Required]
|
||||
public TypeProperties Properties { get; private init; }
|
||||
|
||||
internal TypeResponse(Dictionary<string, string> body, TypeProperties properties) {
|
||||
internal TypeResponse(IReadOnlyDictionary<string, string> body, TypeProperties properties) {
|
||||
ArgumentNullException.ThrowIfNull(body);
|
||||
ArgumentNullException.ThrowIfNull(properties);
|
||||
|
||||
Body = body;
|
||||
Body = body.ToImmutableDictionary();
|
||||
Properties = properties;
|
||||
}
|
||||
}
|
||||
|
||||
18
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
18
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
@@ -1119,24 +1119,6 @@ namespace ArchiSteamFarm.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
public static string WarningWeakIPCPassword {
|
||||
get {
|
||||
return ResourceManager.GetString("WarningWeakIPCPassword", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WarningWeakSteamPassword {
|
||||
get {
|
||||
return ResourceManager.GetString("WarningWeakSteamPassword", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WarningWeakCryptKey {
|
||||
get {
|
||||
return ResourceManager.GetString("WarningWeakCryptKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WarningTooShortCryptKey {
|
||||
get {
|
||||
return ResourceManager.GetString("WarningTooShortCryptKey", resourceCulture);
|
||||
|
||||
@@ -552,9 +552,6 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="PatchingFiles" xml:space="preserve">
|
||||
<value>Выпраўленне файлаў ASF...</value>
|
||||
</data>
|
||||
|
||||
@@ -684,18 +684,6 @@
|
||||
<value>{0} config file ще бъде прехвърлен на последния синтаксис...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Вашата IPC парола изглежда много слаба. Помислете за избиране на по-сложна за увеличаване на сигурността. Детайли: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Вашата Steam парола за {0} изглежда много слаба. Помислете за избиране на по-сложна за увеличаване на сигурността. Детайли: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Вашият криптиращ ключ изглежда много слаб. Помислете за избиране на по-сложна за увеличаване на сигурността. Детайли: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Вашият криптиращ ключ е много къс. Препоръчваме да ползвате някой, който е поне {0} байта (символа) голям.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -451,9 +451,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,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>Aplikace byla ukončena s chybovým kódem {0}!</value>
|
||||
<comment>{0} will be replaced by error code (number)</comment>
|
||||
</data>
|
||||
<data name="ErrorFailingRequest" xml:space="preserve">
|
||||
<value>Požadavek selhal: {0}</value>
|
||||
<comment>{0} will be replaced by URL of the request</comment>
|
||||
@@ -687,23 +690,14 @@ StackTrace:
|
||||
<value>{0} konfigurační soubor bude převeden na nejnovější syntaxi...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Vaše IPC heslo se zdá být slabé. Zvažte výběr silnějšího hesla pro zvýšení bezpečnosti. Detaily: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Vaše Steam heslo pro '{0}' se zdá být slabé. Pro větší zabezpečení zvažte změnu hesla na silnější variantu. Detaily: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Váš šifrovací klíč se zdá být slabý. Zvažte výběr silnější varianty pro zvýšení bezpečnosti. Detaily: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Váš šifrovací klíč je příliš krátký. Doporučujeme použít ten, který je alespoň {0} bajtů (znaků) dlouhý.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
</data>
|
||||
|
||||
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
|
||||
<value>Používáte {0} nastavení {1} vlastnosti, ale neposkytli jste vlastní --cryptkey. Pro zvýšení bezpečnosti byste měli poskytnout vlastní --cryptkey.</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>Používáte {0} nastavení vlastnosti {1}, ale neposkytuješ vlastní --cryptkey. To zcela ruší ochranu, protože ASF je nucen použít svůj vlastní (známý) klíč. Pro využití bezpečnostního přínosu nabízeného tímto nastavením, byste měli poskytnout vlastní --cryptkey.</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>
|
||||
@@ -749,17 +743,48 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
<data name="WarningSkipping" xml:space="preserve">
|
||||
<value>Přeskakování: {0}...</value>
|
||||
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
|
||||
</data>
|
||||
<data name="PluginUpdatesChecking" xml:space="preserve">
|
||||
<value>Kontrola aktualizací zásuvných modulů...</value>
|
||||
</data>
|
||||
<data name="PluginUpdateChecking" xml:space="preserve">
|
||||
<value>Kontrola aktualizace zásuvného modulu {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateNotFound" xml:space="preserve">
|
||||
<value>Není dostupná žádná aktualizace pro zásuvný modul {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>Nová verze zásuvného modulu {0} je k dispozici. Zvažte aktualizaci!</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFound" xml:space="preserve">
|
||||
<value>Nalezena aktualizace pro zásuvný modul {0} z verze {1} na {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>Aktualizuji zásuvný modul {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFinished" xml:space="preserve">
|
||||
<value>Aktualizace zásuvného modulu {0} byla provedena úspěšně, změny se projeví až při opětovném spuštění ASF.</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateEnabled" xml:space="preserve">
|
||||
<value>Zásuvný modul {0}/{1} byl zaregistrován a je mu umožněno provádět automatické aktualizace.</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>Zásuvnému modulu {0} ({1}) byly zakázány automatické aktualizace, přestože tuto funkci podporuje.</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>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>
|
||||
</root>
|
||||
|
||||
@@ -652,9 +652,6 @@ Processens oppetid: {1}</value>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
@@ -691,18 +691,6 @@ Prozesslaufzeit: {1}</value>
|
||||
<value>Die Konfigurationsdatei {0} wird zur neuesten Version migriert...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Ihr IPC-Passwort scheint schwach zu sein. Für erhöhte Sicherheit sollten Sie überlegen, ein Stärkeres auszusuchen. Details: {0} Ihr</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Ihr Steam-Passwort für '{0}' scheint schwach zu sein. Für erhöhte Sicherheit sollten Sie überlegen, ein Stärkeres auszusuchen. Details: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Ihr kryptografischer Schlüssel scheint schwach zu sein. Für erhöhte Sicherheit sollten Sie überlegen, einen Stärkeren auszusuchen. Details: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Ihr kryptografischer Schlüssel ist zu kurz. Wir empfehlen einen zu verwenden, der mindestens {0} Bytes (Zeichen) lang ist.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -687,18 +687,6 @@ StackTrace:
|
||||
<value>{0} αρχείο ρυθμίσεων θα μεταφερθεί στην τελευταία σύνταξη...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Ο κωδικός πρόσβασης IPC φαίνεται να είναι αδύναμος. Εξετάστε το ενδεχόμενο να επιλέξετε έναν ισχυρότερο για αυξημένη ασφάλεια. Λεπτομέρειες: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Ο κωδικός πρόσβασης Steam για το '{0}' φαίνεται να είναι αδύναμος. Εξετάστε το ενδεχόμενο να επιλέξετε έναν ισχυρότερο για αυξημένη ασφάλεια. Λεπτομέρειες: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Το κλειδί κρυπτογράφησής σας φαίνεται να είναι αδύναμο. Εξετάστε το ενδεχόμενο να επιλέξετε ένα ισχυρότερο για αυξημένη ασφάλεια. Λεπτομέρειες: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Το κλειδί κρυπτογράφησης σας είναι πολύ μικρό. Σας συνιστούμε να χρησιμοποιήσετε ένα που είναι τουλάχιστον {0} bytes (χαρακτήρες).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -689,18 +689,6 @@ Tiempo de actividad del proceso: {1}</value>
|
||||
<value>El archivo de configuración {0} será migrado a la sintaxis más reciente...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Parece que tu contraseña IPC es débil. Considera elegir una más fuerte para mayor seguridad. Detalles: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Parece que tu contraseña de Steam para '{0}' es débil. Considera elegir una más fuerte para mayor seguridad. Detalles: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Parece que tu clave de cifrado es débil. Considera elegir una más fuerte para mayor seguridad. Detalles: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Tu clave de cifrado es muy corta. Recomendamos usar una que tenga al menos {0} bytes (caracteres) de largo.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -266,9 +266,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -687,18 +687,6 @@ Prosessin käyttöaika: {1}</value>
|
||||
<value>{0} asetustiedosto muutetaan uusimpaan syntaksiin...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>IPC-salasanasi näyttää olevan heikko. Harkitse vahvemman salasanan valitsemista turvallisuuden parantamiseksi. Yksityiskohdat: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Steam-salasanasi '{0}' näyttää olevan heikko. Harkitse vahvemman salasanan valitsemista turvallisuuden lisäämiseksi. Yksityiskohdat: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Salausavaimesi näyttää olevan heikko. Harkitse vahvemman valintaa turvallisuuden parantamiseksi. Yksityiskohdat: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Salausavaimesi on liian lyhyt. Suosittelemme käyttämään salausavainta, joka on vähintään {0} tavua (merkkiä) pitkä.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -87,7 +87,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>Erreur : Sortie avec un code d'erreur non nul {0}!</value>
|
||||
<comment>{0} will be replaced by error code (number)</comment>
|
||||
</data>
|
||||
<data name="ErrorFailingRequest" xml:space="preserve">
|
||||
<value>Échec de la requête : {0}</value>
|
||||
<comment>{0} will be replaced by URL of the request</comment>
|
||||
@@ -687,23 +690,14 @@ Durée de fonctionnement : {1}</value>
|
||||
<value>Le fichier de configuration de {0} sera migré vers la dernière syntaxe...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Votre mot de passe IPC semble faible. Pensez à en choisir un plus fort pour plus de sécurité. Détails: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Votre mot de passe Steam pour '{0}' semble faible. Pensez à choisir un mot de passe plus fort pour plus de sécurité. Détails: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Votre clé de chiffrement semble faible. Pensez à en choisir une plus forte pour plus sécurité. Détails: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Votre clé de chiffrement est trop courte. Nous vous recommandons d'en utiliser une longue d'au moins {0} octets (caractères).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
</data>
|
||||
|
||||
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
|
||||
<value>Vous utilisez le paramètre {0} de la propriété {1} , mais vous n'avez pas fourni de --cryptkey personnalisé. Vous devriez fournir une --cryptkey personnalisée pour plus de sécurité.</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>Vous utilisez le paramètre {0} de la propriété {1} , mais vous n'avez pas fourni de --cryptkey personnalisé. Cela casse complètement la protection, car ASF est forcé d’utiliser sa propre clé (connue). Vous devez fournir une --cryptkey personnalisée pour utiliser les avantages de sécurité offerts par ce paramètre.</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>
|
||||
@@ -723,7 +717,9 @@ Durée de fonctionnement : {1}</value>
|
||||
<data name="ChecksumMissing" xml:space="preserve">
|
||||
<value>Le serveur distant n'a pas d'informations sur la version vers laquelle nous mettons à jour. Il est possible que la version ai été publiée récemment. Refus de procéder à la mise à jour pour plus de sécurité.</value>
|
||||
</data>
|
||||
|
||||
<data name="ChecksumTimeout" xml:space="preserve">
|
||||
<value>Impossible de récupérer la somme de contrôle du binaire téléchargé - refusant de procéder à la procédure de mise à jour en ce moment comme mesure de sécurité supplémentaire.</value>
|
||||
</data>
|
||||
<data name="ChecksumWrong" xml:space="preserve">
|
||||
<value>Le serveur distant a répondu avec une somme de contrôle différente, ce qui pourrait indiquer un téléchargement corrompu ou une attaque de type MITM. Refus de procéder à la mise à jour !</value>
|
||||
</data>
|
||||
@@ -746,20 +742,65 @@ Durée de fonctionnement : {1}</value>
|
||||
<value>ASF ne peut pas jouer l'application {0} car elle a une restriction relative à la région pour le pays {1} qui dure jusqu'à {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>Vous essayez d'exécuter le plugin officiel {0} en ne correspondant pas à la version ASF: {1} (attendu {2}). Cela suggère que vous fassiez quelque chose d'horriblement mauvais, que ce soit pour réparer votre configuration ou pour fournir --ignore-unsupported-environment argument si vous savez vraiment ce que vous faites.</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>Votre ASF a planté trop de fois récemment, et en raison de cela l'initialisation du processus a été désactivée. Recherchez, corrigez votre configuration, puis supprimez ASF. rash file from your config directory, or supply --ignore-unsupported-environment argument si vous savez vraiment ce que vous faites.</value>
|
||||
</data>
|
||||
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
|
||||
<value>L'agriculture {0} ({1}) est désactivée, car ce jeu est actuellement marqué comme privé. Si vous avez l'intention d'ASF de cultiver ce jeu, alors envisagez de modifier ses paramètres de confidentialité.</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>Ignorer : {0}...</value>
|
||||
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
|
||||
</data>
|
||||
<data name="PluginUpdatesChecking" xml:space="preserve">
|
||||
<value>Vérification des mises à jour du plugin...</value>
|
||||
</data>
|
||||
<data name="PluginUpdateChecking" xml:space="preserve">
|
||||
<value>Vérification de la mise à jour du plugin {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateNotFound" xml:space="preserve">
|
||||
<value>Aucune mise à jour disponible pour le 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>La nouvelle version du plugin {0} est disponible! Pensez à vous mettre à jour !</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFound" xml:space="preserve">
|
||||
<value>Mise à jour du plugin {0} trouvée de la version {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="PluginUpdateNoAssetFound" xml:space="preserve">
|
||||
<value>Aucune ressource disponible pour la mise à jour du plugin {0} de la version {1} vers {2}, cela signifie généralement que la mise à jour sera disponible plus tard.</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>Aucune ressource n'a pu être déterminée pour la mise à jour du plugin {0} de la version {1} à {2}. Cela peut se produire si la version n'est pas encore terminée - si cela continue de se produire, vous devriez en informer le créateur du plugin.</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>Mise à jour du plugin {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFinished" xml:space="preserve">
|
||||
<value>La mise à jour du plugin {0} a réussi, les modifications seront chargées au prochain lancement d'ASF.</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateEnabled" xml:space="preserve">
|
||||
<value>Le plugin {0}/{1} a été enregistré et activé pour les mises à jour automatiques.</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>Le plugin {0} ({1}) a été désactivé à partir des mises à jour automatiques, malgré la prise en charge de cette fonctionnalité.</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>Les plugins personnalisés ont été enregistrés pour les mises à jour automatiques. L'équipe ASF voudrait vous rappeler que, pour votre propre sécurité, vous ne devriez activer les mises à jour automatiques que des groupes de confiance. Si vous n'aviez pas l'intention de le faire, vous pouvez désactiver les mises à jour de plugin dans la configuration globale d'ASF.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -687,18 +687,6 @@ StackTrace:
|
||||
<value>קובץ ה-config שמיקומו {0} יועבר לתחביר העדכני ביותר...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>נראה שסיסמת ה-IPC שלך חלשה. שקול לבחור חזק יותר להגברת האבטחה. פרטים: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>נראה שהסיסמה שלך ב-Steam עבור '{0}' חלשה. שקול לבחור חזק יותר להגברת האבטחה. פרטים: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>מפתח ההצפנה שלך נראה חלש. שקול לבחור חזק יותר להגברת האבטחה. פרטים: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>מפתח ההצפנה שלך קצר מדי. אנו ממליצים להשתמש באחד שאורכו לפחות {0} בייטים (תווים).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -682,18 +682,6 @@ Ennyi ideje fut: {1}</value>
|
||||
<value>A(z) {0} konfigurációs fájl a legújabb szintaxisra kerül áttelepítésre...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Úgy tűnik, hogy az IPC jelszava gyenge. Fontolja meg, hogy erősebbet válasszon a nagyobb biztonság érdekében. Részletek: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Úgy tűnik, hogy a(z) '{0}' Steam jelszava gyenge. Fontolja meg, hogy erősebbet válasszon a nagyobb biztonság érdekében. Részletek: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Úgy tűnik, hogy a titkosítási kulcsa gyenge. Fontolja meg, hogy erősebbet válasszon a nagyobb biztonság érdekében. Részletek: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>A titkosítási kulcs túl rövid. Azt javasoljuk, hogy legalább {0} bájt (karakter) hosszúságú legyen.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -686,9 +686,6 @@ Waktu aktif proses: {1}</value>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="ErrorIPNotBanned" xml:space="preserve">
|
||||
<value>Alamat IP {0} tidak diblokir!</value>
|
||||
<comment>{0} will be replaced by an IP address which was requested to be unbanned from using IPC</comment>
|
||||
|
||||
@@ -688,18 +688,6 @@ Tempo di attività: {1}</value>
|
||||
<value>Il file di configurazione {0} verrà migrato all'ultima sintassi...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>La tua password IPC sembra essere debole. Considera di sceglierne una più forte per una maggiore sicurezza. Dettagli: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>La tua password di Steam per '{0}' sembra essere debole. Considera di sceglierne una più forte per una maggiore sicurezza. Dettagli: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>La tua chiave di crittografia sembra essere debole. Considera di sceglierne una più forte per una maggiore sicurezza. Dettagli: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>La chiave di crittografia è troppo corta. Si consiglia di utilizzarne una lunga almeno {0} byte (caratteri).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -684,18 +684,6 @@ Process uptime: {1}</value>
|
||||
<value>{0} 設定ファイルは最新の構文に移行されます...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>IPCパスワードが弱いようです。セキュリティを強化するためにもっと強力なパスワードを選択してください。詳細: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>あなたのSteamパスワード '{0}' は脆弱なようです。セキュリティを強化するために、より強力なパスワードを選択することを検討してください。詳細: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>暗号化キーが弱いようです。セキュリティを強化するために強力なキーを選択することを検討してください。詳細: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>暗号化キーが短すぎます。少なくとも {0} バイト (文字) の長いものを使用することをお勧めします。</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -280,9 +280,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -690,18 +690,6 @@ StackTrace:
|
||||
<value>{0} 설정 파일이 최신 버전으로 업데이트 됩니다</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>IPC 비밀번호가 쉬워 보입니다. 보안을 강화하기 위하여 더 복잡한 비밀번호를 사용하는 것을 고려해 보세요. 자세한 설명: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>'{0}'을(를) 위한 Steam 비밀번호가 쉬워 보입니다. 보안을 강화하기 위하여 더 복잡한 비밀번호를 사용하는 것을 고려해 보세요. 자세한 설명: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>암호키가 쉬워 보입니다. 보안을 강화하기 위하여 더 복잡한 암호키를 사용하는 것을 고려해 보세요. 자세한 설명: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>암호키가 너무 짧습니다. 최소한 {0} 바이트(글자수) 길이 이상의 암호키를 사용하는 것을 추천합니다.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -687,18 +687,6 @@ Proceso veikimo laikas: {1}</value>
|
||||
<value>{0} konfigūracinis failas bus migruojamas į naujausią sintaksę...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Jūsų IPC aplinkos slaptažodis yra silpnas. Pagalvokite pasirinkti stipresnį slaptažodį, kad geriau apsisaugotumėte. Detalės {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Jūsų „Steam“ slaptažodis paskyrai '{0}' yra silpnas. Pagalvokite pasirinkti stipresnį slaptažodį, kad geriau apsisaugotumėte. Detalės: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Jūsų šifravimo raktas yra silpnas. Pagalvokite pasirinkti stipresnį šifravimo raktą, kad geriau apsisaugotumėte. Detalės {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Jūsų šifravimo raktas yra per trumpas. Rekomenduojame naudoti raktą, kuris yra bent {0} baitų (simbolių) ilgio.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -687,18 +687,6 @@ Darbspējas laiks: {1}</value>
|
||||
<value>{0} konfigurācijas fails tiks migrēts uz jaunāko sintaksi...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>IPC parole ir vāja. Apsver iespēju izvēlēties stiprāku paroli papildu drošībai. Detaļas: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Steam parole lietotājam '{0}' ir vāja. Apsver iespēju izvēlēties stiprāku paroli papildu drošībai. Detaļas: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Šifrēšanas atslēga ir vāja. Apsver iespēju izvēlēties stiprāku paroli papildu drošībai. Detaļas: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Šifrēšanas atslēga ir pārāk īsa. Mēs iesakām izmantot tādu, kas ir vismaz {0} baitus (simbolus) gara.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -683,18 +683,6 @@ Proces uptime: {1}</value>
|
||||
<value>{0} configuratiebestand zal worden gemigreerd naar de laatste syntaxis...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Uw IPC wachtwoord is zwak. Vanwege beveiliging redenen zal het veiliger zijn om een sterker wachtwoord te kiezen. Details: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Je Steam wachtwoord voor '{0}' lijkt zwak te zijn. Overweeg om een sterker wachtwoord te kiezen voor betere veiligheid. Details: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Uw IPC wachtwoord is zwak. Vanwege beveiliging redenen zal het veiliger zijn om een sterker wachtwoord te kiezen. Details: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<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>
|
||||
|
||||
@@ -87,37 +87,79 @@ 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>Avslutter med {0} feilkode!</value>
|
||||
<comment>{0} will be replaced by error code (number)</comment>
|
||||
</data>
|
||||
<data name="ErrorFailingRequest" xml:space="preserve">
|
||||
<value>Forespørsel feiler: {0}</value>
|
||||
<comment>{0} will be replaced by URL of the request</comment>
|
||||
</data>
|
||||
<data name="ErrorGlobalConfigNotLoaded" xml:space="preserve">
|
||||
<value>Global konfigurasjon kunne ikke lastes. Kontroller at {0} eksisterer og er gyldig! Følg "setting up" guide på wiki hvis du er forvirret.</value>
|
||||
<comment>{0} will be replaced by file's path</comment>
|
||||
</data>
|
||||
<data name="ErrorIsInvalid" xml:space="preserve">
|
||||
<value>{0} er ugyldig!</value>
|
||||
<comment>{0} will be replaced by object's name</comment>
|
||||
</data>
|
||||
|
||||
<data name="ErrorNoBotsDefined" xml:space="preserve">
|
||||
<value>Ingen bots er definert. Har du glemt å konfigurere din ASF? Følg "setting up"-guide på wikien dersom du er forvirret.</value>
|
||||
</data>
|
||||
<data name="ErrorObjectIsNull" xml:space="preserve">
|
||||
<value>{0} er null!</value>
|
||||
<comment>{0} will be replaced by object's name</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="ErrorParsingObject" xml:space="preserve">
|
||||
<value>Parsing {0} feilet!</value>
|
||||
<comment>{0} will be replaced by object's name</comment>
|
||||
</data>
|
||||
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
|
||||
<value>Forespørsel mislyktes etter {0} forsøk!</value>
|
||||
<comment>{0} will be replaced by maximum number of tries</comment>
|
||||
</data>
|
||||
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
|
||||
<value>Kunne ikke sjekke den nyeste versjonen!</value>
|
||||
</data>
|
||||
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
|
||||
<value>Kunne ikke fortsette med oppdateringen fordi det ikke er noen ressurs tilknyttet den kjørende versjonen! Automatisk oppdatering til den versjonen er ikke mulig.</value>
|
||||
</data>
|
||||
<data name="ErrorUpdateNoAssets" xml:space="preserve">
|
||||
<value>Kunne ikke fortsette med en oppdatering fordi den versjonen inkluderer ingen ressurser!</value>
|
||||
</data>
|
||||
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
|
||||
<value>Mottok en forespørsel for brukerinnputt, men prosessen kjører i hodeløs-modus!</value>
|
||||
</data>
|
||||
<data name="Exiting" xml:space="preserve">
|
||||
<value>Avslutter...</value>
|
||||
</data>
|
||||
<data name="WarningFailed" xml:space="preserve">
|
||||
<value>Mislykket!</value>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="GlobalConfigChanged" xml:space="preserve">
|
||||
<value>Global konfigurasjonsfil er endret!</value>
|
||||
</data>
|
||||
<data name="ErrorGlobalConfigRemoved" xml:space="preserve">
|
||||
<value>Global konfigurasjonsfil er fjernet!</value>
|
||||
</data>
|
||||
<data name="IgnoringTrade" xml:space="preserve">
|
||||
<value>Ignorerer handel: {0}</value>
|
||||
<comment>{0} will be replaced by trade number</comment>
|
||||
</data>
|
||||
<data name="LoggingIn" xml:space="preserve">
|
||||
<value>Logger inn på {0}...</value>
|
||||
<comment>{0} will be replaced by service's name</comment>
|
||||
</data>
|
||||
<data name="NoBotsAreRunning" xml:space="preserve">
|
||||
<value>Ingen bots kjører, avslutter...</value>
|
||||
</data>
|
||||
<data name="RefreshingOurSession" xml:space="preserve">
|
||||
<value>Oppdaterer økten!</value>
|
||||
</data>
|
||||
<data name="RejectingTrade" xml:space="preserve">
|
||||
<value>Avviser handel: {0}</value>
|
||||
<comment>{0} will be replaced by trade number</comment>
|
||||
</data>
|
||||
<data name="Restarting" xml:space="preserve">
|
||||
<value>Restarter...</value>
|
||||
</data>
|
||||
@@ -127,15 +169,22 @@ StackTrace:
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>Suksess!</value>
|
||||
</data>
|
||||
|
||||
<data name="UnlockingParentalAccount" xml:space="preserve">
|
||||
<value>Låse opp foreldrekonto...</value>
|
||||
</data>
|
||||
<data name="UpdateCheckingNewVersion" xml:space="preserve">
|
||||
<value>Ser etter ny versjon...</value>
|
||||
</data>
|
||||
|
||||
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
|
||||
<value>Laster ned ny versjon: {0} ({1} MB)... Mens du venter kan du kanskje vurdere å donere om du setter pris på arbeidet vårt! :)</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">
|
||||
<value>Oppdateringsprosessen er ferdig!</value>
|
||||
</data>
|
||||
|
||||
<data name="UpdateNewVersionAvailable" xml:space="preserve">
|
||||
<value>Ny ASF-versjon er tilgjengelig! Vurder å oppdatere!</value>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
@@ -344,9 +393,6 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -690,18 +690,6 @@ Czas procesu: {1}</value>
|
||||
<value>{0} plik konfiguracyjny zostanie przeniesiony do najnowszej składni...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Twoje hasło IPC wydaje się słabe. Rozważ wybór silniejszego dla zwiększenia bezpieczeństwa. Szczegóły: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Twoje hasło Steam dla '{0}' wydaje się słabe. Rozważ wybór silniejszego dla zwiększenia bezpieczeństwa. Szczegóły: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Twój klucz szyfrowania wydaje się słaby. Rozważ wybór silniejszego dla zwiększenia bezpieczeństwa. Szczegóły: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Twój klucz szyfrowania jest zbyt krótki. Zalecamy użyć takiego, który ma co najmniej {0} bajtów (znaków).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -690,18 +690,6 @@ Tempo de execução: {1}</value>
|
||||
<value>O arquivo de configuração {0} será migrado para a última sintaxe...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>A senha do servidor IPC é muito fraca. Escolha uma senha mais forte para aumentar a segurança. Detalhes: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>A senha da conta Steam "{0}" é muito fraca. Escolha uma senha mais forte para aumentar a segurança. Detalhes: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>A chave de criptografia é muito fraca. Escolha uma senha mais forte para aumentar a segurança. Detalhes: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>A chave de criptografia é muito curta. Recomendamos usar uma chave que tenha pelo menos {0} bytes (caracteres) de comprimento.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
@@ -770,10 +758,10 @@ Tempo de execução: {1}</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>
|
||||
<value>Procurando por atualizações de plugins...</value>
|
||||
</data>
|
||||
<data name="PluginUpdateChecking" xml:space="preserve">
|
||||
<value>Verificando atualizações para o plugin {0}...</value>
|
||||
<value>Verificando atualização para o plugin {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateNotFound" xml:space="preserve">
|
||||
@@ -793,7 +781,7 @@ Tempo de execução: {1}</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 recurso pôde ser determinado para a atualização do plugin {0} da versão {1} para {2}. Isso pode acontecer se a atualização ainda não estiver concluída - se isso continuar acontecendo, você deve notificar o criador do plugin sobre isso.</value>
|
||||
<value>Nenhum recurso pôde ser determinado para a atualização do plugin {0} da versão {1} para {2}. Isso pode acontecer caso a atualizaçã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">
|
||||
@@ -801,7 +789,7 @@ Tempo de execução: {1}</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFinished" xml:space="preserve">
|
||||
<value>A atualização do plugin {0} foi bem-sucedida. As alterações serão carregadas na próxima inicialização do ASF.</value>
|
||||
<value>A atualização do plugin {0} foi bem-sucedida, 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">
|
||||
|
||||
@@ -687,18 +687,6 @@ Tempo de execução: {1}</value>
|
||||
<value>{0} ficheiro de configuração vai ser migrado para a sintaxe mais recente...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>A tua senha IPC parece ser fraca. Considera escolher uma mais forte para uma melhor segurança. Detalhes: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>A tua senha do Steam para '{0}' parece ser fraca. Considera escolher uma mais forte para uma melhor segurança. Detalhes: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>A tua chave de encriptação parece ser fraca. Considera escolher uma mais forte para uma melhor segurança. Detalhes: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>A tua chave de encriptação é demasiado curta. Recomendamos uma que seja pelo menos {0} bytes (carateres) de comprimento.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -690,18 +690,6 @@ PROCES UPTIME: {1}</value>
|
||||
<value>{0} CONFIG FILE WILL BE MIGRATD 2 TEH LATEST SYNTAX...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>UR IPC PASWORD SEEMS 2 BE WEAK. CONSIDR CHOOSIN STRONGR WAN 4 INCREASD SECURITY. DETAILS: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>UR STEAM PASWORD 4 '{0}' SEEMS 2 BE WEAK. CONSIDR CHOOSIN STRONGR WAN 4 INCREASD SECURITY. DETAILS: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>UR ENCRYPSHUN KEY SEEMS 2 BE WEAK. CONSIDR CHOOSIN STRONGR WAN 4 INCREASD SECURITY. DETAILS: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>UR ENCRYPSHUN KEY IZ 2 SHORT. WE RECOMMEND 2 USE WAN DAT IZ AT LEAST {0} BYTEZ (CHARACTERS) LONG.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -690,18 +690,6 @@ Process uptime: {1}</value>
|
||||
<value>{0} config file will be migrated to the latest syntax...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Your IPC password seems to be weak. Consider choosing a stronger one for increased security. Details: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Your Steam password for '{0}' seems to be weak. Consider choosing a stronger one for increased security. Details: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Your encryption key seems to be weak. Consider choosing a stronger one for increased security. Details: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Your encryption key is too short. We recommend to use one that is at least {0} bytes (characters) long.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -87,7 +87,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>Ieşire cu codul de eroare {0}!</value>
|
||||
<comment>{0} will be replaced by error code (number)</comment>
|
||||
</data>
|
||||
<data name="ErrorFailingRequest" xml:space="preserve">
|
||||
<value>Cerere eșuată: {0}</value>
|
||||
<comment>{0} will be replaced by URL of the request</comment>
|
||||
@@ -186,7 +189,10 @@ StackTrace:
|
||||
<value>Versiunea locală: {0} | Ultima versiune: {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>Vă rugăm să verificați aplicația mobilă Steam, ar fi trebuit să primiți o notificare de aprobare a autentificării. Tastați Y dacă ați primit și aprobat notificarea, N dacă doriți să furnizați codul: </value>
|
||||
<comment>Please note that this translation should end with space</comment>
|
||||
</data>
|
||||
<data name="UserInputSteam2FA" xml:space="preserve">
|
||||
<value>Te rog să introduci codul 2FA de pe autentificatorul Steam: </value>
|
||||
<comment>Please note that this translation should end with space</comment>
|
||||
@@ -684,35 +690,39 @@ Proces: {1}</value>
|
||||
<value>Fișierul de configurare {0} va fi migrat la cea mai recentă sintaxă...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Parola dvs. IPC pare a fi slaba. Va rugam sa considerați sa alegeți o parola mai complexa. Detail: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Parola dvs. de Steam este slaba. Va rugam sa considerați sa alegeți o parola mai complexa. Detail</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Cheia dvs. de encripție este slaba. Va rugam sa considerați sa alegeți o cheie mai complexa. Detail: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Cheia dvs. de encripție este prea scurta. Va recomandam sa folosii o parola cu minim {0} caractere.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
</data>
|
||||
|
||||
|
||||
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
|
||||
<value>Se utilizează setarea {0} pentru proprietatea {1}, dar nu ați furnizat un --cryptkey personalizat. Puteți oferi un particularizat --cryptkey pentru o securitate sporită dacă doriți.</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>Utilizați setarea {0} pentru proprietatea {1}, dar nu ați furnizat un --cryptkey. Acest lucru contravine în totalitate protecției, întrucât ASF este forțat să își utilizeze propria cheie (cunoscută). Ar trebui să furnizați un --cryptkey pentru utilizarea beneficiului de securitate oferit de această setare.</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>Dvs încercați sa rulați ASF ca administrator, ASF nu are nevoie de elevație la nivel de administrator. Pentru securitatea calculatorului dvs, va recomandam sa rulați aplicația fără permisi de administrator.</value>
|
||||
</data>
|
||||
|
||||
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
|
||||
<value>Se rulează ASF într-un mediu nesuportat cu argumentul--ignore-unsupported-environment. Rețineți că nu oferim niciun fel de sprijin în acest scenariu și că îl faceți pe propriul risc. Ați fost avertizat.</value>
|
||||
</data>
|
||||
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
|
||||
<value>Se preia "checksum" de la serverul de la distanta...</value>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
|
||||
<value>Verificarea checksum al binarului descărcat în fața celui de pe serverul de la distanță...</value>
|
||||
</data>
|
||||
<data name="ChecksumMissing" xml:space="preserve">
|
||||
<value>Serverul de la distanţă nu ştie nimic despre versiunea la care actualizăm. Această situație este posibilă în cazul în care versiunea a fost publicată recent - refuzul de a continua imediat procedura de actualizare este ca măsură de securitate suplimentară.</value>
|
||||
</data>
|
||||
<data name="ChecksumTimeout" xml:space="preserve">
|
||||
<value>Nu s-a reușit preluarea sumei de verificare a binarului descărcat - refuzul de a continua procedura de actualizare în acest moment ca măsură suplimentară de securitate.</value>
|
||||
</data>
|
||||
<data name="ChecksumWrong" xml:space="preserve">
|
||||
<value>Serverul de la distanță a răspuns cu un alt checksum. Acest lucru ar putea indica un atac de tip MITM. Se refuză continuarea actualizării!</value>
|
||||
</data>
|
||||
<data name="PatchingFiles" xml:space="preserve">
|
||||
<value>Se repara fișierele ASF...</value>
|
||||
</data>
|
||||
@@ -724,22 +734,73 @@ Proces: {1}</value>
|
||||
<value>Adresa IP {0} nu este interzisă!</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>Ați încercat să utilizați caracteristica {0} plătită, dar nu aveți un cod valid de LicenseID în configurația globală ASF. Vă rugăm să examinați configurația, deoarece funcționalitatea nu va funcționa fără detalii suplimentare.</value>
|
||||
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
|
||||
</data>
|
||||
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
|
||||
<value>ASF nu poate juca aplicația {0} deoarece are restricții legate de regiune pentru țara {1} care durează până la {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>Încercaţi să rulaţi plugin-ul oficial {0} în neconcordanţă cu versiunea ASF: {1} (aşteptat {2}). Asta sugerează că faci ceva îngrozitor de greșit, fie repară-ți configurarea sau aprovizionarea, argumentul ignorat pentru mediu dacă știi cu adevărat ce faci.</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-ul tău s-a bușit de prea multe ori recent, și din cauza faptului că inițializarea procesului a fost dezactivată. Fie investigați, reparați configurarea, apoi eliminați ASF.crash din directorul de configurare, sau furnizați argumentul --ignore-unsupported-environment dacă știi cu adevărat ce faci.</value>
|
||||
</data>
|
||||
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
|
||||
<value>Agricultura {0} ({1}) este dezactivată, deoarece jocul este în prezent marcat ca privat. Dacă intenționezi de la ASF la ferma acel joc, atunci ia în considerare schimbarea setărilor de confidențialitate.</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>Omitere: {0}...</value>
|
||||
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
|
||||
</data>
|
||||
<data name="PluginUpdatesChecking" xml:space="preserve">
|
||||
<value>Se caută actualizări ale plugin-ului...</value>
|
||||
</data>
|
||||
<data name="PluginUpdateChecking" xml:space="preserve">
|
||||
<value>Se caută actualizări pentru plugin-ul {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateNotFound" xml:space="preserve">
|
||||
<value>Nu este disponibilă nicio actualizare pentru plugin-ul {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>Este disponibila o noua versiune de plugin {0}! Luati in considerare actualizarea!</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFound" xml:space="preserve">
|
||||
<value>S-a găsit o actualizare {0} plugin de la versiunea {1} la {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>Nici o resursă disponibilă pentru {0} actualizare plugin de la versiunea {1} la {2}, aceasta înseamnă de obicei că actualizarea va fi disponibilă mai târziu.</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>Nicio resursă nu a putut fi determinată pentru actualizarea plugin-ului {0} de la versiunea {1} la {2}. Acest lucru se poate întâmpla în cazul în care versiunea nu este finalizată încă - dacă se continuă să se întâmple, trebuie să notificați creatorul plugin-ului despre acest lucru.</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>Se actualizează plugin-ul {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFinished" xml:space="preserve">
|
||||
<value>Actualizarea plugin-ului {0} a reușit, modificările vor fi încărcate la următoarea lansare ASF.</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateEnabled" xml:space="preserve">
|
||||
<value>Plugin-ul {0}/{1} a fost înregistrat şi activat pentru actualizări automate.</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>Plugin-ul {0} ({1}) a fost dezactivat din actualizările automate, în ciuda susţinerii unei astfel de funcţii.</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>Au fost înregistrate plugin-uri personalizate pentru actualizări automate. Echipa ASF ar dori să vă reamintească că, pentru siguranța proprie, ar trebui să activați actualizările automate doar de la sursele de încredere. Dacă nu intenționați să faceți acest lucru, puteți dezactiva actualizările plugin-urilor în configurarea globală ASF.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -690,18 +690,6 @@
|
||||
<value>{0} файл конфигурации будет переведет на последнюю версию синтаксиса...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Ваш пароль IPC кажется ненадежным. Подумайте о том, чтобы использовать более надежный вариант для повышения безопасности. Подробности: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Ваш пароль Steam для '{0}' кажется ненадежным. Подумайте о том, чтобы использовать более надежный пароль для повышения безопасности. Подробности: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Ваш ключ шифрования кажется слабым. Подумайте о том, чтобы использовать более надежный вариант для повышения безопасности. Подробности: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Ваш ключ шифрования слишком короткий. Мы рекомендуем использовать тот, который имеет длину не менее {0} байт (символов).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
@@ -729,7 +717,9 @@
|
||||
<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>Удаленный сервер ответил с другой контрольной суммой, это может означать поврежденную загрузку или Атаку посредника-MITM, отказ от процедуры обновления!</value>
|
||||
</data>
|
||||
|
||||
@@ -691,18 +691,6 @@ Interaktívna konzola je teraz aktívna, napíšte "c" pre vstup do príkazovéh
|
||||
<value>{0} konfiguračný súbor bude prevedený na najnovšiu syntax...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Vaše IPC heslo sa zdá byť slabé. Zvážte výber silnejšieho hesla pre zvýšenie bezpečnosti. Detaily: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Vaše Steam heslo pre '{0}' se zdá byť slabé. Zvážte výber silnejšieho hesla pre zvýšenie bezpečnosti. Detaily: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Váš šifrovací kľuč se zdá byť slabý. Zvážte výber silnejšej varianty pre zvýšenie bezpečnosti. Detaily: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Váš šifrovací kľuč je príliš krátky. Doporučujeme použiť ten, ktorý je aspoň {0} bajtu (znakov) dlhý.</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
|
||||
@@ -690,9 +690,6 @@ Vrijeme rada procesa: {1}</value>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -553,9 +553,6 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -558,9 +558,6 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
|
||||
<value>กำลังดึงข้อมูล checksum จากเซิร์ฟเวอร์ระยะไกล...</value>
|
||||
</data>
|
||||
|
||||
@@ -687,21 +687,9 @@ Süreç çalışma zamanı: {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} yapılandırma dosyası en sondaki söz dizimine taşınacak...</value>
|
||||
<value>{0} yapılandırma dosyası en son sürüm söz dizimine aktarılacak...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>IPC parolanız zayıf görünüyor. Daha fazla güvenlik için daha güçlü bir tane seçmeyi düşünün. Ayrıntılar: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>'{0}' için Steam parolanız zayıf görünüyor. Daha fazla güvenlik için daha güçlü bir tane seçmeyi düşünün. Ayrıntılar: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Şifreleme anahtarınız zayıf görünüyor. Daha fazla güvenlik için daha güçlü bir tane seçmeyi düşünün. Ayrıntılar: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</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>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
@@ -729,7 +717,9 @@ Süreç çalışma zamanı: {1}</value>
|
||||
<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>
|
||||
</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>
|
||||
</data>
|
||||
@@ -774,14 +764,43 @@ Süreç çalışma zamanı: {1}</value>
|
||||
<value>{0} eklentisi için güncellemesi denetleniyor...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="PluginUpdateNotFound" xml:space="preserve">
|
||||
<value>{0} eklentisi için güncelleme mevcut değil: {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} eklentisinin yeni sürümü mevcut! Güncellemeyi düşünün!</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFound" xml:space="preserve">
|
||||
<value>{1} sürümünden {2} sürümüne {0} eklentisinin güncellemesi bulundu...</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>{1} sürümünden {2} sürümüne {0} eklentisinin güncellemesi için öğe mevcut değil; bu genellikle güncellemenin daha sonra mevcut olacağı anlamına gelir.</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>{0} eklentisinin {1} sürümünden {2} sürümüne güncellemesi için hiçbir öğe belirlenemedi. Sürüm henüz tamamlanmadıysa bu durum meydana gelebilir; bu durum devam ederse eklentiyi oluşturan kişiye bu konuda bilgi vermelisiniz.</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} eklentisi güncelleniyor...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateFinished" xml:space="preserve">
|
||||
<value>{0} eklentisinin güncellenmesi başarılı oldu, değişiklikler bir sonraki ASF açılışında yüklenecek.</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateEnabled" xml:space="preserve">
|
||||
<value>{0}/{1} eklentisi kaydedildi ve otomatik güncellemeler için etkinleştirildi.</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}) eklentisi, bu özelliği desteklemesine rağmen otomatik güncellemelerden devre dışı bırakıldı.</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>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>
|
||||
</root>
|
||||
|
||||
@@ -690,18 +690,6 @@
|
||||
<value>Файл конфігурації {0} буде оновлено до поточного синтаксису...</value>
|
||||
<comment>{0} will be replaced with the relative path to the affected config file</comment>
|
||||
</data>
|
||||
<data name="WarningWeakIPCPassword" xml:space="preserve">
|
||||
<value>Ваш IPC-пароль здається слабким. Подумайте про вибір міцнішого для підвищення безпеки. Подробиці: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakSteamPassword" xml:space="preserve">
|
||||
<value>Здається, ваш пароль Steam для '{0}' ненадійний. Подумайте про вибір міцнішого для підвищення безпеки. Подробиці: {1}</value>
|
||||
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningWeakCryptKey" xml:space="preserve">
|
||||
<value>Здається, ваш ключ шифрування слабкий. Подумайте про вибір міцнішого для підвищення безпеки. Подробиці: {0}</value>
|
||||
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
|
||||
</data>
|
||||
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||
<value>Ваш ключ шифрування закороткий. Ми рекомендуємо використовувати довжину принаймні {0} байтів (символів).</value>
|
||||
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||
@@ -729,7 +717,9 @@
|
||||
<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>Віддалений сервер відповів з іншою контрольною сумою, це може свідчити про пошкоджене завантаження або атаку MITM, відмовляємось від процедури оновлення!</value>
|
||||
</data>
|
||||
@@ -763,17 +753,54 @@
|
||||
<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>
|
||||
</data>
|
||||
<data name="PluginUpdatesChecking" xml:space="preserve">
|
||||
<value>Перевірка оновлень плагінів...</value>
|
||||
</data>
|
||||
<data name="PluginUpdateChecking" xml:space="preserve">
|
||||
<value>Перевірка оновлення для плагіна {0}...</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateNotFound" 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="PluginUpdateNewVersionAvailable" xml:space="preserve">
|
||||
<value>Доступна нова версія плагіна {0}! Рекомендуємо оновитися!</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="PluginUpdateNoAssetFound" 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="PluginUpdateConflictingAssetsFound" 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} вдалося. Зміни будуть завантажені при наступному запуску ASF.</value>
|
||||
<comment>{0} will be replaced by plugin name (string).</comment>
|
||||
</data>
|
||||
<data name="PluginUpdateEnabled" xml:space="preserve">
|
||||
<value>Плагін {0}/{1} було зареєстровано і ввімкнено для автоматичних оновлень.</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}) було вимкнено від автоматичних оновлень, хоча він підтримує цю функцію.</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 хоче нагадати вам, що з метою вашої безпеки слід увімкнути автоматичні оновлення лише від довірених джерел. Якщо ви не мали на це наміру, ви можете вимкнути оновлення плагінів у загальному конфігураційному файлі ASF.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user