diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..513f4228 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ + diff --git a/.github/workflows/checkin.yml b/.github/workflows/checkin.yml index 898686d6..7c6ffea1 100644 --- a/.github/workflows/checkin.yml +++ b/.github/workflows/checkin.yml @@ -2,7 +2,7 @@ name: CheckIn on: schedule: - - cron: "30 22 * * *" # 北京时间上午06:30 + - cron: "40 22 * * *" # 北京时间上午06:40 workflow_dispatch: jobs: CheckIn: @@ -13,9 +13,15 @@ jobs: - name: Run Project env: COOKIE: ${{ secrets.COOKIE }} + COOKIE_2: ${{ secrets.COOKIE_2 }} + COOKIE_3: ${{ secrets.COOKIE_3 }} + COOKIE_4: ${{ secrets.COOKIE_4 }} + COOKIE_5: ${{ secrets.COOKIE_5 }} EMAIL_USER: ${{ secrets.EMAIL_USER }} EMAIL_PASS: ${{ secrets.EMAIL_PASS }} EMAIL_TO: ${{ secrets.EMAIL_TO }} + DINGDING_WEBHOOK: ${{ secrets.DINGDING_WEBHOOK }} + PUSHPLUS_TOKEN: ${{ secrets.PUSHPLUS_TOKEN }} run: | yarn yarn checkin diff --git a/.github/workflows/seaGold.yml b/.github/workflows/seaGold.yml index c9d87123..0d5ddb11 100644 --- a/.github/workflows/seaGold.yml +++ b/.github/workflows/seaGold.yml @@ -13,9 +13,15 @@ jobs: - name: Run Project env: COOKIE: ${{ secrets.COOKIE }} + COOKIE_2: ${{ secrets.COOKIE_2 }} + COOKIE_3: ${{ secrets.COOKIE_3 }} + COOKIE_4: ${{ secrets.COOKIE_4 }} + COOKIE_5: ${{ secrets.COOKIE_5 }} EMAIL_USER: ${{ secrets.EMAIL_USER }} EMAIL_PASS: ${{ secrets.EMAIL_PASS }} EMAIL_TO: ${{ secrets.EMAIL_TO }} + DINGDING_WEBHOOK: ${{ secrets.DINGDING_WEBHOOK }} + PUSHPLUS_TOKEN: ${{ secrets.PUSHPLUS_TOKEN }} run: | yarn yarn seaGold diff --git a/.gitignore b/.gitignore index 7df6d182..d8c2951c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store node_modules +dist # local env files .env.local diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..824ac82b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "printWidth": 100, + "trailingComma": "none", + "bracketSpacing": false +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a07b7eba --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# 参与贡献 + +## 分支介绍 + +- `package` 掘金API发布npm包,供给自动化工作流使用。 +- `workflows` 自动化工作流开发分支。 +- `main` 是 workflows 分支的稳定版。 + +**处理自动化相关逻辑:** +base: `workflows` <- compare `your branch` + +**处理JueJinAPI相关逻辑:** +base: `package` <- compare `your branch` + +## workflows 分支 + +### 安装 + +- `yarn` 安装依赖 + +### 环境变量 + +- `/scripts/utils/env.js` 替换本地测试所需的环境变量 + +```javascript +module.exports = { + COOKIE: "测试掘金Cookie", + // ... +}; +``` + +### 本地运行 + +- `yarn checkin` 运行掘金签到脚本 +- `yarn seagold` 运行海底掘金游戏脚本 + +## package 分支 + +- `yarn` 安装依赖 +- `yarn dev` 启动开发模式 +- `node tests/your-test.js` 测试一个模块 diff --git a/README.md b/README.md index f6a9b010..b02aea8d 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,23 @@ -
- - 稀土掘金 - -
- -

JuejinHelper-稀土掘金助手

签到、抽奖、沾喜气、海底掘金游戏、自动化工作流。

## 使用 自动化执行任务: 掘金每日签到, 沾喜气, 免费抽奖, 海底掘金游戏, 最后将结果报告邮件通知订阅人。\ +======= +

签到、抽奖、沾喜气、消除Bug、海底掘金游戏、自动化工作流。

+ +## 使用 + +自动化执行任务: 掘金每日签到, 沾喜气, 免费抽奖, 消除Bug, 海底掘金游戏, 最后将结果报告邮件通知订阅人。\ +>>>>>>> Stashed changes 自动化运行时间: 北京时间上午06:30 1. [Fork 仓库](https://github.com/iDerekLi/juejin-helper) 2. 仓库 -> Settings -> Secrets -> New repository secret, 添加Secrets变量如下: +<<<<<<< Updated upstream | Name | Value | | --- | --- | | COOKIE | 掘金网站Cookie, 打开浏览器,登录 [掘金](https://juejin.cn/), 打开控制台DevTools -> Network,复制 cookie, **掘金Cookie有效期约1个月需定期更新.** | @@ -25,12 +26,29 @@ | EMAIL_TO | 订阅人邮箱地址(收件人). 如需多人订阅使用 `, ` 分割, 例如: `a@163.com, b@qq.com` | 3. 仓库 -> Actions, 检查Workflows并启用。 +======= + | Name | Value | Required | + | --- | --- | --- | + | COOKIE | 掘金网站Cookie | 是 | + | COOKIE_2 | 多用户, 当需要同时运行多个掘金用户时所需, 支持最多 **5** 名用户(即COOKIE + COOKIE_2 - COOKIE_5) | 否 | + | EMAIL_USER | 发件人邮箱地址(需要开启 SMTP) | 否 | + | EMAIL_PASS | 发件人邮箱密码(SMTP密码) | 否 | + | EMAIL_TO | 订阅人邮箱地址(收件人). 如需多人订阅使用 `, ` 分割, 例如: `a@163.com, b@qq.com` | 否 | + | DINGDING_WEBHOOK | 钉钉机器人WEBHOOK | 否 | + | PUSHPLUS_TOKEN | [Pushplus](http://www.pushplus.plus/) 官网申请,支持微信消息推送 | 否 | + +4. 仓库 -> Actions, 检查Workflows并启用。 +>>>>>>> Stashed changes ## 预览 | 掘金每日签到 | 海底掘金游戏 | |:-----------:| :-------------:| +<<<<<<< Updated upstream | ![掘金每日签到](https://user-images.githubusercontent.com/24502299/150481822-b488d30c-93b6-4d73-9e28-56c04a9413fb.png) | ![海底掘金游戏](https://user-images.githubusercontent.com/24502299/150625136-5649d2fe-b204-40aa-b8b5-7f54a44e018d.png) | +======= +| ![掘金每日签到](https://user-images.githubusercontent.com/24502299/156475511-342cfcd8-3b66-4b9c-8614-215e0b4e08a1.jpg) | ![海底掘金游戏](https://user-images.githubusercontent.com/24502299/156475550-c8cc459a-3b27-4ca6-a07b-902b65bea7a9.jpg) | +>>>>>>> Stashed changes ## 问题 @@ -51,10 +69,14 @@ DevTools截图: [![海底掘金挑战赛](https://user-images.githubusercontent.com/24502299/151397151-0d69998a-2310-4a32-945f-c8e0035ed65d.png)](https://juejin.cn/game/haidijuejin/) +<<<<<<< Updated upstream ## 赞赏 ### ☕️微信赞赏!鼓励升级! -微信赞赏 +======= +## 贡献 + +这个项目的存在要感谢所有做出贡献的人。 请先阅读 [[Contribute](CONTRIBUTING.md)]。 +您可以将任何想法作为 [拉取请求](https://github.com/iDerekLi/juejin-helper/pulls) 或 [GitHub问题](https://github.com/iDerekLi/juejin-helper/issues) 提交。 + -## 许可 -[MIT](./LICENSE) diff --git a/package.json b/package.json index 3f6ba950..5158a417 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "juejin-helper", - "version": "1.0.0", - "description": "稀土掘金助手:签到、抽奖、沾喜气、海底淘金、自动化工作流。", + "version": "1.5.1", + "description": "稀土掘金助手:签到、抽奖、沾喜气、消除Bug、海底掘金游戏、自动化工作流。", "author": "Derek Li", "license": "MIT", "scripts": { @@ -11,8 +11,10 @@ }, "dependencies": { "fast-astar": "^1.0.6", + "juejin-helper": "^1.7.2", "jsonwebtoken": "^8.5.1", "node-fetch": "^2.6.1", + "juejin-helper": "^1.5.1", "nodemailer": "^6.7.0" }, "repository": { diff --git a/scripts/api/api.js b/scripts/api/api.js deleted file mode 100644 index 8b9e6241..00000000 --- a/scripts/api/api.js +++ /dev/null @@ -1,57 +0,0 @@ -const fetch = require("node-fetch"); - -class Api { - baseURL = ""; - headers = { - "content-type": "application/json; charset=utf-8", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36", - "accept-encoding": "gzip, deflate, br", - "accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", - "sec-ch-ua": `"Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"`, - "sec-ch-ua-mobile": "?0", - accept: "*/*", - credentials: "include" - }; - - requestInterceptor = config => config; - responseInterceptor = res => res; - - async request(config) { - config = this.requestInterceptor({ - baseURL: config.baseURL || this.baseURL, - url: config.url, - method: (config.method || "get").toLocaleUpperCase(), - headers: { - ...this.headers, - ...config.headers - }, - data: config.data - }); - - const response = await fetch(config.baseURL + config.url, { - method: config.method, - headers: config.headers, - body: config.method !== "GET" ? JSON.stringify(config.data) : undefined - }); - - return this.responseInterceptor(await response.json()); - } - - async get(url, config) { - return this.request({ - ...config, - url, - method: "get" - }); - } - - async post(url, config) { - return this.request({ - ...config, - url, - method: "post" - }); - } -} - -module.exports = Api; diff --git a/scripts/api/juejin-api.js b/scripts/api/juejin-api.js deleted file mode 100644 index a1e3bd60..00000000 --- a/scripts/api/juejin-api.js +++ /dev/null @@ -1,67 +0,0 @@ -const Api = require("./api"); -const env = require("../utils/env"); - -class JuejinApi extends Api { - constructor() { - super(); - this.baseURL = "https://api.juejin.cn"; - this.headers.referer = "https://juejin.cn/"; - this.headers.cookie = env.COOKIE; - } - - responseInterceptor = res => { - if (res.err_no) { - throw new Error(res.err_msg); - } - return res.data; - } - - async getToken() { - return this.get("/get/token", { - baseURL: "https://juejin.cn" - }); - } - - async getUserInfo() { - return this.get("/user_api/v1/user/get"); - } - - async getLotteryConfig() { - return this.get("/growth_api/v1/lottery_config/get"); - } - - async getCurrentPoint() { - return this.get("/growth_api/v1/get_cur_point"); - } - - async drawLottery() { - return this.post("/growth_api/v1/lottery/draw"); - } - - async checkIn() { - return this.post("/growth_api/v1/check_in"); - } - - async getLotteriesLuckyUsers() { - return this.post("/growth_api/v1/lottery_history/global_big", { - data: { - page_no: 1, - page_size: 5 - } - }); - } - - async dipLucky(lottery_history_id) { - return this.post("/growth_api/v1/lottery_lucky/dip_lucky", { - data: { - lottery_history_id - } - }); - } - - async getMyLucky() { - return this.post("/growth_api/v1/lottery_lucky/my_lucky"); - } -} - -module.exports = new JuejinApi; diff --git a/scripts/api/juejin-game-api.js b/scripts/api/juejin-game-api.js deleted file mode 100644 index 7c2d5389..00000000 --- a/scripts/api/juejin-game-api.js +++ /dev/null @@ -1,105 +0,0 @@ -const Api = require("./api"); -const jwt = require("jsonwebtoken"); - -class JuejinGameApi extends Api { - user = null; - - constructor() { - super(); - this.baseURL = "https://juejin-game.bytedance.com/game"; - this.headers.referer = "https://juejin.cn/"; - } - - setUser(user) { - this.user = user; - } - - setToken(token) { - this.headers.Authorization = `Bearer ${token}`; - } - - requestInterceptor = config => { - if (this.user) { - config.url += (config.url.indexOf("?") === -1 ? "?" : "&") + `uid=${this.user.user_id}&time=${Date.now()}`; - } - return config; - }; - - responseInterceptor = res => { - if (res.code !== 0) { - throw new Error(res.message); - } - return res.data; - } - - async gameLogin() { - return this.post("/sea-gold/user/login", { - data: { - name: this.user.user_name - } - }); - } - - async gameInfo() { - return this.get("/sea-gold/home/info"); - } - - async gameStart() { - return this.post("/sea-gold/game/start", { - data: { - roleId: 3 - } - }); - } - - async gameOver() { - // const result = { - // activity: "", - // deep: 3, - // gameDiamond: 34, // 当局获取 - // originMapData: [], - // passLine: [{ x: 0, y: 0 }, { x: 0, y: 1 }], - // picoDiamond: 0, - // realDiamond: 34, // 真实获取 - // todayDiamond: 34, // 今日获取 - // todayLimitDiamond: 1500 // 今日最大获取 - // }; - return this.post("/sea-gold/game/over", { - data: { - isButton: 1 - } - }); - } - - async gameCommand(gameId, command = []) { - // const result = { - // appendMapData: [], - // blockData: { moveUp: 14, moveDown: 14, moveLeft: 2, moveRight: 5, jump: 3, loop: 3 }, - // curPos: { x: 0, y: 2 }, - // gameDiamond: 34 - // } - const privateKey = "-----BEGIN EC PARAMETERS-----\nBggqhkjOPQMBBw==\n-----END EC PARAMETERS-----\n-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIDB7KMVQd+eeKt7AwDMMUaT7DE3Sl0Mto3LEojnEkRiAoAoGCCqGSM49\nAwEHoUQDQgAEEkViJDU8lYJUenS6IxPlvFJtUCDNF0c/F/cX07KCweC4Q/nOKsoU\nnYJsb4O8lMqNXaI1j16OmXk9CkcQQXbzfg==\n-----END EC PRIVATE KEY-----\n"; - const token = jwt.sign({ - gameId: gameId, - time: new Date().getTime() - }, privateKey, { - algorithm: "ES256", - expiresIn: 2592e3, - header: { - alg: "ES256", - typ: "JWT" - } - }); - return this.post("/sea-gold/game/command", { - headers: { - "x-tt-gameid": token - }, - data: { - command - // command: ["R", { times: 2, command: ["R"] }, "2"] - } - }); - } -} - -module.exports = new JuejinGameApi; diff --git a/scripts/checkin.js b/scripts/checkin.js index 32065fad..c751947a 100644 --- a/scripts/checkin.js +++ b/scripts/checkin.js @@ -1,143 +1,194 @@ -const api = require("./api/juejin-api"); -const console = require("./utils/logger"); +const JuejinHelper = require("juejin-helper"); const utils = require("./utils/utils"); const email = require("./utils/email"); +const env = require("./utils/env"); + +class CheckIn { + username = ""; + todayStatus = 0; // 未签到 + incrPoint = 0; + sumPoint = 0; // 当前矿石数 + contCount = 0; // 连续签到天数 + sumCount = 0; // 累计签到天数 + dipStatus = 0; + dipValue = 0; // 沾喜气 + luckyValue = 0; + lottery = []; // 奖池 + pointCost = 0; // 一次抽奖消耗 + freeCount = 0; // 免费抽奖次数 + drawLotteryHistory = {}; + lotteryCount = 0; + luckyValueProbability = 0; + + calledSdkSetting = false; + calledTrackGrowthEvent = false; + calledTrackOnloadEvent = false; + + async run() { + const juejin = new JuejinHelper(); + try { + await juejin.login(env.COOKIE); + console.log(env.COOKIE); + } catch (e) { + console.error(e); + + + throw new Error("登录失败, 请尝试更新Cookies!"); + } -async function run(args) { - const state = { - simulateSpeed: 100, // ms/进行一次抽奖 - sumPoint: 0, - pointCost: 0, - supplyPoint: 0, - freeCount: 0, - luckyValue: 0, - lottery: [], - counter: 0, - prize: {} - }; - - await utils.wait(100); - console.clear(); - - try { - const checkInResult = await api.checkIn(); - const incrPoint = checkInResult.incr_point; - console.log(`签到成功 +${incrPoint} 矿石`); - - const sumPoint = checkInResult.sum_point; - state.sumPoint = sumPoint; - } catch (e) { - console.log(e.message); - - const sumPoint = await api.getCurrentPoint(); - state.sumPoint = sumPoint; - } + this.username = juejin.getUser().user_name; + + const growth = juejin.growth(); + + const todayStatus = await growth.getTodayStatus(); + if (!todayStatus) { + const checkInResult = await growth.checkIn(); + + this.incrPoint = checkInResult.incr_point; + this.sumPoint = checkInResult.sum_point; + this.todayStatus = 1; // 本次签到 + } else { + this.todayStatus = 2; // 已签到 + } + + const counts = await growth.getCounts(); + this.contCount = counts.cont_count; + this.sumCount = counts.sum_count; - try { - const luckyusersResult = await api.getLotteriesLuckyUsers(); + const luckyusersResult = await growth.getLotteriesLuckyUsers(); if (luckyusersResult.count > 0) { const no1LuckyUser = luckyusersResult.lotteries[0]; - const dipLuckyResult = await api.dipLucky(no1LuckyUser.history_id); + const dipLuckyResult = await growth.dipLucky(no1LuckyUser.history_id); if (dipLuckyResult.has_dip) { - console.log(`今天你已经沾过喜气,明天再来吧!`); + this.dipStatus = 2; } else { - console.log(`沾喜气 +${dipLuckyResult.dip_value} 幸运值`); + this.dipStatus = 1; + this.dipValue = dipLuckyResult.dip_value; } } - } catch {} - - console.log(`当前余额:${state.sumPoint} 矿石`); - - const luckyResult = await api.getMyLucky(); - state.luckyValue = luckyResult.total_value; - console.log(`当前幸运值:${state.luckyValue}/6000`); - - const lotteryConfig = await api.getLotteryConfig(); - state.lottery = lotteryConfig.lottery; - state.pointCost = lotteryConfig.point_cost; - state.freeCount = lotteryConfig.free_count; - state.sumPoint += state.freeCount * state.pointCost; - - const getProbabilityOfWinning = sumPoint => { - const pointCost = state.pointCost; - const luckyValueCost = 10; - const totalDrawsNumber = sumPoint / pointCost; - let supplyPoint = 0; - for(let i = 0, length = Math.floor(totalDrawsNumber * 0.65); i < length; i++) { - supplyPoint += Math.ceil(Math.random() * 100) + + const luckyResult = await growth.getMyLucky(); + this.luckyValue = luckyResult.total_value; + + const lotteryConfig = await growth.getLotteryConfig(); + this.lottery = lotteryConfig.lottery; + this.pointCost = lotteryConfig.point_cost; + this.freeCount = lotteryConfig.free_count; + this.lotteryCount = 0; + + let freeCount = this.freeCount; + while (freeCount > 0) { + const result = await growth.drawLottery(); + this.drawLotteryHistory[result.lottery_id] = (this.drawLotteryHistory[result.lottery_id] || 0) + 1; + this.luckyValue = result.total_lucky_value + freeCount--; + this.lotteryCount++; + await utils.wait(utils.randomRangeNumber(300, 1000)); } - const luckyValue = (sumPoint + supplyPoint) / pointCost * luckyValueCost + state.luckyValue; - return luckyValue / 6000; - } - console.log(`预测梭哈矿石累计幸运值比率: ${(getProbabilityOfWinning(state.sumPoint) * 100).toFixed(2) + "%"}`); - - console.log(`免费抽奖次数: ${state.freeCount}`); - console.log(`准备免费抽奖!`); - - console.logGroupStart("奖品实况"); - - const getSupplyPoint = draw => { - const maybe = [ - ["lottery_id", "6981716980386496552"], - ["lottery_name", "随机矿石"], - ["lottery_type", 1] - ]; - if (maybe.findIndex(([prop, value]) => draw[prop] === value) !== -1) { - const supplyPoint = Number.parseInt(draw.lottery_name); - if (!isNaN(supplyPoint)) { - return supplyPoint; + + this.sumPoint = await growth.getCurrentPoint(); + + const getProbabilityOfWinning = sumPoint => { + const pointCost = this.pointCost; + const luckyValueCost = 10; + const totalDrawsNumber = sumPoint / pointCost; + let supplyPoint = 0; + for(let i = 0, length = Math.floor(totalDrawsNumber * 0.65); i < length; i++) { + supplyPoint += Math.ceil(Math.random() * 100) } + const luckyValue = (sumPoint + supplyPoint) / pointCost * luckyValueCost + this.luckyValue; + return luckyValue / 6000; } - return 0; - }; - - const lottery = async () => { - const result = await api.drawLottery(); - state.sumPoint -= state.pointCost; - state.sumPoint += getSupplyPoint(result); - state.luckyValue += result.draw_lucky_value; - state.counter++; - state.prize[result.lottery_name] = (state.prize[result.lottery_name] || 0) + 1; - console.log(`[第${state.counter}抽]:${result.lottery_name}`); - }; - - while (state.freeCount > 0) { - await lottery(); - state.freeCount--; - await utils.wait(state.simulateSpeed); - } - console.logGroupEnd("奖品实况"); + this.luckyValueProbability = getProbabilityOfWinning(this.sumPoint); - console.log(`当前余额:${state.sumPoint} 矿石`); + // 调用埋点 + const sdk = juejin.sdk(); - const recordInfo = []; - recordInfo.push("=====[战绩详情]====="); - if (state.counter > 0) { - const prizeList = []; - for (const key in state.prize) { - prizeList.push(`${key}: ${state.prize[key]}`); + try { + await sdk.slardarSDKSetting(); + this.calledSdkSetting = true; + } catch { + this.calledSdkSetting = false; } - recordInfo.push(...prizeList); - recordInfo.push("-------------------"); - recordInfo.push(`共计: ${state.counter}`); - } else { - recordInfo.push("暂无奖品"); + + try { + const result = await sdk.mockTrackGrowthEvent(); + if (result && result.e === 0) { + this.calledTrackGrowthEvent = true; + } else { + throw result; + } + } catch { + this.calledTrackGrowthEvent = false; + } + + try { + const result = await sdk.mockTrackOnloadEvent(); + if (result && result.e === 0) { + this.calledTrackOnloadEvent = true; + } else { + throw result; + } + } catch { + this.calledTrackOnloadEvent = false; + } + + console.log("------事件埋点追踪-------"); + console.log(`SDK状态: ${this.calledSdkSetting ? "加载成功" : "加载失败"}`); + console.log(`成长API事件埋点: ${this.calledTrackGrowthEvent ? "调用成功" : "调用失败"}`); + console.log(`OnLoad事件埋点: ${this.calledTrackOnloadEvent ? "调用成功" : "调用失败"}`); + console.log("-------------------------"); + + await juejin.logout(); } - recordInfo.push("+++++++++++++++++++"); - recordInfo.push(`幸运值: ${state.luckyValue}/6000`); - recordInfo.push("==================="); - console.log(recordInfo.join("\n ")); + + toString() { + const drawLotteryHistory = Object.entries(this.drawLotteryHistory).map(([lottery_id, count]) => { + const lotteryItem = this.lottery.find(item => item.lottery_id === lottery_id); + if (lotteryItem) { + return `${lotteryItem.lottery_name}: ${count}`; + } + return `${lottery_id}: ${count}` + }).join("\n"); + + return ` +掘友: ${this.username} +${this.todayStatus === 1 ? `签到成功 +${this.incrPoint} 矿石` : + this.todayStatus === 2 ? "今日已完成签到" : "签到失败"} +${this.dipStatus === 1 ? `沾喜气 +${this.dipValue} 幸运值` : + this.dipStatus === 2 ? "今日已经沾过喜气" : "沾喜气失败"} +连续签到天数 ${this.contCount} +累计签到天数 ${this.sumCount} +当前矿石数 ${this.sumPoint} +当前幸运值 ${this.luckyValue}/6000 +预测All In矿石累计幸运值比率 ${(this.luckyValueProbability * 100).toFixed(2) + "%"} +抽奖总次数 ${this.lotteryCount} +免费抽奖次数 ${this.freeCount} +${this.lotteryCount > 0 ? "==============\n" + drawLotteryHistory + "\n==============" : ""} + `.trim(); + } +} + +async function run(args) { + const checkin = new CheckIn(); + await utils.wait(utils.randomRangeNumber(1000, 5000)); // 初始等待1-5s + await checkin.run(); // 执行 + const content = checkin.toString(); + + console.log(content); // 打印结果 email({ subject: "掘金每日签到", - text: console.toString() + text: content }); } run(process.argv.splice(2)).catch(error => { email({ subject: "掘金每日签到", - html: `Error
${error.message}
` + html: `Error
${error.message}
` }); + + throw error; }); diff --git a/scripts/juejin-console-script.js b/scripts/juejin-console-script.js deleted file mode 100644 index 886b7059..00000000 --- a/scripts/juejin-console-script.js +++ /dev/null @@ -1,214 +0,0 @@ -!(({ api, console, utils }) => { - const state = { - simulateSpeed: 100, // ms/进行一次抽奖 - sumPoint: 0, - pointCost: 0, - supplyPoint: 0, - freeCount: 0, - luckyValue: 0, - lottery: [], - counter: 0, - prize: {} - }; - - !(async () => { - await utils.wait(100); - console.clear(); - - try { - const checkInResult = await api.checkIn(); - console.log(checkInResult); - const incrPoint = checkInResult.incr_point; - console.log(`签到成功 +${incrPoint} 矿石`); - - const sumPoint = checkInResult.sum_point; - state.sumPoint = sumPoint; - } catch (e) { - console.log(e.message); - - const sumPoint = await api.getCurrentPoint(); - state.sumPoint = sumPoint; - } - - try { - const luckyusersResult = await api.getLotteriesLuckyUsers(); - if (luckyusersResult.count > 0) { - const no1LuckyUser = luckyusersResult.lotteries[0]; - const dipLuckyResult = await api.dipLucky(no1LuckyUser.history_id); - if (dipLuckyResult.has_dip) { - console.log(`今天你已经沾过喜气,明天再来吧!`); - } else { - console.log(`沾喜气 +${dipLuckyResult.dip_value} 幸运值`); - } - } - } catch {} - - console.log(`当前余额:${state.sumPoint} 矿石`); - - const luckyResult = await api.getMyLucky(); - state.luckyValue = luckyResult.total_value; - console.log(`当前幸运值:${state.luckyValue}/6000`); - - const lotteryConfig = await api.getLotteryConfig(); - state.lottery = lotteryConfig.lottery; - state.pointCost = lotteryConfig.point_cost; - state.freeCount = lotteryConfig.free_count; - state.sumPoint += state.freeCount * state.pointCost; - console.log(`免费抽奖次数: ${state.freeCount}`); - - const getProbabilityOfWinning = sumPoint => { - const pointCost = 200; - const luckyValueCost = 10; - const totalDrawsNumber = sumPoint / pointCost; - const perhapsSupplyNumber = Math.floor(totalDrawsNumber * (2 / 3)); - let supplyPoint = 0; - for(let i = 0; i < perhapsSupplyNumber; i++) { - supplyPoint += Math.ceil(Math.random() * 100) - } - const luckyValue = (sumPoint + supplyPoint) / pointCost * luckyValueCost + state.luckyValue; - return luckyValue / 6000; - } - - console.log(`预测您必中奖幸运概率: ${(getProbabilityOfWinning(state.sumPoint) * 100).toFixed(2) + "%"}`); - - console.log(`准备梭哈!`); - - console.logGroupStart("奖品实况"); - - const getSupplyPoint = draw => { - const maybe = [ - ["lottery_id", "6981716980386496552"], - ["lottery_name", "随机矿石"], - ["lottery_type", 1] - ]; - if (maybe.findIndex(([prop, value]) => draw[prop] === value) !== -1) { - const supplyPoint = Number.parseInt(draw.lottery_name); - if (!isNaN(supplyPoint)) { - return supplyPoint; - } - } - return 0; - }; - - const lottery = async () => { - const result = await api.drawLottery(); - state.sumPoint -= state.pointCost; - state.sumPoint += getSupplyPoint(result); - state.luckyValue += result.draw_lucky_value; - state.counter++; - state.prize[result.lottery_name] = (state.prize[result.lottery_name] || 0) + 1; - console.log(`[第${state.counter}抽]:${result.lottery_name}`); - }; - - while (state.freeCount > 0) { - await lottery(); - state.freeCount--; - await utils.wait(state.simulateSpeed); - } - - // while (state.sumPoint >= state.pointCost) { - // await lottery(); - // await utils.wait(state.simulateSpeed); - // } - - console.logGroupEnd("奖品实况"); - - console.log(`弹药不足,当前余额:${state.sumPoint} 矿石`); - console.log(`养精蓄锐来日再战!`); - - const recordInfo = []; - recordInfo.push("=====[战绩详情]====="); - if (state.counter > 0) { - const prizeList = []; - for (const key in state.prize) { - prizeList.push(`${key}: ${state.prize[key]}`); - } - recordInfo.push(...prizeList); - recordInfo.push("-------------------"); - recordInfo.push(`共计: ${state.counter}`); - } else { - recordInfo.push("暂无奖品"); - } - recordInfo.push("+++++++++++++++++++"); - recordInfo.push(`幸运值: ${state.luckyValue}/6000`); - recordInfo.push("==================="); - console.log(recordInfo.join("\n")); - })(); -})( - (() => { - const cs = (() => { - const result = []; - return { - done: () => (typeof completion === "function" && completion(result), (result.length = 0)), - log: msg => (result.push(msg), console.log(msg)), - clear: () => ((result.length = 0), console.clear()), - logGroupStart: name => console.group(name), - logGroupEnd: name => console.groupEnd(name) - }; - })(); - - const api = (() => { - return { - async fetch({ path, method, data }) { - return fetch(`https://api.juejin.cn/growth_api/v1${path}`, { - headers: { - cookie: document.cookie - }, - method: method, - body: JSON.stringify(data), - credentials: "include" - }) - .then(res => res.json()) - .then(res => { - if (res.err_no) { - throw new Error(res.err_msg); - } - return res.data; - }); - }, - async get(path) { - return this.fetch({ path, method: "GET" }); - }, - async post(path, data) { - return this.fetch({ path, method: "POST", data }); - }, - async getLotteryConfig() { - return this.get("/lottery_config/get"); - }, - async getCurrentPoint() { - return this.get("/get_cur_point"); - }, - async drawLottery() { - return this.post("/lottery/draw"); - }, - async checkIn() { - return this.post("/check_in"); - }, - async getLotteriesLuckyUsers() { - return this.post("/lottery_history/global_big", { - page_no: 1, - page_size: 5 - }); - }, - async dipLucky(lottery_history_id) { - return this.post("/lottery_lucky/dip_lucky", { - lottery_history_id - }); - }, - async getMyLucky() { - return this.post("/lottery_lucky/my_lucky"); - } - }; - })(); - - const utils = (() => { - return { - async wait(time = 0) { - return new Promise(resolve => setTimeout(resolve, time)); - } - }; - })(); - - return { console: cs, api, utils }; - })() -); diff --git a/scripts/lottery.js b/scripts/lottery.js deleted file mode 100644 index 73b5b25d..00000000 --- a/scripts/lottery.js +++ /dev/null @@ -1,137 +0,0 @@ -const api = require("./utils/juejin-api"); -const console = require("./utils/logger"); -const utils = require("./utils/utils"); -const email = require("./utils/email"); - -async function run(args) { - const state = { - simulateSpeed: 100, // ms/进行一次抽奖 - sumPoint: 0, - pointCost: 0, - supplyPoint: 0, - freeCount: 0, - luckyValue: 0, - lottery: [], - counter: 0, - prize: {} - }; - - await utils.wait(100); - console.clear(); - - try { - const checkInResult = await api.checkIn(); - console.log(checkInResult); - const incrPoint = checkInResult.incr_point; - console.log(`签到成功 +${incrPoint} 矿石`); - - const sumPoint = checkInResult.sum_point; - state.sumPoint = sumPoint; - } catch (e) { - console.log(e.message); - - const sumPoint = await api.getCurrentPoint(); - state.sumPoint = sumPoint; - } - - try { - const luckyusersResult = await api.getLotteriesLuckyUsers(); - if (luckyusersResult.count > 0) { - const no1LuckyUser = luckyusersResult.lotteries[0]; - const dipLuckyResult = await api.dipLucky(no1LuckyUser.history_id); - if (dipLuckyResult.has_dip) { - console.log(`今天你已经沾过喜气,明天再来吧!`); - } else { - console.log(`沾喜气 +${dipLuckyResult.dip_value} 幸运值`); - } - } - } catch {} - - console.log(`当前余额:${state.sumPoint} 矿石`); - - const luckyResult = await api.getMyLucky(); - state.luckyValue = luckyResult.total_value; - console.log(`当前幸运值:${state.luckyValue}/6000`); - - const lotteryConfig = await api.getLotteryConfig(); - state.lottery = lotteryConfig.lottery; - state.pointCost = lotteryConfig.point_cost; - state.freeCount = lotteryConfig.free_count; - state.sumPoint += state.freeCount * state.pointCost; - console.log(`免费抽奖次数: ${state.freeCount}`); - - console.log(`准备梭哈!`); - - console.logGroupStart("奖品实况"); - - const getSupplyPoint = draw => { - const maybe = [ - ["lottery_id", "6981716980386496552"], - ["lottery_name", "随机矿石"], - ["lottery_type", 1] - ]; - if (maybe.findIndex(([prop, value]) => draw[prop] === value) !== -1) { - const supplyPoint = Number.parseInt(draw.lottery_name); - if (!isNaN(supplyPoint)) { - return supplyPoint; - } - } - return 0; - }; - - const lottery = async () => { - const result = await api.drawLottery(); - state.sumPoint -= state.pointCost; - state.sumPoint += getSupplyPoint(result); - state.luckyValue += result.draw_lucky_value; - state.counter++; - state.prize[result.lottery_name] = (state.prize[result.lottery_name] || 0) + 1; - console.log(`[第${state.counter}抽]:${result.lottery_name}`); - }; - - while (state.freeCount > 0) { - await lottery(); - state.freeCount--; - await utils.wait(state.simulateSpeed); - } - - while (state.sumPoint >= state.pointCost) { - await lottery(); - await utils.wait(state.simulateSpeed); - } - - console.logGroupEnd("奖品实况"); - - console.log(`弹药不足,当前余额:${state.sumPoint} 矿石`); - console.log(`养精蓄锐来日再战!`); - - const recordInfo = []; - recordInfo.push("=====[战绩详情]====="); - if (state.counter > 0) { - const prizeList = []; - for (const key in state.prize) { - prizeList.push(`${key}: ${state.prize[key]}`); - } - recordInfo.push(...prizeList); - recordInfo.push("-------------------"); - recordInfo.push(`共计: ${state.counter}`); - } else { - recordInfo.push("暂无奖品"); - } - recordInfo.push("+++++++++++++++++++"); - recordInfo.push(`幸运值: ${state.luckyValue}/6000`); - recordInfo.push("==================="); - console.log(recordInfo.join("\n")); - - email({ - subject: "掘金每日签到", - text: console.toString() - }); -} - -run(process.argv.splice(2)).catch(error => { - email({ - subject: "掘金每日签到", - html: `Error
${error.message}
` - }); -}); diff --git a/scripts/seaGold.js b/scripts/seaGold.js index 845522eb..bbfb696a 100644 --- a/scripts/seaGold.js +++ b/scripts/seaGold.js @@ -1,49 +1,59 @@ -const api = require("./api/juejin-api"); -const juejinGameApi = require("./api/juejin-game-api"); +const JuejinHelper = require("juejin-helper"); const utils = require("./utils/utils"); const { Grid, Astar } = require("fast-astar"); -const console = require("./utils/logger"); const email = require("./utils/email"); +const env = require("./utils/env"); + +class SeaGold { + gameApi = null; + + nodeRules = [ + { code: 0, hasBounty: false, isWall: false, name: "空地" }, + { code: 2, hasBounty: true, isWall: false, name: "矿石", isBest: true }, + { code: 3, hasBounty: false, isWall: false, name: "星星" }, + { code: 4, hasBounty: false, isWall: true, name: "贝壳" }, + { code: 5, hasBounty: false, isWall: true, name: "水母" }, + { code: 6, hasBounty: false, isWall: true, name: "石头" }, + { code: 10, hasBounty: true, isWall: false, name: "上指令" }, + { code: 11, hasBounty: true, isWall: false, name: "下指令" }, + { code: 12, hasBounty: true, isWall: false, name: "左指令" }, + { code: 13, hasBounty: true, isWall: false, name: "右指令" }, + { code: 14, hasBounty: true, isWall: false, name: "跳跃指令" }, + { code: 15, hasBounty: true, isWall: false, name: "循环指令" } + ]; + + debug = false; + userInfo = { + uid: "", + name: "", + todayDiamond: 0, // 今日获取矿石数 + todayLimitDiamond: 1500, // 今日限制获取矿石数 + maxTodayDiamond: 0 // 今日最大矿石数 + }; + + gameInfo = { + gameId: "", + mapData: [], + curPos: { x: 0, y: 0 }, + blockData: { + moveUp: 0, + moveDown: 0, + moveLeft: 0, + moveRight: 0, + jump: 0, + loop: 0 + }, + gameDiamond: 0 + }; + + history = []; + + get isGaming() { + return this.gameInfo && this.gameInfo.gameId !== ""; + } -async function run(args) { - console.clear(); - - class SeaGold { - static async init() { - const user = await api.getUserInfo(); - const token = await api.getToken(); - juejinGameApi.setUser(user); - juejinGameApi.setToken(token); - const seaGold = new this(); - await seaGold.init(); - return seaGold; - } - - nodeRules = [ - { code: 0, hasBounty: false, isWall: false, name: "空地" }, - { code: 2, hasBounty: true, isWall: false, name: "矿石", isBest: true }, - { code: 3, hasBounty: false, isWall: false, name: "星星" }, - { code: 4, hasBounty: false, isWall: true, name: "贝壳" }, - { code: 5, hasBounty: false, isWall: true, name: "水母" }, - { code: 6, hasBounty: false, isWall: true, name: "石头" }, - { code: 10, hasBounty: true, isWall: false, name: "上指令" }, - { code: 11, hasBounty: true, isWall: false, name: "下指令" }, - { code: 12, hasBounty: true, isWall: false, name: "左指令" }, - { code: 13, hasBounty: true, isWall: false, name: "右指令" }, - { code: 14, hasBounty: true, isWall: false, name: "跳跃指令" }, - { code: 15, hasBounty: true, isWall: false, name: "循环指令" } - ]; - - debug = false; - userInfo = { - uid: "", - name: "", - todayDiamond: 0, // 今日获取矿石数 - todayLimitDiamond: 1500, // 今日限制获取矿石数 - maxTodayDiamond: 0 // 今日最大矿石数 - }; - - gameInfo = { + resetGame() { + this.gameInfo = { gameId: "", mapData: [], curPos: { x: 0, y: 0 }, @@ -57,344 +67,356 @@ async function run(args) { }, gameDiamond: 0 }; + } - get isGaming() { - return this.gameInfo && this.gameInfo.gameId !== ""; + restoreGame(gameInfo) { + this.gameInfo = { + gameId: gameInfo.gameId, + mapData: this.makeMap(gameInfo.mapData, 6), + curPos: gameInfo.curPos, + blockData: gameInfo.blockData, + gameDiamond: gameInfo.gameDiamond } + } - async init() { - const loginInfo = await juejinGameApi.gameLogin(); - if (!loginInfo.isAuth) { - throw Error("玩家未授权, 请前往掘金授权!"); - } - console.log(`玩家: ${loginInfo.name}`); - const info = await juejinGameApi.gameInfo(); - this.userInfo = { - uid: info.userInfo.uid, - name: info.userInfo.name, - todayDiamond: info.userInfo.todayDiamond, - todayLimitDiamond: info.userInfo.todayLimitDiamond, - maxTodayDiamond: info.userInfo.maxTodayDiamond - }; - if (info.gameStatus === 1) { - this.restoreGame(info.gameInfo); - } else { - this.resetGame(); - } - } + async gameStart() { + if (this.isGaming) return; + const roleId = Math.ceil(Math.random() * 3); + const gameInfo = await this.gameApi.gameStart({ roleId }); + + this.gameInfo = { + roleId, + gameId: gameInfo.gameId, + mapData: this.makeMap(gameInfo.mapData, 6), + curPos: gameInfo.curPos, + blockData: gameInfo.blockData, + gameDiamond: 0 + }; + } - resetGame() { - this.gameInfo = { - gameId: "", - mapData: [], - curPos: { x: 0, y: 0 }, - blockData: { - moveUp: 0, - moveDown: 0, - moveLeft: 0, - moveRight: 0, - jump: 0, - loop: 0 - }, - gameDiamond: 0 - }; - } + async gameOver() { + if (!this.isGaming) return; + const gameOverInfo = await this.gameApi.gameOver(); + this.userInfo.todayDiamond = gameOverInfo.todayDiamond; + this.userInfo.todayLimitDiamond = gameOverInfo.todayLimitDiamond; - restoreGame(gameInfo) { - this.gameInfo = { - gameId: gameInfo.gameId, - mapData: this.makeMap(gameInfo.mapData, 6), - curPos: gameInfo.curPos, - blockData: gameInfo.blockData, - gameDiamond: gameInfo.gameDiamond - } - } + this.history.push({ + gameId: this.gameInfo.gameId, + gameDiamond: gameOverInfo.gameDiamond, + realDiamond: gameOverInfo.realDiamond, + todayDiamond: gameOverInfo.todayDiamond, + todayLimitDiamond: gameOverInfo.todayLimitDiamond + }); - async gameStart() { - if (this.isGaming) return; - const gameInfo = await juejinGameApi.gameStart(); - - this.gameInfo = { - gameId: gameInfo.gameId, - mapData: this.makeMap(gameInfo.mapData, 6), - curPos: gameInfo.curPos, - blockData: gameInfo.blockData, - gameDiamond: 0 - }; - - console.log("╔══════游戏开始══════╗"); - console.log(`gameId: ${this.gameInfo.gameId}`); - console.log(`curPos(${this.gameInfo.curPos.x},${this.gameInfo.curPos.y}): ${this.gameInfo.gameDiamond} 矿石`); - } + this.resetGame(); - async gameOver() { - if (!this.isGaming) return; - const gameOverInfo = await juejinGameApi.gameOver(); - this.userInfo.todayDiamond = gameOverInfo.todayDiamond; - this.userInfo.todayLimitDiamond = gameOverInfo.todayLimitDiamond; - // console.log("|==================|"); - const gameDiamond = this.gameInfo.gameDiamond; - console.log(`游戏清算: ${gameDiamond} 矿石`); - console.log("╚══════游戏结束══════╝"); - this.resetGame(); - return gameDiamond; - } + return gameOverInfo; + } - async executeGameCommand() { - const bmmap = this.getBMMap(); - const curNode = this.getNode(this.gameInfo.curPos); - const bestNode = this.getBestNode(bmmap); - const path = this.getRoutePath(bmmap, curNode, bestNode); - const commands = this.getCommands(path); - if (commands.length <= 0) { - console.log("当局游戏资源耗尽"); - return false; - } - const gameCommandInfo = await juejinGameApi.gameCommand(this.gameInfo.gameId, commands); - this.gameInfo.curPos = gameCommandInfo.curPos; - this.gameInfo.blockData = gameCommandInfo.blockData; - this.gameInfo.gameDiamond = gameCommandInfo.gameDiamond; - console.log(`curPos(${this.gameInfo.curPos.x},${this.gameInfo.curPos.y}): ${this.gameInfo.gameDiamond} 矿石`); - return true; + async executeGameCommand() { + const bmmap = this.getBMMap(); + const curNode = this.getNode(this.gameInfo.curPos); + const bestNode = this.getBestNode(bmmap); + const path = this.getRoutePath(bmmap, curNode, bestNode); + const commands = this.getCommands(path); + if (commands.length <= 0) { + return false; } + const gameCommandInfo = await this.gameApi.gameCommand(this.gameInfo.gameId, commands); + this.gameInfo.curPos = gameCommandInfo.curPos; + this.gameInfo.blockData = gameCommandInfo.blockData; + this.gameInfo.gameDiamond = gameCommandInfo.gameDiamond; - getCommand(start, end) { - const [sx, sy] = start; - const [ex, ey] = end; + return true; + } - if (sx === ex && sy !== ey) { - return sy > ey ? "U" : "D"; - } + getCommand(start, end) { + const [sx, sy] = start; + const [ex, ey] = end; - if (sy === ey && sx !== ex) { - return sx > ex ? "L" : "R"; - } + if (sx === ex && sy !== ey) { + return sy > ey ? "U" : "D"; + } - return null; + if (sy === ey && sx !== ex) { + return sx > ex ? "L" : "R"; } - getCommands(path) { - const commands = []; - for(let i=0; i${i+1}`); - } - commands.push(cmd); + return null; + } + + getCommands(path) { + const commands = []; + for(let i=0; i${i+1}`); } - return commands; + commands.push(cmd); } + return commands; + } - getNodePosition(map, node) { - for (let y = 0; y < map.length; y++) { - const list = map[y]; - for (let x = 0; x < list.length; x++) { - const cNode = list[x]; - if (cNode === node) { - return { x, y }; - } + getNodePosition(map, node) { + for (let y = 0; y < map.length; y++) { + const list = map[y]; + for (let x = 0; x < list.length; x++) { + const cNode = list[x]; + if (cNode === node) { + return { x, y }; } } - return { x: 0, y: 0 }; } + return { x: 0, y: 0 }; + } - getRoutePath(map, startNode, endNode) { - const maze = this.generateMapMaze(map); - const startPos = this.getNodePosition(map, startNode); - const endPos = this.getNodePosition(map, endNode); + getRoutePath(map, startNode, endNode) { + const maze = this.generateMapMaze(map); + const startPos = this.getNodePosition(map, startNode); + const endPos = this.getNodePosition(map, endNode); - if (this.debug) { - console.log("地图", this.getMaze(map)); - console.log("开始位置", startPos); - console.log("结束位置", endPos); - } + if (this.debug) { + console.log("地图", this.getMaze(map)); + console.log("开始位置", startPos); + console.log("结束位置", endPos); + } - const astar = new Astar(maze); - const path = astar.search( - [startPos.x, startPos.y], - [endPos.x, endPos.y], - { - rightAngle: true, - optimalResult: true - } - ); + const astar = new Astar(maze); + const path = astar.search( + [startPos.x, startPos.y], + [endPos.x, endPos.y], + { + rightAngle: true, + optimalResult: true + } + ); - return path; - } + return path; + } - makeMap(mapData, grid = 6) { - const map = []; - for (let i = 0, y = 0; i < mapData.length; i+=grid, y++) { - const row = []; - map.push(row); - for (let x = 0; x < grid; x++) { - const cell = mapData[i + x]; - row.push(this.createMapNode(x, y, cell)); - } + makeMap(mapData, grid = 6) { + const map = []; + for (let i = 0, y = 0; i < mapData.length; i+=grid, y++) { + const row = []; + map.push(row); + for (let x = 0; x < grid; x++) { + const cell = mapData[i + x]; + row.push(this.createMapNode(x, y, cell)); } - return map; } + return map; + } - createMapNode(x, y, secret) { - const rule = this.getNodeRule(secret); - return { - code: rule.code, - bounty: rule.hasBounty ? this.getBounty(secret, rule.code) : 0, - x, - y, - isWall: rule.isWall, - isBest: !!rule.isBest - } + createMapNode(x, y, secret) { + const rule = this.getNodeRule(secret); + return { + code: rule.code, + bounty: rule.hasBounty ? this.getBounty(secret, rule.code) : 0, + x, + y, + isWall: rule.isWall, + isBest: !!rule.isBest } + } - // 获取范围地图 - getBMMap() { - const { mapData, blockData, curPos } = this.gameInfo; - const minX = Math.max(curPos.x - blockData.moveLeft, 0); - const maxX = Math.min(curPos.x + blockData.moveRight, mapData[0].length - 1); - const minY = Math.max(curPos.y - blockData.moveUp, 0); - const maxY = Math.min(curPos.y + blockData.moveDown, mapData.length - 1); - - const map = []; - for (let y = minY; y <= maxY; y++) { - const row = []; map.push(row); - for (let x = minX; x <= maxX; x++) { - row.push(mapData[y][x]); - } + // 获取范围地图 + getBMMap() { + const { mapData, blockData, curPos } = this.gameInfo; + const minX = Math.max(curPos.x - blockData.moveLeft, 0); + const maxX = Math.min(curPos.x + blockData.moveRight, mapData[0].length - 1); + const minY = Math.max(curPos.y - blockData.moveUp, 0); + const maxY = Math.min(curPos.y + blockData.moveDown, mapData.length - 1); + + const map = []; + for (let y = minY; y <= maxY; y++) { + const row = []; map.push(row); + for (let x = minX; x <= maxX; x++) { + row.push(mapData[y][x]); } - - return map; } - getNode(pos) { - return this.gameInfo.mapData[pos.y][pos.x]; - } + return map; + } - getBestNode(map) { - let bestNode = null; - map.forEach(row => { - row.forEach(node => { - if (node.isBest && bestNode === null) { - bestNode = node; - } else if (node.isBest && node.bounty > bestNode.bounty) { - bestNode = node; - } - }); - }); - return bestNode; - } + getNode(pos) { + return this.gameInfo.mapData[pos.y][pos.x]; + } - getMaze(map) { - return map.map((row, y) => { - return row.map((node, x) => { - if (node.isWall) { - return 1; - } else { - return 0; - } - }); + getBestNode(map) { + let bestNode = null; + map.forEach(row => { + row.forEach(node => { + if (node.isBest && bestNode === null) { + bestNode = node; + } else if (node.isBest && node.bounty > bestNode.bounty) { + bestNode = node; + } }); - } + }); + return bestNode; + } - // 生成迷宫 - generateMapMaze(map) { - const grid = new Grid({ - col: map[0].length, - row: map.length + getMaze(map) { + return map.map((row, y) => { + return row.map((node, x) => { + if (node.isWall) { + return 1; + } else { + return 0; + } }); + }); + } - map.forEach((row, y) => { - row.forEach((node, x) => { - if (node.isWall) { - grid.set([x, y], 'value', 1); - } - }); + // 生成迷宫 + generateMapMaze(map) { + const grid = new Grid({ + col: map[0].length, + row: map.length + }); + + map.forEach((row, y) => { + row.forEach((node, x) => { + if (node.isWall) { + grid.set([x, y], 'value', 1); + } }); + }); - return grid; - } + return grid; + } - getNodeRule(secret) { - return this.nodeRules.find(rule => { - const reg = new RegExp(`^${rule.code}`); - return reg.test(secret); - }); - } + getNodeRule(secret) { + return this.nodeRules.find(rule => { + const reg = new RegExp(`^${rule.code}`); + return reg.test(secret); + }); + } - getBounty(secret, key) { - const reg = new RegExp(`^${key}([0-9]*)`); - const match = secret.toString().match(reg); - if (match) { - const materials = Number.parseInt(match[1]); - return !isNaN(materials) ? materials : 0; - } - return 0; + getBounty(secret, key) { + const reg = new RegExp(`^${key}([0-9]*)`); + const match = secret.toString().match(reg); + if (match) { + const materials = Number.parseInt(match[1]); + return !isNaN(materials) ? materials : 0; } + return 0; } - const seaGold = await SeaGold.init(); + async run() { + const juejin = new JuejinHelper(); + await juejin.login(env.COOKIE); + this.gameApi = juejin.seagold(); + + const loginInfo = await this.gameApi.gameLogin(); + if (!loginInfo.isAuth) { + throw Error(`掘友 ${loginInfo.name} 未授权, 请前往掘金授权!`); + } + + const info = await this.gameApi.gameInfo(); + this.userInfo = { + uid: info.userInfo.uid, + name: info.userInfo.name, + todayDiamond: info.userInfo.todayDiamond, + todayLimitDiamond: info.userInfo.todayLimitDiamond, + maxTodayDiamond: info.userInfo.maxTodayDiamond + }; + + const runEndTime = new Date(); + runEndTime.setMinutes(runEndTime.getMinutes() + 30); + let runTime = new Date(); - async function runOnceGame() { - try { - if (seaGold.isGaming) { - await seaGold.gameOver(); + const runGame = async () => { + if (this.isGaming) { + return await this.gameOver(); } - await seaGold.gameStart(); - let run = true; - while (run) { + + await this.gameStart(); + + while (await this.executeGameCommand()) { await utils.wait(utils.randomRangeNumber(1000, 1500)); - run = await seaGold.executeGameCommand(); + + if (runTime >= runEndTime) { + throw Error(`掘金游戏异常: 服务运行时间过长.`); + } + + runTime = new Date(); } - return await seaGold.gameOver(); - } catch (e) { - await seaGold.gameOver(); - throw e; + + return await this.gameOver(); } - } - console.log(`今日开采限制: ${seaGold.userInfo.todayLimitDiamond} 矿石`); - if (seaGold.userInfo.todayDiamond >= seaGold.userInfo.todayLimitDiamond) { - console.log(`今日开采已达上限!`); - } else { + const maxZeroCount = 5; let zeroCount = 0; - const runEndTime = new Date(); - runEndTime.setMinutes(runEndTime.getMinutes() + 30); - let runTime = new Date(); - console.log(`准备挖矿!`); - console.log(`当前进度: ${seaGold.userInfo.todayDiamond}/${seaGold.userInfo.todayLimitDiamond} 矿石`); - while (seaGold.userInfo.todayDiamond < seaGold.userInfo.todayLimitDiamond) { + + if (info.gameStatus === 1) { + this.restoreGame(info.gameInfo); + await runGame(); + } else { + this.resetGame(); + } + + while (this.userInfo.todayDiamond < this.userInfo.todayLimitDiamond) { if (runTime >= runEndTime) { - console.log("掘金游戏异常: 服务运行时间过长."); - throw new Error(console.toString()); - } - await utils.wait(utils.randomRangeNumber(1000, 1500)); - const gameDiamond = await runOnceGame(); - if (gameDiamond === 0) { - zeroCount++; + throw Error(`掘金游戏异常: 服务运行时间过长.`); } + if (zeroCount > maxZeroCount) { - console.log("掘金游戏异常: 您 0 矿石游戏对局次数过多."); - throw new Error(console.toString()); + throw new Error("掘金游戏异常: 您 0 矿石游戏对局次数过多."); + } + + await utils.wait(utils.randomRangeNumber(1000, 5000)); + const gameOverInfo = await runGame(); + + if (gameOverInfo.gameDiamond === 0) { + zeroCount++; } - console.log(`当前进度: ${seaGold.userInfo.todayDiamond}/${seaGold.userInfo.todayLimitDiamond} 矿石`); + runTime = new Date(); } - if (seaGold.userInfo.todayDiamond >= seaGold.userInfo.todayLimitDiamond) { - console.log(`今日开采已达上限!`); - } + await juejin.logout(); + } + + toString() { + const userInfo = this.userInfo; + const gameLives = this.history.map(game => `${game.gameId}\n 挖取 ${game.gameDiamond}\n 获得 ${game.realDiamond}`).join("\n"); + + return ` +掘友: ${userInfo.name} +今日限制矿石数 ${userInfo.todayLimitDiamond} +${userInfo.todayDiamond < userInfo.todayLimitDiamond ? `今日获取矿石数 ${userInfo.todayDiamond}` : "今日获取已达上限"} +${this.history.length ? `\n游戏记录\n${gameLives}` : ""} +`.trim(); } +} + +async function run(args) { + const seaGold = new SeaGold(); + + await utils.wait(utils.randomRangeNumber(1000, 5000)); // 初始等待1-5s + + await seaGold.run(); + + const content = seaGold.toString(); + + console.log(content); email({ subject: "海底掘金游戏", - text: console.toString() + text: content }); } run(process.argv.splice(2)).catch(error => { - console.log(error); email({ subject: "海底掘金游戏", - html: `Error
${error.message}
如版本过低请前往升级: juejin-helper
` + html: ` +Error +
${error.message}
+
如果版本过低请前往升级: juejin-helper
+`.trim() }); -}); + + throw error; +}); \ No newline at end of file diff --git a/scripts/test.js b/scripts/test.js new file mode 100644 index 00000000..45a8049d --- /dev/null +++ b/scripts/test.js @@ -0,0 +1,93 @@ +const JuejinHelper = require('juejin-helper'); +const email = require("./utils/email"); +const env = require("./utils/env"); + +const CheckInState = { + no: -1, + success: 1, + error: 0 +} + +class CheckIn { + state = { + simulateSpeed: 100, // ms/进行一次抽奖 + sumPoint: 0, + pointCost: 0, + supplyPoint: 0, + freeCount: 0, + luckyValue: 0, + lottery: [], + counter: 0, + prize: {}, + checkInState: CheckInState.no + }; + + juejin = new JuejinHelper(); + + static async run() { + email({ + subject: "掘金每日签到", + html: ` +
+ +
签到成功 +700 矿石
+
沾喜气 +10 幸运值
+
矿石 98559
+
+
幸运值
+
+
+
+
1385/6000
+
+
All In矿石预估累计幸运值比: 119.10%
+
+
免费抽奖 1 次
+
我的奖品
+
    +
  • [第1抽]:30矿石
  • +
+
+
` + }); + } +} + +CheckIn.run(); + +// async function run() { +// const checkin = new CheckIn(); +// const juejin = new JuejinHelper(); +// await juejin.login(mockCookie); +// console.log(checkin.hello, juejin.getUser()); +// } +// +// run(); diff --git a/scripts/utils/dingding.js b/scripts/utils/dingding.js new file mode 100644 index 00000000..2bfe864f --- /dev/null +++ b/scripts/utils/dingding.js @@ -0,0 +1,20 @@ +const fetch = require("node-fetch"); + +const env = require("./env"); +async function dingding({ subject, text, html }) { + return fetch(env.DINGDING_WEBHOOK, { + headers: { + "Content-Type": "application/json", + Charset: "UTF-8" + }, + method: "POST", + body: JSON.stringify({ + msgtype: "text", + text: { + content: `${subject}\n${text || html}` + } + }) + }).then((res) => console.log(JSON.stringify(res))); +} + +module.exports = dingding; diff --git a/scripts/utils/email.js b/scripts/utils/email.js index b24ed3d1..34a74951 100644 --- a/scripts/utils/email.js +++ b/scripts/utils/email.js @@ -6,13 +6,23 @@ async function main({ subject, text, html }) { const auth = { user: env.EMAIL_USER, // generated ethereal user - pass: env.EMAIL_PASS, // generated ethereal password + pass: env.EMAIL_PASS // generated ethereal password }; + if (!auth.user || !auth.pass) { + console.warn("邮箱功能不可用, 请先配置邮箱用户和密码"); + return; + } + const transporter = nodemailer.createTransport({ host: "smtp." + auth.user.match(/@(.*)/)[1], secure: true, - auth + port: 465, + auth, + tls: { + // do not fail on invalid certs + rejectUnauthorized: false + } }); const template = ` @@ -25,7 +35,7 @@ async function main({ subject, text, html }) { `.trim(); @@ -36,11 +46,13 @@ async function main({ subject, text, html }) { subject, // Subject line // text, // plain text body html: template, // html body - attachments: [{ - filename: "logo.svg", - path: path.resolve(__dirname, "../../resources/logo.svg"), - cid: 'logo.svg' //same cid value as in the html img src - }] + attachments: [ + { + filename: "logo.svg", + path: path.resolve(__dirname, "../../resources/logo.svg"), + cid: "logo.svg" //same cid value as in the html img src + } + ] }); console.log("已通知订阅人!"); diff --git a/scripts/utils/env.js b/scripts/utils/env.js index 2e98bcb7..e49ba69b 100644 --- a/scripts/utils/env.js +++ b/scripts/utils/env.js @@ -1,8 +1,28 @@ const env = process.env || {}; module.exports = { + /* 掘金Cookie */ + COOKIE: env.COOKIE, + /* 多用户掘金Cookie, 当有1名以上用户时填写, 支持同时最多可配置5名用户 */ + COOKIE_2: env.COOKIE_2, + COOKIE_3: env.COOKIE_3, + COOKIE_4: env.COOKIE_4, + COOKIE_5: env.COOKIE_5, + /** + * 邮箱配置 + * user 发件人邮箱, pass, 发件人密码, to收件人 + */ EMAIL_USER: env.EMAIL_USER, EMAIL_PASS: env.EMAIL_PASS, EMAIL_TO: env.EMAIL_TO, - COOKIE: env.COOKIE + /** + * 钉钉配置 + * https://open.dingtalk.com/document/robots/custom-robot-access + */ + DINGDING_WEBHOOK: env.DINGDING_WEBHOOK, + /** + * PushPlus配置 + * http://www.pushplus.plus/doc/guide/openApi.html + */ + PUSHPLUS_TOKEN: env.PUSHPLUS_TOKEN }; diff --git a/scripts/utils/logger.js b/scripts/utils/logger.js deleted file mode 100644 index 331e4be8..00000000 --- a/scripts/utils/logger.js +++ /dev/null @@ -1,84 +0,0 @@ -class LogNode { - constructor(data, parent = null, leaf = true) { - this.data = data; - this.parent = parent; - this.level = parent ? parent.level + 1 : 0; - this.leaf = leaf; - - if (!leaf) { - this.children = []; - } - } - - toString() { - const level = this.level - 1; - const isGroup = !this.leaf; - return `${' '.repeat(level * 3)}${isGroup ? '▼' : level > 0 ? '-' : ' '} ${this.data}\n`; - } -} - -class Logger { - result = this.createNode(null, null, false); - current = this.result; - - createNode(data, parent, leaf) { - return new LogNode(data, parent, leaf); - } - - clear() { - this.result = this.createNode(null, null, false); - this.current = this.result; - console.clear(); - } - - log(msg) { - const node = this.createNode(msg, this.current, true); - this.current.children.push(node); - console.log(msg); - } - - logGroupStart(name) { - const current = this.createNode(name, this.current, false); - this.result.children.push(current); - this.current = current; - console.group(name); - } - - logGroupEnd(name) { - const current = this.current.parent; - this.current = current; - console.groupEnd(name); - } - - toString() { - const each = children => { - if (!Array.isArray(children)) return ""; - let content = ""; - children.forEach(child => { - content += child.toString(); - if (!child.leaf) { - content += each(child.children); - } - }); - return content; - } - return each(this.result.children); - } -} - -const logger = new Logger(); - -module.exports = logger; -// logger.log(2) -// logger.logGroupStart("group 1") -// logger.log(3) -// logger.log(4) -// logger.log(5) -// logger.logGroupStart("group 2") -// logger.log(6) -// logger.log(7) -// logger.log(8) -// logger.logGroupEnd("group 2") -// logger.logGroupEnd("group 1") -// logger.log(9) -// logger.toString(); diff --git a/scripts/utils/pushMessage.js b/scripts/utils/pushMessage.js new file mode 100644 index 00000000..68c4ca2b --- /dev/null +++ b/scripts/utils/pushMessage.js @@ -0,0 +1,12 @@ +const env = require("./env"); +const email = require("./email"); +const pushplus = require("./pushplus"); +const dingding = require("./dingding"); + +async function pushMessage({ subject, text, html }) { + env.EMAIL_USER && (await email({ subject, text, html })); + env.DINGDING_WEBHOOK && (await dingding({ subject, text, html })); + env.PUSHPLUS_TOKEN && (await pushplus({ subject, text, html })); +} + +module.exports = pushMessage; diff --git a/scripts/utils/pushplus.js b/scripts/utils/pushplus.js new file mode 100644 index 00000000..5962b75b --- /dev/null +++ b/scripts/utils/pushplus.js @@ -0,0 +1,41 @@ +const fetch = require("node-fetch"); +const env = require("./env"); +const userConfig = { + url: "http://www.pushplus.plus/send", + token: env.PUSHPLUS_TOKEN +}; + +async function main({ subject, text, html }) { + if (!userConfig.token) { + console.warn("未配置PushPlus之Token, 请先配置PushPlus"); + return; + } + return await postMessage({ + token: userConfig.token, + title: subject, + content: text ?? html, + topic: "", + template: "html", + channel: "wechat", + webhook: "", + callbackUrl: "", + timestamp: "" + }) + .then((res) => res.json()) + .then((json) => { + console.log(`PushPlus推送结果: ` + json.msg); + return json; + }); +} + +async function postMessage(message) { + return await fetch(userConfig.url, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(message) + }).catch((err) => console.log(err)); +} + +module.exports = main; diff --git a/scripts/utils/utils.js b/scripts/utils/utils.js index 2fafe4b2..62b8d950 100644 --- a/scripts/utils/utils.js +++ b/scripts/utils/utils.js @@ -1,8 +1,16 @@ module.exports = { async wait(time = 0) { - return new Promise(resolve => setTimeout(resolve, time)); + return new Promise((resolve) => setTimeout(resolve, time)); }, randomRangeNumber(start = 500, end = 1000) { return (Math.random() * (end - start) + start) >> 0; + }, + getUsersCookie(env) { + const users = [env.COOKIE]; + + const keys = Object.keys(env).filter(key => key.match(/^COOKIE_([0-9])+$/)); + keys.forEach(key => users.push(env[key])); + + return users.filter(cookie => !!cookie); } -} +}; diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 6e3974e8..00000000 --- a/yarn.lock +++ /dev/null @@ -1,133 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.npm.taobao.org/buffer-equal-constant-time/download/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= - -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.nlark.com/ecdsa-sig-formatter/download/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha1-rg8PothQRe8UqBfao86azQSJ5b8= - dependencies: - safe-buffer "^5.0.1" - -fast-astar@^1.0.6: - version "1.0.6" - resolved "https://registry.npmmirror.com/fast-astar/download/fast-astar-1.0.6.tgz#e4cae258839bc6406c49df1eaa80077eda74723c" - integrity sha1-5MriWIObxkBsSd8eqoAHftp0cjw= - -jsonwebtoken@^8.5.1: - version "8.5.1" - resolved "https://registry.npmmirror.com/jsonwebtoken/download/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^5.6.0" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.npm.taobao.org/jwa/download/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha1-dDwymFy56YZVUw1TZBtmyGRbA5o= - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.nlark.com/jws/download/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha1-ABCZ82OUaMlBQADpmZX6UvtHgwQ= - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.npmmirror.com/lodash.includes/download/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.npmmirror.com/lodash.isboolean/download/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.npm.taobao.org/lodash.isinteger/download/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.npm.taobao.org/lodash.isnumber/download/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.npm.taobao.org/lodash.isplainobject/download/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.npmmirror.com/lodash.isstring/download/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.npm.taobao.org/lodash.once/download/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.npmmirror.com/ms/download/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha1-V0yBOM4dK1hh8LRFedut1gxmFbI= - -node-fetch@^2.6.1: - version "2.6.6" - resolved "https://registry.npmmirror.com/node-fetch/download/node-fetch-2.6.6.tgz?cache=0&sync_timestamp=1636395469986&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha1-F1GnwBg06OFpd1hzLp77burfr4k= - dependencies: - whatwg-url "^5.0.0" - -nodemailer@^6.7.0: - version "6.7.0" - resolved "https://registry.npmmirror.com/nodemailer/download/nodemailer-6.7.0.tgz?cache=0&sync_timestamp=1634009331140&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fnodemailer%2Fdownload%2Fnodemailer-6.7.0.tgz#86614722c4e0c33d1b5b02aecb90d6d629932b0d" - integrity sha1-hmFHIsTgwz0bWwKuy5DW1imTKw0= - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= - -semver@^5.6.0: - version "5.7.1" - resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1616463540350&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmmirror.com/tr46/download/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.nlark.com/webidl-conversions/download/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmmirror.com/whatwg-url/download/whatwg-url-5.0.0.tgz?cache=0&sync_timestamp=1634673865107&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fwhatwg-url%2Fdownload%2Fwhatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0"