diff --git a/CHANGELOG.md b/CHANGELOG.md index 703a1fd..9f28e14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,62 +1,40 @@ # Release Notes # 本项目Log -## v0.0.1.191223 alpha (2019-12-23) +## v0.1.0.191227 alpha (2019-12-27) ### Added -- anchor(beta) -- +- 新增备用官方分区监控 +- 新增按勋章亲密度赠送 +- 新增天选时刻获奖推送 +- ### Changed +- 优化部分架构 +- 优化独立监控 +- 优化监控逻辑 +- 优化礼物赠送 +- 优化通用抽奖 +- 优化推送逻辑 - ### Fixed -- +- 修复部分日志显示 +- 修复数据统计异常 +- 修复瓜子宝箱异常 +- 修复Server酱异常 +- 修复天选时刻异常 +- 修复抽奖数据异常 +- 修复部分已知BUG +- 修复获奖推送通知 +- -## v0.0.1.191030 alpha (2019-10-30) +## v0.0.5.191223 alpha (2019-12-23) -### Added -- - -### Changed -- unify raffle api -- danmu -- captcha ocr api - -### Fixed -- - -## v0.0.1.190730 alpha (2019-07-30) - -### Added -- - -### Changed -- unify raffle api - -### Fixed -- - -## v0.0.1.190723 alpha (2019-07-23) - -### Added -- pk lottery - -### Changed -- - -### Fixed -- +## v0.0.4.191030 alpha (2019-10-30) +## v0.0.3.190730 alpha (2019-07-30) +## v0.0.2.190723 alpha (2019-07-23) ## v0.0.1.190713 alpha (2019-07-13) - -### Added -- Initialization - -### Changed -- Initialization - -### Fixed -- Initialization diff --git a/DOC.md b/DOC.md index 4951d9a..7b218da 100644 --- a/DOC.md +++ b/DOC.md @@ -2,7 +2,7 @@

- +

@@ -17,35 +17,40 @@ B 站直播实用脚本 |plugin |version |description | |--------------------|--------------------|--------------------| -|Daily |19.12.23 |每日背包奖励 | -|GiftSend |19.12.23 |自动清空过期礼物 | -|Heart |19.12.23 |双端直播间心跳 | -|Login |19.12.23 |帐号登录组件 | -|Silver |19.12.23 |自动领宝箱 | -|Task |19.12.23 |每日任务 | -|GiftHeart |19.12.23 |心跳礼物 | -|Silver2Coin |19.12.23 |银瓜子换硬币 | -|MaterialObject |19.12.23 |实物抽奖 | -|GroupSignIn |19.12.23 |应援团签到 | -|Storm |19.12.23 |节奏风暴 | -|Notice |19.12.23 |Server酱 | -|UnifyRaffle |19.12.23 |统一活动抽奖 | -|MasterSite |19.12.23 |主站(观看、分享、投币)| -|Guard |19.12.23 |舰长上船亲密度 | -|PkRaffle |19.12.23 |大乱斗 | -|Anchor |19.12.23 |天选时刻 | +|Login |19.12.27 |账号登录 | +|Sleep |19.12.27 |休眠控制 | +|MasterSite |19.12.27 |主站助手 | +|Daily |19.12.27 |每日礼包 | +|Heart |19.12.27 |双端心跳 | +|Task |19.12.27 |每日任务 | +|Silver |19.12.27 |银瓜子宝箱 | +|Barrage |19.12.27 |活跃弹幕 | +|Silver2Coin |19.12.27 |银瓜子换硬币 | +|GiftSend |19.12.27 |礼物赠送 | +|GroupSignIn |19.12.27 |友爱社签到 | +|GiftHeart |19.12.27 |心跳礼物 | +|MaterialObject |19.12.27 |实物抽奖 | +|AloneTcpClient |19.12.27 |独立监控 | +|ZoneTcpClient |19.12.27 |分区监控 | +|StormRaffle |19.12.27 |节奏风暴 | +|GiftRaffle |19.12.27 |活动礼物 | +|PkRaffle |19.12.27 |大乱斗 | +|GuardRaffle |19.12.27 |舰长总督 | +|AnchorRaffle |19.12.27 |天选时刻 | +|AwardRecord |19.12.27 |获奖通知 | +|Statistics |19.12.27 |数据统计 | ## 打赏赞助 -![](https://i.loli.net/2018/04/07/5ac79ff8c2900.png) +![](https://i.loli.net/2019/07/13/5d2963e5cc1eb22973.png) +> 待添加 ## 未完成功能 |待续 | |-----------| -|添加多用户 | -|待添加 | +|多用户 | ## 环境依赖 @@ -58,7 +63,6 @@ B 站直播实用脚本 |php_json | |php_zlib | |php_mbstring | -|待添加 | 通常使用 `composer` 工具会自动检测上述依赖问题。 @@ -79,11 +83,7 @@ https://mirrors.cloud.tencent.com/composer/ composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/ ``` -## 打赏赞助 -![](https://i.loli.net/2019/07/13/5d2963e5cc1eb22973.png) - -> 待添加 ## 使用指南 @@ -196,22 +196,36 @@ APP_CALLBACK="https://api.telegram.org/bot/sendMessage?chat_id=& ## 直播间 ID 问题 -`user.conf` 文件中有个 `ROOM_ID` 配置,填写此项可以清空临过期礼物给指定直播间。 +文件 `user.conf` 里 + +`ROOM_ID` 配置,填写此项可以清空临过期礼物给指定直播间。 + +`ROOM_LIST` 配置,使用长位直播间,填写此项可以清空临礼物给指定有勋章的直播间。 + +`FEED_FILL` 配置,搭配上一条使用,使用过期礼物或者倒序使用正常礼物。 + +`SOCKET_ROOM_ID` 配置,监控使用,暂时没用到。 通常可以在直播间页面的 url 获取到它 ``` http://live.bilibili.com/9522051 ``` -所有直播间号码小于 1000 的直播间为短号,该脚本在每次启动会自动修正,无需关心, +长位直播间ID获取 +``` +https://api.live.bilibili.com/room/v1/Room/room_init?id=3 +``` + +所有直播间号码小于 1000 的直播间为短号,该脚本在每次启动会自动修正部分功能,特殊标注的请留意, ## 相关 - > 本项目基于[BilibiliHelper](https://github.com/metowolf/BilibiliHelper)项目 + > [BilibiliHelper](https://github.com/metowolf/BilibiliHelper) + + > [BiliHelper](https://github.com/lkeme/BiliHelper) + + > [Github](https://github.com/) - > 基于父项目的架构开发,在此感谢父项目的开发 - - > 保留父项目没必要修改的信息,另外欢迎重构(Haha) ## License 许可证 diff --git a/README.md b/README.md index be6f22e..95357f1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Group: [55308141](https://jq.qq.com/?_wv=1027&k=5AIDaJg) ## 公告 -Currently for Personal Edition **0.0.1.191213 alpha** +Currently for Personal Edition **0.1.0.191227 alpha** ## 文档 diff --git a/composer.json b/composer.json index eecd952..ded0d15 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,10 @@ "ext-json": "*", "ext-zlib": "*", "ext-mbstring": "*", - "vlucas/phpdotenv": "^2.4", "monolog/monolog": "^1.23", "bramus/monolog-colored-line-formatter": "^2.0", - "clue/socket-raw": "^1.4.1" + "clue/socket-raw": "^1.4.1", + "vlucas/phpdotenv": "^4.1" }, "license": "MIT", "authors": [ @@ -25,7 +25,9 @@ ], "autoload": { "psr-4": { - "lkeme\\BiliHelper\\": "src/" + "BiliHelper\\Core\\": "src/core", + "BiliHelper\\Plugin\\": "src/plugin", + "BiliHelper\\Util\\": "src/util" } } } diff --git a/composer.lock b/composer.lock index 1c1c100..4093152 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": "d09e06835f7ff6a06fcb74285e6617c5", + "content-hash": "6034c5a467eb270c2c7d1ce12d7277fd", "packages": [ { "name": "bramus/ansi-php", @@ -245,6 +245,67 @@ ], "time": "2019-12-20T14:15:16+00:00" }, + { + "name": "phpoption/phpoption", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.5.9 || ^7.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2019-12-15T19:35:24+00:00" + }, { "name": "psr/log", "version": "1.1.2", @@ -364,16 +425,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.6.1", + "version": "v4.1.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" + "reference": "0176075a1b7ee9cf86f70143ec79edf7072c975a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/0176075a1b7ee9cf86f70143ec79edf7072c975a", + "reference": "0176075a1b7ee9cf86f70143ec79edf7072c975a", "shasum": "", "mirrors": [ { @@ -383,16 +444,18 @@ ] }, "require": { - "php": ">=5.3.9", + "php": "^5.5.9 || ^7.0", + "phpoption/phpoption": "^1.7.1", "symfony/polyfill-ctype": "^1.9" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.0" + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -405,10 +468,15 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "homepage": "https://vancelucas.com/" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -417,7 +485,7 @@ "env", "environment" ], - "time": "2019-01-29T11:11:52+00:00" + "time": "2019-12-14T13:59:29+00:00" } ], "packages-dev": [], diff --git a/conf/user.conf.example b/conf/user.conf.example index 6e184c5..20ff895 100644 --- a/conf/user.conf.example +++ b/conf/user.conf.example @@ -11,32 +11,6 @@ ACCESS_TOKEN= REFRESH_TOKEN= COOKIE= -####################### -# 固定设置 # -####################### - -# 推送服务器 -USE_SERVER=true -SERVER_ADDR=tcp://47.102.120.84:10010 -SERVER_KEY=,*(?PVl]nIbo35sB - -# SERVER酱, 用于推送消息 -USE_SCKEY= - -# 切换HTTPS,为真则使用https协议 -USE_HTTPS=true - -# 是否使用代理(前提保证有效代理) -USE_PROXY=false -PROXY_IP=127.0.0.1 -PROXY_PORT=8888 - -# 直播间ID,用于礼物赠送 -ROOM_ID=9522051 - -# 弹幕监控房间(为空则随机) -SOCKET_ROOM_ID=9522051 - ####################### # 功能设置 # ####################### @@ -78,8 +52,51 @@ USE_ADD_COIN=false ADD_COIN_AV_NUM=1 ADD_COIN_AV=33492180 +# 休眠时间|时间区间(0-23)|逗号分隔 +USE_SLEEP=true +SLEEP_SECTION=2,3,4,5,6 + ####################### -# 日志设置 # +# 基础设置 # +####################### + +# 独立推送服务(主) +USE_ALONE_SERVER=true +ALONE_SERVER_ADDR=tcp://47.102.120.84:10010 +ALONE_SERVER_KEY=,*(?PVl]nIbo35sB + +# 分区推送服务(备) +USE_ZONE_SERVER=false +ZONE_SERVER_ADDR=tcp://broadcastlv.chat.bilibili.com:2243/sub + +# 切换HTTPS,为真则使用https协议 +USE_HTTPS=true + +# 是否使用代理(前提保证有效代理) +USE_PROXY=false +PROXY_IP=127.0.0.1 +PROXY_PORT=8888 + +# SERVER酱, 用于推送消息 +USE_SCKEY= + +####################### +# 房间设置 # +####################### + +# 直播间ID,用于礼物赠送 +ROOM_ID=9522051 + +# 勋章亲密度,测试功能,使用长位房间号,左侧优先,仅支持辣条和亿元 +# 是否填满(按时间投喂正常礼物,否则过期礼物)|直播间ID列表|逗号分隔 +FEED_FILL=false +ROOM_LIST=9522051 + +# 弹幕监控房间(为空则随机) +SOCKET_ROOM_ID=9522051 + +####################### +# 程序设置 # ####################### # 写入日志 diff --git a/index.php b/index.php index 97479e6..3487d48 100644 --- a/index.php +++ b/index.php @@ -8,89 +8,12 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; -//autoload require 'vendor/autoload.php'; -use Dotenv\Dotenv; -set_time_limit(0); -header("Content-Type:text/html; charset=utf-8"); -date_default_timezone_set('Asia/Shanghai'); +$filename = isset($argv[1]) ? $argv[1] : 'user.conf'; -class Index -{ - public static $conf_file = null; - public static $dotenv = null; - - /** - * @param $conf_file - * @throws \Exception - */ - public static function run($conf_file) - { - self::$conf_file = $conf_file; - self::loadConfigFile(); - while (true) { - if (!Login::check()) { - self::$dotenv->overload(); - } - Daily::run(); - MasterSite::run(); - Danmu::run(); - GiftSend::run(); - Heart::run(); - Silver::run(); - Task::run(); - Silver2Coin::run(); - GroupSignIn::run(); - Live::run(); - GiftHeart::run(); - Winning::run(); - MaterialObject::run(); - TcpClient::run(); - Storm::run(); - PkRaffle::run(); - UnifyRaffle::run(); - Guard::run(); - Anchor::run(); - Statistics::run(); - usleep(0.2 * 1000000); - } - } - - protected static function loadConfigFile() - { - $file_path = __DIR__ . '/conf/' . self::$conf_file; - - if (is_file($file_path) && self::$conf_file != 'user.conf') { - $load_files = [ - self::$conf_file, - ]; - } else { - $default_file_path = __DIR__ . '/conf/user.conf'; - if (!is_file($default_file_path)) { - exit('默认加载配置文件不存在,请按照文档添加配置文件!'); - } - - $load_files = [ - 'user.conf', - ]; - } - foreach ($load_files as $load_file) { - self::$dotenv = new Dotenv(__DIR__ . '/conf', $load_file); - self::$dotenv->load(); - } - - // load ACCESS_KEY - Login::run(); - self::$dotenv->overload(); - } - -} - -// LOAD -$conf_file = isset($argv[1]) ? $argv[1] : 'user.conf'; -// RUN -Index::run($conf_file); +$app = new BiliHelper\Core\App(); +$app->load(__DIR__, $filename); +$app->start(); diff --git a/src/File.php b/src/File.php deleted file mode 100644 index 729955a..0000000 --- a/src/File.php +++ /dev/null @@ -1,31 +0,0 @@ - $data['message']]); - Log::warning('清空礼物功能禁用!'); - self::$lock = time() + 100000000; - return; - } - - self::$uid = $data['mid']; - - $payload = [ - 'id' => getenv('ROOM_ID'), - ]; - $data = Curl::get('https://api.live.bilibili.com/room/v1/Room/get_info', Sign::api($payload)); - $data = json_decode($data, true); - - if (isset($data['code']) && $data['code']) { - Log::warning('获取主播房间号失败!', ['msg' => $data['message']]); - Log::warning('清空礼物功能禁用!'); - self::$lock = time() + 100000000; - return; - } - - Log::info('直播间信息生成完毕!'); - - self::$ruid = $data['data']['uid']; - self::$roomid = $data['data']['room_id']; - } - - public static function run() - { - if (empty(self::$ruid)) { - self::getRoomInfo(); - } - - if (self::$lock > time()) { - return; - } - - $payload = []; - $data = Curl::get('https://api.live.bilibili.com/gift/v2/gift/bag_list', Sign::api($payload)); - $data = json_decode($data, true); - - if (isset($data['code']) && $data['code']) { - Log::warning('背包查看失败!', ['msg' => $data['message']]); - } - - if (isset($data['data']['list'])) { - foreach ($data['data']['list'] as $vo) { - if ($vo['corner_mark'] == '永久'){ - continue; - } - if ($vo['expire_at'] >= $data['data']['time'] && $vo['expire_at'] <= $data['data']['time'] + 3600) { - self::send($vo); - sleep(3); - } - } - } - - self::$lock = time() + 600; - } - - protected static function send($value) - { - $payload = [ - 'coin_type' => 'silver', - 'gift_id' => $value['gift_id'], - 'ruid' => self::$ruid, - 'uid' => self::$uid, - 'biz_id' => self::$roomid, - 'gift_num' => $value['gift_num'], - 'data_source_id' => '', - 'data_behavior_id' => '', - 'bag_id' => $value['bag_id'] - ]; - - $data = Curl::post('https://api.live.bilibili.com/gift/v2/live/bag_send', Sign::api($payload)); - $data = json_decode($data, true); - - if (isset($data['code']) && $data['code']) { - Log::warning('送礼失败!', ['msg' => $data['message']]); - } else { - Log::notice("成功向 {$payload['biz_id']} 投喂了 {$value['gift_num']} 个{$value['gift_name']}"); - } - } -} diff --git a/src/Guard.php b/src/Guard.php deleted file mode 100644 index e7b5c01..0000000 --- a/src/Guard.php +++ /dev/null @@ -1,124 +0,0 @@ - time()) { - return; - } - self::startLottery(); - } - - /** - * 抽奖逻辑 - * @return bool - */ - protected static function startLottery(): bool - { - $max_num = 3; - while ($max_num) { - $guard = array_shift(self::$wait_list); - if (is_null($guard)) { - break; - } - $guard_lid = $guard['lid']; - $guard_rid = $guard['rid']; - Live::goToRoom($guard_rid); - Statistics::addJoinList(self::ACTIVE_TITLE); - $data = self::lottery($guard_rid, $guard_lid); - if ($data['code'] == 0) { - Statistics::addSuccessList(self::ACTIVE_TITLE); - Log::notice("房间 {$guard_rid} 编号 {$guard_lid} " . self::ACTIVE_TITLE . ": {$data['data']['message']}"); - } elseif ($data['code'] == 400 && $data['msg'] == '你已经领取过啦') { - Log::info("房间 {$guard_rid} 编号 {$guard_lid} " . self::ACTIVE_TITLE . ": {$data['msg']}"); - } else { - Log::warning("房间 {$guard_rid} 编号 {$guard_lid} " . self::ACTIVE_TITLE . ": {$data['msg']}"); - } - $max_num--; - } - return true; - } - - /** - * 请求抽奖 - * @param $rid - * @param $lid - * @return array - */ - private static function lottery($rid, $lid): array - { - $user_info = User::parseCookies(); - $url = "https://api.live.bilibili.com/lottery/v2/lottery/join"; - $payload = [ - "roomid" => $rid, - "id" => $lid, - "type" => "guard", - "csrf_token" => $user_info['token'] - ]; - $raw = Curl::post($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - return $de_raw; - } - - /** - * 重复检测 - * @param int $lid - * @return bool - */ - private static function toRepeatLid(int $lid): bool - { - if (in_array($lid, self::$all_list)) { - return true; - } - if (count(self::$all_list) > 2000) { - self::$all_list = []; - } - array_push(self::$all_list, $lid); - - return false; - } - - /** - * 数据推入队列 - * @param array $data - * @return bool - */ - public static function pushToQueue(array $data): bool - { - if (getenv(self::ACTIVE_SWITCH) == 'false') { - return false; - } - if (self::toRepeatLid($data['lid'])) { - return false; - } - Statistics::addPushList(self::ACTIVE_TITLE); - self::$wait_list = array_merge(self::$wait_list, [['rid' => $data['rid'], 'lid' => $data['lid']]]); - $wait_num = count(self::$wait_list); - if ($wait_num > 2) { - Log::info("当前队列中共有 {$wait_num} 个" . self::ACTIVE_TITLE . "待抽奖"); - } - return true; - } -} \ No newline at end of file diff --git a/src/Live.php b/src/Live.php deleted file mode 100644 index 154457b..0000000 --- a/src/Live.php +++ /dev/null @@ -1,154 +0,0 @@ - $room_id, - ]; - Curl::post('https://api.live.bilibili.com/room/v1/Room/room_entry_action', Sign::api($payload)); - // Log::info('进入直播间[' . $room_id . ']抽奖!'); - return true; - } - - // get Millisecond - public static function getMillisecond() - { - list($t1, $t2) = explode(' ', microtime()); - return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); - } - - // IS SLEEP - public static function isSleep() - { - if (self::$lock > time()) { - return; - } - self::$lock = time() + 5 * 60; - - $hour = date('H'); - if ($hour >= 2 && $hour < 6) { - self::bannedVisit('sleep'); - Log::warning('休眠时间,暂停非必要任务,4小时后自动开启!'); - return; - } - - $payload = []; - $raw = Curl::get('https://api.live.bilibili.com/mobile/freeSilverAward', Sign::api($payload)); - $de_raw = json_decode($raw, true); - if ($de_raw['msg'] == '访问被拒绝') { - self::bannedVisit('ban'); - Log::warning('账号拒绝访问,暂停非必要任务,凌晨自动开启!'); - } - return; - } - - //被封禁访问 - public static function bannedVisit($arg) - { - //获取当前时间 - $block_time = strtotime(date("Y-m-d H:i:s")); - - if ($arg == 'ban') { - $unblock_time = strtotime(date("Y-m-d", strtotime("+1 day", $block_time))); - } elseif ($arg == 'sleep') { - // TODO - $unblock_time = $block_time + 4 * 60 * 60; - } else { - $unblock_time = time(); - } - - $second = time() + ceil($unblock_time - $block_time) + 5 * 60; - $hour = floor(($second - time()) / 60 / 60); - - if ($arg == 'ban') { - // 推送被ban信息 - Notice::run('banned', $hour); - } - - self::$lock = $second; - - Silver::$lock = $second; - MaterialObject::$lock = $second; - GiftHeart::$lock = $second; - TcpClient::$lock = $second; - return; - } - -} \ No newline at end of file diff --git a/src/Notice.php b/src/Notice.php deleted file mode 100644 index 7df86c4..0000000 --- a/src/Notice.php +++ /dev/null @@ -1,123 +0,0 @@ - '活动抽奖结果', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 在活动抽奖中获得: ' . self::$result, - ]; - break; - case 'storm': - $info = [ - 'title' => '节奏风暴中奖结果', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 在节奏风暴抽奖中: ' . self::$result, - ]; - break; - case 'active': - $info = [ - 'title' => '活动中奖结果', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 在活动抽奖中获得: ' . self::$result, - ]; - break; - case 'cookieRefresh': - $info = [ - 'title' => 'Cookie刷新', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 刷新Cookie: ' . self::$result, - ]; - break; - case 'loginInit': - break; - - case 'todaySign': - $info = [ - 'title' => '每日签到', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 签到: ' . self::$result, - ]; - break; - case 'winIng': - $info = [ - 'title' => '实物中奖', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 实物中奖: ' . self::$result, - ]; - break; - case 'banned': - $info = [ - 'title' => '账号封禁', - 'content' => '[' . $nowtime . ']' . ' 用户: ' . self::$uname . ' 账号被封禁: 程序开始睡眠,凌晨自动唤醒,距离唤醒还有' . self::$result . '小时', - ]; - break; - default: - break; - } - self::scSend($info); - - return true; - } - - // 发送信息 - private static function scSend($info) - { - - $postdata = http_build_query( - [ - 'text' => $info['title'], - 'desp' => $info['content'] - ] - ); - - $opts = ['http' => - [ - 'method' => 'POST', - 'header' => 'Content-type: application/x-www-form-urlencoded', - 'content' => $postdata - ] - ]; - try { - $context = stream_context_create($opts); - file_get_contents('https://sc.ftqq.com/' . self::$sckey . '.send', false, $context); - - } catch (\Exception $e) { - Log::warning('Server酱推送信息失败,请检查!'); - } - return; - //return $result = file_get_contents('https://sc.ftqq.com/' . $this->_sckey . '.send', false, $context); - } -} \ No newline at end of file diff --git a/src/Socket.php b/src/Socket.php deleted file mode 100644 index abd7b29..0000000 --- a/src/Socket.php +++ /dev/null @@ -1,193 +0,0 @@ - time()) { - return; - } - self::$lock = time() + 0.5; - - self::start(); - $message = self::decodeMessage(); - if (!$message) { - unset($message); - self::resetConnection(); - return; - } - $data = DataTreating::socketJsonToArray($message); - if (!$data) { - return; - } - DataTreating::socketArrayToDispose($data); - return; - } - - // KILL - protected static function killConnection() - { - socket_clear_error(self::$socket_connection); - socket_shutdown(self::$socket_connection); - socket_close(self::$socket_connection); - self::$socket_connection = null; - } - - // RECONNECT - protected static function resetConnection() - { - $errorcode = socket_last_error(); - $errormsg = socket_strerror($errorcode); - unset($errormsg); - unset($errorcode); - self::killConnection(); -// Log::warning('SOCKET连接断开,5秒后重新连接...'); -// sleep(5); - self::start(); - return; - } - - // SOCKET READER - protected static function readerSocket(int $length) - { - return socket_read(self::$socket_connection, $length); - } - - // DECODE MESSAGE - protected static function decodeMessage() - { - $res = ''; - $tmp = ''; - while (1) { - while ($out = self::readerSocket(16)) { - $res = unpack('N', $out); - unset($out); - if ($res[1] != 16) { - break; - } - } - if (isset($res[1])) { - $length = $res[1] - 16; - if ($length > 65535) { - continue; - } - if ($length <= 0) { - return false; - } - return self::readerSocket($length); - } - return false; - } - } - - // START - protected static function start() - { - if (is_null(self::$socket_connection)) { - $room_id = empty(getenv('SOCKET_ROOM_ID')) ? Live::getUserRecommend() : Live::getRealRoomID(getenv('SOCKET_ROOM_ID')); - $room_id = intval($room_id); - if ($room_id) { - self::getSocketServer($room_id); - self::connectServer($room_id, self::$socket_ip, self::$socket_port); - } - } - self::sendHeartBeatPkg(); - return; - } - - // SEND HEART - protected static function sendHeartBeatPkg() - { - if (self::$heart_lock > time()) { - return; - } - $action_heart_beat = intval(getenv('ACTIONHEARTBEAT')); - $str = pack('NnnNN', 16, 16, 1, $action_heart_beat, 1); - socket_write(self::$socket_connection, $str, strlen($str)); - Log::info('发送心跳包到弹幕服务器!'); - self::$heart_lock = time() + 30; - return; - } - - // SOCKET CONNECT - protected static function connectServer($room_id, $ip, $port) - { - $falg = 10; - while ($falg) { - try { - $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - socket_connect($socket, $ip, $port); - $str = self::packMsg($room_id); - socket_write($socket, $str, strlen($str)); - self::$socket_connection = $socket; - // TODO - Log::info("连接到弹幕服务器[{$room_id}]成功!"); - return; - } catch (\Exception $e) { - Log::info("连接到弹幕服务器[{$room_id}]失败!"); - Log::warning($e); - $falg -= 1; - } - } - Log::info("连接弹幕服务器[{$room_id}]错误次数过多,检查网络!"); - exit(); - } - - // PACK DATA - protected static function packMsg($room_id) - { - $action_entry = intval(getenv('ACTIONENTRY')); - $data = sprintf("{\"uid\":%d%08d,\"roomid\":%d}", - random_int(1000000, 2999999), - random_int(0, 99999999), - intval($room_id) - ); - return pack('NnnNN', 16 + strlen($data), 16, 1, $action_entry, 1) . $data; - } - - // GET SERVER - protected static function getSocketServer(int $room_id): bool - { - while (1) { - try { - $payload = [ - 'room_id' => $room_id, - ]; - $data = Curl::get('https://api.live.bilibili.com/room/v1/Danmu/getConf', Sign::api($payload)); - $data = json_decode($data, true); - - // TODO 判断 - if (isset($data['code']) && $data['code']) { - continue; - } - - self::$socket_ip = gethostbyname($data['data']['host']); - self::$socket_port = $data['data']['port']; - - break; - } catch (\Exception $e) { - Log::warning("获取弹幕服务器出错,错误信息[{$e}]!"); - continue; - } - } - return true; - } -} \ No newline at end of file diff --git a/src/Storm.php b/src/Storm.php deleted file mode 100644 index 6fbf0a6..0000000 --- a/src/Storm.php +++ /dev/null @@ -1,201 +0,0 @@ - time()) { - return; - } - self::init(); - self::startLottery(); - } - - private static function init() - { - if (!is_null(self::$attempt) && !is_null(self::$drop_rate)) { - return; - } - // TODO 信息不完整, 请检查配置文件 没有严格校验 - self::$drop_rate = getenv('STORM_DROPRATE') !== "" ? (int)getenv('STORM_DROPRATE') : 0; - self::$attempt = getenv('STORM_ATTEMPT') !== "" ? explode(',', getenv('STORM_ATTEMPT')) : [30, 50]; - } - - /** - * 抽奖逻辑 - * @return bool - * @throws \Exception - */ - protected static function startLottery(): bool - { - while (true) { - $storm = array_shift(self::$wait_list); - if (is_null($storm)) { - break; - } - // 丢弃 - if (mt_rand(1, 100) <= (int)self::$drop_rate) { - break; - } - $storm_lid = $storm['lid']; - $storm_rid = $storm['rid']; - Live::goToRoom($storm_rid); - Statistics::addJoinList(self::ACTIVE_TITLE); - $num = random_int((int)self::$attempt[0], (int)self::$attempt[1]); - for ($i = 1; $i < $num; $i++) { - if (!self::lottery($storm_rid, $storm_lid, $i)) { - break; - } - } - } - return true; - } - - /** - * 格式化日志输出 - * @param $id - * @param $num - * @param $info - * @return string - */ - private static function formatInfo($id, $num, $info): string - { - return "风暴 {$id} 请求 {$num} 状态 {$info}"; - } - - /** - * 请求抽奖 - * @param $rid - * @param $lid - * @param $num - * @return bool - */ - protected static function lottery($rid, $lid, $num): bool - { - $user_info = User::parseCookies(); - $payload = [ - "id" => $lid, - "color" => "16772431", - "roomid" => $rid, - "captcha_token" => "", - "captcha_phrase" => "", - "token" => $user_info['token'], - "csrf_token" => $user_info['token'], - "visit_id" => "", - ]; - $raw = Curl::post('https://api.live.bilibili.com/lottery/v1/Storm/join', Sign::api($payload)); - $de_raw = json_decode($raw, true); - if ($de_raw['code'] == 429 || $de_raw['code'] == -429) { - Log::notice(self::formatInfo($lid, $num, '节奏风暴未实名或异常验证码')); - return false; - } - if (isset($de_raw['data']) && empty($de_raw['data'])) { - Log::notice(self::formatInfo($lid, $num, '节奏风暴在小黑屋')); - return false; - } - if ($de_raw['code'] == 0) { - Statistics::addSuccessList(self::ACTIVE_TITLE); - Log::notice(self::formatInfo($lid, $num, $de_raw['data']['mobile_content'])); - return false; - } - if ($de_raw['msg'] == '节奏风暴不存在') { - Log::notice(self::formatInfo($lid, $num, '节奏风暴已结束')); - return false; - } - if ($de_raw['msg'] == '已经领取奖励') { - Log::notice(self::formatInfo($lid, $num, '节奏风暴已经领取')); - return false; - } - if ($de_raw['msg'] == '你错过了奖励,下次要更快一点哦~') { - return true; - } - Log::notice(self::formatInfo($lid, $num, $de_raw['msg'])); - return true; - } - - /** - * 检查ID - * @param $room_id - * @return array|bool - */ - protected static function stormCheckId($room_id) - { - $raw = Curl::get('https://api.live.bilibili.com/lottery/v1/Storm/check?roomid=' . $room_id); - $de_raw = json_decode($raw, true); - - if (empty($de_raw['data']) || $de_raw['data']['hasJoin'] != 0) { - return false; - } - return [ - 'id' => $de_raw['data']['id'], - ]; - } - - - /** - * 重复检测 - * @param $lid - * @return bool - */ - private static function toRepeatLid($lid): bool - { - if (in_array($lid, self::$all_list)) { - return true; - } - if (count(self::$all_list) > 2000) { - self::$all_list = []; - } - array_push(self::$all_list, $lid); - - return false; - } - - /** - * 数据推入队列 - * @param array $data - * @return bool - */ - public static function pushToQueue(array $data): bool - { - if (getenv(self::ACTIVE_SWITCH) == 'false') { - return false; - } - if (self::toRepeatLid($data['lid'])) { - return false; - } - Statistics::addPushList(self::ACTIVE_TITLE); - self::$wait_list = array_merge(self::$wait_list, [['rid' => $data['rid'], 'lid' => $data['lid']]]); - $wait_num = count(self::$wait_list); - if ($wait_num > 2) { - Log::info("当前队列中共有 {$wait_num} 个" . self::ACTIVE_TITLE . "待抽奖"); - } - return true; - } -} diff --git a/src/UnifyRaffle.php b/src/UnifyRaffle.php deleted file mode 100644 index ba184e1..0000000 --- a/src/UnifyRaffle.php +++ /dev/null @@ -1,155 +0,0 @@ - $rid - ]; - $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v3/smalltv/Check'; - $raw = Curl::get($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - - // 计数 && 跳出 - $total = count($de_raw['data']['list']); - if (!$total) { - return false; - } - - for ($i = 0; $i < $total; $i++) { - /** - * raffleId : 88995 - * title : C位光环抽奖 - * type : GIFT_30013 - */ - $data = [ - 'raffle_id' => $de_raw['data']['list'][$i]['raffleId'], - 'title' => $de_raw['data']['list'][$i]['title'], - 'type' => $de_raw['data']['list'][$i]['type'], - 'wait' => $de_raw['data']['list'][$i]['time_wait'] + strtotime(date("Y-m-d H:i:s")), - 'room_id' => $rid, - ]; - if (static::toRepeatLid($data['raffle_id'])) { - continue; - } - Statistics::addPushList(static::ACTIVE_TITLE); - array_push(static::$wait_list, $data); - } - return true; - } - - - /** - * @use WEB中奖查询 - */ - public static function resultWeb() - { - // 时间锁 - if (static::$rw_lock > time()) { - return; - } - // 如果待查询为空 && 去重 - if (!count(static::$finish_list)) { - static::$rw_lock = time() + 40; - return; - } - // 查询,每次查询10个 - $flag = 0; - foreach (static::$finish_list as $winning_web) { - $flag++; - if ($flag > 40) { - break; - } - // 参数 - $payload = [ - 'type' => $winning_web['type'], - 'raffleId' => $winning_web['raffle_id'] - ]; - // Web V3 Notice - $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v3/smalltv/Notice'; - // 请求 && 解码 - $raw = Curl::get($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - // 判断 - switch ($de_raw['data']['status']) { - // case 3: - // break; - case 2: - Statistics::addSuccessList(static::ACTIVE_TITLE); - // 提示信息 - $info = "房间 {$winning_web['room_id']} 编号 {$winning_web['raffle_id']} {$winning_web['title']}: 获得"; - $info .= "{$de_raw['data']['gift_name']}X{$de_raw['data']['gift_num']}"; - Log::notice($info); - // 推送活动抽奖信息 - if ($de_raw['data']['gift_name'] != '辣条' && $de_raw['data']['gift_name'] != '') { - Notice::run('raffle', $info); - } - // 删除查询完成ID - unset(static::$finish_list[$flag - 1]); - static::$finish_list = array_values(static::$finish_list); - break; - default: - break; - } - } - static::$rw_lock = time() + 40; - return; - } - - /** - * @use 请求抽奖 - * @param array $data - * @return bool - */ - protected static function lottery(array $data): bool - { - $user_info = User::parseCookies(); - $payload = [ - 'raffleId' => $data['raffle_id'], - 'roomid' => $data['room_id'], - 'type' => $data['type'], - 'csrf_token' => $user_info['token'], - 'csrf' => $user_info['token'], - 'visit_id' => null, - ]; - // V3接口 暂做保留处理 - // $url = 'https://api.live.bilibili.com/gift/v3/smalltv/join'; - // $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v5/smalltv/Join'; - $url = 'https://api.live.bilibili.com/gift/v4/smalltv/getAward'; - $raw = Curl::post($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - if (isset($de_raw['code']) && $de_raw['code']) { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$de_raw['message']}"); - } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$de_raw['msg']}"); - array_push(static::$finish_list, $data); - } - return true; - } -} diff --git a/src/Websocket.php b/src/Websocket.php deleted file mode 100644 index 7a5d6d0..0000000 --- a/src/Websocket.php +++ /dev/null @@ -1,217 +0,0 @@ - time()) { - return; - } - static::init(); - static::heart(); - static::receive(); - - } - - - /** - * @use 初始化 - */ - protected static function init() - { - if (!static::$websocket) { - $client = new Client( - 'ws://broadcastlv.chat.bilibili.com:2244/sub', - 'http://live.bilibili.com' - ); - static::$websocket = $client; - } - - if (!static::$room_id) { - static::$room_id = empty(getenv('SOCKET_ROOM_ID')) ? Live::getUserRecommend() : Live::getRealRoomID(getenv('SOCKET_ROOM_ID')); - } - return; - } - - /** - * @use 连接 - */ - protected static function connect() - { - Log::info("连接弹幕服务器"); - if (!static::$websocket->connect()) { - Log::error('连接弹幕服务器失败'); - static::$lock = time() + 60; - return; - } - static::$websocket->sendData( - static::packMsg(json_encode([ - 'uid' => 0, - 'roomid' => static::$room_id, - 'protover' => 1, - 'platform' => 'web', - 'clientver' => '1.4.1', - ]), 0x0007) - ); - } - - /** - * @use 断开连接 - */ - protected static function disconnect() - { - Log::info('断开弹幕服务器'); - static::$websocket->disconnect(); - } - - - /** - * @use 读取数据 - */ - protected static function receive() - { - $responses = static::$websocket->receive(); - if (is_array($responses) && !empty($responses)) { - foreach ($responses as $response) { - static::split($response->getPayload()); - } - static::receive(); - } - - } - - /** - * @use 发送心跳 - */ - protected static function heart() - { - if (!static::$websocket->isConnected()) { - static::connect(); - return; - } - if (static::$heart_lock <= time()) { - if (static::$websocket->sendData(static::packMsg('', 0x0002))) { - static::$heart_lock = time() + 30; - } - } - return; - } - - - /** - * @param $id - * @return mixed|string - */ - protected static function type($id) - { - $option = [ - 0x0002 => 'WS_OP_HEARTBEAT', - 0x0003 => 'WS_OP_HEARTBEAT_REPLY', - 0x0005 => 'WS_OP_MESSAGE', - 0x0007 => 'WS_OP_USER_AUTHENTICATION', - 0x0008 => 'WS_OP_CONNECT_SUCCESS', - ]; - return isset($option[$id]) ? $option[$id] : "WS_OP_UNKNOW($id)"; - } - - - /** - * @param $bin - * @throws \Exception - */ - protected static function split($bin) - { - if (strlen($bin)) { - $head = unpack('Npacklen/nheadlen/nver/Nop/Nseq', substr($bin, 0, 16)); - $bin = substr($bin, 16); - - $length = isset($head['packlen']) ? $head['packlen'] : 16; - $type = isset($head['op']) ? $head['op'] : 0x0000; - $body = substr($bin, 0, $length - 16); - - Log::debug(static::type($type) . " (len=$length)"); - - if (($length - 16) > 65535 || ($length - 16) < 0) { - Log::notice("长度{$length}异常,重新连接服务器!"); - if (static::$websocket->isConnected()) { - static::disconnect(); - } - if (!static::$websocket->isConnected()) { - static::connect(); - } - return; - } - - if ($type == 0x0005 || $type == 0x0003) { - if ($head['ver'] == 2) { - $body = gzuncompress($body); - if (substr($body, 0, 1) != '{') { - static::split($bin); - return; - } - } - DataTreating::socketJsonToArray($body); - } - - $bin = substr($bin, $length - 16); - if (strlen($bin)) { - static::split($bin); - } - } - return; - } - - - /** - * @param $value - * @param $option - * @return string - * @throws \Exception - */ - protected static function packMsg($value, $option) - { - $head = pack('NnnNN', 0x10 + strlen($value), 0x10, 0x01, $option, 0x0001); - $str = $head . $value; - static::split($str); - return $str; - } - - /** - * @use 写入log - * @param $message - */ - private static function writeLog($message) - { - $path = './danmu/'; - if (!file_exists($path)) { - mkdir($path); - chmod($path, 0777); - } - $filename = $path . getenv('APP_USER') . ".log"; - $date = date('[Y-m-d H:i:s] '); - $data = "[{$date}]{$message}" . PHP_EOL; - file_put_contents($filename, $data, FILE_APPEND); - return; - } -} \ No newline at end of file diff --git a/src/Winning.php b/src/Winning.php deleted file mode 100644 index b89bce8..0000000 --- a/src/Winning.php +++ /dev/null @@ -1,68 +0,0 @@ - time()) { - return; - } - self::$lock = time() + 24 * 60 * 60; - - $payload = [ - 'page' => '1', - 'month' => '', - ]; - $raw = Curl::post('https://api.live.bilibili.com/lottery/v1/award/award_list', Sign::api($payload)); - $de_raw = json_decode($raw, true); - $month = $de_raw['data']['month_list'][0]['Ym']; - - // TODO - $payload = [ - 'page' => '1', - 'month' => $month, - ]; - $raw = Curl::post('https://api.live.bilibili.com/lottery/v1/award/award_list', Sign::api($payload)); - $de_raw = json_decode($raw, true); - // 没有记录 - if (empty($de_raw['data']['list'])) { - return; - } - - $init_time = strtotime(date("y-m-d h:i:s")); //当前时间 - foreach ($de_raw['data']['list'] as $gift) { - $next_time = strtotime($gift['create_time']); //礼物时间 - $day = ceil(($init_time - $next_time) / 86400); //60s*60min*24h - - if ($day <= 2 && $gift['update_time'] == '') { - $data_info = '您在: ' . $gift['create_time'] . '抽中[' . $gift['gift_name'] . 'X' . $gift['gift_num'] . ']未查看!'; - Log::notice($data_info); - // TODO 推送 log - } - } - return; - } -} \ No newline at end of file diff --git a/src/core/App.php b/src/core/App.php new file mode 100644 index 0000000..0603064 --- /dev/null +++ b/src/core/App.php @@ -0,0 +1,72 @@ +load(); + self::$app_config = $app_config; + self::$config_path = $config_path; + } + + + /** + * @use 写入配置 + * @param $key + * @param $val + * @return bool + */ + private static function _put($key, $val) + { + if (!is_null($val)) { + if (!empty(self::$config_path)) { + file_put_contents(self::$config_path, preg_replace( + '/^' . $key . '=\S*/m', + $key . '=' . $val, + file_get_contents(self::$config_path) + )); + } + } + putenv($key . '=' . $val); + // self::$app_config->load(); + return true; + } + + /** + * @use 读出配置 + * @param string|null $key + * @return mixed|null + */ + private static function _get($key) + { + if (self::$app_config->required($key)) { + return getenv($key); + } + return null; + } + +} \ No newline at end of file diff --git a/src/Curl.php b/src/core/Curl.php similarity index 99% rename from src/Curl.php rename to src/core/Curl.php index adf87a5..86e9b4d 100644 --- a/src/Curl.php +++ b/src/core/Curl.php @@ -8,7 +8,7 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Core; class Curl { diff --git a/src/Log.php b/src/core/Log.php similarity index 99% rename from src/Log.php rename to src/core/Log.php index c6e663c..4dd8268 100644 --- a/src/Log.php +++ b/src/core/Log.php @@ -8,7 +8,7 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Core; use Monolog\Logger; use Monolog\Handler\StreamHandler; diff --git a/src/TcpClient.php b/src/plugin/AloneTcpClient.php similarity index 89% rename from src/TcpClient.php rename to src/plugin/AloneTcpClient.php index 5cafae9..073b626 100644 --- a/src/TcpClient.php +++ b/src/plugin/AloneTcpClient.php @@ -8,14 +8,18 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; use Exception; use Socket\Raw\Factory; -class TcpClient +class AloneTcpClient { - public static $lock = 0; + use TimeLock; private static $heart_lock = 0; private static $client = null; private static $server_addr = null; @@ -23,11 +27,11 @@ class TcpClient private static $socket_timeout = 0; /** - * @desc 入口 + * @use 入口 */ public static function run() { - if (self::$lock > time() || getenv('USE_SERVER') == 'false') { + if (self::getLock() > time() || getenv('USE_ALONE_SERVER') == 'false') { return; } self::init(); @@ -37,16 +41,16 @@ class TcpClient /** - * @desc 初始化 + * @use 初始化 */ private static function init() { - if (empty(getenv('SERVER_ADDR')) || empty(getenv('SERVER_KEY'))) { + if (empty(getenv('ALONE_SERVER_ADDR')) || empty(getenv('ALONE_SERVER_KEY'))) { exit('推送服务器信息不完整, 请检查配置文件!'); } if (!self::$server_addr || !self::$server_key) { - self::$server_addr = getenv('SERVER_ADDR'); - self::$server_key = getenv('SERVER_KEY'); + self::$server_addr = getenv('ALONE_SERVER_ADDR'); + self::$server_key = getenv('ALONE_SERVER_KEY'); } if (!self::$client) { self::openConnect(); @@ -55,7 +59,7 @@ class TcpClient /** - * @desc 数据封装 + * @use 数据封装 * @param $value * @param $fmt * @return string @@ -68,7 +72,7 @@ class TcpClient } /** - * @desc 数据解包 + * @use 数据解包 * @param $value * @param string $fmt * @return array|false @@ -80,7 +84,7 @@ class TcpClient } /** - * @desc 连接认证 + * @use 连接认证 */ private static function handShake() { @@ -96,7 +100,7 @@ class TcpClient } /** - * @desc 心跳 + * @use 心跳 */ private static function heartBeat() { @@ -109,7 +113,7 @@ class TcpClient } /** - * @desc 读数据 + * @use 读数据 * @param $length * @return array|bool|false */ @@ -132,7 +136,7 @@ class TcpClient } /** - * @desc 写数据 + * @use 写数据 * @param $data * @return bool */ @@ -153,7 +157,7 @@ class TcpClient /** - * @desc 打开连接 + * @use 打开连接 */ private static function openConnect() { @@ -166,13 +170,13 @@ class TcpClient Log::info("连接到 {$socket->getPeerName()} 推送服务器"); } catch (Exception $e) { Log::error("连接到推送服务器失败, {$e->getMessage()}"); - self::$lock = time() + 60; + self::setLock( 60); } } } /** - * @desc 重新连接 + * @use 重新连接 */ private static function reConnect() { @@ -182,7 +186,7 @@ class TcpClient } /** - * @desc 断开连接 + * @use 断开连接 */ private static function closeConnect() { diff --git a/src/Anchor.php b/src/plugin/AnchorRaffle.php similarity index 55% rename from src/Anchor.php rename to src/plugin/AnchorRaffle.php index ae6aa60..7b792d9 100644 --- a/src/Anchor.php +++ b/src/plugin/AnchorRaffle.php @@ -8,15 +8,18 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; -class Anchor extends BaseRaffle +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; + +class AnchorRaffle extends BaseRaffle { const ACTIVE_TITLE = '天选时刻'; const ACTIVE_SWITCH = 'USE_ANCHOR'; - public static $lock = 0; - public static $rw_lock = 0; + use TimeLock; protected static $wait_list = []; protected static $finish_list = []; @@ -24,41 +27,45 @@ class Anchor extends BaseRaffle private static $filter_type = []; + /** - * 检查抽奖列表 - * @param $rid + * @use 解析数据 + * @param int $room_id + * @param array $data * @return bool */ - protected static function check($rid): bool + protected static function parse(int $room_id, array $data): bool { - $payload = [ - 'roomid' => $rid - ]; - $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v1/Anchor/Check'; - $raw = Curl::get($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - - // 防止异常情况 - if (!isset($de_raw['data']) || $de_raw['data']['join_type'] || $de_raw['data']['lot_status']) { + // 防止异常 + if (!array_key_exists('anchor', $data['data'])) { return false; } - // TODO + $de_raw = $data['data']['anchor']; + if (empty($de_raw)) { + return false; + } + // 无效抽奖 + if ($de_raw['join_type'] || $de_raw['lot_status']) { + return false; + } + // 过滤抽奖范围 self::$filter_type = empty(self::$filter_type) ? explode(',', getenv('ANCHOR_TYPE')) : self::$filter_type; - if (!in_array((string)$de_raw['data']['require_type'], self::$filter_type)) { + if (!in_array((string)$de_raw['require_type'], self::$filter_type)) { return false; } - + // 去重 + if (self::toRepeatLid($de_raw['id'])) { + return false; + } + // 推入列表 $data = [ - 'room_id' => $de_raw['data']['room_id'], - 'raffle_id' => $de_raw['data']['id'], - 'prize' => $de_raw['data']['award_name'], - 'wait' => strtotime(date("Y-m-d H:i:s")) + 'room_id' => $room_id, + 'raffle_id' => $de_raw['id'], + 'raffle_name' => $de_raw['award_name'], + 'wait' => time() ]; - if (static::toRepeatLid($data['raffle_id'])) { - return false; - } - Statistics::addPushList(static::ACTIVE_TITLE); - array_push(static::$wait_list, $data); + Statistics::addPushList(self::ACTIVE_TITLE); + array_push(self::$wait_list, $data); return true; } @@ -84,11 +91,10 @@ class Anchor extends BaseRaffle $de_raw = json_decode($raw, true); if (isset($de_raw['code']) && $de_raw['code'] == 0) { - print_r($de_raw); - Statistics::addSuccessList(static::ACTIVE_TITLE); - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$data['prize']}"); + Statistics::addSuccessList(self::ACTIVE_TITLE); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$data['raffle_name']}"); } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$de_raw['message']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['message']}"); } return true; } diff --git a/src/plugin/AwardRecord.php b/src/plugin/AwardRecord.php new file mode 100644 index 0000000..be60103 --- /dev/null +++ b/src/plugin/AwardRecord.php @@ -0,0 +1,135 @@ + time()) { + return; + } + if (self::$anchor_lock < time()) { + self::anchorAward(); + } + if (self::$raffle_lock < time()) { + self::raffleAward(); + } + // if (self::$gift_lock < time()) { + // self::giftAward(); + // } + self::setLock(5 * 60); + } + + + /** + * @use 获取天选时刻中奖纪录 + */ + private static function anchorAward() + { + $payload = [ + 'page' => '1', + ]; + $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v1/Anchor/AwardRecord'; + $raw = Curl::get($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + // 防止异常 + if (!isset($de_raw['data']) || !isset($de_raw['data']['list'])) { + Log::warning("获取天选时刻获奖记录错误: " . json_encode($de_raw, JSON_FORCE_OBJECT)); + self::$anchor_lock = time() + 1 * 60 * 60; + return; + } + foreach ($de_raw['data']['list'] as $anchor) { + $win_time = strtotime($anchor['end_time']); //礼物时间 + $day = ceil((time() - $win_time) / 86400); //60s*60min*24h + // 去重 + if (in_array($anchor['id'], self::$anchor_list)) { + continue; + } + // 范围 + if ($day <= 2) { + $info = $anchor['award_name'] . 'x' . $anchor['award_num']; + Log::notice("天选时刻于" . $anchor['end_time'] . "获奖: {$info} ,请留意查看..."); + Notice::push('anchor', $info); + } + array_push(self::$anchor_list, $anchor['id']); + } + self::$anchor_lock = time() + 6 * 60 * 60; + } + + + /** + * @use 获取实物抽奖中奖纪录 + */ + private static function raffleAward() + { + $payload = [ + 'page' => '1', + 'month' => '', + ]; + $url = 'https://api.live.bilibili.com/lottery/v1/award/award_list'; + $raw = Curl::get($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + + // 防止异常 + if (!isset($de_raw['data']) || !isset($de_raw['data']['list']) || $de_raw['code']) { + Log::warning("获取实物奖励获奖记录错误: " . $de_raw['msg']); + self::$raffle_lock = time() + 1 * 60 * 60; + return; + } + foreach ($de_raw['data']['list'] as $raffle) { + $win_time = strtotime($raffle['create_time']); //礼物时间 + $day = ceil((time() - $win_time) / 86400); //60s*60min*24h + // 去重 + if (in_array($raffle['id'], self::$raffle_list)) { + continue; + } + // 范围 + if ($day <= 2 && empty($raffle['update_time'])) { + $info = $raffle['gift_name'] . 'x' . $raffle['gift_num']; + Log::notice("实物奖励于" . $raffle['end_time'] . "获奖: {$info} ,请留意查看..."); + Notice::push('raffle', $info); + } + array_push(self::$raffle_list, $raffle['id']); + } + self::$raffle_lock = time() + 6 * 60 * 60; + } + + + /** + * @use 获取活动礼物中奖纪录 + */ + private static function giftAward() + { + $payload = [ + 'type' => 'type', + 'raffleId' => 'raffle_id' + ]; + // Web V3 Notice + $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v3/smalltv/Notice'; + // 请求 && 解码 + $raw = Curl::get($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + } +} \ No newline at end of file diff --git a/src/Danmu.php b/src/plugin/Barrage.php similarity index 83% rename from src/Danmu.php rename to src/plugin/Barrage.php index c6172d1..e838858 100644 --- a/src/Danmu.php +++ b/src/plugin/Barrage.php @@ -8,15 +8,19 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; -class Danmu +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; + +class Barrage { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time() || getenv('USE_DANMU') == 'false') { + if (self::getLock() > time() || getenv('USE_DANMU') == 'false') { return; } $room_id = empty(getenv('DANMU_ROOMID')) ? Live::getUserRecommend() : Live::getRealRoomID(getenv('DANMU_ROOMID')); @@ -28,14 +32,18 @@ class Danmu ]; if (self::privateSendMsg($info)) { - self::$lock = time() + 3600; + self::setLock(3600); return; } - self::$lock = time() + 30; + self::setLock(30); } - // 获取随机弹幕 + + /** + * @use 获取随机弹幕 + * @return \Exception|false|mixed|string + */ private static function getMsgInfo() { /** @@ -80,7 +88,11 @@ class Danmu } - //发送弹幕通用模块 + /** + * @use 弹幕通用模块 + * @param $info + * @return bool|string + */ private static function sendMsg($info) { $user_info = User::parseCookies(); @@ -101,24 +113,26 @@ class Danmu return Curl::post('https://api.live.bilibili.com/msg/send', Sign::api($payload)); } - //使用发送弹幕模块 + /** + * @use 发送弹幕模块 + * @param $info + * @return bool + */ private static function privateSendMsg($info) { //TODO 暂时性功能 有需求就修改 $raw = self::sendMsg($info); $de_raw = json_decode($raw, true); - if ($de_raw['code'] == 1001) { Log::warning($de_raw['msg']); return false; } - if (!$de_raw['code']) { - Log::info('弹幕发送成功!'); + Log::info('活跃弹幕发送成功!'); return true; } + Log::error("活跃弹幕发送失败!, {$de_raw['msg']}"); - Log::error("弹幕发送失败, {$de_raw['msg']}"); return false; } } \ No newline at end of file diff --git a/src/BaseRaffle.php b/src/plugin/BaseRaffle.php similarity index 65% rename from src/BaseRaffle.php rename to src/plugin/BaseRaffle.php index eb2b92c..5867548 100644 --- a/src/BaseRaffle.php +++ b/src/plugin/BaseRaffle.php @@ -9,16 +9,16 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; abstract class BaseRaffle { const ACTIVE_TITLE = ''; const ACTIVE_SWITCH = ''; - public static $lock; - public static $rw_lock; - protected static $wait_list; protected static $finish_list; protected static $all_list; @@ -28,29 +28,34 @@ abstract class BaseRaffle if (getenv(static::ACTIVE_SWITCH) == 'false') { return; } - if (static::$lock > time()) { + if (static::getLock() > time()) { return; } static::startLottery(); } /** - * 抽奖逻辑 + * @use 抽奖逻辑 * @return bool */ protected static function startLottery(): bool { - $max_num = mt_rand(10, 20); + if (count(static::$wait_list) == 0) { return false; } + if (count(static::$wait_list) < 100) { + $max_num = mt_rand(10, 20); + } else { + $max_num = mt_rand(45, 90); + } static::$wait_list = static::arrKeySort(static::$wait_list, 'wait'); for ($i = 0; $i <= $max_num; $i++) { $raffle = array_shift(static::$wait_list); if (is_null($raffle)) { break; } - if ($raffle['wait'] > strtotime(date("Y-m-d H:i:s"))) { + if ($raffle['wait'] > time()) { array_push(static::$wait_list, $raffle); continue; } @@ -61,13 +66,34 @@ abstract class BaseRaffle return true; } + /** + * @use 返回抽奖数据 + * @param int $room_id + * @return array + */ + protected static function check(int $room_id): array + { + $payload = [ + 'roomid' => $room_id + ]; + $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v1/lottery/getLotteryInfo'; + $raw = Curl::get($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + if (!isset($de_raw['data']) || $de_raw['code']) { + Log::error("获取抽奖数据错误,{$de_raw['message']}"); + return []; + } + return $de_raw; + } + /** - * 检查抽奖列表 - * @param $rid + * @use 解析抽奖数据 + * @param int $room_id + * @param array $data * @return bool */ - abstract protected static function check($rid): bool; + abstract protected static function parse(int $room_id, array $data): bool; /** @@ -100,12 +126,13 @@ abstract class BaseRaffle /** - * 重复检测 - * @param int $lid + * @use 去重检测 + * @param $lid * @return bool */ - protected static function toRepeatLid(int $lid): bool + protected static function toRepeatLid($lid): bool { + $lid = (int)$lid; if (in_array($lid, static::$all_list)) { return true; } @@ -113,12 +140,11 @@ abstract class BaseRaffle static::$all_list = []; } array_push(static::$all_list, $lid); - return false; } /** - * 数据推入队列 + * @use 数据推入队列 * @param array $data * @return bool */ @@ -131,9 +157,12 @@ abstract class BaseRaffle if (Live::fishingDetection($data['rid'])) { return false; } - static::check($data['rid']); + $raffles_info = static::check($data['rid']); + if (!empty($raffles_info)) { + static::parse($data['rid'], $raffles_info); + } $wait_num = count(static::$wait_list); - if ($wait_num > 2) { + if ($wait_num > 4 && ($wait_num % 2)) { Log::info("当前队列中共有 {$wait_num} 个" . static::ACTIVE_TITLE . "待抽奖"); } return true; diff --git a/src/Daily.php b/src/plugin/Daily.php similarity index 69% rename from src/Daily.php rename to src/plugin/Daily.php index f3bf116..945b4e0 100644 --- a/src/Daily.php +++ b/src/plugin/Daily.php @@ -8,23 +8,29 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Daily { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } self::dailyBag(); - - self::$lock = time() + 3600; + self::setLock( 8 * 60 * 60); } - protected static function dailyBag() + /** + * @use 领取每日包裹 + */ + private static function dailyBag() { $payload = []; $data = Curl::get('https://api.live.bilibili.com/gift/v2/live/receive_daily_bag', Sign::api($payload)); diff --git a/src/DataTreating.php b/src/plugin/DataTreating.php similarity index 72% rename from src/DataTreating.php rename to src/plugin/DataTreating.php index b0ece70..ac18afe 100644 --- a/src/DataTreating.php +++ b/src/plugin/DataTreating.php @@ -8,12 +8,17 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class DataTreating { + // TODO 独立分发 Push||Pull数据 /** - * @desc 抽奖分发 + * @use 抽奖分发 * @param array $data */ public static function distribute(array $data) @@ -28,19 +33,19 @@ class DataTreating switch ($data['raffle_type']) { case "storm": // 风暴 - Storm::pushToQueue($info); + StormRaffle::pushToQueue($info); break; case "raffle": // 礼物 - UnifyRaffle::pushToQueue($info); + GiftRaffle::pushToQueue($info); break; case "guard": // 舰长 - Guard::pushToQueue($info); + GuardRaffle::pushToQueue($info); break; case "small_tv": // 电视 - UnifyRaffle::pushToQueue($info); + GiftRaffle::pushToQueue($info); break; case 'pk': // 乱斗 @@ -48,7 +53,7 @@ class DataTreating break; case 'anchor': // 天选时刻 - Anchor::pushToQueue($info); + AnchorRaffle::pushToQueue($info); break; default: break; diff --git a/src/GiftHeart.php b/src/plugin/GiftHeart.php similarity index 77% rename from src/GiftHeart.php rename to src/plugin/GiftHeart.php index 35d3320..3b1f7e1 100644 --- a/src/GiftHeart.php +++ b/src/plugin/GiftHeart.php @@ -8,27 +8,34 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class GiftHeart { - public static $lock = 0; + use TimeLock; - // RUN public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } - if (self::giftheart()) { - self::$lock = time() + 60 * 60; + if (self::giftHeart()) { + self::setLock(60 * 60); return; } - self::$lock = time() + 5 * 60; + self::setLock(5 * 60); } - // GIFT HEART - protected static function giftheart(): bool + + /** + * @use 礼物心跳 + * @return bool + */ + private static function giftHeart(): bool { $payload = [ 'roomid' => getenv('ROOM_ID'), diff --git a/src/plugin/GiftRaffle.php b/src/plugin/GiftRaffle.php new file mode 100644 index 0000000..284f196 --- /dev/null +++ b/src/plugin/GiftRaffle.php @@ -0,0 +1,102 @@ + $room_id, + 'raffle_id' => $gift['raffleId'], + 'title' => $gift['title'], + 'type' => $gift['type'], + 'wait' => $gift['time_wait'] + time(), + ]; + Statistics::addPushList(self::ACTIVE_TITLE); + array_push(self::$wait_list, $data); + } + return true; + } + + + /** + * @use 请求抽奖 + * @param array $data + * @return bool + */ + protected static function lottery(array $data): bool + { + $user_info = User::parseCookies(); + $payload = [ + 'raffleId' => $data['raffle_id'], + 'roomid' => $data['room_id'], + 'type' => $data['type'], + 'csrf_token' => $user_info['token'], + 'csrf' => $user_info['token'], + 'visit_id' => null, + ]; + // V3接口 暂做保留处理 + // $url = 'https://api.live.bilibili.com/gift/v3/smalltv/join'; + // $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v5/smalltv/Join'; + $url = 'https://api.live.bilibili.com/gift/v4/smalltv/getAward'; + $raw = Curl::post($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + if (isset($de_raw['code']) && !$de_raw['code']) { + // 推送中奖信息 + if ($de_raw['data']['gift_name'] != '辣条' && $de_raw['data']['gift_name'] != '') { + $info = $de_raw['data']['gift_name'] . 'x' . $de_raw['data']['gift_num']; + Notice::push('gift', $info); + } + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['data']['gift_name']}x{$de_raw['data']['gift_num']}"); + Statistics::addSuccessList(self::ACTIVE_TITLE); + } else { + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + } + return true; + } +} diff --git a/src/plugin/GiftSend.php b/src/plugin/GiftSend.php new file mode 100644 index 0000000..4165766 --- /dev/null +++ b/src/plugin/GiftSend.php @@ -0,0 +1,275 @@ + time()) { + return; + } + if (!self::$uid) { + self::getUserInfo(); + } + // 方案一未通过使用方案2 + if (!self::procOne()) { + self::procTwo(); + } + self::$room_list = []; + self::$medal_list = []; + self::$tid = 0; + self::setLock(5 * 60); + } + + + /** + * @use 方案1 + */ + protected static function procOne() + { + if (!self::setTargetList()) { + return false; + } + self::getMedalList(); + foreach (self::$medal_list as $key => $val) { + $bag_list = self::fetchBagList(); + array_multisort(array_column($bag_list, "expire_at"), SORT_ASC, $bag_list); + if (getenv('FEED_FILL') == 'false') { + $bag_list = self::checkExpireGift($bag_list); + } + if (count($bag_list)) { + self::$tid = $key; + self::getRoomInfo(); + } else { + break; + } + foreach ($bag_list as $gift) { + // 是辣条、亿元 && 不是过期礼物 + if (!in_array($gift['gift_id'], [1, 6]) && getenv('FEED_FILL') != 'false') { + continue; + } + $amt = self::calcAmt($gift); + self::sendGift($gift, $amt); + $val -= $amt; + if (!$val) { + Log::notice("直播间 {$key} 亲密度 {$val} 送满啦~送满啦~"); + break; + } + } + } + if (!count(self::$medal_list)) { + return false; + } + return true; + } + + /** + * @use 方案2 + */ + protected static function procTwo() + { + $bag_list = self::fetchBagList(); + $expire_gift = self::checkExpireGift($bag_list); + if (count($expire_gift)) { + self::getRoomInfo(); + foreach ($expire_gift as $gift) { + self::sendGift($gift, $gift['gift_num']); + } + } + } + + /** + * @use 设置房间列表 + * @return bool + */ + protected static function setTargetList(): bool + { + $temp = empty(getenv('ROOM_LIST')) ? null : getenv('ROOM_LIST'); + if (is_null($temp)) return false; + self::$room_list = explode(',', getenv('ROOM_LIST')); + return true; + } + + + /** + * @use 获取背包列表 + * @return array + */ + protected static function fetchBagList(): array + { + $bag_list = []; + $payload = []; + $data = Curl::get('https://api.live.bilibili.com/gift/v2/gift/bag_list', Sign::api($payload)); + $data = json_decode($data, true); + if (isset($data['code']) && $data['code']) { + Log::warning('背包查看失败!', ['msg' => $data['message']]); + return $bag_list; + } + if (isset($data['data']['list'])) { + $bag_list = $data['data']['list']; + array_multisort(array_column($bag_list, "gift_id"), SORT_DESC, $bag_list); + foreach ($bag_list as $vo) { + // 去除永久礼物 + if ($vo['corner_mark'] == '永久') { + continue; + } + array_push($bag_list, $vo); + } + } + return $bag_list; + } + + + /** + * @use 查找过期礼物 + * @param array $bag_list + * @return array + */ + protected static function checkExpireGift(array $bag_list): array + { + $expire_gift_list = []; + foreach ($bag_list as $gift) { + if ($gift['expire_at'] >= time() && $gift['expire_at'] <= time() + 3600) { + array_push($expire_gift_list, $gift); + } + } + return $expire_gift_list; + } + + + /** + * @use 获取勋章列表(过滤无勋章或已满) + */ + protected static function getMedalList() + { + self::$medal_list = []; + Log::info('正在获取勋章列表...'); + $payload = []; + $data = Curl::get('https://api.live.bilibili.com/i/api/medal?page=1&pageSize=25', Sign::api($payload)); + $data = json_decode($data, true); + if (isset($data['code']) && $data['code']) { + Log::warning('获取勋章列表失败!', ['msg' => $data['message']]); + return; + } + Log::info('勋章列表获取成功!'); + if (isset($data['data']['fansMedalList'])) { + foreach ($data['data']['fansMedalList'] as $vo) { + if (in_array($vo['roomid'], self::$room_list) && ($vo['day_limit'] - $vo['today_feed'])) { + self::$medal_list[(string)$vo['roomid']] = ($vo['day_limit'] - $vo['today_feed']); +// $data = [ +// $vo['roomid'] => ($vo['day_limit'] - $vo['today_feed']) +// ]; +// array_push(self::$medal_list, $data); + } + } + } + } + + + /** + * @use 获取UID + */ + protected static function getUserInfo() + { + $payload = []; + $data = Curl::get('https://api.live.bilibili.com/xlive/web-ucenter/user/get_user_info', Sign::api($payload)); + $data = json_decode($data, true); + if (isset($data['code']) && $data['code']) { + Log::warning('获取帐号信息失败!', ['msg' => $data['message']]); + Log::warning('清空礼物功能禁用!'); + self::$lock = time() + 100000000; + return; + } + self::$uid = $data['data']['uid']; + } + + /** + * @use 获取直播间信息 + */ + protected static function getRoomInfo() + { + Log::info('正在生成直播间信息...'); + $payload = [ + 'id' => empty(self::$tid) ? getenv('ROOM_ID') : self::$tid, + ]; + $data = Curl::get('https://api.live.bilibili.com/room/v1/Room/room_init', Sign::api($payload)); + $data = json_decode($data, true); + if (isset($data['code']) && $data['code']) { + Log::warning('获取主播房间号失败!', ['msg' => $data['message']]); + Log::warning('清空礼物功能禁用!'); + self::$lock = time() + 100000000; + return; + } + Log::info('直播间信息生成完毕!'); + self::$r_uid = (string)$data['data']['uid']; + self::$room_id = (string)$data['data']['room_id']; + } + + + /** + * @use 计算赠送数量 + * @param array $gift + * @return int + */ + protected static function calcAmt(array $gift): int + { + $amt = $gift['gift_num']; + if ($gift['gift_id'] == 1) { + $amt = (self::$medal_list[self::$room_id] > $gift['gift_num']) ? $gift['gift_num'] : self::$medal_list[self::$room_id]; + } + if ($gift['gift_id'] == 6) { + $amt = (floor(self::$medal_list[self::$room_id] / 10) > $gift['gift_num']) ? $gift['gift_num'] : floor(self::$medal_list[self::$room_id] / 10); + } + return $amt; + } + + + /** + * @use 赠送礼物 + * @param array $value + * @param int $amt + */ + protected static function sendGift(array $value, int $amt) + { + $payload = [ + 'coin_type' => 'silver', + 'gift_id' => $value['gift_id'], + 'ruid' => self::$r_uid, + 'uid' => self::$uid, + 'biz_id' => self::$room_id, + 'gift_num' => $amt, + 'data_source_id' => '', + 'data_behavior_id' => '', + 'bag_id' => $value['bag_id'] + ]; + $data = Curl::post('https://api.live.bilibili.com/gift/v2/live/bag_send', Sign::api($payload)); + $data = json_decode($data, true); + if (isset($data['code']) && $data['code']) { + Log::warning('送礼失败!', ['msg' => $data['message']]); + } else { + Log::notice("成功向 {$payload['biz_id']} 投喂了 {$amt} 个{$value['gift_name']}"); + } + } +} diff --git a/src/GroupSignIn.php b/src/plugin/GroupSignIn.php similarity index 81% rename from src/GroupSignIn.php rename to src/plugin/GroupSignIn.php index b7f4512..5452ba0 100644 --- a/src/GroupSignIn.php +++ b/src/plugin/GroupSignIn.php @@ -8,22 +8,25 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class GroupSignIn { - public static $lock = 0; + use TimeLock; - // RUN public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } $groups = self::getGroupList(); if (empty($groups)) { - self::$lock = time() + 24 * 60 * 60; + self::setLock(24 * 60 * 60); return; } @@ -31,10 +34,14 @@ class GroupSignIn self::signInGroup($group); } - self::$lock = time() + 8 * 60 * 60; + self::setLock(8 * 60 * 60); } - //GROUP LIST + + /** + * @use 获取友爱社列表 + * @return array + */ protected static function getGroupList(): array { $payload = []; @@ -48,7 +55,12 @@ class GroupSignIn return $de_raw['data']['list']; } - //SIGN IN + + /** + * @use 签到 + * @param array $groupInfo + * @return bool + */ protected static function signInGroup(array $groupInfo): bool { $payload = [ diff --git a/src/plugin/GuardRaffle.php b/src/plugin/GuardRaffle.php new file mode 100644 index 0000000..ca084d1 --- /dev/null +++ b/src/plugin/GuardRaffle.php @@ -0,0 +1,113 @@ + $room_id, + 'raffle_id' => $guard['id'], + 'raffle_name' => $raffle_name, + 'wait' => time() + ]; + Statistics::addPushList(self::ACTIVE_TITLE); + array_push(self::$wait_list, $data); + } + return true; + } + + + /** + * @use 请求抽奖 + * @param array $data + * @return bool + */ + protected static function lottery(array $data): bool + { + $user_info = User::parseCookies(); + $payload = [ + 'id' => $data['raffle_id'], + 'roomid' => $data['room_id'], + "type" => "guard", + 'csrf_token' => $user_info['token'], + 'csrf' => $user_info['token'] + ]; + $url = 'https://api.live.bilibili.com/lottery/v2/lottery/join'; + $raw = Curl::post($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + + if (isset($de_raw['code']) && $de_raw['code'] == 0) { + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['data']['message']}"); + Statistics::addSuccessList(self::ACTIVE_TITLE); + } else { + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['msg']}"); + } + return true; + } + + +} \ No newline at end of file diff --git a/src/Heart.php b/src/plugin/Heart.php similarity index 81% rename from src/Heart.php rename to src/plugin/Heart.php index 889cc08..80092cc 100644 --- a/src/Heart.php +++ b/src/plugin/Heart.php @@ -8,24 +8,31 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Heart { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } self::pc(); self::mobile(); - self::$lock = time() + 300; + self::setLock(5 * 60); } + /** + * @use pc端心跳 + */ protected static function pc() { $payload = [ @@ -41,6 +48,9 @@ class Heart } } + /** + * @use 手机端心跳 + */ protected static function mobile() { $payload = [ diff --git a/src/plugin/Live.php b/src/plugin/Live.php new file mode 100644 index 0000000..8a806c3 --- /dev/null +++ b/src/plugin/Live.php @@ -0,0 +1,173 @@ + $area_id, + 'room_id' => 23058 + ]; + } else { + $area_info = [ + 'area_id' => $area_id, + 'room_id' => $de_raw['data'][0]['roomid'] + ]; + } + return $area_info; + } + + + /** + * @use 获取随机直播房间号 + * @return int + * @throws \Exception + */ + public static function getUserRecommend() + { + $raw = Curl::get('https://api.live.bilibili.com/room/v1/Area/getListByAreaID?areaId=0&sort=online&pageSize=30&page=1'); + $de_raw = json_decode($raw, true); + if ($de_raw['code'] != '0') { + return 23058; + } + return $de_raw['data'][random_int(1, 29)]['roomid']; + } + + + /** + * @use 获取直播房间号 + * @param $room_id + * @return bool + */ + public static function getRealRoomID($room_id) + { + $raw = Curl::get('https://api.live.bilibili.com/room/v1/Room/room_init?id=' . $room_id); + $de_raw = json_decode($raw, true); + if ($de_raw['code']) { + Log::warning($room_id . ' : ' . $de_raw['msg']); + return false; + } + if ($de_raw['data']['is_hidden']) { + return false; + } + if ($de_raw['data']['is_locked']) { + return false; + } + if ($de_raw['data']['encrypted']) { + return false; + } + return $de_raw['data']['room_id']; + + } + + + /** + * @use 钓鱼检测 + * @param $room_id + * @return bool + */ + public static function fishingDetection($room_id): bool + { + if (self::getRealRoomID($room_id)) { + return false; + } + return true; + } + + + /** + * @use 随机延迟 + * @param int $min + * @param int $max + * @return bool + */ + public static function randDelay($min = 0, $max = 3): bool + { + $rand = $min + mt_rand() / mt_getrandmax() * ($max - $min); + sleep($rand); + return true; + } + + /** + * @use 访问直播间 + * @param $room_id + * @return bool + */ + public static function goToRoom($room_id): bool + { + $payload = [ + 'room_id' => $room_id, + ]; + // Log::info('进入直播间[' . $room_id . ']抽奖!'); + Curl::post('https://api.live.bilibili.com/room/v1/Room/room_entry_action', Sign::api($payload)); + return true; + } + + + /** + * @use 获取毫秒 + * @return float + */ + public static function getMillisecond() + { + list($t1, $t2) = explode(' ', microtime()); + return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); + } + +} \ No newline at end of file diff --git a/src/Login.php b/src/plugin/Login.php similarity index 84% rename from src/Login.php rename to src/plugin/Login.php index 12d470a..99855dd 100644 --- a/src/Login.php +++ b/src/plugin/Login.php @@ -7,21 +7,29 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; +use BiliHelper\Core\Config; + class Login { - public static $lock = 0; + use TimeLock; public static function run() { + if (self::getLock()) { + self::check(); + return; + } Log::info('开始启动程序...'); if (getenv('ACCESS_TOKEN') == "") { Log::info('令牌载入中...'); self::login(); } - // 重载配置文件 - Index::$dotenv->overload(); Log::info('正在检查令牌合法性...'); if (!self::info()) { @@ -32,15 +40,19 @@ class Login self::login(); } } - self::$lock = time() + 3600; + self::setLock(3600); } + /** + * @use 检查令牌 + * @return bool + */ public static function check() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return true; } - self::$lock = time() + 7200; + self::setLock(7200); if (!self::info()) { Log::warning('令牌即将过期'); Log::info('申请更换令牌中...'); @@ -53,6 +65,10 @@ class Login return true; } + /** + * @use 获取令牌信息 + * @return bool + */ protected static function info() { $access_token = getenv('ACCESS_TOKEN'); @@ -69,6 +85,10 @@ class Login return $data['data']['expires_in'] > 14400; } + /** + * @use 刷新token + * @return bool + */ public static function refresh() { $access_token = getenv('ACCESS_TOKEN'); @@ -85,14 +105,19 @@ class Login } Log::info('令牌生成完毕!'); $access_token = $data['data']['access_token']; - File::writeNewEnvironmentFileWith('ACCESS_TOKEN', $access_token); + Config::put('ACCESS_TOKEN', $access_token); Log::info(' > access token: ' . $access_token); $refresh_token = $data['data']['refresh_token']; - File::writeNewEnvironmentFileWith('REFRESH_TOKEN', $refresh_token); + Config::put('REFRESH_TOKEN', $refresh_token); Log::info(' > refresh token: ' . $refresh_token); return true; } + /** + * @use 普通登陆 + * @param string $captcha + * @param array $headers + */ protected static function login($captcha = '', $headers = []) { $user = getenv('APP_USER'); @@ -129,7 +154,7 @@ class Login $data = Curl::post('https://passport.bilibili.com/api/v2/oauth2/login', Sign::api($payload), $headers); $data = json_decode($data, true); if (isset($data['code']) && $data['code'] == -105) { - $captcha_data = static::loginWithCaptcha(); + $captcha_data = self::loginWithCaptcha(); $captcha = $captcha_data['captcha']; $headers = $captcha_data['headers']; continue; @@ -148,16 +173,20 @@ class Login self::saveCookie($data); Log::info('令牌获取成功!'); $access_token = $data['data']['token_info']['access_token']; - File::writeNewEnvironmentFileWith('ACCESS_TOKEN', $access_token); + Config::put('ACCESS_TOKEN', $access_token); Log::info(' > access token: ' . $access_token); $refresh_token = $data['data']['token_info']['refresh_token']; - File::writeNewEnvironmentFileWith('REFRESH_TOKEN', $refresh_token); + Config::put('REFRESH_TOKEN', $refresh_token); Log::info(' > refresh token: ' . $refresh_token); return; } + /** + * @use 验证码登陆 + * @return array + */ protected static function loginWithCaptcha() { Log::info('登录需要验证, 启动验证码登录!'); @@ -169,7 +198,7 @@ class Login ]; $data = Curl::other('https://passport.bilibili.com/captcha', null, $headers); $data = base64_encode($data); - $captcha = static::ocrCaptcha($data); + $captcha = self::ocrCaptcha($data); return [ 'captcha' => $captcha, 'headers' => $headers, @@ -177,6 +206,11 @@ class Login } + /** + * @use 识别验证码 + * @param $captcha_img + * @return mixed + */ private static function ocrCaptcha($captcha_img) { $payload = [ @@ -192,6 +226,10 @@ class Login return $de_raw['message']; } + /** + * @use 保存cookie + * @param $data + */ private static function saveCookie($data) { Log::info('COOKIE获取成功!'); @@ -201,7 +239,7 @@ class Login foreach ($cookies as $cookie) { $temp .= $cookie['name'] . '=' . $cookie['value'] . ';'; } - File::writeNewEnvironmentFileWith('COOKIE', $temp); + Config::put('COOKIE', $temp); Log::info(' > auth cookie: ' . $temp); return; } diff --git a/src/MasterSite.php b/src/plugin/MasterSite.php similarity index 91% rename from src/MasterSite.php rename to src/plugin/MasterSite.php index 88ad3dd..3ccd5c4 100644 --- a/src/MasterSite.php +++ b/src/plugin/MasterSite.php @@ -8,25 +8,34 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class MasterSite { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time() || getenv('USE_MASTER_SITE') == 'false') { + if (self::getLock() > time() || getenv('USE_MASTER_SITE') == 'false') { return; } if (self::watchAid() && self::shareAid() && self::coinAdd()) { - self::$lock = time() + 24 * 60 * 60; + self::setLock( 24 * 60 * 60); return; } - self::$lock = time() + 3600; + self::setLock( 3600); } - // 投币 + + /** + * @use 投币 + * @param $aid + * @return bool + */ private static function reward($aid): bool { $user_info = User::parseCookies(); @@ -54,7 +63,11 @@ class MasterSite } } - // 投币日志 + + /** + * @use 投币日志 + * @return int + */ protected static function coinLog(): int { $url = "https://api.bilibili.com/x/member/web/coin/log"; @@ -87,7 +100,12 @@ class MasterSite return $coins; } - // 投币操作 + + /** + * @use 投币视频 + * @return bool + * @throws \Exception + */ protected static function coinAdd(): bool { switch (getenv('USE_ADD_COIN')) { @@ -123,7 +141,11 @@ class MasterSite return true; } - // 获取随机AID + + /** + * @use 获取随机AID + * @return string + */ private static function getRandomAid(): string { do { @@ -139,7 +161,13 @@ class MasterSite return (string)$aid; } - // 日榜AID + + /** + * @use 获取日榜AID + * @param $num + * @return array + * @throws \Exception + */ private static function getDayRankingAids($num): array { // day: 日榜1 三榜3 周榜7 月榜30 @@ -166,7 +194,11 @@ class MasterSite return $aids; } - // 分享视频 + + /** + * @use 分享视频 + * @return bool + */ private static function shareAid(): bool { # aid = 稿件av号 @@ -195,7 +227,11 @@ class MasterSite } } - // 观看视频 + + /** + * @use 观看视频 + * @return bool + */ private static function watchAid(): bool { $url = "https://api.bilibili.com/x/report/click/h5"; @@ -259,7 +295,11 @@ class MasterSite return false; } - // 解析AID到CID + + /** + * @use 解析AID到CID + * @return array + */ private static function parseAid(): array { while (true) { diff --git a/src/MaterialObject.php b/src/plugin/MaterialObject.php similarity index 94% rename from src/MaterialObject.php rename to src/plugin/MaterialObject.php index 412236d..400d372 100644 --- a/src/MaterialObject.php +++ b/src/plugin/MaterialObject.php @@ -8,32 +8,33 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class MaterialObject { - // 时间锁 - public static $lock = 0; - // 丢弃列表 + use TimeLock; + private static $discard_aid_list = []; - // 起始 和 结束 private static $start_aid = 0; private static $end_aid = 0; - // RUN public static function run() { if (getenv('USE_MO') == 'false') { return; } - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } // 计算AID TODO 待优化 self::calculateAid(150, 550); self::drawLottery(); - self::$lock = time() + random_int(5, 10) * 60; + self::setLock(random_int(5, 10) * 60); } /** @@ -44,7 +45,7 @@ class MaterialObject { $block_key_list = ['测试', '加密', 'test', 'TEST', '钓鱼', '炸鱼', '调试']; $flag = 5; - + for ($i = self::$start_aid; $i < self::$end_aid; $i++) { if (!$flag) { break; @@ -125,11 +126,13 @@ class MaterialObject return true; } + /** - * @use 计算 开始结束的AID + * @use 计算开始结束的AID * @param $min * @param $max * @return bool + * @throws \Exception */ private static function calculateAid($min, $max): bool { diff --git a/src/plugin/Notice.php b/src/plugin/Notice.php new file mode 100644 index 0000000..9a6be44 --- /dev/null +++ b/src/plugin/Notice.php @@ -0,0 +1,120 @@ + '天选时刻获奖记录', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 在天选时刻中获得: ' . self::$result, + ]; + break; + case 'raffle': + $info = [ + 'title' => '实物奖励获奖纪录', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 在实物奖励中获得: ' . self::$result, + ]; + break; + case 'gift': + $info = [ + 'title' => '活动礼物获奖纪录', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 在活动礼物中获得: ' . self::$result, + ]; + break; + case 'storm': + $info = [ + 'title' => '节奏风暴获奖纪录', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 在节奏风暴中获得: ' . self::$result, + ]; + break; + case 'cookieRefresh': + $info = [ + 'title' => 'Cookie刷新', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 刷新Cookie: ' . self::$result, + ]; + break; + case 'todaySign': + $info = [ + 'title' => '每日签到', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 签到: ' . self::$result, + ]; + break; + case 'banned': + $info = [ + 'title' => '账号封禁', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 账号被封禁: 程序开始睡眠,凌晨自动唤醒,距离唤醒还有' . self::$result . '小时', + ]; + break; + default: + $info = [ + 'title' => '推送消息异常记录', + 'content' => '[' . $now_time . ']' . ' 用户: ' . self::$uname . ' 推送消息key错误' . self::$type . self::$result, + ]; + break; + } + self::scSend($info); + + return true; + } + + + /** + * @use ServerChan发送信息 + * @param array $info + */ + private static function scSend(array $info) + { + $url = "https://sc.ftqq.com/" . self::$sckey . ".send?text=" . urlencode($info['title']) . "&desp=" . urlencode($info['content']); + $data = Curl::singleRequest('get', $url); + if (is_null($data)) { + Log::warning('Server酱推送信息失败,请检查!'); + }; + } +} \ No newline at end of file diff --git a/src/PkRaffle.php b/src/plugin/PkRaffle.php similarity index 62% rename from src/PkRaffle.php rename to src/plugin/PkRaffle.php index c95549d..44d87e2 100644 --- a/src/PkRaffle.php +++ b/src/plugin/PkRaffle.php @@ -8,52 +8,60 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; + class PkRaffle extends BaseRaffle { const ACTIVE_TITLE = '大乱斗'; const ACTIVE_SWITCH = 'USE_PK'; - public static $lock = 0; - public static $rw_lock = 0; + use TimeLock; protected static $wait_list = []; protected static $finish_list = []; protected static $all_list = []; + /** - * 检查抽奖列表 - * @param $rid + * @use 解析数据 + * @param int $room_id + * @param array $data * @return bool */ - protected static function check($rid): bool + protected static function parse(int $room_id, array $data): bool { - $payload = [ - 'roomid' => $rid - ]; - $url = 'https://api.live.bilibili.com/xlive/lottery-interface/v1/pk/check'; - $raw = Curl::get($url, Sign::api($payload)); - $de_raw = json_decode($raw, true); - - // 计数 && 跳出 - $total = count($de_raw['data']); - if (!$total) { + // 防止异常 + if (!array_key_exists('pk', $data['data'])) { + return false; + } + $de_raw = $data['data']['pk']; + if (empty($de_raw)) { return false; } - for ($i = 0; $i < $total; $i++) { - $data = [ - 'raffle_id' => $de_raw['data'][$i]['pk_id'], - 'title' => $de_raw['data'][$i]['title'], - 'room_id' => $de_raw['data'][$i]['room_id'], - 'wait' => strtotime(date("Y-m-d H:i:s")) - ]; - if (static::toRepeatLid($data['raffle_id'])) { + foreach ($de_raw as $pk) { + // 无效抽奖 + if ($pk['status'] != 1) { continue; } - Statistics::addPushList(static::ACTIVE_TITLE); - array_push(static::$wait_list, $data); + // 去重 + if (self::toRepeatLid($pk['id'])) { + continue; + } + // 推入列表 + $data = [ + 'room_id' => $room_id, + 'raffle_id' => $pk['id'], + 'raffle_name' => '大乱斗', + 'wait' => time() + ]; + Statistics::addPushList(self::ACTIVE_TITLE); + array_push(self::$wait_list, $data); } return true; } @@ -83,10 +91,10 @@ class PkRaffle extends BaseRaffle * {"code":-403,"data":null,"message":"访问被拒绝","msg":"访问被拒绝"} */ if (isset($de_raw['code']) && $de_raw['code'] == 0) { - Statistics::addSuccessList(static::ACTIVE_TITLE); - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$de_raw['data']['award_text']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['data']['award_text']}"); + Statistics::addSuccessList(self::ACTIVE_TITLE); } else { - Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . static::ACTIVE_TITLE . ": {$de_raw['message']}"); + Log::notice("房间 {$data['room_id']} 编号 {$data['raffle_id']} " . self::ACTIVE_TITLE . ": {$de_raw['message']}"); } return true; } diff --git a/src/Sign.php b/src/plugin/Sign.php similarity index 85% rename from src/Sign.php rename to src/plugin/Sign.php index 6ffc65e..af6f804 100644 --- a/src/Sign.php +++ b/src/plugin/Sign.php @@ -8,10 +8,19 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Sign { + /** + * @use 计算sign + * @param $payload + * @return array + */ public static function api($payload) { # iOS 6680 diff --git a/src/Silver.php b/src/plugin/Silver.php similarity index 74% rename from src/Silver.php rename to src/plugin/Silver.php index 8946a59..979a0e5 100644 --- a/src/Silver.php +++ b/src/plugin/Silver.php @@ -8,61 +8,34 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Silver { - public static $lock = 0; + use TimeLock; protected static $task = []; public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } - if (!empty(self::$task)) { - self::pushTask(); + if (empty(self::$task)) { + self::getSilverBox(); } else { - self::pullTask(); + self::openSilverBox(); } } - protected static function pushTask() - { - $payload = [ - 'time_end' => self::$task['time_end'], - 'time_start' => self::$task['time_start'] - ]; - $data = Curl::get('https://api.live.bilibili.com/mobile/freeSilverAward', Sign::api($payload)); - $data = json_decode($data, true); - - if ($data['code'] == -800) { - self::$lock = time() + 12 * 60 * 60; - Log::warning("领取宝箱失败,{$data['message']}!"); - return; - } - - if ($data['code'] == -903) { - Log::warning("领取宝箱失败,{$data['message']}!"); - self::$task = []; - self::$lock = time() + 60; - return; - } - - if (isset($data['code']) && $data['code']) { - Log::warning("领取宝箱失败,{$data['message']}!"); - self::$lock = time() + 60; - return; - } - - Log::notice("领取宝箱成功,Silver: {$data['data']['silver']}(+{$data['data']['awardSilver']})"); - - self::$task = []; - self::$lock = time() + 10; - } - - protected static function pullTask() + /** + * @use 获取宝箱 + */ + private static function getSilverBox() { $payload = []; $data = Curl::get('https://api.live.bilibili.com/lottery/v1/SilverBox/getCurrentTask', Sign::api($payload)); @@ -70,7 +43,7 @@ class Silver if (isset($data['code']) && $data['code'] == -10017) { Log::notice($data['message']); - self::$lock = time() + 24 * 60 * 60; + self::setLock( 24 * 60 * 60); return; } @@ -86,7 +59,44 @@ class Silver 'time_start' => $data['data']['time_start'], 'time_end' => $data['data']['time_end'], ]; + self::setLock( $data['data']['minute'] * 60 + 5); + } - self::$lock = time() + $data['data']['minute'] * 60 + 5; + + /** + * @use 开启宝箱 + */ + private static function openSilverBox() + { + $payload = [ + 'time_end' => self::$task['time_end'], + 'time_start' => self::$task['time_start'] + ]; + $data = Curl::get('https://api.live.bilibili.com/mobile/freeSilverAward', Sign::api($payload)); + $data = json_decode($data, true); + + if ($data['code'] == -800) { + self::setLock( 12 * 60 * 60); + Log::warning("领取宝箱失败,{$data['message']}!"); + return; + } + + if ($data['code'] == -903) { + Log::warning("领取宝箱失败,{$data['message']}!"); + self::$task = []; + self::setLock( 60); + return; + } + + if (isset($data['code']) && $data['code']) { + Log::warning("领取宝箱失败,{$data['message']}!"); + self::setLock( 60); + return; + } + + Log::notice("领取宝箱成功,Silver: {$data['data']['silver']}(+{$data['data']['awardSilver']})"); + + self::$task = []; + self::setLock( 10); } } diff --git a/src/Silver2Coin.php b/src/plugin/Silver2Coin.php similarity index 75% rename from src/Silver2Coin.php rename to src/plugin/Silver2Coin.php index f336c2f..8a8a4d4 100644 --- a/src/Silver2Coin.php +++ b/src/plugin/Silver2Coin.php @@ -8,26 +8,33 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Silver2Coin { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time() || getenv('USE_SILVER2COIN') == 'false') { + if (self::getLock() > time() || getenv('USE_SILVER2COIN') == 'false') { return; } if (self::appSilver2coin() && self::pcSilver2coin()) { - self::$lock = time() + 24 * 60 * 60; + self::setLock(24 * 60 * 60); return; } - self::$lock = time() + 3600; + self::setLock(3600); } - // APP API + /** + * @use app兑换 + * @return bool + */ protected static function appSilver2coin(): bool { sleep(1); @@ -46,14 +53,18 @@ class Silver2Coin return true; } - // PC API + + /** + * @use pc兑换 + * @return bool + */ protected static function pcSilver2coin(): bool { sleep(1); $payload = []; + $url = "https://api.live.bilibili.com/exchange/silver2coin"; $url = "https://api.live.bilibili.com/pay/v1/Exchange/silver2coin"; - $url1 = "https://api.live.bilibili.com/exchange/silver2coin"; - + $raw = Curl::get($url, Sign::api($payload)); $de_raw = json_decode($raw, true); if ($de_raw['code'] == -403) { diff --git a/src/plugin/Sleep.php b/src/plugin/Sleep.php new file mode 100644 index 0000000..cb7a5c4 --- /dev/null +++ b/src/plugin/Sleep.php @@ -0,0 +1,80 @@ + time()) { + return; + } + self::isPause(); + self::isRefuse(); + self::setLock(5 * 60); + } + + private static function isPause() + { + self::$sleep_section = empty(self::$filter_type) ? explode(',', getenv('SLEEP_SECTION')) : self::$sleep_section; + if (in_array(date('H'), self::$sleep_section)) { + $unlock_time = 60 * 60; + self::stopProc($unlock_time); + Log::warning('进入自定义休眠时间范围,暂停非必要任务,自动开启!'); + } + return; + } + + private static function isRefuse() + { + $payload = []; + $raw = Curl::get('https://api.live.bilibili.com/mobile/freeSilverAward', Sign::api($payload)); + $de_raw = json_decode($raw, true); + if ($de_raw['msg'] == '访问被拒绝') { + $unlock_time = strtotime(date("Y-m-d", strtotime("+1 day", time()))) - time(); + self::stopProc($unlock_time); + Log::warning('账号拒绝访问,暂停非必要任务,自动开启!'); + // 推送被ban信息 + Notice::push('banned', floor($unlock_time / 60 / 60)); + } + return; + } + + /** + * @use 停止运行 + * @param int $unlock_time + */ + private static function stopProc(int $unlock_time) + { + $unlock_time = $unlock_time + 1 * 60; + // 检测时间提前5分钟 + self::setLock($unlock_time - 5 * 60); + foreach (self::$fillable as $classname) { + Log::info("插件 {$classname} 白名单,保持当前状态继续"); + } + foreach (self::$guarded as $classname) { + Log::info("插件 {$classname} 黑名单,锁定状态将于" . date("Y-m-d H:i", time() + $unlock_time) . "解除"); + call_user_func(array(__NAMESPACE__ . '\\' . $classname, 'setLock'), $unlock_time); + } + } +} \ No newline at end of file diff --git a/src/Statistics.php b/src/plugin/Statistics.php similarity index 74% rename from src/Statistics.php rename to src/plugin/Statistics.php index ef8b4b4..ce3dd20 100644 --- a/src/Statistics.php +++ b/src/plugin/Statistics.php @@ -8,32 +8,37 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Util\TimeLock; class Statistics { - public static $lock = 0; + use TimeLock; - // 推送 参加 成功 private static $push_list = []; private static $join_list = []; private static $success_list = []; - // 日志 public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } - self::getStormResult(); + self::outputResult(); - self::$lock = time() + 5 * 60; + self::setLock(5 * 60); } - // 添加推送 + /** + * @use 添加推送 + * @param string $key + * @return bool + */ public static function addPushList(string $key): bool { // 初始化三个必要值 @@ -47,22 +52,36 @@ class Statistics return true; } - // 添加参与 + + /** + * @use 添加参与 + * @param string $key + * @return bool + */ public static function addJoinList(string $key): bool { array_push(self::$join_list[$key], 1); return true; } - // 添加成功 + + /** + * @use 添加成功 + * @param string $key + * @return bool + */ public static function addSuccessList(string $key): bool { array_push(self::$success_list[$key], 1); return true; } - // 获取结果 - private static function getStormResult(): bool + + /** + * @use 输出结果 + * @return bool + */ + private static function outputResult(): bool { if (empty(self::$push_list)) { return false; diff --git a/src/plugin/StormRaffle.php b/src/plugin/StormRaffle.php new file mode 100644 index 0000000..9c25b4f --- /dev/null +++ b/src/plugin/StormRaffle.php @@ -0,0 +1,141 @@ + $room_id, + 'raffle_id' => $de_raw['id'], + 'raffle_name' => '节奏风暴', + 'wait' => time() + ]; + Statistics::addPushList(self::ACTIVE_TITLE); + array_push(self::$wait_list, $data); + return true; + } + + + /** + * 格式化日志输出 + * @param $id + * @param $num + * @param $info + * @return string + */ + private static function formatInfo($id, $num, $info): string + { + return "风暴 {$id} 请求 {$num} 状态 {$info}"; + } + + + /** + * @use 请求抽奖 + * @param array $data + * @return bool + * @throws \Exception + */ + protected static function lottery(array $data): bool + { + self::$attempt = getenv('STORM_ATTEMPT') !== "" ? explode(',', getenv('STORM_ATTEMPT')) : [30, 50]; + $num = random_int((int)self::$attempt[0], (int)self::$attempt[1]); + $user_info = User::parseCookies(); + $payload = [ + 'id' => $data['raffle_id'], + 'roomid' => $data['room_id'], + "color" => "16772431", + "captcha_token" => "", + "captcha_phrase" => "", + "token" => $user_info['token'], + "csrf_token" => $user_info['token'], + "visit_id" => "", + ]; + $url = 'https://api.live.bilibili.com/lottery/v1/Storm/join'; + for ($i = 1; $i < $num; $i++) { + $raw = Curl::post($url, Sign::api($payload)); + $de_raw = json_decode($raw, true); + if ($de_raw['code'] == 429 || $de_raw['code'] == -429) { + Log::notice(self::formatInfo($data['raffle_id'], $num, '节奏风暴未实名或异常验证码')); + break; + } + if (isset($de_raw['data']) && empty($de_raw['data'])) { + Log::notice(self::formatInfo($data['raffle_id'], $num, '节奏风暴在小黑屋')); + break; + } + if ($de_raw['code'] == 0) { + Statistics::addSuccessList(self::ACTIVE_TITLE); + Log::notice(self::formatInfo($data['raffle_id'], $num, $de_raw['data']['mobile_content'])); + break; + } + if ($de_raw['msg'] == '节奏风暴不存在') { + Log::notice(self::formatInfo($data['raffle_id'], $num, '节奏风暴已结束')); + break; + } + if ($de_raw['msg'] == '已经领取奖励') { + Log::notice(self::formatInfo($data['raffle_id'], $num, '节奏风暴已经领取')); + break; + } + if ($de_raw['msg'] == '你错过了奖励,下次要更快一点哦~') { + continue; + } + Log::notice(self::formatInfo($data['raffle_id'], $num, $de_raw['msg'])); + continue; + } + return true; + } +} diff --git a/src/Task.php b/src/plugin/Task.php similarity index 80% rename from src/Task.php rename to src/plugin/Task.php index 39cf86f..be40306 100644 --- a/src/Task.php +++ b/src/plugin/Task.php @@ -8,22 +8,23 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; class Task { - public static $lock = 0; + use TimeLock; public static function run() { - if (self::$lock > time()) { + if (self::getLock() > time()) { return; } - Log::info('正在检查每日任务...'); - $data = self::check(); - if (isset($data['data']['double_watch_info'])) { self::double_watch_info($data['data']['double_watch_info']); } @@ -31,15 +32,19 @@ class Task self::sign_info($data['data']['sign_info']); } - self::$lock = time() + 3600; + self::setLock(8 * 60 * 60); } - protected static function check() + /** + * @use 检查每日任务 + * @return bool|mixed|string + */ + private static function check() { $payload = []; $data = Curl::get('https://api.live.bilibili.com/i/api/taskInfo', Sign::api($payload)); $data = json_decode($data, true); - + Log::info('正在检查每日任务...'); if (isset($data['code']) && $data['code']) { Log::warning('每日任务检查失败!', ['msg' => $data['message']]); } @@ -47,7 +52,11 @@ class Task return $data; } - protected static function sign_info($info) + /** + * @use 每日签到 + * @param $info + */ + private static function sign_info($info) { Log::info('检查任务「每日签到」...'); @@ -65,11 +74,15 @@ class Task } else { Log::info('签到成功'); // 推送签到信息 - Notice::run('todaySign', $data['message']); + Notice::push('todaySign', $data['message']); } } - protected static function double_watch_info($info) + /** + * @use 双端任务 + * @param $info + */ + private static function double_watch_info($info) { Log::info('检查任务「双端观看直播」...'); @@ -77,12 +90,10 @@ class Task Log::notice('已经领取奖励'); return; } - if ($info['mobile_watch'] != 1 || $info['web_watch'] != 1) { Log::notice('任务未完成,请等待'); return; } - $payload = [ 'task_id' => 'double_watch_task', ]; diff --git a/src/User.php b/src/plugin/User.php similarity index 81% rename from src/User.php rename to src/plugin/User.php index 4bbde7c..fc4b549 100644 --- a/src/User.php +++ b/src/plugin/User.php @@ -8,16 +8,22 @@ * Updated: 2019 ~ 2020 */ -namespace lkeme\BiliHelper; +namespace BiliHelper\Plugin; + +use BiliHelper\Core\Log; +use BiliHelper\Core\Curl; +use BiliHelper\Util\TimeLock; +use BiliHelper\Core\Config; + class User { - // RUN - public static function run() - { - } - // 实名检测 + + /** + * @use 实名检测 + * @return bool + */ public static function realNameCheck(): bool { $payload = []; @@ -30,7 +36,11 @@ class User return true; } - // 老爷检测 + + /** + * @use 是否是老爷 + * @return bool + */ public static function isMaster(): bool { $payload = [ @@ -46,7 +56,11 @@ class User return false; } - // 用户名写入 + + /** + * @use 用户名写入 + * @return bool + */ public static function userInfo(): bool { $payload = [ @@ -59,13 +73,17 @@ class User return true; } if ($de_raw['msg'] == 'ok') { - File::writeNewEnvironmentFileWith('APP_UNAME', $de_raw['data']['uname']); + Config::put('APP_UNAME', $de_raw['data']['uname']); return true; } return false; } - //转换信息 + + /** + * @use 转换信息 + * @return array + */ public static function parseCookies(): array { $cookies = getenv('COOKIE'); diff --git a/src/plugin/ZoneTcpClient.php b/src/plugin/ZoneTcpClient.php new file mode 100644 index 0000000..24c4d1e --- /dev/null +++ b/src/plugin/ZoneTcpClient.php @@ -0,0 +1,427 @@ + time() || getenv('USE_ZONE_SERVER') == 'false') { + return; + } + self::init(); + self::updateConnection(); + self::heartBeat(); + self::receive(); + self::pushHandle(); + } + + + /** + * @use 初始化 + */ + private static function init() + { + if (empty(getenv('ZONE_SERVER_ADDR'))) { + exit('推送服务器信息不完整, 请检查配置文件!'); + } + if (!self::$server_addr) { + self::$server_addr = getenv('ZONE_SERVER_ADDR'); + } + if (!self::$client) { + self::initConnect(); + } + } + + /** + * @use 初始化连接 + */ + private static function initConnect() + { + $areas = Live::fetchLiveAreas(); + foreach ($areas as $area_id) { + self::$client_maps["server{$area_id}"] = ["area_id" => null, "room_id" => null, "client" => null, "heart_beat" => 0]; + self::triggerReConnect([ + 'area_id' => $area_id, + 'wait_time' => time() + ]); + } + } + + + /** + * @use 触发重连 + * @param array $area_data + */ + private static function triggerReConnect(array $area_data) + { + array_push(self::$trigger_restart, $area_data); + } + + /** + * @use 更新连接 + */ + private static function updateConnection() + { + $num = count(self::$trigger_restart); + for ($i = 0; $i < $num; $i++) { + $area_data = array_shift(self::$trigger_restart); + if (is_null($area_data)) { + break; + } + if (time() < $area_data['wait_time']) { + array_push(self::$trigger_restart, $area_data); + continue; + } + Log::notice("update_connections triggered, info: {$area_data['area_id']}"); + $area_info = Live::areaToRid($area_data['area_id']); +// $area_info = [ +// 'area_id' => $area_id, +// 'room_id' => 23058 +// ]; + self::update($area_info); + } + } + + /** + * @use 更新操作 + * @param array $area_info + */ + private static function update(array $area_info) + { + self::$area_id = $area_info['area_id']; + self::$room_id = $area_info['room_id']; + try { + self::$client = (new Factory())->createClient(self::$server_addr, 40); + self::$client->setBlocking(false); + self::sendHandShake(); + self::$client_maps["server" . self::$area_id]['client'] = self::$client; + self::$client_maps["server" . self::$area_id]['area_id'] = self::$area_id; + self::$client_maps["server" . self::$area_id]['room_id'] = self::$room_id; + self::$client_maps["server" . self::$area_id]['heart_beat'] = time() + 20; + Log::info("连接到 " . self::$client->getPeerName() . "#" . self::$area_id . " 推送服务器"); + } catch (Exception $e) { + Log::error("连接到 #" . self::$area_id . " 推送服务器失败, {$e->getMessage()}"); + self::triggerReConnect([ + 'area_id' => self::$area_id, + 'wait_time' => time() + 60 + ]); + } + } + + /** + * 判断字符串是否为 Json 格式 + * @param string $data Json 字符串 + * @param bool $assoc 是否返回对象or关联数组,默认返回关联数组 + * @return array|bool|object 成功返回转换后的对象或数组,失败返回 false + */ + private static function analyJson($data = '', $assoc = true) + { + $data = json_decode($data, $assoc); + if (($data && is_object($data)) || (is_array($data) && !empty($data))) { + return $data; + } + return false; + } + + + /** + * @use 响应数据 + * @param $msg + * @return bool + */ + private static function onMessage($msg) + { + // 心跳后回复人气 + if (strlen($msg) == 4) { + // $num = unpack('N', $msg)[1]; + // Log::info("当前直播间现有 {$num} 人聚众搞基!"); + return false; + } + $de_raw = self::analyJson($msg, true); + // 进入房间返回 + if (isset($de_raw['code']) && !$de_raw['code']) { + return false; + } + // 部分cmd抽风 + if (!$de_raw || !isset($de_raw['cmd'])) { + Log::warning("解析错误: {$msg}"); + return false; + } + $data = []; + switch ($de_raw['cmd']) { + case 'NOTICE_MSG': + $msg_type = $de_raw['msg_type']; + $msg_self = $de_raw['msg_self']; + $msg_common = str_replace(' ', '', $de_raw['msg_common']); + $real_room_id = $de_raw['real_roomid']; + if (in_array($msg_type, [2, 8])) { + $data = [ + 'room_id' => $real_room_id, + 'raffle_id' => self::$raffle_id++, + 'raffle_title' => $msg_self, + 'raffle_type' => 'raffle', + 'source' => $msg + ]; + // echo self::$room_id . '--' . $real_room_id . PHP_EOL; + } + if ($msg_type == 6 && strpos($msg_common, '节奏风暴') !== false) { + $data = [ + 'room_id' => $real_room_id, + 'raffle_id' => self::$raffle_id++, + 'raffle_title' => '节奏风暴', + 'raffle_type' => 'raffle', + 'source' => $msg + ]; + } + break; + case 'GUARD_MSG': + $data = [ + 'room_id' => $de_raw['roomid'], + 'raffle_id' => self::$raffle_id++, + 'raffle_title' => '总督舰长', + 'raffle_type' => 'raffle', + 'source' => $msg + ]; + break; + case 'SPECIAL_GIFT': + if (array_key_exists('39', $de_raw['data'])) { + if ($de_raw['data']['39']['action'] == 'start') { + $data = [ + 'room_id' => $de_raw['roomid'], + 'raffle_id' => self::$raffle_id++, + 'raffle_title' => '节奏风暴', + 'raffle_type' => 'raffle', + 'source' => $msg + ]; + } + } + break; + case 'SYS_GIFT': + /** + * 系统礼物消息, 广播 + */ + break; + case 'SYS_MSG': + /** + * 系统消息, 广播 + */ + break; + // TODO 支持更多消息类型 + default: + $data = []; + break; + } + + if (!empty($data)) { + unset($data['source']); + if (!isset(self::$raffle_list[$data['raffle_type']])) { + self::$raffle_list[$data['raffle_type']] = []; + } + array_push(self::$raffle_list[$data['raffle_type']], $data); + // Log::info("获取到分区 #" . self::$area_id . "# {$data['source']}"); + // print_r($data); + } + } + + + /** + * @推送到上游处理 + */ + private static function pushHandle() + { + foreach (self::$raffle_list as $type => $data) { + $temp_room_id = 0; + foreach (self::$raffle_list[$type] as $raffle) { + if ($temp_room_id != $raffle['room_id']) { + DataTreating::distribute($raffle); + $temp_room_id = $raffle['room_id']; + } + } + } + self::$raffle_list = []; + } + + /** + * @use 响应关闭 + * @param $client + */ + private static function onClosed($client) + { + } + + + /** + * @use 发送握手包 + * @return bool + */ + private static function sendHandShake() + { + return self::writer(self::genHandshakePkg(self::$room_id)); + } + + /** + * @use 心跳包 + * @return string + */ + private static function genHeartBeatPkg(): string + { + return self::packMsg('', 0x0002); + } + + + /** + * @use 握手包 + * @param $room_id + * @return string + */ + private static function genHandshakePkg($room_id): string + { + return self::packMsg(json_encode([ + 'uid' => mt_rand(1000000, 2999999), + 'roomid' => intval($room_id), + ]), 0x0007); + } + + /** + * @use 打包数据 + * @param $value + * @param $option + * @return string + */ + private static function packMsg($value, $option) + { + $head = pack('NnnNN', 0x10 + strlen($value), 0x10, 0x01, $option, 0x0001); + return $head . $value; + } + + + /** + * @use 解包数据 + * @param $value + * @return int|mixed + */ + private static function unPackMsg($value) + { + $res = unpack('N', $value); + return $res[1] - 16; + } + + + /** + * @use 心跳 + */ + private static function heartBeat() + { + foreach (self::$client_maps as $key => $client_info) { + if ($client_info['heart_beat'] > time()) { + continue; + } + self::$client = $client_info['client']; + self::$area_id = $client_info['area_id']; + self::$room_id = $client_info['room_id']; + self::writer(self::genHeartBeatPkg()); + self::$client_maps[$key]['heart_beat'] = time() + 20; + } + } + + /** + * @use 读数据 + * @param $length + * @return array|bool|false + */ + private static function reader($length) + { + $data = false; + try { + while (self::$client->selectRead(self::$socket_timeout)) { + $data = self::$client->read($length); + if (!$data) { + throw new Exception("Connection failure"); + } + if ($length == 16) $data = self::unPackMsg($data); + break; + } + } catch (Exception $exception) { + self::triggerReConnect([ + 'area_id' => self::$area_id, + 'wait_time' => time() + 60 + ]); + } + return $data; + } + + /** + * @use 写数据 + * @param $data + * @return bool + */ + private static function writer($data) + { + $status = false; + try { + while (self::$client->selectWrite(self::$socket_timeout)) { + $status = self::$client->write($data); + break; + } + } catch (Exception $exception) { + self::triggerReConnect([ + 'area_id' => self::$area_id, + 'wait_time' => time() + 60 + ]); + } + return $status; + } + + + /** + * @use 读取数据 + */ + private static function receive() + { + foreach (self::$client_maps as $client_info) { + self::$client = $client_info['client']; + self::$area_id = $client_info['area_id']; + self::$room_id = $client_info['room_id']; + $len_body = self::reader(16); + if (!$len_body) { + // 长度为0 ,空信息 + continue; + } + Log::debug("(len=$len_body)"); + $body = self::reader($len_body); + self::onMessage($body); + } + } +} \ No newline at end of file diff --git a/src/util/TimeLock.php b/src/util/TimeLock.php new file mode 100644 index 0000000..41e9b4a --- /dev/null +++ b/src/util/TimeLock.php @@ -0,0 +1,38 @@ +