mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-26 20:20:14 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
451de6ca55 | ||
|
|
691fb360bb | ||
|
|
686e3987f8 | ||
|
|
79871c3bcb | ||
|
|
c1b19b4929 | ||
|
|
c564ea10eb | ||
|
|
d5006da378 |
+1
-1
Submodule references/MetroRadiance updated: 1b54d1e79e...48978b4cd7
+14
-4
@@ -13,6 +13,16 @@ Steam++只在keylol论坛与github发布,为了账号安全,请不要到其
|
||||
|
||||
## 更新内容
|
||||
|
||||
### 1.0.6
|
||||
```
|
||||
修改了用户信息获取的api为steam官方社区api(但是没有启动软件的自动代理服务的话依然加载不出头像。)
|
||||
新增启用日志记录设置项(反馈bug时一起提交方便排查问题)
|
||||
修复twitch反代聊天连接错误和直播视频无法观看
|
||||
放宽令牌同步时网络请求超时时间以降低令牌同步时提示超时概率
|
||||
修改生成的cer证书编码格式为utf8,解决火狐无法导入cer证书
|
||||
增加80端口反代,以便自动跳转http访问到https请求上
|
||||
```
|
||||
|
||||
### 1.0.5
|
||||
```
|
||||
紧急修复因为第三方steamdb api挂掉导致程序崩溃(第三方api确实还是不太靠谱,考虑之后换回steam官方api)
|
||||
@@ -149,11 +159,11 @@ SDA令牌导入不再支持导入加密文件,如果要导入加密的maFile
|
||||
> [Github](https://github.com/rmbadmin/SteamTools/releases)
|
||||
> 分流下载:
|
||||
> [hide]
|
||||
> [蓝奏云](https://wws.lanzous.com/ilYjRk5ohfg)
|
||||
> [百度云](https://pan.baidu.com/s/1n4yAlzqe6RIhHKU4vuoVGA)
|
||||
> 提取码:g7nh
|
||||
> [蓝奏云](https://wws.lanzous.com/i45yAkbbz9g)
|
||||
> [百度云](https://pan.baidu.com/s/1qRnTuIjjM2FOfTrYHZxshg)
|
||||
> 提取码:97c7
|
||||
> [/hide]
|
||||
> EXE 大小:4.85MB
|
||||
> MD5:D5FB1CD6776687DC13BC01F5C717D2C5
|
||||
> MD5:7FC035E1F38E79569597A6A6DDDF279B
|
||||
> [查毒链接](https://www.virustotal.com/gui/file/6d0a506044013d1cea7c2b4f7734f2405ad7ac6b1f5213abc68743f979acf51f/detection)
|
||||
虽然没有什么杀毒软件报毒,但是使用过程中可能遇到windows defender误报,您可以选择添加信任。
|
||||
@@ -269,6 +269,38 @@
|
||||
"OrderNumber": "",
|
||||
"PayType": 2,
|
||||
"Remark": "不是很常用,但是切换账号就很方便。谢谢啦",
|
||||
"PayTime": "2021-01-08 10:16:04"
|
||||
"PayTime": "2021-01-09 10:16:04"
|
||||
},
|
||||
{
|
||||
"Name": "**宇",
|
||||
"Amount": 5,
|
||||
"OrderNumber": "",
|
||||
"PayType": 1,
|
||||
"Remark": "",
|
||||
"PayTime": "2021-01-12 20:39:26"
|
||||
},
|
||||
{
|
||||
"Name": "Mixer",
|
||||
"Amount": 20,
|
||||
"OrderNumber": "",
|
||||
"PayType": 2,
|
||||
"Remark": "非常感谢!很好用",
|
||||
"PayTime": "2021-01-14 06:15:26"
|
||||
},
|
||||
{
|
||||
"Name": "**政",
|
||||
"Amount": 5,
|
||||
"OrderNumber": "",
|
||||
"PayType": 2,
|
||||
"Remark": "给个建议 令牌页面保持前端显示",
|
||||
"PayTime": "2021-01-14 11:07:54"
|
||||
},
|
||||
{
|
||||
"Name": "**浩",
|
||||
"Amount": 6.66,
|
||||
"OrderNumber": "",
|
||||
"PayType": 1,
|
||||
"Remark": "",
|
||||
"PayTime": "2021-01-16 09:48:57"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -198,14 +198,14 @@ namespace WinAuth
|
||||
/// </summary>
|
||||
public class Confirmation
|
||||
{
|
||||
public string Id;
|
||||
public string Key;
|
||||
public bool Offline;
|
||||
public bool IsNew;
|
||||
public string Image;
|
||||
public string Details;
|
||||
public string Traded;
|
||||
public string When;
|
||||
public string Id { get; set; }
|
||||
public string Key { get; set; }
|
||||
public bool Offline { get; set; }
|
||||
public bool IsNew { get; set; }
|
||||
public string Image { get; set; }
|
||||
public string Details { get; set; }
|
||||
public string Traded { get; set; }
|
||||
public string When { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamTool.Core.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 类名 :MD5加密<br/>
|
||||
/// 说明 :<br/>
|
||||
/// </summary>
|
||||
public static class Md5Method
|
||||
{
|
||||
/// <summary>
|
||||
/// 用MD5加密一段字符串
|
||||
/// </summary>
|
||||
/// <param name="str">字符串</param>
|
||||
/// <param name="isLower">是否小写</param>
|
||||
/// <returns>MD5串</returns>
|
||||
public static string MD5Encrypt(string str, bool isLower = false)
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
var result = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
|
||||
var strResult = BitConverter.ToString(result).Replace("-", "");
|
||||
return isLower ? strResult.ToLower() : strResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用MD5加密流
|
||||
/// </summary>
|
||||
/// <param name="myStream">流</param>
|
||||
/// <returns>str</returns>
|
||||
public static byte[] MD5Encrypt(Stream inputStream)
|
||||
{
|
||||
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
|
||||
return md5.ComputeHash(inputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用MD5加密字节数组
|
||||
/// </summary>
|
||||
/// <param name="myBytes">字节数组</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] MD5Encrypt(byte[] myBytes)
|
||||
{
|
||||
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
|
||||
return md5.ComputeHash(myBytes, 0, myBytes.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string FileMD5Encrypt(string path)
|
||||
{
|
||||
using FileStream fs = new FileStream(path, FileMode.Open);
|
||||
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
|
||||
byte[] data = provider.ComputeHash(fs);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
builder.Append(data[i].ToString("X2"));
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace SteamTool.Model.ToolModel
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public string content_type { get; set; }
|
||||
public string size { get; set; }
|
||||
public long size { get; set; }
|
||||
public string download_count { get; set; }
|
||||
public string updated_at { get; set; }
|
||||
public string browser_download_url { get; set; }
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace SteamTool.Proxy
|
||||
}
|
||||
|
||||
//没有匹配到的结果直接返回不支持,避免出现Loopback死循环内存溢出
|
||||
e.Ok($"URL : {e.HttpClient.Request.RequestUri.AbsoluteUri} {Environment.NewLine} not support proxy");
|
||||
e.Ok($"URL : {e.HttpClient.Request.RequestUri.AbsoluteUri} {Environment.NewLine}not support proxy");
|
||||
return;
|
||||
}
|
||||
public async Task OnResponse(object sender, SessionEventArgs e)
|
||||
@@ -181,12 +181,12 @@ namespace SteamTool.Proxy
|
||||
if (e.HttpClient.Request.RequestUri.AbsoluteUri.IsWildcard(host))
|
||||
{
|
||||
var doc = await e.GetResponseBodyAsString();
|
||||
if (script.Require.Length > 0)
|
||||
if (script.Require.Length > 0 || script.Grant.Length > 0)
|
||||
{
|
||||
//var headIndex = doc.LastIndexOf("</head>", StringComparison.OrdinalIgnoreCase);
|
||||
//doc = doc.Insert(headIndex, "<meta http-equiv=\"Content-Security-Policy\" content=\"default - src 'self' data: gap: https://ssl.gstatic.com 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *\">");
|
||||
var t = e.HttpClient.Response.Headers.GetFirstHeader("Content-Security-Policy");
|
||||
if (!string.IsNullOrEmpty(t.Value))
|
||||
if (!string.IsNullOrEmpty(t?.Value))
|
||||
{
|
||||
//var tt = t.Value.Split(';');
|
||||
//for (var i = 0; i < tt.Length; i++)
|
||||
@@ -261,11 +261,16 @@ namespace SteamTool.Proxy
|
||||
// 在Mono之下,只有BouncyCastle将得到支持
|
||||
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
|
||||
//proxyServer.CertificateManager.SaveFakeCertificates = true;
|
||||
|
||||
var result = proxyServer.CertificateManager.CreateRootCertificate(true);
|
||||
//if (result)
|
||||
//{
|
||||
proxyServer.CertificateManager.EnsureRootCertificate();
|
||||
if (!result)
|
||||
{
|
||||
Logger.Error("创建证书失败");
|
||||
}
|
||||
proxyServer.CertificateManager.RootCertificate.SaveCerCertificateFile(Path.Combine(AppContext.BaseDirectory, $@"{CertificateName}.Certificate.cer"));
|
||||
proxyServer.CertificateManager.EnsureRootCertificate();
|
||||
//}
|
||||
return IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate);
|
||||
}
|
||||
@@ -333,10 +338,10 @@ namespace SteamTool.Proxy
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (PortInUse(443))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//if (PortInUse(443))
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
if (IsProxyGOG) { WirtePemCertificateToGoGSteamPlugins(); }
|
||||
|
||||
#region 写入Hosts
|
||||
@@ -347,7 +352,13 @@ namespace SteamTool.Proxy
|
||||
{
|
||||
foreach (var host in proxyDomain.Hosts)
|
||||
{
|
||||
hosts.Add((IPAddress.Loopback.ToString(), host));
|
||||
if (host.Contains(" "))
|
||||
{
|
||||
var h = host.Split(' ');
|
||||
hosts.Add((h[0], h[1]));
|
||||
}
|
||||
else
|
||||
hosts.Add((IPAddress.Loopback.ToString(), host));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,31 +371,22 @@ namespace SteamTool.Proxy
|
||||
//proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
|
||||
//proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
|
||||
|
||||
//var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 443, true)
|
||||
//var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8888, true)
|
||||
//{
|
||||
// // 在所有https请求上使用自颁发的通用证书
|
||||
// // 通过不为每个启用http的域创建证书来优化性能
|
||||
// // 当代理客户端不需要证书信任时非常有用
|
||||
// //GenericCertificate = new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "genericcert.pfx"), "password")
|
||||
//};
|
||||
//当接收到连接请求时触发
|
||||
//explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelRequest;
|
||||
//explicit endpoint 是客户端知道代理存在的地方
|
||||
//因此,客户端以代理友好的方式发送请求
|
||||
//proxyServer.AddEndPoint(explicitEndPoint);
|
||||
// transparentEndPoint 对于反向代理很有用(客户端不知道代理的存在)
|
||||
// transparentEndPoint 通常需要一个网络路由器端口来转发HTTP(S)包或DNS
|
||||
// 发送数据到此endpoint
|
||||
var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true)
|
||||
proxyServer.AddEndPoint(new TransparentProxyEndPoint(IPAddress.Any, 443, true)
|
||||
{
|
||||
// 通过不启用为每个http的域创建证书来优化性能
|
||||
//GenericCertificate = proxyServer.CertificateManager.RootCertificate
|
||||
};
|
||||
proxyServer.AddEndPoint(transparentEndPoint);
|
||||
var transparentEndPoint80 = new TransparentProxyEndPoint(IPAddress.Any, 80, true)
|
||||
{
|
||||
//GenericCertificate = proxyServer.CertificateManager.RootCertificate
|
||||
};
|
||||
proxyServer.AddEndPoint(transparentEndPoint80);
|
||||
});
|
||||
proxyServer.AddEndPoint(new TransparentProxyEndPoint(IPAddress.Any, 80, true));
|
||||
proxyServer.ExceptionFunc = ((Exception exception) =>
|
||||
{
|
||||
Logger.Error(exception);
|
||||
@@ -399,6 +401,7 @@ namespace SteamTool.Proxy
|
||||
Logger.Error(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
|
||||
//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
|
||||
#endregion
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SteamTool.Proxy
|
||||
/// <summary>
|
||||
/// 代理域名合集
|
||||
/// </summary>
|
||||
public List<string> Domains { get; set; }
|
||||
public IReadOnlyCollection<string> Domains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
@@ -44,7 +44,7 @@ namespace SteamTool.Proxy
|
||||
/// </summary>
|
||||
public bool IsEnable { get; set; }
|
||||
|
||||
public IEnumerable<string> Hosts { get; set; }
|
||||
public IReadOnlyCollection<string> Hosts { get; set; }
|
||||
|
||||
public DomainTag DomainTag { get; set; }
|
||||
}
|
||||
@@ -52,14 +52,8 @@ namespace SteamTool.Proxy
|
||||
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
|
||||
public enum DomainTag : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// steam社区
|
||||
/// </summary>
|
||||
[Description("steam社区")]
|
||||
SteamCommunity = 0,
|
||||
/// <summary>
|
||||
/// steam商店
|
||||
/// </summary>
|
||||
[Description("steam商店")]
|
||||
SteamStore = 1,
|
||||
[Description("steam部分图片修复")]
|
||||
@@ -76,7 +70,7 @@ namespace SteamTool.Proxy
|
||||
GOG = 7,
|
||||
[Description("Google(Recaptcha)")]
|
||||
GoogleCode = 8,
|
||||
[Description("Github图片修复")]
|
||||
[Description("Github图片及资源修复")]
|
||||
GithubContent = 9,
|
||||
[Description("Pixiv")]
|
||||
Pixiv = 10,
|
||||
@@ -86,5 +80,9 @@ namespace SteamTool.Proxy
|
||||
UplayUpdate = 12,
|
||||
[Description("Twitch聊天")]
|
||||
TwitchChat = 13,
|
||||
[Description("Github Gist")]
|
||||
GithubGist = 14,
|
||||
[Description("Pixiv图片")]
|
||||
PixivImage = 15,
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -70,7 +70,7 @@ namespace SteamTool.Proxy.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Discord更新下载 的本地化字符串。
|
||||
/// 查找类似 Discord图片及更新下载 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string DiscordNet {
|
||||
get {
|
||||
@@ -87,6 +87,15 @@ namespace SteamTool.Proxy.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Github Gist 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string GithubGist {
|
||||
get {
|
||||
return ResourceManager.GetString("GithubGist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 GOG Galaxy 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -132,6 +141,15 @@ namespace SteamTool.Proxy.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Pixiv图片 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string PixivImgae {
|
||||
get {
|
||||
return ResourceManager.GetString("PixivImgae", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Steam好友聊天 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -121,11 +121,14 @@
|
||||
<value>Discord语音</value>
|
||||
</data>
|
||||
<data name="DiscordNet" xml:space="preserve">
|
||||
<value>Discord更新下载</value>
|
||||
<value>Discord图片及更新下载</value>
|
||||
</data>
|
||||
<data name="GithubContent" xml:space="preserve">
|
||||
<value>Github图片资源修复</value>
|
||||
</data>
|
||||
<data name="GithubGist" xml:space="preserve">
|
||||
<value>Github Gist</value>
|
||||
</data>
|
||||
<data name="GOG" xml:space="preserve">
|
||||
<value>GOG Galaxy</value>
|
||||
</data>
|
||||
@@ -141,6 +144,9 @@
|
||||
<data name="Pixiv" xml:space="preserve">
|
||||
<value>Pixiv</value>
|
||||
</data>
|
||||
<data name="PixivImgae" xml:space="preserve">
|
||||
<value>Pixiv图片</value>
|
||||
</data>
|
||||
<data name="SteamChat" xml:space="preserve">
|
||||
<value>Steam好友聊天</value>
|
||||
</data>
|
||||
|
||||
@@ -33,10 +33,10 @@ namespace SteamTools
|
||||
{
|
||||
public static App Instance => Current as App;
|
||||
|
||||
#if !NETCOREAPP
|
||||
public string ProgramName => Path.GetFileName(Environment.GetCommandLineArgs()[0]);
|
||||
#else
|
||||
#if NETCOREAPP
|
||||
public string ProgramName => Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
|
||||
#else
|
||||
public string ProgramName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
|
||||
#endif
|
||||
|
||||
public DirectoryInfo LocalAppData = new DirectoryInfo(
|
||||
@@ -257,8 +257,8 @@ namespace SteamTools
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
this.compositeDisposable.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -82,7 +82,11 @@ namespace SteamTools.Models.Settings
|
||||
public static SerializableProperty<bool> IsEnableLogRecord { get; }
|
||||
= new SerializableProperty<bool>(GetKey(), Providers.Roaming, false) { AutoSave = true };
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检测到Steam启动时弹出消息通知
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> IsEnableSteamLaunchNotification { get; }
|
||||
= new SerializableProperty<bool>(GetKey(), Providers.Roaming, false) { AutoSave = true };
|
||||
private static string GetKey([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
return nameof(GeneralSettings) + "." + propertyName;
|
||||
|
||||
@@ -48,12 +48,14 @@ namespace SteamTools.Models.Settings
|
||||
try
|
||||
{
|
||||
Providers.Local.Load();
|
||||
//每次成功读取完成时保存一份bak
|
||||
File.Copy(Providers.LocalFilePath, Providers.LocalFilePath + ".bak", true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex);
|
||||
MessageBox.Show("Local Settings Load Error :" + ex.ToString(), $"{ProductInfo.Title} {ProductInfo.VersionString} Error");
|
||||
File.Copy(Providers.LocalFilePath, Providers.LocalFilePath + ".bak", true);
|
||||
File.Copy(Providers.LocalFilePath, Providers.LocalFilePath + ".error", true);
|
||||
File.Delete(Providers.LocalFilePath);
|
||||
Providers.Local.Load();
|
||||
}
|
||||
@@ -61,12 +63,14 @@ namespace SteamTools.Models.Settings
|
||||
try
|
||||
{
|
||||
Providers.Roaming.Load();
|
||||
//每次成功读取完成时保存一份bak
|
||||
File.Copy(Providers.RoamingFilePath, Providers.RoamingFilePath + ".bak", true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex);
|
||||
MessageBox.Show("Roaming Settings Load Error :" + ex.ToString(), $"{ProductInfo.Title} {ProductInfo.VersionString} Error");
|
||||
File.Copy(Providers.RoamingFilePath, Providers.RoamingFilePath + ".bak", true);
|
||||
File.Copy(Providers.RoamingFilePath, Providers.RoamingFilePath + ".error", true);
|
||||
File.Delete(Providers.RoamingFilePath);
|
||||
Providers.Roaming.Load();
|
||||
}
|
||||
|
||||
+28
-10
@@ -294,6 +294,24 @@ namespace SteamTools.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 和{0}个脚本 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Community_Script_Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("Community_Script_Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 已启用{0}个代理服务 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Community_Service_Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("Community_Service_Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 社区加速 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -627,6 +645,15 @@ namespace SteamTools.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 注销登录 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Logout {
|
||||
get {
|
||||
return ResourceManager.GetString("Logout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 预告视频 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -844,7 +871,7 @@ namespace SteamTools.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 脚本配置(实验性功能) 的本地化字符串。
|
||||
/// 查找类似 脚本配置 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ScriptSettings {
|
||||
get {
|
||||
@@ -1005,15 +1032,6 @@ namespace SteamTools.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Steam未运行 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Steam_Not_Runing {
|
||||
get {
|
||||
return ResourceManager.GetString("Steam_Not_Runing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Steam未运行(该功能不可用) 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -198,6 +198,12 @@
|
||||
<data name="CommunityFix" xml:space="preserve">
|
||||
<value>社区加速</value>
|
||||
</data>
|
||||
<data name="Community_Script_Tips" xml:space="preserve">
|
||||
<value>和{0}个脚本</value>
|
||||
</data>
|
||||
<data name="Community_Service_Tips" xml:space="preserve">
|
||||
<value>已启用{0}个代理服务</value>
|
||||
</data>
|
||||
<data name="Confirm" xml:space="preserve">
|
||||
<value>确定</value>
|
||||
</data>
|
||||
@@ -306,6 +312,9 @@
|
||||
<data name="Logo" xml:space="preserve">
|
||||
<value>封面</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>注销登录</value>
|
||||
</data>
|
||||
<data name="Media" xml:space="preserve">
|
||||
<value>预告视频</value>
|
||||
</data>
|
||||
@@ -379,7 +388,7 @@
|
||||
<value>脚本列表</value>
|
||||
</data>
|
||||
<data name="ScriptSettings" xml:space="preserve">
|
||||
<value>脚本配置(实验性功能)</value>
|
||||
<value>脚本配置</value>
|
||||
</data>
|
||||
<data name="Search" xml:space="preserve">
|
||||
<value>搜索</value>
|
||||
@@ -441,9 +450,6 @@
|
||||
<data name="SteamAuth" xml:space="preserve">
|
||||
<value>本地令牌</value>
|
||||
</data>
|
||||
<data name="Steam_Not_Runing" xml:space="preserve">
|
||||
<value>Steam未运行</value>
|
||||
</data>
|
||||
<data name="Steam_Not_Runing_Tips" xml:space="preserve">
|
||||
<value>Steam未运行(该功能不可用)</value>
|
||||
</data>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 672 B |
Binary file not shown.
|
After Width: | Height: | Size: 383 B |
@@ -172,11 +172,4 @@
|
||||
Value="{DynamicResource ForegroundBrushKey}" />
|
||||
</Style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -57,6 +57,20 @@ namespace SteamTools.Services
|
||||
}
|
||||
#endregion
|
||||
|
||||
private GithubReleaseModel _UpdateInfo;
|
||||
public GithubReleaseModel UpdateInfo
|
||||
{
|
||||
get => this._UpdateInfo;
|
||||
set
|
||||
{
|
||||
if (this._UpdateInfo != value)
|
||||
{
|
||||
this._UpdateInfo = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void CheckUpdate()
|
||||
{
|
||||
try
|
||||
@@ -64,7 +78,6 @@ namespace SteamTools.Services
|
||||
StatusService.Current.Notify("正在从Github检查更新...");
|
||||
var result = await httpServices.Get(Const.GITHUB_LATEST_RELEASEAPI_URL);
|
||||
UpdateInfo = JsonConvert.DeserializeObject<GithubReleaseModel>(result);
|
||||
|
||||
// if (!(ProductInfo.Version > UpdateInfo.version)) Debug时反向检查更新来测试
|
||||
if (!(ProductInfo.Version < UpdateInfo.version))
|
||||
{
|
||||
@@ -82,32 +95,18 @@ namespace SteamTools.Services
|
||||
|
||||
}
|
||||
|
||||
private GithubReleaseModel _UpdateInfo;
|
||||
public GithubReleaseModel UpdateInfo
|
||||
{
|
||||
get => this._UpdateInfo;
|
||||
set
|
||||
{
|
||||
if (this._UpdateInfo != value)
|
||||
{
|
||||
this._UpdateInfo = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void DownloadUpdate()
|
||||
{
|
||||
if (WindowService.Current.MainWindow.Dialog($"检测到新版本更新内容:{UpdateInfo.body}{Environment.NewLine}是否立即更新?", $"{ProductInfo.Title} | 更新提示") == true)
|
||||
if (WindowService.Current.MainWindow.Dialog($"检测到新版本更新内容:{UpdateInfo.body}{Environment.NewLine}是否立即下载更新?", $"{ProductInfo.Title} | 更新提示") == true)
|
||||
{
|
||||
var name = Path.Combine(AppContext.BaseDirectory, UpdateInfo.assets.FirstOrDefault()?.name);
|
||||
var upFile = new FileInfo(Path.Combine(AppContext.BaseDirectory, UpdateInfo.assets.FirstOrDefault()?.name));
|
||||
//var name = Path.Combine(AppContext.BaseDirectory, @$"{ProductInfo.Title} {UpdateInfo.version}.zip");
|
||||
if (File.Exists(name))
|
||||
if (upFile.Exists)
|
||||
{
|
||||
StatusService.Current.Notify("更新文件已经存在,不需要下载");
|
||||
if (Path.GetExtension(name) == ".zip")
|
||||
if (upFile.Extension == ".zip")
|
||||
{
|
||||
OverwriteUpgrade(name);
|
||||
OverwriteUpgrade(upFile.FullName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -116,7 +115,7 @@ namespace SteamTools.Services
|
||||
{
|
||||
long totalBytes = s.Result.ContentLength;
|
||||
using Stream responseStream = s.Result.GetResponseStream();
|
||||
using FileStream fileStream = new FileStream(name, FileMode.Create, FileAccess.Write);
|
||||
using FileStream fileStream = new FileStream(upFile.FullName, FileMode.Create, FileAccess.Write);
|
||||
long totalDownloadBytes = 0;
|
||||
byte[] bs = new byte[1024];
|
||||
int size = responseStream.Read(bs, 0, bs.Length);
|
||||
@@ -131,9 +130,9 @@ namespace SteamTools.Services
|
||||
fileStream.Flush();
|
||||
fileStream.Close();
|
||||
StatusService.Current.Set(Resources.Ready);
|
||||
if (Path.GetExtension(name) == ".zip")
|
||||
if (upFile.Extension == ".zip")
|
||||
{
|
||||
OverwriteUpgrade(name);
|
||||
OverwriteUpgrade(upFile.FullName);
|
||||
}
|
||||
StatusService.Current.Notify($"{ProductInfo.Title} {UpdateInfo.version}版本已经下载到程序根目录下,请手动替换更新");
|
||||
});
|
||||
@@ -142,6 +141,13 @@ namespace SteamTools.Services
|
||||
|
||||
private void OverwriteUpgrade(string zipFile)
|
||||
{
|
||||
if (new FileInfo(zipFile).Length != UpdateInfo.assets.First().size)
|
||||
{
|
||||
File.Delete(zipFile);
|
||||
StatusService.Current.Notify("效验更新文件失败,重新下载更新...");
|
||||
DownloadUpdate();
|
||||
return;
|
||||
}
|
||||
App.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (WindowService.Current.MainWindow.Dialog($"新版本下载完成,是否自动重启替换到新版本?", $"{ProductInfo.Title} | 更新提示") == true)
|
||||
@@ -150,12 +156,12 @@ namespace SteamTools.Services
|
||||
if (ZipHelper.UnpackFiles(zipFile, out_dir))
|
||||
{
|
||||
File.Delete(zipFile);
|
||||
var batpath = Path.Combine(App.Instance.LocalAppData.FullName, "update.cmd");
|
||||
var batpath = Path.Combine(AppContext.BaseDirectory, "update.cmd");
|
||||
File.WriteAllText(batpath,
|
||||
string.Format(SteamTool.Core.Properties.Resources.ProgramUpdateCmd,
|
||||
ProductInfo.Title + ".exe", out_dir, AppContext.BaseDirectory, App.Instance.ProgramName), Encoding.Default);
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName = batpath;//要执行的程序名称
|
||||
p.StartInfo.FileName = batpath;
|
||||
p.StartInfo.UseShellExecute = false;
|
||||
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
|
||||
//管理员权限运行
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace SteamTools.Services
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.SteamCommunity,
|
||||
Domains = new List<string>{"steamcommunity.com" },
|
||||
ToDomain = "steamcommunity-a.akamaihd.net",
|
||||
ToDomain = "steamcommunity.rmbgame.net",
|
||||
Hosts = new List<string>{ "steamcommunity.com", "www.steamcommunity.com"},
|
||||
DomainTag = DomainTag.SteamCommunity,
|
||||
IsEnable= true,
|
||||
@@ -59,8 +59,7 @@ IsEnable= true,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.SteamStore,
|
||||
Domains = new List<string>{"steampowered.com" },
|
||||
ToDomain = "steamstore-a.akamaihd.net",
|
||||
//ToDomain = "media.steampowered.com",
|
||||
ToDomain = "steamstore.rmbgame.net",
|
||||
Hosts = new List<string>{ "store.steampowered.com", "api.steampowered.com"},
|
||||
DomainTag = DomainTag.SteamStore,
|
||||
IsEnable= false,
|
||||
@@ -68,8 +67,8 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.SteamImage,
|
||||
Domains = new List<string>{"steamcdn-a.akamaihd.net" },
|
||||
ToDomain = "cdn.akamai.steamstatic.com",
|
||||
//ToDomain = "media.steampowered.com",
|
||||
//ToDomain = "cdn.akamai.steamstatic.com",
|
||||
ToDomain = "steamimage.rmbgame.net",
|
||||
Hosts = new List<string>{ "steamcdn-a.akamaihd.net"},
|
||||
DomainTag = DomainTag.SteamImage,
|
||||
IsEnable= false,
|
||||
@@ -77,7 +76,7 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.SteamChat,
|
||||
Domains = new List<string>{"steam-chat.com" },
|
||||
ToDomain = "steamstore-a.akamaihd.net",
|
||||
ToDomain = "steamchat.rmbgame.net",
|
||||
Hosts = new List<string>{ "steam-chat.com"},
|
||||
DomainTag = DomainTag.SteamChat,
|
||||
IsEnable= false,
|
||||
@@ -85,8 +84,8 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.Discord,
|
||||
Domains = new List<string>{ "discordapp.com"},
|
||||
//ToDomain = "discord.com",
|
||||
ProxyIPAddres="162.159.129.233",
|
||||
ToDomain = "discord.rmbgame.net",
|
||||
//ProxyIPAddres="162.159.129.233",
|
||||
Hosts = new List<string>{
|
||||
"discordapp.com",
|
||||
"support.discordapp.com",
|
||||
@@ -106,6 +105,10 @@ Hosts = new List<string>{
|
||||
"canary.discordapp.com",
|
||||
"apps.discordapp.com",
|
||||
"pax.discordapp.com",
|
||||
//"1.0.0.1 dl.discordapp.net",
|
||||
//"1.0.0.1 media.discordapp.net",
|
||||
//"1.0.0.1 images-ext-2.discordapp.net",
|
||||
//"1.0.0.1 images-ext-1.discordapp.net",
|
||||
},
|
||||
//ServerName= "discord.com",
|
||||
DomainTag = DomainTag.Discord,
|
||||
@@ -114,9 +117,10 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.DiscordNet,
|
||||
Domains = new List<string>{ "discordapp.net" },
|
||||
ProxyIPAddres="162.159.130.232",
|
||||
//ProxyIPAddres="162.159.129.232",
|
||||
ToDomain = "discordnet.rmbgame.net",
|
||||
Hosts = new List<string>{
|
||||
"dl.discordapp.net",
|
||||
"1.0.0.1 dl.discordapp.net",
|
||||
"media.discordapp.net",
|
||||
"images-ext-2.discordapp.net",
|
||||
"images-ext-1.discordapp.net",
|
||||
@@ -127,7 +131,8 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.TwitchChat,
|
||||
Domains = new List<string>{ "irc-ws.chat.twitch.tv" },
|
||||
ProxyIPAddres="50.112.157.122",
|
||||
//ProxyIPAddres="52.38.70.182",
|
||||
ToDomain = "twitchchat.rmbgame.net",
|
||||
Hosts = new List<string>{
|
||||
"irc-ws.chat.twitch.tv",
|
||||
"irc-ws-r.chat.twitch.tv",
|
||||
@@ -135,23 +140,10 @@ Hosts = new List<string>{
|
||||
DomainTag = DomainTag.TwitchChat,
|
||||
IsEnable= false,
|
||||
},
|
||||
//new ProxyDomainModel{
|
||||
//Name=Resources.Twitch,
|
||||
//Domains = new List<string>{ "usher.ttvnw.net" },
|
||||
////ToDomain="twitch.map.fastly.net",
|
||||
//ProxyIPAddres="23.160.0.254",
|
||||
//Hosts = new List<string>{
|
||||
////"usher.twitch.tv",
|
||||
//"usher.ttvnw.net",
|
||||
//"hls.ttvnw.net",
|
||||
//},
|
||||
//DomainTag = DomainTag.Twitch,
|
||||
//IsEnable= false,
|
||||
//},
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.Twitch,
|
||||
Domains = new List<string>{ "twitch.tv" },
|
||||
ToDomain="twitch.map.fastly.net",
|
||||
ToDomain="twitch.rmbgame.net",
|
||||
Hosts = new List<string>{
|
||||
"twitch.tv",
|
||||
"www.twitch.tv",
|
||||
@@ -214,8 +206,9 @@ IsEnable= false,
|
||||
//new ProxyDomainModel{
|
||||
//Name=Resources.GOG,
|
||||
//Domains = new List<string>{ "gog.com" },
|
||||
//ToDomain = "gog.com",
|
||||
//ToDomain = "gog.rmbgame.net",
|
||||
//Hosts = new List<string>{
|
||||
//"gog.com",
|
||||
//"www.gog.com",
|
||||
//"images.gog.com",
|
||||
//"images-1.gog.com",
|
||||
@@ -246,21 +239,23 @@ IsEnable= false,
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.GoogleRecaptchaCode,
|
||||
Domains = new List<string>{"www.google.com" },
|
||||
ToDomain = "kh.google.com",
|
||||
ToDomain = "googlerecaptchacode.rmbgame.net",
|
||||
Hosts = new List<string>{ "www.google.com"},
|
||||
DomainTag = DomainTag.GoogleCode,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.GithubContent,
|
||||
Domains = new List<string>{"githubusercontent.com","raw.github.com" },
|
||||
//ToDomain = "aw.githubusercontent.com",
|
||||
ProxyIPAddres = "151.101.88.133",
|
||||
Domains = new List<string>{"githubusercontent.com","raw.github.com"},
|
||||
ToDomain = "githubusercontent.rmbgame.net",
|
||||
//ProxyIPAddres = "151.101.88.133",
|
||||
Hosts = new List<string>{
|
||||
"raw.github.com",
|
||||
"githubusercontent.com",
|
||||
"raw.githubusercontent.com",
|
||||
"camo.githubusercontent.com",
|
||||
"cloud.githubusercontent.com",
|
||||
"avatars.githubusercontent.com",
|
||||
"avatars0.githubusercontent.com",
|
||||
"avatars1.githubusercontent.com",
|
||||
"avatars2.githubusercontent.com",
|
||||
@@ -271,10 +266,19 @@ DomainTag = DomainTag.GithubContent,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.GithubGist,
|
||||
Domains = new List<string>{"gist.github.com" },
|
||||
ToDomain = "github.com",
|
||||
Hosts = new List<string>{
|
||||
"gist.github.com",
|
||||
},
|
||||
DomainTag = DomainTag.GithubGist,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.Pixiv,
|
||||
Domains = new List<string>{ "pixiv.net" },
|
||||
//ToDomain="www.fanbox.cc",
|
||||
ToDomain="www.pixivision.net",
|
||||
ToDomain="pixiv.rmbgame.net",
|
||||
Hosts = new List<string>{
|
||||
"www.pixiv.net",
|
||||
"touch.pixiv.net",
|
||||
@@ -313,9 +317,27 @@ Hosts = new List<string>{
|
||||
"comic-api.pixiv.net",
|
||||
"pay.pixiv.net",
|
||||
},
|
||||
DomainTag = DomainTag.GithubContent,
|
||||
DomainTag = DomainTag.Pixiv,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Name=Resources.PixivImgae,
|
||||
Domains = new List<string>{ "pximg.net" },
|
||||
ToDomain="pximg.rmbgame.net",
|
||||
Hosts = new List<string>{
|
||||
"pximg.net",
|
||||
"i.pximg.net",
|
||||
"s.pximg.net",
|
||||
"img-sketch.pximg.net",
|
||||
"source.pximg.net",
|
||||
"booth.pximg.net",
|
||||
"i-f.pximg.net",
|
||||
"imp.pximg.net",
|
||||
"public-img-comic.pximg.net",
|
||||
},
|
||||
DomainTag = DomainTag.PixivImage,
|
||||
IsEnable = false,
|
||||
},
|
||||
});
|
||||
public Lazy<IReadOnlyCollection<ProxyDomainModel>> ProxyDomains
|
||||
{
|
||||
|
||||
@@ -95,6 +95,20 @@ namespace SteamTools.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsSteamChinaLauncher;
|
||||
public bool IsSteamChinaLauncher
|
||||
{
|
||||
get => _IsSteamChinaLauncher;
|
||||
set
|
||||
{
|
||||
if (_IsSteamChinaLauncher != value)
|
||||
{
|
||||
_IsSteamChinaLauncher = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 是否已经释放SteamClient
|
||||
@@ -120,7 +134,6 @@ namespace SteamTools.Services
|
||||
Thread.CurrentThread.IsBackground = true;
|
||||
try
|
||||
{
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Process.GetProcessesByName("steam").Length > 0)
|
||||
@@ -140,20 +153,27 @@ namespace SteamTools.Services
|
||||
IsConnectToSteam = true;
|
||||
CurrentSteamUser = await SteamworksWebApiService.GetUserInfo(id);
|
||||
CurrentSteamUser.IPCountry = ApiService.GetIPCountry();
|
||||
IsSteamChinaLauncher = ApiService.IsSteamChinaLauncher();
|
||||
|
||||
|
||||
if (GeneralSettings.IsEnableSteamLaunchNotification)
|
||||
TaskbarService.Current.Notify($"Steam({(IsSteamChinaLauncher ? "国服" : "国际服")})已经启动{ Environment.NewLine}{ Environment.NewLine}Steam登录用户:{CurrentSteamUser.SteamNickName}{ Environment.NewLine}Steam客户端登录区域:{CurrentSteamUser.IPCountry}");
|
||||
|
||||
#region 初始化需要steam启动才能使用的功能
|
||||
var mainViewModel = (WindowService.Current.MainWindow as MainWindowViewModel);
|
||||
await mainViewModel.SteamAppPage.Initialize();
|
||||
#if DEBUG
|
||||
await mainViewModel.SystemTabItems[mainViewModel.SystemTabItems.Count - 1].Initialize();
|
||||
#endif
|
||||
SteamConnectService.Current.DisposeSteamClient();
|
||||
#endregion
|
||||
|
||||
DisposeSteamClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IsConnectToSteam = false;
|
||||
//StatusService.Current.Notify(Resources.Steam_Not_Runing);
|
||||
}
|
||||
await Task.Delay(1500);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace SteamTools.Services
|
||||
if (this.MainWindow == this.mainWindow)
|
||||
{
|
||||
this.MainWindow
|
||||
.Subscribe(nameof(MainWindowViewModel.SelectedItem),
|
||||
.Subscribe(nameof(MainWindowViewModel.SelectedItem),
|
||||
() => this.MainWindow.StatusBar = (this.MainWindow as MainWindowViewModel).SelectedItem)
|
||||
.AddTo(this);
|
||||
return new MainWindow { DataContext = this.MainWindow, };
|
||||
@@ -62,15 +62,18 @@ namespace SteamTools.Services
|
||||
|
||||
public bool ShowDialogWindow(string content, string title)
|
||||
{
|
||||
var dialog = new DialogWindowViewModel
|
||||
return App.Current.Dispatcher.Invoke<bool>(() =>
|
||||
{
|
||||
Content = content,
|
||||
Title = title
|
||||
};
|
||||
var window = new MessageDialog { DataContext = dialog };
|
||||
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
window.ShowDialog();
|
||||
return dialog.DialogResult;
|
||||
var dialog = new DialogWindowViewModel
|
||||
{
|
||||
Content = content,
|
||||
Title = title
|
||||
};
|
||||
var window = new MessageDialog { DataContext = dialog };
|
||||
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
window.ShowDialog();
|
||||
return dialog.DialogResult;
|
||||
});
|
||||
}
|
||||
|
||||
#region disposable members
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
|
||||
<Copyright>Copyright © 2018 - 2020 软妹币玩家</Copyright>
|
||||
<Copyright>Copyright © 2018 - 2021 软妹币玩家</Copyright>
|
||||
|
||||
<Authors>软妹币玩家</Authors>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<PackageId />
|
||||
|
||||
<Version>1.0.6</Version>
|
||||
<Version>1.1.0</Version>
|
||||
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
@@ -98,12 +98,15 @@
|
||||
<None Remove="Resources\Asstes\alipay.jpg" />
|
||||
<None Remove="Resources\Asstes\app.ico" />
|
||||
<None Remove="Resources\Asstes\avater.jpg" />
|
||||
<None Remove="Resources\Asstes\confirm.png" />
|
||||
<None Remove="Resources\Asstes\Copy.png" />
|
||||
<None Remove="Resources\Asstes\delete.png" />
|
||||
<None Remove="Resources\Asstes\detail.png" />
|
||||
<None Remove="Resources\Asstes\disable.png" />
|
||||
<None Remove="Resources\Asstes\edit.png" />
|
||||
<None Remove="Resources\Asstes\export.png" />
|
||||
<None Remove="Resources\Asstes\install-line.png" />
|
||||
<None Remove="Resources\Asstes\logout.png" />
|
||||
<None Remove="Resources\Asstes\movecross.png" />
|
||||
<None Remove="Resources\Asstes\ok.png" />
|
||||
<None Remove="Resources\Asstes\play.png" />
|
||||
@@ -137,12 +140,14 @@
|
||||
<Resource Include="Resources\Asstes\alipay.jpg" />
|
||||
<Resource Include="Resources\Asstes\app.ico" />
|
||||
<Resource Include="Resources\Asstes\avater.jpg" />
|
||||
<Resource Include="Resources\Asstes\confirm.png" />
|
||||
<Resource Include="Resources\Asstes\copy.png" />
|
||||
<Resource Include="Resources\Asstes\delete.png" />
|
||||
<Resource Include="Resources\Asstes\detail.png" />
|
||||
<Resource Include="Resources\Asstes\edit.png" />
|
||||
<Resource Include="Resources\Asstes\export.png" />
|
||||
<Resource Include="Resources\Asstes\install-line.png" />
|
||||
<Resource Include="Resources\Asstes\logout.png" />
|
||||
<Resource Include="Resources\Asstes\movecross.png" />
|
||||
<Resource Include="Resources\Asstes\ok.png" />
|
||||
<Resource Include="Resources\Asstes\play.png" />
|
||||
@@ -359,6 +364,9 @@
|
||||
<None Update="scripts\GM.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="scripts\Steam历史最低价格查询.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="scripts\Steam自动探索队列.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -107,15 +107,15 @@ namespace SteamTools.ViewModels
|
||||
|
||||
protected override void CloseCanceledCallbackCore()
|
||||
{
|
||||
//var dialog = new DialogViewModel { Title = "确认关闭", };
|
||||
var dialog = new DialogWindowViewModel { Title = "确认关闭", };
|
||||
|
||||
//this.Dialog(dialog, typeof(ExitDialog));
|
||||
this.Dialog(dialog, typeof(MessageDialog));
|
||||
|
||||
//if (dialog.DialogResult)
|
||||
//{
|
||||
// this.CanClose = true;
|
||||
// this.InvokeOnUIDispatcher(this.Close);
|
||||
//}
|
||||
if (dialog.DialogResult)
|
||||
{
|
||||
this.CanClose = true;
|
||||
this.InvokeOnUIDispatcher(this.Close);
|
||||
}
|
||||
}
|
||||
|
||||
protected void RaiseCanCloseChanged()
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace SteamTools.ViewModels
|
||||
public void FixCsgoVacIssue()
|
||||
{
|
||||
SteamTool.KillSteamProcess();
|
||||
var fixpath = Path.Combine(App.Instance.LocalAppData.FullName, "vacfix.cmd");
|
||||
var fixpath = Path.Combine(AppContext.BaseDirectory, "vacfix.cmd");
|
||||
File.WriteAllText(fixpath, Resources.VACFIX_BAT, Encoding.Default);
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace SteamTools.ViewModels
|
||||
{
|
||||
private readonly HostsService hostsService = SteamToolCore.Instance.Get<HostsService>();
|
||||
|
||||
public int EnableServiceCount => ProxyService.Current.ProxyDomains.Value.Count(c => c.IsEnable);
|
||||
|
||||
public int EnableScriptCount => ProxyService.Current.ProxyScripts.Count(c => c.Enable);
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return Properties.Resources.CommunityFix; }
|
||||
|
||||
@@ -13,6 +13,7 @@ using SteamTool.Core.Common;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using MetroTrilithon.Mvvm;
|
||||
using WinAuth;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
@@ -76,7 +77,7 @@ namespace SteamTools.ViewModels
|
||||
public void ImageCopy_Click(WinAuthAuthenticator auth)
|
||||
{
|
||||
auth.CopyCodeToClipboard();
|
||||
TaskbarService.Current.Notify("已复制令牌");
|
||||
TaskbarService.Current.Notify("已复制令牌 " + auth.Name);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,13 +102,19 @@ namespace SteamTools.ViewModels
|
||||
|
||||
public void ImageShowAuth_Click(WinAuthAuthenticator auth)
|
||||
{
|
||||
new ShowAuthWindow() { DataContext = new ShowAuthWindowViewModel(auth) }.Show();
|
||||
if (auth.AuthenticatorData is SteamAuthenticator)
|
||||
{
|
||||
new ShowAuthWindow() { DataContext = new ShowAuthWindowViewModel(auth) }.Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ImageAuthTrade_Click(WinAuthAuthenticator auth)
|
||||
{
|
||||
new AuthTradeWindow() { DataContext = new AuthTradeWindowViewModel(auth) }.Show();
|
||||
if (auth.AuthenticatorData is SteamAuthenticator)
|
||||
{
|
||||
new AuthTradeWindow() { DataContext = new AuthTradeWindowViewModel(auth) }.Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -184,12 +184,10 @@ namespace SteamTools.ViewModels
|
||||
{
|
||||
case SteamAppTypeEnum.Application:
|
||||
case SteamAppTypeEnum.Game:
|
||||
//var achievement = new AchievementWindowViewModel();
|
||||
//WindowService.Current.MainWindow.Transition(achievement, typeof(AchievementWindow));
|
||||
var nApp = app.Clone();
|
||||
//var nApp = app.Clone();
|
||||
//nApp.Process = Process.Start($"{ProductInfo.Title}.exe", app.AppId.ToString(CultureInfo.InvariantCulture));
|
||||
nApp.Process = Process.Start(App.Instance.ProgramName, "-app " + app.AppId.ToString(CultureInfo.InvariantCulture));
|
||||
SteamConnectService.Current.RuningSteamApps.Add(nApp);
|
||||
app.Process = Process.Start(Path.Combine(AppContext.BaseDirectory, App.Instance.ProgramName), "-app " + app.AppId.ToString(CultureInfo.InvariantCulture));
|
||||
SteamConnectService.Current.RuningSteamApps.Add(app);
|
||||
break;
|
||||
default:
|
||||
StatusService.Current.Notify(Resources.Unsupported_Operation);
|
||||
|
||||
@@ -17,26 +17,21 @@ using System.Net;
|
||||
using SteamTools.Win32;
|
||||
using SteamTool.Model;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
public class AuthTradeWindowViewModel : MainWindowViewModelBase
|
||||
{
|
||||
private readonly SteamAuthenticator _AuthenticatorData;
|
||||
private readonly WinAuthAuthenticator _Authenticator;
|
||||
private SteamAuthenticator _AuthenticatorData => _Authenticator.AuthenticatorData as SteamAuthenticator;
|
||||
|
||||
public AuthTradeWindowViewModel(WinAuthAuthenticator auth)
|
||||
{
|
||||
_Authenticator = auth;
|
||||
_AuthenticatorData = auth.AuthenticatorData as SteamAuthenticator;
|
||||
this.Title = ProductInfo.Title + " | " + Resources.Auth_TradeTitle;
|
||||
|
||||
|
||||
//var steam = _Authenticator.GetClient();
|
||||
//if (steam.IsLoggedIn() == false)
|
||||
//{
|
||||
// ExtractSteamCookies(steam);
|
||||
//}
|
||||
Refresh_Click();
|
||||
}
|
||||
|
||||
#region LoginData
|
||||
@@ -111,14 +106,38 @@ namespace SteamTools.ViewModels
|
||||
}
|
||||
#endregion
|
||||
|
||||
public bool IsLoggedIn => this._AuthenticatorData.GetClient().IsLoggedIn();
|
||||
public bool IsRequiresCaptcha => this._AuthenticatorData.GetClient().RequiresCaptcha;
|
||||
public bool IsLoggedIn
|
||||
{
|
||||
get => this._AuthenticatorData.GetClient().IsLoggedIn();
|
||||
set
|
||||
{
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
public bool IsRequiresCaptcha
|
||||
{
|
||||
get => this._AuthenticatorData.GetClient().RequiresCaptcha;
|
||||
set
|
||||
{
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancellation token for confirm all
|
||||
/// </summary>
|
||||
private CancellationTokenSource CancelComfirmAll;
|
||||
|
||||
/// <summary>
|
||||
/// Cancellation token for cancel all
|
||||
/// </summary>
|
||||
private CancellationTokenSource CancelCancelAll;
|
||||
|
||||
/// <summary>
|
||||
/// Trade info state
|
||||
/// </summary>
|
||||
private List<SteamClient.Confirmation> _Confirmations;
|
||||
public List<SteamClient.Confirmation> Confirmations
|
||||
private BindingList<SteamClient.Confirmation> _Confirmations;
|
||||
public BindingList<SteamClient.Confirmation> Confirmations
|
||||
{
|
||||
get => this._Confirmations;
|
||||
set
|
||||
@@ -145,85 +164,368 @@ namespace SteamTools.ViewModels
|
||||
|
||||
}
|
||||
|
||||
private void Init()
|
||||
public void CaptchaButton_Click()
|
||||
{
|
||||
if (CodeImageChar?.Trim().Length > 0)
|
||||
{
|
||||
Process(_AuthenticatorData.GetClient().CaptchaId, CodeImageChar);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Dialog("请输入正确的令牌");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Refresh_Click()
|
||||
{
|
||||
if (IsLoggedIn)
|
||||
{
|
||||
Process();
|
||||
}
|
||||
}
|
||||
|
||||
private void Process(string captchaId = null)
|
||||
public void Logout_Click()
|
||||
{
|
||||
var steam = _AuthenticatorData.GetClient();
|
||||
var steam = this._AuthenticatorData.GetClient();
|
||||
steam.Logout();
|
||||
|
||||
if (!steam.IsLoggedIn())
|
||||
if (String.IsNullOrEmpty(_AuthenticatorData.SessionData) == false)
|
||||
{
|
||||
if (steam.Login(UserName, Password, captchaId, CodeImageChar, ResourceService.Current.GetCurrentCultureSteamLanguageName()) == false)
|
||||
{
|
||||
if (steam.Error == "Incorrect Login")
|
||||
{
|
||||
this.Dialog("账号或密码错误");
|
||||
return;
|
||||
}
|
||||
if (steam.Requires2FA == true)
|
||||
{
|
||||
this.Dialog("无效验证码:您确定这是您账户的当前验证码?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (steam.RequiresCaptcha == true)
|
||||
{
|
||||
this.Dialog("请输入图片验证码");
|
||||
CodeImage = steam.CaptchaUrl;
|
||||
return;
|
||||
}
|
||||
//loginButton.Enabled = true;
|
||||
//captchaGroup.Visible = false;
|
||||
|
||||
if (string.IsNullOrEmpty(steam.Error) == false)
|
||||
{
|
||||
this.Dialog(steam.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_AuthenticatorData.SessionData = (RememberMe ? steam.Session.ToString() : null);
|
||||
IsLoggedIn = false;
|
||||
_AuthenticatorData.SessionData = null;
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
}
|
||||
}
|
||||
|
||||
private void Process(string captchaId = null, string codeChar = null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
var steam = _AuthenticatorData.GetClient();
|
||||
if (!steam.IsLoggedIn())
|
||||
{
|
||||
if (steam.Login(UserName, Password, captchaId, codeChar, ResourceService.Current.GetCurrentCultureSteamLanguageName()) == false)
|
||||
{
|
||||
if (steam.Error == "Incorrect Login")
|
||||
{
|
||||
this.Dialog("账号或密码错误");
|
||||
return;
|
||||
}
|
||||
|
||||
if (steam.Requires2FA == true)
|
||||
{
|
||||
this.Dialog("无效令牌:您确定登录的是您当前令牌的账号?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (steam.RequiresCaptcha == true)
|
||||
{
|
||||
IsRequiresCaptcha = steam.RequiresCaptcha;
|
||||
this.Dialog("请输入图片验证码");
|
||||
CodeImage = steam.CaptchaUrl;
|
||||
return;
|
||||
}
|
||||
//loginButton.Enabled = true;
|
||||
//captchaGroup.Visible = false;
|
||||
|
||||
if (string.IsNullOrEmpty(steam.Error) == false)
|
||||
{
|
||||
this.Dialog(steam.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
IsLoggedIn = true;
|
||||
_AuthenticatorData.SessionData = RememberMe ? steam.Session.ToString() : null;
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
}
|
||||
try
|
||||
{
|
||||
Confirmations = new BindingList<SteamClient.Confirmation>(steam.GetConfirmations());
|
||||
|
||||
// 获取新交易后保存
|
||||
if (!string.IsNullOrEmpty(_AuthenticatorData.SessionData))
|
||||
{
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
}
|
||||
}
|
||||
catch (SteamClient.UnauthorisedSteamRequestException)
|
||||
{
|
||||
// Family view is probably on
|
||||
this.Dialog("You are not allowed to view confirmations. Have you enabled 'community-generated content' in Family View?");
|
||||
return;
|
||||
}
|
||||
catch (SteamClient.InvalidSteamRequestException)
|
||||
{
|
||||
// likely a bad session so try a refresh first
|
||||
try
|
||||
{
|
||||
steam.Refresh();
|
||||
Confirmations = new BindingList<SteamClient.Confirmation>(steam.GetConfirmations());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// reset and show normal login
|
||||
steam.Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}).ContinueWith(s => { Logger.Error(s.Exception); WindowService.Current.ShowDialogWindow(s.Exception.Message); }, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
public void ConfirmTrade_Click(SteamClient.Confirmation trade)
|
||||
{
|
||||
OperationTrade(true, trade);
|
||||
}
|
||||
public void CancelTrade_Click(SteamClient.Confirmation trade)
|
||||
{
|
||||
OperationTrade(false, trade);
|
||||
}
|
||||
|
||||
private void OperationTrade(bool accept, SteamClient.Confirmation trade)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
bool result = false;
|
||||
if (accept)
|
||||
result = await AcceptTrade(trade.Id);
|
||||
else
|
||||
result = await RejectTrade(trade.Id);
|
||||
|
||||
if (result)
|
||||
{
|
||||
StatusService.Current.Notify($"已{(accept ? "同意" : "取消")}{trade.Details}");
|
||||
App.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Confirmations.Remove(trade);
|
||||
});
|
||||
//Refresh_Click();
|
||||
}
|
||||
}).ContinueWith(s =>
|
||||
{
|
||||
Logger.Error(s.Exception); WindowService.Current.ShowDialogWindow(s.Exception.Message);
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accept the trade Confirmation
|
||||
/// </summary>
|
||||
/// <param name="tradeId">Id of Confirmation</param>
|
||||
private async Task<bool> AcceptTrade(string tradeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var trade = Confirmations.Where(t => t.Id == tradeId).FirstOrDefault();
|
||||
if (trade == null)
|
||||
{
|
||||
throw new ApplicationException("无效的交易");
|
||||
}
|
||||
|
||||
var result = await Task.Factory.StartNew<bool>((t) =>
|
||||
{
|
||||
return this._AuthenticatorData.GetClient().ConfirmTrade(((SteamClient.Confirmation)t).Id, ((SteamClient.Confirmation)t).Key, true);
|
||||
}, trade);
|
||||
if (result == false)
|
||||
{
|
||||
throw new ApplicationException("无法确认此交易");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
catch (InvalidTradesResponseException ex)
|
||||
{
|
||||
Logger.Error("允许交易时出错", ex);
|
||||
this.Dialog("允许交易时出错:" + ex);
|
||||
return false;
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
this.Dialog(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reject the trade Confirmation
|
||||
/// </summary>
|
||||
/// <param name="tradeId">ID of Confirmation</param>
|
||||
private async Task<bool> RejectTrade(string tradeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var trade = Confirmations.Where(t => t.Id == tradeId).FirstOrDefault();
|
||||
if (trade == null)
|
||||
{
|
||||
throw new ApplicationException("无效的交易");
|
||||
}
|
||||
var result = await Task.Factory.StartNew<bool>((t) =>
|
||||
{
|
||||
return this._AuthenticatorData.GetClient().ConfirmTrade(((SteamClient.Confirmation)t).Id, ((SteamClient.Confirmation)t).Key, false);
|
||||
}, trade);
|
||||
if (result == false)
|
||||
{
|
||||
throw new ApplicationException("无法取消的交易");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
catch (InvalidTradesResponseException ex)
|
||||
{
|
||||
Logger.Error("拒绝交易时出错", ex);
|
||||
this.Dialog("拒绝交易时出错:" + ex);
|
||||
return false;
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
this.Dialog(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ConfirmAllButton_Click()
|
||||
{
|
||||
OperationTrades(true);
|
||||
}
|
||||
public void CancelAllButton_Click()
|
||||
{
|
||||
OperationTrades(false);
|
||||
}
|
||||
|
||||
private void OperationTrades(bool accept)
|
||||
{
|
||||
if (Confirmations.Count == 0)
|
||||
{
|
||||
StatusService.Current.Notify($"当前没有任何交易");
|
||||
return;
|
||||
}
|
||||
|
||||
if (CancelComfirmAll != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CancelCancelAll != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var str = (accept ? "同意" : "取消");
|
||||
if (!this.Dialog("这将" + str + "您当前所有的交易确认。" + Environment.NewLine + Environment.NewLine +
|
||||
"确定要继续吗?"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StatusService.Current.Set($"正在{str}所有交易中...");
|
||||
|
||||
if (accept)
|
||||
AcceptAllTrade();
|
||||
else
|
||||
RejectAllTrade();
|
||||
|
||||
}
|
||||
|
||||
private async void AcceptAllTrade()
|
||||
{
|
||||
if (CancelComfirmAll != null)
|
||||
{
|
||||
CancelComfirmAll.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
CancelComfirmAll = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
Confirmations = steam.GetConfirmations();
|
||||
|
||||
// 获取新交易后保存
|
||||
if (!string.IsNullOrEmpty(_AuthenticatorData.SessionData))
|
||||
var rand = new Random();
|
||||
var tradeIds = Confirmations.Reverse().ToArray();
|
||||
for (var i = tradeIds.Length - 1; i >= 0; i--)
|
||||
{
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
if (CancelComfirmAll.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
var result = await AcceptTrade(tradeIds[i].Id);
|
||||
if (result == false || CancelComfirmAll.IsCancellationRequested == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Confirmations.Remove(tradeIds[i]);
|
||||
if (i != 0)
|
||||
{
|
||||
var duration = (int)DateTime.Now.Subtract(start).TotalMilliseconds;
|
||||
var delay = SteamClient.CONFIRMATION_EVENT_DELAY + rand.Next(SteamClient.CONFIRMATION_EVENT_DELAY / 2); // delay is 100%-150% of CONFIRMATION_EVENT_DELAY
|
||||
if (delay > duration)
|
||||
{
|
||||
await Task.Delay(delay - duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (SteamClient.UnauthorisedSteamRequestException)
|
||||
finally
|
||||
{
|
||||
// Family view is probably on
|
||||
this.Dialog("You are not allowed to view confirmations. Have you enabled 'community-generated content' in Family View?");
|
||||
CancelComfirmAll = null;
|
||||
StatusService.Current.Set(Resources.Ready);
|
||||
StatusService.Current.Notify($"已成功同意所有交易");
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
}
|
||||
}
|
||||
|
||||
private async void RejectAllTrade()
|
||||
{
|
||||
if (CancelCancelAll != null)
|
||||
{
|
||||
CancelCancelAll.Cancel();
|
||||
return;
|
||||
}
|
||||
catch (SteamClient.InvalidSteamRequestException)
|
||||
|
||||
CancelCancelAll = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
// likely a bad session so try a refresh first
|
||||
try
|
||||
var rand = new Random();
|
||||
var tradeIds = Confirmations.Reverse().ToArray();
|
||||
for (var i = tradeIds.Length - 1; i >= 0; i--)
|
||||
{
|
||||
steam.Refresh();
|
||||
Confirmations = steam.GetConfirmations();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// reset and show normal login
|
||||
steam.Clear();
|
||||
return;
|
||||
if (CancelCancelAll.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
var result = await RejectTrade(tradeIds[i].Id);
|
||||
if (result == false || CancelCancelAll.IsCancellationRequested == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Confirmations.Remove(tradeIds[i]);
|
||||
if (i != 0)
|
||||
{
|
||||
var duration = (int)DateTime.Now.Subtract(start).TotalMilliseconds;
|
||||
var delay = SteamClient.CONFIRMATION_EVENT_DELAY + rand.Next(SteamClient.CONFIRMATION_EVENT_DELAY / 2); // delay is 100%-150% of CONFIRMATION_EVENT_DELAY
|
||||
if (delay > duration)
|
||||
{
|
||||
await Task.Delay(delay - duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
CancelCancelAll = null;
|
||||
StatusService.Current.Set(Resources.Ready);
|
||||
StatusService.Current.Notify($"已成功取消所有交易");
|
||||
AuthService.Current.SaveCurrentAuth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,31 @@
|
||||
FontFamily="Meiryo UI"
|
||||
TextAlignment="Left"
|
||||
MaxPageWidth="900">
|
||||
<Paragraph Language="zh-cn">
|
||||
<Run Text="Steam++ v1.0.6" FontSize="16"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="2021-01-12" FontSize="10" />
|
||||
<LineBreak />
|
||||
<Run Text="更新内容"></Run>
|
||||
<LineBreak />
|
||||
<Run Text="    "/>
|
||||
<Run Text="新增启用日志记录设置项(反馈bug时一起提交方便排查问题)" />
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="修复twitch反代聊天连接错误和直播视频无法观看" />
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="放宽令牌同步时网络请求超时时间以降低令牌同步时提示超时概率" />
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="修改生成的cer证书编码格式为utf8,解决火狐无法导入cer证书"></Run>
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="增加80端口反代,以便自动跳转http访问到https请求上"></Run>
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="修改了用户信息获取的api为steam官方社区api(没有启动软件的自动代理服务的话依然加载不出头像。)"></Run>
|
||||
</Paragraph>
|
||||
<Paragraph Language="zh-cn">
|
||||
<Run Text="Steam++ v1.0.5" FontSize="16"/>
|
||||
<Run Text=" "/>
|
||||
@@ -69,7 +94,7 @@
|
||||
<Run Text="更新内容"></Run>
|
||||
<LineBreak />
|
||||
<Run Text="    "/>
|
||||
<Run Foreground="IndianRed" Text="*此版本修改了配置文件的保存读取功能,会无法读取1.0.4版本以前的配置文件包括令牌数据。(可以通过设置-令牌设置-导入旧版本Steam++令牌数据按钮来恢复旧版本令牌数据)" />
|
||||
<Run Text="*此版本修改了配置文件的保存读取功能,会无法读取1.0.4版本以前的配置文件包括令牌数据。(可以通过设置-令牌设置-导入旧版本Steam++令牌数据按钮来恢复旧版本令牌数据)" />
|
||||
<LineBreak />
|
||||
<Run Text="    "/>
|
||||
<Run Text="还原steam社区反代上游地址修复部分请求会提示需要登录的问题" />
|
||||
|
||||
@@ -79,6 +79,13 @@
|
||||
IsChecked="{Binding Source={x:Static ms:GeneralSettings.IsAutoCheckUpdate}, Path=Value, Mode=TwoWay}">
|
||||
<TextBlock Text="启动时自动检查更新"></TextBlock>
|
||||
</CheckBox>
|
||||
|
||||
<Separator Opacity="0" Height="10"/>
|
||||
<CheckBox
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="{Binding Source={x:Static ms:GeneralSettings.IsEnableSteamLaunchNotification}, Path=Value, Mode=TwoWay}">
|
||||
<TextBlock Text="检测到Steam启动时弹出消息通知"></TextBlock>
|
||||
</CheckBox>
|
||||
|
||||
<Separator Opacity="0" Height="10"/>
|
||||
<WrapPanel>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:SteamTools.Views.Controls"
|
||||
xmlns:metro="http://schemes.grabacr.net/winfx/2014/controls"
|
||||
xmlns:metro2="http://schemes.grabacr.net/winfx/2015/personal/controls"
|
||||
xmlns:prop="clr-namespace:SteamTools.Properties"
|
||||
xmlns:services="clr-namespace:SteamTools.Services"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:livet="http://schemas.livet-mvvm.net/2011/wpf"
|
||||
@@ -13,6 +14,18 @@
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="25" d:DesignWidth="780"
|
||||
d:DataContext="{d:DesignInstance vm:StatusBarViewModel}">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="StatusText" TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource AccentForegroundBrushKey}" />
|
||||
<Setter Property="FontFamily"
|
||||
Value="{DynamicResource DefaultFontFamilyKey}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{DynamicResource DefaultFontSizeKey}" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid Grid.Row="2" Background="{DynamicResource AccentBrushKey}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -58,30 +71,37 @@
|
||||
Content="{Binding}">
|
||||
<ContentControl.Resources>
|
||||
<DataTemplate DataType="{x:Type vm:WelcomePageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:CommunityProxyPageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:CommunityProxyPageViewModel}" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource StatusText}" Visibility="{Binding ProxyStatus,Source={x:Static services:ProxyService.Current},Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Run Text="{Binding EnableServiceCount,Mode=OneWay,StringFormat={x:Static prop:Resources.Community_Service_Tips}}"></Run><Run>
|
||||
<Run.Style>
|
||||
<Style TargetType="{x:Type Run}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsEnableScript,Source={x:Static services:ProxyService.Current},Mode=OneWay}" Value="True">
|
||||
<Setter Property="Text" Value="{Binding EnableScriptCount,Mode=OneWay, StringFormat={x:Static prop:Resources.Community_Script_Tips}}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsEnableScript,Source={x:Static services:ProxyService.Current},Mode=OneWay}" Value="False">
|
||||
<Setter Property="Text" Value=""/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Run.Style>
|
||||
</Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:SteamAccountPageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:SteamAppPageViewModel}" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource AccentForegroundBrushKey}" />
|
||||
<Setter Property="FontFamily"
|
||||
Value="{DynamicResource DefaultFontFamilyKey}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{DynamicResource DefaultFontSizeKey}" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Steam_Not_Runing_Tips}"
|
||||
<TextBlock Style="{StaticResource StatusText}" VerticalAlignment="Center" Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Steam_Not_Runing_Tips}"
|
||||
Visibility="{Binding Source={x:Static services:SteamConnectService.Current}, Path=IsConnectToSteam,Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Total, StringFormat='{}{0}: '}" />
|
||||
<TextBlock Text="{Binding Games.Count,Mode=OneWay}"
|
||||
<TextBlock Style="{StaticResource StatusText}" Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Total, StringFormat='{}{0}: '}" />
|
||||
<TextBlock Style="{StaticResource StatusText}" Text="{Binding Games.Count,Mode=OneWay}"
|
||||
MinWidth="45" />
|
||||
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Install, StringFormat='{}{0}: '}" />
|
||||
<TextBlock Text="{Binding InstalledCount,Mode=OneWay}"
|
||||
<TextBlock Style="{StaticResource StatusText}" Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Install, StringFormat='{}{0}: '}" />
|
||||
<TextBlock Style="{StaticResource StatusText}" Text="{Binding InstalledCount,Mode=OneWay}"
|
||||
MinWidth="65" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
@@ -92,8 +112,11 @@
|
||||
<DataTemplate DataType="{x:Type vm:ArchiSteamFarmPlusPageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:AboutPageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:DebugPageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:AddAuthWindowViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:AchievementWindowViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:SteamIdlePageViewModel}" />
|
||||
<DataTemplate DataType="{x:Type vm:AuthTradeWindowViewModel}">
|
||||
</DataTemplate>
|
||||
</ContentControl.Resources>
|
||||
</ContentControl>
|
||||
<!--<metro:CaptionButton Grid.Column="2" VerticalAlignment="Center"
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
</CheckBox>
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
<StackPanel>
|
||||
<CheckBox Content="{Binding Resources.OnlyWorkSteambrowser,Source={x:Static services:ResourceService.Current}, Mode=OneWay}" HorizontalAlignment="Center" IsChecked="{Binding Source={x:Static ms:ProxySettings.IsOnlyWorkSteamBrowser}, Path=Value, Mode=TwoWay}"></CheckBox>
|
||||
<CheckBox Content="{Binding Resources.OnlyWorkSteambrowser,Source={x:Static services:ResourceService.Current}, Mode=OneWay}" HorizontalAlignment="Center" IsChecked="{Binding IsOnlyWorkSteamBrowser,Source={x:Static services:ProxyService.Current}, Mode=TwoWay}"></CheckBox>
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
<Button Content="{Binding Resources.ImportScript,Source={x:Static services:ResourceService.Current}, Mode=OneWay}" FontSize="14" Height="30" Margin="10,0">
|
||||
<i:Interaction.Triggers>
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
</i:Interaction.Triggers>
|
||||
</Image>
|
||||
<Separator Opacity="0" Width="5"/>
|
||||
<!--<Image Source="/Resources/Asstes/trade.png" Width="26" Cursor="Hand" ToolTip="{Binding Resources.Auth_Trade,Source={x:Static services:ResourceService.Current},Mode=OneWay}" Visibility="{Binding ElementName=u,Path=DataContext.IsEdit,Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
<Image Source="/Resources/Asstes/trade.png" Width="27" Cursor="Hand" ToolTip="{Binding Resources.Auth_Trade,Source={x:Static services:ResourceService.Current},Mode=OneWay}" Visibility="{Binding ElementName=u,Path=DataContext.IsEdit,Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="MouseLeftButtonUp">
|
||||
<livet:LivetCallMethodAction
|
||||
@@ -174,7 +174,7 @@
|
||||
MethodTarget="{Binding DataContext,ElementName=u}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</Image>-->
|
||||
</Image>
|
||||
<Separator Opacity="0" Width="5"/>
|
||||
<Image Source="/Resources/Asstes/seek.png" Width="24" Cursor="Hand" ToolTip="{Binding Resources.Auth_See,Source={x:Static services:ResourceService.Current},Mode=OneWay}" Visibility="{Binding ElementName=u,Path=DataContext.IsEdit,Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
<i:Interaction.Triggers>
|
||||
|
||||
@@ -161,8 +161,7 @@
|
||||
<LineBreak/>
|
||||
<LineBreak />
|
||||
<Run Text=" "></Run>
|
||||
<Run Text="4.Steam本地两步身份验证器,可以使您不用启动移动版Steam App也能查看您的令牌。" />
|
||||
<Run Text="(暂时还不支持进行市场交易确认,计划后续添加支持)"/>
|
||||
<Run Text="4.Steam本地两步身份验证器,可以使您不用启动移动版Steam App也能查看您的令牌,也支持市场交易报价确认。" />
|
||||
<LineBreak/>
|
||||
<LineBreak />
|
||||
<Run Text=" "></Run>
|
||||
@@ -179,8 +178,11 @@
|
||||
<LineBreak/>
|
||||
<LineBreak />
|
||||
<Run Text=" "></Run>
|
||||
<Run Text="Steam皮肤的可视化设计编辑功能。" />
|
||||
<Run Text="(挖坑画大饼,可视化编辑Steam皮肤,而且如果软件能上架Steam的话打算支持创意工坊分享设计的Steam皮肤,短期内肯定做不完...)"></Run>
|
||||
<Run Text="Steam Edit功能,编辑Steam库内的游戏名字和部分信息。" />
|
||||
<LineBreak/>
|
||||
<LineBreak />
|
||||
<Run Text=" "></Run>
|
||||
<Run Text="每周的EPIC游戏自动领取" />
|
||||
<LineBreak/>
|
||||
<LineBreak />
|
||||
<Run Text=" "></Run>
|
||||
|
||||
@@ -451,7 +451,7 @@
|
||||
</Grid>
|
||||
|
||||
<!--Footer-->
|
||||
<controls:StatusBar Grid.Row="3" DataContext="{Binding StatusBar}" >
|
||||
<controls:StatusBar Grid.Row="3" DataContext="{Binding}" >
|
||||
</controls:StatusBar>
|
||||
</Grid>
|
||||
</metro:MetroWindow>
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
</ScrollViewer>
|
||||
|
||||
<!--Footer-->
|
||||
<controls:StatusBar Grid.Row="2" DataContext="{Binding StatusBar}">
|
||||
<controls:StatusBar Grid.Row="2" DataContext="{Binding}">
|
||||
</controls:StatusBar>
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
mc:Ignorable="d"
|
||||
Width="600"
|
||||
Height="400"
|
||||
x:Name="u"
|
||||
IsRestoringWindowPlacement="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Title="{Binding Title}"
|
||||
@@ -26,7 +27,7 @@
|
||||
UseLayoutRounding="True"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
SnapsToDevicePixels="True"
|
||||
d:DataContext="{d:DesignInstance viewModel:ShowAuthWindowViewModel}">
|
||||
d:DataContext="{d:DesignInstance viewModel:AuthTradeWindowViewModel}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="ContentRendered">
|
||||
<livet:LivetCallMethodAction MethodTarget="{Binding}"
|
||||
@@ -65,6 +66,7 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
@@ -79,7 +81,29 @@
|
||||
Foreground="{DynamicResource ForegroundBrushKey}"
|
||||
FontSize="16"
|
||||
VerticalAlignment="Center" />
|
||||
<metro:SystemButtons Grid.Column="2"
|
||||
<StackPanel Height="32" VerticalAlignment="Top" Orientation="Horizontal" Grid.Column="2" WindowChrome.IsHitTestVisibleInChrome="True" Visibility="{Binding IsLoggedIn,Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<metro:CaptionButton >
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<livet:LivetCallMethodAction
|
||||
MethodName="Refresh_Click"
|
||||
MethodTarget="{Binding}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<Image Source="/Resources/Asstes/refresh.png" Margin="6,0" Width="21" ToolTip="{Binding Resources.Refresh,Source={x:Static services:ResourceService.Current}, Mode=OneWay}" />
|
||||
</metro:CaptionButton>
|
||||
<metro:CaptionButton >
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<livet:LivetCallMethodAction
|
||||
MethodName="Logout_Click"
|
||||
MethodTarget="{Binding}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<Image Source="/Resources/Asstes/logout.png" Margin="6,0" Width="21" ToolTip="{Binding Resources.Logout,Source={x:Static services:ResourceService.Current}, Mode=OneWay}" />
|
||||
</metro:CaptionButton>
|
||||
</StackPanel>
|
||||
<metro:SystemButtons Grid.Column="3"
|
||||
Grid.Row="0"
|
||||
VerticalAlignment="Top" />
|
||||
</Grid>
|
||||
@@ -108,7 +132,8 @@
|
||||
HorizontalAlignment="Left"
|
||||
MethodTarget="{Binding}"
|
||||
MethodName="LoginButton_Click"></metro2:CallMethodButton>
|
||||
<TextBlock Text="确认交易需要您登陆您的Steam账号" Style="{StaticResource DetailTextStyleKey}"></TextBlock>
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
<TextBlock Text="确认交易需要您登陆您的Steam账号,程序不会记录你的账号密码,只会保存登录的状态以便每次使用。" Style="{StaticResource DetailTextStyleKey}"></TextBlock>
|
||||
<StackPanel Margin="8" Visibility="{Binding IsRequiresCaptcha,Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<WrapPanel>
|
||||
<Border BorderBrush="{DynamicResource AccentBrushKey}" Width="206" Height="37" HorizontalAlignment="Left" BorderThickness=".99">
|
||||
@@ -119,20 +144,88 @@
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
<metro:PromptTextBox Text="{Binding CodeImageChar}" Prompt="输入图中的验证码" Width="206" HorizontalAlignment="Left"></metro:PromptTextBox>
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
<metro2:CallMethodButton Content="确定" Width="200" Height="30" HorizontalAlignment="Left"></metro2:CallMethodButton>
|
||||
<metro2:CallMethodButton Content="确定" Width="200" Height="30" HorizontalAlignment="Left" MethodTarget="{Binding}"
|
||||
MethodName="CaptchaButton_Click"></metro2:CallMethodButton>
|
||||
<Separator Opacity="0" Height="5"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<DockPanel Visibility="{Binding IsLoggedIn,Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<DockPanel Margin="8" Grid.Row="1" Visibility="{Binding IsLoggedIn,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<StackPanel DockPanel.Dock="Top">
|
||||
<DockPanel>
|
||||
<!--<CheckBox Margin="0,0,10,0"></CheckBox>
|
||||
<metro2:CallMethodButton Margin="0,0,10,0" Content="确认选中" Height="30" MethodName="CancelAllButton_Click"
|
||||
MethodTarget="{Binding}"></metro2:CallMethodButton>
|
||||
<metro2:CallMethodButton Margin="0,0,10,0" Content="否认选中" Height="30"
|
||||
MethodName="ConfirmAllButton_Click"
|
||||
MethodTarget="{Binding}"></metro2:CallMethodButton>-->
|
||||
<WrapPanel FlowDirection="RightToLeft" HorizontalAlignment="Right">
|
||||
<metro2:CallMethodButton Margin="0,0,10,0" Content="取消所有交易" Height="30"
|
||||
MethodName="CancelAllButton_Click"
|
||||
MethodTarget="{Binding}"></metro2:CallMethodButton>
|
||||
<metro2:CallMethodButton Margin="0,0,10,0" Content="确认所有交易" Height="30" MethodName="ConfirmAllButton_Click"
|
||||
MethodTarget="{Binding}"></metro2:CallMethodButton>
|
||||
</WrapPanel>
|
||||
</DockPanel>
|
||||
<Rectangle Height=".99"
|
||||
Fill="{DynamicResource InactiveForegroundBrushKey}"
|
||||
Margin="0,8" />
|
||||
</StackPanel>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl Foreground="{DynamicResource ActiveForegroundBrushKey}"
|
||||
ItemsSource="{Binding Authenticators,Source={x:Static services:AuthService.Current},Mode=OneWay}">
|
||||
|
||||
ItemsSource="{Binding Confirmations,Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
|
||||
<!--<CheckBox Margin="0,0,5,0"></CheckBox>-->
|
||||
<Image Source="{Binding Image,Mode=OneWay}"
|
||||
Width="36" Height="36" Margin="0,0,5,0"></Image>
|
||||
<TextBlock>
|
||||
<Run Text="{Binding Details,Mode=OneWay}" FontSize="12"/>
|
||||
<LineBreak/>
|
||||
<Run Text="{Binding Traded,Mode=OneWay}"/>
|
||||
<LineBreak/>
|
||||
<Run Text="{Binding When,Mode=OneWay}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<WrapPanel Orientation="Vertical" DockPanel.Dock="Right" VerticalAlignment="Center" FlowDirection="RightToLeft">
|
||||
<metro2:CallMethodButton
|
||||
MethodName="ConfirmTrade_Click"
|
||||
MethodParameter="{Binding}"
|
||||
MethodTarget="{Binding DataContext,ElementName=u}">
|
||||
<DockPanel>
|
||||
<Image Source="/Resources/Asstes/confirm.png" Width="20" VerticalAlignment="Center" Margin="0,0,5,0"
|
||||
ToolTip="{Binding Resources.Auth_Add,Source={x:Static services:ResourceService.Current},Mode=OneWay}">
|
||||
</Image>
|
||||
<TextBlock Text="确认"></TextBlock>
|
||||
</DockPanel>
|
||||
</metro2:CallMethodButton>
|
||||
<metro2:CallMethodButton
|
||||
MethodName="CancelTrade_Click"
|
||||
MethodParameter="{Binding}"
|
||||
MethodTarget="{Binding DataContext,ElementName=u}">
|
||||
<DockPanel>
|
||||
<Image Source="/Resources/Asstes/delete.png" Width="20"
|
||||
VerticalAlignment="Center" Margin="0,0,5,0"
|
||||
ToolTip="{Binding Resources.Auth_Add,Source={x:Static services:ResourceService.Current},Mode=OneWay}">
|
||||
</Image>
|
||||
<TextBlock Text="取消"></TextBlock>
|
||||
</DockPanel>
|
||||
</metro2:CallMethodButton>
|
||||
</WrapPanel>
|
||||
</DockPanel>
|
||||
<Rectangle DockPanel.Dock="Bottom" Height=".99"
|
||||
Fill="{DynamicResource InactiveForegroundBrushKey}"
|
||||
Margin="0,8" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
<!--Footer-->
|
||||
<controls:StatusBar Grid.Row="2" DataContext="{Binding StatusBar}">
|
||||
<controls:StatusBar Grid.Row="2" DataContext="{Binding}">
|
||||
</controls:StatusBar>
|
||||
</Grid>
|
||||
</metro:MetroWindow>
|
||||
|
||||
@@ -10,6 +10,40 @@
|
||||
// ==/UserScript==
|
||||
|
||||
var unsafeWindow = this;
|
||||
function GM_xmlhttpRequest(details)
|
||||
{
|
||||
|
||||
function GM_xmlhttpRequest(option) {
|
||||
if (String(option) !== '[object Object]') return undefined
|
||||
option.method = option.method ? option.method.toUpperCase() : 'GET'
|
||||
option.data = option.data || {}
|
||||
var formData = []
|
||||
for (var key in option.data) {
|
||||
formData.push(''.concat(key, '=', option.data[key]))
|
||||
}
|
||||
option.data = formData.join('&')
|
||||
|
||||
if (option.method === 'GET') {
|
||||
option.url += location.search.length === 0 ? ''.concat('?', option.data) : ''.concat('&', option.data)
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = option.timeout;
|
||||
xhr.responseType = option.responseType || 'json'
|
||||
xhr.onload = (e) => {
|
||||
if (option.onload && typeof option.onload === 'function')
|
||||
{
|
||||
option.onload(e.target)
|
||||
}
|
||||
};
|
||||
xhr.onerror = option.onerror;
|
||||
xhr.ontimeout = option.ontimeout;
|
||||
xhr.open(option.method, option.url, true)
|
||||
if (option.method === 'POST') {
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
|
||||
}
|
||||
if (option.headers) {
|
||||
Object.keys(option.headers).forEach(function (key) {
|
||||
xhr.setRequestHeader(key, option.headers[key]);
|
||||
});
|
||||
}
|
||||
xhr.send(option.method === 'POST' ? option.data : null)
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
// ==UserScript==
|
||||
// @name Steam历史最低价格查询
|
||||
// @namespace SteamHistoryLowestPrice
|
||||
// @description 在steam商店页显示当前app历史最低价格及进包次数
|
||||
// @include https://store.steampowered.com/app/*
|
||||
// @include https://store.steampowered.com/bundle/*
|
||||
// @include https://store.steampowered.com/sub/*
|
||||
// @author 软妹币玩家、byzod
|
||||
// @license GPL version 3 or any later version
|
||||
// @version 1.1
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @enable true
|
||||
// jshint esversion:6
|
||||
// ==/UserScript==
|
||||
|
||||
// 显示样式
|
||||
// 0 = 显示在购买按钮上面
|
||||
// 1 = 显示在购买信息框上面
|
||||
const INFO_STYLE = 1;
|
||||
|
||||
// 货币区域覆盖,两个字母的国家代号,大小写均可
|
||||
// 空字符("")代表不覆盖,使用steam的cookie中steamCountry的值
|
||||
// 见 https://zh.wikipedia.org/wiki/ISO_3166-1 或 https://en.wikipedia.org/wiki/ISO_3166-1
|
||||
// 常用 美国USD:"us", 中国CNY: "cn", 英国GBP: "uk", 日本JPY: "jp", 俄国RUS: "ru"
|
||||
const CC_OVERRIDE = "";
|
||||
|
||||
// 货币符号
|
||||
const CURRENCY_SYMBOLS = {
|
||||
'AED': 'DH',
|
||||
'AUD': 'A$',
|
||||
'BRL': 'R$',
|
||||
'CAD': 'CDN$',
|
||||
'CHF': 'CHF',
|
||||
'CLP': 'CLP$',
|
||||
'CNY': '¥', // Chines Yuan
|
||||
'COP': 'COL$',
|
||||
'CRC': '₡', // Costa Rican Colón
|
||||
'EUR': '€', // Euro
|
||||
'GBP': '£', // British Pound Sterling
|
||||
'HKD': 'HK$',
|
||||
'IDR': 'Rp',
|
||||
'ILS': '₪', // Israeli New Sheqel
|
||||
'INR': '₹', // Indian Rupee
|
||||
'JPY': '¥', // Japanese Yen
|
||||
'KRW': '₩', // South Korean Won
|
||||
'MXN': 'Mex$',
|
||||
'MYR': 'RM',
|
||||
'NGN': '₦', // Nigerian Naira
|
||||
'NOK': 'kr',
|
||||
'NZD': 'NZ$',
|
||||
'PEN': 'S/.',
|
||||
'PHP': '₱', // Philippine Peso
|
||||
'PLN': 'zł', // Polish Zloty
|
||||
'PYG': '₲', // Paraguayan Guarani
|
||||
'RUB': 'pуб',
|
||||
'SAR': 'SR',
|
||||
'SGD': 'S$',
|
||||
'THB': '฿', // Thai Baht
|
||||
'TRY': 'TL',
|
||||
'TWD': 'NT$',
|
||||
'UAH': '₴', // Ukrainian Hryvnia
|
||||
'USD': '$', // US Dollar
|
||||
'VND': '₫', // Vietnamese Dong
|
||||
'ZAR': 'R ',
|
||||
};
|
||||
|
||||
// 查询历史低价包括的商店
|
||||
const STORES = [
|
||||
"steam",
|
||||
// "amazonus",
|
||||
// "impulse",
|
||||
// "gamersgate",
|
||||
// "direct2drive",
|
||||
// "origin",
|
||||
// "uplay",
|
||||
// "indiegalastore",
|
||||
// "gamesplanet",
|
||||
// "indiegamestand",
|
||||
// "gog",
|
||||
// "nuuvem",
|
||||
// "dlgamer",
|
||||
// "humblestore",
|
||||
// "squenix",
|
||||
// "bundlestars",
|
||||
// "fireflower",
|
||||
// "humblewidgets",
|
||||
// "newegg",
|
||||
// "coinplay",
|
||||
// "wingamestore",
|
||||
// "macgamestore",
|
||||
// "gamebillet",
|
||||
// "silagames",
|
||||
// "itchio",
|
||||
// "gamejolt",
|
||||
// "paradox"
|
||||
];
|
||||
|
||||
|
||||
// 在app页和愿望单页显示史低价格
|
||||
let urlMatch = location.href.match(/(app|sub|bundle)\/(\d+)/);
|
||||
let appId = "";
|
||||
let type = "";
|
||||
let subIds = [];
|
||||
let bundleids = [];
|
||||
if (urlMatch && urlMatch.length == 3) {
|
||||
type = urlMatch[1]
|
||||
appId = urlMatch[2];
|
||||
}
|
||||
|
||||
// console.log('[史低]: ' + type + ' : ' + appId + ', requesting data info...'); // DEBUG
|
||||
|
||||
// 获取subs
|
||||
document.querySelectorAll("input[name=subid]")
|
||||
.forEach(sub => subIds.push(sub.value));
|
||||
// 获取bundles
|
||||
document.querySelectorAll("input[name=bundleid]")
|
||||
.forEach(sub => bundleids.push(sub.value));
|
||||
|
||||
let cc = "cn";
|
||||
if (CC_OVERRIDE.length > 0) {
|
||||
// 使用覆盖的货币区域
|
||||
cc = CC_OVERRIDE;
|
||||
} else {
|
||||
// 使用默认的的货币区域
|
||||
let ccMatch = document.cookie.match(/steamCountry=([a-z]{2})/i);
|
||||
if (ccMatch !== null && ccMatch.length == 2) {
|
||||
cc = ccMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
AddLowestPriceTag(appId, type, subIds, bundleids, STORES.join(","), cc, location.protocol);
|
||||
|
||||
// 在商店页添加史低信息
|
||||
async function AddLowestPriceTag(appId, type = "app", subIds = [], bundleids = [], stores = "steam", cc = "cn", protocol = "https") {
|
||||
// 史低信息容器们
|
||||
let lowestPriceNodes = {};
|
||||
|
||||
// 统计subid
|
||||
let findSubIds = [];
|
||||
if (type == "bundle") {
|
||||
// bundle就一个, 视作subid
|
||||
findSubIds.push(appId);
|
||||
} else if (type == "app" || type == "sub") {
|
||||
// app/sub/bundle 可能有好多
|
||||
findSubIds = subIds.slice();
|
||||
if (bundleids.length > 0) {
|
||||
findSubIds.push.apply(findSubIds, bundleids);
|
||||
}
|
||||
}
|
||||
|
||||
// 寻找每一个subid的购买按钮,生成史低信息容器们
|
||||
findSubIds.forEach(subId => {
|
||||
let gameWrapper = null;
|
||||
try {
|
||||
gameWrapper = document.querySelector('.game_area_purchase_game input[value="' + subId + '"]');
|
||||
switch (INFO_STYLE) {
|
||||
case 0:
|
||||
gameWrapper = gameWrapper.parentNode.parentNode.querySelector('.game_purchase_action');
|
||||
break;
|
||||
case 1:
|
||||
gameWrapper = gameWrapper.parentNode.parentNode;
|
||||
break;
|
||||
}
|
||||
} catch (ex) {
|
||||
gameWrapper = null;
|
||||
}
|
||||
if (gameWrapper) {
|
||||
let lowestInfo = document.createElement("div");
|
||||
lowestInfo.className = "game_lowest_price";
|
||||
lowestInfo.innerText = "正在读取历史最低价格...";
|
||||
switch (INFO_STYLE) {
|
||||
case 0:
|
||||
gameWrapper.prepend(lowestInfo);
|
||||
break;
|
||||
case 1:
|
||||
gameWrapper.append(lowestInfo);
|
||||
break;
|
||||
}
|
||||
lowestPriceNodes[subId] = lowestInfo;
|
||||
}
|
||||
});
|
||||
|
||||
// 获取sub们的数据
|
||||
let data = null;
|
||||
try {
|
||||
data = await GettingSteamDBAppInfo(appId, type, subIds, stores, cc, protocol);
|
||||
if ((typeof data == 'string'))
|
||||
data = JSON.parse(data);
|
||||
if (data.result == 'success') {
|
||||
data = data.data;
|
||||
} else {
|
||||
console.log('[史低]: ' + err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[史低]: ' + err);
|
||||
}
|
||||
|
||||
// console.log('[史低]: app ' + appId + ' data : %o', data); // DEBUG
|
||||
|
||||
// 解析data
|
||||
let appInfos = [];
|
||||
let metaInfo = data ? data[".meta"] : null;
|
||||
// 如果是bundle, 除了.meta外只有一个bundle/xxx,否则是一大堆xxx
|
||||
if (type == "bundle") {
|
||||
appInfos.push({ Id: appId, Info: data["bundle/" + appId] });
|
||||
} else if (type == "app" || type == "sub") {
|
||||
data = data.data;
|
||||
for (let key in data) {
|
||||
let appid = key.replace(new RegExp('(app|sub|bundle)/'), "");
|
||||
if (!isNaN(appid)) {
|
||||
appInfos.push({ Id: appid, Info: data[key] });
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log('[史低]: app ' + appId + ' metaInfo: %o', metaInfo); // DEBUG
|
||||
// console.log('[史低]: app ' + appId + ' appInfos: %o', appInfos); // DEBUG
|
||||
|
||||
// 如果查到info,塞到购买按钮上面去
|
||||
if (metaInfo && appInfos.length > 0) {
|
||||
// 获取整体信息
|
||||
let currencySymbol = metaInfo.currency in CURRENCY_SYMBOLS
|
||||
? CURRENCY_SYMBOLS[metaInfo.currency]
|
||||
: metaInfo.currency;
|
||||
|
||||
// 为每一个sub或bundle添加史低
|
||||
appInfos.forEach(app => {
|
||||
let lowestInfo = lowestPriceNodes[app.Id];
|
||||
|
||||
if (lowestInfo) {
|
||||
lowestInfo.innerHTML =
|
||||
// 历史最低
|
||||
'历史最低价是 '
|
||||
+ '<span style="cursor:help;text-decoration:underline;" title="' + app.Info.lowest.recorded_formatted + '">'
|
||||
+ new Date(app.Info.lowest.recorded * 1e3).toLocaleDateString()
|
||||
+ '</span> 时在 '
|
||||
+ '<a target="_blank" href="' + app.Info.lowest.url + '"> '
|
||||
+ app.Info.lowest.store
|
||||
+ '</a> 中的 '
|
||||
+ '<span class="discount_pct">-' + app.Info.lowest.cut + '%</span>'
|
||||
+ '<a target="_blank" title="查看价格历史" href="' + app.Info.urls.history + '"> '
|
||||
+ currencySymbol + ' ' + app.Info.lowest.price
|
||||
+ '</a>'
|
||||
|
||||
// 第二行
|
||||
+ '<br />'
|
||||
|
||||
// 进包次数
|
||||
+ '进包 <a target="_blank" title="查看进包信息" href="' + app.Info.urls.bundles + '"'
|
||||
+ (app.Info.bundles && app.Info.bundles.live.length > 0
|
||||
? ' style="color:#0d0" title="' + app.Info.bundles.live.length + ' 个正在销售的慈善包"'
|
||||
: '')
|
||||
+ '> '
|
||||
+ app.Info.bundles.count
|
||||
+ ' </a> 次,'
|
||||
|
||||
// 当前最低
|
||||
+ (app.Info.price.price <= app.Info.lowest.price
|
||||
? '<span class="game_purchase_discount_countdown">当前为历史最低价</span>,'
|
||||
: '<span>当前最低价是</span>')
|
||||
+ '在 '
|
||||
+ '<a target="_blank" href="' + app.Info.price.url + '"> '
|
||||
+ app.Info.price.store
|
||||
+ '</a> 中的 '
|
||||
+ '<span class="discount_pct">-' + app.Info.price.cut + '%</span>'
|
||||
+ '<a target="_blank" title="查看价格信息" href="' + app.Info.urls.info + '"> '
|
||||
+ currencySymbol + ' ' + app.Info.price.price
|
||||
+ '</a>';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// metaInfo为空,或者appInfos无内容
|
||||
console.log('[史低]: get lowest price failed, data = %o', data);
|
||||
for (let id in lowestPriceNodes) {
|
||||
lowestPriceNodes[id].innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 返回史低info
|
||||
return Promise.resolve(lowestPriceNodes);
|
||||
}
|
||||
|
||||
// 获取史低信息
|
||||
async function GettingSteamDBAppInfo(appId, type = "app", subIds = [], stores = "steam", cc = "cn", protocol = "https") {
|
||||
let requestPromise = null;
|
||||
let bundleId = "";
|
||||
|
||||
if (type == "bundle") {
|
||||
bundleId = appId;
|
||||
} else if (type == "app" || type == "sub") {
|
||||
bundleId = bundleids.join(',');
|
||||
}
|
||||
if (!isNaN(appId) && parseInt(appId) > 0) {
|
||||
let requestUrl = protocol + "//esapi.isthereanydeal.com/v01/prices/?"
|
||||
+ "bundleids=" + bundleId
|
||||
+ "&subids=" + subIds.join(',')
|
||||
+ "&appids=" + appId
|
||||
+ "&stores=" + stores
|
||||
+ "&cc=" + cc
|
||||
+ "&coupon=true";
|
||||
// console.log('[史低]: requestUrl: ' + requestUrl); // DEBUG
|
||||
requestPromise = new Promise((resolve, reject) => {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: requestUrl,
|
||||
onload: function (response) {
|
||||
resolve(response.response);
|
||||
},
|
||||
onerror: function (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
requestPromise = Promise.reject("Invalid appid");
|
||||
}
|
||||
|
||||
return requestPromise;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ let conf = {
|
||||
};
|
||||
|
||||
let temp = {};
|
||||
let blockingWaitDialog;
|
||||
let blockingWaitDialog;
|
||||
|
||||
function init() {
|
||||
conf = JSON.parse(localStorage.getItem("STEAMCC_CONF")) || conf;
|
||||
@@ -133,7 +133,7 @@ function anonymousAccess(region) {
|
||||
function access(region) {
|
||||
blockingWaitDialog = blockingWaitDialog || ShowBlockingWaitDialog("匿名访问中", `${region} 区域匿名数据获取中...`);
|
||||
|
||||
let url = `${location.protocol + "//www.steampowered.com" + location.pathname.replace( /\/agecheck/, "" ) + (location.search == "" ? "?" : (location.search + "&"))}cc=${region}`;
|
||||
let url = `${location.protocol + "//store.steampowered.com" + location.pathname.replace( /\/agecheck/, "" ) + (location.search == "" ? "?" : (location.search + "&"))}cc=${region}`;
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method:"GET",
|
||||
|
||||
Reference in New Issue
Block a user