diff --git a/.gitignore b/.gitignore index 22439ea..8670abe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ .vscode/ tests/ dyids/ +lottery_info/ dist/ .env *.log diff --git a/env.example.js b/env.example.js index 5398490..5bd0d3d 100644 --- a/env.example.js +++ b/env.example.js @@ -32,12 +32,21 @@ module.exports = Object.freeze({ /** * 为防止环境变量过长, 请将多账号填在此处 - * 以大括号内容为模板依次复制(包含大括号),逗号分割 - * ``` - * ... - * NUMBER: 1 - * ... - * NUMBER: 2 + * 以 **大括号内容** 为模板依次复制(包含大括号),逗号分割 + * + * ```txt + * [ + * { + * ... + * NUMBER: 1 + * ... + * }, + * { + * ... + * NUMBER: 2 + * ... + * } + * ] * ``` */ multiple_account_parm: [ diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 5616d5c..855607f 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -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 bili = require('../net/bili'); const { sendNotify } = require('../helper/notify'); @@ -256,7 +256,7 @@ class Monitor extends Searcher { /** 所有抽奖信息 */ let alllotteryinfo = []; 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; /** @@ -287,9 +287,14 @@ class Monitor extends Searcher { 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) { - log.info("上传抽奖信息", "开始") - await new Promise((resolve) => { + log.info("上传抽奖信息", "上传开始") + new Promise((resolve) => { send({ url: set_lottery_info_url, method: "POST", diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 88af392..f2bfad1 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -478,64 +478,68 @@ class Searcher { if (api) { const { strToJson } = utils; log.info('获取动态', `开始获取链接(${api})中的抽奖信息`) - 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 (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 (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 (!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) + if (card) { + await utils.delay(get_dynamic_detail_wait) - const { is_liked } = parseDynamicCard(card) + const { is_liked } = parseDynamicCard(card) - if (is_liked) { - log.info('获取动态', `动态(${dyid})已转发过`) - } else { - cur.is_liked = is_liked - results.push(cur) + if (is_liked) { + log.info('获取动态', `动态(${dyid})已转发过`) + } else { + cur.is_liked = is_liked + results.push(cur) + } } + } else { + results.push(cur) } - } else { - results.push(cur) - } - return results + return results - }, Promise.resolve([])) + }, Promise.resolve([])) - resolve(lottery_info) - return + resolve(lottery_info) + 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) } - }, - failure: err => { - log.error("从API响应数据中获取抽奖信息", err) - resolve(null) - } - }) + }) + } } else { log.warn('获取动态', `链接为空`) resolve(null) diff --git a/lib/data/config.js b/lib/data/config.js index addc2b0..45ccc55 100644 --- a/lib/data/config.js +++ b/lib/data/config.js @@ -17,7 +17,6 @@ const config = { Articles: [], /** - * 从API接口中获取抽奖信息 * @typedef {object} LotteryInfo * @property {string} lottery_info_type * @property {number} create_time @@ -32,11 +31,19 @@ const config = { * @property {string} des * @property {number} type * @property {boolean} hasOfficialLottery 是否官方 - * @typedef RespondBody + * @typedef {object} RespondBody * @property {string} err_msg 错误信息 * @property {LotteryInfo[]} lottery_info - * API传回数据类型 {RespondBody} + * + * - 从API接口中获取抽奖信息 * 获取抽奖信息的链接字符串 + * @example + * ["https://github.com/spiritLHL/sync_lottery"] + * + * - 从当前路径下符合要求的文件中获取 + * 文件名 + * @example + * ["file://lottery_info_1.json"] */ APIs: [], @@ -52,6 +59,11 @@ const config = { */ LotteryOrder: [2, 0, 1, 3], + /** + * 保存抽奖信息至文件 + */ + save_lottery_info_to_file: false, + /** * API发送数据类型 {LotteryInfo[]} * 上传抽奖信息的链接字符串 diff --git a/lib/data/global_var.js b/lib/data/global_var.js index 050b5c9..b72f9fb 100644 --- a/lib/data/global_var.js +++ b/lib/data/global_var.js @@ -1,4 +1,4 @@ -const { getRemoteConfig, createDir, createFile } = require("../utils"); +const { getRemoteConfig, createDir, createFile, dyids_dir } = require("../utils"); const config = require("../data/config"); let global_var = { @@ -47,7 +47,7 @@ let global_var = { this.set('remoteconfig', await getRemoteConfig()); } 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') } }; diff --git a/lib/utils.js b/lib/utils.js index 6fc0066..24042cb 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -15,6 +15,8 @@ const utils = { config_file: path.join(process.cwd(), "my_config.js"), /**dyids存放目录 */ dyids_dir: path.join(process.cwd(), "dyids"), + /**lottery_info存放目录 */ + lottery_info_dir: path.join(process.cwd(), "lottery_info"), /**dyid长度 */ dyid_length: 18, /** @@ -343,13 +345,14 @@ const utils = { }, /** * CreateFile - * @param {string} filepath 相对于dyids的文件路径 + * @param {string} basename + * @param {string} filename * @param {string} [defaultValue] 写入默认值 * @param {string} flag * @returns {Promise} */ - createFile(filepath, defaultValue, flag) { - const fpath = path.join(utils.dyids_dir, filepath); + createFile(basename, filename, defaultValue, flag) { + const fpath = path.join(basename, filename); const buffer = Buffer.from(defaultValue); return new Promise((resolve, rejects) => { fs.open(fpath, flag, (err, fd) => { @@ -384,6 +387,55 @@ const utils = { writeDyidFile(num) { 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' }) + }, + /** + * 追加lotteryinfo + * @param {string} from + * @param {import("./core/searcher").LotteryInfo[]} lottery_info + * @return {Promise} + */ + 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} + */ + 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) + }); } }; diff --git a/main.js b/main.js index 5afcff8..2908317 100644 --- a/main.js +++ b/main.js @@ -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 = [ ` _ _ _ _____ _ _ `, @@ -158,11 +158,13 @@ function initConfig() { log.warn('结束运行', '5秒后自动退出'); await delay(5 * 1000); } else { + await clearLotteryInfo(); while (loop_wait) { log.info('程序休眠', `${loop_wait / 1000}秒后再次启动`) await delay(loop_wait) if (initEnv() || initConfig()) return; await main() + await clearLotteryInfo(); } log.info('结束运行', '未在config.js中设置休眠时间') } diff --git a/my_config.example.js b/my_config.example.js index c133256..bb2e34d 100644 --- a/my_config.example.js +++ b/my_config.example.js @@ -6,30 +6,19 @@ module.exports = Object.freeze({ /** * 监视更转的用户uid */ - UIDs: [ - 689277291, - 241675899 - ], + UIDs: [], /** * 监视的tag */ - TAGs: [ - '互动抽奖', - '转发抽奖', - '动态抽奖', - '抽奖', - ], + TAGs: [], /** * 监视的专栏关键词 */ - Articles: [ - '抽奖合集' - ], + Articles: [], /** - * 从API接口中获取抽奖信息 * @typedef {object} LotteryInfo * @property {string} lottery_info_type * @property {number} create_time @@ -44,15 +33,21 @@ module.exports = Object.freeze({ * @property {string} des * @property {number} type * @property {boolean} hasOfficialLottery 是否官方 - * @typedef RespondBody + * @typedef {object} RespondBody * @property {string} err_msg 错误信息 * @property {LotteryInfo[]} lottery_info - * API传回数据类型 {RespondBody} + * + * - 从API接口中获取抽奖信息 * 获取抽奖信息的链接字符串 * @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], + /** + * 保存抽奖信息至文件 + */ + save_lottery_info_to_file: false, + /** * API发送数据类型 {LotteryInfo[]} * 上传抽奖信息的链接字符串 @@ -434,7 +434,28 @@ module.exports = Object.freeze({ * 针对某一账号的特别设置 * config_[数字] 依次类推 */ - config_1: {}, + config_1: { + /** + * 手动添加抽奖号UID + * - 抽奖动态下的二级小号 + */ + UIDs: [], + + TAGs: [ + '互动抽奖', + '转发抽奖', + '动态抽奖', + '抽奖', + ], + + Articles: [ + '抽奖合集' + ], + + APIs: [], + + save_lottery_info_to_file: true, + }, config_2: {}, config_3: {} })