Skip to content

Commit

Permalink
feat 新增playtime命令
Browse files Browse the repository at this point in the history
  • Loading branch information
chr233 committed Oct 9, 2023
1 parent 0d3784e commit f6c862a
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 5 deletions.
15 changes: 13 additions & 2 deletions ASFEnhance/ASFEnhance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public Task OnLoaded()
{
//Event
"SIM4" when access >= EAccess.Operator =>
Event.Command.ResponseSim4(bot),
Event.Command.ResponseSim4(bot),

"DL2" when access >= EAccess.Operator =>
Event.Command.ResponseDL2(bot),
Expand All @@ -211,7 +211,7 @@ public Task OnLoaded()
Event.Command.ResponseRle(bot, null),

"CLAIMITEM" or
"CI" when access >= EAccess.Operator =>
"CI" when access >= EAccess.Operator =>
Event.Command.ResponseClaimItem(bot),

"CLAIM20TH" or
Expand Down Expand Up @@ -269,6 +269,10 @@ public Task OnLoaded()
"RG" when access >= EAccess.Operator =>
Account.Command.ResponseReceiveGift(bot),

"PLAYTIME" or
"PT" when access >= EAccess.Operator =>
Account.Command.ResponseGetPlayTime(bot, null),

//Cart
"CART" or
"C" when access >= EAccess.Operator =>
Expand Down Expand Up @@ -514,6 +518,13 @@ public Task OnLoaded()
"RG" when access >= EAccess.Operator =>
Account.Command.ResponseReceiveGift(Utilities.GetArgsAsText(args, 1, ",")),

"PLAYTIME" or
"PT" when argLength > 2 && access >= EAccess.Operator =>
Account.Command.ResponseGetPlayTime(args[1], Utilities.GetArgsAsText(args, 2, ",")),
"PLAYTIME" or
"PT" when access >= EAccess.Operator =>
Account.Command.ResponseGetPlayTime(bot, args[1]),

//Cart
"CART" or
"C" when access >= EAccess.Operator =>
Expand Down
124 changes: 123 additions & 1 deletion ASFEnhance/Account/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using ASFEnhance.Data;
using Microsoft.AspNetCore.Http;
using SteamKit2;
using System.Text;

Expand Down Expand Up @@ -862,8 +863,18 @@ private static string NotificationTargetToString(NotificationTarget target)
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}

/// <summary>
/// 手动接收礼物
/// </summary>
/// <param name="bot"></param>
/// <returns></returns>
internal static async Task<string?> ResponseReceiveGift(Bot bot)
{
if (!bot.IsConnectedAndLoggedOn)
{
return bot.FormatBotResponse(Strings.BotNotConnected);
}

var result = await WebRequest.GetReceivedGift(bot).ConfigureAwait(false);

if (result == null)
Expand All @@ -887,7 +898,7 @@ private static string NotificationTargetToString(NotificationTarget target)
}

/// <summary>
/// 获取账户封禁情况 (多个Bot)
/// 手动接收礼物 (多个Bot)
/// </summary>
/// <param name="botNames"></param>
/// <returns></returns>
Expand All @@ -912,4 +923,115 @@ private static string NotificationTargetToString(NotificationTarget target)

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

/// <summary>
/// 获取游玩时间
/// </summary>
/// <param name="bot"></param>
/// <returns></returns>
internal static async Task<string?> ResponseGetPlayTime(Bot bot, string? query)
{
if (!bot.IsConnectedAndLoggedOn)
{
return bot.FormatBotResponse(Strings.BotNotConnected);
}

(_, string? apiKey) = await bot.ArchiWebHandler.CachedApiKey.GetValue().ConfigureAwait(false);

if (string.IsNullOrEmpty(apiKey))
{
return bot.FormatBotResponse(Langs.NetworkError);
}

var result = await WebRequest.GetGamePlayTime(bot, apiKey).ConfigureAwait(false);

if (result == null)
{
return bot.FormatBotResponse(Langs.NetworkError);
}

var sb = new StringBuilder();

var appIds = new HashSet<uint>();
if (!string.IsNullOrEmpty(query))
{
var entries = query.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var entry in entries)
{
if (uint.TryParse(entry, out var appId))
{
appIds.Add(appId);
}
else
{
sb.AppendFormat("{0}: 无效的AppId", entry);
}
}
}

if (sb.Length > 0)
{
sb.AppendLine();
}

long twoWeekHours = 0;
long totalHours = 0;

if (appIds.Any())
{
foreach (var appId in appIds)
{
if (result.TryGetValue(appId, out var game))
{
sb.AppendLineFormat("{0}: 游玩时长 {2:F2}h 2周游玩时长 {3:F2}h [{1}]", appId, game.Name, game.PlayTimeForever / 60.0, game.PlayTime2Weeks / 60.0);
totalHours += game.PlayTimeForever;
twoWeekHours += game.PlayTime2Weeks;
}
else
{
sb.AppendLineFormat("{0}: 无游玩时长数据", appId);
}
}
}
else
{
sb.AppendLine("未指定游戏, 统计所有游戏");
foreach (var game in result.Values)
{
totalHours += game.PlayTimeForever;
twoWeekHours += game.PlayTime2Weeks;
}
}

sb.AppendLineFormat("累计游玩时长: {0:F2}h 2周游玩时长: {1:F2}h", totalHours / 60.0, twoWeekHours / 60.0);

return bot.FormatBotResponse(sb.ToString());
}

/// <summary>
/// 获取游玩时间 (多个Bot)
/// </summary>
/// <param name="botNames"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
internal static async Task<string?> ResponseGetPlayTime(string botNames, string? query)
{
if (string.IsNullOrEmpty(botNames))
{
throw new ArgumentNullException(nameof(botNames));
}

var bots = Bot.GetBots(botNames);

if (bots == null || bots.Count == 0)
{
return FormatStaticResponse(Strings.BotNotFound, botNames);
}

var results = await Utilities.InParallel(bots.Select(bot => ResponseGetPlayTime(bot, query))).ConfigureAwait(false);

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

return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
}
41 changes: 41 additions & 0 deletions ASFEnhance/Account/WebRequest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using AngleSharp.Dom;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Steam.Data;
Expand Down Expand Up @@ -326,6 +327,11 @@ internal static async Task<bool> RemoveLicense(Bot bot, uint subId)
return response?.Content;
}

/// <summary>
/// 获取礼物Id
/// </summary>
/// <param name="bot"></param>
/// <returns></returns>
internal static async Task<HashSet<ulong>?> GetReceivedGift(Bot bot)
{
var request = new Uri(SteamStoreURL, "/gifts");
Expand All @@ -335,6 +341,12 @@ internal static async Task<bool> RemoveLicense(Bot bot, uint subId)
return HtmlParser.ParseGiftPage(response);
}

/// <summary>
/// 接收礼物
/// </summary>
/// <param name="bot"></param>
/// <param name="giftId"></param>
/// <returns></returns>
internal static async Task<UnpackGiftResponse?> AcceptReceivedGift(Bot bot, ulong giftId)
{
var request = new Uri(SteamStoreURL, $"/gifts/{giftId}/unpack");
Expand All @@ -343,4 +355,33 @@ internal static async Task<bool> RemoveLicense(Bot bot, uint subId)

return response?.Content;
}

/// <summary>
/// 获取游戏游玩时间
/// </summary>
/// <param name="bot"></param>
/// <param name="apiKey"></param>
/// <returns></returns>
internal static async Task<Dictionary<uint, GetOwnedGamesResponse.GameData>?> GetGamePlayTime(Bot bot, string apiKey)
{
var request = new Uri(SteamApiURL, $"/IPlayerService/GetOwnedGames/v1/?key={apiKey}&steamid={bot.SteamID}&include_appinfo=true&include_played_free_games=true&include_free_sub=true&skip_unvetted_apps=true&language={Langs.Language}&include_extended_appinfo=true");

var response = await bot.ArchiWebHandler.UrlGetToJsonObjectWithSession<GetOwnedGamesResponse>(request, referer: SteamStoreURL).ConfigureAwait(false);

if (response?.Content?.Response?.Games != null)
{
var result = new Dictionary<uint, GetOwnedGamesResponse.GameData>();

foreach (var game in response.Content.Response.Games)
{
result.TryAdd(game.AppId, game);
}

return result;
}
else
{
return null;
}
}
}
10 changes: 10 additions & 0 deletions ASFEnhance/Command/CommandHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ASFEnhance.Command;
class CommandHandler
{
}
56 changes: 56 additions & 0 deletions ASFEnhance/Data/GetOwnedGamesResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ASFEnhance.Data;
internal sealed record GetOwnedGamesResponse
{
[JsonProperty("response")]
public ResponseData? Response { get; set; }

internal sealed record ResponseData
{
[JsonProperty("game_count")]
public uint GameCount { get; set; }

[JsonProperty("games")]
public List<GameData>? Games { get; set; }
}

internal sealed record GameData
{
[JsonProperty("appid")]
public uint AppId { get; set; }

[JsonProperty("name")]
public string? Name { get; set; }

[JsonProperty("playtime_2weeks")]
public uint PlayTime2Weeks { get; set; }

[JsonProperty("playtime_forever")]
public uint PlayTimeForever { get; set; }

[JsonProperty("has_community_visible_stats")]
public bool HasCommunityVisibleStats { get; set; }

[JsonProperty("playtime_windows_forever")]
public uint PlaytimeWindowsForever { get; set; }

[JsonProperty("playtime_mac_forever")]
public uint PlaytimeMacForever { get; set; }

[JsonProperty("playtime_linux_forever")]
public uint PlaytimeLinuxForever { get; set; }

[JsonProperty("rtime_last_played")]
public ulong RtimeLastPlayed { get; set; }

[JsonProperty("playtime_disconnected")]
public uint PlaytimeDisconnected { get; set; }

}
}
4 changes: 2 additions & 2 deletions ASFEnhance/Data/GitHubReleaseResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace ASFEnhance.Data;

internal sealed record GitHubReleaseResponse
public sealed record GitHubReleaseResponse
{
[JsonProperty(PropertyName = "html_url", Required = Required.Always)]
public string Url { get; set; } = "";
Expand All @@ -25,7 +25,7 @@ internal sealed record GitHubReleaseResponse
[JsonProperty(PropertyName = "assets", Required = Required.Always)]
public HashSet<GitHubAssetsData> Assets { get; set; } = new();

internal sealed record GitHubAssetsData
public sealed record GitHubAssetsData
{
[JsonProperty(PropertyName = "name", Required = Required.Always)]
public string Name { get; set; } = "";
Expand Down
54 changes: 54 additions & 0 deletions ASFEnhance/ExpansionUtils/Update.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Web.Responses;
using ASFEnhance.Data;

namespace ASFEnhance.ExpansionUtils;

/// <summary>
/// 插件更新相关
/// </summary>
public static class Update
{
public static Uri GetGitHubApiUri(string repo, bool useMirror)
{
var addr = useMirror ?
$"https://hub.chrxw.com/{repo}/releases/latest" :
$"https://api.github.com/repos/chr233/{repo}/releases/latest";

return new Uri(addr);
}

/// <summary>
/// 获取最新的发行版
/// </summary>
/// <returns></returns>
public static async Task<GitHubReleaseResponse?> GetLatestRelease(string repo, bool useMirror)
{
var request = GetGitHubApiUri(repo, useMirror);
var response = await ASF.WebBrowser!.UrlGetToJsonObject<GitHubReleaseResponse>(request).ConfigureAwait(false);

if (response == null && useMirror)
{
return await GetLatestRelease(repo, false).ConfigureAwait(false);
}

return response?.Content;
}

/// <summary>
/// 下载发行版
/// </summary>
/// <param name="downloadUrl"></param>
/// <returns></returns>
public static async Task<BinaryResponse?> DownloadRelease(string? downloadUrl)
{
if (string.IsNullOrEmpty(downloadUrl))
{
return null;
}

var request = new Uri(downloadUrl);
var response = await ASF.WebBrowser!.UrlGetToBinary(request).ConfigureAwait(false);
return response;
}
}

0 comments on commit f6c862a

Please sign in to comment.