diff --git a/CHANGELOG.md b/CHANGELOG.md index 15b95bc..6fd7a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ # Release Notes # 本项目Log +## v0.5.0.200624 alpha (2020-06-24) + +### Added +- 添加破产机(赔到破产) +- 添加推送KEY到期通知 +- 添加天选自动取关(测试) +- 添加收益统计 +- 添加关注投币模式 +- + +### Changed +- 更新部分信息输出 +- 修改日志打印前缀 +- 更新活跃弹幕延迟 +- 重构部分统计代码 +- 更新视频投币逻辑 +- 更新实物抽奖API +- 修改硬币兑换延迟 +- + +### Fixed +- 修复日志输出错误 +- 修复每日送礼异常 +- 修复赛事逻辑错误 +- 修复部分已知问题 +- + ## v0.4.0.200505 alpha (2020-05-05) ### Added diff --git a/DOC.md b/DOC.md index 5ec250e..d20f722 100644 --- a/DOC.md +++ b/DOC.md @@ -2,7 +2,7 @@

- +

@@ -15,31 +15,32 @@ B 站直播实用脚本 |plugin |version |description | |--------------------|--------------------|--------------------| -|Login |20.05.05 |账号登录 | -|Schedule |20.05.05 |休眠控制 | -|MasterSite |20.05.05 |主站助手 | -|Daily |20.05.05 |每日礼包 | -|Heart |20.05.05 |双端心跳 | -|Task |20.05.05 |每日任务 | -|Silver |20.05.05 |银瓜子宝箱 | -|Barrage |20.05.05 |活跃弹幕 | -|Silver2Coin |20.05.05 |银瓜子换硬币 | -|GiftSend |20.05.05 |礼物赠送 | -|Judge |20.05.05 |风纪 | -|GroupSignIn |20.05.05 |友爱社签到 | -|ManGa |20.05.05 |漫画签到分享 | -|Match |20.05.05 |赛事签到分享 | -|GiftHeart |20.05.05 |心跳礼物 | -|MaterialObject |20.05.05 |实物抽奖 | -|AloneTcpClient |20.05.05 |独立监控 | -|ZoneTcpClient |20.05.05 |分区监控 | -|StormRaffle |20.05.05 |节奏风暴 | -|GiftRaffle |20.05.05 |活动礼物 | -|PkRaffle |20.05.05 |大乱斗 | -|GuardRaffle |20.05.05 |舰长总督 | -|AnchorRaffle |20.05.05 |天选时刻 | -|AwardRecord |20.05.05 |获奖通知 | -|Statistics |20.05.05 |数据统计 | +|Login |20.06.24 |账号登录 | +|Schedule |20.06.24 |休眠控制 | +|MasterSite |20.06.24 |主站助手 | +|Daily |20.06.24 |每日礼包 | +|Heart |20.06.24 |双端心跳 | +|Task |20.06.24 |每日任务 | +|Silver |20.06.24 |银瓜子宝箱 | +|Barrage |20.06.24 |活跃弹幕 | +|Silver2Coin |20.06.24 |银瓜子换硬币 | +|GiftSend |20.06.24 |礼物赠送 | +|Judge |20.06.24 |风纪 | +|GroupSignIn |20.06.24 |友爱社签到 | +|ManGa |20.06.24 |漫画签到分享 | +|Match |20.06.24 |赛事签到分享 | +|GiftHeart |20.06.24 |心跳礼物 | +|MaterialObject |20.06.24 |实物抽奖 | +|AloneTcpClient |20.06.24 |独立监控 | +|ZoneTcpClient |20.06.24 |分区监控 | +|StormRaffle |20.06.24 |节奏风暴 | +|GiftRaffle |20.06.24 |活动礼物 | +|PkRaffle |20.06.24 |大乱斗 | +|GuardRaffle |20.06.24 |舰长总督 | +|AnchorRaffle |20.06.24 |天选时刻 | +|AwardRecord |20.06.24 |获奖通知 | +|Statistics |20.06.24 |数据统计 | +|Competition |20.06.24 |赛事竞猜 | ## 打赏赞助 diff --git a/README.md b/README.md index d9151ee..05c3ff3 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Group: [55308141](https://jq.qq.com/?_wv=1027&k=5AIDaJg) | **仅用于BUG提交 ## 公告 -> Currently for Personal Edition **0.4.0.200505 alpha** +> Currently for Personal Edition **0.5.0.200624 alpha** ```notice ---- 免费的东西总是得不到人的珍惜。 diff --git a/composer.json b/composer.json index bc6d5b2..df5f982 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "clue/socket-raw": "^1.4.1", "vlucas/phpdotenv": "^4.1", "amphp/amp": "^2.4", - "guzzlehttp/guzzle": "^6.5" + "guzzlehttp/guzzle": "^6.5", + "mathieuviossat/arraytotexttable": "^1.0" }, "license": "MIT", "authors": [ diff --git a/composer.lock b/composer.lock index fa8de01..c5eabb3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e12b1349c43efa1aa58a89b33a44613e", + "content-hash": "773a1bbd829be3a7bb684f926002ac37", "packages": [ { "name": "amphp/amp", @@ -245,6 +245,44 @@ ], "time": "2019-10-28T12:32:07+00:00" }, + { + "name": "container-interop/container-interop", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "psr/container": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "abandoned": "psr/container", + "time": "2017-02-14T19:40:03+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "6.5.3", @@ -452,6 +490,59 @@ ], "time": "2019-07-01T23:21:34+00:00" }, + { + "name": "mathieuviossat/arraytotexttable", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/viossat/arraytotexttable.git", + "reference": "df25fafc56cedd64fcdab5a1d8793d0e97e635e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/viossat/arraytotexttable/zipball/df25fafc56cedd64fcdab5a1d8793d0e97e635e3", + "reference": "df25fafc56cedd64fcdab5a1d8793d0e97e635e3", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0", + "zendframework/zend-text": "^2.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "MathieuViossat\\Util\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathieu Viossat", + "email": "mathieu@viossat.fr", + "homepage": "https://viossat.fr" + } + ], + "description": "Display arrays in terminal", + "homepage": "https://github.com/viossat/arraytotexttable", + "keywords": [ + "array", + "ascii", + "table", + "terminal", + "text", + "unicode" + ], + "time": "2019-05-15T14:51:03+00:00" + }, { "name": "monolog/monolog", "version": "1.25.3", @@ -597,6 +688,61 @@ ], "time": "2020-03-21T18:07:53+00:00" }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -1145,6 +1291,189 @@ } ], "time": "2020-04-12T15:20:09+00:00" + }, + { + "name": "zendframework/zend-servicemanager", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-servicemanager.git", + "reference": "a1ed6140d0d3ee803fec96582593ed024950067b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/a1ed6140d0d3ee803fec96582593ed024950067b", + "reference": "a1ed6140d0d3ee803fec96582593ed024950067b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "container-interop/container-interop": "^1.2", + "php": "^5.6 || ^7.0", + "psr/container": "^1.0", + "zendframework/zend-stdlib": "^3.2.1" + }, + "provide": { + "container-interop/container-interop-implementation": "^1.2", + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6.5", + "ocramius/proxy-manager": "^1.0 || ^2.0", + "phpbench/phpbench": "^0.13.0", + "phpunit/phpunit": "^5.7.25 || ^6.4.4", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "suggest": { + "ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services", + "zendframework/zend-stdlib": "zend-stdlib ^2.5 if you wish to use the MergeReplaceKey or MergeRemoveKey features in Config instances" + }, + "bin": [ + "bin/generate-deps-for-config-factory", + "bin/generate-factory-for-class" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev", + "dev-develop": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\ServiceManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Factory-Driven Dependency Injection Container", + "keywords": [ + "PSR-11", + "ZendFramework", + "dependency-injection", + "di", + "dic", + "service-manager", + "servicemanager", + "zf" + ], + "abandoned": "laminas/laminas-servicemanager", + "time": "2018-12-22T06:05:09+00:00" + }, + { + "name": "zendframework/zend-stdlib", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-stdlib.git", + "reference": "66536006722aff9e62d1b331025089b7ec71c065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/66536006722aff9e62d1b331025089b7ec71c065", + "reference": "66536006722aff9e62d1b331025089b7ec71c065", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.13", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev", + "dev-develop": "3.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "SPL extensions, array utilities, error handlers, and more", + "keywords": [ + "ZendFramework", + "stdlib", + "zf" + ], + "abandoned": "laminas/laminas-stdlib", + "time": "2018-08-28T21:34:05+00:00" + }, + { + "name": "zendframework/zend-text", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-text.git", + "reference": "41e32dafa4015e160e2f95a7039554385c71624d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-text/zipball/41e32dafa4015e160e2f95a7039554385c71624d", + "reference": "41e32dafa4015e160e2f95a7039554385c71624d", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-config": "^2.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev", + "dev-develop": "2.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Text\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Create FIGlets and text-based tables", + "keywords": [ + "ZendFramework", + "text", + "zf" + ], + "abandoned": "laminas/laminas-text", + "time": "2019-10-16T20:36:27+00:00" } ], "packages-dev": [], diff --git a/conf/user.conf.example b/conf/user.conf.example index 5f56c40..a6b0b11 100644 --- a/conf/user.conf.example +++ b/conf/user.conf.example @@ -27,8 +27,9 @@ USE_GUARD=true # 大乱斗 USE_PK=true -# 天选时刻|抽取类型(0: 无限制; 1: 关注主播; 2: 粉丝勋章; 3大航海; 4用户等级;5主站等级)|过滤关键词|逗号分隔 +# 天选时刻|抽取类型(0: 无限制; 1: 关注主播; 2: 粉丝勋章; 3大航海; 4用户等级;5主站等级)|自动取关(测试功能)|过滤关键词|逗号分隔 USE_ANCHOR=false +ANCHOR_UNFOLLOW=false ANCHOR_TYPE=0,1 ANCHOR_FILTER_WORDS= @@ -48,10 +49,10 @@ USE_DANMU=true DANMU_ROOMID=9522051 DANMU_CONTENT= -# 视频投币|投币稿件数(每日任务最大5)|自定义稿件ID,空则随机(AV_NUM=1生效) +# 视频投币|random(随机热门)/fixed(关注列表)|投币稿件数(每日任务最大5) USE_ADD_COIN=false -ADD_COIN_AV_NUM=1 -ADD_COIN_AV=33492180 +ADD_COIN_MODE=random +ADD_COIN_NUM=5 # 休眠时间|时间区间(0-23)|逗号分隔 USE_SLEEP=true @@ -63,7 +64,13 @@ USE_MANGA=false # 赛事助手 USE_MATCH=false -# 风纪(测试) +# 破产机|每日竞猜次数|每次竞猜硬币(1-10)|下注(1.压大,2.压小,3.随机) +USE_COMPETITION=false +COMPET_MAX_NUM=20 +COMPET_MAX_COIN=10 +COMPET_STAKE=1 + +# 风纪委员 USE_JUDGE=false ####################### @@ -71,8 +78,8 @@ USE_JUDGE=false ####################### # 独立推送服务(主)|主备冲突 -USE_ALONE_SERVER=false -ALONE_SERVER_ADDR= +USE_ALONE_SERVER=true +ALONE_SERVER_ADDR=tcp://livecmt-1.mudew.com:10088 ALONE_SERVER_KEY= # 分区推送服务(备)|主备冲突 diff --git a/src/core/App.php b/src/core/App.php index ef8ee8c..b3be68c 100644 --- a/src/core/App.php +++ b/src/core/App.php @@ -70,6 +70,7 @@ class App 'Daily', 'ManGa', 'Match', + 'Competition', 'Heart', 'Task', 'Silver', diff --git a/src/core/Env.php b/src/core/Env.php index 1f46c03..4afbd6c 100644 --- a/src/core/Env.php +++ b/src/core/Env.php @@ -13,7 +13,7 @@ namespace BiliHelper\Core; class Env { private $app_name = 'BiliHelper Personal'; - private $app_version = '0.4.0.*'; + private $app_version = '0.5.0.*'; /** * Env constructor. @@ -50,7 +50,7 @@ class Env public function inspect_configure() { Log::info("欢迎使用 {$this->app_name} 当前版本 {$this->app_version}"); - Log::info("程序使用相关请移步 https://github.com/lkeme/BiliHelper-personal 文档部分查看。"); + Log::info("使用说明请移步 https://github.com/lkeme/BiliHelper-personal 查看。"); if (PHP_SAPI != 'cli') { die("Please run this script from command line ."); diff --git a/src/core/Log.php b/src/core/Log.php index 9936931..d0db464 100644 --- a/src/core/Log.php +++ b/src/core/Log.php @@ -29,7 +29,7 @@ class Log protected static function configureInstance() { - $logger = new Logger('Bilibili'); + $logger = new Logger('BH'); $handler = new StreamHandler('php://stdout', getenv('APP_DEBUG') == 'true' ? Logger::DEBUG : Logger::INFO); $handler->setFormatter(new ColoredLineFormatter()); $logger->pushHandler($handler); diff --git a/src/plugin/AloneTcpClient.php b/src/plugin/AloneTcpClient.php index 76f623f..6501f7b 100644 --- a/src/plugin/AloneTcpClient.php +++ b/src/plugin/AloneTcpClient.php @@ -228,8 +228,12 @@ class AloneTcpClient Log::info("确认到推送服务器 {$raw_data['type']}"); break; case 'error': - // 致命错误 - Log::error("推送服务器发生致命错误 {$raw_data['data']['msg']}"); + // 产生错误 + Log::error("推送服务器异常 {$raw_data['data']['msg']}, 程序挂起请手动关闭!"); + // KEY到期推送提醒 + Notice::push('key_expired', ''); + // 程序挂起 防止systemd无限重启导致触发过多推送提醒 + sleep(86400); exit(); break; case 'heartbeat': diff --git a/src/plugin/AnchorRaffle.php b/src/plugin/AnchorRaffle.php index 4d97690..56fa566 100644 --- a/src/plugin/AnchorRaffle.php +++ b/src/plugin/AnchorRaffle.php @@ -24,8 +24,102 @@ class AnchorRaffle extends BaseRaffle protected static $wait_list = []; protected static $finish_list = []; protected static $all_list = []; - + // 过滤类型 private static $filter_type = []; + // 默认关注 特殊关注 等待关注 + private static $default_follows = []; + private static $special_follows = []; + public static $wait_un_follows = []; + // 特殊分组 分组ID + private static $group_name = "玄不改非"; // 氪不改命 + private static $group_id = null; + + + /** + * @use 删除分组 + * @param int $un_follow_uid + * @param int $anchor_id + * @param bool $un_follow + */ + public static function delToGroup(int $un_follow_uid, int $anchor_id, bool $un_follow = true) + { + // 取关 + if ($un_follow) { + User::setUserFollow($un_follow_uid, true); + } + self::delValue($un_follow_uid, $anchor_id); + } + + /** + * @use 添加分组 + * @param int $room_id + * @param int $anchor_id + * @param int $time + */ + private static function addToGroup(int $room_id, int $anchor_id, int $time) + { + // 获取分组id + if (is_null(self::$group_id)) { + $tags = User::fetchTags(); + $tag_id = array_search(self::$group_name, $tags); + // 如果不存在则调用创建 + self::$group_id = $tag_id ? $tag_id : User::createRelationTag(self::$group_name); + } + // 获取需要关注的 + $data = Live::getRoomInfo($room_id); + if ($data['code'] == 0 && isset($data['data'])) { + $need_follow_uid = $data['data']['uid']; + } else { + return; + } + // 是否在关注里 + $default_follows = self::getDefaultFollows(); + if (!in_array($need_follow_uid, $default_follows)) { + User::setUserFollow($need_follow_uid); + User::tagAddUsers($need_follow_uid, self::$group_id); + // 添加到检测中奖 + array_push(self::$wait_un_follows, [ + 'uid' => $need_follow_uid, + 'anchor_id' => $anchor_id, + 'time' => $time, + ]); + } + } + + /** + * @use 删除值并重置数组 + * @param int $uid + * @param int $anchor_id + */ + private static function delValue(int $uid, int $anchor_id) + { + $new_list = []; + foreach (self::$wait_un_follows as $wait_un_follow) { + if ($wait_un_follow['uid'] == $uid && $wait_un_follow['uid'] == $anchor_id) { + continue; + } + array_push($new_list, $wait_un_follow); + } + self::$wait_un_follows = $new_list; + } + + + /** + * @use 获取默认关注 + * @return array + */ + private static function getDefaultFollows(): array + { + if (!empty(self::$default_follows)) { + return self::$default_follows; + } + // 如果获取默认关注错误 或者 为空则补全一个 + self::$default_follows = User::fetchTagFollowings(); + if (empty(self::$default_follows)) { + array_push(self::$default_follows, 1); + } + return self::$default_follows; + } /** @@ -88,6 +182,10 @@ class AnchorRaffle extends BaseRaffle if (self::toRepeatLid($de_raw['id'])) { return false; } + // 分组操作 + if (getenv('ANCHOR_UNFOLLOW') == 'true' && $de_raw['require_text'] == '关注主播') { + self::addToGroup($room_id, $de_raw['id'], time() + $de_raw['time'] + 5); + } // 推入列表 $data = [ 'room_id' => $room_id, @@ -95,7 +193,7 @@ class AnchorRaffle extends BaseRaffle 'raffle_name' => $de_raw['award_name'], 'wait' => time() + mt_rand(5, 25) ]; - Statistics::addPushList(self::ACTIVE_TITLE); + Statistics::addPushList($data['raffle_name']); array_push(self::$wait_list, $data); return true; } @@ -125,7 +223,8 @@ class AnchorRaffle extends BaseRaffle 'payload' => Sign::common($payload), 'source' => [ 'room_id' => $raffle['room_id'], - 'raffle_id' => $raffle['raffle_id'] + 'raffle_id' => $raffle['raffle_id'], + 'raffle_name' => $raffle['raffle_name'] ] ]); } @@ -147,7 +246,7 @@ class AnchorRaffle extends BaseRaffle $de_raw = json_decode($content, true); // {"code":-403,"data":null,"message":"访问被拒绝","msg":"访问被拒绝"} if (isset($de_raw['code']) && $de_raw['code'] == 0) { - Statistics::addSuccessList(self::ACTIVE_TITLE); + Statistics::addSuccessList($data['raffle_name']); Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": 参与抽奖成功~"); } elseif (isset($de_raw['msg']) && $de_raw['code'] == -403 && $de_raw['msg'] == '访问被拒绝') { Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['message']}"); diff --git a/src/plugin/AwardRecord.php b/src/plugin/AwardRecord.php index 5f45fcd..c3c4c45 100644 --- a/src/plugin/AwardRecord.php +++ b/src/plugin/AwardRecord.php @@ -17,6 +17,7 @@ use BiliHelper\Util\TimeLock; class AwardRecord { use TimeLock; + private static $raffle_lock = 0; private static $raffle_list = []; private static $anchor_lock = 0; @@ -75,6 +76,18 @@ class AwardRecord } array_push(self::$anchor_list, $anchor['id']); } + // 处理取关操作 + foreach (AnchorRaffle::$wait_un_follows as $wait_un_follow) { + if ($wait_un_follow['time'] > time()) { + continue; + } + if (in_array($wait_un_follow['anchor_id'], self::$anchor_list)) { + AnchorRaffle::delToGroup($wait_un_follow['uid'], $wait_un_follow['anchor_id'], false); + }else{ + AnchorRaffle::delToGroup($wait_un_follow['uid'], $wait_un_follow['anchor_id'], true); + } + } + self::$anchor_lock = time() + 6 * 60 * 60; } diff --git a/src/plugin/Barrage.php b/src/plugin/Barrage.php index b34c25a..e465b29 100644 --- a/src/plugin/Barrage.php +++ b/src/plugin/Barrage.php @@ -33,7 +33,7 @@ class Barrage ]; if (self::privateSendMsg($info)) { - self::setLock(mt_rand(15, 30) * 60); + self::setLock(mt_rand(20, 40) * 60); return; } @@ -117,7 +117,7 @@ class Barrage */ private static function privateSendMsg($info): bool { - //TODO 暂时性功能 有需求就修改 + //TODO 短期功能 有需求就修改 $response = self::sendMsg($info); if (isset($response['code']) && $response['code'] == 0) { Log::info('活跃弹幕发送成功!'); diff --git a/src/plugin/BaseRaffle.php b/src/plugin/BaseRaffle.php index 4010538..cd488eb 100644 --- a/src/plugin/BaseRaffle.php +++ b/src/plugin/BaseRaffle.php @@ -63,7 +63,7 @@ abstract class BaseRaffle } array_push($room_list, $raffle['room_id']); array_push($raffle_list, $raffle); - Statistics::addJoinList(static::ACTIVE_TITLE); + Statistics::addJoinList($raffle['raffle_name']); } if (count($raffle_list) && count($room_list)) { $room_list = array_unique($room_list); @@ -90,6 +90,7 @@ abstract class BaseRaffle $raw = Curl::get('app', $url, Sign::common($payload)); $de_raw = json_decode($raw, true); if (!isset($de_raw['data']) || $de_raw['code']) { + // TODO 请求被拦截 412 Log::error("获取抽奖数据错误,{$de_raw['message']}"); return []; } diff --git a/src/plugin/Competition.php b/src/plugin/Competition.php new file mode 100644 index 0000000..5868b50 --- /dev/null +++ b/src/plugin/Competition.php @@ -0,0 +1,172 @@ + time()) { + return; + } + self::startStake(); + + self::setLock(self::timing(1,30)); + } + + + /** + * @use 开始破产 + */ + private static function startStake() + { + $questions = self::fetchQuestions(); + $max_guess = intval(getenv('COMPET_MAX_NUM')); + foreach ($questions as $index => $question) { + if (($index + 1) >= $max_guess) { + break; + } + // int $, int $main_id, int $detail_id, int $coin_num + $guess = self::parseQuestion($question); + self::addGuess($guess); + } + } + + /** + * @use 添加竞猜 + * @param array $guess + */ + private static function addGuess(array $guess) + { + Log::info($guess['title']); + Log::info($guess['estimate']); + $user_info = User::parseCookies(); + $url = 'https://api.bilibili.com/x/esports/guess/add'; + $payload = [ + 'oid' => $guess['oid'], + 'main_id' => $guess['main_id'], + 'detail_id' => $guess['detail_id'], + 'count' => $guess['count'], + 'is_fav' => 0, + 'csrf' => $user_info['token'] + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/v/game/match/competition' + ]; + $raw = Curl::post('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + // {"code":0,"message":"0","ttl":1} + if ($de_raw['code'] == 0) { + Log::notice("破产成功: {$de_raw['message']}"); + } else { + Log::warning("破产失败: {$raw}"); + } + } + + + /** + * @use 预计猜测结果 + * @param array $question + * @return array + */ + private static function parseQuestion(array $question): array + { + $guess = []; + $guess['oid'] = $question['contest']['id']; + $guess['main_id'] = $question['questions'][0]['id']; + $details = $question['questions'][0]['details']; + $guess['count'] = intval(in_array(getenv('COMPET_MAX_COIN'), range(1, 10)) ? getenv('COMPET_MAX_COIN') : 10); + $guess['title'] = $question['questions'][0]['title']; + foreach ($details as $detail) { + $guess['title'] .= " 队伍: {$detail['option']} 赔率: {$detail['odds']}"; + } + array_multisort(array_column($details, "odds"), SORT_ASC, $details); + switch (intval(getenv('COMPET_STAKE'))) { + case 1: + // 压大 + $detail = array_pop($details); + break; + case 2: + // 压小 + $detail = array_shift($details); + break; + case 3: + // 随机 + $detail = $details[array_rand($details)]; + break; + default: + // 乱序 + shuffle($details); + $detail = $details[array_rand($details)]; + break; + } + $guess['detail_id'] = $detail['detail_id']; + $profit = ceil($guess['count'] * $detail['odds']); + $guess['estimate'] = "竞猜队伍: {$detail['option']} 预计下注: {$guess['count']} 预计赚取: {$profit} 预计亏损: {$guess['count']} (硬币)"; + return $guess; + } + + /** + * @use 获取所有问题 + * @param int $page_max + * @return array + */ + private static function fetchQuestions(int $page_max = 10): array + { + $questions = []; + $url = 'https://api.bilibili.com/x/esports/guess/collection/question'; + for ($i = 1; $i < $page_max; $i++) { + $payload = [ + 'pn' => $i, + 'ps' => 50, + 'stime' => date("Y-m-d H:i:s", strtotime(date("Y-m-d", time()))), + 'etime' => date("Y-m-d H:i:s", strtotime(date("Y-m-d", time())) + 86400 - 1) + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/v/game/match/competition', + ]; + $raw = Curl::get('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + if ($de_raw['code'] == 0 && isset($de_raw['data']['list'])) { + // 为空跳出 + if (count($de_raw['data']['list']) == 0) { + break; + } + // 添加到集合 + foreach ($de_raw['data']['list'] as $question) { + // 判断是否有效 正2分钟 + if (($question['contest']['stime'] - 600 - 120) > time()) { + array_push($questions, $question); + } + } + // 和页面的不匹配 跳出 + if (count($de_raw['data']['list']) != $de_raw['data']['page']['size']) { + break; + } + } else { + // 错误跳出 + break; + } + } + Log::info('获取到 ' . count($questions) . ' 个有效竞猜'); + return $questions; + } + + +} \ No newline at end of file diff --git a/src/plugin/GiftRaffle.php b/src/plugin/GiftRaffle.php index 6bd97ad..3af8831 100644 --- a/src/plugin/GiftRaffle.php +++ b/src/plugin/GiftRaffle.php @@ -53,11 +53,11 @@ class GiftRaffle extends BaseRaffle $data = [ 'room_id' => $room_id, 'raffle_id' => $gift['raffleId'], - 'title' => $gift['title'], + 'raffle_name' => $gift['title'], 'type' => $gift['type'], 'wait' => $gift['time_wait'] + time(), ]; - Statistics::addPushList(self::ACTIVE_TITLE); + Statistics::addPushList($data['raffle_name']); array_push(self::$wait_list, $data); } return true; @@ -91,7 +91,8 @@ class GiftRaffle extends BaseRaffle 'payload' => Sign::common($payload), 'source' => [ 'room_id' => $raffle['room_id'], - 'raffle_id' => $raffle['raffle_id'] + 'raffle_id' => $raffle['raffle_id'], + 'raffle_name' => $raffle['raffle_name'] ] ]); } @@ -118,13 +119,14 @@ class GiftRaffle extends BaseRaffle $info = $de_raw['data']['award_name'] . 'x' . $de_raw['data']['award_num']; Notice::push('gift', $info); } - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['data']['award_name']}x{$de_raw['data']['award_num']}"); - Statistics::addSuccessList(self::ACTIVE_TITLE); + Statistics::addSuccessList($data['raffle_name']); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$de_raw['data']['award_name']}x{$de_raw['data']['award_num']}"); + Statistics::addProfitList($data['raffle_name'] . '-' . $de_raw['data']['award_name'], $de_raw['data']['award_num']); } elseif (isset($de_raw['msg']) && $de_raw['code'] == -403 && $de_raw['msg'] == '访问被拒绝') { - Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$de_raw['msg']}"); self::pauseLock(); } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: " . isset($de_raw['msg']) ? $de_raw['msg'] : $de_raw); } } } diff --git a/src/plugin/GiftSend.php b/src/plugin/GiftSend.php index f9d09c5..f211027 100644 --- a/src/plugin/GiftSend.php +++ b/src/plugin/GiftSend.php @@ -43,7 +43,12 @@ class GiftSend self::$room_list = []; self::$medal_list = []; self::$tid = 0; - self::setLock(5 * 60); + // 如果在每日最后5分钟内 就50s执行一次 否则 第二天固定时间执行 + if (self::inTime('23:55:00', '23:59:59')) { + self::setLock(50); + } else { + self::setLock(self::timing(23, 55)); + } } @@ -136,7 +141,9 @@ class GiftSend if (isset($data['data']['list'])) { $bag_list = $data['data']['list']; if (count($bag_list)) { - array_multisort(array_column($bag_list, "gift_id"), SORT_DESC, $bag_list); + // 按过期时间 升序 + // array_multisort(array_column($bag_list, "gift_id"), SORT_DESC, $bag_list); + array_multisort(array_column($bag_list, "expire_at"), SORT_ASC, $bag_list); } foreach ($bag_list as $vo) { // 去除永久礼物 @@ -192,14 +199,14 @@ class GiftSend $fans_medals[(string)$vo['roomid']] = $vo; } // 基于配置 - foreach (self::$room_list as $room_id ){ + foreach (self::$room_list as $room_id) { // 配置是否存在获取 - if (!array_key_exists((string)$room_id ,$fans_medals)){ + if (!array_key_exists((string)$room_id, $fans_medals)) { continue; } $vo = $fans_medals[(string)$room_id]; // 是否还需要投喂 - if ($vo['day_limit'] - $vo['today_feed']){ + if ($vo['day_limit'] - $vo['today_feed']) { self::$medal_list[(string)$vo['roomid']] = ($vo['day_limit'] - $vo['today_feed']); } } diff --git a/src/plugin/GroupSignIn.php b/src/plugin/GroupSignIn.php index a3f220c..214bfb2 100644 --- a/src/plugin/GroupSignIn.php +++ b/src/plugin/GroupSignIn.php @@ -73,8 +73,8 @@ class GroupSignIn $de_raw = json_decode($raw, true); if ($de_raw['code'] != '0') { - Log::warning('在应援团{' . $groupInfo['group_name'] . '}中签到失败,原因待查'); - // TODO + Log::warning('在应援团{' . $groupInfo['group_name'] . '}中签到失败, 原因待查'); + // TODO 任务失败原因 return false; } if ($de_raw['data']['status'] == '0') { diff --git a/src/plugin/GuardRaffle.php b/src/plugin/GuardRaffle.php index f42877c..0b41c45 100644 --- a/src/plugin/GuardRaffle.php +++ b/src/plugin/GuardRaffle.php @@ -53,28 +53,29 @@ class GuardRaffle extends BaseRaffle continue; } // 获取等级名称 - switch ($guard['privilege_type']) { - case 1: - $raffle_name = '总督'; - break; - case 2: - $raffle_name = '提督'; - break; - case 3: - $raffle_name = '舰长'; - break; - default: - $raffle_name = '舰队'; - break; - } +// switch ($guard['privilege_type']) { +// case 1: +// $raffle_name = '总督'; +// break; +// case 2: +// $raffle_name = '提督'; +// break; +// case 3: +// $raffle_name = '舰长'; +// break; +// default: +// $raffle_name = '舰队'; +// break; +// } + // 推入列表 $data = [ 'room_id' => $room_id, 'raffle_id' => $guard['id'], - 'raffle_name' => $raffle_name, - 'wait' => time() + mt_rand(5, 25) + 'raffle_name' => $guard['gift_name'], + 'wait' => time() + mt_rand(5, 30) ]; - Statistics::addPushList(self::ACTIVE_TITLE); + Statistics::addPushList($data['raffle_name']); array_push(self::$wait_list, $data); } return true; @@ -105,7 +106,8 @@ class GuardRaffle extends BaseRaffle 'payload' => Sign::common($payload), 'source' => [ 'room_id' => $raffle['room_id'], - 'raffle_id' => $raffle['raffle_id'] + 'raffle_id' => $raffle['raffle_id'], + 'raffle_name' => $raffle['raffle_name'] ] ]); } @@ -127,13 +129,14 @@ class GuardRaffle extends BaseRaffle $de_raw = json_decode($content, true); // {"code":-403,"data":null,"message":"访问被拒绝","msg":"访问被拒绝"} if (isset($de_raw['code']) && $de_raw['code'] == 0) { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": " . $de_raw['data']['award_name'] . "x" . $de_raw['data']['award_num']); - Statistics::addSuccessList(self::ACTIVE_TITLE); + Statistics::addSuccessList($data['raffle_name']); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: " . $de_raw['data']['award_name'] . "x" . $de_raw['data']['award_num']); + Statistics::addProfitList($data['raffle_name'] . '-' . $de_raw['data']['award_name'], $de_raw['data']['award_num']); } elseif (isset($de_raw['msg']) && $de_raw['code'] == -403 && $de_raw['msg'] == '访问被拒绝') { - Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$de_raw['msg']}"); self::pauseLock(); } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: " . isset($de_raw['msg']) ? $de_raw['msg'] : $de_raw); } } } diff --git a/src/plugin/Judge.php b/src/plugin/Judge.php index 8583ee0..595655b 100644 --- a/src/plugin/Judge.php +++ b/src/plugin/Judge.php @@ -40,7 +40,7 @@ class Judge } /** - * @use 判案 TODO: 处理案例已满(MAX20例) / 尝试已实名续期风纪 + * @use 判案 TODO: 处理案例已满(MAX20例) * @param $case_id * @return bool */ diff --git a/src/plugin/Login.php b/src/plugin/Login.php index 2c20141..b6a9e4d 100644 --- a/src/plugin/Login.php +++ b/src/plugin/Login.php @@ -225,6 +225,7 @@ class Login */ private static function ocrCaptcha($captcha_img) { + // $url = 'http://captcha-v1.mudew.com:19951/'; $url = 'http://47.102.120.84:19951/'; $payload = [ 'image' => (string)$captcha_img diff --git a/src/plugin/MasterSite.php b/src/plugin/MasterSite.php index c76eb6a..e8ad10f 100644 --- a/src/plugin/MasterSite.php +++ b/src/plugin/MasterSite.php @@ -101,7 +101,7 @@ class MasterSite } /** - * @use 视频投币 TODO : 处理视频投币硬币少于需要投币数 + * @use 视频投币 * @return bool */ protected static function coinAdd(): bool @@ -110,29 +110,34 @@ class MasterSite case 'false': break; case 'true': - $av_num = getenv('ADD_COIN_AV_NUM'); - $av_num = (int)$av_num; - if ($av_num == 0) { - Log::warning('当前视频投币设置不正确,请检查配置文件!'); - die(); + // 预计数量 失败默认0 避免损失 + $estimate_num = intval(getenv('ADD_COIN_NUM') ?? 0); + // 库存数量 + $stock_num = self::getCoin(); + // 实际数量 处理硬币库存少于预计数量 + $actual_num = intval($estimate_num > $stock_num ? $stock_num : $estimate_num) - self::coinLog(); + Log::info("当前硬币库存 {$stock_num} 预计投币 {$estimate_num} 实际投币 {$actual_num}"); + // 上限 + if ($actual_num <= 0) { + Log::info('今日投币上限已满!'); + break; } - if ($av_num == 1) { - $aid = !empty(getenv('ADD_COIN_AV')) ? getenv('ADD_COIN_AV') : self::getRandomAid(); + // 稿件列表 + if (gettype('RANDOM_ADD_COIN') =='random'){ + // 随机热门稿件榜单 + $aids = self::getDayRankingAids($actual_num); + }else{ + // 固定获取关注UP稿件榜单, 不足会随机补全 + $aids = self::getFollowUpAids($actual_num); + } + Log::info("获取稿件列表: ". implode(" ",$aids)); + // 投币 + foreach ($aids as $aid) { self::reward($aid); - } else { - $need_coins = $av_num - self::coinLog(); - if ($need_coins <= 0) { - Log::info('今日投币上限已满!'); - break; - } - $aids = self::getDayRankingAids($need_coins); - foreach ($aids as $aid) { - self::reward($aid); - } } break; default: - Log::warning('当前视频投币设置不正确,请检查配置文件!'); + Log::warning('当前视频投币设置不正确, 请检查配置文件!'); die(); break; } @@ -163,11 +168,46 @@ class MasterSite /** - * @use 获取日榜AID - * @param $num + * @use 获取关注UP稿件列表 + * @param int $num * @return array */ - private static function getDayRankingAids($num): array + private static function getFollowUpAids(int $num): array + { + $aids = []; + $rand_nums = []; + $url = 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new'; + $user_info = User::parseCookies(); + $payload = [ + 'uid' => $user_info['uid'], + 'type_list' => '8,512,4097,4098,4099,4100,4101' + ]; + $headers = [ + 'origin' => 'https://t.bilibili.com', + 'referer' => 'https://t.bilibili.com/pages/nav/index_new' + ]; + $raw = Curl::get('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + foreach ($de_raw['data']['cards'] as $index => $card) { + if ($index >= $num) { + break; + } + array_push($aids, $card['desc']['rid']); + } + // 此处补全缺失 + if (count($aids) < $num) { + $aids = array_merge($aids, self::getDayRankingAids($num - count($aids))); + } + return $aids; + } + + + /** + * @use 获取榜单稿件列表 + * @param int $num + * @return array + */ + private static function getDayRankingAids(int $num): array { // day: 日榜1 三榜3 周榜7 月榜30 $aids = []; @@ -330,4 +370,24 @@ class MasterSite } } + /** + * @use 获取硬币数量 + * @return int + */ + private static function getCoin(): int + { + $url = 'https://account.bilibili.com/site/getCoin'; + $payload = []; + $headers = [ + 'referer' => 'https://account.bilibili.com/account/coin', + ]; + $raw = Curl::get('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + // {"code":0,"status":true,"data":{"money":1707.9}} + if ($de_raw['code'] == 0 && isset($de_raw['data']['money'])) { + return floor($de_raw['data']['money']); + } + return 0; + } + } \ No newline at end of file diff --git a/src/plugin/Match.php b/src/plugin/Match.php index cf87ae7..cc8e973 100644 --- a/src/plugin/Match.php +++ b/src/plugin/Match.php @@ -28,20 +28,20 @@ class Match // 'lottery_id' => 46, // 'status' => true // ], - 'OW' => [ - 'type_id' => 26, - 'room_id' => 14073662, - 'short_room_id' => 76, - 'lottery_id' => 52, - 'status' => true - ], - 'KPL' => [ - 'type_id' => 27, - 'room_id' => 21144080, - 'short_room_id' => 55, - 'lottery_id' => 55, - 'status' => true - ], +// 'OW' => [ +// 'type_id' => 26, +// 'room_id' => 14073662, +// 'short_room_id' => 76, +// 'lottery_id' => 52, +// 'status' => true +// ], +// 'KPL' => [ +// 'type_id' => 27, +// 'room_id' => 21144080, +// 'short_room_id' => 55, +// 'lottery_id' => 55, +// 'status' => true +// ], ]; public static function run() diff --git a/src/plugin/MaterialObject.php b/src/plugin/MaterialObject.php index 26c2b90..b1aab3b 100644 --- a/src/plugin/MaterialObject.php +++ b/src/plugin/MaterialObject.php @@ -67,21 +67,24 @@ class MaterialObject */ private static function boxStatus(int $aid, $reply = 'bool') { - $url = 'https://api.live.bilibili.com/lottery/v1/box/getStatus'; + // $url = 'https://api.live.bilibili.com/lottery/v1/box/getStatus'; + $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v2/Box/getStatus'; $payload = [ 'aid' => $aid, ]; $raw = Curl::get('pc', $url, $payload); $de_raw = json_decode($raw, true); + // {"code":0,"data":null,"message":"ok","msg":"ok"} + // {"code":0,"data":{"title":"荣耀宝箱抽奖","rule":"a 抽奖时间按如下规则抽取一次,重复无效。\nb 获奖者需要再获奖名单公布后一周内反馈姓名、邮寄地址、联系方式,因获奖者逾期查看获奖名单、逾期提交个人资料或个人资料有误,将视为自动放弃获奖资格及由此产生的权利。","current_round":2,"typeB":[{"startTime":"2020-05-18 18:30:00","imgUrl":"https://i0.hdslb.com/bfs/live/f600b89f2c2550b600612feba90e39901a9f027c.jpg","join_start_time":1589796000,"join_end_time":1589797800,"status":4,"list":[{"jp_name":"荣耀路由3","jp_num":"1","jp_id":3181,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/f600b89f2c2550b600612feba90e39901a9f027c.jpg"}],"round_num":1},{"startTime":"2020-05-18 19:00:00","imgUrl":"https://i0.hdslb.com/bfs/live/f600b89f2c2550b600612feba90e39901a9f027c.jpg","join_start_time":1589797800,"join_end_time":1589799600,"status":0,"list":[{"jp_name":"荣耀路由3","jp_num":"1","jp_id":3182,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/f600b89f2c2550b600612feba90e39901a9f027c.jpg"}],"round_num":2},{"startTime":"2020-05-18 19:30:00","imgUrl":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg","join_start_time":1589799600,"join_end_time":1589801400,"status":-1,"list":[{"jp_name":"荣耀平板V6","jp_num":"1","jp_id":3183,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg"}],"round_num":3},{"startTime":"2020-05-18 20:00:00","imgUrl":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg","join_start_time":1589801400,"join_end_time":1589803200,"status":-1,"list":[{"jp_name":"荣耀平板V6","jp_num":"1","jp_id":3184,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg"}],"round_num":4},{"startTime":"2020-05-18 20:30:00","imgUrl":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg","join_start_time":1589803200,"join_end_time":1589805000,"status":-1,"list":[{"jp_name":"荣耀平板V6","jp_num":"1","jp_id":3185,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/9fcde6f26a546b9dfb5ffc7a0c4f4503a05e16f2.jpg"}],"round_num":5},{"startTime":"2020-05-18 21:00:00","imgUrl":"https://i0.hdslb.com/bfs/live/73db69bd5a9e5dedb7d2f32d72fd6248b860e238.jpg","join_start_time":1589805000,"join_end_time":1589806800,"status":-1,"list":[{"jp_name":"荣耀MagicBook Pro","jp_num":"1","jp_id":3186,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/73db69bd5a9e5dedb7d2f32d72fd6248b860e238.jpg"}],"round_num":6},{"startTime":"2020-05-18 22:00:00","imgUrl":"https://i0.hdslb.com/bfs/live/4dba1e8b58c174d5e2311de339b1e02a3ac77a98.jpg","join_start_time":1589806800,"join_end_time":1589810400,"status":-1,"list":[{"jp_name":"荣耀智慧屏新品,荣耀MagicBook Pro,荣耀平板V6,荣耀路由3","jp_num":"1","jp_id":3187,"jp_type":2,"ex_text":"","jp_pic":"https://i0.hdslb.com/bfs/live/4dba1e8b58c174d5e2311de339b1e02a3ac77a98.jpg"}],"round_num":7}],"activity_pic":"https://i0.hdslb.com/bfs/live/c3ed87683f6e87d256d1f5fdddbfb220fc4c2cdf.png","activity_id":556,"weight":20,"background":"https://i0.hdslb.com/bfs/live/84cd59bcb1e977359df618dbeb0f7828751f457c.png","title_color":"#FFFFFF","closeable":0,"jump_url":"https://live.bilibili.com/p/html/live-app-treasurebox/index.html?is_live_half_webview=1\u0026hybrid_biz=live-app-treasurebox\u0026hybrid_rotate_d=1\u0026hybrid_half_ui=1,3,100p,70p,0,0,30,100;2,2,375,100p,0,0,30,100;3,3,100p,70p,0,0,30,100;4,2,375,100p,0,0,30,100;5,3,100p,70p,0,0,30,100;6,3,100p,70p,0,0,30,100;7,3,100p,70p,0,0,30,100\u0026aid=556"},"message":"","msg":""} switch ($reply) { // 等于0是有抽奖返回false case 'bool': - if ($de_raw['code'] == 0) { + if (!is_null($de_raw['data'])) { return false; } return true; case 'array': - if ($de_raw['code'] == 0) { + if (!is_null($de_raw['data'])) { return $de_raw; } return []; @@ -175,7 +178,8 @@ class MaterialObject $aid = $lottery['aid']; $num = $lottery['num']; Log::notice("实物抽奖 {$aid} 轮次 {$num} 可参与抽奖~"); - $url = 'https://api.live.bilibili.com/lottery/v1/Box/draw'; + // $url = 'https://api.live.bilibili.com/lottery/v1/Box/draw'; + $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v2/Box/draw'; $payload = [ 'aid' => $aid, 'number' => $num, diff --git a/src/plugin/Notice.php b/src/plugin/Notice.php index a804e4e..f092e83 100644 --- a/src/plugin/Notice.php +++ b/src/plugin/Notice.php @@ -122,6 +122,12 @@ class Notice 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 程序运行错误: ' . self::$result, ]; break; + case 'key_expired': + $info = [ + 'title' => '监控KEY异常', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 监控KEY到期或者错误,请及时查错或续期后重试哦~', + ]; + break; default: $info = [ 'title' => '推送消息异常记录', diff --git a/src/plugin/PkRaffle.php b/src/plugin/PkRaffle.php index ca09e6e..c6bb135 100644 --- a/src/plugin/PkRaffle.php +++ b/src/plugin/PkRaffle.php @@ -57,10 +57,10 @@ class PkRaffle extends BaseRaffle $data = [ 'room_id' => $room_id, 'raffle_id' => $pk['id'], - 'raffle_name' => '大乱斗', + 'raffle_name' => $pk['title'], 'wait' => time() + mt_rand(5, 25) ]; - Statistics::addPushList(self::ACTIVE_TITLE); + Statistics::addPushList($data['raffle_name']); array_push(self::$wait_list, $data); } return true; @@ -89,7 +89,8 @@ class PkRaffle extends BaseRaffle 'payload' => Sign::common($payload), 'source' => [ 'room_id' => $raffle['room_id'], - 'raffle_id' => $raffle['raffle_id'] + 'raffle_id' => $raffle['raffle_id'], + 'raffle_name' => $raffle['raffle_name'] ] ]); } @@ -116,13 +117,16 @@ class PkRaffle extends BaseRaffle * {"code":-403,"data":null,"message":"访问被拒绝","msg":"访问被拒绝"} */ if (isset($de_raw['code']) && $de_raw['code'] == 0) { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['data']['award_text']}"); - Statistics::addSuccessList(self::ACTIVE_TITLE); + Statistics::addSuccessList($data['raffle_name']); + $award_text = $de_raw['data']['award_text']; + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$award_text}"); + // 收益 + Statistics::addProfitList($data['raffle_name'] . '-' . explode('X', $award_text)[0], $de_raw['data']['award_num']); } elseif (isset($de_raw['msg']) && $de_raw['code'] == -403 && $de_raw['msg'] == '访问被拒绝') { - Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['message']}"); + Log::debug("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$de_raw['message']}"); self::pauseLock(); } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['message']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} {$data['raffle_name']}: {$de_raw['message']}"); } } } diff --git a/src/plugin/Silver2Coin.php b/src/plugin/Silver2Coin.php index 21cf74c..d351903 100644 --- a/src/plugin/Silver2Coin.php +++ b/src/plugin/Silver2Coin.php @@ -37,7 +37,7 @@ class Silver2Coin */ protected static function appSilver2coin(): bool { - sleep(1); + sleep(0.5); $url = 'https://api.live.bilibili.com/AppExchange/silver2coin'; $payload = []; $raw = Curl::get('app', $url, Sign::common($payload)); @@ -61,7 +61,7 @@ class Silver2Coin */ protected static function pcSilver2coin(): bool { - sleep(1); + sleep(0.5); $payload = []; $url = "https://api.live.bilibili.com/exchange/silver2coin"; $url = "https://api.live.bilibili.com/pay/v1/Exchange/silver2coin"; @@ -72,7 +72,6 @@ class Silver2Coin return false; } Log::info('[PC]银瓜子兑换硬币: ' . $de_raw['msg']); - // TODO return true; } } \ No newline at end of file diff --git a/src/plugin/Statistics.php b/src/plugin/Statistics.php index 9094463..363329e 100644 --- a/src/plugin/Statistics.php +++ b/src/plugin/Statistics.php @@ -11,8 +11,8 @@ namespace BiliHelper\Plugin; use BiliHelper\Core\Log; -use BiliHelper\Core\Curl; use BiliHelper\Util\TimeLock; +use MathieuViossat\Util\ArrayToTextTable; class Statistics @@ -22,6 +22,7 @@ class Statistics private static $push_list = []; private static $join_list = []; private static $success_list = []; + private static $profit_list = []; public static function run() @@ -38,12 +39,13 @@ class Statistics /** * @use 添加推送 * @param string $key + * @param int $num * @return bool */ - public static function addPushList(string $key): bool + public static function addPushList(string $key, int $num = 1): bool { self::initKeyValue(self::$push_list, $key); - self::$push_list[$key]++; + self::valIncrease(self::$push_list, $key); return true; } @@ -51,12 +53,13 @@ class Statistics /** * @use 添加参与 * @param string $key + * @param int $num * @return bool */ - public static function addJoinList(string $key): bool + public static function addJoinList(string $key, int $num = 1): bool { self::initKeyValue(self::$join_list, $key); - self::$join_list[$key]++; + self::valIncrease(self::$join_list, $key); return true; } @@ -64,50 +67,220 @@ class Statistics /** * @use 添加成功 * @param string $key + * @param int $num * @return bool */ - public static function addSuccessList(string $key): bool + public static function addSuccessList(string $key, int $num = 1): bool { self::initKeyValue(self::$success_list, $key); - self::$success_list[$key]++; + self::valIncrease(self::$success_list, $key); return true; } + + /** + * @use 添加收益 + * @param string $title + * @param int $num + * @param int $updated_time + * @return bool + */ + public static function addProfitList(string $title, int $num, int $updated_time = 0): bool + { + self::initKeyValue(self::$profit_list, $title, 0, 'num'); + self::initKeyValue(self::$profit_list, $title, time(), 'updated_time'); + self::valIncrease(self::$profit_list, $title, $num, 'num'); + self::valReplace(self::$profit_list, $title, time(), 'updated_time'); + return true; + } + + + /** + * @use 转换时间 + * @param int $the_time + * @return string + */ + private static function timeTran(int $the_time): string + { + $t = time() - $the_time;//现在时间-发布时间 获取时间差 + $f = [ + '31536000' => '年', + '2592000' => '个月', + '604800' => '星期', + '86400' => '天', + '3600' => '小时', + '60' => '分钟', + '1' => '秒', + '0' => '秒' + ]; + foreach ($f as $k => $v) { + if (0 != $c = floor($t / (int)$k)) { + return $c . $v . '前'; + } + } + } + /** * @use 初始化键值 * @param array $target * @param string $key * @param int $value + * @param null $second_key * @return bool */ - private static function initKeyValue(array &$target, string $key, $value = 0): bool + private static function initKeyValue(array &$target, string $key, $value = 0, $second_key = null): bool { - if (!array_key_exists($key, $target)) { - $target[$key] = $value; + if (!array_key_exists(self::getTodayKey(), $target)) { + $target[self::getTodayKey()] = []; + } + if (!array_key_exists($key, $target[self::getTodayKey()])) { + $target[self::getTodayKey()][$key] = is_null($second_key) ? $value : []; + } + if (!is_null($second_key) && !array_key_exists($second_key, $target[self::getTodayKey()][$key])) { + $target[self::getTodayKey()][$key][$second_key] = $value; } return true; } /** - * @use 输出结果 + * @use 获取结果 + * @param array $target + * @param string $key + * @param null $second_key + * @return mixed + */ + private static function getResult(array &$target, string $key, $second_key = null) + { + is_null($second_key) ? self::initKeyValue($target, $key) : self::initKeyValue($target, $key, 0, $second_key); + return is_null($second_key) ? $target[self::getTodayKey()][$key] : $target[self::getTodayKey()][$key][$second_key]; + } + + + /** + * @use 获取所有结果 + * @param array $target + * @param string $key + * @param string $second_key + * @return int + */ + private static function getResults(array &$target, string $key, $second_key = null) + { + $results = 0; + is_null($second_key) ? self::initKeyValue($target, $key) : self::initKeyValue($target, $key, 0, $second_key); + foreach ($target as $item) { + is_null($second_key) ? $results += intval($item[$key]) : $results += intval($item[$key][$second_key]); + } + return $results; + } + + + /** + * @use 变量增加 + * @param array $target + * @param string $key + * @param int $num + * @param null $second_key * @return bool */ - private static function outputResult(): bool + private static function valIncrease(array &$target, string $key, $num = 1, $second_key = null) { - if (empty(self::$push_list)) { - return false; - } - Log::info("-----------密----------封---------线------------"); - foreach (self::$push_list as $key => $val) { - $title = $key; - $push_num = isset(self::$push_list[$key]) ? self::$push_list[$key] : 0; - $join_num = isset(self::$join_list[$key]) ? self::$join_list[$key] : 0; - $success_num = isset(self::$success_list[$key]) ? self::$success_list[$key] : 0; - $content = "{$title}: #推送 {$push_num} #参与 {$join_num} #成功 {$success_num}"; - Log::notice($content); - } - Log::info("-----------密----------封---------线------------"); + is_null($second_key) ? $target[self::getTodayKey()][$key] += $num : $target[self::getTodayKey()][$key][$second_key] += $num; return true; } + + + /** + * @use 变量替换 + * @param array $target + * @param string $key + * @param null $data + * @param string $second_key + * @return bool + */ + private static function valReplace(array &$target, string $key, $data = null, $second_key = '') + { + is_null($second_key) ? $target[self::getTodayKey()][$key] = $data : $target[self::getTodayKey()][$key][$second_key] = $data; + return true; + } + + /** + * @use 获取 table -> tr -> td + * @return array + */ + private static function getTrList(): array + { + $tr_list_count = []; + $tr_list_profit = []; + // 统计数量 + foreach (self::$push_list as $index => $item) { + foreach ($item as $key => $val) { + $td = [ + '名称 (总计/今日)' => $key, + '推送' => self::getResults(self::$push_list, $key) . '/' . self::getResult(self::$push_list, $key), + '参与' => self::getResults(self::$join_list, $key) . '/' . self::getResult(self::$join_list, $key), + '成功' => self::getResults(self::$success_list, $key) . '/' . self::getResult(self::$success_list, $key), + ]; + array_push($tr_list_count, $td); + } + } + // 收益数量 + foreach (self::$profit_list as $index => $item) { + foreach ($item as $key => $val) { + $td = [ + '名称 (总计/今日)' => explode('-', $key)[0], + '数量' => self::getResults(self::$profit_list, $key, 'num') . '/' . self::getResult(self::$profit_list, $key, 'num'), + '奖品' => explode('-', $key)[1], + '更新时间' => self::timeTran(self::getResult(self::$profit_list, $key, 'updated_time')), + ]; + array_push($tr_list_profit, $td); + } + } + return [$tr_list_count, $tr_list_profit]; + } + + /** + * @use 数据数组转表格数组 + * @param array $data + * @return array + */ + private static function arrayToTable(array $data): array + { + $th_list = []; + if ($data) { + $renderer = new ArrayToTextTable($data); + foreach (explode("\n", $renderer->getTable()) as $value) { + if ($value) { + array_push($th_list, $value); + } + } + } + return $th_list; + } + + /** + * @use 打印表格 + */ + private static function outputResult() + { + $arr_tr_list = self::getTrList(); + foreach ($arr_tr_list as $tr_list) { + $th_list = self::arrayToTable($tr_list); + foreach ($th_list as $th) { + Log::notice($th); + } + } + } + + /** + * @use 获取今日KEY + * @return string + */ + private static function getTodayKey(): string + { + $ts = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + // 1592668800 -> 5bb4085b4cc25bc0 + return md5($ts); + } + } \ No newline at end of file diff --git a/src/plugin/StormRaffle.php b/src/plugin/StormRaffle.php index 598753e..2baa3a5 100644 --- a/src/plugin/StormRaffle.php +++ b/src/plugin/StormRaffle.php @@ -65,7 +65,7 @@ class StormRaffle extends BaseRaffle 'raffle_name' => '节奏风暴', 'wait' => time() ]; - Statistics::addPushList(self::ACTIVE_TITLE); + Statistics::addPushList($data['raffle_name']); array_push(self::$wait_list, $data); return true; } @@ -118,8 +118,10 @@ class StormRaffle extends BaseRaffle break; } if ($de_raw['code'] == 0) { - Statistics::addSuccessList(self::ACTIVE_TITLE); - Log::notice(self::formatInfo($raffle['raffle_id'], $num, $de_raw['data']['mobile_content'])); + $data = $de_raw['data']; + Statistics::addSuccessList($raffle['raffle_name']); + Log::notice(self::formatInfo($raffle['raffle_id'], $num, $data['mobile_content'])); + Statistics::addProfitList($data['title'] . '-' . $data['gift_name'], $data['gift_num']); break; } if (!isset($de_raw['msg'])) { diff --git a/src/plugin/User.php b/src/plugin/User.php index 5c6f837..f08c470 100644 --- a/src/plugin/User.php +++ b/src/plugin/User.php @@ -94,7 +94,7 @@ class User 'room_id' => $room_id ?? getenv('ROOM_ID') ]; $raw = Curl::get('pc', $url, $payload); - return json_decode($raw, true);; + return json_decode($raw, true); } @@ -134,10 +134,10 @@ class User } /** - * @use 获取关注列表 + * @use 获取全部关注列表 * @return array */ - public static function fetchFollowings(): array + public static function fetchAllFollowings(): array { $user_info = User::parseCookies(); $uid = $user_info['uid']; @@ -169,6 +169,46 @@ class User } + /** + * @use 获取分组关注列表 + * @param int $tag_id + * @param int $page_num + * @param int $page_size + * @return array + */ + public static function fetchTagFollowings(int $tag_id = 0, int $page_num = 100, int $page_size = 50): array + { + $user_info = User::parseCookies(); + $uid = $user_info['uid']; + $followings = []; + for ($i = 1; $i < $page_num; $i++) { + $url = "https://api.bilibili.com/x/relation/tag"; + $payload = [ + 'mid' => $uid, + 'tagid' => $tag_id, + 'pn' => $i, + 'ps' => $page_size, + ]; + $headers = [ + 'referer' => "https://space.bilibili.com/{$uid}/fans/follow?tagid={$tag_id}", + ]; + $raw = Curl::get('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + if ($de_raw['code'] == 0 && isset($de_raw['data'])) { + foreach ($de_raw['data'] as $user) { + array_push($followings, $user['mid']); + } + if (count($de_raw['data']) != $page_size || empty($de_raw['data'])) { + break; + } + continue; + } + break; + } + return $followings; + } + + /** * @use 设置用户关注 * @param int $follow_uid @@ -204,9 +244,9 @@ class User /** * @use 创建关注分组 * @param string $tag_name - * @return bool + * @return int */ - public static function createRelationTag(string $tag_name): bool + public static function createRelationTag(string $tag_name): int { $user_info = User::parseCookies(); $url = 'https://api.bilibili.com/x/relation/tag/create?cross_domain=true'; @@ -222,10 +262,10 @@ class User $raw = Curl::post('pc', $url, $payload, $headers); $de_raw = json_decode($raw, true); // {"code":0,"message":"0","ttl":1,"data":{"tagid":244413}} - if ($de_raw['code'] == 0) { - return true; + if ($de_raw['code'] == 0 && isset($de_raw['data']['tagid'])) { + return $de_raw['data']['tagid']; } - return false; + return 0; } /** @@ -257,4 +297,27 @@ class User return false; } + /** + * @use 获取分组列表 + * @return array + */ + public static function fetchTags(): array + { + $user_info = User::parseCookies(); + $tags = []; + $url = 'https://api.bilibili.com/x/relation/tags'; + $payload = []; + $headers = [ + 'referer' => "https://space.bilibili.com/{$user_info['uid']}/fans/follow", + ]; + $raw = Curl::get('pc', $url, $payload, $headers); + $de_raw = json_decode($raw, true); + if ($de_raw['code'] == 0 && isset($de_raw['data'])) { + foreach ($de_raw['data'] as $tag) { + $tags[$tag['tagid']] = $tag['name']; + } + } + return $tags; + } + } \ No newline at end of file diff --git a/src/tool/BvToAv.php b/src/tool/BvToAv.php index e7c61d8..9ca26c6 100644 --- a/src/tool/BvToAv.php +++ b/src/tool/BvToAv.php @@ -9,7 +9,6 @@ * Source: https://github.com/anhao/bv2av/ */ - namespace BiliHelper\Tool; use BiliHelper\Core\Log; diff --git a/src/tool/DumpMemory.php b/src/tool/DumpMemory.php index bc223b4..a99dca9 100644 --- a/src/tool/DumpMemory.php +++ b/src/tool/DumpMemory.php @@ -1,5 +1,13 @@ = $timeBegin && $curr_time <= $timeEnd) { + return true; + } + return false; } /**