diff --git a/CHANGELOG.md b/CHANGELOG.md index 77fbdd1..87482ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,23 @@ # Release Notes # 本项目Log +## v0.8.1.210423 alpha (2021-04-23) + +### Added +- + +### Changed +- 更新天选敏感词 +- 更新活动列表 +- 优化直播间心跳 +- + +### Fixed +- + +### Remarks +- + ## v0.8.0.210327 alpha (2021-03-27) ### Added diff --git a/DOC.md b/DOC.md index afce528..85879fc 100644 --- a/DOC.md +++ b/DOC.md @@ -2,7 +2,7 @@

- +

@@ -17,7 +17,7 @@ B 站直播实用脚本 |--------------------|--------------------|--------------------| |Login |21.03.27 |账号登录 | |Schedule |21.03.27 |休眠控制 | -|MainSite |21.03.27 |主站助手 | +|MainSite |21.03.27 |主站助手 | |Daily |21.03.27 |每日礼包 | |Heart |21.03.27 |双端心跳 | |DailyTask |21.03.27 |每日任务 | diff --git a/README.md b/README.md index cf48b01..c26e1bc 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Group: [55308141](https://jq.qq.com/?_wv=1027&k=5AIDaJg) | **仅用于BUG提交 ## 公告 -> Personal Edition **0.8.0.210327 alpha** +> Personal Edition **0.8.1.210423 alpha** ```notice ---- 免费的东西总是得不到人的珍惜。 diff --git a/data/activity_infos.json b/data/activity_infos.json index 3047d95..90c1d60 100644 --- a/data/activity_infos.json +++ b/data/activity_infos.json @@ -41,7 +41,7 @@ "follow": "false", "share": "true", "draw_times": 2, - "expire_at": "2021-04-15 11:59:59" + "expire_at": "2021-05-23 11:59:59" }, { "url": "https://www.bilibili.com/blackboard/activity-QEya2bouhQ.html", @@ -63,19 +63,30 @@ "follow": "false", "share": "true", "draw_times": 1, - "expire_at": "2021-04-30 23:59:59", + "expire_at": "2021-05-30 23:59:59", "remarks": "时间不名,暂定一个月。" }, { - "url": "https://www.bilibili.com/blackboard/activity-M22oqFLY1w.html", - "title": "最强搞事王", + "url": "https://www.bilibili.com/blackboard/activity-aT7zphkwF1.html", + "title": "初夏逛吃大会", "description": "活动期间每天分享页面,新增一次机会。", - "sid": "e168f825-8be6-11eb-8597-246e966235d8", + "sid": "01aff78a-9e1a-11eb-8597-246e966235d8", "login": "true", "follow": "false", "share": "true", "draw_times": 1, - "expire_at": "2021-04-23 23:59:59" + "expire_at": "2021-06-10 23:59:59" + }, + { + "url": "https://www.bilibili.com/blackboard/activity-oGiWFe0YTz.html", + "title": "京东超市超有young", + "description": "活动期间每天分享页面,新增一次机会。", + "sid": "4eb728e2-a0d7-11eb-8597-246e966235d8", + "login": "true", + "follow": "false", + "share": "true", + "draw_times": 1, + "expire_at": "2021-04-25 23:59:59" } ] } \ No newline at end of file diff --git a/data/capsule_infos.json b/data/capsule_infos.json index fff65fb..09fcb31 100644 --- a/data/capsule_infos.json +++ b/data/capsule_infos.json @@ -34,23 +34,23 @@ "parent_area_id": 6, "coin_id": 121, "watch_time": 3720, - "draw_times": 9, + "draw_times": 2, "expire_at": "2021-04-26 23:59:59" }, { "url": "https://live.bilibili.com/11218604", - "title": "PGI全球邀请赛", - "description": "每日在PGI直播间观看,10分钟1张", + "title": "2021PCL春季赛观赛任务", + "description": "每日在PGI直播间观看,10、15、30", "room_id": 11218604, "area_id": 0, "parent_area_id": 2, - "coin_id": 91, + "coin_id": 129, "watch_time": 3720, - "draw_times": 6, - "expire_at": "2021-03-28 23:59:59" + "draw_times": 3, + "expire_at": "2021-05-31 23:59:59" }, { - "url": "https://live.bilibili.com/blackboard/2021-lpl-main.html", + "url": "https://live.bilibili.com/6", "title": "2021LPL春季赛", "description": "每日在LOL直播间观看,5分钟1张,15分钟1张", "room_id": 7734200, @@ -59,19 +59,19 @@ "coin_id": 76, "watch_time": 3720, "draw_times": 3, - "expire_at": "2021-03-28 23:59:59" + "expire_at": "2021-05-31 23:59:59" }, { "url": "https://live.bilibili.com/23", - "title": "PEL和平精英职业联赛", + "title": "PEI亚洲邀请赛", "description": "每日在PEL直播间观看,5分钟1张", "room_id": 13242892, "area_id": 0, "parent_area_id": 2, "coin_id": 109, "watch_time": 3720, - "draw_times": 6, - "expire_at": "2021-04-11 23:59:59" + "draw_times": 2, + "expire_at": "2021-05-31 23:59:59" } ] } \ No newline at end of file diff --git a/data/filter_words.json b/data/filter_words.json index bbe3b69..b5eb8ec 100644 --- a/data/filter_words.json +++ b/data/filter_words.json @@ -198,7 +198,106 @@ "1元红包", "红包3.3元", "5.2元红包", - "2.33元红包" + "2.33元红包", + "测试", + "钓鱼", + "炸鱼", + "黑屋", + "脚本", + "空气", + "大航海", + "上船", + "舰长", + "返现", + "抵用", + "代金", + "上车", + "上反船", + "照片", + "素颜", + "自拍", + "皂片", + "开舰", + "上舰", + "自画像", + "封面", + "取关", + "美照", + "随机照", + "女装照", + "日常照", + "好友", + "给主播", + "照骗", + "连麦", + "情书", + "一局", + "舰涨优惠卷", + "开黑", + "test", + "Test", + "金币", + "元宝", + "代打", + "上分", + "上段", + "台历", + "一毛", + "五毛", + "王者荣耀", + "玩游戏", + "encrypt", + "壁纸", + "相片", + "排位", + "语音", + "车位", + "网剧", + "一起玩", + "一次", + "专属头衔", + "手游", + "宠物", + "蒸汽", + "月饼", + "加速", + "挂件", + "渔夫", + "小黑屋", + "头像", + "许愿码", + "电池", + "赛车", + "保底", + "代币", + "越南盾", + "网点", + "机器", + "话梅", + "志愿", + "令牌", + "永久", + "第五人格", + "大蒜", + "唢呐", + "皇冠", + "徽章", + "铜牌", + "动物园", + "植物", + "钻石", + "宝石", + "尖叫", + "扭蛋机", + "点播", + "数字版月历", + "点歌一首", + "体验", + "点歌", + "三次取关", + "大航海", + "3块钱之前的巨款", + "礼金" ] }, "CapsuleLottery": { diff --git a/src/core/Env.php b/src/core/Env.php index 49ab0a7..6015082 100644 --- a/src/core/Env.php +++ b/src/core/Env.php @@ -13,7 +13,7 @@ namespace BiliHelper\Core; class Env { private $app_name = 'BiliHelper Personal'; - private $app_version = '0.8.0.*'; + private $app_version = '0.8.1.*'; /** * Env constructor. diff --git a/src/plugin/CapsuleLottery.php b/src/plugin/CapsuleLottery.php index 382d30a..bcdcc81 100644 --- a/src/plugin/CapsuleLottery.php +++ b/src/plugin/CapsuleLottery.php @@ -15,53 +15,37 @@ use BiliHelper\Core\Log; use BiliHelper\Core\Curl; use BiliHelper\Util\AllotTasks; use BiliHelper\Util\TimeLock; -use BiliHelper\Tool\Generator; +use BiliHelper\Util\XliveHeartBeat; class CapsuleLottery { use TimeLock; use AllotTasks; + use XliveHeartBeat; private static $repository = APP_DATA_PATH . 'capsule_infos.json'; - - private static $work_room_id = null; - private static $enc_server = null; // 加密服务器 配置文件 - private static $hb_payload = []; // 心跳请求数据 - private static $hb_headers = []; // 心跳请求头 - private static $hb_count_total = 0; - private static $hb_count = 0; // 心跳次数 max 24 - private static $hb_room_info = []; // 心跳带勋章房间信息 - private static $heartbeat_interval = 60; // 每次跳动时间 + private static $interval = 60; + /** + * @throws \JsonDecodeStream\Exception\TokenizerException + * @throws \JsonDecodeStream\Exception\SelectorException + * @throws \JsonDecodeStream\Exception\ParserException + * @throws \JsonDecodeStream\Exception\CollectorException + */ public static function run() { - if (self::getLock() > time() || !self::init()) { + if (self::getLock() > time() || getenv('USE_CAPSULE') == 'false') { return; } self::allotTasks(); if (self::workTask()) { - self::setLock(self::$heartbeat_interval); + self::setLock(self::$interval); } else { self::setLock(self::timing(5) + mt_rand(1, 180)); } } - /** - * @use init - * @return bool - */ - private static function init(): bool - { - if (getenv('USE_CAPSULE') == 'false' || getenv('ENC_SERVER') == '') { - return false; - } - if (is_null(self::$enc_server)) { - self::$enc_server = getenv('ENC_SERVER'); - } - return true; - } - /** * @use 分配任务 @@ -126,7 +110,8 @@ class CapsuleLottery // 执行任务 switch ($task['operation']) { case 'watch': - self::heartBeat($task['act']->room_id); + $interval = self::xliveHeartBeatTask($task['act']->room_id,999,999); + self::$interval = $interval == 0 ? 60 : $interval; break; case 'draw': self::doLottery($task['act']->coin_id, $task['act']->url, 0); @@ -138,196 +123,6 @@ class CapsuleLottery return true; } - - /** - * @use 重置变量 - * @param false $reset_num - */ - private static function resetVar($reset_num = false) - { - self::$hb_payload = []; // 心跳请求数据 - self::$hb_headers = []; // 心跳请求头 - if ($reset_num) { - self::$hb_count_total = 0; - } - self::$hb_room_info = []; // 心跳带勋章房间信息 - self::$hb_count = 0; // 心跳次数 max 24 - self::$heartbeat_interval = 60; // 跳变时间 - } - - - /** - * @use 心跳处理 - * @param int $room_id - */ - private static function heartBeat(int $room_id) - { - if (self::$work_room_id != $room_id) { - self::resetVar(); - self::$work_room_id = $room_id; - } - if (empty(self::$hb_room_info)) { - self::$hb_room_info = Live::webGetRoomInfo($room_id); - } - if (!self::$hb_count) { - $e_data = self::eHeartBeat(self::$hb_room_info['data']['room_info']); - if (!$e_data['status']) { - // 错误级别 - return; - } - self::$hb_count += 1; - self::$hb_count_total += 1; - self::$hb_payload = $e_data['payload']; - self::$hb_headers = $e_data['headers']; - return; - } - $x_data = self::xHeartBeat(self::$hb_count); - if (!$x_data['status']) { - // 错误级别 - self::resetVar(); - return; - } - self::$hb_count_total += 1; - self::$hb_count += 1; - } - - /** - * @use E心跳 - * @param array $room_info - * @param int $index - * @return array|bool[] - */ - private static function eHeartBeat(array $room_info, $index = 0): array - { - $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/E'; - $headers = [ - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Origin' => 'https://live.bilibili.com', - 'Referer' => 'https://live.bilibili.com/' . $room_info['room_id'], - ]; - $user_info = User::parseCookies(); - $payload = [ - 'id' => json_encode([$room_info['parent_area_id'], $room_info['area_id'], $index, $room_info['room_id']], true), - 'device' => json_encode([ - Generator::hash(), Generator::uuid4() - ], true), - 'ts' => time() * 1000, - 'is_patch' => 0, - 'heart_beat' => [], - 'ua' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0', - 'csrf_token' => $user_info['token'], - 'csrf' => $user_info['token'], - 'visit_id' => '' - ]; - $raw = Curl::post('pc', $url, $payload, $headers); - $de_raw = json_decode($raw, true); - // {"code":0,"message":"0","ttl":1,"data":{"timestamp":1595342828,"heartbeat_interval":300,"secret_key":"seacasdgyijfhofiuxoannn","secret_rule":[2,5,1,4],"patch_status":2}} - if ($de_raw['code'] != 0) { - Log::warning("小心心礼物E-{$index}心跳失败"); - return ['status' => false]; - } - Log::info("小心心礼物E-{$index}心跳成功"); - // Log::info($raw); - $payload['ets'] = $de_raw['data']['timestamp']; - $payload['secret_key'] = $de_raw['data']['secret_key']; - $payload['heartbeat_interval'] = $de_raw['data']['heartbeat_interval']; - $payload['secret_rule'] = $de_raw['data']['secret_rule']; - // 自动跳变时间 - self::$heartbeat_interval = $de_raw['data']['heartbeat_interval']; - return [ - 'status' => true, - 'payload' => $payload, - 'headers' => $headers, - ]; - } - - /** - * @use X心跳 - * @param int $index - * @return array|bool[] - */ - private static function xHeartBeat(int $index = 1): array - { - $s_data = self::encParamS($index); - if (!$s_data) { - return ['status' => false]; - } - $s = $s_data['s']; - $t = $s_data['payload']; - - $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/X'; - $user_info = User::parseCookies(); - $payload = [ - 's' => $s, - 'id' => $t['id'], - 'device' => $t['device'], - 'ets' => $t['ets'], - 'benchmark' => $t['benchmark'], - 'time' => $t['time'], - 'ts' => $t['ts'], - 'ua' => $t['ua'], - 'csrf_token' => $user_info['token'], - 'csrf' => $user_info['token'], - 'visit_id' => '' - ]; - // print_r($payload); - $raw = Curl::post('pc', $url, $payload, self::$hb_headers); - $de_raw = json_decode($raw, true); - # {"code":0,"message":"0","ttl":1,"data":{"heartbeat_interval":300,"timestamp":1595346846,"secret_rule":[2,5,1,4],"secret_key":"seacasdgyijfhofiuxoannn"}} - if ($de_raw['code'] != 0) { - Log::warning("小心心礼物X-{$index}心跳失败"); - return ['status' => false]; - } - self::$hb_payload['ets'] = $de_raw['data']['timestamp']; - self::$hb_payload['secret_key'] = $de_raw['data']['secret_key']; - self::$hb_payload['heartbeat_interval'] = $de_raw['data']['heartbeat_interval']; - // 自动跳变时间 - self::$heartbeat_interval = $de_raw['data']['heartbeat_interval']; - Log::info("小心心礼物X-{$index}心跳成功"); - return ['status' => true]; - } - - /** - * @use 加密参数S - * @param int $index - * @return array|false - */ - private static function encParamS(int $index) - { - // 转换index - $temp = json_decode(self::$hb_payload['id'], true); - $temp[2] += 1; - self::$hb_payload['id'] = json_encode($temp, true); - // 加密部分 - $payload = [ - 't' => [ - 'id' => self::$hb_payload['id'], - 'device' => self::$hb_payload['device'], - 'ets' => self::$hb_payload['ets'], - 'benchmark' => self::$hb_payload['secret_key'], - 'time' => self::$hb_payload['heartbeat_interval'], - 'ts' => time() * 1000, - 'ua' => self::$hb_payload['ua'] - ], - 'r' => self::$hb_payload['secret_rule'] - ]; - $headers = [ - 'Content-Type' => 'application/json', - ]; - $data = Curl::put('other', self::$enc_server, $payload, $headers); - $de_raw = json_decode($data, true); - if ($de_raw['code'] == 0) { - Log::info("S加密成功 {$de_raw['s']}"); - return [ - 's' => $de_raw['s'], - 'payload' => $payload['t'] - ]; - } else { - Log::warning("S加密成功 {$de_raw['message']}"); - return false; - } - } - /** * @use 开始抽奖 * @param int $coin_id @@ -335,7 +130,7 @@ class CapsuleLottery * @param int $num * @return bool */ - private static function doLottery(int $coin_id, string $referer, int $num) + private static function doLottery(int $coin_id, string $referer, int $num): bool { $url = 'https://api.live.bilibili.com/xlive/web-ucenter/v1/capsule/open_capsule_by_id'; $headers = [ diff --git a/src/plugin/Live.php b/src/plugin/Live.php index 5fe239d..5f3300e 100644 --- a/src/plugin/Live.php +++ b/src/plugin/Live.php @@ -390,7 +390,7 @@ class Live 'platform' => 'web', 'parent_area_id' => $parent_area_id, 'area_id' => $area_id, - 'sort_type' => 'sort_type_282', + 'sort_type' => 'online', 'page' => $page ]; $raw = Curl::get('other', $url, $payload); diff --git a/src/plugin/SmallHeart.php b/src/plugin/SmallHeart.php index 03ec0ab..ce90b70 100644 --- a/src/plugin/SmallHeart.php +++ b/src/plugin/SmallHeart.php @@ -11,34 +11,25 @@ namespace BiliHelper\Plugin; -use BiliHelper\Core\Log; -use BiliHelper\Core\Curl; use BiliHelper\Util\TimeLock; -use BiliHelper\Tool\Generator; +use BiliHelper\Util\XliveHeartBeat; class SmallHeart { use TimeLock; + use XliveHeartBeat; - private static $enc_server = null; // 加密服务器 配置文件 - - private static $hb_payload = []; // 心跳请求数据 - private static $hb_headers = []; // 心跳请求头 - - private static $hb_count_total = 0; - private static $hb_count = 0; // 心跳次数 max 24 - private static $hb_room_info = []; // 心跳带勋章房间信息 private static $fans_medals = []; // 全部勋章 private static $grey_fans_medals = []; // 灰色勋章 - private static $metal_lock = 0; // 勋章时间锁 - - private static $heartbeat_interval = 60; // 每次跳动时间 + private static $interval = 60; // 每次跳动时间 + private static $total_time = 0; + private static $metal = null; public static function run() { - if (!self::init()) { + if (getenv('USE_HEARTBEAT') == 'false') { return; } @@ -48,48 +39,16 @@ class SmallHeart } if (self::getLock() < time()) { self::heartBeat(); - if (self::$hb_count_total >= 200) { - self::resetVar(true); + if (self::$total_time >= 12000) { + self::$total_time = 0; self::setLock(self::timing(2)); } else { - self::setLock(self::$heartbeat_interval); + self::setLock(self::$interval); } } } - /** - * @use 重置变量 - * @param false $reset_num - */ - private static function resetVar($reset_num = false) - { - self::$hb_payload = []; // 心跳请求数据 - self::$hb_headers = []; // 心跳请求头 - if ($reset_num) { - self::$hb_count_total = 0; - } - self::$hb_room_info = []; // 心跳带勋章房间信息 - self::$hb_count = 0; // 心跳次数 max 24 - self::$heartbeat_interval = 60; // 跳变时间 - } - - /** - * @use init - * @return bool - */ - private static function init(): bool - { - if (getenv('USE_HEARTBEAT') == 'false' || getenv('ENC_SERVER') == '') { - return false; - } - if (is_null(self::$enc_server)) { - self::$enc_server = getenv('ENC_SERVER'); - } - return true; - } - - /** * @use 勋章处理 */ @@ -115,8 +74,6 @@ class SmallHeart Live::sendGift($grey_fans_medal, $gift, 1); } } - - } @@ -128,168 +85,14 @@ class SmallHeart if (empty(self::$fans_medals)) { return; } - if (empty(self::$hb_room_info)) { - $metal = self::$fans_medals[array_rand(self::$fans_medals)]; - self::$hb_room_info = Live::webGetRoomInfo($metal['roomid']); + if (is_null(self::$metal)){ + self::$metal = self::$fans_medals[array_rand(self::$fans_medals)]; } - if (self::$hb_count == 0) { - $e_data = self::eHeartBeat(self::$hb_room_info['data']['room_info']); - if (!$e_data['status']) { - // 错误级别 - return; - } - self::$hb_count += 1; - self::$hb_count_total +=1; - self::$hb_payload = $e_data['payload']; - self::$hb_headers = $e_data['headers']; - return; - } - $x_data = self::xHeartBeat(self::$hb_count); - if (!$x_data['status']) { - // 错误级别 - self::resetVar(); - return; - } - self::$hb_count_total +=1; - self::$hb_count += 1; - } - - /** - * @use E心跳 - * @param array $room_info - * @param int $index - * @return array|bool[] - */ - private static function eHeartBeat(array $room_info, $index = 0): array - { - $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/E'; - $headers = [ - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Origin' => 'https://live.bilibili.com', - 'Referer' => 'https://live.bilibili.com/' . $room_info['room_id'], - ]; - $user_info = User::parseCookies(); - $payload = [ - 'id' => json_encode([$room_info['parent_area_id'], $room_info['area_id'], $index, $room_info['room_id']], true), - 'device' => json_encode([ - Generator::hash(), Generator::uuid4() - ], true), - 'ts' => time() * 1000, - 'is_patch' => 0, - 'heart_beat' => [], - 'ua' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0', - 'csrf_token' => $user_info['token'], - 'csrf' => $user_info['token'], - 'visit_id' => '' - ]; - $raw = Curl::post('pc', $url, $payload, $headers); - $de_raw = json_decode($raw, true); - // {"code":0,"message":"0","ttl":1,"data":{"timestamp":1595342828,"heartbeat_interval":300,"secret_key":"seacasdgyijfhofiuxoannn","secret_rule":[2,5,1,4],"patch_status":2}} - if ($de_raw['code'] != 0) { - Log::warning("小心心礼物E-{$index}心跳失败"); - return ['status' => false]; - } - Log::info("小心心礼物E-{$index}心跳成功"); - // Log::info($raw); - $payload['ets'] = $de_raw['data']['timestamp']; - $payload['secret_key'] = $de_raw['data']['secret_key']; - $payload['heartbeat_interval'] = $de_raw['data']['heartbeat_interval']; - $payload['secret_rule'] = $de_raw['data']['secret_rule']; - // 自动跳变时间 - self::$heartbeat_interval = $de_raw['data']['heartbeat_interval']; - return [ - 'status' => true, - 'payload' => $payload, - 'headers' => $headers, - ]; - } - - /** - * @use X心跳 - * @param int $index - * @return array|bool[] - */ - private static function xHeartBeat(int $index = 1): array - { - $s_data = self::encParamS($index); - if (!$s_data) { - return ['status' => false]; - } - $s = $s_data['s']; - $t = $s_data['payload']; - - $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/X'; - $user_info = User::parseCookies(); - $payload = [ - 's' => $s, - 'id' => $t['id'], - 'device' => $t['device'], - 'ets' => $t['ets'], - 'benchmark' => $t['benchmark'], - 'time' => $t['time'], - 'ts' => $t['ts'], - 'ua' => $t['ua'], - 'csrf_token' => $user_info['token'], - 'csrf' => $user_info['token'], - 'visit_id' => '' - ]; - // print_r($payload); - $raw = Curl::post('pc', $url, $payload, self::$hb_headers); - $de_raw = json_decode($raw, true); - # {"code":0,"message":"0","ttl":1,"data":{"heartbeat_interval":300,"timestamp":1595346846,"secret_rule":[2,5,1,4],"secret_key":"seacasdgyijfhofiuxoannn"}} - if ($de_raw['code'] != 0) { - Log::warning("小心心礼物X-{$index}心跳失败"); - return ['status' => false]; - } - self::$hb_payload['ets'] = $de_raw['data']['timestamp']; - self::$hb_payload['secret_key'] = $de_raw['data']['secret_key']; - self::$hb_payload['heartbeat_interval'] = $de_raw['data']['heartbeat_interval']; - // 自动跳变时间 - self::$heartbeat_interval = $de_raw['data']['heartbeat_interval']; - Log::info("小心心礼物X-{$index}心跳成功"); - return ['status' => true]; - } - - - /** - * @use 加密参数S - * @param int $index - * @return array|false - */ - private static function encParamS(int $index) - { - // 转换index - $temp = json_decode(self::$hb_payload['id'], true); - $temp[2] += 1; - self::$hb_payload['id'] = json_encode($temp, true); - // 加密部分 - $payload = [ - 't' => [ - 'id' => self::$hb_payload['id'], - 'device' => self::$hb_payload['device'], - 'ets' => self::$hb_payload['ets'], - 'benchmark' => self::$hb_payload['secret_key'], - 'time' => self::$hb_payload['heartbeat_interval'], - 'ts' => time() * 1000, - 'ua' => self::$hb_payload['ua'] - ], - 'r' => self::$hb_payload['secret_rule'] - ]; - $headers = [ - 'Content-Type' => 'application/json', - ]; - $data = Curl::put('other', self::$enc_server, $payload, $headers); - $de_raw = json_decode($data, true); - if ($de_raw['code'] == 0) { - Log::info("S加密成功 {$de_raw['s']}"); - return [ - 's' => $de_raw['s'], - 'payload' => $payload['t'] - ]; - } else { - Log::warning("S加密成功 {$de_raw['message']}"); - return false; + $interval = self::xliveHeartBeatTask(self::$metal['roomid'], 999, 999); + if ($interval != 0) { + self::$total_time += $interval; } + self::$interval = $interval == 0 ? 60 : $interval; } diff --git a/src/util/XliveHeartBeat.php b/src/util/XliveHeartBeat.php new file mode 100644 index 0000000..3792a8b --- /dev/null +++ b/src/util/XliveHeartBeat.php @@ -0,0 +1,243 @@ + []]; // data [ets, benchmark, time, secret_rule, id] data->id [parent_area_id, area_id, 0, room_id] + protected static $_secret_rule = []; // secret_rule [2, 3, 1, 5] + protected static $_room_info = []; // 心跳房间信息 + + protected static $_retry = 3; // 重试次数 + protected static $_count_num = 0; // 计数 + protected static $_count_time = 0; // 计时间 + + protected static $_current_room_id = 0; // 当前运行的ROOM_ID + protected static $_enc_server = null; // 加密服务器 依赖配置文件 + + protected static $_default = 0; // 默认值 + + + /** + * @use 重置变量 + * @param false $force + */ + protected static function resetVar($force = false) + { + if ($force){ + self::$_room_info = []; + self::$_current_room_id = 0; + + self::$_retry = 3; + self::$_count_num = 0; + self::$_count_time = 0; + } + $data = [ + 'id' => self::$_data['id'], + ]; + $data["id"][2] = 0; + self::$_data = $data; + } + + + protected static function xliveHeartBeatTask(int $room_id, int $max_time, int $max_num) + { + // 加载依赖 + if (!self::depend()) { + return self::$_default; + } + // 对比当前运行 + if (self::$_current_room_id != $room_id) { + self::resetVar(true); + self::$_current_room_id = $room_id; + } + // 加载房间信息 + if (empty(self::$_room_info)) { + $r_data = Live::webGetRoomInfo($room_id); + if ($r_data['code'] != 0) { + Log::warning('直播间信息获取失败'); + return self::$_default; + } + $rdata = $r_data['data']; + $parent_area_id = $rdata['room_info']['parent_area_id']; + $area_id = $rdata['room_info']['area_id']; + # 短位转长位 + $room_id = $rdata['room_info']['room_id']; + self::$_data['id'] = [$parent_area_id, $area_id, 0, $room_id]; + } + // 执行心跳 + $r_data = self::heartBeatIterator(); + $index = self::$_data['id'][2]; + if ($r_data['code'] != 0) { + if (self::$_retry) { + Log::warning("心跳失败-{$index} {$r_data['message']}"); + self::resetVar(); + self::$_retry -= 1; + return self::$_default; + } + } + self::$_count_num += 1; + self::$_count_time += $r_data['heartbeat_interval']; + + // 最大次数限制 + if ($max_num <= self::$_count_num) { + // 成功在id为{room_id}的直播间发送完{ii}次心跳,退出直播心跳(达到最大心跳次数) + } + // 最大时间限制 + if ($max_time <= self::$_count_time) { + //成功在id为{room_id}的直播间发送第{ii}次心跳 + } + $minute = round(self::$_count_time / 60); + Log::info("已在直播间 {$room_id} 连续观看了 {$minute} 分钟"); + return $r_data['heartbeat_interval']; + + } + + /** + * @use 检查依赖 + * @return bool + */ + protected static function depend(): bool + { + if (getenv('ENC_SERVER') == '') { + return false; + } + // 加载加密服务器 + if (is_null(self::$_enc_server)) { + self::$_enc_server = getenv('ENC_SERVER'); + } + return true; + } + + + protected static function heartBeatIterator(): array + { + $rdata = []; + # 第1次执行 eHeartBeat + if (self::$_data['id'][2] == 0) { + $r_data = self::eHeartBeat(self::$_data['id']); + } else { + # 第1次之后执行 xHeartBeat + self::$_data['ts'] = time() * 1000; + self::$_data['s'] = self::encParamS(self::$_data, self::$_secret_rule); + $r_data = self::xHeartBeat(self::$_data['id']); + } + if ($r_data['code'] == 0) { + $rdata = $r_data['data']; + self::$_data['ets'] = $rdata['timestamp']; + self::$_data['benchmark'] = $rdata['secret_key']; + self::$_data['time'] = $rdata['heartbeat_interval']; + self::$_secret_rule = $rdata['secret_rule']; + self::$_data['id'][2] += 1; + } + return [ + 'code' => $r_data['code'], + 'message' => $r_data['message'], + 'heartbeat_interval' => $rdata['heartbeat_interval'] + ]; + } + + + /** + * @use E心跳 + * @param array $id + * @return array|false[] + */ + protected static function eHeartBeat(array $id): array + { + $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/E'; + $headers = [ + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Origin' => 'https://live.bilibili.com', + 'Referer' => 'https://live.bilibili.com/' . $id[3], + ]; + $user_info = User::parseCookies(); + $payload = [ + 'id' => json_encode([$id[0], $id[1], $id[2], $id[3]], true), + 'device' => json_encode([Generator::hash(), Generator::uuid4()], true), + 'ts' => time() * 1000, + 'is_patch' => 0, + 'heart_beat' => [], + 'ua' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0', + 'csrf_token' => $user_info['token'], + 'csrf' => $user_info['token'], + 'visit_id' => '' + ]; + $raw = Curl::post('pc', $url, $payload, $headers); + // {'code':0,'message':'0','ttl':1,'data':{'timestamp':1595342828,'heartbeat_interval':300,'secret_key':'seacasdgyijfhofiuxoannn','secret_rule':[2,5,1,4],'patch_status':2}} + + unset($payload['id']); + self::$_data = array_merge_recursive(self::$_data, $payload); + + return json_decode($raw, true); + } + + /** + * @use X心跳 + * @param array $id + * @return array|bool[] + */ + protected static function xHeartBeat(array $id): array + { + $url = 'https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/X'; + $user_info = User::parseCookies(); + $payload = [ + 's' => self::$_data['s'], + 'id' => json_encode([$id[0], $id[1], $id[2], $id[3]], true), + 'device' => self::$_data['device'], + 'ets' => self::$_data['ets'], + 'benchmark' => self::$_data['benchmark'], + 'time' => self::$_data['time'], + 'ts' => self::$_data['ts'], + 'ua' => self::$_data['ua'], + 'csrf_token' => $user_info['token'], + 'csrf' => $user_info['token'], + 'visit_id' => '' + ]; + // print_r($payload); + $raw = Curl::post('pc', $url, $payload, self::$hb_headers); + # {'code':0,'message':'0','ttl':1,'data':{'heartbeat_interval':300,'timestamp':1595346846,'secret_rule':[2,5,1,4],'secret_key':'seacasdgyijfhofiuxoannn'}} + return json_decode($raw, true); + } + + /** + * @use 加密参数S + * @param array $t + * @param array $r + * @return string|false + */ + protected static function encParamS(array $t, array $r) + { + $headers = [ + 'Content-Type' => 'application/json', + ]; + // 加密部分 + $payload = ['t' => $t, 'r' => $r]; + $data = Curl::put('other', self::$_enc_server, $payload, $headers); + $de_raw = json_decode($data, true); + if ($de_raw['code'] == 0) { + // Log::info("S加密成功 {$de_raw['s']}"); + return $de_raw['s']; + } else { + Log::warning("S加密失败 {$de_raw['message']}"); + return false; + } + } + + +} \ No newline at end of file