feat(多账号优化): 抽奖信息本地保存 (#209)

Fixed #209
This commit is contained in:
shanmite 2022-10-29 13:09:19 +08:00
parent 2b6cc8d602
commit c220ff5d27
9 changed files with 188 additions and 82 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ node_modules/
.vscode/ .vscode/
tests/ tests/
dyids/ dyids/
lottery_info/
dist/ dist/
.env .env
*.log *.log

View File

@ -32,12 +32,21 @@ module.exports = Object.freeze({
/** /**
* 为防止环境变量过长, 请将多账号填在此处 * 为防止环境变量过长, 请将多账号填在此处
* 以大括号内容为模板依次复制(包含大括号),逗号分割 * **大括号内容** 为模板依次复制(包含大括号),逗号分割
* ``` *
* ... * ```txt
* NUMBER: 1 * [
* ... * {
* NUMBER: 2 * ...
* NUMBER: 1
* ...
* },
* {
* ...
* NUMBER: 2
* ...
* }
* ]
* ``` * ```
*/ */
multiple_account_parm: [ multiple_account_parm: [

View File

@ -1,4 +1,4 @@
const { log, hasEnv, shuffle, getRandomOne, delay, try_for_each, retryfn } = require('../utils'); const { log, hasEnv, shuffle, getRandomOne, delay, try_for_each, retryfn, appendLotteryInfoFile } = require('../utils');
const { send } = require('../net/http'); const { send } = require('../net/http');
const bili = require('../net/bili'); const bili = require('../net/bili');
const { sendNotify } = require('../helper/notify'); const { sendNotify } = require('../helper/notify');
@ -256,7 +256,7 @@ class Monitor extends Searcher {
/** 所有抽奖信息 */ /** 所有抽奖信息 */
let alllotteryinfo = []; let alllotteryinfo = [];
const const
{ check_if_duplicated, set_lottery_info_url, disable_reserve_lottery, reserve_lottery_wait, sneaktower, key_words, model, chatmodel, chat: chats, relay: relays, block_dynamic_type, max_create_time, is_imitator, only_followed, at_users, blockword, blacklist, use_public_blacklist } = config, { check_if_duplicated, save_lottery_info_to_file, set_lottery_info_url, disable_reserve_lottery, reserve_lottery_wait, sneaktower, key_words, model, chatmodel, chat: chats, relay: relays, block_dynamic_type, max_create_time, is_imitator, only_followed, at_users, blockword, blacklist, use_public_blacklist } = config,
now_ts = Date.now() / 1000; now_ts = Date.now() / 1000;
/** /**
@ -287,9 +287,14 @@ class Monitor extends Searcher {
log.info('筛选动态', `并发查询本地dyid完毕`); log.info('筛选动态', `并发查询本地dyid完毕`);
} }
if (lottery_param[0] !== "APIs" && save_lottery_info_to_file && protoLotteryInfo.length) {
log.info("保存抽奖信息", "保存开始")
appendLotteryInfoFile(lottery_param[1].toString(), protoLotteryInfo)
}
if (lottery_param[0] !== "APIs" && set_lottery_info_url && protoLotteryInfo.length) { if (lottery_param[0] !== "APIs" && set_lottery_info_url && protoLotteryInfo.length) {
log.info("上传抽奖信息", "开始") log.info("上传抽奖信息", "上传开始")
await new Promise((resolve) => { new Promise((resolve) => {
send({ send({
url: set_lottery_info_url, url: set_lottery_info_url,
method: "POST", method: "POST",

View File

@ -478,64 +478,68 @@ class Searcher {
if (api) { if (api) {
const { strToJson } = utils; const { strToJson } = utils;
log.info('获取动态', `开始获取链接(${api})中的抽奖信息`) log.info('获取动态', `开始获取链接(${api})中的抽奖信息`)
send({ if (api.startsWith("file://")) {
url: api, utils.readLotteryInfoFile(api.substring(7)).then(resolve)
config: { } else {
redirect: true send({
}, url: api,
method: 'GET', config: {
success: ({ body }) => { redirect: true
if (body.err_msg) { },
log.error("从API响应数据中获取抽奖信息", body.err_msg) method: 'GET',
resolve(null) success: ({ body }) => {
} else { if (body.err_msg) {
const raw_lottery_info = strToJson(body).lottery_info; log.error("从API响应数据中获取抽奖信息", body.err_msg)
resolve(null)
} else {
const raw_lottery_info = strToJson(body).lottery_info;
if (raw_lottery_info) { if (raw_lottery_info) {
let { length } = raw_lottery_info; let { length } = raw_lottery_info;
if (length) { if (length) {
const lottery_info = raw_lottery_info const lottery_info = raw_lottery_info
.reduce(async (pre, cur) => { .reduce(async (pre, cur) => {
let results = await pre let results = await pre
, { dyid } = cur; , { dyid } = cur;
if (!check_if_duplicated || check_if_duplicated >= 2) { if (!check_if_duplicated || check_if_duplicated >= 2) {
log.info('获取动态', `查看动态(${dyid})是否点赞 (${length--})`) log.info('获取动态', `查看动态(${dyid})是否点赞 (${length--})`)
const card = await bili.getOneDynamicByDyid(dyid) const card = await bili.getOneDynamicByDyid(dyid)
if (card) { if (card) {
await utils.delay(get_dynamic_detail_wait) await utils.delay(get_dynamic_detail_wait)
const { is_liked } = parseDynamicCard(card) const { is_liked } = parseDynamicCard(card)
if (is_liked) { if (is_liked) {
log.info('获取动态', `动态(${dyid})已转发过`) log.info('获取动态', `动态(${dyid})已转发过`)
} else { } else {
cur.is_liked = is_liked cur.is_liked = is_liked
results.push(cur) results.push(cur)
}
} }
} else {
results.push(cur)
} }
} else {
results.push(cur)
}
return results return results
}, Promise.resolve([])) }, Promise.resolve([]))
resolve(lottery_info) resolve(lottery_info)
return return
}
} }
log.error("从API响应数据中获取抽奖信息", "非Json数据或没有lottery_info或lottery为空")
resolve(null)
} }
log.error("从API响应数据中获取抽奖信息", "非Json数据或没有lottery_info或lottery为空") },
failure: err => {
log.error("从API响应数据中获取抽奖信息", err)
resolve(null) resolve(null)
} }
}, })
failure: err => { }
log.error("从API响应数据中获取抽奖信息", err)
resolve(null)
}
})
} else { } else {
log.warn('获取动态', `链接为空`) log.warn('获取动态', `链接为空`)
resolve(null) resolve(null)

View File

@ -17,7 +17,6 @@ const config = {
Articles: [], Articles: [],
/** /**
* 从API接口中获取抽奖信息
* @typedef {object} LotteryInfo * @typedef {object} LotteryInfo
* @property {string} lottery_info_type * @property {string} lottery_info_type
* @property {number} create_time * @property {number} create_time
@ -32,11 +31,19 @@ const config = {
* @property {string} des * @property {string} des
* @property {number} type * @property {number} type
* @property {boolean} hasOfficialLottery 是否官方 * @property {boolean} hasOfficialLottery 是否官方
* @typedef RespondBody * @typedef {object} RespondBody
* @property {string} err_msg 错误信息 * @property {string} err_msg 错误信息
* @property {LotteryInfo[]} lottery_info * @property {LotteryInfo[]} lottery_info
* API传回数据类型 {RespondBody} *
* - 从API接口中获取抽奖信息
* 获取抽奖信息的链接字符串 * 获取抽奖信息的链接字符串
* @example
* ["https://github.com/spiritLHL/sync_lottery"]
*
* - 从当前路径下符合要求的文件中获取
* 文件名
* @example
* ["file://lottery_info_1.json"]
*/ */
APIs: [], APIs: [],
@ -52,6 +59,11 @@ const config = {
*/ */
LotteryOrder: [2, 0, 1, 3], LotteryOrder: [2, 0, 1, 3],
/**
* 保存抽奖信息至文件
*/
save_lottery_info_to_file: false,
/** /**
* API发送数据类型 {LotteryInfo[]} * API发送数据类型 {LotteryInfo[]}
* 上传抽奖信息的链接字符串 * 上传抽奖信息的链接字符串

View File

@ -1,4 +1,4 @@
const { getRemoteConfig, createDir, createFile } = require("../utils"); const { getRemoteConfig, createDir, createFile, dyids_dir } = require("../utils");
const config = require("../data/config"); const config = require("../data/config");
let global_var = { let global_var = {
@ -47,7 +47,7 @@ let global_var = {
this.set('remoteconfig', await getRemoteConfig()); this.set('remoteconfig', await getRemoteConfig());
} }
await createDir('dyids'); await createDir('dyids');
await createFile(num < 2 ? 'dyid.txt' : `dyid${num}.txt`, '', 'a') await createFile(dyids_dir, num < 2 ? 'dyid.txt' : `dyid${num}.txt`, '', 'a')
} }
}; };

View File

@ -15,6 +15,8 @@ const utils = {
config_file: path.join(process.cwd(), "my_config.js"), config_file: path.join(process.cwd(), "my_config.js"),
/**dyids存放目录 */ /**dyids存放目录 */
dyids_dir: path.join(process.cwd(), "dyids"), dyids_dir: path.join(process.cwd(), "dyids"),
/**lottery_info存放目录 */
lottery_info_dir: path.join(process.cwd(), "lottery_info"),
/**dyid长度 */ /**dyid长度 */
dyid_length: 18, dyid_length: 18,
/** /**
@ -343,13 +345,14 @@ const utils = {
}, },
/** /**
* CreateFile * CreateFile
* @param {string} filepath 相对于dyids的文件路径 * @param {string} basename
* @param {string} filename
* @param {string} [defaultValue] 写入默认值 * @param {string} [defaultValue] 写入默认值
* @param {string} flag * @param {string} flag
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
createFile(filepath, defaultValue, flag) { createFile(basename, filename, defaultValue, flag) {
const fpath = path.join(utils.dyids_dir, filepath); const fpath = path.join(basename, filename);
const buffer = Buffer.from(defaultValue); const buffer = Buffer.from(defaultValue);
return new Promise((resolve, rejects) => { return new Promise((resolve, rejects) => {
fs.open(fpath, flag, (err, fd) => { fs.open(fpath, flag, (err, fd) => {
@ -384,6 +387,55 @@ const utils = {
writeDyidFile(num) { writeDyidFile(num) {
const fpath = num < 2 ? path.join(utils.dyids_dir, 'dyid.txt') : path.join(utils.dyids_dir, `dyid${num}.txt`); const fpath = num < 2 ? path.join(utils.dyids_dir, 'dyid.txt') : path.join(utils.dyids_dir, `dyid${num}.txt`);
return fs.createWriteStream(fpath, { flags: 'a' }) return fs.createWriteStream(fpath, { flags: 'a' })
},
/**
* 追加lotteryinfo
* @param {string} from
* @param {import("./core/searcher").LotteryInfo[]} lottery_info
* @return {Promise<void>}
*/
appendLotteryInfoFile(from, lottery_info) {
let all_lottery_info = {};
try {
all_lottery_info = utils.strToJson(fs.readFileSync(path.join(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`)).toString())
} catch (_) {
all_lottery_info = {}
}
utils
.createDir(utils.lottery_info_dir)
.then(() => {
if (all_lottery_info[from] instanceof Array) {
all_lottery_info[from].push(...lottery_info)
} else {
all_lottery_info[from] = lottery_info
}
utils.createFile(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`, JSON.stringify(all_lottery_info), "w")
})
},
/**
* 读取lottery_info
* @param {string} filename
* @return {Promise<import("./core/searcher").LotteryInfo[]>}
*/
readLotteryInfoFile(filename) {
return new Promise((resolve) => {
fs.readFile(path.join(utils.lottery_info_dir, filename), (err, data) => {
if (err) {
resolve([])
} else {
let all_lottery_info = utils.strToJson(data.toString('utf8'));
resolve(Object.values(all_lottery_info).flat())
}
})
});
},
/**
* 清空lottery_info
*/
clearLotteryInfo() {
return new Promise((resolve) => {
fs.rm(utils.lottery_info_dir, { recursive: true, force: true }, resolve)
});
} }
}; };

View File

@ -1,4 +1,4 @@
const { version: ve, env_file, config_file, log, hasEnv, delay, hasFileOrDir } = require("./lib/utils"); const { version: ve, env_file, config_file, log, hasEnv, delay, hasFileOrDir, clearLotteryInfo } = require("./lib/utils");
const metainfo = [ const metainfo = [
` _ _ _ _____ _ _ `, ` _ _ _ _____ _ _ `,
@ -158,11 +158,13 @@ function initConfig() {
log.warn('结束运行', '5秒后自动退出'); log.warn('结束运行', '5秒后自动退出');
await delay(5 * 1000); await delay(5 * 1000);
} else { } else {
await clearLotteryInfo();
while (loop_wait) { while (loop_wait) {
log.info('程序休眠', `${loop_wait / 1000}秒后再次启动`) log.info('程序休眠', `${loop_wait / 1000}秒后再次启动`)
await delay(loop_wait) await delay(loop_wait)
if (initEnv() || initConfig()) return; if (initEnv() || initConfig()) return;
await main() await main()
await clearLotteryInfo();
} }
log.info('结束运行', '未在config.js中设置休眠时间') log.info('结束运行', '未在config.js中设置休眠时间')
} }

View File

@ -6,30 +6,19 @@ module.exports = Object.freeze({
/** /**
* 监视更转的用户uid * 监视更转的用户uid
*/ */
UIDs: [ UIDs: [],
689277291,
241675899
],
/** /**
* 监视的tag * 监视的tag
*/ */
TAGs: [ TAGs: [],
'互动抽奖',
'转发抽奖',
'动态抽奖',
'抽奖',
],
/** /**
* 监视的专栏关键词 * 监视的专栏关键词
*/ */
Articles: [ Articles: [],
'抽奖合集'
],
/** /**
* 从API接口中获取抽奖信息
* @typedef {object} LotteryInfo * @typedef {object} LotteryInfo
* @property {string} lottery_info_type * @property {string} lottery_info_type
* @property {number} create_time * @property {number} create_time
@ -44,15 +33,21 @@ module.exports = Object.freeze({
* @property {string} des * @property {string} des
* @property {number} type * @property {number} type
* @property {boolean} hasOfficialLottery 是否官方 * @property {boolean} hasOfficialLottery 是否官方
* @typedef RespondBody * @typedef {object} RespondBody
* @property {string} err_msg 错误信息 * @property {string} err_msg 错误信息
* @property {LotteryInfo[]} lottery_info * @property {LotteryInfo[]} lottery_info
* API传回数据类型 {RespondBody} *
* - 从API接口中获取抽奖信息
* 获取抽奖信息的链接字符串 * 获取抽奖信息的链接字符串
* @example * @example
* "https://github.com/spiritLHL/sync_lottery" * ["https://github.com/spiritLHL/sync_lottery"]
*
* - 从当前路径下符合要求的文件中获取
* 文件名
* @example
* ["file://lottery_info_1.json"]
*/ */
APIs: [], APIs: ["file://lottery_info_1.json"],
/** /**
* 抽奖参与顺序组合 * 抽奖参与顺序组合
@ -66,6 +61,11 @@ module.exports = Object.freeze({
*/ */
LotteryOrder: [2, 0, 1, 3], LotteryOrder: [2, 0, 1, 3],
/**
* 保存抽奖信息至文件
*/
save_lottery_info_to_file: false,
/** /**
* API发送数据类型 {LotteryInfo[]} * API发送数据类型 {LotteryInfo[]}
* 上传抽奖信息的链接字符串 * 上传抽奖信息的链接字符串
@ -434,7 +434,28 @@ module.exports = Object.freeze({
* 针对某一账号的特别设置 * 针对某一账号的特别设置
* config_[数字] 依次类推 * config_[数字] 依次类推
*/ */
config_1: {}, config_1: {
/**
* 手动添加抽奖号UID
* - 抽奖动态下的二级小号
*/
UIDs: [],
TAGs: [
'互动抽奖',
'转发抽奖',
'动态抽奖',
'抽奖',
],
Articles: [
'抽奖合集'
],
APIs: [],
save_lottery_info_to_file: true,
},
config_2: {}, config_2: {},
config_3: {} config_3: {}
}) })