mirror of
https://github.com/lkeme/BiliHelper-personal.git
synced 2025-12-19 01:20:08 +08:00
[update] XliveHeartBeat
This commit is contained in:
parent
2d50437b70
commit
f6ad4fe262
17
CHANGELOG.md
17
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
|
||||
|
||||
4
DOC.md
4
DOC.md
@ -2,7 +2,7 @@
|
||||
<p align="center"><img width="300px" src="https://i.loli.net/2018/04/20/5ad97bd395912.jpeg"></p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/version-0.8.0.210327 alpha-green.svg?longCache=true&style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/version-0.8.1.210423 alpha-green.svg?longCache=true&style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/license-mit-blue.svg?longCache=true&style=for-the-badge">
|
||||
</p>
|
||||
|
||||
@ -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 |每日任务 |
|
||||
|
||||
@ -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
|
||||
---- 免费的东西总是得不到人的珍惜。
|
||||
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -198,7 +198,106 @@
|
||||
"1元红包",
|
||||
"红包3.3元",
|
||||
"5.2元红包",
|
||||
"2.33元红包"
|
||||
"2.33元红包",
|
||||
"测试",
|
||||
"钓鱼",
|
||||
"炸鱼",
|
||||
"黑屋",
|
||||
"脚本",
|
||||
"空气",
|
||||
"大航海",
|
||||
"上船",
|
||||
"舰长",
|
||||
"返现",
|
||||
"抵用",
|
||||
"代金",
|
||||
"上车",
|
||||
"上反船",
|
||||
"照片",
|
||||
"素颜",
|
||||
"自拍",
|
||||
"皂片",
|
||||
"开舰",
|
||||
"上舰",
|
||||
"自画像",
|
||||
"封面",
|
||||
"取关",
|
||||
"美照",
|
||||
"随机照",
|
||||
"女装照",
|
||||
"日常照",
|
||||
"好友",
|
||||
"给主播",
|
||||
"照骗",
|
||||
"连麦",
|
||||
"情书",
|
||||
"一局",
|
||||
"舰涨优惠卷",
|
||||
"开黑",
|
||||
"test",
|
||||
"Test",
|
||||
"金币",
|
||||
"元宝",
|
||||
"代打",
|
||||
"上分",
|
||||
"上段",
|
||||
"台历",
|
||||
"一毛",
|
||||
"五毛",
|
||||
"王者荣耀",
|
||||
"玩游戏",
|
||||
"encrypt",
|
||||
"壁纸",
|
||||
"相片",
|
||||
"排位",
|
||||
"语音",
|
||||
"车位",
|
||||
"网剧",
|
||||
"一起玩",
|
||||
"一次",
|
||||
"专属头衔",
|
||||
"手游",
|
||||
"宠物",
|
||||
"蒸汽",
|
||||
"月饼",
|
||||
"加速",
|
||||
"挂件",
|
||||
"渔夫",
|
||||
"小黑屋",
|
||||
"头像",
|
||||
"许愿码",
|
||||
"电池",
|
||||
"赛车",
|
||||
"保底",
|
||||
"代币",
|
||||
"越南盾",
|
||||
"网点",
|
||||
"机器",
|
||||
"话梅",
|
||||
"志愿",
|
||||
"令牌",
|
||||
"永久",
|
||||
"第五人格",
|
||||
"大蒜",
|
||||
"唢呐",
|
||||
"皇冠",
|
||||
"徽章",
|
||||
"铜牌",
|
||||
"动物园",
|
||||
"植物",
|
||||
"钻石",
|
||||
"宝石",
|
||||
"尖叫",
|
||||
"扭蛋机",
|
||||
"点播",
|
||||
"数字版月历",
|
||||
"点歌一首",
|
||||
"体验",
|
||||
"点歌",
|
||||
"三次取关",
|
||||
"大航海",
|
||||
"3块钱之前的巨款",
|
||||
"礼金"
|
||||
]
|
||||
},
|
||||
"CapsuleLottery": {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 = [
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -11,34 +11,24 @@
|
||||
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;
|
||||
|
||||
public static function run()
|
||||
{
|
||||
if (!self::init()) {
|
||||
if (getenv('USE_HEARTBEAT') == 'false') {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -48,48 +38,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 +73,6 @@ class SmallHeart
|
||||
Live::sendGift($grey_fans_medal, $gift, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -128,168 +84,12 @@ 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 (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;
|
||||
$metal = self::$fans_medals[array_rand(self::$fans_medals)];
|
||||
$interval = self::xliveHeartBeatTask($metal['roomid'], 999, 999);
|
||||
if ($interval != 0) {
|
||||
self::$total_time += $interval;
|
||||
}
|
||||
self::$interval = $interval == 0 ? 60 : $interval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
243
src/util/XliveHeartBeat.php
Normal file
243
src/util/XliveHeartBeat.php
Normal file
@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2021 ~ 2022
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Util;
|
||||
|
||||
use BiliHelper\Core\Curl;
|
||||
use BiliHelper\Core\Log;
|
||||
use BiliHelper\Plugin\Live;
|
||||
use BiliHelper\Plugin\User;
|
||||
use BiliHelper\Tool\Generator;
|
||||
|
||||
trait XliveHeartBeat
|
||||
{
|
||||
|
||||
protected static $_data = ['id' => []]; // 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user