diff --git a/README.en.md b/README.en.md
index 131a62647..7d1628aff 100644
--- a/README.en.md
+++ b/README.en.md
@@ -89,9 +89,11 @@ Read what we [milestones](https://github.com/SteamTools-Team/SteamTools/mileston
* [SteamDB-API](https://github.com/SteamDB-API/api)
* [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)
* [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm)
+* [Steam4NET](https://github.com/SteamRE/Steam4NET)
* [WinAuth](https://github.com/winauth/winauth)
* [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
* [Gameloop.Vdf](https://github.com/shravan2x/Gameloop.Vdf)
+* [DnsClient.NET](https://github.com/MichaCo/DnsClient.NET)
* [Costura.Fody](https://github.com/Fody/Costura)
* [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)
* [Nito.Comparers](https://github.com/StephenCleary/Comparers)
@@ -99,14 +101,16 @@ Read what we [milestones](https://github.com/SteamTools-Team/SteamTools/mileston
* [gfoidl.Base64](https://github.com/gfoidl/Base64)
* [sqlite-net-pcl](https://github.com/praeclarum/sqlite-net)
* [Polly](https://github.com/App-vNext/Polly)
+* [TaskScheduler](https://github.com/dahall/taskscheduler)
+* [SharpZipLib](https://github.com/icsharpcode/SharpZipLib)
* [NLog](https://github.com/nlog/NLog)
* [NUnit](https://github.com/nunit/nunit)
* [ReactiveUI](https://github.com/reactiveui/reactiveui)
* [MessageBox.Avalonia](https://github.com/AvaloniaUtils/MessageBox.Avalonia)
* [AvaloniaUI](https://github.com/AvaloniaUI/Avalonia)
* [Xamarin.Essentials](https://github.com/xamarin/essentials)
-* [ASP.NET Core](https://github.com/dotnet/aspnetcore)
* [Entity Framework Core](https://github.com/dotnet/efcore)
+* [ASP.NET Core](https://github.com/dotnet/aspnetcore)
* [Windows Forms](https://github.com/dotnet/winforms)
* [Windows Presentation Foundation (WPF)](https://github.com/dotnet/wpf)
* [.NET Extensions](https://github.com/dotnet/extensions)
diff --git a/README.md b/README.md
index ea66c78d4..0aa9528ab 100644
--- a/README.md
+++ b/README.md
@@ -99,9 +99,11 @@
* [SteamDB-API](https://github.com/SteamDB-API/api)
* [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)
* [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm)
+* [Steam4NET](https://github.com/SteamRE/Steam4NET)
* [WinAuth](https://github.com/winauth/winauth)
* [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
* [Gameloop.Vdf](https://github.com/shravan2x/Gameloop.Vdf)
+* [DnsClient.NET](https://github.com/MichaCo/DnsClient.NET)
* [Costura.Fody](https://github.com/Fody/Costura)
* [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)
* [Nito.Comparers](https://github.com/StephenCleary/Comparers)
@@ -109,6 +111,8 @@
* [gfoidl.Base64](https://github.com/gfoidl/Base64)
* [sqlite-net-pcl](https://github.com/praeclarum/sqlite-net)
* [Polly](https://github.com/App-vNext/Polly)
+* [TaskScheduler](https://github.com/dahall/taskscheduler)
+* [SharpZipLib](https://github.com/icsharpcode/SharpZipLib)
* [NLog](https://github.com/nlog/NLog)
* [NUnit](https://github.com/nunit/nunit)
* [ReactiveUI](https://github.com/reactiveui/reactiveui)
diff --git a/SteamToolsV1.2+.sln b/SteamToolsV1.2+.sln
index 6a09a46dc..cd53d151c 100644
--- a/SteamToolsV1.2+.sln
+++ b/SteamToolsV1.2+.sln
@@ -69,94 +69,216 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamToo
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{CC6FF77A-6E6B-4D42-B12B-0177745E9D22}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2_Reference", "2_Reference", "{8EB91F53-1062-4E9B-8E4A-096F35EA688D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authenticator", "references\WinAuth\Authenticator\Authenticator.csproj", "{D018C980-17FD-49BB-A95D-EDE3C18BBE0A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SAM.API", "references\SteamAchievementManager\SAM.API\SAM.API.csproj", "{6DD9644F-F005-4C19-8ADF-70C303EC5BB8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steam4NET", "references\Steam4NET\Steam4NET\Steam4NET.csproj", "{3C05CED6-7712-40F0-AF17-8DD3F4C0A224}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "references\Titanium-Web-Proxy\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{35D60129-6652-4B6E-A04A-9766C3CF1869}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|x86.Build.0 = Debug|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|x86.Build.0 = Release|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|x86.Build.0 = Debug|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|x86.ActiveCfg = Release|Any CPU
+ {8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|x86.Build.0 = Release|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|x86.Build.0 = Debug|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|x86.ActiveCfg = Release|Any CPU
+ {E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|x86.Build.0 = Release|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7C8D906E-426B-49AB-9072-178555370F62}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7C8D906E-426B-49AB-9072-178555370F62}.Debug|x86.Build.0 = Debug|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7C8D906E-426B-49AB-9072-178555370F62}.Release|x86.ActiveCfg = Release|Any CPU
+ {7C8D906E-426B-49AB-9072-178555370F62}.Release|x86.Build.0 = Release|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|x86.Build.0 = Debug|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|x86.ActiveCfg = Release|Any CPU
+ {F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|x86.Build.0 = Release|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|x86.Build.0 = Debug|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|x86.ActiveCfg = Release|Any CPU
+ {6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|x86.Build.0 = Release|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|x86.Build.0 = Debug|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|Any CPU.Build.0 = Release|Any CPU
+ {65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|x86.ActiveCfg = Release|Any CPU
+ {65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|x86.Build.0 = Release|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|x86.Build.0 = Debug|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|x86.ActiveCfg = Release|Any CPU
+ {B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|x86.Build.0 = Release|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0073A08E-6336-4C09-99F9-2E808889D715}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0073A08E-6336-4C09-99F9-2E808889D715}.Debug|x86.Build.0 = Debug|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0073A08E-6336-4C09-99F9-2E808889D715}.Release|x86.ActiveCfg = Release|Any CPU
+ {0073A08E-6336-4C09-99F9-2E808889D715}.Release|x86.Build.0 = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|x86.Build.0 = Debug|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|x86.Deploy.0 = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.Build.0 = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|x86.ActiveCfg = Release|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|x86.Build.0 = Release|Any CPU
+ {AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|x86.Deploy.0 = Release|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|x86.Build.0 = Debug|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|x86.ActiveCfg = Release|Any CPU
+ {66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|x86.Build.0 = Release|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|x86.Build.0 = Debug|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|x86.ActiveCfg = Release|Any CPU
+ {0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|x86.Build.0 = Release|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|x86.Build.0 = Debug|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|x86.ActiveCfg = Release|Any CPU
+ {D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|x86.Build.0 = Release|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|x86.Build.0 = Debug|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|x86.ActiveCfg = Release|Any CPU
+ {2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|x86.Build.0 = Release|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|x86.Build.0 = Debug|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|x86.ActiveCfg = Release|Any CPU
+ {4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|x86.Build.0 = Release|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|x86.Build.0 = Debug|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|x86.Build.0 = Release|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|x86.Build.0 = Debug|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|x86.ActiveCfg = Release|Any CPU
+ {948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|x86.Build.0 = Release|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {141532E1-540E-4E50-8723-96936C191281}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {141532E1-540E-4E50-8723-96936C191281}.Debug|x86.Build.0 = Debug|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Release|Any CPU.ActiveCfg = Release|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Release|Any CPU.Build.0 = Release|Any CPU
+ {141532E1-540E-4E50-8723-96936C191281}.Release|x86.ActiveCfg = Release|Any CPU
+ {141532E1-540E-4E50-8723-96936C191281}.Release|x86.Build.0 = Release|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|x86.Build.0 = Debug|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|x86.ActiveCfg = Release|Any CPU
+ {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|x86.Build.0 = Release|Any CPU
{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|x86.Build.0 = Debug|Any CPU
{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|x86.ActiveCfg = Release|Any CPU
+ {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|x86.Build.0 = Release|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Debug|x86.Build.0 = Debug|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Release|x86.ActiveCfg = Release|Any CPU
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A}.Release|x86.Build.0 = Release|Any CPU
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Debug|x86.ActiveCfg = Debug|x86
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Debug|x86.Build.0 = Debug|x86
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Release|Any CPU.ActiveCfg = Release|x86
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Release|x86.ActiveCfg = Release|x86
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8}.Release|x86.Build.0 = Release|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Debug|x86.ActiveCfg = Debug|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Debug|x86.Build.0 = Debug|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Release|Any CPU.ActiveCfg = Release|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Release|x86.ActiveCfg = Release|x86
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224}.Release|x86.Build.0 = Release|x86
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Debug|x86.Build.0 = Debug|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Release|x86.ActiveCfg = Release|Any CPU
+ {35D60129-6652-4B6E-A04A-9766C3CF1869}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -189,6 +311,11 @@ Global
{60530AF8-4790-4A85-BCE2-C5673E9C601B} = {CC6FF77A-6E6B-4D42-B12B-0177745E9D22}
{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34} = {CC6FF77A-6E6B-4D42-B12B-0177745E9D22}
{CC6FF77A-6E6B-4D42-B12B-0177745E9D22} = {1460800B-D9ED-4147-B1E7-ABF502BEF59A}
+ {8EB91F53-1062-4E9B-8E4A-096F35EA688D} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
+ {D018C980-17FD-49BB-A95D-EDE3C18BBE0A} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
+ {6DD9644F-F005-4C19-8ADF-70C303EC5BB8} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
+ {3C05CED6-7712-40F0-AF17-8DD3F4C0A224} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
+ {35D60129-6652-4B6E-A04A-9766C3CF1869} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs
index b77b70d22..ca4d17c06 100644
--- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs
+++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs
@@ -16,6 +16,9 @@ namespace System.Application.UI
[STAThread]
static void Main(string[] args)
{
+ // 目前桌面端默认使用 SystemTextJson 如果出现兼容性问题可取消下面这行代码
+ // Serializable.DefaultJsonImplType = Serializable.JsonImplType.NewtonsoftJson;
+
var logger = LogManager.GetCurrentClassLogger();
try
{
@@ -94,6 +97,9 @@ namespace System.Application.UI
// 通用 Http 服务
services.AddHttpService();
+
+ // Steam 相关助手、工具类服务
+ services.AddSteamService();
}
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x64.pubxml b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x64.pubxml
deleted file mode 100644
index 84c3f7d68..000000000
--- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x64.pubxml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- PUBLISH;$(DefineConstants)
- Release
- Any CPU
- bin\Release\Publish\win-x64
- FileSystem
- win-x64
- true
- true
- true
-
- True
- link
- true
-
- false
- false
- false
- false
- false
- false
- true
- none
- false
-
-
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Linux/Application/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Linux/Application/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
index e61cb2f7b..ef59a9454 100644
--- a/System.Application.SteamTools.Client.Desktop.Linux/Application/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
+++ b/System.Application.SteamTools.Client.Desktop.Linux/Application/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
@@ -18,5 +18,22 @@ namespace System.Application.Services.Implementation
{
return null;
}
+
+ public void SetBootAutoStart(bool isAutoStart, string name)
+ {
+
+ }
+
+ public string? GetSteamDirPath()
+ {
+ return null;
+ }
+
+ public string? GetSteamProgramPath()
+ {
+ return null;
+ }
+
+ public string GetLastSteamLoginUserName() => string.Empty;
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Mac/Application/Services/Implementation/MacDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Mac/Application/Services/Implementation/MacDesktopPlatformServiceImpl.cs
index 7d42a52e4..cb0e5b1bb 100644
--- a/System.Application.SteamTools.Client.Desktop.Mac/Application/Services/Implementation/MacDesktopPlatformServiceImpl.cs
+++ b/System.Application.SteamTools.Client.Desktop.Mac/Application/Services/Implementation/MacDesktopPlatformServiceImpl.cs
@@ -18,5 +18,22 @@ namespace System.Application.Services.Implementation
{
return null;
}
+
+ public void SetBootAutoStart(bool isAutoStart, string name)
+ {
+
+ }
+
+ public string? GetSteamDirPath()
+ {
+ return null;
+ }
+
+ public string? GetSteamProgramPath()
+ {
+ return null;
+ }
+
+ public string GetLastSteamLoginUserName() => string.Empty;
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.Administrator.cs b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.Administrator.cs
new file mode 100644
index 000000000..658dab0ca
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.Administrator.cs
@@ -0,0 +1,23 @@
+using System.Security.Principal;
+
+namespace System.Application.Services.Implementation
+{
+ partial class WindowsDesktopPlatformServiceImpl
+ {
+ #region Administrator
+
+ static readonly Lazy mIsAdministrator = new Lazy(IsAdministrator_);
+
+ static bool IsAdministrator_()
+ => new WindowsPrincipal(WindowsIdentity.GetCurrent())
+ .IsInRole(WindowsBuiltInRole.Administrator);
+
+ ///
+ /// 是否是管理员权限
+ ///
+ ///
+ public bool IsAdministrator => mIsAdministrator.Value;
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs
new file mode 100644
index 000000000..2080d22a2
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs
@@ -0,0 +1,88 @@
+using System.Runtime.InteropServices;
+
+namespace System.Application.Services.Implementation
+{
+ partial class WindowsDesktopPlatformServiceImpl
+ {
+ #region 窗口右上角的三个按钮(最小化,最大化,关闭)
+
+ // https://stackoverflow.com/questions/339620/how-do-i-remove-minimize-and-maximize-from-a-resizable-window-in-wpf
+ // https://blog.magnusmontin.net/2014/11/30/disabling-or-hiding-the-minimize-maximize-or-close-button-of-a-wpf-window/
+
+ public const int MF_BYCOMMAND = 0x00000000;
+ public const int SC_CLOSE = 0xF060;
+ public const int SC_MINIMIZE = 0xF020;
+ public const int SC_MAXIMIZE = 0xF030;
+
+ [DllImport("user32.dll")]
+ public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
+
+ public const int GWL_STYLE = -16,
+ WS_MAXIMIZEBOX = 0x10000,
+ WS_MINIMIZEBOX = 0x20000;
+
+ [DllImport("user32.dll")]
+ public extern static int GetWindowLong(IntPtr hwnd, int index);
+
+ [DllImport("user32.dll")]
+ public extern static int SetWindowLong(IntPtr hwnd, int index, int value);
+
+ public const int WS_SYSMENU = 0x80000;
+
+ public static void EnableMinimizeButton(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
+ }
+
+ public static void EnableMaximizeButton(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX);
+ }
+
+ public static void ShowMinimizeAndMaximizeButtons(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
+ }
+
+ public static void ShowAllButtons(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_SYSMENU);
+ }
+
+ public static void HideMinimizeAndMaximizeButtons(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
+ }
+
+ public static void DisableMinimizeButton(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MINIMIZEBOX);
+ }
+
+ public static void DisableMaximizeButton(IntPtr hWnd)
+ {
+ _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
+ }
+
+ public void SetResizeMode(IntPtr hWnd, int value)
+ {
+ switch (value)
+ {
+ case IDesktopPlatformService.ResizeMode_NoResize:
+ _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
+ _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MINIMIZE, MF_BYCOMMAND);
+ HideMinimizeAndMaximizeButtons(hWnd);
+ break;
+ case IDesktopPlatformService.ResizeMode_CanMinimize:
+ _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
+ DisableMaximizeButton(hWnd);
+ break;
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
index 8a35734ad..be88c0796 100644
--- a/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
+++ b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
@@ -1,100 +1,22 @@
-using System.Application.Models;
-using System.Collections.Generic;
+using Microsoft.Win32;
+using Microsoft.Win32.TaskScheduler;
+using System.Application.Models;
+using System.Application.UI;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
-using System.Runtime.InteropServices;
+using System.Reflection;
using System.Runtime.Versioning;
namespace System.Application.Services.Implementation
{
[SupportedOSPlatform("Windows")]
- internal sealed class WindowsDesktopPlatformServiceImpl : IDesktopPlatformService
+ internal sealed partial class WindowsDesktopPlatformServiceImpl : IDesktopPlatformService
{
const string TAG = "WindowsDesktopPlatformS";
-
- #region 窗口右上角的三个按钮(最小化,最大化,关闭)
-
- // https://stackoverflow.com/questions/339620/how-do-i-remove-minimize-and-maximize-from-a-resizable-window-in-wpf
- // https://blog.magnusmontin.net/2014/11/30/disabling-or-hiding-the-minimize-maximize-or-close-button-of-a-wpf-window/
-
- public const int MF_BYCOMMAND = 0x00000000;
- public const int SC_CLOSE = 0xF060;
- public const int SC_MINIMIZE = 0xF020;
- public const int SC_MAXIMIZE = 0xF030;
-
- [DllImport("user32.dll")]
- public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
-
- [DllImport("user32.dll")]
- public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
-
- public const int GWL_STYLE = -16,
- WS_MAXIMIZEBOX = 0x10000,
- WS_MINIMIZEBOX = 0x20000;
-
- [DllImport("user32.dll")]
- public extern static int GetWindowLong(IntPtr hwnd, int index);
-
- [DllImport("user32.dll")]
- public extern static int SetWindowLong(IntPtr hwnd, int index, int value);
-
- public const int WS_SYSMENU = 0x80000;
-
- public static void EnableMinimizeButton(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
- }
-
- public static void EnableMaximizeButton(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX);
- }
-
- public static void ShowMinimizeAndMaximizeButtons(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
- }
-
- public static void ShowAllButtons(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_SYSMENU);
- }
-
- public static void HideMinimizeAndMaximizeButtons(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
- }
-
- public static void DisableMinimizeButton(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MINIMIZEBOX);
- }
-
- public static void DisableMaximizeButton(IntPtr hWnd)
- {
- _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
- }
-
- public void SetResizeMode(IntPtr hWnd, int value)
- {
- switch (value)
- {
- case IDesktopPlatformService.ResizeMode_NoResize:
- _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
- _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MINIMIZE, MF_BYCOMMAND);
- HideMinimizeAndMaximizeButtons(hWnd);
- break;
- case IDesktopPlatformService.ResizeMode_CanMinimize:
- _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
- DisableMaximizeButton(hWnd);
- break;
- }
- }
-
- #endregion
+ const string SteamRegistryPath = @"SOFTWARE\Valve\Steam";
public string GetCommandLineArgs(Process process)
{
@@ -138,5 +60,55 @@ namespace System.Application.Services.Implementation
return null;
}
}
+
+ public void SetBootAutoStart(bool isAutoStart, string name)
+ {
+ // 开机启动使用 taskschd.msc 实现
+ try
+ {
+ if (isAutoStart)
+ {
+ using var td = TaskService.Instance.NewTask();
+ td.RegistrationInfo.Description = name + " System Boot Run";
+ td.Settings.Priority = ProcessPriorityClass.Normal;
+ td.Settings.ExecutionTimeLimit = new TimeSpan(0);
+ td.Settings.AllowHardTerminate = false;
+ td.Settings.StopIfGoingOnBatteries = false;
+ td.Settings.DisallowStartIfOnBatteries = false;
+ td.Triggers.Add(new LogonTrigger());
+ td.Actions.Add(new ExecAction(AppHelper.ProgramName, "-minimized", Path.GetDirectoryName(Assembly.GetCallingAssembly().Location)));
+ if (IsAdministrator)
+ td.Principal.RunLevel = TaskRunLevel.Highest;
+ TaskService.Instance.RootFolder.RegisterTaskDefinition(name, td);
+ }
+ else
+ {
+ TaskService.Instance.RootFolder.DeleteTask(name);
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(TAG, e,
+ "SetBootAutoStart Fail, isAutoStart: {0}, name: {1}.", isAutoStart, name);
+ }
+ }
+
+ static string? GetFullPath(string s)
+ {
+ if (!string.IsNullOrWhiteSpace(s) && File.Exists(s))
+ {
+ return Path.GetFullPath(s);
+ }
+ return null;
+ }
+
+ public string? GetSteamDirPath()
+ => GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamPath"));
+
+ public string? GetSteamProgramPath()
+ => GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamExe"));
+
+ public string GetLastSteamLoginUserName()
+ => Registry.CurrentUser.Read(SteamRegistryPath, "AutoLoginUser");
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj b/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj
index cb8fbbd33..0c94076ce 100644
--- a/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj
+++ b/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj
@@ -14,9 +14,12 @@
+
+
+
diff --git a/System.Application.SteamTools.Client.Desktop/Models/ProxyDomain.cs b/System.Application.SteamTools.Client.Desktop/Models/ProxyDomain.cs
new file mode 100644
index 000000000..b9d74d76e
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop/Models/ProxyDomain.cs
@@ -0,0 +1,119 @@
+using MessagePack;
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace System.Application.Models
+{
+ [MessagePackObject(keyAsPropertyName: true)]
+ public class ProxyDomain
+ {
+ ///
+ /// 显示在UI上的名称
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// 代理域名合集
+ ///
+ public IReadOnlyCollection? Domains { get; set; }
+
+ ///
+ /// 端口
+ ///
+ public int Port { get; set; } = 443;
+
+ ///
+ /// 转发域名
+ ///
+ public string? ToDomain { get; set; }
+
+ ///
+ /// 转发域名IP
+ ///
+ public string? ProxyIPAddres { get; set; }
+
+ ///
+ /// 伪装的ServerName
+ ///
+ public string? ServerName { get; set; }
+
+ ///
+ /// 启用该域名代理
+ ///
+ public bool IsEnable { get; set; }
+
+ ///
+ /// 启用重定向
+ ///
+ public bool IsRedirect { get; set; }
+
+ public IReadOnlyCollection? Hosts { get; set; }
+
+ public DomainTag DomainTag { get; set; }
+ }
+
+ [TypeConverter(typeof(EnumDescriptionTypeConverter))]
+ public enum DomainTag : byte
+ {
+ [Description("steam社区")]
+ SteamCommunity = 0,
+
+ [Description("steam商店")]
+ SteamStore = 1,
+
+ [Description("steam部分图片修复")]
+ SteamImage = 2,
+
+ [Description("steam好友服务")]
+ SteamChat = 3,
+
+ [Description("Discord语音")]
+ Discord = 4,
+
+ [Description("Twitch直播")]
+ Twitch = 5,
+
+ [Description("Origin下载(Akamai)")]
+ OriginGameDownload = 6,
+
+ [Description("GOG.COM")]
+ GOG = 7,
+
+ [Description("Google(Recaptcha)")]
+ GoogleCode = 8,
+
+ [Description("Github图片及资源修复")]
+ GithubContent = 9,
+
+ [Description("Pixiv")]
+ Pixiv = 10,
+
+ [Description("Discord更新下载")]
+ DiscordNet = 11,
+
+ [Description("Uplay更新防劫持")]
+ UplayUpdate = 12,
+
+ [Description("Twitch聊天")]
+ TwitchChat = 13,
+
+ [Description("Github Gist")]
+ GithubGist = 14,
+
+ [Description("Pixiv图片")]
+ PixivImage = 15,
+
+ [Description("steam图片上传(聊天\\截图)")]
+ SteamImageUpload = 16,
+
+ [Description("steam更新")]
+ SteamMeidia = 17,
+ }
+
+#if DEBUG
+
+ [Obsolete("use ProxyDomain", true)]
+ public class ProxyDomainModel { }
+
+#endif
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/Models/ProxyScript.cs b/System.Application.SteamTools.Client.Desktop/Models/ProxyScript.cs
new file mode 100644
index 000000000..a7fa6db5f
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop/Models/ProxyScript.cs
@@ -0,0 +1,128 @@
+using MessagePack;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace System.Application.Models
+{
+ [MessagePackObject(keyAsPropertyName: true)]
+ public class ProxyScript
+ {
+ ///
+ /// 脚本文件路径
+ ///
+ public string? FilePath { get; set; }
+
+ ///
+ /// 脚本文件名称
+ ///
+ public string? FileName { get; set; }
+
+ ///
+ /// name
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// namespace
+ ///
+ public string[]? NameSpace { get; set; }
+
+ ///
+ /// Version
+ ///
+ public string? Version { get; set; }
+
+ public string? HomepageURL { get; set; }
+
+ public string? SupportURL { get; set; }
+
+ public string? DownloadURL { get; set; }
+
+ public string? UpdateURL { get; set; }
+
+ ///
+ /// description
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// author
+ ///
+ public string? Author { get; set; }
+
+ ///
+ /// author
+ ///
+ public string[]? Match { get; set; }
+
+ ///
+ /// include
+ ///
+ public string[]? Include { get; set; }
+
+ ///
+ /// exclude
+ ///
+ public string[]? Exclude { get; set; }
+
+ public string[]? Grant { get; set; }
+
+ public string[]? Require { get; set; }
+
+ public bool Enable { get; set; }
+
+ public string? Content { get; set; }
+
+ const string DescRegex = @"(?<={0})[\s\S]*?(?=\n)";
+
+ public static bool TryParse(string path, [NotNullWhen(true)] out ProxyScript? proxyScript)
+ {
+ var content = File.ReadAllText(path);
+ if (!string.IsNullOrEmpty(content))
+ {
+ var userScript = content.Substring("==UserScript==", "==/UserScript==");
+ if (!string.IsNullOrEmpty(userScript))
+ {
+ var script = new ProxyScript
+ {
+ FilePath = path,
+ Content = RemoveComment(content.Replace("", "<\\/script>")).Replace("\t", ""),
+ //Content = content.Replace("", "<\\/script>").Replace(" ", "").Replace("\r", "").Replace("\n", "").Replace("\t", ""),
+ FileName = Path.GetFileName(path),
+ Name = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(Name)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ NameSpace = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(NameSpace)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray(),
+ Version = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(Version)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ Description = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(Description)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ Author = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(Author)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ HomepageURL = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(HomepageURL)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ SupportURL = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(SupportURL)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ DownloadURL = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(DownloadURL)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ UpdateURL = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(UpdateURL)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true),
+ Exclude = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(Exclude)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray(),
+ Grant = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(Grant)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray(),
+ Require = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(Require)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray()
+ };
+ var matchs = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(Match)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray();
+ var Includes = Regex.Matches(userScript, string.Format(DescRegex, $"@{nameof(Include)}"), RegexOptions.IgnoreCase).GetValues(s => s.Success == true).ToArray();
+ script.Match = matchs.Length == 0 ? Includes : matchs;
+ var enable = Regex.Match(userScript, string.Format(DescRegex, $"@{nameof(Enable)}"), RegexOptions.IgnoreCase).GetValue(s => s.Success == true);
+
+ script.Enable = bool.TryParse(enable, out var e) && e;
+ proxyScript = script;
+ return true;
+ }
+ }
+ proxyScript = null;
+ return false;
+ }
+
+ static string RemoveComment(string str)
+ {
+ var r = Regex.Replace(str, "^//.*", "", RegexOptions.Multiline);
+
+ return Regex.Replace(r, @"^\s*\n", "", RegexOptions.Multiline);
+ }
+ }
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/Models/SteamUser.cs b/System.Application.SteamTools.Client.Desktop/Models/SteamUser.cs
index f817b5d3b..26123e315 100644
--- a/System.Application.SteamTools.Client.Desktop/Models/SteamUser.cs
+++ b/System.Application.SteamTools.Client.Desktop/Models/SteamUser.cs
@@ -1,10 +1,11 @@
-using System.Xml.Serialization;
+using System.Application.Models;
+using System.Xml.Serialization;
using static System.Application.SteamApiUrls;
namespace System.Application.Models
{
[XmlRoot("profile")]
- public class SteamUser
+ public class SteamUser : ISteamUserAvatar
{
public SteamUser()
{
@@ -15,11 +16,11 @@ namespace System.Application.Models
OriginVdfString = vdfstring;
}
- public string SteamId3 { get; set; }
+ public string? SteamId3 { get; set; }
public long SteamId3_Int => (SteamId64 >> 0) & 0xFFFFFFFF;
- public string SteamId32 { get; set; }
+ public string? SteamId32 { get; set; }
public long SteamId32_Int { get; set; }
@@ -35,9 +36,9 @@ namespace System.Application.Models
/// 在线状态
///
[XmlElement("onlineState")]
- public string OnlineState { get; set; }
+ public string? OnlineState { get; set; }
- public string IPCountry { get; set; }
+ public string? IPCountry { get; set; }
///
/// 公开状态
@@ -45,46 +46,40 @@ namespace System.Application.Models
/// public
///
[XmlElement("privacyState")]
- public string PrivacyState { get; set; }
+ public string? PrivacyState { get; set; }
- ///
- /// 头像小图标
- ///
[XmlElement("avatarIcon")]
- public string AvatarIcon { get; set; }
+ [Obsolete("use GetAvatarIcon()", true)]
+ public string? AvatarIcon { get; set; }
- ///
- /// 头像中等图片链接
- ///
[XmlElement("avatarMedium")]
- public string AvatarMedium { get; set; } = "/Resources/Asstes/avater.jpg";
+ [Obsolete("use GetAvatarMedium()", true)]
+ public string? AvatarMedium { get; set; } /*= "/Resources/Asstes/avater.jpg";*/
- ///
- /// 头像大图链接
- ///
[XmlElement("avatarFull")]
- public string AvatarFull { get; set; }
+ [Obsolete("use GetAvatarFull()", true)]
+ public string? AvatarFull { get; set; }
///
/// 昵称
///
[XmlElement("steamID")]
- public string SteamID { get; set; }
+ public string? SteamID { get; set; }
///
/// 昵称
///
- public string SteamNickName => string.IsNullOrEmpty(SteamID) ? PersonaName : SteamID;
+ public string? SteamNickName => string.IsNullOrEmpty(SteamID) ? PersonaName : SteamID;
///
/// 从 Valve Data File 读取到的用户名
///
- public string PersonaName { get; set; }
+ public string? PersonaName { get; set; }
///
/// 用户名
///
- public string AccountName { get; set; }
+ public string? AccountName { get; set; }
///
/// 是否记住密码
@@ -94,7 +89,7 @@ namespace System.Application.Models
///
/// 密码
///
- public string PassWord { get; set; }
+ public string? PassWord { get; set; }
///
/// 最后登录时间戳
@@ -124,24 +119,77 @@ namespace System.Application.Models
///
/// 备注
///
- public string Remark { get; set; }
+ public string? Remark { get; set; }
///
- /// 来源VDF字符串
+ /// 来源 Valve Data File 字符串
///
- public string OriginVdfString { get; set; }
+ public string? OriginVdfString { get; set; }
///
- /// 导出VDF配置字符串
+ /// 导出 Valve Data File 配置字符串
///
public string CurrentVdfString =>
- "\"" + SteamId64 + "\"\n{\n" +
- "\t\t\"AccountName\"\t\t\"" + AccountName + "\"\n" +
- "\t\t\"PersonaName\"\t\t\"" + PersonaName + "\"\n" +
- "\t\t\"RememberPassword\"\t\t\"" + Convert.ToByte(RememberPassword) + "\"\n" +
- "\t\t\"MostRecent\"\t\t\"" + Convert.ToByte(MostRecent) + "\"\n" +
- "\t\t\"WantsOfflineMode\"\t\t\"" + Convert.ToByte(WantsOfflineMode) + "\"\n" +
- "\t\t\"SkipOfflineModeWarning\"\t\t\"" + Convert.ToByte(SkipOfflineModeWarning) + "\"\n" +
- "\t\t\"Timestamp\"\t\t\"" + Timestamp + "\"\n}";
+ "\"" + SteamId64 + "\"\n{\n" +
+ "\t\t\"AccountName\"\t\t\"" + AccountName + "\"\n" +
+ "\t\t\"PersonaName\"\t\t\"" + PersonaName + "\"\n" +
+ "\t\t\"RememberPassword\"\t\t\"" + Convert.ToByte(RememberPassword) + "\"\n" +
+ "\t\t\"MostRecent\"\t\t\"" + Convert.ToByte(MostRecent) + "\"\n" +
+ "\t\t\"WantsOfflineMode\"\t\t\"" + Convert.ToByte(WantsOfflineMode) + "\"\n" +
+ "\t\t\"SkipOfflineModeWarning\"\t\t\"" + Convert.ToByte(SkipOfflineModeWarning) + "\"\n" +
+ "\t\t\"Timestamp\"\t\t\"" + Timestamp + "\"\n}";
+ }
+
+ internal interface ISteamUserAvatar
+ {
+ public const string DefaultAvatar = "/Resources/Asstes/avater.jpg";
+
+ ///
+ /// 头像小图标
+ ///
+ string? AvatarIcon { get; set; }
+
+ ///
+ /// 头像中等图片链接
+ ///
+ string? AvatarMedium { get; set; }
+
+ ///
+ /// 头像大图链接
+ ///
+ string? AvatarFull { get; set; }
+ }
+}
+
+namespace System
+{
+ public static class SteamUserAvatarExtensions
+ {
+ static ISteamUserAvatar GetAvatar(this SteamUser user)
+ {
+ ISteamUserAvatar user_ = user;
+ return user_;
+ }
+
+ ///
+ /// 获取头像小图标
+ ///
+ ///
+ ///
+ public static string GetAvatarIcon(this SteamUser user) => user.GetAvatar().AvatarIcon ?? ISteamUserAvatar.DefaultAvatar;
+
+ ///
+ /// 获取头像中等图片链接
+ ///
+ ///
+ ///
+ public static string GetAvatarMedium(this SteamUser user) => user.GetAvatar().AvatarMedium ?? ISteamUserAvatar.DefaultAvatar;
+
+ ///
+ /// 获取头像大图链接
+ ///
+ ///
+ ///
+ public static string GetAvatarFull(this SteamUser user) => user.GetAvatar().AvatarFull ?? ISteamUserAvatar.DefaultAvatar;
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/Proxy/DnsResolution.cs b/System.Application.SteamTools.Client.Desktop/Proxy/DnsResolution.cs
new file mode 100644
index 000000000..46f84aba3
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop/Proxy/DnsResolution.cs
@@ -0,0 +1,84 @@
+using DnsClient;
+using DnsClient.Protocol;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+
+namespace System.Application.Proxy
+{
+ ///
+ /// DNS 解析
+ ///
+ public static class DnsResolution
+ {
+ public static IPAddress ResolutionDomainIp(string url)
+ {
+ if (!string.IsNullOrEmpty(url))
+ {
+ var client = new LookupClient();
+ var result = client.Query(url, QueryType.A);
+ if (result.Answers.Count > 0)
+ {
+ var address = result.Answers.ARecords().FirstOrDefault()?.Address;
+ if (address != null) return address;
+ }
+ }
+ return IPAddress.Any;
+ }
+
+ public static int PingDomain(string url)
+ {
+ if (!string.IsNullOrEmpty(url))
+ {
+ var client = new LookupClient();
+ var result = client.Query(url, QueryType.A);
+ if (result.Answers.Count > 0)
+ {
+ var value = result.Answers.ARecords().FirstOrDefault()?.TimeToLive;
+ if (value.HasValue) return value.Value;
+ }
+ }
+ return 0;
+ }
+
+ public static IEnumerable GetPingDomainData(string url)
+ {
+ if (!string.IsNullOrEmpty(url))
+ {
+ var client = new LookupClient();
+ var result = client.Query(url, QueryType.A);
+ if (result.Answers.Count > 0)
+ {
+ return result.Answers.ARecords();
+ }
+ }
+ return new List();
+ }
+
+ public static IPAddress ResolutionDomainIpByGoogleDns(string url)
+ {
+ if (!string.IsNullOrEmpty(url))
+ {
+ var client = new LookupClient();
+ var dns = new IPAddress[2] { IPAddress.Parse("8.8.8.8"), IPAddress.Parse("8.8.8.4") };
+ var result = client.Query(new DnsQuestion(url, QueryType.A), new DnsQueryAndServerOptions(dns));
+ if (result.Answers.Count > 0)
+ {
+ var address = result.Answers.ARecords().FirstOrDefault()?.Address;
+ if (address != null) return address;
+ }
+ }
+ return IPAddress.Any;
+ }
+
+ public static string GetHostByIPAddress(string ip)
+ {
+ if (!string.IsNullOrEmpty(ip))
+ {
+ var result = Dns.GetHostEntry(IPAddress.Parse(ip)).HostName;
+ return result;
+ }
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs
index a05cbdf11..eccfb9f9f 100644
--- a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs
+++ b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs
@@ -83,9 +83,20 @@ namespace Microsoft.Extensions.DependencyInjection
///
public static IServiceCollection AddHttpService(this IServiceCollection services)
{
- services.AddHttpClient();
+ services.AddHttpClient(); // 添加 System.Net.Http.HttpClient / HttpClientFactory
services.AddSingleton();
return services;
}
+
+ ///
+ /// 添加 Steam 相关助手、工具类服务
+ ///
+ ///
+ ///
+ public static IServiceCollection AddSteamService(this IServiceCollection services)
+ {
+ services.AddSingleton();
+ return services;
+ }
}
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/Services/IDesktopPlatformService.cs b/System.Application.SteamTools.Client.Desktop/Services/IDesktopPlatformService.cs
index f85526730..f32469e77 100644
--- a/System.Application.SteamTools.Client.Desktop/Services/IDesktopPlatformService.cs
+++ b/System.Application.SteamTools.Client.Desktop/Services/IDesktopPlatformService.cs
@@ -99,6 +99,26 @@ namespace System.Application.Services
///
string? GetFileName(TextReaderProvider provider);
+ ///
+ /// 设置开机自启动
+ ///
+ /// 开启、关闭
+ ///
+ void SetBootAutoStart(bool isAutoStart, string name);
+
+ #region Steam
+
+ ///
+ string? GetSteamDirPath();
+
+ ///
+ string? GetSteamProgramPath();
+
+ ///
+ string GetLastSteamLoginUserName();
+
+ #endregion
+
public const ResizeMode ResizeMode_NoResize = 0;
public const ResizeMode ResizeMode_CanMinimize = 1;
public const ResizeMode ResizeMode_CanResize = 2;
diff --git a/System.Application.SteamTools.Client.Desktop/Services/ISteamService.cs b/System.Application.SteamTools.Client.Desktop/Services/ISteamService.cs
index 40eea32d7..a6567f32c 100644
--- a/System.Application.SteamTools.Client.Desktop/Services/ISteamService.cs
+++ b/System.Application.SteamTools.Client.Desktop/Services/ISteamService.cs
@@ -1,5 +1,11 @@
-namespace System.Application.Services
+using System.Application.Models;
+using System.Collections.Generic;
+
+namespace System.Application.Services
{
+ ///
+ /// Steam 相关助手、工具类服务
+ ///
public interface ISteamService
{
public static ISteamService Instance => DI.Get();
@@ -7,12 +13,12 @@
///
/// Steam 文件夹目录
///
- string SteamDirPath { get; }
+ string? SteamDirPath { get; }
///
/// Steam 主程序文件目录
///
- string SteamProgramPath { get; }
+ string? SteamProgramPath { get; }
///
/// 结束 Steam 进程
@@ -30,6 +36,29 @@
///
///
string GetLastLoginUserName();
+
+ ///
+ /// 获取所有记住登陆 Steam 用户信息
+ ///
+ ///
+ List GetRememberUserList();
+
+ List? GetAppListJson(string filePath);
+
+ bool UpdateAppListJson(List apps, string filePath);
+
+ bool UpdateAppListJson(string appsJsonStr, string filePath);
+
+ void DeleteLocalUserData(SteamUser user);
+
+ void UpdateLocalUserData(SteamUser user);
+
+#if DEBUG
+
+ [Obsolete("use AppHelper.SetBootAutoStart", true)]
+ void SetWindowsStartupAutoRun(bool IsAutoRun, string Name = "Steam++");
+
+#endif
}
#if DEBUG
@@ -37,9 +66,26 @@
[Obsolete("use ISteamService", true)]
public class SteamToolService
{
-
[Obsolete("use SteamDirPath", true)]
public string? SteamPath { get; }
+
+ [Obsolete("use SteamProgramPath", true)]
+ public string? SteamExePath { get; }
+
+ [Obsolete("use ISteamService.DeleteLocalUserData", true)]
+ public void DeleteSteamLocalUserData(SteamUser user)
+ {
+ }
+
+ [Obsolete("use ISteamService.UpdateLocalUserData", true)]
+ public void UpdateSteamLocalUserData(SteamUser user)
+ {
+ }
+ }
+
+ [Obsolete("use ISteamService", true)]
+ public class SteamService
+ {
}
#endif
diff --git a/System.Application.SteamTools.Client.Desktop/Services/ISteamworksLocalApiService.cs b/System.Application.SteamTools.Client.Desktop/Services/ISteamworksLocalApiService.cs
new file mode 100644
index 000000000..523737cdc
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop/Services/ISteamworksLocalApiService.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace System.Application.Services
+{
+ public interface ISteamworksLocalApiService
+ {
+ //Client SteamClient { get; }
+ }
+
+
+#if DEBUG
+
+ [Obsolete("use ISteamworksLocalApiService", true)]
+ public class SteamworksApiService
+ {
+
+ }
+
+#endif
+}
diff --git a/System.Application.SteamTools.Client.Desktop/Services/Implementation/HostsFileServiceImpl.cs b/System.Application.SteamTools.Client.Desktop/Services/Implementation/HostsFileServiceImpl.cs
index ebf2553a9..955e3f798 100644
--- a/System.Application.SteamTools.Client.Desktop/Services/Implementation/HostsFileServiceImpl.cs
+++ b/System.Application.SteamTools.Client.Desktop/Services/Implementation/HostsFileServiceImpl.cs
@@ -86,7 +86,7 @@ namespace System.Application.Services.Implementation
try
{
- dataLines.Add($"{ip} {domain} {Constants.HOST_TAG}");
+ dataLines.Add($"{ip} {domain} {Constants.CERTIFICATE_HOST_TAG}");
File.WriteAllLines(s.HostsFilePath, dataLines, Encoding.UTF8);
//File.SetAttributes(HostsPath, FileAttributes.ReadOnly);
@@ -145,7 +145,7 @@ namespace System.Application.Services.Implementation
foreach (var (ip, domain) in hosts)
{
- dataLines.Add($"{ip} {domain} {Constants.HOST_TAG}");
+ dataLines.Add($"{ip} {domain} {Constants.CERTIFICATE_HOST_TAG}");
}
try
{
@@ -232,7 +232,7 @@ namespace System.Application.Services.Implementation
{
if (!temp[0].StartsWith("#"))
{
- return !temp.Contains(Constants.HOST_TAG);
+ return !temp.Contains(Constants.CERTIFICATE_HOST_TAG);
}
}
return true;
diff --git a/System.Application.SteamTools.Client.Desktop/Services/Implementation/SteamServiceImpl.cs b/System.Application.SteamTools.Client.Desktop/Services/Implementation/SteamServiceImpl.cs
new file mode 100644
index 000000000..f1b88fe5f
--- /dev/null
+++ b/System.Application.SteamTools.Client.Desktop/Services/Implementation/SteamServiceImpl.cs
@@ -0,0 +1,206 @@
+using System.Application.Models;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace System.Application.Services.Implementation
+{
+ internal sealed class SteamServiceImpl : ISteamService
+ {
+ const string TAG = "SteamS";
+ ///
+ ///
+ /// -
+ /// Windows:~\Steam\config\loginusers.vdf
+ ///
+ /// -
+ /// Linux:~/.steam/steam/config/loginusers.vdf
+ ///
+ /// -
+ /// Mac:~/Library/Application Support/Steam/config/loginusers.vdf
+ ///
+ ///
+ ///
+ const string UserVdfPath = @"\config\loginusers.vdf";
+ const string UserDataDirectory = @"\userdata";
+ readonly IDesktopPlatformService platformService;
+ readonly Lazy mSteamDirPath;
+ readonly Lazy mSteamProgramPath;
+ readonly string[] steamProcess = new[] { "steam", "steamservice", "steamwebhelper" };
+
+ public SteamServiceImpl(IDesktopPlatformService platformService)
+ {
+ this.platformService = platformService;
+ mSteamDirPath = new Lazy(platformService.GetSteamDirPath);
+ mSteamProgramPath = new Lazy(platformService.GetSteamProgramPath);
+ }
+
+ public string? SteamDirPath => mSteamDirPath.Value;
+
+ public string? SteamProgramPath => mSteamProgramPath.Value;
+
+ public void KillSteamProcess()
+ {
+ var processes = Process.GetProcesses();
+ foreach (var p in processes)
+ {
+ if (steamProcess.Contains(p.ProcessName, StringComparer.OrdinalIgnoreCase))
+ {
+ p.Kill();
+ }
+ }
+ }
+
+ public void StartSteam(string arguments)
+ {
+ if (!string.IsNullOrEmpty(SteamProgramPath))
+ {
+ Process.Start(SteamProgramPath, arguments);
+ }
+ }
+
+ public string GetLastLoginUserName() => platformService.GetLastSteamLoginUserName();
+
+ public List GetRememberUserList()
+ {
+ var users = new List();
+ try
+ {
+ if (File.Exists(SteamDirPath + UserVdfPath))
+ {
+ // 注意:动态类型在移动端受限,且运行时可能抛出异常
+ dynamic v = VdfHelper.Read(SteamDirPath + UserVdfPath);
+ foreach (var item in v.Value)
+ {
+ try
+ {
+ var i = item.Value;
+ var user = new SteamUser(item.ToString())
+ {
+ SteamId64 = Convert.ToInt64(item.Key.ToString()),
+ AccountName = i.AccountName?.ToString(),
+ SteamID = i.PersonaName?.ToString(),
+ PersonaName = i.PersonaName?.ToString(),
+ RememberPassword = Convert.ToBoolean(Convert.ToInt64(i.RememberPassword?.ToString())),
+ Timestamp = Convert.ToInt64(i.Timestamp?.ToString())
+ };
+ user.LastLoginTime = user.Timestamp.ToDateTime();
+
+ // 老版本 Steam 数据 小写 mostrecent 支持
+ user.MostRecent = i.mostrecent != null ?
+ Convert.ToBoolean(Convert.ToByte(i.mostrecent.ToString())) :
+ Convert.ToBoolean(Convert.ToByte(i.MostRecent.ToString()));
+
+ user.WantsOfflineMode = i.WantsOfflineMode != null ?
+ Convert.ToBoolean(Convert.ToByte(i.WantsOfflineMode.ToString())) : false;
+
+ // 因为警告这个东西应该都不需要所以直接默认跳过好了
+ user.SkipOfflineModeWarning = true;
+ //user.SkipOfflineModeWarning = i.SkipOfflineModeWarning != null ?
+ // Convert.ToBoolean(Convert.ToByte(i.SkipOfflineModeWarning.ToString())) : false;
+
+ users.Add(user);
+ }
+ catch (Exception e)
+ {
+ Log.Error(TAG, e, "GetRememberUserList Fail(0).");
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(TAG, e, "GetRememberUserList Fail(1).");
+ }
+ return users;
+ }
+
+ public List? GetAppListJson(string filePath)
+ {
+ if (!File.Exists(filePath))
+ {
+ return null;
+ }
+
+ var lastChanged = File.GetLastWriteTime(filePath);
+ int daysSinceChanged = (int)(DateTime.Now - lastChanged).TotalDays;
+ if (daysSinceChanged > 10)
+ {
+ return null;
+ }
+
+ string json = File.ReadAllText(filePath, Encoding.UTF8);
+ if (string.IsNullOrEmpty(json))
+ {
+ return null;
+ }
+
+ var apps = Serializable.DJSON(json);
+ return apps?.AppList?.Apps;
+ }
+
+ public bool UpdateAppListJson(List apps, string filePath)
+ {
+ try
+ {
+ var json_str = Serializable.SJSON(apps);
+ File.WriteAllText(filePath, json_str, Encoding.UTF8);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(TAG, ex, "UpdateAppListJson(obj) Fail.");
+ return false;
+ }
+ }
+
+ public bool UpdateAppListJson(string appsJsonStr, string filePath)
+ {
+ try
+ {
+ File.WriteAllText(filePath, appsJsonStr, Encoding.UTF8);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(TAG, ex, "UpdateAppListJson(str) Fail.");
+ return false;
+ }
+ }
+
+ public void DeleteLocalUserData(SteamUser user)
+ {
+ VdfHelper.DeleteValueByKey(SteamDirPath + UserVdfPath, user.SteamId64.ToString());
+ var temp = SteamDirPath + Path.Combine(UserDataDirectory, user.SteamId3_Int.ToString());
+ if (Directory.Exists(temp))
+ {
+ Directory.Delete(temp, true);
+ }
+ }
+
+ public void UpdateLocalUserData(SteamUser user)
+ {
+ var originVdfStr = user.OriginVdfString;
+ VdfHelper.UpdateValueByReplace(
+ SteamDirPath + UserVdfPath,
+ originVdfStr.ThrowIsNull(nameof(originVdfStr)),
+ user.CurrentVdfString);
+ }
+
+#if DEBUG
+
+ [Obsolete("use AppHelper.SetBootAutoStart", true)]
+ public void SetWindowsStartupAutoRun(bool IsAutoRun, string Name)
+ => throw new NotImplementedException();
+
+ [Obsolete("use SteamDirPath", true)]
+ public string? SteamPath { get; }
+
+ [Obsolete("use SteamProgramPath", true)]
+ public string? SteamExePath { get; }
+
+#endif
+ }
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/SteamApiUrls.cs b/System.Application.SteamTools.Client.Desktop/SteamApiUrls.cs
index 61e74f00e..fe9044d3d 100644
--- a/System.Application.SteamTools.Client.Desktop/SteamApiUrls.cs
+++ b/System.Application.SteamTools.Client.Desktop/SteamApiUrls.cs
@@ -33,4 +33,25 @@
public const string STEAMCN_USERINFO_XML_URL = "https://my.steamchina.com/profiles/76561198289531723?xml=1";
}
+
+#if DEBUG
+
+ [Obsolete("use SteamApiUrls / System.Application.SteamTools/Constants.cs", true)]
+ public class Const
+ {
+ [Obsolete("use Constants.APP_LIST_FILE", true)]
+ public const string APP_LIST_FILE = "apps.json";
+ [Obsolete("use Constants.AUTHDATA_FILE", true)]
+ public const string AUTHDATA_FILE = "authenticators.dat";
+ [Obsolete("use System.Application.Services.IConfigFileService", true)]
+ public const string SETTINGS_FILE = "settings.json";
+ [Obsolete("use Constants.SCRIPT_DIR", true)]
+ public const string SCRIPT_DIR = "scripts";
+ [Obsolete("use Constants.LOGS_DIR", true)]
+ public const string LOG_DIR = "log";
+ [Obsolete("use Constants.CERTIFICATE_HOST_TAG", true)]
+ public const string HOST_TAG = "#Steam++";
+ }
+
+#endif
}
\ No newline at end of file
diff --git a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj
index 49fdef0e5..0e0cb7e86 100644
--- a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj
+++ b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj
@@ -12,14 +12,17 @@
+
+
+
diff --git a/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs
index ef426578b..be2911e45 100644
--- a/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs
+++ b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NLog.Extensions.Logging;
+using System.Application.Services;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -33,6 +34,13 @@ namespace System.Application.UI
///
public static string ProgramName { get; }
+ ///
+ public static void SetBootAutoStart(bool isAutoStart)
+ {
+ var s = DI.Get();
+ s.SetBootAutoStart(isAutoStart, Constants.HARDCODED_APP_NAME);
+ }
+
#region Logger
const LogLevel DefaultLoggerMinLevel = ThisAssembly.Debuggable ? LogLevel.Debug : LogLevel.Error;
@@ -97,7 +105,7 @@ namespace System.Application.UI
///
public static bool EnableLogger
{
- get => LoggerMinLevel < LogLevel.None;
+ get => LoggerMinLevel > LogLevel.None;
set
{
LoggerMinLevel = value ? DefaultLoggerMinLevel : LogLevel.None;
diff --git a/System.Application.SteamTools/Constants.cs b/System.Application.SteamTools/Constants.cs
index 9e391a173..b52a853f4 100644
--- a/System.Application.SteamTools/Constants.cs
+++ b/System.Application.SteamTools/Constants.cs
@@ -1,11 +1,20 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace System.Application
+namespace System.Application
{
public static class Constants
{
- public const string HOST_TAG = "#Steam++";
+ ///
+ /// 当前应用程序的硬编码名称,此值不可更改!
+ ///
+ public const string HARDCODED_APP_NAME = "Steam++";
+
+ public const string CERTIFICATE_HOST_TAG = "#Steam++";
+
+ public const string APP_LIST_FILE = "apps.json";
+
+ public const string AUTHDATA_FILE = "authenticators.dat";
+
+ public const string SCRIPT_DIR = "scripts";
+
+ public const string LOGS_DIR = "logs";
}
-}
+}
\ No newline at end of file
diff --git a/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs b/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs
index 4cfda64e6..48801b82b 100644
--- a/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs
+++ b/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs
@@ -14,12 +14,12 @@ namespace System.Application
public static string GetPublicPemCertificateString(this X509Certificate2 @this)
{
StringBuilder builder = new StringBuilder();
- builder.AppendLine(Constants.HOST_TAG);
+ builder.AppendLine(Constants.CERTIFICATE_HOST_TAG);
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(
Convert.ToBase64String(@this.RawData, Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
- builder.AppendLine(Constants.HOST_TAG);
+ builder.AppendLine(Constants.CERTIFICATE_HOST_TAG);
return builder.ToString();
}
diff --git a/references/SteamAchievementManager b/references/SteamAchievementManager
index a605270e0..645029fb5 160000
--- a/references/SteamAchievementManager
+++ b/references/SteamAchievementManager
@@ -1 +1 @@
-Subproject commit a605270e02f60d78dc67e162573b76b91644d091
+Subproject commit 645029fb5a8a4324d7541f5930f4628272d20799