mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-25 10:46:48 +00:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca83301ae3 | ||
|
|
ff9a7631ee | ||
|
|
6fa197d0d1 | ||
|
|
331297e4f8 | ||
|
|
b9f25c5e92 | ||
|
|
6d597afb99 | ||
|
|
e876b1fb3e | ||
|
|
830aea1f4e | ||
|
|
e0209d9d75 | ||
|
|
36bfbb69c6 | ||
|
|
289d3e90b7 | ||
|
|
24678372af | ||
|
|
0dc57a3532 | ||
|
|
47b729a14d | ||
|
|
7a521da68b | ||
|
|
960dbf9b71 | ||
|
|
e8097be48a | ||
|
|
00c53244c4 | ||
|
|
5e39731a27 | ||
|
|
c852f024a2 | ||
|
|
45ac5ac6f6 | ||
|
|
704fb06460 | ||
|
|
ae2f3ce1ff | ||
|
|
5360cba93a | ||
|
|
15fe5c60fc | ||
|
|
184bc32847 | ||
|
|
2f2bc140af | ||
|
|
b4e9d8ae48 | ||
|
|
e62b22beb9 | ||
|
|
ea07ee18b8 | ||
|
|
cb92ae2a6b | ||
|
|
a50d0f937a | ||
|
|
a03b4dd41b | ||
|
|
569a7af20c | ||
|
|
a22430d6e8 | ||
|
|
86c6eae25c | ||
|
|
3d60ca41d3 | ||
|
|
003fae98a9 | ||
|
|
14fde3f12b | ||
|
|
1e87341877 | ||
|
|
fbe5bd12ae | ||
|
|
862d4b006d | ||
|
|
fc802bfa1a | ||
|
|
7d7e78130f | ||
|
|
b4de9179a1 | ||
|
|
63aa94966b | ||
|
|
7e271986c7 | ||
|
|
da18dd7d20 | ||
|
|
baff629923 | ||
|
|
f7c3713345 | ||
|
|
6abe80c507 | ||
|
|
059f4132f5 | ||
|
|
c0bb8847bb | ||
|
|
41eec6d3d4 | ||
|
|
b467cd384f | ||
|
|
6878bf32da | ||
|
|
8b70223911 | ||
|
|
b87b6dd83b | ||
|
|
06c6b75481 | ||
|
|
19712fec8c | ||
|
|
8b87e37975 | ||
|
|
9c1ff4f5ba | ||
|
|
cebad272f0 | ||
|
|
382772a384 | ||
|
|
ffe7f7f7e4 | ||
|
|
f9313fee79 | ||
|
|
df73cc8f2a | ||
|
|
3944c5550a | ||
|
|
c311c78744 | ||
|
|
6e3b65fc9e | ||
|
|
8608724383 | ||
|
|
e7e8a7549a | ||
|
|
c43cce583b | ||
|
|
f79d09b3d8 | ||
|
|
4add3add1b | ||
|
|
80131b1edf | ||
|
|
a9cc294a94 | ||
|
|
b5d1b4e976 | ||
|
|
98d584ed3a | ||
|
|
7f25f2c54b | ||
|
|
57f363d078 | ||
|
|
c12d22b35b | ||
|
|
3a8fc0760a | ||
|
|
960187624f | ||
|
|
66be3e8134 | ||
|
|
0fef0652ec | ||
|
|
9fd22c43dd | ||
|
|
12b940d1df | ||
|
|
b0ef7309b8 | ||
|
|
ce18794e3c | ||
|
|
2ac5a9c5f9 | ||
|
|
573d73c7a9 | ||
|
|
45dec47bf0 |
511
.dockerignore
511
.dockerignore
@@ -1,2 +1,509 @@
|
||||
bin/
|
||||
obj/
|
||||
# _ ____ _____
|
||||
# / \ / ___| | ___|
|
||||
# / _ \ \___ \ | |_
|
||||
# / ___ \ ___) || _|
|
||||
# /_/ \_\|____/ |_|
|
||||
|
||||
# Ignore all files in custom in-tree config directory (if exists)
|
||||
ArchiSteamFarm/config
|
||||
|
||||
# Ignore local log + debug of development builds
|
||||
ArchiSteamFarm/log.txt
|
||||
ArchiSteamFarm/debug
|
||||
ArchiSteamFarm/logs
|
||||
|
||||
# Ignore standard out folders for publishing
|
||||
**/out
|
||||
|
||||
# Ignore crowdin CLI secret (if exists)
|
||||
tools/ArchiCrowdin/crowdin_identity.yml
|
||||
|
||||
# _ ____ _____ ____ _
|
||||
# / \ / ___|| ___| | _ \ ___ ___| | _____ _ __
|
||||
# / _ \ \___ \| |_ _____| | | |/ _ \ / __| |/ / _ \ '__|
|
||||
# / ___ \ ___) | _|_____| |_| | (_) | (__| < __/ |
|
||||
# /_/ \_\____/|_| |____/ \___/ \___|_|\_\___|_|
|
||||
|
||||
# Additional folders that aren't used during image building:
|
||||
|
||||
**/.git*
|
||||
**/[Bb]in/
|
||||
**/[Oo]bj/
|
||||
|
||||
ArchiSteamFarm.CustomPlugins.ExamplePlugin
|
||||
ASF-WebConfigGenerator
|
||||
ASF-ui/dist
|
||||
ASF-ui/tools
|
||||
tools
|
||||
wiki
|
||||
|
||||
# _ _
|
||||
# | | (_) _ __ _ _ __ __
|
||||
# | | | || '_ \ | | | |\ \/ /
|
||||
# | |___ | || | | || |_| | > <
|
||||
# |_____||_||_| |_| \__,_|/_/\_\
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/Global/Linux.gitignore
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# ___ ____
|
||||
# _ __ ___ __ _ ___ / _ \ / ___|
|
||||
# | '_ ` _ \ / _` | / __|| | | |\___ \
|
||||
# | | | | | || (_| || (__ | |_| | ___) |
|
||||
# |_| |_| |_| \__,_| \___| \___/ |____/
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# __ __ ____ _
|
||||
# | \/ | ___ _ __ ___ | _ \ ___ __ __ ___ | | ___ _ __
|
||||
# | |\/| | / _ \ | '_ \ / _ \ | | | | / _ \\ \ / // _ \| | / _ \ | '_ \
|
||||
# | | | || (_) || | | || (_) || |_| || __/ \ V /| __/| || (_) || |_) |
|
||||
# |_| |_| \___/ |_| |_| \___/ |____/ \___| \_/ \___||_| \___/ | .__/
|
||||
# |_|
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/Global/MonoDevelop.gitignore
|
||||
|
||||
#User Specific
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
|
||||
#Mono Project Files
|
||||
*.pidb
|
||||
*.resources
|
||||
test-results/
|
||||
|
||||
# __ __ _ _ ____ _ _ _
|
||||
# \ \ / /(_) ___ _ _ __ _ | |/ ___| | |_ _ _ __| |(_) ___
|
||||
# \ \ / / | |/ __|| | | | / _` || |\___ \ | __|| | | | / _` || | / _ \
|
||||
# \ V / | |\__ \| |_| || (_| || | ___) || |_ | |_| || (_| || || (_) |
|
||||
# \_/ |_||___/ \__,_| \__,_||_||____/ \__| \__,_| \__,_||_| \___/
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
|
||||
**/wwwroot/lib/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# __ __ _ _ ____ _ _ _ ____ _
|
||||
# \ \ / /(_) ___ _ _ __ _ | |/ ___| | |_ _ _ __| |(_) ___ / ___| ___ __| | ___
|
||||
# \ \ / / | |/ __|| | | | / _` || |\___ \ | __|| | | | / _` || | / _ \ | | / _ \ / _` | / _ \
|
||||
# \ V / | |\__ \| |_| || (_| || | ___) || |_ | |_| || (_| || || (_) || |___| (_) || (_| || __/
|
||||
# \_/ |_||___/ \__,_| \__,_||_||____/ \__| \__,_| \__,_||_| \___/ \____|\___/ \__,_| \___|
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/Global/VisualStudioCode.gitignore
|
||||
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# __ __ _ _
|
||||
# \ \ / /(_) _ __ __| | ___ __ __ ___
|
||||
# \ \ /\ / / | || '_ \ / _` | / _ \\ \ /\ / // __|
|
||||
# \ V V / | || | | || (_| || (_) |\ V V / \__ \
|
||||
# \_/\_/ |_||_| |_| \__,_| \___/ \_/\_/ |___/
|
||||
#
|
||||
# https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -5,12 +5,12 @@ on: [push, pull_request]
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SDK_VERSION: 3.1.100
|
||||
DOTNET_SDK_VERSION: 3.1.201
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
GITHUB_JOBS: 2 # 2-core CPU, without HT: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources
|
||||
NET_CORE_VERSION: netcoreapp3.1
|
||||
NET_FRAMEWORK_VERSION: net48
|
||||
NODE_JS_VERSION: 12.x
|
||||
NODE_JS_VERSION: 12
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
- name: Publish ArchiSteamFarm on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
VARIANTS: generic linux-arm linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
VARIANTS: generic linux-arm linux-arm64 linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
- name: Publish ArchiSteamFarm on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
env:
|
||||
VARIANTS: generic generic-netf linux-arm linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
VARIANTS: generic generic-netf linux-arm linux-arm64 linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -191,6 +191,12 @@ jobs:
|
||||
name: ${{ matrix.os }}_ASF-linux-arm
|
||||
path: out/linux-arm
|
||||
|
||||
- name: Upload ASF-linux-arm64
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ${{ matrix.os }}_ASF-linux-arm64
|
||||
path: out/linux-arm64
|
||||
|
||||
- name: Upload ASF-linux-x64
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ env:
|
||||
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
- NET_CORE_VERSION: netcoreapp3.1
|
||||
- VARIANTS="generic linux-arm linux-x64 osx-x64 win-x64" # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
- VARIANTS="generic linux-arm linux-arm64 linux-x64 osx-x64 win-x64" # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
before_script:
|
||||
- |
|
||||
set -eu
|
||||
@@ -76,5 +76,5 @@ matrix:
|
||||
dist: bionic
|
||||
- os: osx
|
||||
# Ref: https://docs.travis-ci.com/user/reference/osx
|
||||
dotnet: 3.1.100 # For OSX, we need absolute dotnet version until https://github.com/dotnet/core-setup/issues/4187 is resolved
|
||||
osx_image: xcode11.2
|
||||
dotnet: 3.1.201 # For OSX, we need absolute dotnet version until https://github.com/dotnet/core-setup/issues/4187 is resolved
|
||||
osx_image: xcode11.3
|
||||
|
||||
Submodule ASF-WebConfigGenerator updated: 90246f85c2...85a7da814c
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: eab83601b8...0c01122a09
@@ -38,8 +38,8 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
public void MultiGameMultiTypeBadReject() {
|
||||
HashSet<Steam.Asset> inventory = new HashSet<Steam.Asset> {
|
||||
CreateItem(1, 9),
|
||||
CreateItem(3, 9, realAppID: 730, type: Steam.Asset.EType.Emoticon),
|
||||
CreateItem(3, 9, 730, Steam.Asset.EType.Emoticon),
|
||||
CreateItem(4, realAppID: 730, type: Steam.Asset.EType.Emoticon)
|
||||
};
|
||||
|
||||
@@ -367,6 +367,6 @@ namespace ArchiSteamFarm.Tests {
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private static Steam.Asset CreateItem(ulong classID, uint amount = 1, ulong instanceID = 0, ulong assetID = 0, bool marketable = true, bool tradable = true, uint realAppID = Steam.Asset.SteamAppID, Steam.Asset.EType type = Steam.Asset.EType.TradingCard, Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Common) => new Steam.Asset(Steam.Asset.SteamAppID, Steam.Asset.SteamCommunityContextID, classID, amount, instanceID, assetID, marketable, tradable, realAppID, type, rarity);
|
||||
private static Steam.Asset CreateItem(ulong classID, uint amount = 1, uint realAppID = Steam.Asset.SteamAppID, Steam.Asset.EType type = Steam.Asset.EType.TradingCard, Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Common) => new Steam.Asset(Steam.Asset.SteamAppID, Steam.Asset.SteamCommunityContextID, classID, amount, realAppID: realAppID, type: type, rarity: rarity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,24 +326,6 @@ namespace ArchiSteamFarm {
|
||||
return (true, Strings.BotLootingSuccess);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[PublicAPI]
|
||||
public async Task<(bool Success, string Message)> SendTradeOffer(uint appID = Steam.Asset.SteamAppID, ulong contextID = Steam.Asset.SteamCommunityContextID, ulong targetSteamID = 0, string tradeToken = null, IReadOnlyCollection<uint> wantedRealAppIDs = null, IReadOnlyCollection<uint> unwantedRealAppIDs = null, IReadOnlyCollection<Steam.Asset.EType> wantedTypes = null) {
|
||||
if ((appID == 0) || (contextID == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(contextID));
|
||||
|
||||
return (false, string.Format(Strings.ErrorObjectIsNull, nameof(appID) + " || " + nameof(contextID)));
|
||||
}
|
||||
|
||||
if ((wantedRealAppIDs?.Count == 0) || (unwantedRealAppIDs?.Count == 0) || (wantedTypes?.Count == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(wantedRealAppIDs) + " || " + nameof(unwantedRealAppIDs) + " || " + nameof(wantedTypes));
|
||||
|
||||
return (false, string.Format(Strings.ErrorObjectIsNull, nameof(wantedRealAppIDs) + " || " + nameof(unwantedRealAppIDs) + " || " + nameof(wantedTypes)));
|
||||
}
|
||||
|
||||
return await SendInventory(appID, contextID, targetSteamID, tradeToken, item => (wantedRealAppIDs?.Contains(item.RealAppID) != false) && (unwantedRealAppIDs?.Contains(item.RealAppID) != true) && (wantedTypes?.Contains(item.Type) != false)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public (bool Success, string Message) Start() {
|
||||
if (Bot.KeepRunning) {
|
||||
|
||||
@@ -70,32 +70,44 @@ namespace ArchiSteamFarm {
|
||||
LastPacketReceived = DateTime.UtcNow;
|
||||
|
||||
switch (packetMsg.MsgType) {
|
||||
case EMsg.ClientCommentNotifications:
|
||||
ClientMsgProtobuf<CMsgClientCommentNotifications> commentNotifications = new ClientMsgProtobuf<CMsgClientCommentNotifications>(packetMsg);
|
||||
Client.PostCallback(new UserNotificationsCallback(packetMsg.TargetJobID, commentNotifications.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientItemAnnouncements:
|
||||
HandleItemAnnouncements(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientItemAnnouncements> itemAnnouncements = new ClientMsgProtobuf<CMsgClientItemAnnouncements>(packetMsg);
|
||||
Client.PostCallback(new UserNotificationsCallback(packetMsg.TargetJobID, itemAnnouncements.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientPlayingSessionState:
|
||||
HandlePlayingSessionState(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientPlayingSessionState> playingSessionState = new ClientMsgProtobuf<CMsgClientPlayingSessionState>(packetMsg);
|
||||
Client.PostCallback(new PlayingSessionStateCallback(packetMsg.TargetJobID, playingSessionState.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientPurchaseResponse:
|
||||
HandlePurchaseResponse(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientPurchaseResponse> purchaseResponse = new ClientMsgProtobuf<CMsgClientPurchaseResponse>(packetMsg);
|
||||
Client.PostCallback(new PurchaseResponseCallback(packetMsg.TargetJobID, purchaseResponse.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientRedeemGuestPassResponse:
|
||||
HandleRedeemGuestPassResponse(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientRedeemGuestPassResponse> redeemGuestPassResponse = new ClientMsgProtobuf<CMsgClientRedeemGuestPassResponse>(packetMsg);
|
||||
Client.PostCallback(new RedeemGuestPassResponseCallback(packetMsg.TargetJobID, redeemGuestPassResponse.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientSharedLibraryLockStatus:
|
||||
HandleSharedLibraryLockStatus(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientSharedLibraryLockStatus> sharedLibraryLockStatus = new ClientMsgProtobuf<CMsgClientSharedLibraryLockStatus>(packetMsg);
|
||||
Client.PostCallback(new SharedLibraryLockStatusCallback(packetMsg.TargetJobID, sharedLibraryLockStatus.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientUserNotifications:
|
||||
HandleUserNotifications(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientUserNotifications> userNotifications = new ClientMsgProtobuf<CMsgClientUserNotifications>(packetMsg);
|
||||
Client.PostCallback(new UserNotificationsCallback(packetMsg.TargetJobID, userNotifications.Body));
|
||||
|
||||
break;
|
||||
case EMsg.ClientVanityURLChangedNotification:
|
||||
HandleVanityURLChangedNotification(packetMsg);
|
||||
ClientMsgProtobuf<CMsgClientVanityURLChangedNotification> vanityURLChangedNotification = new ClientMsgProtobuf<CMsgClientVanityURLChangedNotification>(packetMsg);
|
||||
Client.PostCallback(new VanityURLChangedCallback(packetMsg.TargetJobID, vanityURLChangedNotification.Body));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -629,83 +641,6 @@ namespace ArchiSteamFarm {
|
||||
Client.Send(request);
|
||||
}
|
||||
|
||||
private void HandleItemAnnouncements(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientItemAnnouncements> response = new ClientMsgProtobuf<CMsgClientItemAnnouncements>(packetMsg);
|
||||
Client.PostCallback(new UserNotificationsCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandlePlayingSessionState(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientPlayingSessionState> response = new ClientMsgProtobuf<CMsgClientPlayingSessionState>(packetMsg);
|
||||
Client.PostCallback(new PlayingSessionStateCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandlePurchaseResponse(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientPurchaseResponse> response = new ClientMsgProtobuf<CMsgClientPurchaseResponse>(packetMsg);
|
||||
Client.PostCallback(new PurchaseResponseCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandleRedeemGuestPassResponse(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientRedeemGuestPassResponse> response = new ClientMsgProtobuf<CMsgClientRedeemGuestPassResponse>(packetMsg);
|
||||
Client.PostCallback(new RedeemGuestPassResponseCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandleSharedLibraryLockStatus(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientSharedLibraryLockStatus> response = new ClientMsgProtobuf<CMsgClientSharedLibraryLockStatus>(packetMsg);
|
||||
Client.PostCallback(new SharedLibraryLockStatusCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandleUserNotifications(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientUserNotifications> response = new ClientMsgProtobuf<CMsgClientUserNotifications>(packetMsg);
|
||||
Client.PostCallback(new UserNotificationsCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
private void HandleVanityURLChangedNotification(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
ArchiLogger.LogNullError(nameof(packetMsg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ClientMsgProtobuf<CMsgClientVanityURLChangedNotification> response = new ClientMsgProtobuf<CMsgClientVanityURLChangedNotification>(packetMsg);
|
||||
Client.PostCallback(new VanityURLChangedCallback(packetMsg.TargetJobID, response.Body));
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
public sealed class PurchaseResponseCallback : CallbackMsg {
|
||||
public readonly Dictionary<uint, string> Items;
|
||||
@@ -837,6 +772,15 @@ namespace ArchiSteamFarm {
|
||||
Notifications = new Dictionary<EUserNotification, uint>(1) { { EUserNotification.Items, msg.count_new_items } };
|
||||
}
|
||||
|
||||
internal UserNotificationsCallback([JetBrains.Annotations.NotNull] JobID jobID, [JetBrains.Annotations.NotNull] CMsgClientCommentNotifications msg) {
|
||||
if ((jobID == null) || (msg == null)) {
|
||||
throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg));
|
||||
}
|
||||
|
||||
JobID = jobID;
|
||||
Notifications = new Dictionary<EUserNotification, uint>(1) { { EUserNotification.Comments, msg.count_new_comments + msg.count_new_comments_owner + msg.count_new_comments_subscriptions } };
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public enum EUserNotification : byte {
|
||||
Unknown,
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>ASF.ico</ApplicationIcon>
|
||||
<AssemblyVersion>4.1.2.2</AssemblyVersion>
|
||||
<AssemblyVersion>4.2.0.3</AssemblyVersion>
|
||||
<Authors>JustArchi</Authors>
|
||||
<Company>JustArchi</Company>
|
||||
<Copyright>Copyright © ArchiSteamFarm 2015-2020</Copyright>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);config/**;debug/**;out/**;overlay/**</DefaultItemExcludes>
|
||||
<Description>ASF is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously.</Description>
|
||||
<ErrorReport>none</ErrorReport>
|
||||
<FileVersion>4.1.2.2</FileVersion>
|
||||
<FileVersion>4.2.0.3</FileVersion>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<NoWarn>1591</NoWarn>
|
||||
@@ -20,7 +20,7 @@
|
||||
<PackageProjectUrl>https://github.com/JustArchiNET/ArchiSteamFarm</PackageProjectUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/JustArchiNET/ArchiSteamFarm.git</RepositoryUrl>
|
||||
<RuntimeIdentifiers>linux-arm;linux-x64;osx-x64;win-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64;osx-x64;win-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -51,32 +51,28 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp.XPath" Version="1.1.7" />
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="4.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CryptSharpStandard" Version="1.0.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.21" />
|
||||
<PackageReference Include="Humanizer" Version="2.7.9" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="Markdig.Signed" Version="0.18.1" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
<PackageReference Include="Markdig.Signed" Version="0.18.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.0.0" />
|
||||
<PackageReference Include="NLog" Version="4.6.8" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
|
||||
<PackageReference Include="protobuf-net" Version="3.0.0-alpha.43" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.0.0" />
|
||||
<PackageReference Include="NLog" Version="4.7.0" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.1" />
|
||||
<PackageReference Include="SteamKit2" Version="2.3.0-Beta.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.3.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.3.1" />
|
||||
<PackageReference Include="System.Composition" Version="1.4.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.0.0" />
|
||||
<Reference Include="SteamKit2">
|
||||
<HintPath>lib\SteamKit2.dll</HintPath>
|
||||
</Reference>
|
||||
<PackageReference Include="System.Linq.Async" Version="4.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -88,8 +84,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.3" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
|
||||
<Reference Include="System.Net.Http">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Net.Http.dll</HintPath>
|
||||
|
||||
@@ -30,10 +30,10 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -121,35 +121,6 @@ namespace ArchiSteamFarm {
|
||||
return string.IsNullOrEmpty(VanityURL) ? "/profiles/" + Bot.SteamID : "/id/" + VanityURL;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
[Obsolete]
|
||||
[PublicAPI]
|
||||
public async Task<HashSet<Steam.Asset>> GetInventory(ulong steamID = 0, uint appID = Steam.Asset.SteamAppID, ulong contextID = Steam.Asset.SteamCommunityContextID, bool? marketable = null, bool? tradable = null, IReadOnlyCollection<uint> wantedRealAppIDs = null, IReadOnlyCollection<uint> unwantedRealAppIDs = null, IReadOnlyCollection<Steam.Asset.EType> wantedTypes = null, IReadOnlyCollection<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = null) {
|
||||
if ((appID == 0) || (contextID == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(contextID));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return await GetInventoryAsync(steamID, appID, contextID).Where(
|
||||
item =>
|
||||
(!marketable.HasValue || (item.Marketable == marketable.Value)) &&
|
||||
(!tradable.HasValue || (item.Tradable == tradable.Value)) &&
|
||||
(wantedRealAppIDs?.Contains(item.RealAppID) != false) &&
|
||||
(unwantedRealAppIDs?.Contains(item.RealAppID) != true) &&
|
||||
(wantedTypes?.Contains(item.Type) != false) &&
|
||||
(wantedSets?.Contains((item.RealAppID, item.Type, item.Rarity)) != false)
|
||||
).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[JetBrains.Annotations.NotNull]
|
||||
[PublicAPI]
|
||||
[SuppressMessage("ReSharper", "FunctionComplexityOverflow")]
|
||||
@@ -226,10 +197,14 @@ namespace ArchiSteamFarm {
|
||||
|
||||
asset.Marketable = description.Marketable;
|
||||
asset.Tradable = description.Tradable;
|
||||
asset.Tags = description.Tags;
|
||||
asset.RealAppID = description.RealAppID;
|
||||
asset.Type = description.Type;
|
||||
asset.Rarity = description.Rarity;
|
||||
asset.AdditionalProperties = description.AdditionalProperties;
|
||||
|
||||
if (description.AdditionalProperties != null) {
|
||||
asset.AdditionalProperties = description.AdditionalProperties.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
assetIDs.Add(asset.AssetID);
|
||||
|
||||
@@ -450,7 +425,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public async Task<HtmlDocument> UrlGetToHtmlDocumentWithSession(string host, string request, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) {
|
||||
public async Task<IDocument> UrlGetToHtmlDocumentWithSession(string host, string request, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) {
|
||||
if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(host) + " || " + nameof(request));
|
||||
|
||||
@@ -750,7 +725,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public async Task<HtmlDocument> UrlPostToHtmlDocumentWithSession(string host, string request, Dictionary<string, string> data = null, string referer = null, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) {
|
||||
public async Task<IDocument> UrlPostToHtmlDocumentWithSession(string host, string request, Dictionary<string, string> data = null, string referer = null, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) {
|
||||
if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request) || !Enum.IsDefined(typeof(ESession), session)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(host) + " || " + nameof(request) + " || " + nameof(session));
|
||||
|
||||
@@ -1300,9 +1275,9 @@ namespace ArchiSteamFarm {
|
||||
{ "subid", subID.ToString() }
|
||||
};
|
||||
|
||||
HtmlDocument htmlDocument = await UrlPostToHtmlDocumentWithSession(SteamStoreURL, request, data).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await UrlPostToHtmlDocumentWithSession(SteamStoreURL, request, data).ConfigureAwait(false);
|
||||
|
||||
return htmlDocument?.DocumentNode.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
|
||||
return htmlDocument?.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
|
||||
}
|
||||
|
||||
internal async Task<bool> ChangePrivacySettings(Steam.UserPrivacy userPrivacy) {
|
||||
@@ -1502,7 +1477,7 @@ namespace ArchiSteamFarm {
|
||||
List<KeyValue> tags = description["tags"].Children;
|
||||
|
||||
if (tags.Count > 0) {
|
||||
HashSet<Steam.InventoryResponse.Description.Tag> parsedTags = new HashSet<Steam.InventoryResponse.Description.Tag>();
|
||||
HashSet<Steam.Asset.Tag> parsedTags = new HashSet<Steam.Asset.Tag>(tags.Count);
|
||||
|
||||
foreach (KeyValue tag in tags) {
|
||||
string identifier = tag["category"].AsString();
|
||||
@@ -1521,7 +1496,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
parsedTags.Add(new Steam.InventoryResponse.Description.Tag(identifier, value));
|
||||
parsedTags.Add(new Steam.Asset.Tag(identifier, value));
|
||||
}
|
||||
|
||||
parsedDescription.Tags = parsedTags.ToImmutableHashSet();
|
||||
@@ -1641,7 +1616,7 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal async Task<HtmlDocument> GetBadgePage(byte page) {
|
||||
internal async Task<IDocument> GetBadgePage(byte page) {
|
||||
if (page == 0) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(page));
|
||||
|
||||
@@ -1686,7 +1661,7 @@ namespace ArchiSteamFarm {
|
||||
return response;
|
||||
}
|
||||
|
||||
internal async Task<HtmlDocument> GetConfirmations(string deviceID, string confirmationHash, uint time) {
|
||||
internal async Task<IDocument> GetConfirmations(string deviceID, string confirmationHash, uint time) {
|
||||
if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time));
|
||||
|
||||
@@ -1713,17 +1688,21 @@ namespace ArchiSteamFarm {
|
||||
[ItemCanBeNull]
|
||||
internal async Task<HashSet<ulong>> GetDigitalGiftCards() {
|
||||
const string request = "/gifts";
|
||||
HtmlDocument response = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false);
|
||||
IDocument response = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false);
|
||||
|
||||
HtmlNodeCollection htmlNodes = response?.DocumentNode.SelectNodes("//div[@class='pending_gift']/div[starts-with(@id, 'pending_gift_')][count(div[@class='pending_giftcard_leftcol']) > 0]/@id");
|
||||
|
||||
if (htmlNodes == null) {
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<ulong> results = new HashSet<ulong>();
|
||||
List<IElement> htmlNodes = response.SelectNodes("//div[@class='pending_gift']/div[starts-with(@id, 'pending_gift_')][count(div[@class='pending_giftcard_leftcol']) > 0]/@id");
|
||||
|
||||
foreach (string giftCardIDText in htmlNodes.Select(node => node.GetAttributeValue("id", null))) {
|
||||
if (htmlNodes.Count == 0) {
|
||||
return new HashSet<ulong>(0);
|
||||
}
|
||||
|
||||
HashSet<ulong> results = new HashSet<ulong>(htmlNodes.Count);
|
||||
|
||||
foreach (string giftCardIDText in htmlNodes.Select(node => node.GetAttributeValue("id"))) {
|
||||
if (string.IsNullOrEmpty(giftCardIDText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(giftCardIDText));
|
||||
|
||||
@@ -1748,7 +1727,7 @@ namespace ArchiSteamFarm {
|
||||
return results;
|
||||
}
|
||||
|
||||
internal async Task<HtmlDocument> GetDiscoveryQueuePage() {
|
||||
internal async Task<IDocument> GetDiscoveryQueuePage() {
|
||||
const string request = "/explore?l=english";
|
||||
|
||||
return await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false);
|
||||
@@ -1757,22 +1736,22 @@ namespace ArchiSteamFarm {
|
||||
[ItemCanBeNull]
|
||||
internal async Task<HashSet<ulong>> GetFamilySharingSteamIDs() {
|
||||
const string request = "/account/managedevices?l=english";
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false);
|
||||
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("(//table[@class='accountTable'])[2]//a/@data-miniprofile");
|
||||
List<IElement> htmlNodes = htmlDocument.SelectNodes("(//table[@class='accountTable'])[2]//a/@data-miniprofile");
|
||||
|
||||
HashSet<ulong> result = new HashSet<ulong>();
|
||||
|
||||
if (htmlNodes == null) {
|
||||
if (htmlNodes.Count == 0) {
|
||||
// OK, no authorized steamIDs
|
||||
return result;
|
||||
return new HashSet<ulong>(0);
|
||||
}
|
||||
|
||||
foreach (string miniProfile in htmlNodes.Select(htmlNode => htmlNode.GetAttributeValue("data-miniprofile", null))) {
|
||||
HashSet<ulong> result = new HashSet<ulong>(htmlNodes.Count);
|
||||
|
||||
foreach (string miniProfile in htmlNodes.Select(htmlNode => htmlNode.GetAttributeValue("data-miniprofile"))) {
|
||||
if (string.IsNullOrEmpty(miniProfile)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(miniProfile));
|
||||
|
||||
@@ -1792,7 +1771,7 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal async Task<HtmlDocument> GetGameCardsPage(ulong appID) {
|
||||
internal async Task<IDocument> GetGameCardsPage(ulong appID) {
|
||||
if (appID == 0) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(appID));
|
||||
|
||||
@@ -1852,16 +1831,16 @@ namespace ArchiSteamFarm {
|
||||
|
||||
string request = "/tradeoffer/" + tradeID + "?l=english";
|
||||
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request).ConfigureAwait(false);
|
||||
|
||||
HtmlNode htmlNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@class='pagecontent']/script");
|
||||
IElement htmlNode = htmlDocument?.SelectSingleNode("//div[@class='pagecontent']/script");
|
||||
|
||||
if (htmlNode == null) {
|
||||
// Trade can be no longer valid
|
||||
return null;
|
||||
}
|
||||
|
||||
string text = htmlNode.InnerText;
|
||||
string text = htmlNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(text)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(text));
|
||||
@@ -1869,7 +1848,8 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = text.IndexOf("g_daysTheirEscrow = ", StringComparison.Ordinal);
|
||||
const string daysTheirVariableName = "g_daysTheirEscrow = ";
|
||||
int index = text.IndexOf(daysTheirVariableName, StringComparison.Ordinal);
|
||||
|
||||
if (index < 0) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(index));
|
||||
@@ -1877,7 +1857,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
index += 20;
|
||||
index += daysTheirVariableName.Length;
|
||||
text = text.Substring(index);
|
||||
|
||||
index = text.IndexOf(';');
|
||||
@@ -2302,15 +2282,15 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private async Task<(ESteamApiKeyState State, string Key)> GetApiKeyState() {
|
||||
const string request = "/dev/apikey?l=english";
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request).ConfigureAwait(false);
|
||||
|
||||
HtmlNode titleNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='mainContents']/h2");
|
||||
IElement titleNode = htmlDocument?.SelectSingleNode("//div[@id='mainContents']/h2");
|
||||
|
||||
if (titleNode == null) {
|
||||
return (ESteamApiKeyState.Timeout, null);
|
||||
}
|
||||
|
||||
string title = titleNode.InnerText;
|
||||
string title = titleNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(title)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(title));
|
||||
@@ -2322,7 +2302,7 @@ namespace ArchiSteamFarm {
|
||||
return (ESteamApiKeyState.AccessDenied, null);
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@id='bodyContents_ex']/p");
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("//div[@id='bodyContents_ex']/p");
|
||||
|
||||
if (htmlNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||
@@ -2330,7 +2310,7 @@ namespace ArchiSteamFarm {
|
||||
return (ESteamApiKeyState.Error, null);
|
||||
}
|
||||
|
||||
string text = htmlNode.InnerText;
|
||||
string text = htmlNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(text)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(text));
|
||||
@@ -2489,6 +2469,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
bool marketable = true;
|
||||
bool tradable = true;
|
||||
ImmutableHashSet<Steam.Asset.Tag> tags = null;
|
||||
uint realAppID = 0;
|
||||
Steam.Asset.EType type = Steam.Asset.EType.Unknown;
|
||||
Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Unknown;
|
||||
@@ -2496,12 +2477,13 @@ namespace ArchiSteamFarm {
|
||||
if (descriptions.TryGetValue(key, out Steam.InventoryResponse.Description description)) {
|
||||
marketable = description.Marketable;
|
||||
tradable = description.Tradable;
|
||||
tags = description.Tags;
|
||||
realAppID = description.RealAppID;
|
||||
type = description.Type;
|
||||
rarity = description.Rarity;
|
||||
}
|
||||
|
||||
Steam.Asset steamAsset = new Steam.Asset(appID, contextID, classID, amount, instanceID, assetID, marketable, tradable, realAppID, type, rarity);
|
||||
Steam.Asset steamAsset = new Steam.Asset(appID, contextID, classID, amount, instanceID, assetID, marketable, tradable, tags, realAppID, type, rarity);
|
||||
output.Add(steamAsset);
|
||||
}
|
||||
|
||||
@@ -2608,13 +2590,13 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private async Task<(bool Success, bool Result)> ResolvePublicInventory() {
|
||||
const string request = "/my/edit/settings?l=english";
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request, false).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request, false).ConfigureAwait(false);
|
||||
|
||||
if (htmlDocument == null) {
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@data-component='ProfilePrivacySettings']/@data-privacysettings");
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("//div[@data-component='ProfilePrivacySettings']/@data-privacysettings");
|
||||
|
||||
if (htmlNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||
@@ -2622,7 +2604,7 @@ namespace ArchiSteamFarm {
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
string json = htmlNode.GetAttributeValue("data-privacysettings", null);
|
||||
string json = htmlNode.GetAttributeValue("data-privacysettings");
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(json));
|
||||
|
||||
@@ -816,7 +816,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
value.AppIDs = new HashSet<uint>();
|
||||
value.AppIDs = new HashSet<uint>(appIDs.Children.Count);
|
||||
|
||||
foreach (string appIDText in appIDs.Children.Select(app => app.Value)) {
|
||||
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
|
||||
|
||||
@@ -151,7 +151,11 @@ namespace ArchiSteamFarm {
|
||||
public ulong SteamMasterClanID { get; private set; } = DefaultSteamMasterClanID;
|
||||
|
||||
[JsonExtensionData]
|
||||
internal Dictionary<string, JToken> AdditionalProperties { get; set; }
|
||||
internal Dictionary<string, JToken> AdditionalProperties {
|
||||
get;
|
||||
[UsedImplicitly]
|
||||
set;
|
||||
}
|
||||
|
||||
internal string DecryptedSteamPassword {
|
||||
get {
|
||||
|
||||
@@ -30,10 +30,10 @@ using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Collections;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
@@ -372,32 +372,32 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "FunctionComplexityOverflow")]
|
||||
private async Task CheckPage(HtmlDocument htmlDocument, ISet<uint> parsedAppIDs) {
|
||||
private async Task CheckPage(IDocument htmlDocument, ISet<uint> parsedAppIDs) {
|
||||
if ((htmlDocument == null) || (parsedAppIDs == null)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(htmlDocument) + " || " + nameof(parsedAppIDs));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='badge_row_inner']");
|
||||
List<IElement> htmlNodes = htmlDocument.SelectNodes("//div[@class='badge_row_inner']");
|
||||
|
||||
if (htmlNodes == null) {
|
||||
if (htmlNodes.Count == 0) {
|
||||
// No eligible badges whatsoever
|
||||
return;
|
||||
}
|
||||
|
||||
List<Task> backgroundTasks = null;
|
||||
HashSet<Task> backgroundTasks = null;
|
||||
|
||||
foreach (HtmlNode htmlNode in htmlNodes) {
|
||||
HtmlNode statsNode = htmlNode.SelectSingleNode(".//div[@class='badge_title_stats_content']");
|
||||
HtmlNode appIDNode = statsNode?.SelectSingleNode(".//div[@class='card_drop_info_dialog']");
|
||||
foreach (IElement htmlNode in htmlNodes) {
|
||||
IElement statsNode = htmlNode.SelectSingleElementNode(".//div[@class='badge_title_stats_content']");
|
||||
IElement appIDNode = statsNode?.SelectSingleElementNode(".//div[@class='card_drop_info_dialog']");
|
||||
|
||||
if (appIDNode == null) {
|
||||
// It's just a badge, nothing more
|
||||
continue;
|
||||
}
|
||||
|
||||
string appIDText = appIDNode.GetAttributeValue("id", null);
|
||||
string appIDText = appIDNode.GetAttributeValue("id");
|
||||
|
||||
if (string.IsNullOrEmpty(appIDText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(appIDText));
|
||||
@@ -454,7 +454,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Cards
|
||||
HtmlNode progressNode = statsNode.SelectSingleNode(".//span[@class='progress_info_bold']");
|
||||
IElement progressNode = statsNode.SelectSingleElementNode(".//span[@class='progress_info_bold']");
|
||||
|
||||
if (progressNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(progressNode));
|
||||
@@ -462,7 +462,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
string progressText = progressNode.InnerText;
|
||||
string progressText = progressNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(progressText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(progressText));
|
||||
@@ -493,7 +493,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// To save us on extra work, check cards earned so far first
|
||||
HtmlNode cardsEarnedNode = statsNode.SelectSingleNode(".//div[@class='card_drop_info_header']");
|
||||
IElement cardsEarnedNode = statsNode.SelectSingleElementNode(".//div[@class='card_drop_info_header']");
|
||||
|
||||
if (cardsEarnedNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedNode));
|
||||
@@ -501,7 +501,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
string cardsEarnedText = cardsEarnedNode.InnerText;
|
||||
string cardsEarnedText = cardsEarnedNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(cardsEarnedText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedText));
|
||||
@@ -538,7 +538,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Hours
|
||||
HtmlNode timeNode = statsNode.SelectSingleNode(".//div[@class='badge_title_stats_playtime']");
|
||||
IElement timeNode = statsNode.SelectSingleElementNode(".//div[@class='badge_title_stats_playtime']");
|
||||
|
||||
if (timeNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(timeNode));
|
||||
@@ -546,7 +546,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
string hoursText = timeNode.InnerText;
|
||||
string hoursText = timeNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(hoursText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(hoursText));
|
||||
@@ -567,7 +567,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Names
|
||||
HtmlNode nameNode = statsNode.SelectSingleNode("(.//div[@class='card_drop_info_body'])[last()]");
|
||||
IElement nameNode = statsNode.SelectSingleElementNode("(.//div[@class='card_drop_info_body'])[last()]");
|
||||
|
||||
if (nameNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(nameNode));
|
||||
@@ -575,7 +575,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = nameNode.InnerText;
|
||||
string name = nameNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(name)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(name));
|
||||
@@ -619,11 +619,11 @@ namespace ArchiSteamFarm {
|
||||
// Levels
|
||||
byte badgeLevel = 0;
|
||||
|
||||
HtmlNode levelNode = htmlNode.SelectSingleNode(".//div[@class='badge_info_description']/div[2]");
|
||||
IElement levelNode = htmlNode.SelectSingleElementNode(".//div[@class='badge_info_description']/div[2]");
|
||||
|
||||
if (levelNode != null) {
|
||||
// There is no levelNode if we didn't craft that badge yet (level 0)
|
||||
string levelText = levelNode.InnerText;
|
||||
string levelText = levelNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(levelText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(levelText));
|
||||
@@ -671,7 +671,7 @@ namespace ArchiSteamFarm {
|
||||
break;
|
||||
default:
|
||||
if (backgroundTasks == null) {
|
||||
backgroundTasks = new List<Task>();
|
||||
backgroundTasks = new HashSet<Task>();
|
||||
}
|
||||
|
||||
backgroundTasks.Add(task);
|
||||
@@ -694,7 +694,7 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(page).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(page).ConfigureAwait(false);
|
||||
|
||||
if (htmlDocument == null) {
|
||||
return;
|
||||
@@ -942,15 +942,15 @@ namespace ArchiSteamFarm {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||
|
||||
HtmlNode progressNode = htmlDocument?.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
|
||||
IElement progressNode = htmlDocument?.SelectSingleNode("//span[@class='progress_info_bold']");
|
||||
|
||||
if (progressNode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string progress = progressNode.InnerText;
|
||||
string progress = progressNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(progress)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(progress));
|
||||
@@ -976,7 +976,7 @@ namespace ArchiSteamFarm {
|
||||
private async Task<bool?> IsAnythingToFarm() {
|
||||
// Find the number of badge pages
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.CheckingFirstBadgePage);
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(1).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(1).ConfigureAwait(false);
|
||||
|
||||
if (htmlDocument == null) {
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.WarningCouldNotCheckBadges);
|
||||
@@ -986,10 +986,10 @@ namespace ArchiSteamFarm {
|
||||
|
||||
byte maxPages = 1;
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("(//a[@class='pagelink'])[last()]");
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("(//a[@class='pagelink'])[last()]");
|
||||
|
||||
if (htmlNode != null) {
|
||||
string lastPage = htmlNode.InnerText;
|
||||
string lastPage = htmlNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(lastPage)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(lastPage));
|
||||
@@ -1024,7 +1024,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
break;
|
||||
default:
|
||||
List<Task> tasks = new List<Task>(maxPages) { mainTask };
|
||||
HashSet<Task> tasks = new HashSet<Task>(maxPages) { mainTask };
|
||||
|
||||
if (maxPages > 1) {
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.CheckingOtherBadgePages);
|
||||
|
||||
@@ -197,7 +197,11 @@ namespace ArchiSteamFarm {
|
||||
public ProtocolTypes SteamProtocols { get; private set; } = DefaultSteamProtocols;
|
||||
|
||||
[JsonExtensionData]
|
||||
internal Dictionary<string, JToken> AdditionalProperties { get; set; }
|
||||
internal Dictionary<string, JToken> AdditionalProperties {
|
||||
get;
|
||||
[UsedImplicitly]
|
||||
set;
|
||||
}
|
||||
|
||||
internal bool IsWebProxyPasswordSet { get; private set; }
|
||||
internal bool ShouldSerializeEverything { private get; set; } = true;
|
||||
|
||||
@@ -24,8 +24,8 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -71,6 +71,9 @@ namespace ArchiSteamFarm.Json {
|
||||
[PublicAPI]
|
||||
public uint RealAppID { get; internal set; }
|
||||
|
||||
[PublicAPI]
|
||||
public ImmutableHashSet<Tag> Tags { get; internal set; }
|
||||
|
||||
[PublicAPI]
|
||||
public bool Tradable { get; internal set; }
|
||||
|
||||
@@ -198,7 +201,7 @@ namespace ArchiSteamFarm.Json {
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
// Constructed from trades being received or plugins
|
||||
public Asset(uint appID, ulong contextID, ulong classID, uint amount, ulong instanceID = 0, ulong assetID = 0, bool marketable = true, bool tradable = true, uint realAppID = 0, EType type = EType.Unknown, ERarity rarity = ERarity.Unknown) {
|
||||
public Asset(uint appID, ulong contextID, ulong classID, uint amount, ulong instanceID = 0, ulong assetID = 0, bool marketable = true, bool tradable = true, ImmutableHashSet<Tag> tags = null, uint realAppID = 0, EType type = EType.Unknown, ERarity rarity = ERarity.Unknown) {
|
||||
if ((appID == 0) || (contextID == 0) || (classID == 0) || (amount == 0)) {
|
||||
throw new ArgumentNullException(nameof(appID) + " || " + nameof(contextID) + " || " + nameof(classID) + " || " + nameof(amount));
|
||||
}
|
||||
@@ -214,6 +217,10 @@ namespace ArchiSteamFarm.Json {
|
||||
RealAppID = realAppID;
|
||||
Type = type;
|
||||
Rarity = rarity;
|
||||
|
||||
if ((tags != null) && (tags.Count > 0)) {
|
||||
Tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
@@ -222,6 +229,28 @@ namespace ArchiSteamFarm.Json {
|
||||
[JetBrains.Annotations.NotNull]
|
||||
internal Asset CreateShallowCopy() => (Asset) MemberwiseClone();
|
||||
|
||||
public sealed class Tag {
|
||||
[JsonProperty(PropertyName = "category", Required = Required.Always)]
|
||||
[PublicAPI]
|
||||
public readonly string Identifier;
|
||||
|
||||
[JsonProperty(PropertyName = "internal_name", Required = Required.Always)]
|
||||
[PublicAPI]
|
||||
public readonly string Value;
|
||||
|
||||
internal Tag([JetBrains.Annotations.NotNull] string identifier, [JetBrains.Annotations.NotNull] string value) {
|
||||
if (string.IsNullOrEmpty(identifier) || string.IsNullOrEmpty(value)) {
|
||||
throw new ArgumentNullException(nameof(identifier) + " || " + nameof(value));
|
||||
}
|
||||
|
||||
Identifier = identifier;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private Tag() { }
|
||||
}
|
||||
|
||||
public enum ERarity : byte {
|
||||
Unknown,
|
||||
Common,
|
||||
@@ -271,7 +300,7 @@ namespace ArchiSteamFarm.Json {
|
||||
return;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = WebBrowser.StringToHtmlDocument(value);
|
||||
IDocument htmlDocument = WebBrowser.StringToHtmlDocument(value).Result;
|
||||
|
||||
if (htmlDocument == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(htmlDocument));
|
||||
@@ -279,10 +308,10 @@ namespace ArchiSteamFarm.Json {
|
||||
return;
|
||||
}
|
||||
|
||||
if (htmlDocument.DocumentNode.SelectSingleNode("//div[@class='mobileconf_trade_area']") != null) {
|
||||
if (htmlDocument.SelectSingleNode("//div[@class='mobileconf_trade_area']") != null) {
|
||||
Type = EType.Trade;
|
||||
|
||||
HtmlNode tradeOfferNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='tradeoffer']");
|
||||
IElement tradeOfferNode = htmlDocument.SelectSingleNode("//div[@class='tradeoffer']");
|
||||
|
||||
if (tradeOfferNode == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(tradeOfferNode));
|
||||
@@ -290,7 +319,7 @@ namespace ArchiSteamFarm.Json {
|
||||
return;
|
||||
}
|
||||
|
||||
string idText = tradeOfferNode.GetAttributeValue("id", null);
|
||||
string idText = tradeOfferNode.GetAttributeValue("id");
|
||||
|
||||
if (string.IsNullOrEmpty(idText)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(idText));
|
||||
@@ -323,7 +352,7 @@ namespace ArchiSteamFarm.Json {
|
||||
}
|
||||
|
||||
TradeOfferID = tradeOfferID;
|
||||
} else if (htmlDocument.DocumentNode.SelectSingleNode("//div[@class='mobileconf_listing_prices']") != null) {
|
||||
} else if (htmlDocument.SelectSingleNode("//div[@class='mobileconf_listing_prices']") != null) {
|
||||
Type = EType.Market;
|
||||
} else {
|
||||
// Normally this should be reported, but under some specific circumstances we might actually receive this one
|
||||
@@ -482,14 +511,13 @@ namespace ArchiSteamFarm.Json {
|
||||
private InventoryResponse() { }
|
||||
|
||||
internal sealed class Description {
|
||||
#pragma warning disable 649
|
||||
[JsonExtensionData]
|
||||
internal readonly ImmutableDictionary<string, JToken> AdditionalProperties;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal Asset.ERarity Rarity {
|
||||
get {
|
||||
foreach (Tag tag in Tags) {
|
||||
if (Tags == null) {
|
||||
return Asset.ERarity.Unknown;
|
||||
}
|
||||
|
||||
foreach (Asset.Tag tag in Tags) {
|
||||
switch (tag.Identifier) {
|
||||
case "droprate":
|
||||
switch (tag.Value) {
|
||||
@@ -515,7 +543,11 @@ namespace ArchiSteamFarm.Json {
|
||||
|
||||
internal uint RealAppID {
|
||||
get {
|
||||
foreach (Tag tag in Tags) {
|
||||
if (Tags == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach (Asset.Tag tag in Tags) {
|
||||
switch (tag.Identifier) {
|
||||
case "Game":
|
||||
if ((tag.Value.Length <= 4) || !tag.Value.StartsWith("app_", StringComparison.Ordinal)) {
|
||||
@@ -542,9 +574,13 @@ namespace ArchiSteamFarm.Json {
|
||||
|
||||
internal Asset.EType Type {
|
||||
get {
|
||||
if (Tags == null) {
|
||||
return Asset.EType.Unknown;
|
||||
}
|
||||
|
||||
Asset.EType type = Asset.EType.Unknown;
|
||||
|
||||
foreach (Tag tag in Tags) {
|
||||
foreach (Asset.Tag tag in Tags) {
|
||||
switch (tag.Identifier) {
|
||||
case "cardborder":
|
||||
switch (tag.Value) {
|
||||
@@ -555,10 +591,8 @@ namespace ArchiSteamFarm.Json {
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
break;
|
||||
return Asset.EType.Unknown;
|
||||
}
|
||||
|
||||
break;
|
||||
case "item_class":
|
||||
switch (tag.Value) {
|
||||
case "item_class_2":
|
||||
@@ -567,7 +601,7 @@ namespace ArchiSteamFarm.Json {
|
||||
type = Asset.EType.TradingCard;
|
||||
}
|
||||
|
||||
break;
|
||||
continue;
|
||||
case "item_class_3":
|
||||
return Asset.EType.ProfileBackground;
|
||||
case "item_class_4":
|
||||
@@ -591,10 +625,8 @@ namespace ArchiSteamFarm.Json {
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
break;
|
||||
return Asset.EType.Unknown;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,6 +634,13 @@ namespace ArchiSteamFarm.Json {
|
||||
}
|
||||
}
|
||||
|
||||
[JsonExtensionData]
|
||||
internal Dictionary<string, JToken> AdditionalProperties {
|
||||
get;
|
||||
[UsedImplicitly]
|
||||
set;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "appid", Required = Required.Always)]
|
||||
internal uint AppID { get; set; }
|
||||
|
||||
@@ -610,7 +649,7 @@ namespace ArchiSteamFarm.Json {
|
||||
internal bool Marketable { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "tags", Required = Required.DisallowNull)]
|
||||
internal ImmutableHashSet<Tag> Tags { get; set; } = ImmutableHashSet<Tag>.Empty;
|
||||
internal ImmutableHashSet<Asset.Tag> Tags { get; set; }
|
||||
|
||||
internal bool Tradable { get; set; }
|
||||
|
||||
@@ -670,26 +709,6 @@ namespace ArchiSteamFarm.Json {
|
||||
|
||||
[JsonConstructor]
|
||||
internal Description() { }
|
||||
|
||||
internal sealed class Tag {
|
||||
[JsonProperty(PropertyName = "category", Required = Required.Always)]
|
||||
internal readonly string Identifier;
|
||||
|
||||
[JsonProperty(PropertyName = "internal_name", Required = Required.Always)]
|
||||
internal readonly string Value;
|
||||
|
||||
internal Tag([JetBrains.Annotations.NotNull] string identifier, [JetBrains.Annotations.NotNull] string value) {
|
||||
if (string.IsNullOrEmpty(identifier) || string.IsNullOrEmpty(value)) {
|
||||
throw new ArgumentNullException(nameof(identifier) + " || " + nameof(value));
|
||||
}
|
||||
|
||||
Identifier = identifier;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private Tag() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -732,7 +732,7 @@ StackTrace:
|
||||
<value>Alte Dateien nach dem Update bereinigen...</value>
|
||||
</data>
|
||||
<data name="BotGeneratingSteamParentalCode" xml:space="preserve">
|
||||
<value>Erstelle Steam-Jugendschutz-Code, das kann einige Zeit dauern. Eventuell sollten Sie den Code in der Konfiguration hinterlegen...</value>
|
||||
<value>Erstelle Steam-Jugendschutz-Code, das kann einige Zeit dauern. Eventuell sollten Sie stattdessen den Code in der Konfiguration hinterlegen...</value>
|
||||
</data>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Die IPC-Konfiguration wurde geändert!</value>
|
||||
|
||||
@@ -643,7 +643,10 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="BotLevel" xml:space="preserve">
|
||||
<value>Το bot βρίσκεται στο επίπεδο {0}.</value>
|
||||
<comment>{0} will be replaced by bot's level</comment>
|
||||
</data>
|
||||
|
||||
|
||||
<data name="ErrorAborted" xml:space="preserve">
|
||||
@@ -651,7 +654,10 @@ StackTrace:
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
<data name="PluginLoaded" xml:space="preserve">
|
||||
<value>{0} φορτώθηκε με επιτυχία!</value>
|
||||
<comment>{0} will be replaced by the name of the custom ASF plugin</comment>
|
||||
</data>
|
||||
<data name="PluginLoading" xml:space="preserve">
|
||||
<value>Φόρτωση του {0} Εκδ.{1}...</value>
|
||||
<comment>{0} will be replaced by the name of the custom ASF plugin, {1} will be replaced by its version</comment>
|
||||
@@ -676,14 +682,25 @@ StackTrace:
|
||||
<value>Η διαδραστική κονσόλα δεν είναι διαθέσιμη διότι λείπει η ιδιότητα {0} από το αρχείο διαμόρφωσης.</value>
|
||||
<comment>{0} will be replaced by the name of the missing config property (string)</comment>
|
||||
</data>
|
||||
|
||||
<data name="Response" xml:space="preserve">
|
||||
<value>Ανταπόκριση: {0}</value>
|
||||
<comment>{0} will be replaced by the generated response (string)</comment>
|
||||
</data>
|
||||
<data name="BotGamesToRedeemInBackgroundCount" xml:space="preserve">
|
||||
<value>Το bot έχει {0} παιχνίδια που απομένουν στην ουρά.</value>
|
||||
<comment>{0} will be replaced by remaining number of games in BGR's queue</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
<data name="ErrorSingleInstanceRequired" xml:space="preserve">
|
||||
<value>Η διαδικασία ASF εκτελείται ήδη για αυτόν τον κατάλογο εργασίας, ματαίωση!</value>
|
||||
</data>
|
||||
<data name="BotHandledConfirmations" xml:space="preserve">
|
||||
<value>Επεξεργάστηκαν {0} επιβεβαιώσεις με επιτυχία!</value>
|
||||
<comment>{0} will be replaced by number of confirmations</comment>
|
||||
</data>
|
||||
<data name="BotExtraIdlingCooldown" xml:space="preserve">
|
||||
<value>Περιμένουμε {0} για να διασφαλίσουμε ότι είμαστε ελεύθεροι να ξεκινήσουμε την συλλογή...</value>
|
||||
<comment>{0} will be replaced by translated TimeSpan string (such as "1 minute")</comment>
|
||||
</data>
|
||||
<data name="UpdateCleanup" xml:space="preserve">
|
||||
<value>Εκκαθάριση παλιών αρχείων μετά την ενημέρωση...</value>
|
||||
</data>
|
||||
|
||||
@@ -337,7 +337,9 @@
|
||||
<data name="IdlingStopped" xml:space="preserve">
|
||||
<value>Idling berhenti!</value>
|
||||
</data>
|
||||
|
||||
<data name="IgnoredPermanentPauseEnabled" xml:space="preserve">
|
||||
<value>Mengabaikan permintaan ini, karena jeda permanen diaktifkan!</value>
|
||||
</data>
|
||||
<data name="NothingToIdle" xml:space="preserve">
|
||||
<value>Kami tidak memiliki apa-apa untuk dimainkan di akun ini!</value>
|
||||
</data>
|
||||
@@ -620,7 +622,9 @@
|
||||
<value>{0}/{1} bot sudah mempunyai gamenya {2}.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own particular game being checked, {1} will be replaced by total number of bots that were checked during the process, {2} will be replaced by game's ID (number)</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotRefreshingPackagesData" xml:space="preserve">
|
||||
<value>Menyegarkan data paket...</value>
|
||||
</data>
|
||||
|
||||
<data name="BotAcceptedDonationTrade" xml:space="preserve">
|
||||
<value>Menerima trade donasi: {0}</value>
|
||||
|
||||
@@ -26,9 +26,9 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -155,18 +155,22 @@ namespace ArchiSteamFarm {
|
||||
|
||||
await LimitConfirmationsRequestsAsync().ConfigureAwait(false);
|
||||
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetConfirmations(DeviceID, confirmationHash, time).ConfigureAwait(false);
|
||||
IDocument htmlDocument = await Bot.ArchiWebHandler.GetConfirmations(DeviceID, confirmationHash, time).ConfigureAwait(false);
|
||||
|
||||
HtmlNodeCollection confirmationNodes = htmlDocument?.DocumentNode.SelectNodes("//div[@class='mobileconf_list_entry']");
|
||||
|
||||
if (confirmationNodes == null) {
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Confirmation> result = new HashSet<Confirmation>();
|
||||
|
||||
foreach (HtmlNode confirmationNode in confirmationNodes) {
|
||||
string idText = confirmationNode.GetAttributeValue("data-confid", null);
|
||||
List<IElement> confirmationNodes = htmlDocument.SelectNodes("//div[@class='mobileconf_list_entry']");
|
||||
|
||||
if (confirmationNodes.Count == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (IElement confirmationNode in confirmationNodes) {
|
||||
string idText = confirmationNode.GetAttributeValue("data-confid");
|
||||
|
||||
if (string.IsNullOrEmpty(idText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(idText));
|
||||
@@ -180,7 +184,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
string keyText = confirmationNode.GetAttributeValue("data-key", null);
|
||||
string keyText = confirmationNode.GetAttributeValue("data-key");
|
||||
|
||||
if (string.IsNullOrEmpty(keyText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(keyText));
|
||||
@@ -194,7 +198,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
string typeText = confirmationNode.GetAttributeValue("data-type", null);
|
||||
string typeText = confirmationNode.GetAttributeValue("data-type");
|
||||
|
||||
if (string.IsNullOrEmpty(typeText)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(typeText));
|
||||
|
||||
@@ -112,6 +112,11 @@ namespace ArchiSteamFarm {
|
||||
|
||||
[NotNull]
|
||||
internal static string Variant => "linux-arm";
|
||||
#elif ASF_VARIANT_LINUX_ARM64
|
||||
internal static bool CanUpdate => true;
|
||||
|
||||
[NotNull]
|
||||
internal static string Variant => "linux-arm64";
|
||||
#elif ASF_VARIANT_LINUX_X64
|
||||
internal static bool CanUpdate => true;
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
@@ -83,20 +83,20 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
private async Task<bool?> IsDiscoveryQueueAvailable() {
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetDiscoveryQueuePage().ConfigureAwait(false);
|
||||
IDocument htmlDocument = await Bot.ArchiWebHandler.GetDiscoveryQueuePage().ConfigureAwait(false);
|
||||
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='subtext']");
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("//div[@class='subtext']");
|
||||
|
||||
if (htmlNode == null) {
|
||||
// Valid, no cards for exploring the queue available
|
||||
return false;
|
||||
}
|
||||
|
||||
string text = htmlNode.InnerText;
|
||||
string text = htmlNode.TextContent;
|
||||
|
||||
if (string.IsNullOrEmpty(text)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(text));
|
||||
|
||||
@@ -27,6 +27,8 @@ using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using AngleSharp.XPath;
|
||||
using Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using JetBrains.Annotations;
|
||||
@@ -60,6 +62,17 @@ namespace ArchiSteamFarm {
|
||||
return args[args.Length - 1];
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static string GetAttributeValue(this INode node, string attributeName) {
|
||||
if ((node == null) || string.IsNullOrEmpty(attributeName)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(node) + " || " + nameof(attributeName));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return node is IElement element ? element.GetAttribute(attributeName) : null;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static uint GetUnixTime() => (uint) DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
|
||||
@@ -183,6 +196,24 @@ namespace ArchiSteamFarm {
|
||||
return (text.Length % 2 == 0) && text.All(Uri.IsHexDigit);
|
||||
}
|
||||
|
||||
[ItemNotNull]
|
||||
[NotNull]
|
||||
[PublicAPI]
|
||||
public static List<IElement> SelectElementNodes([NotNull] this IElement element, string xpath) => element.SelectNodes(xpath).Cast<IElement>().ToList();
|
||||
|
||||
[ItemNotNull]
|
||||
[NotNull]
|
||||
[PublicAPI]
|
||||
public static List<IElement> SelectNodes([NotNull] this IDocument document, string xpath) => document.Body.SelectNodes(xpath).Cast<IElement>().ToList();
|
||||
|
||||
[CanBeNull]
|
||||
[PublicAPI]
|
||||
public static IElement SelectSingleElementNode([NotNull] this IElement element, string xpath) => (IElement) element.SelectSingleNode(xpath);
|
||||
|
||||
[CanBeNull]
|
||||
[PublicAPI]
|
||||
public static IElement SelectSingleNode([NotNull] this IDocument document, string xpath) => (IElement) document.Body.SelectSingleNode(xpath);
|
||||
|
||||
[PublicAPI]
|
||||
public static IEnumerable<T> ToEnumerable<T>(this T item) {
|
||||
yield return item;
|
||||
|
||||
@@ -27,9 +27,10 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using AngleSharp;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
using HtmlAgilityPack;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -104,9 +105,44 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringResponse response = await UrlGetToString(request, referer, requestOptions, maxTries).ConfigureAwait(false);
|
||||
HtmlDocumentResponse result = null;
|
||||
|
||||
return response != null ? new HtmlDocumentResponse(response) : null;
|
||||
for (int i = 0; i < maxTries; i++) {
|
||||
using StreamResponse response = await UrlGetToStream(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.StatusCode.IsClientErrorCode()) {
|
||||
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
|
||||
result = new HtmlDocumentResponse(response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.Content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
result = await HtmlDocumentResponse.Create(response).ConfigureAwait(false);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (maxTries > 1) {
|
||||
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, maxTries));
|
||||
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
@@ -121,7 +157,7 @@ namespace ArchiSteamFarm {
|
||||
ObjectResponse<T> result = null;
|
||||
|
||||
for (byte i = 0; i < maxTries; i++) {
|
||||
StringResponse response = await UrlGetToString(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
using StreamResponse response = await UrlGetToStream(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
// ReSharper disable once UseNullPropagationWhenPossible - false check
|
||||
if (response == null) {
|
||||
@@ -136,20 +172,20 @@ namespace ArchiSteamFarm {
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(response.Content)) {
|
||||
if (response.Content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
T obj;
|
||||
|
||||
try {
|
||||
obj = JsonConvert.DeserializeObject<T>(response.Content);
|
||||
} catch (JsonException e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
using StreamReader streamReader = new StreamReader(response.Content);
|
||||
using JsonReader jsonReader = new JsonTextReader(streamReader);
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
if (Debugging.IsUserDebugging) {
|
||||
ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response.Content));
|
||||
}
|
||||
obj = serializer.Deserialize<T>(jsonReader);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -177,7 +213,7 @@ namespace ArchiSteamFarm {
|
||||
XmlDocumentResponse result = null;
|
||||
|
||||
for (byte i = 0; i < maxTries; i++) {
|
||||
StringResponse response = await UrlGetToString(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
using StreamResponse response = await UrlGetToStream(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
// ReSharper disable once UseNullPropagationWhenPossible - false check
|
||||
if (response == null) {
|
||||
@@ -192,14 +228,14 @@ namespace ArchiSteamFarm {
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(response.Content)) {
|
||||
if (response.Content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
|
||||
try {
|
||||
xmlDocument.LoadXml(response.Content);
|
||||
xmlDocument.Load(response.Content);
|
||||
} catch (XmlException e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
@@ -300,9 +336,44 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringResponse response = await UrlPostToString(request, data, referer, requestOptions, maxTries).ConfigureAwait(false);
|
||||
HtmlDocumentResponse result = null;
|
||||
|
||||
return response != null ? new HtmlDocumentResponse(response) : null;
|
||||
for (int i = 0; i < maxTries; i++) {
|
||||
using StreamResponse response = await UrlPostToStream(request, data, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.StatusCode.IsClientErrorCode()) {
|
||||
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
|
||||
result = new HtmlDocumentResponse(response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.Content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
result = await HtmlDocumentResponse.Create(response).ConfigureAwait(false);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (maxTries > 1) {
|
||||
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, maxTries));
|
||||
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
@@ -317,7 +388,7 @@ namespace ArchiSteamFarm {
|
||||
ObjectResponse<T> result = null;
|
||||
|
||||
for (byte i = 0; i < maxTries; i++) {
|
||||
StringResponse response = await UrlPostToString(request, data, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
using StreamResponse response = await UrlPostToStream(request, data, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
@@ -331,20 +402,20 @@ namespace ArchiSteamFarm {
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(response.Content)) {
|
||||
if (response.Content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
T obj;
|
||||
|
||||
try {
|
||||
obj = JsonConvert.DeserializeObject<T>(response.Content);
|
||||
} catch (JsonException e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
using StreamReader steamReader = new StreamReader(response.Content);
|
||||
using JsonReader jsonReader = new JsonTextReader(steamReader);
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
if (Debugging.IsUserDebugging) {
|
||||
ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response.Content));
|
||||
}
|
||||
obj = serializer.Deserialize<T>(jsonReader);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -376,17 +447,16 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
internal static HtmlDocument StringToHtmlDocument(string html) {
|
||||
internal static async Task<IDocument> StringToHtmlDocument(string html) {
|
||||
if (html == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(html));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = new HtmlDocument();
|
||||
htmlDocument.LoadHtml(html);
|
||||
IBrowsingContext context = BrowsingContext.New(Configuration.Default.WithXPath());
|
||||
|
||||
return htmlDocument;
|
||||
return await context.OpenAsync(req => req.Content(html)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
@@ -403,7 +473,7 @@ namespace ArchiSteamFarm {
|
||||
const byte printPercentage = 10;
|
||||
const byte maxBatches = 99 / printPercentage;
|
||||
|
||||
using HttpResponseMessage response = await InternalGet(request, referer, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
using StreamResponse response = await UrlGetToStream(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
continue;
|
||||
@@ -419,12 +489,10 @@ namespace ArchiSteamFarm {
|
||||
|
||||
ArchiLogger.LogGenericDebug("0%...");
|
||||
|
||||
uint contentLength = (uint) response.Content.Headers.ContentLength.GetValueOrDefault();
|
||||
|
||||
using MemoryStream ms = new MemoryStream((int) contentLength);
|
||||
using MemoryStream ms = new MemoryStream((int) response.Length);
|
||||
|
||||
try {
|
||||
using Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
using Stream contentStream = response.Content;
|
||||
|
||||
byte batch = 0;
|
||||
uint readThisBatch = 0;
|
||||
@@ -439,17 +507,17 @@ namespace ArchiSteamFarm {
|
||||
|
||||
await ms.WriteAsync(buffer, 0, read).ConfigureAwait(false);
|
||||
|
||||
if ((contentLength == 0) || (batch >= maxBatches)) {
|
||||
if ((response.Length == 0) || (batch >= maxBatches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
readThisBatch += (uint) read;
|
||||
|
||||
if (readThisBatch < contentLength / printPercentage) {
|
||||
if (readThisBatch < response.Length / printPercentage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
readThisBatch -= contentLength / printPercentage;
|
||||
readThisBatch -= response.Length / printPercentage;
|
||||
ArchiLogger.LogGenericDebug((++batch * printPercentage) + "%...");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -507,14 +575,14 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> InternalGet(string request, string referer = null, HttpCompletionOption httpCompletionOptions = HttpCompletionOption.ResponseContentRead) {
|
||||
private async Task<HttpResponseMessage> InternalGet(string request, string referer = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
ArchiLogger.LogNullError(nameof(request));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return await InternalRequest(new Uri(request), HttpMethod.Get, null, referer, httpCompletionOptions).ConfigureAwait(false);
|
||||
return await InternalRequest(new Uri(request), HttpMethod.Get, null, referer, httpCompletionOption).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> InternalHead(string request, string referer = null) {
|
||||
@@ -527,14 +595,14 @@ namespace ArchiSteamFarm {
|
||||
return await InternalRequest(new Uri(request), HttpMethod.Head, null, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> InternalPost(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
|
||||
private async Task<HttpResponseMessage> InternalPost(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
ArchiLogger.LogNullError(nameof(request));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return await InternalRequest(new Uri(request), HttpMethod.Post, data, referer).ConfigureAwait(false);
|
||||
return await InternalRequest(new Uri(request), HttpMethod.Post, data, referer, httpCompletionOption).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> InternalRequest(Uri requestUri, HttpMethod httpMethod, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, byte maxRedirections = MaxTries) {
|
||||
@@ -643,17 +711,17 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
private async Task<StringResponse> UrlPostToString(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, ERequestOptions requestOptions = ERequestOptions.None, byte maxTries = MaxTries) {
|
||||
private async Task<StreamResponse> UrlGetToStream(string request, string referer = null, ERequestOptions requestOptions = ERequestOptions.None, byte maxTries = MaxTries) {
|
||||
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
|
||||
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
StringResponse result = null;
|
||||
StreamResponse result = null;
|
||||
|
||||
for (byte i = 0; i < maxTries; i++) {
|
||||
using HttpResponseMessage response = await InternalPost(request, data, referer).ConfigureAwait(false);
|
||||
HttpResponseMessage response = await InternalGet(request, referer, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
continue;
|
||||
@@ -661,13 +729,49 @@ namespace ArchiSteamFarm {
|
||||
|
||||
if (response.StatusCode.IsClientErrorCode()) {
|
||||
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
|
||||
result = new StringResponse(response);
|
||||
result = new StreamResponse(response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return new StringResponse(response, await response.Content.ReadAsStringAsync().ConfigureAwait(false));
|
||||
return new StreamResponse(response, await response.Content.ReadAsStreamAsync().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
if (maxTries > 1) {
|
||||
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, maxTries));
|
||||
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
private async Task<StreamResponse> UrlPostToStream(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, ERequestOptions requestOptions = ERequestOptions.None, byte maxTries = MaxTries) {
|
||||
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
|
||||
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
StreamResponse result = null;
|
||||
|
||||
for (byte i = 0; i < maxTries; i++) {
|
||||
HttpResponseMessage response = await InternalPost(request, data, referer, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.StatusCode.IsClientErrorCode()) {
|
||||
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
|
||||
result = new StreamResponse(response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return new StreamResponse(response, await response.Content.ReadAsStreamAsync().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
if (maxTries > 1) {
|
||||
@@ -705,15 +809,38 @@ namespace ArchiSteamFarm {
|
||||
|
||||
public sealed class HtmlDocumentResponse : BasicResponse {
|
||||
[PublicAPI]
|
||||
public readonly HtmlDocument Content;
|
||||
public readonly IDocument Content;
|
||||
|
||||
internal HtmlDocumentResponse([NotNull] StringResponse stringResponse) : base(stringResponse) {
|
||||
if (stringResponse == null) {
|
||||
throw new ArgumentNullException(nameof(stringResponse));
|
||||
internal HtmlDocumentResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) {
|
||||
if (basicResponse == null) {
|
||||
throw new ArgumentNullException(nameof(basicResponse));
|
||||
}
|
||||
}
|
||||
|
||||
private HtmlDocumentResponse([NotNull] StreamResponse streamResponse, [NotNull] IDocument document) : this(streamResponse) {
|
||||
if ((streamResponse == null) || (document == null)) {
|
||||
throw new ArgumentNullException(nameof(streamResponse) + " || " + nameof(document));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(stringResponse.Content)) {
|
||||
Content = StringToHtmlDocument(stringResponse.Content);
|
||||
Content = document;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
internal static async Task<HtmlDocumentResponse> Create([NotNull] StreamResponse streamResponse) {
|
||||
if (streamResponse == null) {
|
||||
throw new ArgumentNullException(nameof(streamResponse));
|
||||
}
|
||||
|
||||
IBrowsingContext context = BrowsingContext.New(Configuration.Default.WithXPath());
|
||||
|
||||
try {
|
||||
IDocument document = await context.OpenAsync(req => req.Content(streamResponse.Content, true)).ConfigureAwait(false);
|
||||
|
||||
return new HtmlDocumentResponse(streamResponse, document);
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -722,30 +849,38 @@ namespace ArchiSteamFarm {
|
||||
[PublicAPI]
|
||||
public readonly T Content;
|
||||
|
||||
internal ObjectResponse([NotNull] StringResponse stringResponse, T content) : base(stringResponse) {
|
||||
if (stringResponse == null) {
|
||||
throw new ArgumentNullException(nameof(stringResponse));
|
||||
internal ObjectResponse([NotNull] StreamResponse streamResponse, T content) : this(streamResponse) {
|
||||
if (streamResponse == null) {
|
||||
throw new ArgumentNullException(nameof(streamResponse));
|
||||
}
|
||||
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal ObjectResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) { }
|
||||
internal ObjectResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) {
|
||||
if (basicResponse == null) {
|
||||
throw new ArgumentNullException(nameof(basicResponse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class XmlDocumentResponse : BasicResponse {
|
||||
[PublicAPI]
|
||||
public readonly XmlDocument Content;
|
||||
|
||||
internal XmlDocumentResponse([NotNull] StringResponse stringResponse, XmlDocument content) : base(stringResponse) {
|
||||
if (stringResponse == null) {
|
||||
throw new ArgumentNullException(nameof(stringResponse));
|
||||
internal XmlDocumentResponse([NotNull] StreamResponse streamResponse, XmlDocument content) : this(streamResponse) {
|
||||
if (streamResponse == null) {
|
||||
throw new ArgumentNullException(nameof(streamResponse));
|
||||
}
|
||||
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal XmlDocumentResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) { }
|
||||
internal XmlDocumentResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) {
|
||||
if (basicResponse == null) {
|
||||
throw new ArgumentNullException(nameof(basicResponse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
@@ -757,7 +892,28 @@ namespace ArchiSteamFarm {
|
||||
internal sealed class BinaryResponse : BasicResponse {
|
||||
internal readonly byte[] Content;
|
||||
|
||||
internal BinaryResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] byte[] content) : base(httpResponseMessage) {
|
||||
internal BinaryResponse([NotNull] BasicResponse basicResponse, [NotNull] byte[] content) : this(basicResponse) {
|
||||
if ((basicResponse == null) || (content == null)) {
|
||||
throw new ArgumentNullException(nameof(basicResponse) + " || " + nameof(content));
|
||||
}
|
||||
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal BinaryResponse([NotNull] BasicResponse basicResponse) : base(basicResponse) {
|
||||
if (basicResponse == null) {
|
||||
throw new ArgumentNullException(nameof(basicResponse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class StreamResponse : BasicResponse, IDisposable {
|
||||
internal readonly Stream Content;
|
||||
internal readonly uint Length;
|
||||
|
||||
private readonly HttpResponseMessage ResponseMessage;
|
||||
|
||||
internal StreamResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] Stream content) : this(httpResponseMessage) {
|
||||
if ((httpResponseMessage == null) || (content == null)) {
|
||||
throw new ArgumentNullException(nameof(httpResponseMessage) + " || " + nameof(content));
|
||||
}
|
||||
@@ -765,13 +921,26 @@ namespace ArchiSteamFarm {
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal BinaryResponse([NotNull] HttpResponseMessage httpResponseMessage) : base(httpResponseMessage) { }
|
||||
internal StreamResponse([NotNull] HttpResponseMessage httpResponseMessage) : base(httpResponseMessage) {
|
||||
if (httpResponseMessage == null) {
|
||||
throw new ArgumentNullException(nameof(httpResponseMessage));
|
||||
}
|
||||
|
||||
Length = (uint) httpResponseMessage.Content.Headers.ContentLength.GetValueOrDefault();
|
||||
ResponseMessage = httpResponseMessage;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Content?.Dispose();
|
||||
|
||||
ResponseMessage.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class StringResponse : BasicResponse {
|
||||
internal readonly string Content;
|
||||
|
||||
internal StringResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] string content) : base(httpResponseMessage) {
|
||||
internal StringResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] string content) : this(httpResponseMessage) {
|
||||
if ((httpResponseMessage == null) || (content == null)) {
|
||||
throw new ArgumentNullException(nameof(httpResponseMessage) + " || " + nameof(content));
|
||||
}
|
||||
@@ -779,7 +948,11 @@ namespace ArchiSteamFarm {
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal StringResponse([NotNull] HttpResponseMessage httpResponseMessage) : base(httpResponseMessage) { }
|
||||
internal StringResponse([NotNull] HttpResponseMessage httpResponseMessage) : base(httpResponseMessage) {
|
||||
if (httpResponseMessage == null) {
|
||||
throw new ArgumentNullException(nameof(httpResponseMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
77
ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh
Executable file
77
ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
CONFIG_PATH="config/ASF.json"
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
SCRIPT_DIR="$(pwd)"
|
||||
SCRIPT_PATH="${SCRIPT_DIR}/${0}"
|
||||
|
||||
BINARY="${SCRIPT_DIR}/ArchiSteamFarm"
|
||||
|
||||
if [ ! -f "$BINARY" ]; then
|
||||
echo "ERROR: $BINARY could not be found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BINARY_ARGS=""
|
||||
PATH_NEXT=0
|
||||
|
||||
PARSE_ARG() {
|
||||
BINARY_ARGS="$BINARY_ARGS $1"
|
||||
|
||||
case "$1" in
|
||||
--path) PATH_NEXT=1 ;;
|
||||
--path=*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
else
|
||||
cd "$(echo "$1" | cut -d '=' -f 2-)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
fi
|
||||
esac
|
||||
}
|
||||
|
||||
if [ -n "${ASF_PATH-}" ]; then
|
||||
cd "$ASF_PATH"
|
||||
fi
|
||||
|
||||
if [ -n "${ASF_ARGS-}" ]; then
|
||||
for ARG in $ASF_ARGS; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
for ARG in "$@"; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
|
||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||
|
||||
# Kill underlying ASF process on shell process exit
|
||||
trap "trap - TERM && kill -- -$$" INT TERM
|
||||
|
||||
while :; do
|
||||
if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then
|
||||
# We're running ASF in headless mode so we don't need STDIN
|
||||
"$BINARY" $BINARY_ARGS & # Start ASF in the background, trap will work properly due to non-blocking call
|
||||
wait $! # This will forward dotnet error code, set -e will abort the script if it's non-zero
|
||||
else
|
||||
# We're running ASF in non-headless mode, so we need STDIN to be operative
|
||||
"$BINARY" $BINARY_ARGS # Start ASF in the foreground, trap sadly won't work until process exit
|
||||
fi
|
||||
|
||||
chmod +x "$SCRIPT_PATH" # If ASF exited by itself, we need to ensure that our script is still set to +x after auto-update
|
||||
sleep 1
|
||||
done
|
||||
77
ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh
Executable file
77
ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
CONFIG_PATH="config/ASF.json"
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
SCRIPT_DIR="$(pwd)"
|
||||
SCRIPT_PATH="${SCRIPT_DIR}/${0}"
|
||||
|
||||
BINARY="${SCRIPT_DIR}/ArchiSteamFarm"
|
||||
|
||||
if [ ! -f "$BINARY" ]; then
|
||||
echo "ERROR: $BINARY could not be found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BINARY_ARGS=""
|
||||
PATH_NEXT=0
|
||||
|
||||
PARSE_ARG() {
|
||||
BINARY_ARGS="$BINARY_ARGS $1"
|
||||
|
||||
case "$1" in
|
||||
--path) PATH_NEXT=1 ;;
|
||||
--path=*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
else
|
||||
cd "$(echo "$1" | cut -d '=' -f 2-)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
fi
|
||||
esac
|
||||
}
|
||||
|
||||
if [ -n "${ASF_PATH-}" ]; then
|
||||
cd "$ASF_PATH"
|
||||
fi
|
||||
|
||||
if [ -n "${ASF_ARGS-}" ]; then
|
||||
for ARG in $ASF_ARGS; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
for ARG in "$@"; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
|
||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||
|
||||
# Kill underlying ASF process on shell process exit
|
||||
trap "trap - TERM && kill -- -$$" INT TERM
|
||||
|
||||
while :; do
|
||||
if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then
|
||||
# We're running ASF in headless mode so we don't need STDIN
|
||||
"$BINARY" $BINARY_ARGS & # Start ASF in the background, trap will work properly due to non-blocking call
|
||||
wait $! # This will forward dotnet error code, set -e will abort the script if it's non-zero
|
||||
else
|
||||
# We're running ASF in non-headless mode, so we need STDIN to be operative
|
||||
"$BINARY" $BINARY_ARGS # Start ASF in the foreground, trap sadly won't work until process exit
|
||||
fi
|
||||
|
||||
chmod +x "$SCRIPT_PATH" # If ASF exited by itself, we need to ensure that our script is still set to +x after auto-update
|
||||
sleep 1
|
||||
done
|
||||
77
ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh
Executable file
77
ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
CONFIG_PATH="config/ASF.json"
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
SCRIPT_DIR="$(pwd)"
|
||||
SCRIPT_PATH="${SCRIPT_DIR}/${0}"
|
||||
|
||||
BINARY="${SCRIPT_DIR}/ArchiSteamFarm"
|
||||
|
||||
if [ ! -f "$BINARY" ]; then
|
||||
echo "ERROR: $BINARY could not be found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BINARY_ARGS=""
|
||||
PATH_NEXT=0
|
||||
|
||||
PARSE_ARG() {
|
||||
BINARY_ARGS="$BINARY_ARGS $1"
|
||||
|
||||
case "$1" in
|
||||
--path) PATH_NEXT=1 ;;
|
||||
--path=*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
else
|
||||
cd "$(echo "$1" | cut -d '=' -f 2-)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ "$PATH_NEXT" -eq 1 ]; then
|
||||
PATH_NEXT=0
|
||||
cd "$1"
|
||||
fi
|
||||
esac
|
||||
}
|
||||
|
||||
if [ -n "${ASF_PATH-}" ]; then
|
||||
cd "$ASF_PATH"
|
||||
fi
|
||||
|
||||
if [ -n "${ASF_ARGS-}" ]; then
|
||||
for ARG in $ASF_ARGS; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
for ARG in "$@"; do
|
||||
if [ -n "$ARG" ]; then
|
||||
PARSE_ARG "$ARG"
|
||||
fi
|
||||
done
|
||||
|
||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||
|
||||
# Kill underlying ASF process on shell process exit
|
||||
trap "trap - TERM && kill -- -$$" INT TERM
|
||||
|
||||
while :; do
|
||||
if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then
|
||||
# We're running ASF in headless mode so we don't need STDIN
|
||||
"$BINARY" $BINARY_ARGS & # Start ASF in the background, trap will work properly due to non-blocking call
|
||||
wait $! # This will forward dotnet error code, set -e will abort the script if it's non-zero
|
||||
else
|
||||
# We're running ASF in non-headless mode, so we need STDIN to be operative
|
||||
"$BINARY" $BINARY_ARGS # Start ASF in the foreground, trap sadly won't work until process exit
|
||||
fi
|
||||
|
||||
chmod +x "$SCRIPT_PATH" # If ASF exited by itself, we need to ensure that our script is still set to +x after auto-update
|
||||
sleep 1
|
||||
done
|
||||
@@ -20,10 +20,10 @@ RUN dotnet --info && \
|
||||
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet clean ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' --nologo /p:ASFVariant=generic /p:UseAppHost=false && \
|
||||
cp "ArchiSteamFarm/overlay/generic/ArchiSteamFarm-Service.sh" "out/ArchiSteamFarm-Service.sh"
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' -r 'linux-arm' --nologo /p:ASFVariant=linux-arm /p:PublishTrimmed=true && \
|
||||
cp "ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh" "out/ArchiSteamFarm-Service.sh"
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim-arm32v7 AS runtime
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim-arm32v7 AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
LABEL maintainer="JustArchi <JustArchi@JustArchi.net>"
|
||||
EXPOSE 1242
|
||||
|
||||
32
Dockerfile.Service.arm64
Normal file
32
Dockerfile.Service.arm64
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM node:lts AS build-node
|
||||
WORKDIR /app
|
||||
COPY ASF-ui .
|
||||
RUN echo "node: $(node --version)" && \
|
||||
echo "npm: $(npm --version)" && \
|
||||
npm ci && \
|
||||
npm run deploy
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-dotnet
|
||||
ENV CONFIGURATION Release
|
||||
ENV NET_CORE_VERSION netcoreapp3.1
|
||||
WORKDIR /app
|
||||
COPY --from=build-node /app/dist ASF-ui/dist
|
||||
COPY ArchiSteamFarm ArchiSteamFarm
|
||||
COPY ArchiSteamFarm.Tests ArchiSteamFarm.Tests
|
||||
RUN dotnet --info && \
|
||||
# TODO: Remove workaround for https://github.com/microsoft/msbuild/issues/3897 when it's no longer needed
|
||||
if [ -f "ArchiSteamFarm/Localization/Strings.zh-CN.resx" ]; then ln -s "Strings.zh-CN.resx" "ArchiSteamFarm/Localization/Strings.zh-Hans.resx"; fi && \
|
||||
if [ -f "ArchiSteamFarm/Localization/Strings.zh-TW.resx" ]; then ln -s "Strings.zh-TW.resx" "ArchiSteamFarm/Localization/Strings.zh-Hant.resx"; fi && \
|
||||
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet clean ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' -r 'linux-arm64' --nologo /p:ASFVariant=linux-arm64 /p:PublishTrimmed=true && \
|
||||
cp "ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh" "out/ArchiSteamFarm-Service.sh"
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim-arm64v8 AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
LABEL maintainer="JustArchi <JustArchi@JustArchi.net>"
|
||||
EXPOSE 1242
|
||||
WORKDIR /app
|
||||
COPY --from=build-dotnet /app/out .
|
||||
ENTRYPOINT ["./ArchiSteamFarm-Service.sh", "--no-restart", "--process-required", "--system-required"]
|
||||
@@ -20,10 +20,10 @@ RUN dotnet --info && \
|
||||
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet clean ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' --nologo /p:ASFVariant=generic /p:UseAppHost=false && \
|
||||
cp "ArchiSteamFarm/overlay/generic/ArchiSteamFarm-Service.sh" "out/ArchiSteamFarm-Service.sh"
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' -r 'linux-x64' --nologo /p:ASFVariant=linux-x64 /p:PublishTrimmed=true && \
|
||||
cp "ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh" "out/ArchiSteamFarm-Service.sh"
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS runtime
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
LABEL maintainer="JustArchi <JustArchi@JustArchi.net>"
|
||||
EXPOSE 1242
|
||||
|
||||
32
Dockerfile.arm64
Normal file
32
Dockerfile.arm64
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM node:lts AS build-node
|
||||
WORKDIR /app
|
||||
COPY ASF-ui .
|
||||
RUN echo "node: $(node --version)" && \
|
||||
echo "npm: $(npm --version)" && \
|
||||
npm ci && \
|
||||
npm run deploy
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-dotnet
|
||||
ENV CONFIGURATION Release
|
||||
ENV NET_CORE_VERSION netcoreapp3.1
|
||||
WORKDIR /app
|
||||
COPY --from=build-node /app/dist ASF-ui/dist
|
||||
COPY ArchiSteamFarm ArchiSteamFarm
|
||||
COPY ArchiSteamFarm.Tests ArchiSteamFarm.Tests
|
||||
RUN dotnet --info && \
|
||||
# TODO: Remove workaround for https://github.com/microsoft/msbuild/issues/3897 when it's no longer needed
|
||||
if [ -f "ArchiSteamFarm/Localization/Strings.zh-CN.resx" ]; then ln -s "Strings.zh-CN.resx" "ArchiSteamFarm/Localization/Strings.zh-Hans.resx"; fi && \
|
||||
if [ -f "ArchiSteamFarm/Localization/Strings.zh-TW.resx" ]; then ln -s "Strings.zh-TW.resx" "ArchiSteamFarm/Localization/Strings.zh-Hant.resx"; fi && \
|
||||
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet clean ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" --nologo && \
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out' --nologo /p:ASFVariant=docker /p:UseAppHost=false && \
|
||||
cp "ArchiSteamFarm/overlay/generic/ArchiSteamFarm.sh" "out/ArchiSteamFarm.sh"
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim-arm64v8 AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
LABEL maintainer="JustArchi <JustArchi@JustArchi.net>"
|
||||
EXPOSE 1242
|
||||
WORKDIR /app
|
||||
COPY --from=build-dotnet /app/out .
|
||||
ENTRYPOINT ["./ArchiSteamFarm.sh", "--no-restart", "--process-required", "--system-required"]
|
||||
14
appveyor.yml
14
appveyor.yml
@@ -15,7 +15,7 @@ environment:
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
NET_CORE_VERSION: netcoreapp3.1
|
||||
NET_FRAMEWORK_VERSION: net48
|
||||
VARIANTS: generic generic-netf linux-arm linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
VARIANTS: generic generic-netf linux-arm linux-arm64 linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
|
||||
matrix:
|
||||
allow_failures:
|
||||
- image: Visual Studio 2019 Preview
|
||||
@@ -146,10 +146,8 @@ after_test:
|
||||
Set-Location "$env:APPVEYOR_BUILD_FOLDER"
|
||||
|
||||
if ($variant -like '*-netf') {
|
||||
$compressionMethod = 'Deflate' # This depends on what ZipArchive supports on given platform
|
||||
$targetFramework = $env:NET_FRAMEWORK_VERSION
|
||||
} else {
|
||||
$compressionMethod = 'Deflate64' # This depends on what ZipArchive supports on given platform
|
||||
$targetFramework = $env:NET_CORE_VERSION
|
||||
}
|
||||
|
||||
@@ -189,17 +187,11 @@ after_test:
|
||||
|
||||
# If this build is going to be deployed further, prefer maximum compression
|
||||
if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq 'Visual Studio 2019') {
|
||||
$compressionArgs = '-mx=9', '-mpass=15'
|
||||
|
||||
if ($compressionMethod -eq 'Deflate64') {
|
||||
$compressionArgs += '-mfb=257'
|
||||
} else {
|
||||
$compressionArgs += '-mfb=258'
|
||||
}
|
||||
$compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
|
||||
}
|
||||
}
|
||||
|
||||
7z a -bd -tzip "-mm=$compressionMethod" $compressionArgs "out\ASF-$variant.zip" "$env:APPVEYOR_BUILD_FOLDER\out\$variant\*"
|
||||
7z a -bd -slp -tzip -mm=Deflate $compressionArgs "out\ASF-$variant.zip" "$env:APPVEYOR_BUILD_FOLDER\out\$variant\*"
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed."
|
||||
|
||||
2
wiki
2
wiki
Submodule wiki updated: 464384862f...9722145621
Reference in New Issue
Block a user