BiliHelper-personal/src/plugin/Live.php
2021-10-05 10:58:13 +08:00

525 lines
18 KiB
PHP

<?php
/**
* Website: https://mudew.com/
* Author: Lkeme
* License: The MIT License
* Email: Useri@live.cn
* Updated: 2021 ~ 2022
*/
namespace BiliHelper\Plugin;
use BiliHelper\Core\Log;
use BiliHelper\Core\Curl;
use BiliHelper\Util\TimeLock;
use JetBrains\PhpStorm\ArrayShape;
class Live
{
use TimeLock;
/**
* @use 获取分区列表
* @return array
*/
public static function fetchLiveAreas(): array
{
$areas = [];
$url = "https://api.live.bilibili.com/room/v1/Area/getList";
$payload = [];
$raw = Curl::get('other', $url, $payload);
$de_raw = json_decode($raw, true);
// 防止异常
if (!isset($de_raw['data']) || $de_raw['code']) {
Log::warning("获取直播分区异常: " . $de_raw['msg']);
$areas = range(1, 6);
} else {
foreach ($de_raw['data'] as $area) {
array_push($areas, $area['id']);
}
}
return $areas;
}
/**
* @use AREA_ID转ROOM_ID
* @param $area_id
* @return array
*/
#[ArrayShape(['area_id' => "", 'room_id' => "int|mixed"])]
public static function areaToRid($area_id): array
{
$url = "https://api.live.bilibili.com/room/v1/area/getRoomList";
$payload = [
'platform' => 'web',
'parent_area_id' => $area_id,
'cate_id' => 0,
'area_id' => 0,
'sort_type' => 'online',
'page' => 1,
'page_size' => 30
];
$raw = Curl::get('other', $url, $payload);
$de_raw = json_decode($raw, true);
// 防止异常
if (!isset($de_raw['data']) || $de_raw['code'] || count($de_raw['data']) == 0) {
Log::warning("获取直播分区异常: " . $de_raw['msg']);
$area_info = [
'area_id' => $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
*/
public static function getUserRecommend(): int
{
$url = 'https://api.live.bilibili.com/room/v1/Area/getListByAreaID';
$payload = [
'areaId' => 0,
'sort' => 'online',
'pageSize' => 30,
'page' => 1
];
$raw = Curl::get('other', $url, $payload);
$de_raw = json_decode($raw, true);
// print_r($de_raw);
if ($de_raw['code'] != '0') {
return 23058;
}
return $de_raw['data'][mt_rand(1, 29)]['roomid'];
}
/**
* @use 获取直播房间号
* @param $room_id
* @param bool $uid
* @return mixed
*/
public static function getRealRoomID($room_id, bool $uid = false): mixed
{
$room_infos = [];
// 缓存开始 如果存在就赋值 否则默认值
if ($temp = getCache('room_infos')) {
$room_infos = $temp;
}
// 取缓存
if (isset($room_infos[strval($room_id)])) {
$data = $room_infos[strval($room_id)];
} else {
// 默认数据
$_data = ['uid' => false, 'room_id' => false];
// TODO 优化
$data = self::getRoomInfoV1($room_id);
if (!isset($data['code']) || !isset($data['data'])) {
// 访问错误
$data = $_data;
} elseif ($data['code']) {
// 访问错误
$data = $_data;
Log::warning($room_id . ' : ' . $data['msg']);
} elseif ($data['data']['is_hidden']) {
// 隐藏
$data = $_data;
} elseif ($data['data']['is_locked']) {
// 锁定
$data = $_data;
} elseif ($data['data']['encrypted']) {
// 加密
$data = $_data;
} else {
// 有效
$data = [
'uid' => $data['data']['uid'],
'room_id' => $data['data']['room_id'],
];
}
// 推入缓存前
$room_infos[strval($room_id)] = $data;
}
// 缓存结束 需要的数据的放进缓存
setCache('room_infos', $room_infos);
// 如果需要UID
if ($uid) return $data;
// 否
return $data['room_id'];
}
/**
* @use 获取直播间信息
* @param $room_id
* @return array
*/
public static function getRoomInfoV1($room_id): array
{
$url = 'https://api.live.bilibili.com/room/v1/Room/room_init';
$payload = [
'id' => $room_id
];
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 获取直播间信息
* @param $room_id
* @return array
*/
public static function getRoomInfoV2($room_id): array
{
$url = ' https://api.live.bilibili.com/room/v1/Room/get_info_by_id';
$payload = [
'ids[]' => $room_id
];
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 获取弹幕配置
* @param $room_id
* @return array
*/
public static function getDanMuConf($room_id): array
{
$url = 'https://api.live.bilibili.com/room/v1/Danmu/getConf';
$payload = [
'room_id' => $room_id,
'platform' => 'pc',
'player' => 'web'
];
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 获取配置信息
* @param $room_id
* @return array
*/
#[ArrayShape(['addr' => "mixed|string", 'token' => "mixed|string"])]
public static function getDanMuInfo($room_id): array
{
$data = self::getDanMuConf($room_id);
if (isset($data['data']['host_server_list'][0]['host'])) {
$server = $data['data']['host_server_list'][0];
$addr = "tcp://{$server['host']}:{$server['port']}/sub";
} else {
$addr = getConf('server_addr', 'zone_monitor');
}
return [
'addr' => $addr,
'token' => $data['data']['token'] ?? '',
];
}
/**
* @use web端获取直播间信息
* @param $room_id
* @return array
*/
public static function webGetRoomInfo($room_id): array
{
$url = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom';
$payload = [
'room_id' => $room_id
];
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 钓鱼检测
* @param $room_id
* @return bool
*/
public static function fishingDetection($room_id): bool
{
if (self::getRealRoomID($room_id)) {
return false;
}
return true;
}
/**
* @use 访问直播间
* @param $room_id
* @return bool
*/
public static function goToRoom($room_id): bool
{
$url = 'https://api.live.bilibili.com/room/v1/Room/room_entry_action';
$payload = [
'room_id' => $room_id,
];
// Log::info('进入直播间[' . $room_id . ']抽奖!');
Curl::post('app', $url, Sign::common($payload));
return true;
}
/**
* @use 发送弹幕pc
* @param int $room_id
* @param string $content
* @return array
*/
public static function sendBarragePC(int $room_id, string $content): array
{
$room_id = self::getRealRoomID($room_id);
if (!$room_id) {
return ['code' => 404, 'message' => '直播间数据异常'];
}
$url = 'https://api.live.bilibili.com/msg/send';
$payload = [
'color' => '16777215',
'fontsize' => 25,
'mode' => 1,
'msg' => $content,
'rnd' => 0,
'bubble' => 0,
'roomid' => $room_id,
'csrf' => getCsrf(),
'csrf_token' => getCsrf(),
];
$headers = [
'origin' => 'https://live.bilibili.com',
'referer' => "https://live.bilibili.com/$room_id"
];
$raw = Curl::post('pc', $url, $payload, $headers);
// {"code":0,"data":[],"message":"","msg":""}
return json_decode($raw, true) ?? ['code' => 404, 'msg' => '上层数据为空!'];
}
/**
* @use 发送弹幕app
* @param int $room_id
* @param string $content
* @return array
*/
public static function sendBarrageAPP(int $room_id, string $content): array
{
$room_id = self::getRealRoomID($room_id);
if (!$room_id) {
return ['code' => 404, 'message' => '直播间数据异常'];
}
$url = 'https://api.live.bilibili.com/msg/send';
$payload = [
'color' => '16777215',
'fontsize' => 25,
'mode' => 1,
'msg' => $content,
'rnd' => 0,
'roomid' => $room_id,
'csrf' => getCsrf(),
'csrf_token' => getCsrf(),
];
$raw = Curl::post('app', $url, Sign::common($payload));
return json_decode($raw, true) ?? ['code' => 404, 'msg' => '上层数据为空!'];
}
/**
* @use 获取勋章列表
* @param int $page_size
* @return array
*/
public static function fetchMedalList(int $page_size = 10): array
{
$metal_list = [];
for ($i = 1; $i <= 100; $i++) {
// https://live.bilibili.com/p/html/live-app-fansmedal-manange/index.html
// $url = 'https://api.live.bilibili.com/fans_medal/v5/live_fans_medal/iApiMedal';
$url = 'https://api.live.bilibili.com/i/api/medal';
// TODO size变小 需要优化获取逻辑 可能会412
$payload = [
'page' => $i,
'pageSize' => $page_size
];
$raw = Curl::get('app', $url, Sign::common($payload));
$de_raw = json_decode($raw, true);
if (isset($data['code']) && $data['code']) {
Log::warning('获取勋章列表失败!', ['msg' => $data['message']]);
return $metal_list;
}
if (empty($de_raw['data']['fansMedalList'])) {
return $metal_list;
}
if (isset($de_raw['data']['fansMedalList'])) {
foreach ($de_raw['data']['fansMedalList'] as $vo) {
array_push($metal_list, $vo);
}
}
if ($de_raw['data']['pageinfo']['totalpages'] == $de_raw['data']['pageinfo']['curPage']) {
return $metal_list;
}
}
Log::info('勋章列表获取成功!');
return $metal_list;
}
/**
* @use 背包获取单项礼物
* @param string $gift_name
* @param int $gift_id
* @return array
*/
public static function fetchBagListByGift(string $gift_name, int $gift_id): array
{
$new_bag_list = [];
$payload = [];
$url = 'https://api.live.bilibili.com/gift/v2/gift/bag_list';
$data = Curl::get('app', $url, Sign::common($payload));
$data = json_decode($data, true);
if (isset($data['code']) && $data['code']) {
Log::warning('背包查看失败!', ['msg' => $data['message']]);
return $new_bag_list;
}
if (isset($data['data']['list'])) {
$bag_list = $data['data']['list'];
if (count($bag_list)) {
// 按过期时间 升序
// array_multisort(array_column($bag_list, "gift_id"), SORT_DESC, $bag_list);
array_multisort(array_column($bag_list, "expire_at"), SORT_ASC, $bag_list);
}
foreach ($bag_list as $vo) {
// 去除永久礼物
if ($vo['corner_mark'] == '永久') continue;
if ($vo['gift_id'] == $gift_id && $vo['gift_name'] == $gift_name) {
array_push($new_bag_list, $vo);
}
}
}
return $new_bag_list;
}
/**
* @use 赠送礼物
* @param array $guest // 用户信息
* @param array $gift // 礼物信息
* @param int $num // 数量
*/
public static function sendGift(array $guest, array $gift, int $num)
{
$url = 'https://api.live.bilibili.com/gift/v2/live/bag_send';
$payload = [
'uid' => getUid(), // 自己的UID
'gift_id' => $gift['gift_id'],
'ruid' => $guest['uid'], // UP的UID
'send_ruid' => 0,
'gift_num' => $num,
'bag_id' => $gift['bag_id'],
'platform' => 'pc',
'biz_code' => 'live',
'biz_id' => $guest['roomid'], // UP的直播间
'rnd' => time(), // 时间戳
'storm_beat_id' => 0,
'metadata' => '',
'price' => 0,
'csrf' => getCsrf(),
'csrf_token' => getCsrf()
];
// {"code":0,"msg":"success","message":"success","data":{"tid":"1595419985112400002","uid":4133274,"uname":"沙奈之朵","face":"https://i2.hdslb.com/bfs/face/eb101ef90ebc4e9bf79f65312a22ebac84946700.jpg","guard_level":0,"ruid":893213,"rcost":30834251,"gift_id":30607,"gift_type":5,"gift_name":"小心心","gift_num":1,"gift_action":"投喂","gift_price":5000,"coin_type":"silver","total_coin":5000,"pay_coin":5000,"metadata":"","fulltext":"","rnd":"1595419967","tag_image":"","effect_block":1,"extra":{"wallet":null,"gift_bag":{"bag_id":210196588,"gift_num":20},"top_list":[],"follow":null,"medal":null,"title":null,"pk":{"pk_gift_tips":"","crit_prob":0},"fulltext":"","event":{"event_score":0,"event_redbag_num":0},"capsule":null},"blow_switch":0,"send_tips":"赠送成功","gift_effect":{"super":0,"combo_timeout":0,"super_gift_num":0,"super_batch_gift_num":0,"batch_combo_id":"","broadcast_msg_list":[],"small_tv_list":[],"beat_storm":null,"smallTVCountFlag":true},"send_master":null,"crit_prob":0,"combo_stay_time":3,"combo_total_coin":0,"demarcation":2,"magnification":1,"combo_resources_id":1,"is_special_batch":0,"send_gift_countdown":6}}
$data = Curl::post('app', $url, Sign::common($payload));
$data = json_decode($data, true);
if (isset($data['code']) && $data['code']) {
Log::warning('送礼失败!', ['msg' => $data['message']]);
} else {
Log::notice("成功向 {$payload['biz_id']} 投喂了 $num{$gift['gift_name']}");
}
}
/**
* @use 获取分区直播间
* @param int $parent_area_id
* @param int $area_id
* @param int $page
* @return array
*/
public static function getAreaRoomList(int $parent_area_id, int $area_id, int $page = 1): array
{
$url = 'https://api.live.bilibili.com/xlive/web-interface/v1/second/getList';
$payload = [
'platform' => 'web',
'parent_area_id' => $parent_area_id,
'area_id' => $area_id,
'sort_type' => 'online',
'page' => $page
];
$raw = Curl::get('other', $url, $payload);
$de_raw = json_decode($raw, true);
$room_ids = [];
if ($de_raw['code'] == 0) {
foreach ($de_raw['data']['list'] as $room) {
array_push($room_ids, $room['roomid']);
}
}
return $room_ids;
}
/**
* @use 获取用户卡片
* @param int $mid
* @return array
*/
public static function getMidCard(int $mid): array
{
$url = 'https://api.bilibili.com/x/web-interface/card';
$payload = [
'mid' => $mid,
];
//{"code":0,"message":"0","ttl":1,"data":{"card":{"mid":"1","name":"bishi","approve":false,"sex":"男","rank":"10000","face":"http://i1.hdslb.com/bfs/face/34c5b30a990c7ce4a809626d8153fa7895ec7b63.gif","DisplayRank":"0","regtime":0,"spacesta":0,"birthday":"","place":"","description":"","article":0,"attentions":[],"fans":154167,"friend":5,"attention":5,"sign":"","level_info":{"current_level":4,"current_min":0,"current_exp":0,"next_exp":0},"pendant":{"pid":0,"name":"","image":"","expire":0,"image_enhance":"","image_enhance_frame":""},"nameplate":{"nid":0,"name":"","image":"","image_small":"","level":"","condition":""},"Official":{"role":0,"title":"","desc":"","type":-1},"official_verify":{"type":-1,"desc":""},"vip":{"type":2,"status":1,"due_date":1727625600000,"vip_pay_type":1,"theme_type":0,"label":{"path":"","text":"年度大会员","label_theme":"annual_vip","text_color":"#FFFFFF","bg_style":1,"bg_color":"#FB7299","border_color":""},"avatar_subscript":1,"nickname_color":"#FB7299","role":3,"avatar_subscript_url":"http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png","vipType":2,"vipStatus":1}},"following":false,"archive_count":2,"article_count":0,"follower":154167}}
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 获取用户状态
* @param int $mid
* @return array
*/
public static function getMidStat(int $mid): array
{
$url = 'https://api.bilibili.com/x/relation/stat';
$payload = [
'vmid' => $mid,
];
// {"code":0,"message":"0","ttl":1,"data":{"mid":50329118,"following":62,"whisper":0,"black":0,"follower":7610241}}
$raw = Curl::get('other', $url, $payload);
return json_decode($raw, true);
}
/**
* @use 获取用户关注数
* @param int $mid
* @return int
*/
public static function getMidFollower(int $mid): int
{
$follower = 0;
// root->data->follower
if (mt_rand(0, 10) > 5) {
$data = self::getMidStat($mid);
} else {
$data = self::getMidCard($mid);
}
if (isset($data['code']) && $data['code']) {
Log::warning("获取用户资料卡片失败: CODE -> {$data['code']} MSG -> {$data['message']} ");
} else {
// root->data->follower
$follower = $data['data']['follower'];
}
return $follower;
}
}