From 433a5d7e63a9f276593c07586584da5d1dfc20c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Sun, 11 Jun 2023 22:20:11 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83=20(#530)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 优化部分代码规范 * 添加buildKey * Update runInLocal.md * Update runInLocal.md * Update runInLocal.md * Update runInLocal.md * 恢复donte启动方式的描述 * 增加部分空格 * 增加if前面的空格 * 使用new() * 删除分号前的空格 --------- Co-authored-by: 王学懿 Co-authored-by: Ray --- docs/runInLocal.md | 1 + src/Ray.BiliBiliTool.Config/Constants.cs | 22 +++++++----- ...iablesExcludeEmptyConfigurationProvider.cs | 10 ++++-- ...ariablesExcludeEmptyConfigurationSource.cs | 9 ++--- .../Options/DailyTaskOptions.cs | 12 +++---- .../BiliBiliToolHostedService.cs | 36 +++++++++++-------- src/Ray.BiliBiliTool.Console/Program.cs | 33 ++++++++++++----- 7 files changed, 75 insertions(+), 48 deletions(-) diff --git a/docs/runInLocal.md b/docs/runInLocal.md index 01564856f..e7d3ed0df 100644 --- a/docs/runInLocal.md +++ b/docs/runInLocal.md @@ -35,6 +35,7 @@ P.S.这里的运行环境指的是 `.NET Runtime 6.0.0` ,安装方法可详见 请下载 `win-x86-x64.zip`,此文件已自包含(self-contained)运行环境。 解压后,在应用目录打开cmd或powershell,执行`.\Ray.BiliBiliTool.Console.exe --runTasks=Login`,扫码登录。 +也可以直接双击`Ray.BiliBiliTool.Console.exe`来运行,建议使用windows自带的定时任务来执行它 ## 3. Linux: diff --git a/src/Ray.BiliBiliTool.Config/Constants.cs b/src/Ray.BiliBiliTool.Config/Constants.cs index 870682bbe..f9737d223 100644 --- a/src/Ray.BiliBiliTool.Config/Constants.cs +++ b/src/Ray.BiliBiliTool.Config/Constants.cs @@ -1,5 +1,4 @@ - -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Linq; @@ -35,26 +34,30 @@ public static class OptionsNames /// public static Dictionary GetExpDic() { - var dic = new Dictionary() + Dictionary dic = new() { {"每日登录", "5"}, {"每日观看视频", "5"}, {"每日分享视频", "5"}, {"每日投币", "10"} }; + + string buildKey(string key) => $"{OptionsNames.ExpDictionaryName}:{key}"; + return dic.Select(x => - new KeyValuePair($"{OptionsNames.ExpDictionaryName}:{x.Key}", x.Value)) + new KeyValuePair(buildKey(x.Key), x.Value)) .ToDictionary(k => k.Key, v => v.Value); } /// - /// 投币接口的data.code返回以下这些状态码,则可以继续尝试投币 - /// 如返回除这些之外的状态码,则终止投币流程,不进行无意义的尝试(比如返回-101:账号未登录;-102:账号被封停;-111:csrf校验失败等) + /// 投币接口的data.code返回以下这些状态码,则可以继续尝试投币 + /// 如返回除这些之外的状态码,则终止投币流程,不进行无意义的尝试 + /// (比如返回-101:账号未登录;-102:账号被封停;-111:csrf校验失败等) /// /// public static Dictionary GetDonateCoinCanContinueStatusDic() { - var dic = new Dictionary() + Dictionary dic = new() { {"0", "成功"}, {"-400", "请求错误"}, @@ -64,8 +67,11 @@ public static Dictionary GetDonateCoinCanContinueStatusDic() {"34004", "投币间隔太短"}, {"34005", "超过投币上限"} }; + + string buildKey(string key) => $"{OptionsNames.DonateCoinCanContinueStatusDictionaryName}:{key}"; + return dic.Select(x => - new KeyValuePair($"{OptionsNames.DonateCoinCanContinueStatusDictionaryName}:{x.Key}", x.Value)) + new KeyValuePair(buildKey(x.Key), x.Value)) .ToDictionary(k => k.Key, v => v.Value) ; } diff --git a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs index e6aaa0064..61dec6a96 100644 --- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs +++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs @@ -8,7 +8,7 @@ namespace Ray.BiliBiliTool.Config { /// - /// 自定义的排除空值的环境变量提供者 + /// 自定义的排除空值的环境变量提供者 /// (使用GitHub Actions的脚本传入环境变量,空值会保留,所以这里自己写了一个用来替换掉默认的) /// public class EnvironmentVariablesExcludeEmptyConfigurationProvider : EnvironmentVariablesConfigurationProvider @@ -19,7 +19,10 @@ public class EnvironmentVariablesExcludeEmptyConfigurationProvider : Environment private readonly Func, bool> _removeNullValue; private readonly Func, bool> _fifter; - public EnvironmentVariablesExcludeEmptyConfigurationProvider(string prefix = null, bool removeKeyPrefix = true) : base(prefix) + public EnvironmentVariablesExcludeEmptyConfigurationProvider( + string prefix = null, + bool removeKeyPrefix = true) + : base(prefix) { _removeKeyPrefix = removeKeyPrefix; _prefix = prefix ?? string.Empty; @@ -46,7 +49,8 @@ public override void Load() /// private string NormalizeKey(string key) { - if(_removeKeyPrefix) key = RemoveKeyPrefix(key); + if (_removeKeyPrefix) + key = RemoveKeyPrefix(key); key = ReplaceKeyDelimiter(key); return key; } diff --git a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs index fea853940..4d553edfc 100644 --- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs +++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.EnvironmentVariables; namespace Ray.BiliBiliTool.Config { /// - /// 自定义的排除空值的环境变量配置源 + /// 自定义的排除空值的环境变量配置源 /// (用于取待默认的) /// public class EnvironmentVariablesExcludeEmptyConfigurationSource : IConfigurationSource diff --git a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs index da828c8e7..91b75b02e 100644 --- a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs +++ b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs @@ -28,7 +28,6 @@ public class DailyTaskOptions /// public bool SaveCoinsWhenLv6 { get; set; } = false; - /// /// 投币时是否点赞[false,true] /// @@ -50,6 +49,7 @@ public class DailyTaskOptions public string AutoChargeUpId { get; set; } private string _chargeComment; + /// /// 充电后留言 /// @@ -77,16 +77,16 @@ public string ChargeComment /// public string DevicePlatform { get; set; } = "android"; - public List SupportUpIdList { get { - var re = new List(); - if (string.IsNullOrWhiteSpace(SupportUpIds) | SupportUpIds == "-1") return re; + List re = new(); + if (string.IsNullOrWhiteSpace(SupportUpIds) | SupportUpIds == "-1") + return re; - var array = SupportUpIds.Split(','); - foreach (var item in array) + string[] array = SupportUpIds.Split(','); + foreach (string item in array) { if (long.TryParse(item.Trim(), out long upId)) re.Add(upId); diff --git a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs index 5bbd4e513..40741ed87 100644 --- a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs +++ b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs @@ -45,25 +45,25 @@ IHostApplicationLifetime applicationLifetime public async Task StartAsync(CancellationToken cancellationToken) { - var isNotifySingle = _configuration.GetSection("Notification:IsSingleAccountSingleNotify").Get(); + bool isNotifySingle = _configuration.GetSection("Notification:IsSingleAccountSingleNotify").Get(); try { _logger.LogInformation("BiliBiliToolPro 开始运行...{newLine}", Environment.NewLine); - var pass = await PreCheckAsync(cancellationToken); - if (!pass) return; + bool pass = await PreCheckAsync(cancellationToken); + if (!pass) + return; await RandomSleepAsync(cancellationToken); - var tasks = await ReadTargetTasksAsync(cancellationToken); + string[] tasks = await ReadTargetTasksAsync(cancellationToken); _logger.LogInformation("【目标任务】{tasks}", string.Join(",", tasks)); if (tasks.Contains("Login")) { await DoTasksAsync(tasks, cancellationToken); } - else { for (int i = 0; i < _cookieStrFactory.Count; i++) @@ -78,7 +78,7 @@ public async Task StartAsync(CancellationToken cancellationToken) { LogAppInfo(); - var accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : ""; + string accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : ""; _logger.LogInformation("·开始推送·{task}·{user}", $"{_configuration["RunTasks"]}任务", accountName); } } @@ -134,7 +134,8 @@ private Task PreCheckAsync(CancellationToken cancellationToken) private async Task RandomSleepAsync(CancellationToken cancellationToken) { - if (_configuration["RunTasks"].Contains("Login") || _configuration["RunTasks"].Contains("Test")) return; + if (_configuration["RunTasks"].Contains("Login") || _configuration["RunTasks"].Contains("Test")) + return; if (_securityOptions.RandomSleepMaxMin > 0) { @@ -144,9 +145,14 @@ private async Task RandomSleepAsync(CancellationToken cancellationToken) } } + /// + /// 读取目标任务 + /// + /// + /// private Task ReadTargetTasksAsync(CancellationToken cancellationToken) { - var tasks = _configuration["RunTasks"] + string[] tasks = _configuration["RunTasks"] .Split("&", options: StringSplitOptions.RemoveEmptyEntries); if (tasks.Any()) { @@ -159,11 +165,11 @@ private Task ReadTargetTasksAsync(CancellationToken cancellationToken) while (true) { - var index = System.Console.ReadLine(); - var suc = int.TryParse(index, out int num); + string index = System.Console.ReadLine(); + bool suc = int.TryParse(index, out int num); if (suc) { - var code = TaskTypeFactory.GetCodeByIndex(num); + string code = TaskTypeFactory.GetCodeByIndex(num); _configuration["RunTasks"] = code; return Task.FromResult(new string[] { code }); } @@ -174,17 +180,17 @@ private Task ReadTargetTasksAsync(CancellationToken cancellationToken) private async Task DoTasksAsync(string[] tasks, CancellationToken cancellationToken) { - using var scope = _serviceProvider.CreateScope(); - foreach (var task in tasks) + using IServiceScope scope = _serviceProvider.CreateScope(); + foreach (string task in tasks) { - var type = TaskTypeFactory.Create(task); + Type type = TaskTypeFactory.Create(task); if (type == null) { _logger.LogWarning("任务不存在:{task}", task); continue; } - var appService = (IAppService)scope.ServiceProvider.GetRequiredService(type); + IAppService appService = (IAppService)scope.ServiceProvider.GetRequiredService(type); await appService?.DoTaskAsync(cancellationToken); } } diff --git a/src/Ray.BiliBiliTool.Console/Program.cs b/src/Ray.BiliBiliTool.Console/Program.cs index 7dc7ce0a1..0e3da4a4a 100644 --- a/src/Ray.BiliBiliTool.Console/Program.cs +++ b/src/Ray.BiliBiliTool.Console/Program.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; @@ -56,7 +54,8 @@ internal static IHostBuilder CreateHostBuilder(string[] args) //hostBuilder.UseContentRoot(Directory.GetCurrentDirectory()); - //承载系统自身的配置: + #region 承载系统自身的配置 + hostBuilder.ConfigureHostConfiguration(hostConfigurationBuilder => { hostConfigurationBuilder.AddEnvironmentVariables(prefix: "DOTNET_"); @@ -67,22 +66,26 @@ internal static IHostBuilder CreateHostBuilder(string[] args) } }); - //应用配置: + #endregion 承载系统自身的配置 + + #region 应用配置 + hostBuilder.ConfigureAppConfiguration((hostBuilderContext, configurationBuilder) => { Global.HostingEnvironment = hostBuilderContext.HostingEnvironment; IHostEnvironment env = hostBuilderContext.HostingEnvironment; //json文件: + string envName = hostBuilderContext.HostingEnvironment.EnvironmentName; configurationBuilder.AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{hostBuilderContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile($"appsettings.{envName}.json", true, true) ; //用户机密: if (env.IsDevelopment() && env.ApplicationName?.Length > 0) { //var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); - var appAssembly = Assembly.GetAssembly(typeof(Program)); + Assembly appAssembly = Assembly.GetAssembly(typeof(Program)); configurationBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: true); } @@ -104,16 +107,23 @@ internal static IHostBuilder CreateHostBuilder(string[] args) configurationBuilder.AddInMemoryCollection(Config.Constants.GetDonateCoinCanContinueStatusDic()); }); - //日志: + #endregion 应用配置 + + #region 日志 + hostBuilder.ConfigureLogging((hostBuilderContext, loggingBuilder) => { Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(hostBuilderContext.Configuration) .CreateLogger(); SelfLog.Enable(x => System.Console.WriteLine(x ?? "")); - }).UseSerilog(); + }) + .UseSerilog(); + + #endregion 日志 + + #region DI容器 - //DI容器: hostBuilder.ConfigureServices((hostContext, services) => { Global.ConfigurationRoot = (IConfigurationRoot)hostContext.Configuration; @@ -126,9 +136,14 @@ internal static IHostBuilder CreateHostBuilder(string[] args) services.AddAppServices(); }); + #endregion DI容器 + return hostBuilder; } + /// + /// 输出本工具启动logo + /// private static void PrintLogo() { System.Console.WriteLine(@" ____ ____ _ _____ _ "); From fbc01c7dbbb41afcbe02bf12ac36762e284b8fbd Mon Sep 17 00:00:00 2001 From: Initial-heart <63091661+Initial-heart-1@users.noreply.github.com> Date: Sun, 11 Jun 2023 22:30:29 +0800 Subject: [PATCH 2/8] feat: add NumberOfProtectedCoins (#560) * feat: add NumberOfProtectedCoins * fix: allow command line pass in arg * fix: unnecessary logs --- src/Ray.BiliBiliTool.Config/Constants.cs | 1 + .../Options/DailyTaskOptions.cs | 5 +++++ src/Ray.BiliBiliTool.Console/appsettings.json | 1 + .../DonateCoinDomainService.cs | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/src/Ray.BiliBiliTool.Config/Constants.cs b/src/Ray.BiliBiliTool.Config/Constants.cs index f9737d223..cc6448cd8 100644 --- a/src/Ray.BiliBiliTool.Config/Constants.cs +++ b/src/Ray.BiliBiliTool.Config/Constants.cs @@ -87,6 +87,7 @@ public static Dictionary GetCommandLineMappingsDic() {"--randomSleep","Security:RandomSleepMaxMin"}, {"--numberOfCoins", "DailyTaskConfig:NumberOfCoins"}, + {"--numberOfProtectedCoins", "DailyTaskConfig:NumberOfProtectedCoins"}, {"--saveCoinsWhenLv6", "DailyTaskConfig:SaveCoinsWhenLv6"}, {"--selectLike", "DailyTaskConfig:SelectLike"}, {"--supportUpIds", "DailyTaskConfig:SupportUpIds"}, diff --git a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs index 91b75b02e..de5f2df70 100644 --- a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs +++ b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs @@ -23,6 +23,11 @@ public class DailyTaskOptions /// public int NumberOfCoins { get; set; } = 5; + /// + /// 要保留的硬币数量 [0,int_max] + /// + public int NumberOfProtectedCoins { get; set; } = 0; + /// /// 达到六级后是否开始白嫖 /// diff --git a/src/Ray.BiliBiliTool.Console/appsettings.json b/src/Ray.BiliBiliTool.Console/appsettings.json index 89740733a..3eea38f84 100644 --- a/src/Ray.BiliBiliTool.Console/appsettings.json +++ b/src/Ray.BiliBiliTool.Console/appsettings.json @@ -7,6 +7,7 @@ "IsWatchVideo": true, //是否观看视频 "IsShareVideo": true, //是否分享视频 "NumberOfCoins": 5, //每日设定的投币数 [0,5] + "NumberOfProtectedCoins": 0, // 要保留的硬币数量 [0,int_max],0 为不保留,int_max 通常取 (2^31)-1 "SaveCoinsWhenLv6": false, //达到六级后是否开始白嫖[false,true] "SelectLike": true, //投币时是否同时点赞[false,true] "SupportUpIds": "", //优先选择支持的up主Id集合,多个以英文逗号分隔,如:"123,456"。配置后会优先从指定的up主下挑选视频进行观看、分享和投币,不配置或配置为-1则表示没有特别支持的up,会从关注和排行耪中随机获取支持视频 diff --git a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs index 387afb54c..8e5114749 100644 --- a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs @@ -70,11 +70,13 @@ IVideoApi videoApi public async Task AddCoinsForVideos() { int needCoins = await GetNeedDonateCoinNum(); + int protectedCoins = _dailyTaskOptions.NumberOfProtectedCoins; if (needCoins <= 0) return; //投币前硬币余额 decimal coinBalance = await _coinDomainService.GetCoinBalance(); _logger.LogInformation("【投币前余额】 : {coinBalance}", coinBalance); + _ = int.TryParse(decimal.Truncate(coinBalance - protectedCoins).ToString(), out int unprotectedCoins); if (coinBalance <= 0) { @@ -82,6 +84,12 @@ public async Task AddCoinsForVideos() return; } + if (coinBalance <= protectedCoins) + { + _logger.LogInformation("因硬币余额达到或低于保留值,今日暂不执行投币任务"); + return; + } + //余额小于目标投币数,按余额投 if (coinBalance < needCoins) { @@ -89,6 +97,17 @@ public async Task AddCoinsForVideos() _logger.LogInformation("因硬币余额不足,目标投币数调整为: {needCoins}", needCoins); } + //投币后余额小于等于保护值,按保护值允许投 + if (coinBalance - needCoins <= protectedCoins) + { + //排除需投等于保护后可投数量相等时的情况 + if (unprotectedCoins != needCoins) + { + needCoins = unprotectedCoins; + _logger.LogInformation("因硬币余额投币后将达到或低于保留值,目标投币数调整为: {needCoins}", needCoins); + } + } + int success = 0; int tryCount = 10; for (int i = 1; i <= tryCount && success < needCoins; i++) From 171c89583542cac67a2b1258bbe32f2a8e00fbe5 Mon Sep 17 00:00:00 2001 From: Initial-heart <63091661+Initial-heart-1@users.noreply.github.com> Date: Mon, 19 Jun 2023 00:03:22 +0800 Subject: [PATCH 3/8] feat: add CustomComicId and CustomEpId (#562) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add CustomComicId and CustomEpId * fix: str to int * fix: avoid possible value overflows * Update src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs * Update src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs --------- Co-authored-by: 在7楼 <31154238+RayWangQvQ@users.noreply.github.com> --- .../BiliBiliAgent/Interfaces/IMangaApi.cs | 4 ++-- .../Options/DailyTaskOptions.cs | 10 ++++++++++ src/Ray.BiliBiliTool.Console/appsettings.json | 4 +++- .../MangaDomainService.cs | 5 +++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs index 903d5405c..7a851b2de 100644 --- a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs @@ -26,8 +26,8 @@ public interface IMangaApi : IBiliBiliApi /// /// /// - [HttpPost("/twirp/bookshelf.v1.Bookshelf/AddHistory?platform={platform}&comic_id=27355&ep_id=381662")] - Task ReadManga(string platform); + [HttpPost("/twirp/bookshelf.v1.Bookshelf/AddHistory?platform={platform}&comic_id={comic_id}&ep_id={ep_id}")] + Task ReadManga(string platform, long comic_id, long ep_id); /// /// 获取会员漫画奖励 diff --git a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs index de5f2df70..2258edf00 100644 --- a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs +++ b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs @@ -82,6 +82,16 @@ public string ChargeComment /// public string DevicePlatform { get; set; } = "android"; + /// + /// 自定义漫画阅读 comic_id + /// + public long CustomComicId { get; set; } = 27355; + + /// + /// 自定义漫画阅读 ep_id + /// + public long CustomEpId { get; set; } = 381662; + public List SupportUpIdList { get diff --git a/src/Ray.BiliBiliTool.Console/appsettings.json b/src/Ray.BiliBiliTool.Console/appsettings.json index 3eea38f84..a3f85f0cf 100644 --- a/src/Ray.BiliBiliTool.Console/appsettings.json +++ b/src/Ray.BiliBiliTool.Console/appsettings.json @@ -16,7 +16,9 @@ "ChargeComment": "", //充电后留言 "DayOfReceiveVipPrivilege": 1, //每月几号自动领取会员权益的[-1,31],-1表示不指定,默认每月1号;0表示不自动领取 "DayOfExchangeSilver2Coin": 0, //每月几号执行银瓜子兑换硬币[-1,31],-1表示不指定,默认每月最后一天;-2表示每天;0表示不进行兑换 - "DevicePlatform": "android" //执行客户端操作时的平台 [ios,android] + "DevicePlatform": "android", //执行客户端操作时的平台 [ios,android] + "CustomComicId": 27355, //自定义漫画阅读 comic_id,若不清楚含义请勿修改 + "CustomEpId": 381662 //自定义漫画阅读 ep_id,若不清楚含义请勿修改 }, "LiveLotteryTaskConfig": { diff --git a/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs b/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs index 4459f4625..7d175a108 100644 --- a/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs @@ -62,11 +62,12 @@ public async Task MangaSign() /// public async Task MangaRead() { - BiliApiResponse response = await _mangaApi.ReadManga(_dailyTaskOptions.DevicePlatform); + if ( _dailyTaskOptions.CustomComicId <= 0 ) return; + BiliApiResponse response = await _mangaApi.ReadManga(_dailyTaskOptions.DevicePlatform, _dailyTaskOptions.CustomComicId, _dailyTaskOptions.CustomEpId); if (response.Code == 0) { - _logger.LogInformation("【漫画阅读】成功, 阅读漫画为:堀与宫村"); + _logger.LogInformation("【漫画阅读】成功"); } else { From ef6ea123740f435259c3f42b2457dd01fe2bd7b5 Mon Sep 17 00:00:00 2001 From: Polaris_cn <2984098720@qq.com> Date: Sat, 12 Aug 2023 21:35:46 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E6=97=B6=E9=97=B4=E8=AE=A1=E7=AE=97=E7=9A=84?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=EF=BC=8C=E5=B9=B6=E5=A2=9E=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20(#590)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 基本完成升级时间计算的升级,并增加一个单元测试。 * 调整了升级时间的日志描述 --- .../AccountDomainService.cs | 47 ++++++++++++++++-- .../Interfaces/IAccountDomainService.cs | 7 +++ .../CalculateUpgradeTimeTest.cs | 48 +++++++++++++++++++ 3 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 test/DomainServiceTest/CalculateUpgradeTimeTest.cs diff --git a/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs b/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs index efa7f6e68..e6d12dae5 100644 --- a/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs @@ -25,6 +25,7 @@ public class AccountDomainService : IAccountDomainService private readonly IRelationApi _relationApi; private readonly UnfollowBatchedTaskOptions _unfollowBatchedTaskOptions; private readonly BiliCookie _cookie; + private readonly DailyTaskOptions _dailyTaskOptions; public AccountDomainService( ILogger logger, @@ -32,14 +33,15 @@ public AccountDomainService( BiliCookie cookie, IUserInfoApi userInfoApi, IRelationApi relationApi, - IOptionsMonitor unfollowBatchedTaskOptions - ) + IOptionsMonitor unfollowBatchedTaskOptions, + IOptionsMonitor dailyTaskOptions) { _logger = logger; _dailyTaskApi = dailyTaskApi; _cookie = cookie; _userInfoApi = userInfoApi; _relationApi = relationApi; + _dailyTaskOptions = dailyTaskOptions.CurrentValue; _unfollowBatchedTaskOptions = unfollowBatchedTaskOptions.CurrentValue; } @@ -66,9 +68,9 @@ public async Task LoginByCookie() if (useInfo.Level_info.Current_level < 6) { - _logger.LogInformation("【距升级Lv{0}】{1}天(如每日做满65点经验)", + _logger.LogInformation("【距升级Lv{0}】预计{1}天", useInfo.Level_info.Current_level + 1, - (useInfo.Level_info.GetNext_expLong() - useInfo.Level_info.Current_exp) / Constants.EveryDayExp); + CalculateUpgradeTime(useInfo)); } else { @@ -216,5 +218,42 @@ private async Task GetTag(string groupName) TagDto tag = tagList.FirstOrDefault(x => x.Name == groupName); return tag; } + + /// + /// 计算升级时间 + /// + /// + /// 升级时间 + public int CalculateUpgradeTime(UserInfo useInfo) + { + double availableCoins = decimal.ToDouble(useInfo.Money ?? 0) - _dailyTaskOptions.NumberOfProtectedCoins; + long needExp = useInfo.Level_info.GetNext_expLong() - useInfo.Level_info.Current_exp; + int needDay; + + if (availableCoins < 0) + needDay = (int)((double)needExp / 25 + _dailyTaskOptions.NumberOfProtectedCoins - Math.Abs(availableCoins)); + + switch (_dailyTaskOptions.NumberOfCoins) + { + case 0: + needDay = (int)(needExp / 15); + break; + case 1: + needDay = (int)(needExp / 25); + break; + default: + int dailyExpAvailable = 15 + _dailyTaskOptions.NumberOfCoins * 10; + double needFrontDay = availableCoins / (_dailyTaskOptions.NumberOfCoins - 1); + + if ((double)needExp / dailyExpAvailable > needFrontDay) + needDay = (int)(needFrontDay + (needExp - dailyExpAvailable * needFrontDay) / 25); + else + needDay= (int)(needExp / dailyExpAvailable ); + break; + } + + return needDay; + } + } } diff --git a/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs b/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs index b599bd78c..83d03da69 100644 --- a/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs @@ -24,5 +24,12 @@ public interface IAccountDomainService : IDomainService /// 批量取关 /// Task UnfollowBatched(); + + /// + /// 计算升级时间 + /// + /// + /// 升级时间 + int CalculateUpgradeTime(UserInfo useInfo); } } diff --git a/test/DomainServiceTest/CalculateUpgradeTimeTest.cs b/test/DomainServiceTest/CalculateUpgradeTimeTest.cs new file mode 100644 index 000000000..b9b70df03 --- /dev/null +++ b/test/DomainServiceTest/CalculateUpgradeTimeTest.cs @@ -0,0 +1,48 @@ +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos; + +namespace DomainServiceTest; + +public class CalculateUpgradeTimeTest +{ + public CalculateUpgradeTimeTest() + { + Program.CreateHost(new[] { "--ENVIRONMENT=Development" }); + } + + [Fact] + public void TestCalculateUpgradeTime() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + var accountDomainService = scope.ServiceProvider.GetRequiredService(); + int needDay = accountDomainService.CalculateUpgradeTime(new UserInfo() + { + Money = 7, + Level_info = new LevelInfo() + { + Current_level = 5, + Current_exp = 100, + Next_exp = 200 + } + }); + int needDay2 = accountDomainService.CalculateUpgradeTime(new UserInfo() + { + Money = 7, + Level_info = new LevelInfo() + { + Current_level = 5, + Current_exp = 1000, + Next_exp = 2000 + } + }); + + Assert.Equal(1,needDay); + Assert.Equal(37,needDay2); + + } +} + + + + + + From a539bb286949e498b06dd6fa2250d71f33fa119c Mon Sep 17 00:00:00 2001 From: chenliu1993 Date: Sat, 2 Dec 2023 01:07:02 +0900 Subject: [PATCH 5/8] Update plugin to fix some probelms amd update image version to latest (#598) fix version showing issue, now it uses upstream commit as plugin version update image to 2.0.1 in login part. wait for the deployment to be ready and then getthe QR code Signed-off-by: chenliu1993 --- krew/.gitignore | 2 + krew/Makefile | 26 ++++++++--- krew/README.md | 9 ++-- krew/cmd/kubectl-bilipro.go | 4 +- krew/go.mod | 4 +- krew/pkg/cmd/delete.go | 6 +-- krew/pkg/cmd/get.go | 5 +-- krew/pkg/cmd/init.go | 43 +++++++++++++++---- krew/pkg/cmd/version.go | 4 +- .../base/bilibiliPro/deployment.yaml | 2 +- krew/pkg/utils/client.go | 2 + 11 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 krew/.gitignore diff --git a/krew/.gitignore b/krew/.gitignore new file mode 100644 index 000000000..45f4d8132 --- /dev/null +++ b/krew/.gitignore @@ -0,0 +1,2 @@ +bin +bilipro \ No newline at end of file diff --git a/krew/Makefile b/krew/Makefile index b18791ada..23f9d3c1f 100644 --- a/krew/Makefile +++ b/krew/Makefile @@ -20,18 +20,30 @@ help: #### display help deploy: build install #### build + install +.PHONY: fmt +fmt: #### run go fmt against code + @go fmt ./... + + +.PHONY: vet +vet: #### run go vet against code + @go vet ./... + +.PHONY: update-modules +update-modules: tidy #### update go modules + +.PHONY: tidy +tidy: #### run go mod tidy + @go mod tidy + .PHONY: build build: #### build the plugin - @go vet ./... && \ - go fmt ./... && \ - echo "build on ${GOOS}/${GOARCH}" && \ - cd ${ROOT_DIR}/krew/cmd && \ - GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -ldflags "-X github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd.Version=${GITCOMMIT}" -o $(BIN_NAME) kubectl-bilipro.go - + @echo "build on ${GOOS}/${GOARCH}" && \ + GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -mod readonly -ldflags "-X github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd.version=${GITCOMMIT}" -o bin/$(BIN_NAME) cmd/kubectl-bilipro.go .PHONY: install install: #### install the plugin - @cd ${ROOT_DIR}/krew/cmd && \ + @cd ${ROOT_DIR}/krew/bin && \ sudo install ./$(BIN_NAME) ${KUBECTL_DIR}/$(BIN_NAME) .PHONY: test diff --git a/krew/README.md b/krew/README.md index f56318963..36697df11 100644 --- a/krew/README.md +++ b/krew/README.md @@ -18,15 +18,18 @@ For example: the kubectl is installed under `/usr/bin`, then put the bilibilipro ### Deployment && Update -Command: `kubectl bilipro init --config config.yaml [optional]--login` +Prerequsites: please make sure you have the right permission to at least manage namespaces/deployments + +Command: `kubectl bilipro init --config config.yaml` Creates Deployment with the needed environments. Optional Options: -- `--image=zai7lou/bilibili_tool_pro:1.0.1` +- `--image=zai7lou/bilibili_tool_pro:2.0.1` - `--namespace=bilipro` -- `--image-pull-secret=` +- `--image-pull-secret=` +- `--login` to scan QR code to login Required Options: diff --git a/krew/cmd/kubectl-bilipro.go b/krew/cmd/kubectl-bilipro.go index f9e3ca6ea..55256366e 100644 --- a/krew/cmd/kubectl-bilipro.go +++ b/krew/cmd/kubectl-bilipro.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" "github.com/spf13/pflag" @@ -8,7 +9,6 @@ import ( "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd" helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/klog/v2" ) func main() { @@ -17,7 +17,7 @@ func main() { cmd := cmd.NewExecutor(genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}) if err := cmd.Execute(); err != nil { - klog.Error(helper.GenErrorMsg(helper.SERVER_ERROR, err.Error()).Error()) + fmt.Println(helper.GenErrorMsg(helper.SERVER_ERROR, err.Error()).Error()) os.Exit(1) } } diff --git a/krew/go.mod b/krew/go.mod index 37d7d67a8..9f7fd48fa 100644 --- a/krew/go.mod +++ b/krew/go.mod @@ -9,7 +9,6 @@ require ( k8s.io/apimachinery v0.25.4 k8s.io/cli-runtime v0.25.4 k8s.io/client-go v0.25.4 - k8s.io/klog/v2 v2.80.1 sigs.k8s.io/kustomize/api v0.12.1 sigs.k8s.io/kustomize/kyaml v0.13.9 sigs.k8s.io/yaml v1.3.0 @@ -58,10 +57,11 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) -replace github.com/RayWangQvQ/BiliBiliToolPro/krew => ../krew +// replace github.com/RayWangQvQ/BiliBiliToolPro/krew => ../krew diff --git a/krew/pkg/cmd/delete.go b/krew/pkg/cmd/delete.go index 9acbdf5f4..a291d4e27 100644 --- a/krew/pkg/cmd/delete.go +++ b/krew/pkg/cmd/delete.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "io" "os/exec" "strings" @@ -9,8 +10,6 @@ import ( "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/yaml" - "k8s.io/klog/v2" - "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options" helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils" "github.com/spf13/cobra" @@ -42,9 +41,10 @@ func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command { err := o.run(out) if err != nil { - klog.Error(err) + fmt.Println(err) return err } + fmt.Println("bilibili tool is removed from your cluster") return nil }, } diff --git a/krew/pkg/cmd/get.go b/krew/pkg/cmd/get.go index 162538ec0..15744cb20 100644 --- a/krew/pkg/cmd/get.go +++ b/krew/pkg/cmd/get.go @@ -1,11 +1,10 @@ package cmd import ( + "fmt" "io" "os/exec" - "k8s.io/klog/v2" - "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options" helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils" "github.com/spf13/cobra" @@ -37,7 +36,7 @@ func newGetCmd(out io.Writer, errOut io.Writer) *cobra.Command { err := o.run(out) if err != nil { - klog.Error(err) + fmt.Println(err) return err } return nil diff --git a/krew/pkg/cmd/init.go b/krew/pkg/cmd/init.go index 21a80cf51..3a1f5ccd4 100644 --- a/krew/pkg/cmd/init.go +++ b/krew/pkg/cmd/init.go @@ -7,7 +7,6 @@ import ( "os" "os/exec" "strings" - "time" corev1 "k8s.io/api/core/v1" @@ -17,8 +16,6 @@ import ( "sigs.k8s.io/kustomize/api/types" - "k8s.io/klog/v2" - "github.com/spf13/cobra" "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options" @@ -52,7 +49,7 @@ func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { err := o.run(out) if err != nil { - klog.Error(err) + fmt.Println(err) return err } return nil @@ -60,7 +57,7 @@ func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command { } f := cmd.Flags() - f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:1.0.1", "bilibilipro image") + f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:2.0.1", "bilibilipro image") f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request") f.StringVar(&o.deployOpts.ImagePullSecret, "image-pull-secret", "", "image pull secret to be used for pulling bilibilipro image") f.StringVarP(&o.deployOpts.ConfigFilePath, "config", "c", "", "the config file contanis the environment variables") @@ -94,6 +91,8 @@ func (o *initCmd) run(writer io.Writer) error { } // TODO: All about paths are a little bit tricky should give it more thoughts + + fmt.Println("Creating the kustomization file") // if the bilibili tool is deployed under system/pre-defined namespace, ignore the namespace file var resources []string // nolint: go-staticcheck if o.deployOpts.Namespace == "default" || o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" { @@ -211,6 +210,7 @@ func (o *initCmd) run(writer io.Writer) error { } } + fmt.Println("Applying the kustomization file") // do kubectl apply // make sure kubectl is under your PATH cmd := exec.Command("kubectl", "apply", "-f", "-") @@ -219,9 +219,9 @@ func (o *initCmd) run(writer io.Writer) error { return err } - // if there is login required + // if there is login required, exectue the login command as the last step if o.login { - + fmt.Println("please login...") client, _, err := helper.GetK8sClient() if err != nil { return err @@ -233,8 +233,33 @@ func (o *initCmd) run(writer io.Writer) error { return err } - // TODO: Stupid way, just sleep to wait container is ready, maybe a watch is a better option - time.Sleep(15 * time.Second) + fmt.Println("wait for the deployment to be ready") + // Wait for the deployment ready + checkCmdArgs := []string{ + "rollout", + "status", + "deployment/bilibilipro", + "-n", + o.deployOpts.Namespace, + } + checkCmd := exec.Command("kubectl", checkCmdArgs...) + + for { + if err := checkCmd.Start(); err != nil { + fmt.Printf("deployment is not ready yet, current status: %v\n", err) + continue + } + + err := checkCmd.Wait() + if err == nil { + fmt.Printf("deployment is ready\n") + break + } + fmt.Printf("deployment is not ready yet, current status: %v\n", err) + } + + fmt.Println("please scan the QR code") + // Exec the login command args := []string{ "exec", podName, diff --git a/krew/pkg/cmd/version.go b/krew/pkg/cmd/version.go index 6a7b43f30..d0c85d860 100644 --- a/krew/pkg/cmd/version.go +++ b/krew/pkg/cmd/version.go @@ -4,8 +4,6 @@ import ( "fmt" "io" - "k8s.io/klog/v2" - "github.com/spf13/cobra" ) @@ -35,7 +33,7 @@ func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { err := o.run() if err != nil { - klog.Error(err) + fmt.Println(err) return err } return nil diff --git a/krew/pkg/resources/base/bilibiliPro/deployment.yaml b/krew/pkg/resources/base/bilibiliPro/deployment.yaml index 7ec6d1343..97b8d89a3 100644 --- a/krew/pkg/resources/base/bilibiliPro/deployment.yaml +++ b/krew/pkg/resources/base/bilibiliPro/deployment.yaml @@ -13,7 +13,7 @@ spec: spec: containers: - name: bilibilipro - image: zai7lou/bilibili_tool_pro:1.0.1 + image: zai7lou/bilibili_tool_pro:2.0.1 imagePullPolicy: IfNotPresent resources: requests: diff --git a/krew/pkg/utils/client.go b/krew/pkg/utils/client.go index 7a220867b..81f058736 100644 --- a/krew/pkg/utils/client.go +++ b/krew/pkg/utils/client.go @@ -33,6 +33,8 @@ func GetK8sClient() (*kubernetes.Clientset, *rest.Config, error) { if err != nil { return nil, nil, GenErrorMsg(SERVER_ERROR, err.Error()) } + config.QPS = float32(10.0) + config.Burst = 20 // create the clientset clientset, err := kubernetes.NewForConfig(config) From 0f21718ee657c4fbc5b340ec4af6195fe8569a92 Mon Sep 17 00:00:00 2001 From: seiuneko <25706824+seiuneko@users.noreply.github.com> Date: Sat, 2 Dec 2023 00:08:04 +0800 Subject: [PATCH 6/8] =?UTF-8?q?build:=20=E4=BF=AE=E6=94=B9=20publish.sh=20?= =?UTF-8?q?=E6=8A=91=E5=88=B6=E8=B0=83=E8=AF=95=E7=AC=A6=E5=8F=B7=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=B9=E5=BC=8F=20(#600)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/publish.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/publish.sh b/scripts/publish.sh index 22ef74fcd..74811d8e7 100644 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -62,11 +62,10 @@ publish_dotnet_dependent() { dotnet publish --configuration Release \ --self-contained false \ -p:PublishSingleFile=true \ + -p:DebugType=None \ + -p:DebugSymbols=false \ -o $outputDir - echo "clear pdb files" - rm -rf $outputDir/*.pdb - echo "zip files..." cd $publishDir zip -q -r bilibili-tool-pro-v$version-dotnet-dependent.zip ./dotnet-dependent/* @@ -90,11 +89,10 @@ publish_self_contained() { --runtime $runtime \ -p:PublishTrimmed=true \ -p:PublishSingleFile=true \ + -p:DebugType=None \ + -p:DebugSymbols=false \ -o $outputDir - echo "clear pdb files" - rm -rf $outputDir/*.pdb - echo "zip files..." cd $publishDir zip -q -r bilibili-tool-pro-v$version-$runtime.zip ./$runtime/* From aa737895521bb08b71ab153dd26aedc6dd9c6f8d Mon Sep 17 00:00:00 2001 From: Polaris_cn Date: Sat, 2 Dec 2023 00:11:26 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=A2=9E=E5=8A=A0=E4=B8=93=E6=A0=8F=E6=8A=95?= =?UTF-8?q?=E5=B8=81=E5=8A=9F=E8=83=BD=E4=B8=8E=E9=A2=86=E5=8F=96=E5=A4=A7?= =?UTF-8?q?=E4=BC=9A=E5=91=98=E7=BB=8F=E9=AA=8C=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20(#617)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 添加条件排除无法进行直播挂机的up主 * 为跳过的主播添加跳过提示 * 专栏投币基本框架已完成 * 专栏签到全流程基本完成,将开发环境硬编码调整为专栏投币模式开始进行挂机测试。 * 修复了一下Bug,目前专栏投币功能已经能正常运行 * 显式添加个性化配置IsDonateCoinForArticle * 添加对专栏投币同时点赞的功能,与视频点赞共享一个参数 * 修复硬币数量多的时候可投硬币数返回值错误 * 添加了一些log,方便调试 * 修改单词拼写错误 * 临时的windows环境构建脚本 * 删除未使用的参数 * 添加卡券状态查询相关api * 完成每日领取大会员经验任务,同时修复在大积分任务中的一些错误 * 修改调用错误 --- scripts/publish.ps1 | 16 + .../Dtos/Article/AddCoinForArticleRequest.cs | 22 + .../Dtos/Article/SearchArticleInfoResponse.cs | 10 + .../Article/SearchArticlesByUpIdFullFto.cs | 19 + .../Dtos/Article/SearchUpArticlesResponse.cs | 18 + .../Dtos/VipTask/VipExperienceRequest.cs | 6 + .../Dtos/VipTask/VouchersInfoResponse.cs | 28 ++ .../BiliBiliAgent/Interfaces/IArticleApi.cs | 45 ++ .../Interfaces/IVipBigPointApi.cs | 7 + .../Extensions/ServiceCollectionExtension.cs | 3 + .../IVipBigPointAppService.cs | 2 + .../DailyTaskAppService.cs | 30 +- .../VipBigPointAppService.cs | 71 +++- .../Options/DailyTaskOptions.cs | 5 + src/Ray.BiliBiliTool.Console/appsettings.json | 1 + .../ArticleDomainService.cs | 395 ++++++++++++++++++ .../DonateCoinDomainService.cs | 4 +- .../Interfaces/IArticleDomainService.cs | 12 + .../LiveDomainService.cs | 8 + test/AppServiceTest/VipServiceTest.cs | 21 + test/BiliAgentTest/VipApiTest.cs | 59 +++ .../ArticleDomainServiceTest.cs | 47 +++ 22 files changed, 818 insertions(+), 11 deletions(-) create mode 100644 scripts/publish.ps1 create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs create mode 100644 src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs create mode 100644 src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs create mode 100644 src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs create mode 100644 test/AppServiceTest/VipServiceTest.cs create mode 100644 test/BiliAgentTest/VipApiTest.cs create mode 100644 test/DomainServiceTest/ArticleDomainServiceTest.cs diff --git a/scripts/publish.ps1 b/scripts/publish.ps1 new file mode 100644 index 000000000..e21417b8c --- /dev/null +++ b/scripts/publish.ps1 @@ -0,0 +1,16 @@ +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-x86 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-x86 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-x64 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-arm64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-arm64 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-x64 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-musl-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-musl-x64 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-arm64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-arm64 +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-arm --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-arm +dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime osx-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/osx-x64 +Remove-Item ./bin/Publish/win-x86/*.pdb +Remove-Item ./bin/Publish/win-x64/*.pdb +Remove-Item ./bin/Publish/win-arm64/*.pdb +Remove-Item ./bin/Publish/linux-x64/*.pdb +Remove-Item ./bin/Publish/linux-musl-x64/*.pdb +Remove-Item ./bin/Publish/linux-arm64/*.pdb +Remove-Item ./bin/Publish/linux-arm/*.pdb +Remove-Item ./bin/Publish/osx-x64/*.pdb diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs new file mode 100644 index 000000000..7fd3f3e9d --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs @@ -0,0 +1,22 @@ +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; + +public class AddCoinForArticleRequest +{ + public AddCoinForArticleRequest(long cvid,long mid,string csrf) + { + Aid = cvid; + Upid = mid; + Csrf = csrf; + } + + public long Aid { get; set; } + + public long Upid { get; set; } + + public int Multiply { get; set; } = 1; + + // 必须为2 + public int Avtype { get; private set; } = 2; + + public string Csrf { get; set; } +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs new file mode 100644 index 000000000..22b9b37a6 --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs @@ -0,0 +1,10 @@ +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; + +public class SearchArticleInfoResponse +{ + public int Like { get; set; } + + public int Coin { get; set; } + + public long Mid { get; set; } +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs new file mode 100644 index 000000000..e4cae3b9b --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs @@ -0,0 +1,19 @@ +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; + +public class SearchArticlesByUpIdDto +{ + public long Mid { get; set; } + + public int Pn { get; set; } = 1; + + public int Ps { get; set; } = 30; + + public string Sort { get; set; } = "publish_time"; +} + +public class SearchArticlesByUpIdFullDto : SearchArticlesByUpIdDto +{ + public string w_rid { get; set; } + + public long wts { get; set; } +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs new file mode 100644 index 000000000..bef59b449 --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; + +public class SearchUpArticlesResponse +{ + public List Articles { get; set; } + public int Count { get; set; } + +} + +public class ArticleInfo +{ + public long Id { get; set; } + + public string Title { get; set; } + +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs new file mode 100644 index 000000000..542e6b083 --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs @@ -0,0 +1,6 @@ +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask; + +public class VipExperienceRequest +{ + public string csrf { get; set; } +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs new file mode 100644 index 000000000..ae85e0fd8 --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask; + +public class VouchersInfoResponse +{ + public List List { get; set; } + public bool IsShortVip { get; set; } + public bool IsFreightOpen { get; set; } + public int Level { get; set; } + public int CurExp { get; set; } + public int NextExp { get; set; } + public bool IsVip { get; set; } + public int IsSeniorMember { get; set; } + public int Format060102 { get; set; } +} + + +public class List +{ + public int Type { get; set; } + public int State { get; set; } + public int ExpireTime { get; set; } + public int VipType { get; set; } + public int NextReceiveDays { get; set; } + public int PeriodEndUnix { get; set; } +} + diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs new file mode 100644 index 000000000..2019bb33b --- /dev/null +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Video; +using WebApiClientCore.Attributes; + +namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces +{ + + [Header("Host", "api.bilibili.com")] + public interface IArticleApi : IBiliBiliApi + { + [Header("Content-Type", "application/x-www-form-urlencoded")] + [Header("Origin", "https://www.bilibili.com")] + [HttpPost("/x/web-interface/coin/add")] + Task AddCoinForArticle([FormContent] AddCoinForArticleRequest request, [Header("referer")] string refer = "https://www.bilibili.com/read/cv5806746/?from=search&spm_id_from=333.337.0.0"); + + + [Header("Referer", "https://www.bilibili.com/")] + [Header("Origin", "https://space.bilibili.com")] + [HttpGet("/x/space/wbi/article")] + Task> SearchUpArticlesByUpId( + [PathQuery] SearchArticlesByUpIdFullDto request); + + /// + /// 获取专栏详情 + /// + /// + /// + [HttpGet("/x/article/viewinfo?id={cvid}")] + Task> SearchArticleInfo(long cvid); + + + [Header("Content-Type", "application/x-www-form-urlencoded")] + [Header("Referer", "https://www.bilibili.com/read/cv{cvid}/?from=search&spm_id_from=333.337.0.0")] + [Header("Origin", "https://www.bilibili.com")] + [HttpPost("/x/article/like?id={cvid}&type=1&csrf={csrf}")] + Task Like(long cvid, string csrf); + + } + + +} diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs index ecc0451da..f83122d74 100644 --- a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs +++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs @@ -31,5 +31,12 @@ public interface IVipBigPointApi [HttpPost("/pgc/activity/deliver/task/complete")] Task ViewComplete([FormContent] ViewRequest request); + + [HttpGet("/x/vip/privilege/my")] + Task> GetVouchersInfo(); + + [Header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")] + [HttpPost("/x/vip/experience/add")] + Task GetVipExperience([FormContent] VipExperienceRequest request); } } diff --git a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs index 64558e390..92b8831c4 100644 --- a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs +++ b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs @@ -73,6 +73,9 @@ public static IServiceCollection AddBiliBiliClientApi(this IServiceCollection se services.AddBiliBiliClientApi("https://live-trace.bilibili.com"); services.AddBiliBiliClientApi("https://www.bilibili.com", false); + // 添加注入 + services.AddBiliBiliClientApi("https://api.bilibili.com"); + //qinglong var qinglongHost = configuration["QL_URL"] ?? "http://localhost:5600"; services diff --git a/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs b/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs index abd10b07f..f78097ef3 100644 --- a/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs +++ b/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Text; +using System.Threading.Tasks; namespace Ray.BiliBiliTool.Application.Contracts { @@ -12,5 +13,6 @@ namespace Ray.BiliBiliTool.Application.Contracts public interface IVipBigPointAppService : IAppService { + Task VipExpress(); } } diff --git a/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs b/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs index 6f82e6d59..db2ee02f9 100644 --- a/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs +++ b/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs @@ -23,6 +23,7 @@ public class DailyTaskAppService : AppService, IDailyTaskAppService private readonly ILogger _logger; private readonly IAccountDomainService _accountDomainService; private readonly IVideoDomainService _videoDomainService; + private readonly IArticleDomainService _articleDomainService; private readonly IDonateCoinDomainService _donateCoinDomainService; private readonly IMangaDomainService _mangaDomainService; private readonly ILiveDomainService _liveDomainService; @@ -41,6 +42,7 @@ public DailyTaskAppService( IOptionsMonitor> dicOptions, IAccountDomainService accountDomainService, IVideoDomainService videoDomainService, + IArticleDomainService articleDomainService, IDonateCoinDomainService donateCoinDomainService, IMangaDomainService mangaDomainService, ILiveDomainService liveDomainService, @@ -56,6 +58,7 @@ public DailyTaskAppService( _expDic = dicOptions.Get(Constants.OptionsNames.ExpDictionaryName); _accountDomainService = accountDomainService; _videoDomainService = videoDomainService; + _articleDomainService = articleDomainService; _donateCoinDomainService = donateCoinDomainService; _mangaDomainService = mangaDomainService; _liveDomainService = liveDomainService; @@ -79,7 +82,8 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken) DailyTaskInfo dailyTaskInfo = await GetDailyTaskStatus(); await WatchAndShareVideo(dailyTaskInfo); - await AddCoinsForVideo(userInfo); + + await AddCoins(userInfo); //签到: await LiveSign(); @@ -91,6 +95,9 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken) await ReceiveVipPrivilege(userInfo); await ReceiveMangaVipReward(userInfo); + //TODO 大会员领经验 + + await Charge(userInfo); } @@ -124,7 +131,7 @@ protected async Task SetCookiesAsync(BiliCookie biliCookie, Cancella private async Task Login() { UserInfo userInfo = await _accountDomainService.LoginByCookie(); - if (userInfo == null) throw new Exception("登录失败,请检查Cookie");//终止流程 + if (userInfo == null) throw new Exception("登录失败,请检查Cookie"); //终止流程 _expDic.TryGetValue("每日登录", out int exp); _logger.LogInformation("登录成功,经验+{exp} √", exp); @@ -153,6 +160,7 @@ private async Task WatchAndShareVideo(DailyTaskInfo dailyTaskInfo) _logger.LogInformation("已配置为关闭,跳过任务"); return; } + await _videoDomainService.WatchAndShareVideo(dailyTaskInfo); } @@ -160,14 +168,28 @@ private async Task WatchAndShareVideo(DailyTaskInfo dailyTaskInfo) /// 投币任务 /// [TaskInterceptor("投币", rethrowWhenException: false)] - private async Task AddCoinsForVideo(UserInfo userInfo) + private async Task AddCoins(UserInfo userInfo) { if (_dailyTaskOptions.SaveCoinsWhenLv6 && userInfo.Level_info.Current_level >= 6) { _logger.LogInformation("已经为LV6大佬,开始白嫖"); return; } - await _donateCoinDomainService.AddCoinsForVideos(); + + if (_dailyTaskOptions.IsDonateCoinForArticle) + { + _logger.LogInformation("专栏投币已开启"); + + if (!await _articleDomainService.AddCoinForArticles()) + { + _logger.LogInformation("专栏投币结束,转入视频投币"); + await _donateCoinDomainService.AddCoinsForVideos(); + } + } + else + { + await _donateCoinDomainService.AddCoinsForVideos(); + } } /// diff --git a/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs b/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs index fd7a8c197..7d3d038ee 100644 --- a/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs +++ b/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Ray.BiliBiliTool.Agent; using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos; using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask; using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces; @@ -19,23 +20,81 @@ public class VipBigPointAppService : AppService, IVipBigPointAppService private readonly IConfiguration _configuration; private readonly IVipBigPointApi _vipApi; private readonly IAccountDomainService _loginDomainService; + private readonly IVideoDomainService _videoDomainService; + private readonly IAccountDomainService _accountDomainService; + private readonly BiliCookie _biliCookie; public VipBigPointAppService( IConfiguration configuration, ILogger logger, IVipBigPointApi vipApi, - IAccountDomainService loginDomainService - ) + IAccountDomainService loginDomainService, + IVideoDomainService videoDomainService, + BiliCookie biliCookie, IAccountDomainService accountDomainService) { _configuration = configuration; _logger = logger; _vipApi = vipApi; _loginDomainService = loginDomainService; + _videoDomainService = videoDomainService; + _biliCookie = biliCookie; + _accountDomainService = accountDomainService; } + public async Task VipExpress() + { + _logger.LogInformation("大会员经验领取任务开始"); + var re = await _vipApi.GetVouchersInfo(); + if (re.Code == 0) + { + var state = re.Data.List.Find(x => x.Type == 9).State; + + switch (state) + { + case 2: + _logger.LogInformation("大会员经验观看任务未完成"); + _logger.LogInformation("开始观看视频"); + // 观看视频,暂时没有好办法解决,先这样使着 + DailyTaskInfo dailyTaskInfo = await _accountDomainService.GetDailyTaskStatus(); + await _videoDomainService.WatchAndShareVideo(dailyTaskInfo); + // 跳转到未兑换,执行兑换任务 + goto case 0; + + case 1: + _logger.LogInformation("大会员经验已兑换"); + break; + + case 0: + _logger.LogInformation("大会员经验未兑换"); + //兑换api + var response = await _vipApi.GetVipExperience(new VipExperienceRequest() + { + csrf = _biliCookie.BiliJct + }); + if (response.Code != 0) + { + _logger.LogInformation("大会员经验领取失败,错误信息:{message}", response.Message); + break; + } + _logger.LogInformation("领取成功,经验+10 √"); + break; + + default: + _logger.LogDebug("大会员经验领取失败,未知错误"); + break; + } + + } + + } + + [TaskInterceptor("大会员大积分", TaskLevel.One)] public override async Task DoTaskAsync(CancellationToken cancellationToken) { + await VipExpress(); + + // TODO 解决taskInfo在一个任务出错后,后续的任务均会报空引用错误 var ui = await GetUserInfo(); if (ui.GetVipType() == VipType.None) @@ -66,7 +125,7 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken) taskInfo = await ViewAnimate(taskInfo); //浏览影视频道页10秒 - taskInfo = await ViewFilmChannel(taskInfo); + // taskInfo = await ViewFilmChannel(taskInfo); //浏览会员购页面10秒 taskInfo = ViewVipMall(taskInfo); @@ -76,10 +135,12 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken) //领取购买任务 taskInfo = await BuyVipVideo(taskInfo); - taskInfo = await BuyVipProduct(taskInfo); + // taskInfo = await BuyVipProduct(taskInfo); taskInfo = await BuyVipMall(taskInfo); - + taskInfo.LogInfo(_logger); + + } [TaskInterceptor("测试Cookie")] diff --git a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs index 2258edf00..810562797 100644 --- a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs +++ b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs @@ -18,6 +18,11 @@ public class DailyTaskOptions /// public bool IsShareVideo { get; set; } + /// + /// 是否开启专栏投币模式 + /// + public bool IsDonateCoinForArticle { get; set; } + /// /// 每日设定的投币数 [0,5] /// diff --git a/src/Ray.BiliBiliTool.Console/appsettings.json b/src/Ray.BiliBiliTool.Console/appsettings.json index a3f85f0cf..d92fc1e05 100644 --- a/src/Ray.BiliBiliTool.Console/appsettings.json +++ b/src/Ray.BiliBiliTool.Console/appsettings.json @@ -6,6 +6,7 @@ "Cron": "0 15 * * *", "IsWatchVideo": true, //是否观看视频 "IsShareVideo": true, //是否分享视频 + "IsDonateCoinForArticle": false, "NumberOfCoins": 5, //每日设定的投币数 [0,5] "NumberOfProtectedCoins": 0, // 要保留的硬币数量 [0,int_max],0 为不保留,int_max 通常取 (2^31)-1 "SaveCoinsWhenLv6": false, //达到六级后是否开始白嫖[false,true] diff --git a/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs b/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs new file mode 100644 index 000000000..bda778dba --- /dev/null +++ b/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Polly; +using Ray.BiliBiliTool.Agent; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces; +using Ray.BiliBiliTool.Config.Options; +using Ray.BiliBiliTool.DomainService.Interfaces; + +namespace Ray.BiliBiliTool.DomainService; + +public class ArticleDomainService : IArticleDomainService +{ + private readonly IArticleApi _articleApi; + private readonly BiliCookie _biliCookie; + private readonly ILogger _logger; + private readonly DailyTaskOptions _dailyTaskOptions; + private readonly ICoinDomainService _coinDomainService; + private readonly IAccountApi _accountApi; + private readonly IWbiDomainService _wbiDomainService; + + + /// + /// up的专栏总数缓存 + /// + private readonly Dictionary _upArticleCountDicCatch = new(); + + /// + /// 已对投币数量缓存 + /// + private readonly Dictionary _alreadyDonatedCoinCountCatch = new(); + + public ArticleDomainService( + IArticleApi articleApi, + BiliCookie biliCookie, + ILogger logger, + IOptionsMonitor dailyTaskOptions, + ICoinDomainService coinDomainService, + IAccountApi accountApi, IWbiDomainService wbiDomainService) + { + _articleApi = articleApi; + _biliCookie = biliCookie; + _logger = logger; + _coinDomainService = coinDomainService; + _accountApi = accountApi; + _wbiDomainService = wbiDomainService; + _dailyTaskOptions = dailyTaskOptions.CurrentValue; + } + + + + public async Task LikeArticle(long cvid) + { + await _articleApi.Like(cvid, _biliCookie.BiliJct); + } + + /// + /// 投币专栏任务 + /// + /// + public async Task AddCoinForArticles() + { + + var donateCoinsCounts = await CalculateDonateCoinsCounts(); + + if (donateCoinsCounts == 0) + { + // 没有可投的币相当于投币任务全部完成 + return true; + } + + + int success = 0; + int tryCount = 10; + + for (int i = 0; i <= tryCount && success < donateCoinsCounts; i++) + { + _logger.LogDebug("开始尝试第{num}次", i); + + var upId = GetUpFromConfigUps(); + var cvid = await GetRandomArticleFromUp(upId); + if (upId == 0 || cvid == 0) + { + _logger.LogInformation("未添加支持的Up主,任务跳过"); + return false; + } + + if (await AddCoinForArticle(cvid, upId)) + { + // 点赞 + if (_dailyTaskOptions.SelectLike) + { + await LikeArticle(cvid); + _logger.LogInformation("文章点赞成功"); + } + success++; + } + + + } + + if (success == donateCoinsCounts) + _logger.LogInformation("专栏投币任务完成"); + else + { + _logger.LogInformation("投币尝试超过10次,已终止"); + return false; + } + + + _logger.LogInformation("【硬币余额】{coin}", (await _accountApi.GetCoinBalance()).Data.Money ?? 0); + + return true; + } + + + /// + /// 给某一篇专栏投币 + /// + /// 文章cvid + /// 文章作者mid + /// 投币是否成功(false 投币失败,true 投币成功) + public async Task AddCoinForArticle(long cvid, long mid) + { + BiliApiResponse result; + try + { + var refer = $"https://www.bilibili.com/read/cv{cvid}/?from=search&spm_id_from=333.337.0.0"; + result = await _articleApi.AddCoinForArticle(new AddCoinForArticleRequest(cvid, mid, _biliCookie.BiliJct), + refer); + } + catch (Exception) + { + return false; + } + + if (result.Code == 0) + { + _logger.LogInformation("投币成功,经验+10 √"); + return true; + } + else + { + _logger.LogError("投币错误 {message}", result.Message); + return false; + } + } + + + #region private + + /// + /// 从某个up主中随机挑选一个专栏 + /// + /// + /// 专栏的cvid + private async Task GetRandomArticleFromUp(long mid) + { + if (!_upArticleCountDicCatch.TryGetValue(mid, out int articleCount)) + { + articleCount = await GetArticleCountOfUp(mid); + _upArticleCountDicCatch.Add(mid, articleCount); + } + + // 专栏数为0时 + if (articleCount == 0) + { + return 0; + } + + var req = new SearchArticlesByUpIdDto() + { + Mid = mid, + Ps = 1, + Pn = new Random().Next(1, articleCount + 1) + }; + var w_ridDto = await _wbiDomainService.GetWridAsync(req); + + var fullDto = new SearchArticlesByUpIdFullDto() + { + Mid = mid, + Ps = req.Ps, + Pn = req.Pn, + w_rid = w_ridDto.w_rid, + wts = w_ridDto.wts + }; + + BiliApiResponse re = await _articleApi.SearchUpArticlesByUpId(fullDto); + + if (re.Code != 0) + { + throw new Exception(re.Message); + } + + ArticleInfo articleInfo = re.Data.Articles.FirstOrDefault(); + + _logger.LogDebug("获取到的专栏{cvid}({title})", articleInfo.Id, articleInfo.Title); + + // 检查是否可投 + if (!await IsCanDonate(articleInfo.Id)) + { + return 0; + } + + return articleInfo.Id; + } + + + // TODO 转变为异步代码 + /// + /// 从支持UP主列表中随机挑选一位 + /// + /// 被挑选up主的mid + private long GetUpFromConfigUps() + { + if (_dailyTaskOptions.SupportUpIdList == null || _dailyTaskOptions.SupportUpIdList.Count == 0) + { + return 0; + } + + try + { + long randomUpId = + _dailyTaskOptions.SupportUpIdList[new Random().Next(0, _dailyTaskOptions.SupportUpIdList.Count)]; + + if (randomUpId is 0 or long.MinValue) return 0; + + if (randomUpId.ToString() == _biliCookie.UserId) + { + _logger.LogDebug("不能为自己投币"); + return 0; + } + _logger.LogDebug("挑选出的up主为{UpId}",randomUpId); + return randomUpId; + } + catch (Exception e) + { + _logger.LogWarning("异常:{msg}", e); + } + + return 0; + } + + /// + /// 获取Up主专栏总数 + /// + /// up主mid + /// 专栏总数 + /// + private async Task GetArticleCountOfUp(long mid) + { + var req = new SearchArticlesByUpIdDto() + { + Mid = mid + }; + + var w_ridDto = await _wbiDomainService.GetWridAsync(req); + + var fullDto = new SearchArticlesByUpIdFullDto() + { + Mid = mid, + w_rid = w_ridDto.w_rid, + wts = w_ridDto.wts + }; + + BiliApiResponse re = await _articleApi.SearchUpArticlesByUpId(fullDto); + + if (re.Code != 0) + { + throw new Exception(re.Message); + } + + return re.Data.Count; + } + + /// + /// 计算所需要投的硬币数量 + /// + /// 硬币数量 + private async Task CalculateDonateCoinsCounts() + { + int needCoins = await GetNeedDonateCoinCounts(); + + int protectedCoins = _dailyTaskOptions.NumberOfProtectedCoins; + if (needCoins <= 0) return 0; + + //投币前硬币余额 + decimal coinBalance = await _coinDomainService.GetCoinBalance(); + _logger.LogInformation("【投币前余额】 : {coinBalance}", coinBalance); + _ = int.TryParse(decimal.Truncate(coinBalance - protectedCoins).ToString(), out int unprotectedCoins); + + if (coinBalance <= 0) + { + _logger.LogInformation("因硬币余额不足,今日暂不执行投币任务"); + return 0; + } + + if (coinBalance <= protectedCoins) + { + _logger.LogInformation("因硬币余额达到或低于保留值,今日暂不执行投币任务"); + return 0; + } + + //余额小于目标投币数,按余额投 + if (coinBalance < needCoins) + { + _ = int.TryParse(decimal.Truncate(coinBalance).ToString(), out needCoins); + _logger.LogInformation("因硬币余额不足,目标投币数调整为: {needCoins}", needCoins); + return needCoins; + } + + //投币后余额小于等于保护值,按保护值允许投 + if (coinBalance - needCoins <= protectedCoins) + { + //排除需投等于保护后可投数量相等时的情况 + if (unprotectedCoins != needCoins) + { + needCoins = unprotectedCoins; + _logger.LogInformation("因硬币余额投币后将达到或低于保留值,目标投币数调整为: {needCoins}", needCoins); + return needCoins; + } + } + + return needCoins; + } + + private async Task GetNeedDonateCoinCounts() + { + int configCoins = _dailyTaskOptions.NumberOfCoins; + + if (configCoins <= 0) + { + _logger.LogInformation("已配置为跳过投币任务"); + return configCoins; + } + + //已投的硬币 + int alreadyCoins = await _coinDomainService.GetDonatedCoins(); + + int targetCoins = configCoins; + + _logger.LogInformation("【今日已投】{already}枚", alreadyCoins); + _logger.LogInformation("【目标欲投】{already}枚", targetCoins); + + if (targetCoins > alreadyCoins) + { + int needCoins = targetCoins - alreadyCoins; + _logger.LogInformation("【还需再投】{need}枚", needCoins); + return needCoins; + } + + _logger.LogInformation("已完成投币任务,不需要再投啦~"); + return 0; + } + + + private async Task IsCanDonate(long cvid) + { + try + { + if (_alreadyDonatedCoinCountCatch.Any(x => x.Key == cvid.ToString())) + { + _logger.LogDebug("重复专栏,丢弃处理"); + return false; + } + + if (!_alreadyDonatedCoinCountCatch.TryGetValue(cvid.ToString(), out int multiply)) + { + multiply = (await _articleApi.SearchArticleInfo(cvid)).Data.Coin; + _alreadyDonatedCoinCountCatch.TryAdd(cvid.ToString(), multiply); + } + + // 在网页端我测试时只能投一枚硬币,暂时设置最多投一枚 + if (multiply >= 1) + { + return false; + } + + return true; + } + catch (Exception e) + { + _logger.LogWarning("异常:{mag}", e); + return false; + } + } + + #endregion +} diff --git a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs index 8e5114749..c989c595f 100644 --- a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs @@ -124,7 +124,7 @@ public async Task AddCoinsForVideos() } if (success == needCoins) - _logger.LogInformation("投币任务完成"); + _logger.LogInformation("视频投币任务完成"); else _logger.LogInformation("投币尝试超过10次,已终止"); @@ -419,7 +419,7 @@ private async Task IsCanDonate(string aid) //已经投满2个币的,不能再投 if (!await IsDonatedLessThenLimitCoinsForVideo(aid)) { - _logger.LogDebug("超出单个视频投币数量限制,丢弃处理", aid); + _logger.LogDebug("超出单个视频投币数量限制,丢弃处理"); return false; } diff --git a/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs b/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs new file mode 100644 index 000000000..f5a2f6d77 --- /dev/null +++ b/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; + +namespace Ray.BiliBiliTool.DomainService.Interfaces; + +public interface IArticleDomainService : IDomainService +{ + Task AddCoinForArticle(long cvid, long mid); + + Task AddCoinForArticles(); + + Task LikeArticle(long cvid); +} diff --git a/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs b/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs index 71e9fe23f..6cf387596 100644 --- a/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs +++ b/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs @@ -614,6 +614,14 @@ private async Task> GetFansMedalInfoList() continue; } + // 用以排除有牌子无直播间的up主 + if (spaceInfo.Data.Live_room is null) + { + _logger.LogInformation("【主播】{name} 直播间id获取失败,已跳过",medal.Target_name); + continue; + } + + var roomId = spaceInfo.Data.Live_room.Roomid; // 获取直播间详细信息 diff --git a/test/AppServiceTest/VipServiceTest.cs b/test/AppServiceTest/VipServiceTest.cs new file mode 100644 index 000000000..f50bafe0d --- /dev/null +++ b/test/AppServiceTest/VipServiceTest.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Ray.BiliBiliTool.Application.Contracts; +using Ray.BiliBiliTool.Infrastructure; + +namespace AppServiceTest; + +public class VipServiceTest +{ + public VipServiceTest() + { + Program.CreateHost(new[] { "--ENVIRONMENT=Development" }); + } + + [Fact] + public async Task VipExpressTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + var appService = scope.ServiceProvider.GetRequiredService(); + await appService.VipExpress(); + } +} diff --git a/test/BiliAgentTest/VipApiTest.cs b/test/BiliAgentTest/VipApiTest.cs new file mode 100644 index 000000000..3e540a0a2 --- /dev/null +++ b/test/BiliAgentTest/VipApiTest.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using Xunit; +using Microsoft.Extensions.DependencyInjection; +using Ray.BiliBiliTool.Agent; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask; +using Ray.BiliBiliTool.Console; +using Ray.BiliBiliTool.Infrastructure; +using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces; +using Xunit.Abstractions; +namespace BiliAgentTest; + +public class VipApiTest +{ + private readonly ITestOutputHelper _output; + public VipApiTest(ITestOutputHelper output) + { + _output = output; + Program.CreateHost(new[] { "--ENVIRONMENT=Development" }); + } + + [Fact] + public async Task VipInfoTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + + var ck = scope.ServiceProvider.GetRequiredService(); + var api = scope.ServiceProvider.GetRequiredService(); + + var re = await api.GetVouchersInfo(); + if (re.Code == 0) + { + var info = re.Data.List.Find(x => x.Type == 9); + if (info != null) + { + _output.WriteLine(info.State.ToString()); + } + else + { + _output.WriteLine("error"); + } + } + } + + + [Fact] + public async Task GetVipExperienceTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + + var ck = scope.ServiceProvider.GetRequiredService(); + var api = scope.ServiceProvider.GetRequiredService(); + var re = await api.GetVipExperience(new VipExperienceRequest() + { + csrf = ck.BiliJct + }); + + _output.WriteLine(re.Message); + } +} diff --git a/test/DomainServiceTest/ArticleDomainServiceTest.cs b/test/DomainServiceTest/ArticleDomainServiceTest.cs new file mode 100644 index 000000000..6f9d268e4 --- /dev/null +++ b/test/DomainServiceTest/ArticleDomainServiceTest.cs @@ -0,0 +1,47 @@ +using Xunit.Abstractions; + +namespace DomainServiceTest; + +public class ArticleDomainServiceTest +{ + private readonly ITestOutputHelper _output; + public ArticleDomainServiceTest(ITestOutputHelper output) + { + _output = output; + Program.CreateHost(new[] { "--ENVIRONMENT=Development" }); + } + + [Fact] + public async Task LikeArticleTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + var config = Global.ConfigurationRoot; + var domainService = scope.ServiceProvider.GetRequiredService(); + await domainService.LikeArticle(5806746); + } + + + [Fact] + public async Task AddCoinForArticleTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + var config = Global.ConfigurationRoot; + var domainService = scope.ServiceProvider.GetRequiredService(); + + // 测试用的专栏:https://www.bilibili.com/read/cv5806746/?from=search&spm_id_from=333.337.0.0 + + await domainService.AddCoinForArticle(5806746, 486980924); + } + + + [Fact] + public async Task AddCoinForArticlesTest() + { + using var scope = Global.ServiceProviderRoot.CreateScope(); + var config = Global.ConfigurationRoot; + var domainService = scope.ServiceProvider.GetRequiredService(); + await domainService.AddCoinForArticles(); + } + + +} From 435475b0538407865a1e2751389d8ecaf6828196 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 3 Dec 2023 00:09:48 +0800 Subject: [PATCH 8/8] update current tag --- CHANGELOG.md | 2 ++ common.props | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc1962371..8c8d0f943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,3 +119,5 @@ ## 2.0.1 - PR[#539]:更新文档 - PR[#557]:修复直播接口权限不足问题 +## 2.0.2 +- PR[#617]:增加专栏投币功能与领取大会员经验的功能 diff --git a/common.props b/common.props index 79e7c677e..74347ebbe 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ Ray - 2.0.1 + 2.0.2 $(NoWarn);CS1591;CS0436