Skip to content

Commit

Permalink
新增 EVENT EVENTCHECK 命令, 秋促批量投票
Browse files Browse the repository at this point in the history
使用方法参见 README.md
更新版本 1.5.7.194 -> 1.5.8.208
  • Loading branch information
chr233 committed Nov 25, 2021
1 parent af1f3c2 commit 77567c2
Show file tree
Hide file tree
Showing 13 changed files with 439 additions and 4 deletions.
21 changes: 21 additions & 0 deletions ASFEnhance/ASFEnhance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ public void OnLoaded()
case "CA":
return await Cart.Command.ResponseGetCartGames(steamID, "ASF").ConfigureAwait(false);

//EVENT
case "EVENT":
case "E":
return await Event.Command.ResponseSteamEvents(bot, steamID, "").ConfigureAwait(false);

case "EVENTCHECK":
case "EC":
return await Event.Command.ResponseCheckSummerBadge(bot, steamID).ConfigureAwait(false);

//Cart
case "CART":
case "C":
Expand Down Expand Up @@ -96,6 +105,18 @@ public void OnLoaded()
case "P":
return await bot.Commands.Response(steamID, "POINTS " + Utilities.GetArgsAsText(message, 1)).ConfigureAwait(false);

//Event
case "EVENT" when args.Length > 2:
case "E" when args.Length > 2:
return await Event.Command.ResponseSteamEvents(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
case "EVENT":
case "E":
return await Event.Command.ResponseSteamEvents(bot, steamID, args[1]).ConfigureAwait(false);

case "EVENTCHECK":
case "EC":
return await Event.Command.ResponseCheckSummerBadge(steamID, Utilities.GetArgsAsText(message, 1)).ConfigureAwait(false);

//WishList
case "ADDWISHLIST" when args.Length > 2:
case "AW" when args.Length > 2:
Expand Down
3 changes: 3 additions & 0 deletions ASFEnhance/ASFEnhance.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<NoWarn />
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Data\AppDetails.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions ASFEnhance/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Reflection;

[assembly: System.CLSCompliant(false)]
[assembly: AssemblyVersion("1.5.7.194")]
[assembly: AssemblyFileVersion("1.5.7.194")]
[assembly: AssemblyVersion("1.5.8.208")]
[assembly: AssemblyFileVersion("1.5.8.208")]

[assembly: AssemblyCopyright("Copyright © 2021 Chr_")]
[assembly: AssemblyProduct("ASFEnhance")]
Expand Down
53 changes: 53 additions & 0 deletions ASFEnhance/Data/AppDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SteamKit2;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Chrxw.ASFEnhance.Data
{
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal sealed class AppDetailsResponse
{
[JsonExtensionData]
private IDictionary<string, JToken> _additionalData;
}
internal sealed class AppDetailsPayload
{
[JsonProperty(PropertyName = "success", Required = Required.Always)]
public EResult Result { get; private set; }

[JsonProperty(PropertyName = "data", Required = Required.DisallowNull)]
public AppDetailsData Data { get; private set; }

[JsonProperty(PropertyName = "dlc", Required = Required.DisallowNull)]
public AppDetailsDlcs Dlc { get; private set; }

[JsonProperty(PropertyName = "discount", Required = Required.DisallowNull)]
public int Discount { get; private set; }
}

internal sealed class AppDetailsData
{
[JsonProperty(PropertyName = "type", Required = Required.Always)]
public EResult Result { get; private set; }

[JsonProperty(PropertyName = "name", Required = Required.DisallowNull)]
public int BasePrice { get; private set; }

[JsonProperty(PropertyName = "steam_appid", Required = Required.DisallowNull)]
public int Tax { get; private set; }

[JsonProperty(PropertyName = "required_age", Required = Required.DisallowNull)]
public int Discount { get; private set; }

[JsonProperty(PropertyName = "is_free", Required = Required.DisallowNull)]
public bool IsFree { get; private set; }
}
internal sealed class AppDetailsDlcs
{
[JsonExtensionData]
private IDictionary<int, int> Dlcs;
}

}
167 changes: 167 additions & 0 deletions ASFEnhance/Event/Command.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#pragma warning disable CS8632 // 只能在 "#nullable" 注释上下文内的代码中使用可为 null 的引用类型的注释。

using ArchiSteamFarm.Core;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Steam.Storage;
using Chrxw.ASFEnhance.Localization;
using SteamKit2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static Chrxw.ASFEnhance.Event.Response;
using static Chrxw.ASFEnhance.Utils;

namespace Chrxw.ASFEnhance.Event
{
internal static class Command
{
internal static string Boolen2String(bool value)
{
return value ? "√" : "×";
}
// 秋促投票
internal static async Task<string?> ResponseSteamEvents(Bot bot, ulong steamID, string gameIDs)
{
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount)
{
throw new ArgumentOutOfRangeException(nameof(steamID));
}

if (!bot.HasAccess(steamID, BotConfig.EAccess.Operator))
{
return null;
}

if (!bot.IsConnectedAndLoggedOn)
{
return FormatBotResponse(bot, Strings.BotNotConnected);
}

string[] entries = gameIDs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

List<uint> intGamsIDs = new();

foreach (string entry in entries)
{
if (uint.TryParse(entry, out uint choice))
{
intGamsIDs.Add(choice);
if (intGamsIDs.Count >= 10)
{
break;
}
}
}

if (intGamsIDs.Count < 10) //不足10个游戏自动补齐
{
Random rd = new();
uint[] defaultGames = new uint[] { 1639930, 1506980, 1374480, 585020, 1639230, 1584090, 1111460, 977880, 1366540, 1398740, 1369630, 1195290 };
while (intGamsIDs.Count < 10)
{
intGamsIDs.Add(defaultGames[rd.Next(defaultGames.Length)]);
}
}

for (int i = 0; i < 10; i++)
{
int categoryID = 61 + i;
await WebRequest.MakeVote(bot, intGamsIDs[i], categoryID).ConfigureAwait(false);
}

SummerBadgeResponse? summerBadgeStatus = await WebRequest.CheckSummerBadge(bot).ConfigureAwait(false);

if (summerBadgeStatus == null)
{
return FormatBotResponse(bot, Langs.EventReadBadgeStatusFailed);
}

return FormatBotResponse(bot, string.Format(CurrentCulture, Langs.EventVoteResponse, Boolen2String(summerBadgeStatus.VoteOne), Boolen2String(summerBadgeStatus.VoteAll)));
}

// 秋促投票(多个Bot)
internal static async Task<string?> ResponseSteamEvents(ulong steamID, string botNames, string choose)
{
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount)
{
throw new ArgumentOutOfRangeException(nameof(steamID));
}

if (string.IsNullOrEmpty(botNames))
{
throw new ArgumentNullException(nameof(botNames));
}

HashSet<Bot>? bots = Bot.GetBots(botNames);

if ((bots == null) || (bots.Count == 0))
{
return ASF.IsOwner(steamID) ? FormatStaticResponse(string.Format(CurrentCulture, Strings.BotNotFound, botNames)) : null;
}

IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseSteamEvents(bot, steamID, choose))).ConfigureAwait(false);

List<string> responses = new(results.Where(result => !string.IsNullOrEmpty(result))!);

return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}

// 检查秋促徽章
internal static async Task<string?> ResponseCheckSummerBadge(Bot bot, ulong steamID)
{
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount)
{
throw new ArgumentOutOfRangeException(nameof(steamID));
}

if (!bot.HasAccess(steamID, BotConfig.EAccess.Operator))
{
return null;
}

if (!bot.IsConnectedAndLoggedOn)
{
return FormatBotResponse(bot, Strings.BotNotConnected);
}

SummerBadgeResponse? summerBadgeStatus = await WebRequest.CheckSummerBadge(bot).ConfigureAwait(false);

if (summerBadgeStatus == null)
{
return FormatBotResponse(bot, Langs.EventReadBadgeStatusFailed);
}

return FormatBotResponse(bot, string.Format(CurrentCulture, Langs.EventCheckResponse, Boolen2String(summerBadgeStatus.VoteOne), Boolen2String(summerBadgeStatus.VoteAll), Boolen2String(summerBadgeStatus.PlayOne), Boolen2String(summerBadgeStatus.ReviewOne)));
}

// 秋促投票(多个Bot)
internal static async Task<string?> ResponseCheckSummerBadge(ulong steamID, string botNames)
{
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount)
{
throw new ArgumentOutOfRangeException(nameof(steamID));
}

if (string.IsNullOrEmpty(botNames))
{
throw new ArgumentNullException(nameof(botNames));
}

HashSet<Bot>? bots = Bot.GetBots(botNames);

if ((bots == null) || (bots.Count == 0))
{
return ASF.IsOwner(steamID) ? FormatStaticResponse(string.Format(CurrentCulture, Strings.BotNotFound, botNames)) : null;
}

IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseCheckSummerBadge(bot, steamID))).ConfigureAwait(false);

List<string> responses = new(results.Where(result => !string.IsNullOrEmpty(result))!);

return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}

}
}
25 changes: 25 additions & 0 deletions ASFEnhance/Event/Response.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Chrxw.ASFEnhance.Event
{
internal class Response
{
//秋促徽章信息
internal class SummerBadgeResponse
{
//提名一项奖项
public bool VoteOne { get; }
//提名全部奖项
public bool VoteAll { get; }
//玩一款提名游戏
public bool PlayOne { get; }
//评测一款提名游戏
public bool ReviewOne { get; }
public SummerBadgeResponse(bool VoteOne = false, bool VoteAll = false, bool PlayOne = false, bool ReviewOne = false)
{
this.VoteOne = VoteOne;
this.VoteAll = VoteAll;
this.PlayOne = PlayOne;
this.ReviewOne = ReviewOne;
}
}
}
}
76 changes: 76 additions & 0 deletions ASFEnhance/Event/WebRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#pragma warning disable CS8632 // 只能在 "#nullable" 注释上下文内的代码中使用可为 null 的引用类型的注释。

using AngleSharp.Dom;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Web.Responses;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static Chrxw.ASFEnhance.Event.Response;
using static Chrxw.ASFEnhance.Utils;

namespace Chrxw.ASFEnhance.Event
{
internal static class WebRequest
{
// 秋促投票
internal static async Task<bool?> MakeVote(Bot bot, uint gameID, int categoryID)
{
Uri request = new(SteamStoreURL, "/steamawards/nominategame");
Uri referer = new(SteamStoreURL, "/steamawards/category/63");

string? sessionID = bot.ArchiWebHandler.WebBrowser.CookieContainer.GetCookieValue(SteamStoreURL, "sessionid");

if (string.IsNullOrEmpty(sessionID))
{
bot.ArchiLogger.LogNullError(nameof(sessionID));
return false;
}

Dictionary<string, string> data = new(5, StringComparer.Ordinal)
{
{ "sessionid", sessionID! },
{ "nominatedid", gameID.ToString() },
{ "categoryid", categoryID.ToString() },
{ "source", "3" },
};

await bot.ArchiWebHandler.UrlPostWithSession(request, data: data, referer: referer).ConfigureAwait(false);

return true;
}

// 检查秋促徽章
internal static async Task<SummerBadgeResponse?> CheckSummerBadge(Bot bot)
{
Uri request = new(SteamCommunityURL, "/profiles/" + bot.SteamID.ToString() + "/badges/56");

HtmlDocumentResponse? response = await bot.ArchiWebHandler.UrlGetToHtmlDocumentWithSession(request, referer: SteamCommunityURL).ConfigureAwait(false);

if (response == null)
{
ASF.ArchiLogger.LogGenericInfo("null");
return null;
}

bool[] taskStatus = new bool[] { false, false, false, false };

for (int i = 0; i < 4; i++)
{
string xpath = string.Format("//div[@class='badge_task'][{0}]/img", i + 1);
IElement? eleTask = response.Content.SelectSingleNode(xpath);
string taskSrc = eleTask?.GetAttribute("src") ?? "";

if (string.IsNullOrEmpty(taskSrc))
{
ASF.ArchiLogger.LogNullError(string.Format("{0}", i));
continue;
}

taskStatus[i] = taskSrc.EndsWith("_on.png");
}
return new SummerBadgeResponse(taskStatus[0], taskStatus[1], taskStatus[2], taskStatus[3]);
}
}
}
Loading

0 comments on commit 77567c2

Please sign in to comment.