mirror of
https://github.com/shanmiteko/LotteryAutoScript.git
synced 2026-06-04 21:01:17 +08:00
Some checks failed
Build and push Docker images / docker (push) Has been cancelled
Mirror and run GitLab CI / build (push) Has been cancelled
Package Node.js project into an executable / node${{ matrix.nodev }}-${{ matrix.platform }}-x64 (18, linux) (push) Has been cancelled
Package Node.js project into an executable / node${{ matrix.nodev }}-${{ matrix.platform }}-x64 (18, macos) (push) Has been cancelled
Package Node.js project into an executable / node${{ matrix.nodev }}-${{ matrix.platform }}-x64 (18, win) (push) Has been cancelled
Package Node.js project into an executable / node18-${{ matrix.platform }}-arm64 (alpine) (push) Has been cancelled
Package Node.js project into an executable / node18-${{ matrix.platform }}-arm64 (linux) (push) Has been cancelled
Package Node.js project into an executable / node18-${{ matrix.platform }}-arm64 (linuxstatic) (push) Has been cancelled
Fixed #447 * fix:oldparseDynamicCard已经无法获取是否抽奖 使用新版api * 当 offset 为 '0'(初始页)时,传入 offset 会报错 * 小修
839 lines
33 KiB
JavaScript
839 lines
33 KiB
JavaScript
const utils = require('../utils');
|
||
const bili = require('../net/bili');
|
||
const { send } = require('../net/http');
|
||
const { check_if_duplicated, article_scan_page, article_create_time, not_check_article, get_dynamic_detail_wait, uid_scan_page, search_wait, tag_scan_page } = require('../data/config');
|
||
const d_storage = require('../helper/d_storage');
|
||
|
||
const { log } = utils;
|
||
|
||
/**
|
||
* 解析dynamic_detail_card
|
||
* 提取出的有用动态信息
|
||
* @typedef {object} UsefulDynamicInfo
|
||
* @property {number} uid
|
||
* @property {string} uname
|
||
* @property {boolean} is_liked
|
||
* @property {number} create_time 10
|
||
* @property {string} rid_str
|
||
* @property {number} chat_type
|
||
* @property {string} dynamic_id
|
||
* @property {number} type
|
||
* @property {string} description
|
||
* @property {string} reserve_id
|
||
* @property {string} reserve_lottery_text
|
||
* @property {boolean} is_charge_lottery
|
||
* @property {boolean} hasOfficialLottery
|
||
* @property {Array<Object.<string,string|number>>} ctrl
|
||
* @property {number} origin_create_time 10
|
||
* @property {number} origin_uid
|
||
* @property {string} origin_uname
|
||
* @property {string} origin_rid_str
|
||
* @property {number} origin_chat_type
|
||
* @property {string} origin_dynamic_id
|
||
* @property {number} origin_type
|
||
* @property {string} origin_description
|
||
* @property {string} origin_reserve_id
|
||
* @property {string} origin_reserve_lottery_text
|
||
* @property {boolean} origin_is_charge_lottery
|
||
* @property {boolean} origin_hasOfficialLottery
|
||
*
|
||
* 整理后的抽奖信息
|
||
* @typedef {object} LotteryInfo
|
||
* @property {string} lottery_info_type
|
||
* @property {number} create_time
|
||
* @property {boolean} is_liked
|
||
* @property {number[]} uids `[uid,ouid]`
|
||
* @property {string} uname
|
||
* @property {Array<{}>} ctrl
|
||
* @property {string} dyid
|
||
* @property {string} reserve_id
|
||
* @property {string} reserve_lottery_text
|
||
* @property {boolean} is_charge_lottery
|
||
* @property {string} rid
|
||
* @property {number} chat_type
|
||
* @property {string} des
|
||
* @property {number} type
|
||
* @property {boolean} hasOfficialLottery 是否官方
|
||
*
|
||
* @param {object} data
|
||
* @return {UsefulDynamicInfo}
|
||
*/
|
||
function parseDynamicCard(data) {
|
||
if (data?.card?.desc?.uid) {
|
||
return oldParseDynamicCard(data?.card);
|
||
}
|
||
|
||
// 如果是多个 items,返回一个数组
|
||
if (Array.isArray(data?.items)) {
|
||
return data.items.map(item => parseDynamicCard({ item }));
|
||
}
|
||
|
||
let ditem = data?.item;
|
||
/**临时储存单个动态中的信息 */
|
||
let obj = {};
|
||
try {
|
||
const dy_typeenum2num = new Map([
|
||
['DYNAMIC_TYPE_FORWARD', 1],
|
||
['DYNAMIC_TYPE_DRAW', 2],
|
||
['DYNAMIC_TYPE_WORD', 4],
|
||
['DYNAMIC_TYPE_AV', 8],
|
||
['DYNAMIC_TYPE_ARTICLE', 64]
|
||
]);
|
||
const dy_type2chat_type = new Map([
|
||
['DYNAMIC_TYPE_FORWARD', 17],
|
||
['DYNAMIC_TYPE_DRAW', 11],
|
||
['DYNAMIC_TYPE_WORD', 17],
|
||
['DYNAMIC_TYPE_AV', 1],
|
||
['DYNAMIC_TYPE_ARTICLE', 12]
|
||
]);
|
||
/* 转发者的UID */
|
||
obj.uid = ditem?.modules?.module_author?.mid || 0;
|
||
/* 转发者的name */
|
||
obj.uname = ditem?.modules?.module_author?.name || '';
|
||
/* 动态是否点过赞 */
|
||
obj.is_liked = ditem?.modules?.module_stat?.like?.status || false;
|
||
/* 动态的ts10 */
|
||
obj.create_time = ditem?.modules?.module_author?.pub_ts || 0;
|
||
/* 动态类型 */
|
||
obj.type = dy_typeenum2num.get(ditem?.type) || 0;
|
||
/* 用于发送评论 */
|
||
obj.rid_str = ditem?.basic?.comment_id_str || '';
|
||
/* 用于发送评论 */
|
||
obj.chat_type = ditem?.basic?.comment_type || 0;
|
||
/* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */
|
||
obj.dynamic_id = ditem?.id_str || '';
|
||
/* 定位@信息 */
|
||
obj.ctrl = [];
|
||
/* 是否有官方抽奖 */
|
||
obj.hasOfficialLottery = false;
|
||
/* 转发描述 */
|
||
obj.description = '';
|
||
let _total_len = 0;
|
||
if (Array.isArray(ditem?.modules?.module_dynamic?.desc?.rich_text_nodes)) {
|
||
ditem?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => {
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_AT') {
|
||
obj.ctrl.push({
|
||
data: node.rid,
|
||
location: _total_len,
|
||
length: node.text.length,
|
||
type: 1
|
||
});
|
||
}
|
||
/* 是否有官方抽奖 */
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
||
obj.hasOfficialLottery = true;
|
||
}
|
||
obj.description += node.orig_text;
|
||
_total_len += node.text.length;
|
||
});
|
||
} else {
|
||
ditem?.modules?.module_dynamic?.major?.opus?.summary?.rich_text_nodes.forEach(node => {
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_AT') {
|
||
obj.ctrl.push({
|
||
data: node.rid,
|
||
location: _total_len,
|
||
length: node.text.length,
|
||
type: 1
|
||
});
|
||
}
|
||
/* 是否有官方抽奖 */
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
||
obj.hasOfficialLottery = true;
|
||
}
|
||
obj.description += node.orig_text;
|
||
_total_len += node.text.length;
|
||
});
|
||
}
|
||
/* 预约抽奖信息 */
|
||
obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0;
|
||
obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失';
|
||
/* 充电抽奖 */
|
||
if (ditem?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') {
|
||
obj.is_charge_lottery = true;
|
||
}
|
||
/* 转发 */
|
||
if (obj.type === 1) {
|
||
/* 被转发者的UID */
|
||
obj.origin_uid = ditem?.orig?.modules?.module_author?.mid || 0;
|
||
/* 被转发者的name */
|
||
obj.origin_uname = ditem?.orig?.modules?.module_author?.name || '';
|
||
/* 源动态的ts10 */
|
||
obj.origin_create_time = ditem?.orig?.modules?.module_author?.pub_ts || 0;
|
||
/* 源动态类型 */
|
||
obj.origin_type = dy_typeenum2num.get(ditem?.orig?.type) || 0;
|
||
/* 被转发者的rid(用于发评论) */
|
||
switch (ditem?.orig?.type) {
|
||
case 'DYNAMIC_TYPE_DRAW':
|
||
obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.draw?.id?.toString() || '';
|
||
break;
|
||
case 'DYNAMIC_TYPE_AV':
|
||
obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.archive?.aid || '';
|
||
break;
|
||
case 'DYNAMIC_TYPE_ARTICLE':
|
||
obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.article?.id?.toString() || '';
|
||
break;
|
||
default:
|
||
obj.origin_rid_str = ditem?.orig?.id_str || '';
|
||
break;
|
||
}
|
||
/* 用于发送评论 */
|
||
obj.origin_chat_type = dy_type2chat_type.get(ditem?.orig?.type) || 0;
|
||
/* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */
|
||
obj.origin_dynamic_id = ditem?.orig?.id_str || '';
|
||
/* 预约抽奖信息 */
|
||
obj.origin_reserve_id = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.rid || 0;
|
||
obj.origin_reserve_lottery_text = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失';
|
||
/* 充电抽奖 */
|
||
if (ditem?.orig?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') {
|
||
obj.origin_is_charge_lottery = true;
|
||
}
|
||
/* 是否有官方抽奖 */
|
||
obj.origin_hasOfficialLottery = false;
|
||
/* 转发描述 */
|
||
obj.origin_description = '';
|
||
if (Array.isArray(ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes)) {
|
||
ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => {
|
||
/* 是否有官方抽奖 */
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
||
obj.origin_hasOfficialLottery = true;
|
||
}
|
||
obj.origin_description += node.orig_text;
|
||
});
|
||
} else {
|
||
ditem?.orig.modules?.module_dynamic?.major?.opus?.summary?.rich_text_nodes.forEach(node => {
|
||
/* 是否有官方抽奖 */
|
||
if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
||
obj.origin_hasOfficialLottery = true;
|
||
}
|
||
obj.origin_description += node.orig_text;
|
||
});
|
||
}
|
||
}
|
||
} catch (e) {
|
||
log.error('动态卡片解析', e);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* @param {object} dynamic_detail_card
|
||
* @return {UsefulDynamicInfo}
|
||
*/
|
||
function oldParseDynamicCard(dynamic_detail_card) {
|
||
const { strToJson } = utils;
|
||
/**临时储存单个动态中的信息 */
|
||
let obj = {};
|
||
try {
|
||
const { desc, card, extension, extend_json = '{}', display = {} } = dynamic_detail_card
|
||
, { is_liked = 1, user_profile = {} } = desc
|
||
, { info = {} } = user_profile || {}
|
||
, cardToJson = strToJson(card)
|
||
, extendjsonToJson = strToJson(extend_json)
|
||
, { add_on_card_info = [] } = display || {}
|
||
, { item } = cardToJson;
|
||
const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]);
|
||
/* 转发者的UID */
|
||
obj.uid = desc.uid;
|
||
/* 转发者的name */
|
||
obj.uname = info.uname || '';
|
||
/* 动态是否点过赞 */
|
||
obj.is_liked = is_liked > 0;
|
||
/* 动态的ts10 */
|
||
obj.create_time = desc.timestamp;
|
||
/* 动态类型 */
|
||
obj.type = desc.type;
|
||
/* 用于发送评论 */
|
||
obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str;
|
||
/* 用于发送评论 */
|
||
obj.chat_type = dy_type2chat_type.get(obj.type) || 0;
|
||
/* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */
|
||
obj.dynamic_id = desc.dynamic_id_str;
|
||
/* 定位@信息 */
|
||
obj.ctrl = (extendjsonToJson.ctrl) || [];
|
||
/* 预约抽奖信息 */
|
||
if (add_on_card_info.length > 0) {
|
||
const [status, oid_str, text] = add_on_card_info
|
||
.filter(it => typeof it.reserve_attach_card !== 'undefined'
|
||
&& typeof it.reserve_attach_card.reserve_lottery !== 'undefined'
|
||
&& typeof it.reserve_attach_card.reserve_button !== 'undefined')
|
||
.map(({ reserve_attach_card }) => [
|
||
reserve_attach_card.reserve_button.status,
|
||
reserve_attach_card.oid_str,
|
||
reserve_attach_card.reserve_lottery.text])[0] || [];
|
||
if (status === 1) {
|
||
obj.reserve_id = oid_str;
|
||
obj.reserve_lottery_text = text;
|
||
}
|
||
}
|
||
if (extendjsonToJson['']) {
|
||
let r = extendjsonToJson[''].reserve || {};
|
||
let { reserve_id, reserve_lottery } = r;
|
||
if (reserve_lottery === 1) {
|
||
obj.reserve_id = reserve_id + '';
|
||
obj.reserve_lottery_text = '信息丢失';
|
||
}
|
||
}
|
||
if (extend_json.match(/"":\{"lottery/)) {
|
||
obj.is_charge_lottery = true;
|
||
}
|
||
/* 是否有官方抽奖 */
|
||
obj.hasOfficialLottery = extension && extension.lott && true;
|
||
/* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/
|
||
obj.description =
|
||
(item && ((item.content || '') + (item.description || '')))
|
||
|| (
|
||
(cardToJson.dynamic || '')
|
||
+ (cardToJson.desc || '')
|
||
+ (cardToJson.vest && cardToJson.vest.content || '')
|
||
)
|
||
|| '';
|
||
/* 转发 */
|
||
if (obj.type === 1) {
|
||
const { origin_extension, origin, origin_extend_json = '{}' } = cardToJson
|
||
, originToJson = strToJson(origin)
|
||
, { add_on_card_info = [] } = display.origin || {}
|
||
, originExtendjsonToJson = strToJson(origin_extend_json)
|
||
, { user, item } = originToJson;
|
||
/* 源动态的ts10 */
|
||
obj.origin_create_time = desc.origin.timestamp;
|
||
/* 被转发者的UID */
|
||
obj.origin_uid = desc.origin.uid;
|
||
/* 源动态类型 */
|
||
obj.origin_type = desc.orig_type;
|
||
/* 被转发者的rid(用于发评论) */
|
||
obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str;
|
||
/* 用于发送评论 */
|
||
obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0;
|
||
/* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */
|
||
obj.origin_dynamic_id = desc.orig_dy_id_str;
|
||
/* 预约抽奖信息 */
|
||
if (add_on_card_info.length > 0) {
|
||
const [status, oid_str, text] = add_on_card_info
|
||
.filter(it => typeof it.reserve_attach_card !== 'undefined'
|
||
&& typeof it.reserve_attach_card.reserve_lottery !== 'undefined'
|
||
&& typeof it.reserve_attach_card.reserve_button !== 'undefined')
|
||
.map(({ reserve_attach_card }) => [
|
||
reserve_attach_card.reserve_button.status,
|
||
reserve_attach_card.oid_str,
|
||
reserve_attach_card.reserve_lottery.text])[0] || [];
|
||
if (status === 1) {
|
||
obj.origin_reserve_id = oid_str;
|
||
obj.origin_reserve_lottery_text = text;
|
||
}
|
||
}
|
||
if (originExtendjsonToJson['']) {
|
||
let r = originExtendjsonToJson[''].reserve || {};
|
||
let { reserve_id, reserve_lottery } = r;
|
||
if (reserve_lottery === 1) {
|
||
obj.origin_reserve_id = reserve_id + '';
|
||
obj.origin_reserve_lottery_text = '信息丢失';
|
||
}
|
||
}
|
||
if (origin_extend_json.match(/"":\{"lottery/)) {
|
||
obj.origin_is_charge_lottery = true;
|
||
}
|
||
/* 是否有官方抽奖 */
|
||
obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott;
|
||
/* 被转发者的name */
|
||
obj.origin_uname = (user && (user.name || user.uname)) || '';
|
||
/* 被转发者的描述 */
|
||
obj.origin_description =
|
||
(item && (item.content || '' + item.description || ''))
|
||
|| (originToJson.dynamic || '' + originToJson.desc || '')
|
||
|| '';
|
||
}
|
||
} catch (e) {
|
||
log.error('动态卡片解析', e);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* 处理来自个人动态或话题页面的一组动态数据
|
||
* @param {String} res
|
||
* @returns {{modifyDynamicResArray: UsefulDynamicInfo[], nextinfo: {has_more: number, next_offset: string}} | UsefulDynamicInfo |null}
|
||
*/
|
||
function modifyDynamicRes(res) {
|
||
let
|
||
{ data, code } = utils.strToJson(res),
|
||
{ items, has_more, offset } = data || {};
|
||
|
||
if (code !== 0) {
|
||
log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res);
|
||
return null;
|
||
}
|
||
/**
|
||
* !cards已经能涵盖cards == null,你在想什么?
|
||
*/
|
||
if (!items || !items.length) {
|
||
log.warn('处理动态数据', '未找到任何动态信息');
|
||
items = [];
|
||
}
|
||
|
||
if (typeof has_more === 'undefined'
|
||
&& typeof offset === 'undefined') {
|
||
log.error('处理动态数据', '该功能已失效');
|
||
return null;
|
||
}
|
||
|
||
const
|
||
/**
|
||
* 字符串offset防止损失精度
|
||
*/
|
||
next = {
|
||
has_more,
|
||
next_offset: offset
|
||
},
|
||
/**
|
||
* 储存获取到的一组动态中的信息
|
||
*/
|
||
array = next.has_more === 0
|
||
? []
|
||
: items.map(item => parseDynamicCard({ item }));
|
||
|
||
log.info('处理动态数据', `动态数据读取完毕(${items.length})(${next.has_more})`);
|
||
|
||
return {
|
||
modifyDynamicResArray: array,
|
||
nextinfo: next
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 基础搜索功能
|
||
*/
|
||
class Searcher {
|
||
constructor() { }
|
||
/**
|
||
* 检查指定用户的所有的动态信息
|
||
* @param {number} hostuid 指定的用户UID
|
||
* @param {number} pages 读取页数
|
||
* @param {number} time 时延
|
||
* @param {string} [offset] 默认'0'
|
||
* @returns {Promise<{allModifyDynamicResArray: UsefulDynamicInfo[], offset: string} | null>} 获取前 `pages*12` 个动态信息
|
||
*/
|
||
static async checkAllDynamic(host_mid, pages, time = 0, offset = '0') {
|
||
log.info('检查所有动态', `准备读取${pages}页动态`);
|
||
|
||
const { getOneDynamicInfoByUID } = bili,
|
||
/**
|
||
* 柯里化请求函数
|
||
*/
|
||
curriedGetOneDynamicInfoByUID = utils.curryify(getOneDynamicInfoByUID),
|
||
/**
|
||
* 储存了特定UID的请求函数
|
||
*/
|
||
hadUidGetOneDynamicInfoByUID = curriedGetOneDynamicInfoByUID(host_mid);
|
||
|
||
/**
|
||
* 储存所有经过整理后信息
|
||
* @type { UsefulDynamicInfo[] }
|
||
*/
|
||
let allModifyDynamicResArray = [];
|
||
|
||
for (let i = 0; i < pages; i++) {
|
||
log.info('检查所有动态', `正在读取其中第${i + 1}页动态`);
|
||
|
||
// 当 offset 为 '0'(初始页)时,传入 offset 会报错
|
||
const OneDynamicInfo = offset === '0'
|
||
? await hadUidGetOneDynamicInfoByUID()
|
||
: await hadUidGetOneDynamicInfoByUID(offset);
|
||
|
||
const mDRdata = modifyDynamicRes(OneDynamicInfo);
|
||
|
||
if (mDRdata === null) {
|
||
return null;
|
||
}
|
||
|
||
const
|
||
/**
|
||
* 一片动态
|
||
*/
|
||
mDRArry = mDRdata.modifyDynamicResArray,
|
||
nextinfo = mDRdata.nextinfo;
|
||
|
||
if (nextinfo.has_more === 0) {
|
||
offset = nextinfo.next_offset;
|
||
log.info('检查所有动态', '已经是最后一页了故无法读取更多');
|
||
break;
|
||
} else {
|
||
/**合并 */
|
||
allModifyDynamicResArray.push.apply(allModifyDynamicResArray, mDRArry);
|
||
offset = nextinfo.next_offset;
|
||
}
|
||
|
||
await utils.delay(time);
|
||
}
|
||
|
||
log.info('检查所有动态', `${pages}页信息读取完成`);
|
||
|
||
return ({ allModifyDynamicResArray, offset });
|
||
}
|
||
|
||
/**
|
||
* 获取最新动态信息(转发子动态)
|
||
* 并初步整理
|
||
* @param {string} UID
|
||
* @returns {Promise<LotteryInfo[] | null>}
|
||
*/
|
||
async getLotteryInfoByUID(UID) {
|
||
log.info('获取动态', `开始获取用户${UID}的动态信息`);
|
||
const AllDynamic = await Searcher.checkAllDynamic(UID, uid_scan_page, search_wait);
|
||
|
||
if (AllDynamic === null) return null;
|
||
|
||
let { allModifyDynamicResArray } = AllDynamic,
|
||
{ length } = allModifyDynamicResArray;
|
||
|
||
if (!length) return null;
|
||
|
||
const fomatdata = await allModifyDynamicResArray
|
||
.filter(d => {
|
||
if (d.type === 1) {
|
||
return true;
|
||
} else {
|
||
length--;
|
||
return false;
|
||
}
|
||
})
|
||
.reduce(async (pre, cur) => {
|
||
let
|
||
results = await pre,
|
||
{ origin_dynamic_id } = cur,
|
||
is_liked = false;
|
||
|
||
if (!check_if_duplicated || check_if_duplicated >= 2) {
|
||
const card = await bili.getOneDynamicByDyid(origin_dynamic_id);
|
||
log.info('获取动态', `查看源动态(${origin_dynamic_id})是否点赞 (${length--})`);
|
||
if (card) {
|
||
({ is_liked } = parseDynamicCard(card));
|
||
}
|
||
await utils.delay(get_dynamic_detail_wait);
|
||
}
|
||
|
||
results.push({
|
||
lottery_info_type: 'uid',
|
||
create_time: cur.origin_create_time,
|
||
is_liked,
|
||
uids: [cur.uid, cur.origin_uid],
|
||
uname: cur.origin_uname,
|
||
ctrl: [],
|
||
dyid: cur.origin_dynamic_id,
|
||
reserve_id: cur.origin_reserve_id,
|
||
reserve_lottery_text: cur.origin_reserve_lottery_text,
|
||
is_charge_lottery: cur.origin_is_charge_lottery,
|
||
rid: cur.origin_rid_str,
|
||
chat_type: cur.origin_chat_type,
|
||
des: cur.origin_description,
|
||
type: cur.origin_type,
|
||
hasOfficialLottery: cur.origin_hasOfficialLottery
|
||
});
|
||
|
||
return results;
|
||
}, Promise.resolve([]));
|
||
|
||
log.info('获取动态', `成功获取用户${UID}的动态信息`);
|
||
|
||
return fomatdata;
|
||
}
|
||
|
||
/**
|
||
* 获取tag下的抽奖信息(转发母动态)
|
||
* 并初步整理
|
||
* @param {string} tag_name
|
||
* @returns {Promise<LotteryInfo[] | null>}
|
||
*/
|
||
async getLotteryInfoByTag(tag_name) {
|
||
log.info('获取动态', `开始获取带话题#${tag_name}#的动态信息`);
|
||
|
||
const
|
||
tag_id = await bili.getTagIDByTagName(tag_name),
|
||
hotdy = await bili.getHotDynamicInfoByTagID(tag_id),
|
||
modDR = modifyDynamicRes(hotdy);
|
||
|
||
if (modDR === null) return null;
|
||
|
||
log.info('获取动态', '成功获取热门动态');
|
||
|
||
/**
|
||
* 热门动态
|
||
*/
|
||
let mDRdata = modDR.modifyDynamicResArray;
|
||
let next_offset = modDR.nextinfo.next_offset;
|
||
|
||
for (let index = 0; index < tag_scan_page; index++) {
|
||
log.info('获取动态', `读取第${index + 1}页动态`);
|
||
const
|
||
newdy = await bili.getOneDynamicInfoByTag(tag_name, next_offset),
|
||
_modify = modifyDynamicRes(newdy);
|
||
|
||
if (_modify === null) return null;
|
||
|
||
mDRdata.push.apply(mDRdata, _modify.modifyDynamicResArray);
|
||
next_offset = _modify.nextinfo.next_offset;
|
||
|
||
await utils.delay(search_wait);
|
||
}
|
||
const fomatdata = mDRdata.map(o => {
|
||
return {
|
||
lottery_info_type: 'tag',
|
||
create_time: o.create_time,
|
||
is_liked: o.is_liked,
|
||
uids: [o.uid, o.origin_uid],
|
||
uname: o.uname,
|
||
ctrl: o.ctrl,
|
||
dyid: o.dynamic_id,
|
||
reserve_id: o.reserve_id,
|
||
reserve_lottery_text: o.reserve_lottery_text,
|
||
is_charge_lottery: o.is_charge_lottery,
|
||
rid: o.rid_str,
|
||
chat_type: o.chat_type,
|
||
des: o.description,
|
||
type: o.type,
|
||
hasOfficialLottery: o.hasOfficialLottery
|
||
};
|
||
});
|
||
log.info('获取动态', `成功获取带话题#${tag_name}#的动态信息`);
|
||
|
||
return fomatdata;
|
||
}
|
||
|
||
/**
|
||
* 从专栏中获取抽奖信息
|
||
* @param {string} key_words
|
||
* @returns {Promise<LotteryInfo[] | null>}
|
||
*/
|
||
async getLotteryInfoByArticle(key_words) {
|
||
log.info('获取动态', `开始获取含关键词${key_words}的专栏信息`);
|
||
const cvs = (await bili.searchArticlesByKeyword(key_words)).slice(0, article_scan_page);
|
||
|
||
/**存储所有专栏中的dyid */
|
||
let dyinfos = [];
|
||
/**遍历专栏s */
|
||
for (const { id, pub_time } of cvs) {
|
||
let now_time = Math.floor(Date.now() / 1000);
|
||
if ((now_time - pub_time) / 86400 > article_create_time) {
|
||
log.warn('获取动态', `该专栏(${id})创建时间大于设定天数(${article_create_time}天)`);
|
||
continue;
|
||
}
|
||
const
|
||
content = (await bili.getOneArticleByCv(id) || '').split('推荐文章')[0],
|
||
dyids = content.match(/[0-9]{18,}/g) || [],
|
||
short_ids = content.match(/(?<=b23.tv\/)[a-zA-Z0-9]{7}/g) || [],
|
||
short_id_set = [...new Set(short_ids)],
|
||
short_ids_to_dyids = await Promise.all(short_id_set.map(bili.shortDynamicIdToDyid)),
|
||
dyid_set = [...new Set([...dyids, ...short_ids_to_dyids])],
|
||
/**判断此专栏是否查看过的权重 */
|
||
weight = dyid_set.length / 2;
|
||
|
||
let { length } = dyid_set,
|
||
/**初始权重 */
|
||
_weight = 0,
|
||
/**单个专栏中的dyid */
|
||
_dyinfos = [];
|
||
log.info('获取动态', `提取专栏(${id})中提及的dyid(${length})`);
|
||
|
||
/**遍历某专栏中的dyids */
|
||
for (const dyid of dyid_set) {
|
||
log.info('获取动态', `查看专栏中所提及动态(${dyid}) (${length--})`);
|
||
const card = await bili.getOneDynamicByDyid(dyid);
|
||
|
||
if (card) {
|
||
await utils.delay(get_dynamic_detail_wait);
|
||
|
||
const parsed_card = parseDynamicCard(card)
|
||
, { is_liked } = parsed_card;
|
||
|
||
if (
|
||
((!check_if_duplicated || check_if_duplicated >= 2)
|
||
&& is_liked)
|
||
|| ((check_if_duplicated >= 1)
|
||
&& await d_storage.searchDyid(dyid))
|
||
) {
|
||
log.info('获取动态', `动态(${dyid})已转发过`);
|
||
_weight += 1;
|
||
}
|
||
|
||
if (_weight >= weight && !not_check_article) {
|
||
log.warn('获取动态', '1/2动态曾经转过,该专栏或已查看,故中止');
|
||
_dyinfos = [];
|
||
break;
|
||
}
|
||
|
||
_dyinfos.push(parsed_card);
|
||
} else {
|
||
log.warn('获取动态', `动态细节获取失败(${dyid})`);
|
||
}
|
||
}
|
||
dyinfos.push(..._dyinfos);
|
||
}
|
||
const fomatdata = dyinfos.map(o => {
|
||
return {
|
||
lottery_info_type: 'article',
|
||
create_time: o.create_time,
|
||
is_liked: o.is_liked,
|
||
uids: [o.uid, o.origin_uid],
|
||
uname: o.uname,
|
||
ctrl: o.ctrl,
|
||
dyid: o.dynamic_id,
|
||
reserve_id: o.reserve_id,
|
||
reserve_lottery_text: o.reserve_lottery_text,
|
||
is_charge_lottery: o.is_charge_lottery,
|
||
rid: o.rid_str,
|
||
chat_type: o.chat_type,
|
||
des: o.description,
|
||
type: o.type,
|
||
hasOfficialLottery: o.hasOfficialLottery
|
||
};
|
||
});
|
||
log.info('获取动态', `成功获取含关键词${key_words}的专栏信息`);
|
||
|
||
return fomatdata;
|
||
}
|
||
|
||
/**
|
||
* 从特定格式的api响应数据中获取抽奖信息
|
||
* @param {string} api
|
||
* @returns {Promise<LotteryInfo[] | null>}
|
||
*/
|
||
getLotteryInfoByAPI(api) {
|
||
return new Promise((resolve) => {
|
||
if (api) {
|
||
const { strToJson } = utils;
|
||
log.info('获取动态', `开始获取链接(${api})中的抽奖信息`);
|
||
if (api.startsWith('file://')) {
|
||
utils.readLotteryInfoFile(api.substring(7)).then(resolve);
|
||
} else {
|
||
send({
|
||
url: api,
|
||
config: {
|
||
redirect: true
|
||
},
|
||
method: 'GET',
|
||
success: ({ body }) => {
|
||
if (body.err_msg) {
|
||
log.error('从API响应数据中获取抽奖信息', body.err_msg);
|
||
resolve(null);
|
||
} else {
|
||
const raw_lottery_info = strToJson(body).lottery_info;
|
||
|
||
if (raw_lottery_info) {
|
||
let { length } = raw_lottery_info;
|
||
if (length) {
|
||
const lottery_info = raw_lottery_info
|
||
.reduce(async (pre, cur) => {
|
||
let results = await pre
|
||
, { dyid } = cur;
|
||
|
||
if (!check_if_duplicated || check_if_duplicated >= 2) {
|
||
log.info('获取动态', `查看动态(${dyid})是否点赞 (${length--})`);
|
||
const card = await bili.getOneDynamicByDyid(dyid);
|
||
|
||
if (card) {
|
||
await utils.delay(get_dynamic_detail_wait);
|
||
|
||
const { is_liked } = parseDynamicCard(card);
|
||
|
||
if (is_liked) {
|
||
log.info('获取动态', `动态(${dyid})已转发过`);
|
||
} else {
|
||
cur.is_liked = is_liked;
|
||
results.push(cur);
|
||
}
|
||
}
|
||
} else {
|
||
results.push(cur);
|
||
}
|
||
|
||
return results;
|
||
|
||
}, Promise.resolve([]));
|
||
|
||
resolve(lottery_info);
|
||
return;
|
||
}
|
||
}
|
||
log.error('从API响应数据中获取抽奖信息', '非Json数据或没有lottery_info或lottery为空');
|
||
resolve(null);
|
||
}
|
||
},
|
||
failure: err => {
|
||
log.error('从API响应数据中获取抽奖信息', err);
|
||
resolve(null);
|
||
}
|
||
});
|
||
}
|
||
} else {
|
||
log.warn('获取动态', '链接为空');
|
||
resolve(null);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 从本地文件中获取抽奖信息
|
||
* @param {string} txt
|
||
* @returns {Promise<LotteryInfo[] | null>}
|
||
*/
|
||
async getLotteryInfoByTxT(txt) {
|
||
log.info('获取动态', `开始获取${utils.lottery_dyids}`);
|
||
const dyids = await utils.getLocalLotteryTxt(txt);
|
||
let
|
||
length = dyids.length,
|
||
dyinfos = [];
|
||
|
||
for (const dyid of dyids) {
|
||
log.info('获取动态', `查看Txt中所提及动态(${dyid}) (${length--})`);
|
||
const card = await bili.getOneDynamicByDyid(dyid);
|
||
|
||
if (card) {
|
||
await utils.delay(get_dynamic_detail_wait);
|
||
|
||
const parsed_card = parseDynamicCard(card)
|
||
, { is_liked } = parsed_card;
|
||
|
||
if (
|
||
((!check_if_duplicated || check_if_duplicated >= 2)
|
||
&& is_liked)
|
||
|| ((check_if_duplicated >= 1)
|
||
&& await d_storage.searchDyid(dyid))
|
||
) {
|
||
log.info('获取动态', `动态(${dyid})已转发过`);
|
||
continue;
|
||
}
|
||
|
||
dyinfos.push(parsed_card);
|
||
} else {
|
||
log.warn('获取动态', `动态细节获取失败(${dyid})`);
|
||
}
|
||
|
||
}
|
||
const fomatdata = dyinfos.map(o => {
|
||
return {
|
||
lottery_info_type: 'txt',
|
||
create_time: o.create_time,
|
||
is_liked: o.is_liked,
|
||
uids: [o.uid, o.origin_uid],
|
||
uname: o.uname,
|
||
ctrl: o.ctrl,
|
||
dyid: o.dynamic_id,
|
||
reserve_id: o.reserve_id,
|
||
reserve_lottery_text: o.reserve_lottery_text,
|
||
is_charge_lottery: o.is_charge_lottery,
|
||
rid: o.rid_str,
|
||
chat_type: o.chat_type,
|
||
des: o.description,
|
||
type: o.type,
|
||
hasOfficialLottery: o.hasOfficialLottery
|
||
};
|
||
});
|
||
log.info('获取动态', '成功获取txt信息');
|
||
|
||
return fomatdata;
|
||
}
|
||
}
|
||
|
||
module.exports = { Searcher, parseDynamicCard };
|