feat: 增加从专栏获取抽奖的功能

This commit is contained in:
shanmite 2021-07-27 21:48:12 +08:00
parent a63456bd29
commit cbce4b113d
7 changed files with 218 additions and 93 deletions

View File

@ -321,6 +321,49 @@ const BiliAPI = {
});
});
},
/**
* 搜索专栏
* @param {string} keyword
* @return {Promise<Array<number>>}
*/
searchArticlesByKeyword(keyword) {
return new Promise((resolve) => {
Ajax.get({
url: 'https://api.bilibili.com/x/web-interface/search/type',
queryStringsObj: {
keyword,
page: 1,
order: 'pubdate',
search_type: 'article'
},
success: responseText => {
const res = JSON.parse(responseText);
if (res.code === 0) {
log.info('搜索专栏', '成功 关键词: ' + keyword)
resolve(res.data.result.map(it => it.id))
} else {
log.error('搜索专栏', '失败 原因:\n' + responseText)
resolve([])
}
}
})
});
},
/**
* 获取专栏内容
* @param {number} cv
* @returns {Promise<string>}
*/
getOneArticleByCv(cv) {
return new Promise((resolve) => {
Ajax.get({
url: `https://www.bilibili.com/read/cv${cv}`,
success: responseText => {
resolve(responseText)
}
})
});
},
/**
* 获取粉丝数
* @param {number} uid

View File

@ -14,13 +14,18 @@ const { log, hasEnv } = Util;
class Monitor extends Public {
/**
* @constructor
* @param {number | string} param
* @param {[string, number | string]} lottery_param
*/
constructor(param) {
constructor(lottery_param) {
super();
typeof param === 'number' ? this.UID = param : this.tag_name = param;
this.lottery_param = lottery_param
this.tagid = config.partition_id; /* tagid初始化 */
this.attentionList = ''; /* 转为字符串的所有关注的up主uid */
this.LotteryInfoMap = new Map([
['UIDs', this.getLotteryInfoByUID.bind(this)],
['TAGs', this.getLotteryInfoByTag.bind(this)],
['Articles', this.getLotteryInfoByArticle.bind(this)],
]);
}
/**
* 初始化
@ -37,7 +42,8 @@ class Monitor extends Public {
return
}
}
this.attentionList = await BiliAPI.getAttentionList(GlobalVar.get("myUID")); /* 获取关注列表 */
/** 关注列表初始化 */
this.attentionList = await BiliAPI.getAttentionList(GlobalVar.get("myUID"));
switch (await this.startLottery()) {
case 0:
eventBus.emit('Turn_on_the_Monitor')
@ -142,10 +148,8 @@ class Monitor extends Public {
* @returns {Promise<LotteryOptions[]>}
*/
async filterLotteryInfo() {
let self = this,
protoLotteryInfo = typeof self.UID === 'number'
? await self.getLotteryInfoByUID(self.UID)
: await self.getLotteryInfoByTag(self.tag_name);
const { lottery_param, LotteryInfoMap, attentionList } = this;
let protoLotteryInfo = await LotteryInfoMap.get(lottery_param[0])(lottery_param[1]);
if (protoLotteryInfo === null)
return [];
@ -188,9 +192,10 @@ class Monitor extends Public {
/* 遇到转发过就退出 */
if (dyids_map.get(dyid)) return false;
/**判断是转发源动态还是现动态 */
const uid = lottery_info_type === 'tag' ? uids[0] : uids[1]
, isFollowed = (new RegExp(uid)).test(self.attentionList)
const
/**判断是转发源动态还是现动态 */
uid = lottery_info_type === ('tag' || 'article') ? uids[0] : uids[1]
, isFollowed = (new RegExp(uid)).test(attentionList)
, description = typeof des === 'string' ? des : ''
, needAt = /(?:@|艾特)[^@|(艾特)]*?好友/.test(description)
, needTopic = (/(?<=[带加上](?:话题|tag))#.*#/i.exec(description) || [])[0]
@ -199,7 +204,7 @@ class Monitor extends Public {
, has_key_words = key_words.every(it => new RegExp(it).test(description))
, isBlock = new RegExp(blockword.join('|')).test(description)
, isLottery =
(lottery_info_type === 'uid' && is_imitator && model !== '00')
(is_imitator && lottery_info_type === 'uid' && model !== '00')
|| (hasOfficialLottery && model[0] === '1')
|| (!hasOfficialLottery && model[1] === '1' && !isTwoLevelDynamic && has_key_words)
, isSendChat =
@ -274,7 +279,7 @@ class Monitor extends Public {
item.location += addlength;
return item;
}).forEach(it => new_ctrl.push(it))
if (!(new RegExp(uids[1])).test(self.attentionList))
if (!(new RegExp(uids[1])).test(attentionList))
onelotteryinfo.uid.push(uids[1]);
} else {
onelotteryinfo.relay_chat = RandomStr;

View File

@ -77,25 +77,81 @@ function parseDynamicCard(dynamic_detail_card) {
return obj
}
/**
* 处理来自个人动态或话题页面的一组动态数据
* @param {String} res
* @returns {{modifyDynamicResArray: UsefulDynamicInfo[], nextinfo: {has_more: number, next_offset: string}} | UsefulDynamicInfo |null}
*/
function modifyDynamicRes(res) {
const
strToJson = Util.strToJson
, { data, code } = strToJson(res)
, { cards = [], has_more, offset } = data;
if (code !== 0) {
log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res);
return null;
}
if (!cards.length) {
log.warn('处理动态数据', '未找到任何动态信息')
}
const
/**
* 字符串offset防止损失精度
*/
next = {
has_more,
next_offset: typeof offset === 'string'
? offset
: /(?<=next_offset":)[0-9]+/.exec(res)[0]
},
/**
* 储存获取到的一组动态中的信息
*/
array = next.has_more === 0
? []
: cards.map(onecard => parseDynamicCard(onecard))
log.info('处理动态数据', `动态数据读取完毕(${cards.length})(${next.has_more})`);
return {
modifyDynamicResArray: array,
nextinfo: next
}
}
/**
* 基础功能
*/
class Public {
constructor() { }
/**
* 检查所有的动态信息
* 整理后的抽奖信息
* @typedef {object} LotteryInfo
* @property {string} lottery_info_type
* @property {number[]} uids `[uid,ouid]`
* @property {string} uname
* @property {Array<{}>} ctrl
* @property {string} dyid
* @property {string} rid
* @property {string} des
* @property {number} type
* @property {boolean} hasOfficialLottery 是否官方
*/
/**
* 检查指定用户的所有的动态信息
* @param {string} UID 指定的用户UID
* @param {number} pages 读取页数
* @param {number} time 时延
* @param {string} [offset] 默认'0'
* @returns {Promise<{allModifyDynamicResArray: UsefulDynamicInfo[];offset: string}>} 获取前 `pages*12` 个动态信息
* @returns {Promise<{allModifyDynamicResArray: UsefulDynamicInfo[], offset: string}>} 获取前 `pages*12` 个动态信息
*/
async checkAllDynamic(hostuid, pages, time = 0, offset = '0') {
log.info('检查所有动态', `准备读取${pages}页动态`);
const
{ modifyDynamicRes } = this,
{ getOneDynamicInfoByUID } = BiliAPI,
const { getOneDynamicInfoByUID } = BiliAPI,
/**
* 柯里化请求函数
*/
@ -148,57 +204,34 @@ class Public {
return ({ allModifyDynamicResArray, offset });
}
/**
* 互动抽奖
* 处理来自动态页面的数据
* @param {String} res
* @returns {{modifyDynamicResArray: UsefulDynamicInfo[];nextinfo: {has_more: number;next_offset: string;};} | null}
* 获取最新动态信息(转发子动态)
* 并初步整理
* @param {string} UID
* @returns {Promise<LotteryInfo[] | null>}
*/
modifyDynamicRes(res) {
const
strToJson = Util.strToJson
, { data, code } = strToJson(res)
, { cards = [] } = data;
async getLotteryInfoByUID(UID) {
log.info('获取动态', `开始获取用户${UID}的动态信息`);
const { allModifyDynamicResArray } = await this.checkAllDynamic(UID, config.uid_scan_page, config.search_wait);
if (code !== 0) {
log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res);
return null;
}
const
/**
* 字符串offset防止损失精度
*/
next = {
has_more: data.has_more,
next_offset: typeof data.offset === 'string'
? data.offset
: /(?<=next_offset":)[0-9]*/.exec(res)[0]
},
/**
* 储存获取到的一组动态中的信息
*/
array = next.has_more === 0
? []
: cards.map(onecard => parseDynamicCard(onecard))
if (!allModifyDynamicResArray.length) return null;
log.info('处理动态数据', `动态数据读取完毕(${cards.length})(${next.has_more})`);
const fomatdata = allModifyDynamicResArray.map(o => {
return {
lottery_info_type: 'uid',
uids: [o.uid, o.origin_uid],
uname: o.origin_uname,
ctrl: [],
dyid: o.origin_dynamic_id,
rid: o.origin_rid_str,
des: o.origin_description,
type: o.orig_type,
hasOfficialLottery: o.origin_hasOfficialLottery
}
}).filter(a => a.type != 0)
log.info('获取动态', `成功获取用户${UID}的动态信息`);
return {
modifyDynamicResArray: array,
nextinfo: next
};
return fomatdata;
}
/**
* @typedef {object} LotteryInfo
* @property {string} lottery_info_type
* @property {number[]} uids `[uid,ouid]`
* @property {string} uname
* @property {Array<{}>} ctrl
* @property {string} dyid
* @property {string} rid
* @property {string} des
* @property {number} type
* @property {boolean} hasOfficialLottery 是否官方
*/
/**
* 获取tag下的抽奖信息(转发母动态)
* 并初步整理
@ -207,7 +240,6 @@ class Public {
*/
async getLotteryInfoByTag(tag_name) {
const
{ modifyDynamicRes } = this,
tag_id = await BiliAPI.getTagIDByTagName(tag_name),
hotdy = await BiliAPI.getHotDynamicInfoByTagID(tag_id),
modDR = modifyDynamicRes(hotdy);
@ -223,7 +255,7 @@ class Public {
let mDRdata = modDR.modifyDynamicResArray;
let next_offset = modDR.nextinfo.next_offset;
for (let index = 0; index < config.scan_page_num; index++) {
for (let index = 0; index < config.tag_scan_page; index++) {
log.info('获取动态', `读取第${index + 1}页动态`);
const
newdy = await BiliAPI.getOneDynamicInfoByTag(tag_name, next_offset),
@ -254,33 +286,54 @@ class Public {
return fomatdata
}
/**
* 获取最新动态信息(转发子动态)
* 并初步整理
* @param {string} UID
* 从专栏中获取抽奖信息
* @param {string} key_words
* @returns {Promise<LotteryInfo[] | null>}
*/
async getLotteryInfoByUID(UID) {
log.info('获取动态', `开始获取用户${UID}的动态信息`);
const { allModifyDynamicResArray } = await this.checkAllDynamic(UID, config.scan_page_num, config.search_wait);
async getLotteryInfoByArticle(key_words) {
log.info('获取动态', `开始获取含关键词${key_words}的专栏信息`);
const cvs = (await BiliAPI.searchArticlesByKeyword(key_words)).slice(0, config.article_scan_page);
if (!allModifyDynamicResArray.length) return null;
let dyinfos = [];
for (const cv of cvs) {
const content = await BiliAPI.getOneArticleByCv(cv)
, dyids = content.match(/(?<=t.bilibili.com\/)[0-9]+/g) || [];
let { length } = dyids;
log.info('获取动态', `提取专栏中提及的dyid(${length})`)
for (const dyid of dyids) {
log.info('获取动态', `查看动态(${dyid})的细节 (${length--})`)
const res = await BiliAPI.getOneDynamicByDyid(dyid)
, { code, data } = Util.strToJson(res)
, { card } = data;
const fomatdata = allModifyDynamicResArray.map(o => {
return {
lottery_info_type: 'uid',
uids: [o.uid, o.origin_uid],
uname: o.origin_uname,
ctrl: [],
dyid: o.origin_dynamic_id,
rid: o.origin_rid_str,
des: o.origin_description,
type: o.orig_type,
hasOfficialLottery: o.origin_hasOfficialLottery
if (code !== 0) {
log.error('获取动态', '获取动态数据出错,可能是访问太频繁 \n' + res)
break
}
await Util.delay(2000)
if (card) {
dyinfos.push(parseDynamicCard(card));
}
}
}).filter(a => a.type != 0)
log.info('获取动态', `成功获取用户${UID}的动态信息`);
}
const fomatdata = dyinfos.map(o => {
return {
lottery_info_type: 'article',
uids: [o.uid, o.origin_uid],
uname: o.uname,
ctrl: o.ctrl,
dyid: o.dynamic_id,
rid: o.rid_str,
des: o.description,
type: o.type,
hasOfficialLottery: o.hasOfficialLottery
};
})
log.info('获取动态', `成功获取含关键词${key_words}的专栏信息`);
return fomatdata;
return fomatdata
}
}

View File

@ -47,8 +47,8 @@ function start() {
return;
}
const lottery = lotterys[times.next()];
const nlottery = Number(lottery);
await (new Monitor(isNaN(nlottery) ? lottery : nlottery)).init();
await (new Monitor(lottery)).init();
});
eventBus.on('Turn_off_the_Monitor', async (msg) => {
await createRandomDynamic(config.create_dy_num);

View File

@ -15,12 +15,20 @@ async function setVariable(cookie, n) {
config.updata(process.env.NUMBER);
GlobalVar.set('cookie', cookie);
cookie.split(/\s*;\s*/).forEach(item => {
const _item = item.split('=');
if (key_map.has(_item[0]))
GlobalVar.set(key_map.get(_item[0]), _item[1]);
});
GlobalVar.set('Lottery', [...config.UIDs, ...config.TAGs]);
const { UIDs = [], TAGs = [], Articles = [] } = config;
GlobalVar.set('Lottery', [
...UIDs.map(it => ['UIDs', it]),
...TAGs.map(it => ['TAGs', it]),
...Articles.map(it => ['Articles', it])
]);
GlobalVar.set('remoteconfig', await Util.getRemoteConfig());
}
await Util.createDir('dyids');

View File

@ -12,6 +12,13 @@ module.exports = {
241675899
],
/**
* 监视的专栏关键词
*/
Articles: [
'抽奖合集'
],
/**
* 监视的tag
*/
@ -53,9 +60,19 @@ module.exports = {
is_imitator: false,
/**
* - 在uid或tag里检索的页数
* - 在uid里检索的页数
*/
scan_page_num: 3,
uid_scan_page: 3,
/**
* - 在tag里检索的页数
*/
tag_scan_page: 3,
/**
* - 获取专栏数量
*/
article_scan_page: 3,
/**
* - 开奖时间距离现在的最大天数

View File

@ -17,7 +17,6 @@ Copy-Item -Path $TEMPLATE_CONFIG_FILE -Destination $TARGET_DIR -Force
Set-Location -Path $TARGET_DIR
# 重命名文件
Move-Item -Path $TEMPLATE_ENV_FILE -Destination $ENV_FILE -Force
Move-Item -Path $TEMPLATE_CONFIG_FILE -Destination $CONFIG_FILE -Force