From a0cb551b96f6d691a3855e5f725f0d0f2dfc43f8 Mon Sep 17 00:00:00 2001 From: Lkeme <19500576+lkeme@users.noreply.github.com> Date: Mon, 6 Jun 2022 15:43:40 +0800 Subject: [PATCH] [feat] Judge --- plugin/Judge/Judge.php | 352 ++++++++++++++++++++++++++++++++ profile/example/config/user.ini | 5 + src/Api/Credit/ApiJury.php | 179 ++++++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 plugin/Judge/Judge.php create mode 100644 src/Api/Credit/ApiJury.php diff --git a/plugin/Judge/Judge.php b/plugin/Judge/Judge.php new file mode 100644 index 0000000..12490ab --- /dev/null +++ b/plugin/Judge/Judge.php @@ -0,0 +1,352 @@ + __CLASS__, // hook + 'name' => 'Judge', // 插件名称 + 'version' => '0.0.1', // 插件版本 + 'desc' => '風機委員', // 插件描述 + 'author' => 'Lkeme',// 作者 + 'priority' => 1126, // 插件优先级 + 'cycle' => '15-30(分钟)', // 运行周期 + ]; + + /** + * @var array + */ + protected array $wait_case = []; + + // https://www.bilibili.com/judgement/index + + // 评论 case_type: 1 default_vote: 4 + // 0: {vote: 1, vote_text: "合适"} + // 1: {vote: 2, vote_text: "一般"} + // 2: {vote: 3, vote_text: "不合适"} + // 3: {vote: 4, vote_text: "无法判断"} + + // 弹幕氛围 case_type: 4 default_vote: 14 + // 0: {vote: 11, vote_text: "好"} + // 1: {vote: 12, vote_text: "普通"} + // 2: {vote: 13, vote_text: "差"} + // 3: {vote: 14, vote_text: "无法判断"} + + /** + * @param Plugin $plugin + */ + public function __construct(Plugin &$plugin) + { + // + TimeLock::initTimeLock(); +// // 需要缓存 +// Cache::initCache(); + // $this::class + $plugin->register($this, 'execute'); + } + + /** + * @use 执行 + * @return void + */ + public function execute(): void + { + if (TimeLock::getTimes() > time() || !getEnable('judge')) return; + // 资格判断 没有资格就60-120分钟后计息 不排除其他错误 + if (!$this->juryInfo()) { + TimeLock::setTimes(mt_rand(60, 120) * 60); + return; + } + // + $this->judgementTask(); + // 如果没有设置时间 就设置个默认时间 可能在一秒钟内处理完 所以 <= + if (TimeLock::getTimes() <= time()) { + TimeLock::setTimes(mt_rand(15, 30) * 60); + } + } + + /** + * @use 審判任務 + * @return void + */ + protected function judgementTask(): void + { + if (empty($this->wait_case)) { + // 獲取 + $cid = $this->caseObtain(); + $this->caseCheck($cid); + } else { + // 執行 + $case = array_pop($this->wait_case); + $this->vote($case['id'], $case['vote']); + } + } + + /** + * @use 案件核查 + * @param string $case_id + * @return bool + */ + protected function caseCheck(string $case_id): bool + { + if ($case_id == '') return true; + // 獲取詳情失敗 + $case_info = $this->caseInfo($case_id); + if (empty($case_info)) return true; + // 獲取衆議論失敗 + $case_opinion = $this->caseOpinion($case_id); + if (empty($case_opinion)) { + $vote_info = $case_info[$this->probability()]; + } else { + $vote_info = $case_opinion[array_rand($case_opinion)]; + } + // + $vote = $vote_info['vote']; + $vote_text = $vote_info['vote_text']; + $this->wait_case[] = ['id' => $case_id, 'vote' => $vote]; + Log::info("風機委員: 案件{$case_id}的預測投票結果 $vote($vote_text)"); + // 尝试修复25018 未测试 + $this->vote($case_id, 0); + // + TimeLock::setTimes(60 + 5); + return false; + } + + /** + * @use 投票 + * @param string $case_id + * @param int $vote + */ + private static function vote(string $case_id, int $vote): void + { + // {"code":0,"message":"0","ttl":1} + // {"code":25018,"message":"不能进行此操作","ttl":1} + $response = ApiJury::vote($case_id, $vote, '', 0, array_rand([0, 1])); + + if ($response['code']) { + Log::warning("風機委員: 案件{$case_id}投票失败 {$response['code']} -> {$response['message']}"); + } else { + Log::notice("風機委員: 案件{$case_id}投票成功"); + } + } + + /** + * @use 隨機整數 + * @param int $max + * @return string + */ + protected function randInt(int $max = 17): string + { + $temp = []; + foreach (range(1, $max) as $ignored) { + $temp[] = mt_rand(0, 9); + } + return implode("", $temp); + } + + /** + * @use 概率 + * @return int + */ + protected function probability(): int + { + $result = 0; + $prize_arr = [0 => 25, 1 => 40, 2 => 25, 3 => 10]; + // 概率数组的总概率精度 + $sum = array_sum($prize_arr); + // 概率数组循环 + foreach ($prize_arr as $key => $value) { + if (mt_rand(1, $sum) <= $value) { + $result = $key; + break; + } + $sum -= $value; + } + return $result; + } + + /** + * @use 获取衆議觀點 + * @param string $case_id + * @return array + */ + protected function caseOpinion(string $case_id): array + { + // {"code":0,"message":"0","ttl":1,"data":{"total":438,"list":[]}} + $response = ApiJury::caseOpinion($case_id); + // + if ($response['code']) { + Log::warning("風機委員: 獲取案件{$case_id}衆議觀點失敗 {$response['code']} -> {$response['message']}"); + return []; + } + return $response['data']['list']; + } + + /** + * @use 获取案例详情 + * @param string $case_id + * @return mixed + */ + protected function caseInfo(string $case_id): array + { + // {"code":0,"message":"0","ttl":1,"data":{"case_id":"","case_type":1,"vote_items":[{"vote":1,"vote_text":"合适"},{"vote":2,"vote_text":"一般"},{"vote":3,"vote_text":"不合适"},{"vote":4,"vote_text":"无法判断"}],"default_vote":4,"status":0,"origin_start":0,"avid":,"cid":,"vote_cd":5,"case_info":{"comment":{"uname":"用户1","face":"xxxx"},"danmu_img":""}}} + $response = ApiJury::caseInfo($case_id); + // + if ($response['code']) { + Log::warning("風機委員: 獲取案件{$case_id}詳情失敗 {$response['code']} -> {$response['message']}"); + return []; + } + return $response['data']['vote_items']; + } + + /** + * @use 获取案件任务 + * @return string + */ + protected function caseObtain(): string + { + // {"code":0,"message":"0","ttl":1,"data":{"case_id":"AC1xx411c7At"}} + // {"code":25008,"message":"真给力 , 移交众裁的举报案件已经被处理完了","ttl":1} + // {"code":25014,"message":"25014","ttl":1} + // {"code":25005,"message":"请成为風機委員后再试","ttl":1} + // {"code":25006,"message":"風機委員资格已过期","ttl":1} + $response = ApiJury::caseNext(); + // + switch ($response['code']) { + case 0: + $cid = $response['data']['case_id']; + Log::info("風紀委員: 获取案例ID成功 $cid ~"); + return $cid; + case 25005: + Log::warning("風紀委員: 获取案例ID失敗 {$response['code']} -> {$response['message']}"); + TimeLock::setTimes(TimeLock::timing(10)); + break; + case 25006: + Log::warning("風紀委員: 获取案例ID失敗 {$response['code']} -> {$response['message']}"); + TimeLock::setTimes(TimeLock::timing(10)); + Notice::push('jury_leave_office', $response['message']); + break; + case 25008: + Log::info("風紀委員: {$response['message']}"); + break; + case 25014: + Log::info("風紀委員: 今日案件已審滿,感謝您對社區的貢獻,明天再來看看吧~"); + TimeLock::setTimes(TimeLock::timing(7, 0, 0, true)); + break; + default: + Log::warning("風紀委員: 获取案例ID失敗 {$response['code']} -> {$response['message']}"); + break; + } + return ''; + } + + + /** + * @use 陪審團信息 + * @return bool + */ + protected function juryInfo(): bool + { + // {"code":25005,"message":"请成为風機委員后再试","ttl":1} + // {"code":0,"message":"0","ttl":1,"data":{"uname":"","face":"http://i2.hdslb.com/bfs/face/.jpg","case_total":,"term_end":,"status":1}} + $response = ApiJury::jury(); + // + if ($response['code']) return false; +// "status": 1 理论正常 +// "status": 2, 没有资格 +// "apply_status": -1 已经卸任但未连任 +// "apply_status": 0 申请连任后 +// "apply_status": 5 审核连任中 +// "apply_status": 3 连任成功后 +// "apply_status": 4 申请连任失败(?) + // 理论上正常 + if ($response['data']['status'] == 1) { + Log::info('風機委員: 當前可以參與社區衆裁,共創良好環境哦~'); + return true; + } + // 只是嘗試 TODO 更換位置 + if ($response['data']['apply_status'] == -1 && getConf('judge.auto_apply', false, 'bool')) { + $this->juryApply(); + } + // + Log::warning('風機委員: 當前沒有審判資格哦~'); + // + return false; + } + + /** + * @use 申請連任資格 + * @return void + */ + protected function juryApply(): void + { + // {"code":0,"message":"0","ttl":1} + $response = ApiJury::juryApply(); + if ($response['code']) { + Log::warning("風機委員: 申請連任提交失敗 {$response['code']} -> {$response['message']}"); + } else { + Log::notice('風機委員: 申請連任提交成功'); + Notice::push('jury_auto_apply', '提交連任申請成功'); + } + } + + /** + * @use 获取案例數據 + * @return bool + */ + private static function judgementIndex(): bool + { + $response = ApiJury::caseList(); + if ($response['code']) { + Log::info("風紀委員: 獲取案例數據失敗 {$response['code']} -> {$response['message']}"); + return false; + } + // + $data = $response['data']; + $today = date("Y-m-d"); + $sum_cases = 0; + $valid_cases = 0; + $judging_cases = 0; + foreach ($data as $case) { + $ts = $case['voteTime'] / 1000; + $vote_day = date("Y-m-d", $ts); + if ($vote_day == $today) { + $sum_cases += 1; + $vote = $case['vote']; + if ($vote) { + $valid_cases += 1; + } else { + $judging_cases += 1; + } + } + } + Log::info("風紀委員: 今日投票{$sum_cases}({$valid_cases}票有效(非棄權),{$judging_cases}票还在进行中)"); + return true; + } +} + \ No newline at end of file diff --git a/profile/example/config/user.ini b/profile/example/config/user.ini index e831c41..ac5e26a 100644 --- a/profile/example/config/user.ini +++ b/profile/example/config/user.ini @@ -60,6 +60,11 @@ bet = 1 [silver2coin] enable = true +; 風機委員/自動連任/需要實名 +[judge] +enable = false +auto_apply = false + ####################### # 通知设置 # ####################### diff --git a/src/Api/Credit/ApiJury.php b/src/Api/Credit/ApiJury.php new file mode 100644 index 0000000..e367a5c --- /dev/null +++ b/src/Api/Credit/ApiJury.php @@ -0,0 +1,179 @@ + 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":25005,"message":"请成为風機委員后再试","ttl":1} + // {"code":0,"message":"0","ttl":1,"data":{"uname":"","face":"http://i2.hdslb.com/bfs/face/.jpg","case_total":,"term_end":,"status":1}} + return Request::getJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 申請連任 + * @return array + */ + public static function juryApply(): array + { + $user = User::parseCookie(); + // + $url = 'https://api.bilibili.com/x/credit/v2/jury/apply'; + $payload = [ + "csrf" => $user['csrf'], + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":0,"message":"0","ttl":1} + return Request::postJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 獲取案件任務 + * @return array + */ + public static function caseNext(): array + { + $url = 'https://api.bilibili.com/x/credit/v2/jury/case/next'; + $payload = []; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":0,"message":"0","ttl":1,"data":{"case_id":"AC1xx411c7At"}} + // {"code":25008,"message":"真给力 , 移交众裁的举报案件已经被处理完了","ttl":1} + // {"code":25014,"message":"25014","ttl":1} + // {"code":25005,"message":"请成为風機委員后再试","ttl":1} + // {"code":25006,"message":"風機委員资格已过期","ttl":1} + return Request::getJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 案件信息 + * @param string $case_id + * @return array + */ + public static function caseInfo(string $case_id): array + { + $url = 'https://api.bilibili.com/x/credit/v2/jury/case/info'; + $payload = [ + 'case_id' => $case_id, + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":0,"message":"0","ttl":1,"data":{"case_id":"","case_type":1,"vote_items":[{"vote":1,"vote_text":"合适"},{"vote":2,"vote_text":"一般"},{"vote":3,"vote_text":"不合适"},{"vote":4,"vote_text":"无法判断"}],"default_vote":4,"status":0,"origin_start":0,"avid":,"cid":,"vote_cd":5,"case_info":{"comment":{"uname":"用户1","face":"xxxx"},"danmu_img":""}}} + return Request::getJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 衆議觀點 + * @param string $case_id + * @param int $pn + * @param int $ps + * @return array + */ + public static function caseOpinion(string $case_id, int $pn = 1, int $ps = 20): array + { + $url = 'https://api.bilibili.com/x/credit/v2/jury/case/opinion'; + $payload = [ + 'case_id' => $case_id, + 'pn' => $pn, + 'ps' => $ps + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":0,"message":"0","ttl":1,"data":{"total":438,"list":[]}} + return Request::getJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 投票 + * @param string $case_id + * @param int $vote + * @param string $content + * @param int $anonymous + * @param int $insiders + * @return array + */ + public static function vote(string $case_id, int $vote, string $content = '', int $anonymous = 0, int $insiders = 0): array + { + $user = User::parseCookie(); + // + $url = 'https://api.bilibili.com/x/credit/v2/jury/vote'; + $payload = [ + 'case_id' => $case_id, # 案件id + 'vote' => $vote, # 投票选项 + 'content' => $content, # 内容 + 'anonymous' => $anonymous, # 是否匿名 + 'insiders' => $insiders, # 是否观看 + 'csrf' => $user['csrf'], # 验证 + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => 'https://www.bilibili.com/', + ]; + // {"code":0,"message":"0","ttl":1} + // {"code":25018,"message":"不能进行此操作","ttl":1} + return Request::postJson(true, 'pc', $url, $payload, $headers); + } + + /** + * @use 案件列表 + * @param int $pn + * @param int $ps + * @return array + */ + public static function caseList(int $pn = 1, int $ps = 25): array + { + $url = 'https://api.bilibili.com/x/credit/jury/caseList'; + $payload = [ + 'pn' => $pn, + 'ps' => $ps, + '_' => time() + ]; + $headers = [ + 'origin' => 'https://www.bilibili.com', + 'referer' => "https://www.bilibili.com/judgement/index" + ]; + return Request::getJson(true, 'pc', $url, $payload, $headers); + } + +} + + \ No newline at end of file