├── src ├── view │ ├── styles │ │ ├── abyss.css │ │ ├── Genshin_Impact_Font.woff │ │ ├── common.css │ │ ├── character.css │ │ └── profile.css │ ├── images │ │ ├── Lock.png │ │ ├── Star │ │ │ ├── 1.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ └── 5.png │ │ ├── Element │ │ │ ├── Cryo.png │ │ │ ├── Geo.png │ │ │ ├── Pyro.png │ │ │ ├── Anemo.png │ │ │ ├── Dendro.png │ │ │ ├── Electro.png │ │ │ └── Hydro.png │ │ ├── City_background.png │ │ ├── Header_background.png │ │ └── ItemBackground │ │ │ ├── Rarity_1.png │ │ │ ├── Rarity_105.png │ │ │ ├── Rarity_2.png │ │ │ ├── Rarity_3.png │ │ │ ├── Rarity_4.png │ │ │ └── Rarity_5.png │ ├── abyss.pug │ ├── footer.pug │ ├── index.html │ ├── character.pug │ └── profile.pug ├── assets │ └── how-to-donate.png ├── modules │ ├── checkCookie.js │ ├── character.test.js │ ├── renderCharacter.js │ ├── profile.test.js │ ├── renderProfile.js │ └── database.js ├── utils │ ├── handleError.js │ └── dateFormat.js ├── plugins │ ├── donate.js │ ├── profile.js │ ├── dailynote.js │ ├── character.js │ ├── abyss.js │ └── wish.js ├── index.js └── i18n.js ├── .vscode └── settings.json ├── design └── allCharacters_v1.png ├── .npmrc ├── .eslintrc.js ├── .github └── workflows │ └── build.prod.yml.disabled ├── package.json ├── .gitignore ├── README.md ├── LICENSE └── yarn.lock /src/view/styles/abyss.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "compile-hero.disable-compile-files-on-did-save-code": true 3 | } -------------------------------------------------------------------------------- /src/view/images/Lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Lock.png -------------------------------------------------------------------------------- /design/allCharacters_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/design/allCharacters_v1.png -------------------------------------------------------------------------------- /src/view/images/Star/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Star/1.png -------------------------------------------------------------------------------- /src/view/images/Star/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Star/3.png -------------------------------------------------------------------------------- /src/view/images/Star/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Star/4.png -------------------------------------------------------------------------------- /src/view/images/Star/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Star/5.png -------------------------------------------------------------------------------- /src/assets/how-to-donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/assets/how-to-donate.png -------------------------------------------------------------------------------- /src/view/images/Element/Cryo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Cryo.png -------------------------------------------------------------------------------- /src/view/images/Element/Geo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Geo.png -------------------------------------------------------------------------------- /src/view/images/Element/Pyro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Pyro.png -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | canvas_binary_host_mirror=https://npm.taobao.org/mirrors/node-canvas-prebuilt/ 2 | PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors -------------------------------------------------------------------------------- /src/view/images/City_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/City_background.png -------------------------------------------------------------------------------- /src/view/images/Element/Anemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Anemo.png -------------------------------------------------------------------------------- /src/view/images/Element/Dendro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Dendro.png -------------------------------------------------------------------------------- /src/view/images/Element/Electro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Electro.png -------------------------------------------------------------------------------- /src/view/images/Element/Hydro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Element/Hydro.png -------------------------------------------------------------------------------- /src/view/images/Header_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/Header_background.png -------------------------------------------------------------------------------- /src/view/abyss.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | style 5 | include styles/common.css 6 | include styles/abyss.css 7 | 8 | body -------------------------------------------------------------------------------- /src/view/styles/Genshin_Impact_Font.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/styles/Genshin_Impact_Font.woff -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_1.png -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_105.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_105.png -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_2.png -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_3.png -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_4.png -------------------------------------------------------------------------------- /src/view/images/ItemBackground/Rarity_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koishijs/koishi-plugin-genshin-legacy/HEAD/src/view/images/ItemBackground/Rarity_5.png -------------------------------------------------------------------------------- /src/view/footer.pug: -------------------------------------------------------------------------------- 1 | footer 2 | p © koishijs/koishi-plugin-genshin 机智的小鱼君 3 | p All game data & media: © miHoYo 4 | p 5 | i For communication and learning only. -------------------------------------------------------------------------------- /src/modules/checkCookie.js: -------------------------------------------------------------------------------- 1 | const { GenshinKit } = require('@genshin-kit/core') 2 | async function checkCookie(cookie, uid) { 3 | const App = new GenshinKit() 4 | try { 5 | await App.loginWithCookie(cookie).getUserInfo(uid) 6 | return true 7 | } catch (err) { 8 | return err 9 | } 10 | } 11 | module.exports = checkCookie 12 | -------------------------------------------------------------------------------- /src/view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | This file is the entry point for generate screenshots. 13 | Access this file first to use local media resources in CSS via file:// protocol. 14 | 15 | 16 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | env: { 4 | browser: false, 5 | es2021: true, 6 | }, 7 | extends: ['eslint:recommended'], 8 | // parser: '', 9 | parserOptions: { 10 | ecmaVersion: 12, 11 | sourceType: 'module', 12 | }, 13 | plugins: [], 14 | rules: { 15 | indent: ['error', 2, { SwitchCase: 1 }], 16 | 'linebreak-style': ['warn', 'windows'], 17 | quotes: ['error', 'single'], 18 | semi: ['error', 'never'], 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/build.prod.yml.disabled: -------------------------------------------------------------------------------- 1 | name: Production Build 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | jobs: 7 | build: 8 | # 使用最新版ubantu虚拟机运行 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # from: https://github.com/actions/checkout 13 | - name: 本工作流 14 | uses: actions/checkout@master 15 | 16 | # 安装最新版 Node.js 17 | # from: https://github.com/actions/setup-node 18 | - name: 安装 Node.js 19 | uses: actions/setup-node@master 20 | with: 21 | node-version: 14 22 | registry-url: https://registry.npmjs.org/ 23 | 24 | - name: 安装 yarn 25 | run: | 26 | npm install yarn -g 27 | - name: 安装项目依赖 28 | run: | 29 | yarn install 30 | - name: 测试项目 31 | run: | 32 | yarn test 33 | - name: 构建项目并打包发布 34 | run: | 35 | npm run publish:stable 36 | env: 37 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 38 | -------------------------------------------------------------------------------- /src/modules/character.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const pug = require('pug') 3 | const { writeFileSync } = require('fs') 4 | 5 | const { uid, cookie } = require('./secret') 6 | const { GenshinKit, util } = require('@genshin-kit/core') 7 | const { template } = require('koishi-utils') 8 | 9 | template.set('genshin', require('../i18n')) 10 | 11 | function m(k) { 12 | return template(`genshin.profile.${k}`) 13 | } 14 | 15 | const genshin = new GenshinKit() 16 | genshin.loginWithCookie(cookie) 17 | 18 | genshin.getUserRoles(uid).then((data) => { 19 | const Filter = new util.CharactersFilter(data) 20 | const character = Filter.name('迪奥娜') 21 | 22 | console.log(character) 23 | const config = { 24 | pretty: 1, 25 | ...character, 26 | } 27 | 28 | const html = pug.renderFile( 29 | path.resolve(__dirname, '../view/character.pug'), 30 | config 31 | ) 32 | 33 | writeFileSync(path.resolve(__dirname, '../view/character.dev.html'), html) 34 | }) 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koishi-plugin-genshin", 3 | "version": "2.0.0-beta.21", 4 | "description": "Genshin Impact player data fetcher and gacha simulator for Koishi.js", 5 | "main": "src/index.js", 6 | "repository": "https://github.com/Dragon-Fish/koishi-plugin-genshin", 7 | "author": "Dragon-Fish <824399619@qq.com>", 8 | "license": "Apache-2.0", 9 | "scripts": { 10 | "publish:stable": "npm publish --tag latest", 11 | "publish:next": "npm publish --tag next" 12 | }, 13 | "dependencies": { 14 | "@genshin-kit/core": "^2.6.0", 15 | "genshin-gacha-kit": "^1.1.0", 16 | "pug": "^3.0.2" 17 | }, 18 | "peerDependencies": { 19 | "koishi-core": "^3.13.1" 20 | }, 21 | "devDependencies": { 22 | "@dragon-fish/bump": "^0.0.15", 23 | "koishi-core": "^3.13.1" 24 | }, 25 | "keywords": [ 26 | "genshin", 27 | "genshin-impact", 28 | "genshin-api", 29 | "hoyolab", 30 | "koishi", 31 | "mihoyo", 32 | "qqbot" 33 | ] 34 | } -------------------------------------------------------------------------------- /src/utils/handleError.js: -------------------------------------------------------------------------------- 1 | const { template, segment } = require('koishi-utils') 2 | const { disableCookie } = require('../modules/database') 3 | 4 | const errorMap = { 5 | '-10001': '米游社协议异常,请更新 genshin-kit。', 6 | 10001: '登录状态异常,请检查 cookie。', 7 | 10101: '当前账号查询人数达到上限。', 8 | 10102: '被查询者米游社信息未公开。', 9 | } 10 | 11 | function getErrMsg(err) { 12 | return template( 13 | 'genshin.error', 14 | errorMap[err.code] || err.message || template('genshin.error_unknown'), 15 | err.code 16 | ) 17 | } 18 | 19 | /** 20 | * @param {import('koishi-core').Session} session 21 | * @param {import('genshin-kit').GenshinKit} genshin 22 | * @param {*} err 23 | */ 24 | async function handleError(session, genshin, err) { 25 | // 10001 - cookie 异常 26 | // 10101 - 次数耗尽 27 | if ([10001, 10101].includes(err.code)) { 28 | await session.send(template('genshin.donate.current_runout')) 29 | await disableCookie(session, genshin.cookie) 30 | return 31 | } 32 | return session.send(segment.quote(session.messageId) + getErrMsg(err)) 33 | } 34 | 35 | module.exports = { 36 | errorMap, 37 | getErrMsg, 38 | handleError, 39 | } 40 | -------------------------------------------------------------------------------- /src/utils/dateFormat.js: -------------------------------------------------------------------------------- 1 | const { Time } = require('koishi-core') 2 | 3 | /** 4 | * @param {string} fmt 5 | * @param {Date?} date 6 | * @returns 7 | */ 8 | module.exports.dateFormat = function(fmt, date) { 9 | date = date || new Date() 10 | const o = { 11 | 'M+': date.getMonth() + 1, //月份 12 | 'd+': date.getDate(), //日 13 | 'h+': date.getHours(), //小时 14 | 'm+': date.getMinutes(), //分 15 | 's+': date.getSeconds(), //秒 16 | 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 17 | S: date.getMilliseconds(), //毫秒 18 | } 19 | if (/(y+)/.test(fmt)) { 20 | fmt = fmt.replace( 21 | RegExp.$1, 22 | (date.getFullYear() + '').substr(4 - RegExp.$1.length) 23 | ) 24 | } 25 | for (let k in o) { 26 | if (new RegExp('(' + k + ')').test(fmt)) { 27 | fmt = fmt.replace( 28 | RegExp.$1, 29 | RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length) 30 | ) 31 | } 32 | } 33 | return fmt 34 | } 35 | 36 | /** 37 | * @param {number} time 38 | * @returns 39 | */ 40 | module.exports.getTimeLeft = function(time) { 41 | return Time.formatTime(time - Date.now()) 42 | } 43 | -------------------------------------------------------------------------------- /src/modules/renderCharacter.js: -------------------------------------------------------------------------------- 1 | const pug = require('pug') 2 | const { segment, template } = require('koishi-utils') 3 | const path = require('path') 4 | 5 | module.exports = async ({ uid, character, ctx }) => { 6 | let screenshot 7 | 8 | const options = { 9 | uid, 10 | ...character, 11 | } 12 | const html = pug.renderFile( 13 | path.resolve(__dirname, '../view/character.pug'), 14 | options 15 | ) 16 | 17 | const page = await ctx.app.puppeteer.page(); 18 | 19 | try { 20 | await page.goto( 21 | 'file:///' + path.resolve(__dirname, '../view/index.html') 22 | ) 23 | await page.setContent(html) 24 | const { width, height } = await page.evaluate(() => { 25 | const ele = document.body; 26 | return { 27 | width: ele.scrollWidth, 28 | height: ele.scrollHeight, 29 | }; 30 | }); 31 | await page.setViewport({ 32 | width: Math.ceil(width + 14), 33 | height: Math.ceil(height + 14), 34 | }); 35 | screenshot = await page.screenshot({ 36 | fullPage: true, 37 | type: 'jpeg', 38 | }) 39 | } catch (err) { 40 | await page.close() 41 | return `错误:${err}` 42 | } 43 | 44 | await page.close() 45 | return ( 46 | template('genshin.has_character', uid, character.name) + 47 | segment.image(screenshot) 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /src/modules/profile.test.js: -------------------------------------------------------------------------------- 1 | const pug = require('pug') 2 | const path = require('path') 3 | const { writeFileSync } = require('fs') 4 | 5 | const { uid, cookie } = require('./secret') 6 | const { GenshinKit, util } = require('@genshin-kit/core') 7 | const { template } = require('koishi-utils') 8 | 9 | template.set('genshin', require('../i18n')) 10 | 11 | function m(k) { 12 | return template(`genshin.profile.${k}`) 13 | } 14 | 15 | const genshin = new GenshinKit() 16 | genshin.loginWithCookie(cookie) 17 | Promise.all([genshin.getUserInfo(uid), genshin.getAllCharacters(uid)]) 18 | .then(([userInfo, allCharacters]) => { 19 | let _stats = Object.assign({}, userInfo.stats) 20 | userInfo.stats = [] 21 | for (key in _stats) { 22 | userInfo.stats.push({ desc: m('stats.' + key), count: _stats[key] }) 23 | } 24 | 25 | allCharacters.forEach((item) => { 26 | item.activedConstellations = util.activedConstellations(item) 27 | }) 28 | 29 | userInfo.avatars = allCharacters 30 | 31 | const options = { 32 | ui: { 33 | title: m('ui.title'), 34 | }, 35 | uid, 36 | ...userInfo, 37 | } 38 | console.log(options) 39 | const html = pug.renderFile( 40 | path.resolve(__dirname, '../view/profile.pug'), 41 | options 42 | ) 43 | writeFileSync(path.resolve(__dirname, '../view/profile.dev.html'), html) 44 | }) 45 | .catch(console.error) 46 | -------------------------------------------------------------------------------- /src/plugins/donate.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { readFileSync } = require('fs') 3 | const { segment, template } = require('koishi-utils') 4 | const { insertCookie } = require('../modules/database') 5 | 6 | const HOW_TO_DONATE = readFileSync( 7 | path.resolve(__dirname, '../assets/how-to-donate.png') 8 | ) 9 | 10 | /** 11 | * @param {import('koishi-core').Context} ctx 12 | */ 13 | function apply(ctx) { 14 | ctx 15 | .private() 16 | .command('genshin.donate [cookie:text]', '捐赠米游社账号') 17 | .alias('捐赠米游社账号', '捐赠原神账号') 18 | .usage('输入“米游社账号捐赠指南”查看教程') 19 | .check(({ session, options }, cookie) => { 20 | if (!cookie || options.help) return session.execute('genshin.donate.how') 21 | }) 22 | .action(async ({ session }, cookie) => { 23 | return insertCookie(session, cookie) 24 | }) 25 | 26 | ctx 27 | .command('genshin.donate.delete', '取消捐赠米游社账号') 28 | .alias('取消捐赠米游社账号', '取消捐赠原神账号') 29 | .option('user', '-u 指定捐赠者', { authority: 2 }) 30 | .usage('输入“米游社账号捐赠指南”查看教程') 31 | .action(async ({ session, options }) => { 32 | return '该功能暂未实装,请联系 bot 管理员进行操作!' 33 | }) 34 | 35 | ctx 36 | .command('genshin.donate.how', 'internal command', { hidden: true }) 37 | .alias('米游社账号捐赠指南', '原神账号捐赠指南') 38 | .action(() => { 39 | return segment.image(HOW_TO_DONATE) + template('genshin.donate.help_extra') 40 | }) 41 | } 42 | 43 | module.exports = { 44 | name: 'genshin/donate', 45 | apply, 46 | } 47 | -------------------------------------------------------------------------------- /src/view/styles/common.css: -------------------------------------------------------------------------------- 1 | /* Common STyles */ 2 | @font-face { 3 | font-family: 'Genshin'; 4 | font-style: normal; 5 | font-weight: normal; 6 | src: url('Genshin_Impact_Font.woff') 7 | format('truetype'); 8 | } 9 | 10 | * { 11 | box-sizing: border-box; 12 | } 13 | 14 | html, 15 | body { 16 | margin: 0; 17 | padding: 0; 18 | font-size: 14px; 19 | font-family: Genshin, '微软雅黑', 'Microsoft Yahei', Arial, Helvetica, 20 | sans-serif; 21 | background-color: white; 22 | } 23 | 24 | h1 { 25 | font-size: 1.4rem; 26 | font-weight: bold; 27 | text-align: center; 28 | padding: 1rem; 29 | border-radius: 8px; 30 | background-color: #eae3dd; 31 | box-shadow: 0 0 0 2px #d9d3c5 inset, 0 0 0 4px #eae3dd; 32 | } 33 | 34 | .box { 35 | margin: 1rem 0; 36 | } 37 | 38 | .box .boxTitle { 39 | margin: 2rem 0 1rem 0; 40 | padding: 0.5rem 1rem; 41 | text-align: center; 42 | color: #fff; 43 | font-size: 1.4rem; 44 | line-height: 2.4; 45 | background-image: url(../images/Header_background.png); 46 | background-position: center; 47 | background-repeat: no-repeat; 48 | background-size: auto 3rem; 49 | } 50 | 51 | .box .boxContent { 52 | border: 1px solid #ffdd95; 53 | background-color: #f5f5f5; 54 | padding: 0.4rem 0.75rem; 55 | border-radius: 8px; 56 | } 57 | 58 | footer { 59 | line-height: 1.2; 60 | text-align: right; 61 | color: gray; 62 | padding-right: 8px; 63 | border-right: 6px solid #ffdd95; 64 | border-radius: 4px; 65 | } 66 | footer p { 67 | margin: 0; 68 | } 69 | 70 | .flex { 71 | display: flex; 72 | } 73 | .flex-1 { 74 | flex: 1; 75 | } 76 | -------------------------------------------------------------------------------- /src/modules/renderProfile.js: -------------------------------------------------------------------------------- 1 | const pug = require('pug') 2 | const { segment, template } = require('koishi-utils') 3 | const path = require('path') 4 | const { activedConstellations } = require('@genshin-kit/core').util 5 | 6 | function m(k) { 7 | return template(`genshin.profile.${k}`) 8 | } 9 | 10 | module.exports = async ({ uid, userInfo, allCharacters, ctx }) => { 11 | let screenshot 12 | 13 | let _stats = Object.assign({}, userInfo.stats) 14 | userInfo.stats = [] 15 | for (key in _stats) { 16 | userInfo.stats.push({ desc: m('stats.' + key), count: _stats[key] }) 17 | } 18 | 19 | allCharacters.forEach((item) => { 20 | item.activedConstellations = activedConstellations(item) 21 | }) 22 | 23 | userInfo.avatars = allCharacters 24 | 25 | const options = { 26 | ui: { 27 | title: m('ui.title'), 28 | }, 29 | uid, 30 | ...userInfo, 31 | } 32 | const html = pug.renderFile( 33 | path.resolve(__dirname, '../view/profile.pug'), 34 | options 35 | ) 36 | 37 | const page = await ctx.app.puppeteer.page(); 38 | 39 | try { 40 | await page.goto( 41 | 'file:///' + path.resolve(__dirname, '../view/index.html') 42 | ) 43 | await page.setContent(html) 44 | const { width, height } = await page.evaluate(() => { 45 | const ele = document.body; 46 | return { 47 | width: ele.scrollWidth, 48 | height: ele.scrollHeight, 49 | }; 50 | }); 51 | await page.setViewport({ 52 | width: Math.ceil(width + 14), 53 | height: Math.ceil(height + 14), 54 | }); 55 | screenshot = await page.screenshot({ 56 | fullPage: true, 57 | type: 'jpeg', 58 | }) 59 | } catch (err) { 60 | await page.close() 61 | return `错误:${err}` 62 | } 63 | 64 | await page.close() 65 | return segment.image(screenshot) 66 | } 67 | -------------------------------------------------------------------------------- /src/plugins/profile.js: -------------------------------------------------------------------------------- 1 | const { template, segment, Time } = require('koishi-utils') 2 | const { isValidCnUid } = require('@genshin-kit/core').util 3 | const { getErrMsg, handleError } = require('../utils/handleError') 4 | const { getGenshinApp } = require('../modules/database') 5 | 6 | /** 7 | * @param {import('koishi-core').Context} ctx 8 | */ 9 | function apply(ctx) { 10 | ctx 11 | .command('genshin.profile', template('genshin.commands.profile'), { 12 | minInterval: Time.second * 30, 13 | }) 14 | .userFields(['genshin_uid']) 15 | .option('uid', `-u ${template('genshin.commands.options_specify_uid')}`) 16 | .check(({ session, options }) => { 17 | let uid = options.uid || session.user.genshin_uid 18 | if (!uid) return template('genshin.not_registered') 19 | if (!isValidCnUid(uid)) return template('genshin.invalid_cn_uid') 20 | }) 21 | .action(async ({ session, options }) => { 22 | let uid = options.uid || session.user.genshin_uid 23 | const genshin = await getGenshinApp(session, uid) 24 | if (!genshin) { 25 | return template('genshin.donate.daily_runout') 26 | } 27 | 28 | try { 29 | const [userInfo, allCharacters] = await Promise.all([ 30 | genshin.getUserInfo(uid, true), 31 | genshin.getAllCharacters(uid, true), 32 | ]) 33 | 34 | // 截图 35 | if (ctx.app.puppeteer) { 36 | let image = await require('../modules/renderProfile')({ 37 | uid, 38 | userInfo, 39 | allCharacters, 40 | ctx, 41 | }) 42 | return segment.quote(session.messageId) + image 43 | } 44 | 45 | // 文字版 46 | return '截图失败:未安装 koishi-plugin-puppeteer,请联系 bot 管理员。' 47 | } catch (err) { 48 | handleError(session, genshin, err) 49 | } 50 | }) 51 | } 52 | 53 | module.exports = { 54 | name: 'genshin/profile', 55 | apply, 56 | } 57 | -------------------------------------------------------------------------------- /src/view/character.pug: -------------------------------------------------------------------------------- 1 | mixin reliquaries(ctx) 2 | - const { name, icon, rarity , pos_name, level } = ctx; 3 | .item.flex(class=[`rarity-${rarity}`]) 4 | img.icon(src=icon) 5 | .info 6 | .name= name 7 | .flex 8 | .rarity 9 | img(src=`images/Star/${rarity}.png`) 10 | .level +#{level} 11 | 12 | mixin constellations(ctx) 13 | - const { icon, is_actived } = ctx; 14 | div.item(class={ 'is-actived': is_actived, 'is-locked': !is_actived }) 15 | img.icon(src=icon) 16 | 17 | doctype html 18 | html 19 | head 20 | style 21 | link(rel="stylesheet", href="styles/common.css") 22 | link(rel="stylesheet", href="styles/character.css") 23 | 24 | body 25 | .container(class=[`rarity-${rarity}`]) 26 | .left 27 | .flex 28 | .portrait 29 | img(src=image) 30 | .title 31 | .name= name 32 | .level #{level}级 33 | .fetter 好感度 #{fetter} 34 | 35 | .right 36 | .card.constellations 37 | h2 命之座 38 | .content 39 | .flex 40 | each item in constellations 41 | +constellations(item) 42 | .desc 已激活: #{actived_constellation_num} 43 | 44 | .card.weapon 45 | h2 武器 - #{weapon.type_name} 46 | .content 47 | .flex 48 | .icon 49 | img(src=weapon.icon) 50 | .info 51 | .title 52 | .name= weapon.name 53 | .affix_level 精炼 #{weapon.affix_level} 阶 54 | .rarity 55 | img(src=`images/Star/${weapon.rarity}.png`) 56 | .level #{weapon.level}级 57 | hr 58 | .desc= weapon.desc 59 | 60 | .card.reliquaries 61 | h2 圣遗物 62 | .content 63 | each item in reliquaries 64 | +reliquaries(item) 65 | 66 | //- 脚注 67 | include footer.pug -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # This part is for develop 107 | dev/ 108 | *.dev.* 109 | 110 | # Secrets 111 | secret*.* 112 | secret/ 113 | !secret_sample/ 114 | !secret*.sample.* -------------------------------------------------------------------------------- /src/plugins/dailynote.js: -------------------------------------------------------------------------------- 1 | const { template, segment, Time } = require('koishi-utils') 2 | const { handleError } = require('../utils/handleError') 3 | const { getGenshinApp } = require('../modules/database') 4 | 5 | /** 6 | * @param {import('koishi-core').Context} ctx 7 | */ 8 | function apply(ctx) { 9 | ctx 10 | .command('genshin.dailynote', template('genshin.commands.dailynote'), { 11 | minInterval: Time.second * 15, 12 | }) 13 | .alias('genshin.note') 14 | .userFields(['genshin_uid']) 15 | .check(({ session }) => { 16 | let uid = session.user.genshin_uid 17 | if (!uid) return template('genshin.not_registered') 18 | }) 19 | .action(async ({ session }) => { 20 | let uid = session.user.genshin_uid 21 | const genshin = await getGenshinApp(session, uid) 22 | if (!genshin?.selfUid?.includes('' + uid)) { 23 | return template('genshin.dailynote.no_permission', uid) 24 | } 25 | 26 | try { 27 | const { 28 | current_resin, 29 | max_resin, 30 | resin_recovery_time, 31 | finished_task_num, 32 | total_task_num, 33 | // is_extra_task_reward_received, 34 | remain_resin_discount_num, 35 | resin_discount_num_limit, 36 | current_expedition_num, 37 | max_expedition_num, 38 | expeditions, 39 | } = await genshin.getDailyNote(uid) 40 | 41 | return [ 42 | `${segment.quote(session.messageId)}〓玩家 ${uid} 的实时便笺〓`, 43 | `原粹树脂:${current_resin}/${max_resin} (${ 44 | resin_recovery_time > 0 45 | ? `${Time.formatTime(resin_recovery_time * 1000)} 后回满` 46 | : '已完全恢复' 47 | })`, 48 | `每日委托:已完成 ${finished_task_num}/${total_task_num} 个`, 49 | `周常副本:半价领取奖励机会 ${remain_resin_discount_num}/${resin_discount_num_limit} 次`, 50 | `〓探索派遣〓`, 51 | `已派出 ${current_expedition_num}/${max_expedition_num} 人`, 52 | expeditions 53 | .map( 54 | ({ avatar_side_icon, status, remained_time }) => 55 | ` ${ 56 | avatar_side_icon.split('_').pop().split('.')[0] 57 | } - ${template( 58 | `genshin.dailynote.status_${status.toLocaleLowerCase()}` 59 | )}${ 60 | remained_time > 0 61 | ? ` (${Time.formatTime(remained_time * 1000)} 后结束)` 62 | : '' 63 | }` 64 | ) 65 | .join('\n'), 66 | ].join('\n') 67 | } catch (e) { 68 | handleError(e) 69 | } 70 | }) 71 | } 72 | 73 | module.exports = { 74 | name: 'genshin/dailynote', 75 | apply, 76 | } 77 | -------------------------------------------------------------------------------- /src/view/profile.pug: -------------------------------------------------------------------------------- 1 | mixin statsCard(ctx) 2 | - const { desc, count } = ctx; 3 | .item 4 | .count= count 5 | .desc= desc 6 | 7 | mixin characterCard(ctx) 8 | - const { name, icon, level, rarity, fetter, element, activedConstellations } = ctx; 9 | div(class=['characterCard', 'rarity-' + rarity]) 10 | .inner(style={'background-image':`url(images/ItemBackground/Rarity_${rarity}.png)`}) 11 | .sideIcons 12 | .element 13 | img(src=`images/Element/${element}.png` alt=element) 14 | .constellation= activedConstellations 15 | img.avatar(src=icon) 16 | .characterName 17 | span.text #{name} 18 | .outer 19 | .characterLevel 等级 #{level} 20 | .characterFetter 好感 #{fetter} 21 | 22 | mixin cityCard(ctx) 23 | - const { level, exploration_percentage, icon, name } = ctx; 24 | .cityCard 25 | .left 26 | img.cityIcon(src=icon) 27 | .right 28 | .cityName= name 29 | .cityLevel 声望 #{level} 级 30 | .cityExploration 探索度 #{exploration_percentage / 10}% 31 | 32 | mixin homeCard(ctx) 33 | - const { name, icon, level, item_num, visit_num, comfort_num, comfort_level_name, comfort_level_icon } = ctx 34 | .homeCard( 35 | style={ 'background-image': 'url(' + icon + ')' } 36 | ) 37 | .top 38 | .comfortInfo 39 | img(src=comfort_level_icon) 40 | .confortName= comfort_level_name 41 | .homeName= name 42 | .bottom 43 | .levelInfo 44 | .num= level 45 | .desc 信任等阶 46 | .comfortNum 47 | .num= comfort_num 48 | .desc 最高仙力 49 | .itemNum 50 | .num= item_num 51 | .desc 摆设数量 52 | .visitorNum 53 | .num= visit_num 54 | .desc 来访人数 55 | 56 | 57 | doctype html 58 | html 59 | head 60 | link(rel="stylesheet", href="styles/common.css") 61 | link(rel="stylesheet", href="styles/profile.css") 62 | 63 | body 64 | //- 标题 65 | .profile-container 66 | h1 玩家 #{uid} 的原神信息 67 | 68 | //- 数据总览 69 | .box 70 | .boxTitle 数据总览 71 | .boxContent 72 | .statsList 73 | each item in stats 74 | +statsCard(item) 75 | 76 | //- 角色列表 77 | .box 78 | .boxTitle 角色列表 79 | .boxContent 80 | .characterList 81 | each item in avatars 82 | +characterCard(item) 83 | p 右上角为命座数量 84 | 85 | //- 世界探索 86 | .box 87 | .boxTitle 世界探索 88 | .boxContent 89 | .cityList 90 | each item in world_explorations 91 | +cityCard(item) 92 | 93 | //- 尘歌壶 94 | .box 95 | .boxTitle 尘歌壶 96 | .boxContent 97 | .homeList 98 | each item in homes 99 | +homeCard(item) 100 | 101 | include footer.pug -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # koishi-plugin-genshin 2 | 3 | **Koishi 原神大礼包**(_Genshin Impact for Koishi.js_)是一个为[koishi](https://github.com/koishijs/koishi)设计的查询展示原神国服玩家数据以及抽卡模拟的插件。 4 | 5 | ## 特色功能 6 | 7 | 喜欢玩《原神》?懒得下载米游社?想和沙雕群友一起凹数据?那么本插件将会是您的不二之选!来给您的群聊安排一只能查询原神数据的 koishi 机械姬吧~ 8 | 9 | 为您的机械姬安装本插件,玩家们无需打开米游社,向 koishi bot 发送指令,一键炫耀您的五星角色、五星武器和深渊数据! 10 | 11 | 想看看自己是不是非酋?想要成为下一个天选之人?向 koishi bot 发送指令,进行模拟抽卡吧! 12 | 13 | **截图展示** 14 | 15 |
16 | 玩家资料卡 (genshin.profile) 17 | 18 | ![genshin-profile.jpg](https://i.loli.net/2021/09/10/9Q1MzJfqmUhj46y.jpg) 19 | 20 |
21 | 22 |
23 | 角色展示卡 (genshin.character) 24 | 25 | ![genshin-character.jpg](https://i.loli.net/2021/09/10/oq1AYMeQNjlX8Zf.jpg) 26 | 27 |
28 | 29 | ## 安装方法 30 | 31 | ```bash 32 | # Via yarn 33 | yarn add koishi-plugin-genshin 34 | # Or via npm 35 | npm install koishi-plugin-genshin 36 | ``` 37 | 38 | ## 使用指南 39 | 40 | 具体用法请使用`help genshin`查看(~~作者只是懒得写文档~~) 41 | 42 | ## 系统需求 43 | 44 | 需要配合最新版 koishi v3。需要配置数据库,暂时只保证兼容 MongoDB。 45 | 46 | 若要使用完整的“卡片”功能,需要配置并安装 [koishi-plugin-puppeteer](https://npmjs.com/package/koishi-plugin-puppeteer)。 47 | 48 | ## 配置项目 49 | 50 | 插件目前需要使用您的网页版米游社的 cookie 来获取玩家信息。 51 | 52 | > 使用网页版米游社登录 ,然后在控制台输入 `document.cookie`,返回的结果就是 cookie,一般来说只要没有进行修改密码、换绑手机或点击退出按钮等操作,当前 cookie 便能长久使用,如果失效了就重新登录获取一遍。 53 | 54 | > **⚠️ 注意 ⚠️**:请妥善保存您的 cookies。
绝对不要把你的 cookies 交给任何人!
绝对绝对不要把你的 cookies 交给任何人!!
绝对绝对绝对不要把你的 cookies 交给任何人!!! 55 | 56 | 安装插件,详见 [官方指南](https://koishi.js.org/guide/context.html)。 57 | 58 |
59 | 配置示例 60 | 61 | ```js 62 | // koishi.config.js 63 | module.exports = { 64 | plugins: { 65 | // ... 66 | genshin: { 67 | // 本插件的配置项 68 | } 69 | // ... 70 | } 71 | } 72 | // 当然如果您是 index.js 玩家也可以这样 73 | App.plugin(require('koishi-plugin-genshin'), { 74 | // 本插件的配置项 75 | }) 76 | ``` 77 | 78 |
79 | 80 | 自定义输出排版,可以使用 koishi 的 template 语法,由于字符串太多,[《请您读源码.jpg》](./i18n.js)。 81 | 82 | **可用配置项** 83 | 84 | - `cookie` {string} 您的米游社小饼干 85 | - `wish` {object} 86 | - `wish.enable` {boolean} 是否开启抽卡模拟器 87 | - `wish.customPools` {[AppGachaPool[]](https://github.com/genshin-kit/genshin-gacha-kit)} 自定义卡池(格式详见`genshin-gacha-kit`) 88 | 89 | ## 注意事项 90 | 91 | 一个米游社账号一天内只能查询 30 个玩家数据,目前还没有考虑负载均衡的设计,请自行处理频率控制! 92 | 93 | ~~【广告】如果你喜欢本插件,欢迎给作者打钱或者捐赠米游社账号。~~ 94 | 95 | --- 96 | 97 | _For communication and learning only._ 98 | 99 | **All game data & pictures from query, Genshin Impact font:** ©miHoYo 100 | 101 | > Copyright 2021 koishijs/机智的小鱼君 102 | > 103 | > Licensed under the Apache License, Version 2.0 (the "License");
104 | > you may not use this file except in compliance with the License.
105 | > You may obtain a copy of the License at 106 | > 107 | > http://www.apache.org/licenses/LICENSE-2.0 108 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name koishi-plugin-genshin 3 | * @desc Genshin Impact plugin for Koishijs 4 | * 5 | * @author Koishijs(机智的小鱼君) 6 | * @license Apache-2.0 7 | */ 8 | // Koishi 9 | const { segment, template, Time } = require('koishi-core') 10 | 11 | // GenshinKit 12 | const { isValidCnUid } = require('@genshin-kit/core').util 13 | 14 | /** 15 | * @command genshin 16 | * @param {import('koishi-core').Context} ctx 17 | */ 18 | function apply(ctx, pOptions) { 19 | pOptions = { 20 | donate: { 21 | enable: true, 22 | }, 23 | wish: { 24 | enable: false, 25 | officialPools: true, 26 | customPools: [], 27 | }, 28 | ...pOptions, 29 | } 30 | 31 | // Set template 32 | template.set('genshin', { ...require('./i18n'), ...pOptions.i18n }) 33 | 34 | // Register 35 | ctx 36 | .command('genshin [uid:posint]', template('genshin.commands.genshin'), { 37 | minInterval: Time.hour, 38 | }) 39 | .alias('原神') 40 | .userFields(['genshin_uid']) 41 | .example('@我 genshin 100000001') 42 | .check(({ session, options }, uid) => { 43 | if (options.help) return 44 | const userFileds = session.user 45 | if (!uid) { 46 | const reply = userFileds.genshin_uid 47 | ? template('genshin.info_regestered', userFileds.genshin_uid) 48 | : template('genshin.not_registered') 49 | return segment('quote', { id: session.messageId }) + reply 50 | } else if (!isValidCnUid(uid)) { 51 | return ( 52 | segment('quote', { id: session.messageId }) + 53 | template('genshin.invalid_cn_uid') 54 | ) 55 | } 56 | }) 57 | .action(async ({ session }, uid) => { 58 | const userFileds = session.user 59 | userFileds.genshin_uid = uid 60 | try { 61 | await session.user._update() 62 | } catch (err) { 63 | return ( 64 | segment('quote', { id: session.messageId }) + 65 | template('genshin.faild', err.message) 66 | ) 67 | } 68 | return ( 69 | segment('quote', { id: session.messageId }) + 70 | template('genshin.successfully_registered') 71 | ) 72 | }) 73 | 74 | // Abyss 75 | ctx.plugin(require('./plugins/abyss')) 76 | 77 | // Daily Note 78 | ctx.plugin(require('./plugins/dailynote')) 79 | 80 | // Character Card 81 | ctx.plugin(require('./plugins/character')) 82 | 83 | // Profile 84 | ctx.plugin(require('./plugins/profile')) 85 | 86 | // Wish 87 | if (pOptions.wish.enable) { 88 | ctx.plugin(require('./plugins/wish'), pOptions) 89 | } 90 | 91 | // Donate 92 | ctx.plugin(require('./plugins/donate')) 93 | 94 | // Debug 95 | ctx.command('genshin.debug', 'DEBUG', { hidden: true }).action(() => { 96 | const hoyolabVer = genshin._hoyolabVersion() 97 | return [`hoyolab(cn): ${hoyolabVer}`].join('\n') 98 | }) 99 | } 100 | 101 | module.exports = { 102 | name: 'genshin', 103 | apply, 104 | } 105 | -------------------------------------------------------------------------------- /src/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // command descriptions 3 | commands: { 4 | genshin: '《原神 Genshin Impact》功能', 5 | abyss: '查询原神深境螺旋数据。', 6 | character: '查询指定名称的角色的等级与装备信息。', 7 | dailynote: '查看本人实时便笺(需捐赠账号)。', 8 | donate: 9 | '捐赠您的米游社账号,提高每日查询上限。解锁无限次查询自己信息+实时便笺的特权!', 10 | profile: '查询玩家基本信息(宝箱、成就、声望)', 11 | options_specify_uid: '查询指定 uid 的信息', 12 | }, 13 | // genshin 14 | info_regestered: '您的《原神》uid已注册为:{0}', 15 | invalid_cn_uid: '您输入的不是合法的《原神》国服uid~', 16 | not_registered: 17 | '您还没有注册您的《原神》用户信息,请艾特我输入“genshin 游戏内uid”进行注册~(注意打空格)', 18 | successfully_registered: '您的《原神》信息注册成功~', 19 | // abyss 20 | abyss: { 21 | cur_not_active: '玩家 {0} 还没有开启本期深境螺旋。', 22 | cur_is_active: '玩家 {0} 的本期深境螺旋数据:', 23 | prev_not_active: '玩家 {0} 没有参与上一期深境螺旋。', 24 | prev_is_active: '玩家 {0} 的上一期深境螺旋数据:', 25 | basic_data: 26 | '〓基本信息〓\n到达层数:{{ max_floor }}\n战斗次数:{{ total_win_times }}次通关/{{ total_battle_times }}总尝试\n获得渊星:{{ total_star }}', 27 | top_stats: 28 | '〓最佳战绩〓\n最强一击:{{ damage_rank }}\n最高承伤:{{ take_damage_rank }}\n最常出场:{{ reveal_rank }}\n元素爆发:{{ energy_skill_rank }}', 29 | cur_time: '本期深境螺旋将于【{0}】结束,还剩 {1}。', 30 | prev_time: '上期深境螺旋从 {0} 开始,于 {1} 结束。', 31 | }, 32 | // characters 33 | has_character: '玩家 {0} 的 {1}:', 34 | no_character: '玩家 {0} 似乎没有名为 {1} 的角色。', 35 | character_basic: 36 | '{{ icon }}\n{{ name }} {{ rarity }}★ {{ constellation }}命\n等级:{{ level }}级,好感:{{ fetter }}级', // {{ icon }} -> 头像, {{ image }} -> 立绘 37 | character_weapon: 38 | '〓武器〓\n{{ name }} ({{ rarity }}★{{ type_name }})\n{{ level }}级 ({{ affix_level }}精炼)', 39 | character_reliquaries: '〓圣遗物〓\n{0}', 40 | has_x_star_characters: '玩家 {0} 一共拥有 {1} 个 {2}★ 角色。', 41 | no_x_star_character: '玩家 {0} 似乎没有 {1}★ 角色。', 42 | // 实时便笺 43 | dailynote: { 44 | no_permission: 45 | '未找到与 {0} 绑定的账号凭据,无法查看实时便笺。请捐赠账号后再试。', 46 | status_ongoing: '正在探索', 47 | status_finished: '探索完成', 48 | }, 49 | // 用于玩家信息截图 50 | profile: { 51 | ui: { 52 | title: '玩家 {0} 的原神信息', 53 | stats_title: '数据总览', 54 | avatar_title: '角色列表', 55 | city_explorations_title: '城市探索', 56 | }, 57 | stats: { 58 | active_day_number: '活跃天数', 59 | achievement_number: '达成成就', 60 | win_rate: 'win_rate', 61 | anemoculus_number: '风神瞳', 62 | geoculus_number: '岩神瞳', 63 | electroculus_number: '雷神瞳', 64 | avatar_number: '获得角色数', 65 | way_point_number: '解锁传送点', 66 | domain_number: '解锁秘境', 67 | spiral_abyss: '深境螺旋', 68 | precious_chest_number: '珍贵宝箱', 69 | luxurious_chest_number: '华丽宝箱', 70 | exquisite_chest_number: '精致宝箱', 71 | common_chest_number: '普通宝箱', 72 | magic_chest_number: '奇馈宝箱', 73 | }, 74 | }, 75 | // 贡献账号 76 | donate: { 77 | current_runout: '系统正在维护,请稍等片刻后再试一次!', 78 | daily_runout: 79 | '今日查询次数已耗尽,明天再来吧!\n想要提高查询上限吗?想要解锁无限次查询自己信息的特权吗?私信bot“捐赠米游社账号”了解详情。', 80 | upper_limit: '今日理论查询上限:{0} 名玩家(不包括捐赠者)', 81 | donor_thank: '感谢以下 {0} 位捐赠过账号的用户!\n{1}', 82 | help_extra: `〓您可能会用到的资料〓 83 | 米游社网页版: https://bbs.mihoyo.com/ys/ 84 | 输入到控制台的代码: alert(document.cookie) 85 | *注意:请私信 bot 操作捐赠!!!`, 86 | }, 87 | // error messages 88 | error: '出现了亿点问题:{0} ({1})', 89 | error_unknown: '未知问题', 90 | } 91 | -------------------------------------------------------------------------------- /src/plugins/character.js: -------------------------------------------------------------------------------- 1 | const { template, segment, Time } = require('koishi-utils') 2 | const { 3 | isValidCnUid, 4 | CharactersFilter, 5 | activedConstellations, 6 | } = require('@genshin-kit/core').util 7 | const { handleError } = require('../utils/handleError') 8 | const { getGenshinApp } = require('../modules/database') 9 | 10 | /** 11 | * @param {import('koishi-core').Context} ctx 12 | */ 13 | function apply(ctx) { 14 | ctx 15 | .command( 16 | 'genshin.character ', 17 | template('genshin.commands.character'), 18 | { 19 | minInterval: Time.second * 15, 20 | } 21 | ) 22 | .option('uid', `-u ${template('genshin.commands.options_specify_uid')}`) 23 | .example('genshin.character 旅行者') 24 | .userFields(['genshin_uid']) 25 | .check(({ session, options }) => { 26 | let uid = options.uid || session.user.genshin_uid 27 | if (!uid) return template('genshin.not_registered') 28 | if (!isValidCnUid(uid)) return template('genshin.invalid_cn_uid') 29 | }) 30 | .action(async ({ session, options }, name = '旅行者') => { 31 | let uid = options.uid || session.user.genshin_uid 32 | const genshin = await getGenshinApp(session, uid) 33 | if (!genshin) { 34 | return template('genshin.donate.daily_runout') 35 | } 36 | 37 | try { 38 | const allCharacters = await genshin.getAllCharacters(uid, true) 39 | const Filter = new CharactersFilter(allCharacters) 40 | const character = Filter.name(name) 41 | 42 | if (!character) return template('genshin.no_character', uid, name) 43 | 44 | // 截图 45 | if (ctx.app.puppeteer) { 46 | const image = await require('../modules/renderCharacter')({ 47 | uid, 48 | character, 49 | ctx, 50 | }) 51 | return segment.quote(session.messageId) + image 52 | } 53 | 54 | // 文字版 55 | return [ 56 | template('genshin.has_character', uid, character.name), 57 | template('genshin.character_basic', { 58 | icon: segment('image', { url: character.icon }), 59 | image: segment('image', { url: character.image }), 60 | name: character.name, 61 | rarity: character.rarity, 62 | constellation: activedConstellations(character), 63 | level: character.level, 64 | fetter: character.fetter, 65 | }), 66 | template('genshin.character_weapon', { 67 | name: character.weapon.name, 68 | rarity: character.weapon.rarity, 69 | type_name: character.weapon.type_name, 70 | level: character.weapon.level, 71 | affix_level: character.weapon.affix_level, 72 | }), 73 | template( 74 | 'genshin.character_reliquaries', 75 | reliquariesFmt(character.reliquaries) 76 | ), 77 | ].join('\n') 78 | } catch (err) { 79 | handleError(session, genshin, err) 80 | } 81 | }) 82 | 83 | function reliquariesFmt(reliquaries) { 84 | if (reliquaries.length < 1) return '无' 85 | let msg = '' 86 | reliquaries.forEach((item) => { 87 | msg += `${item.pos_name}:${item.name} (${item.rarity}★)\n` 88 | }) 89 | return msg.trim() 90 | } 91 | } 92 | 93 | module.exports = { 94 | name: 'genshin/character', 95 | apply, 96 | } 97 | -------------------------------------------------------------------------------- /src/view/styles/character.css: -------------------------------------------------------------------------------- 1 | /* palette */ 2 | .rarity-5 { 3 | --bg-color: #fcf0d5; 4 | --card-color: #f4e4be; 5 | --border-color: #b2732b; 6 | --hr-color: #e0cda1; 7 | } 8 | .rarity-4 { 9 | --bg-color: #e4dffb; 10 | --card-color: #d3ccf3; 11 | --border-color: #63598b; 12 | --hr-color: #b9afe7; 13 | } 14 | .rarity-105 { 15 | --bg-color: #fad6d8; 16 | --card-color: #f1c1c4; 17 | --border-color: #b54f56; 18 | --hr-color: #eba8ac; 19 | } 20 | 21 | /* common */ 22 | .flex { 23 | display: flex; 24 | } 25 | .container { 26 | display: flex; 27 | background-color: var(--bg-color); 28 | margin: 6px; 29 | box-shadow: 0 0 0 2px #fff inset, 0 0 0 2px var(--border-color); 30 | border-radius: 6px; 31 | } 32 | 33 | /* left */ 34 | .container > .left { 35 | display: flex; 36 | position: relative; 37 | width: 40vw; 38 | } 39 | .container > .left .flex { 40 | align-items: center; 41 | } 42 | .container > .left .portrait { 43 | align-content: center; 44 | display: flex; 45 | } 46 | .container > .left .portrait img { 47 | width: 100%; 48 | height: auto; 49 | } 50 | .container > .left .title { 51 | position: absolute; 52 | width: 100%; 53 | bottom: 25%; 54 | left: 50%; 55 | text-align: center; 56 | transform: translateX(-50%); 57 | padding: 1rem; 58 | color: #fff; 59 | background-image: linear-gradient( 60 | 90deg, 61 | rgba(0, 0, 0, 0), 62 | rgba(0, 0, 0, 0.5), 63 | rgba(0, 0, 0, 0) 64 | ); 65 | } 66 | .container > .left .title .name { 67 | font-size: 2rem; 68 | } 69 | 70 | /* right */ 71 | .container > .right { 72 | flex: 1; 73 | padding: 1rem; 74 | position: relative; 75 | display: flex; 76 | flex-direction: column; 77 | gap: 1rem; 78 | justify-content: center; 79 | } 80 | 81 | /* card */ 82 | .card h2 { 83 | font-weight: normal; 84 | background-color: var(--border-color); 85 | color: #fff; 86 | margin: 0; 87 | padding: 0.4rem; 88 | padding-left: 1rem; 89 | } 90 | .card .content { 91 | background-color: var(--card-color); 92 | padding: 1rem; 93 | } 94 | .card hr { 95 | border: none; 96 | border-bottom: 2px dashed var(--hr-color); 97 | margin: 0.4rem 0 0.4rem 0; 98 | padding: 0; 99 | } 100 | 101 | /* constellations */ 102 | .constellations .flex { 103 | display: flex; 104 | gap: 1rem; 105 | justify-content: space-around; 106 | } 107 | .constellations .item .icon { 108 | height: auto; 109 | width: 100%; 110 | } 111 | .constellations .desc { 112 | margin-top: 0.5rem; 113 | } 114 | .constellations .item { 115 | flex: 1; 116 | position: relative; 117 | border-radius: 50%; 118 | } 119 | .constellations .item { 120 | border: 4px solid #fff; 121 | background-color: rgba(0, 0, 0, 0.1); 122 | } 123 | .constellations .item.is-locked::before { 124 | content: ''; 125 | display: block; 126 | position: absolute; 127 | border-radius: 50%; 128 | width: 100%; 129 | height: 100%; 130 | background-color: rgba(0, 0, 0, 0.25); 131 | background-image: url(../images/Lock.png); 132 | background-repeat: no-repeat; 133 | background-position: 50%; 134 | background-size: 30px; 135 | } 136 | 137 | /* reliquaries */ 138 | .reliquaries .content { 139 | display: flex; 140 | flex-wrap: wrap; 141 | gap: 1rem; 142 | } 143 | .reliquaries .item { 144 | width: calc(50% - 1rem); 145 | align-items: center; 146 | } 147 | .reliquaries .icon { 148 | width: 65px; 149 | } 150 | .reliquaries .info { 151 | display: flex; 152 | flex-direction: column; 153 | align-items: center; 154 | font-size: 1.2rem; 155 | } 156 | .reliquaries .info .name { 157 | font-size: 1.2rem; 158 | } 159 | .reliquaries .info .rarity img { 160 | height: 1em; 161 | } 162 | 163 | /* weapon */ 164 | .weapon .content > .flex { 165 | gap: 1rem; 166 | align-items: center; 167 | } 168 | .weapon .icon img { 169 | width: 80px; 170 | } 171 | .weapon .info { 172 | flex: 1; 173 | } 174 | .weapon .rarity img { 175 | height: 1.4rem; 176 | } 177 | .weapon .info .title { 178 | gap: 8px; 179 | vertical-align: baseline; 180 | } 181 | 182 | .weapon .info .title > div { 183 | display: inline; 184 | } 185 | 186 | .weapon .info .title .name { 187 | font-size: 1.6rem; 188 | } 189 | -------------------------------------------------------------------------------- /src/plugins/abyss.js: -------------------------------------------------------------------------------- 1 | const { template, segment, Time } = require('koishi-utils') 2 | const { isValidCnUid, CharactersFilter } = require('@genshin-kit/core').util 3 | const { dateFormat, getTimeLeft } = require('../utils/dateFormat') 4 | const { handleError } = require('../utils/handleError') 5 | const { getGenshinApp } = require('../modules/database') 6 | 7 | /** 8 | * @param {import('koishi-core').Context} ctx 9 | */ 10 | function apply(ctx) { 11 | ctx 12 | .command('genshin.abyss', template('genshin.commands.abyss'), { 13 | minInterval: Time.second * 15, 14 | }) 15 | // .shortcut(/(原神深渊|深境螺旋)/) 16 | .option( 17 | 'uid', 18 | `-u ${template('genshin.commands.options_specify_uid')}` 19 | ) 20 | .option('previous', '-p 查询上一期的数据', { type: 'boolean' }) 21 | .userFields(['genshin_uid']) 22 | .check(({ session, options }) => { 23 | let uid = options.uid || session.user.genshin_uid 24 | if (!uid) return template('genshin.not_registered') 25 | if (!isValidCnUid(uid)) return template('genshin.invalid_cn_uid') 26 | }) 27 | .action(async ({ session, options }) => { 28 | let uid = options.uid || session.user.genshin_uid 29 | const genshin = await getGenshinApp(session, uid) 30 | if (!genshin) { 31 | return template('genshin.donate.daily_runout') 32 | } 33 | 34 | const type = options.previous ? 'prev' : 'cur' 35 | 36 | Promise.all([ 37 | genshin.getAbyss(uid, type === 'cur' ? 1 : 2, true), 38 | genshin.getUserInfo(uid, true), 39 | ]).then( 40 | (data) => { 41 | // 变量 42 | const [abyssInfo, basicInfo] = data 43 | const Filter = new CharactersFilter(basicInfo.avatars || []) 44 | const { 45 | start_time, 46 | end_time, 47 | total_battle_times, 48 | total_win_times, 49 | max_floor, 50 | total_star, 51 | is_unlock, 52 | reveal_rank, 53 | damage_rank, 54 | take_damage_rank, 55 | energy_skill_rank, 56 | } = abyssInfo 57 | 58 | const startTimeStr = dateFormat( 59 | 'yyyy年M月d日 hh:mm:ss', 60 | new Date(start_time * 1000) 61 | ) 62 | const endTimeStr = dateFormat( 63 | 'yyyy年M月d日 hh:mm:ss', 64 | new Date(end_time * 1000) 65 | ) 66 | 67 | // 格式化的顶尖信息 68 | function formatedCharacterValue(data) { 69 | if (data.length < 1) return '无' 70 | let top = data[0] 71 | return `${Filter.id(top.avatar_id).name || top.avatar_id} ${ 72 | top.value 73 | }` 74 | } 75 | 76 | // 格式化信息 77 | let msg = '' 78 | if (!is_unlock) { 79 | msg += template(`genshin.abyss.${type}_not_active`, uid) 80 | } else { 81 | msg += [ 82 | template(`genshin.abyss.${type}_is_active`, uid), 83 | template('genshin.abyss.basic_data', { 84 | max_floor, 85 | total_win_times, 86 | total_battle_times, 87 | total_star, 88 | }), 89 | template('genshin.abyss.top_stats', { 90 | damage_rank: formatedCharacterValue(damage_rank), 91 | take_damage_rank: formatedCharacterValue(take_damage_rank), 92 | reveal_rank: formatedCharacterValue(reveal_rank), 93 | energy_skill_rank: formatedCharacterValue(energy_skill_rank), 94 | }), 95 | ].join('\n') 96 | } 97 | 98 | // 时间信息 99 | msg += '\n\n' 100 | if (type === 'cur') { 101 | msg += template( 102 | 'genshin.abyss.cur_time', 103 | endTimeStr, 104 | getTimeLeft(end_time * 1000) 105 | ) 106 | } else { 107 | msg += template('genshin.abyss.prev_time', startTimeStr, endTimeStr) 108 | } 109 | 110 | // 发送 111 | session.send(segment('quote', { id: session.messageId }) + msg) 112 | }, 113 | (err) => { 114 | handleError(session, genshin, err) 115 | } 116 | ) 117 | }) 118 | } 119 | 120 | module.exports = { 121 | name: 'genshin/abyss', 122 | apply, 123 | } 124 | -------------------------------------------------------------------------------- /src/view/styles/profile.css: -------------------------------------------------------------------------------- 1 | /* 基础信息(神瞳数量等) */ 2 | .profile-container { 3 | margin: 1rem; 4 | } 5 | 6 | .statsList { 7 | display: flex; 8 | flex-wrap: wrap; 9 | justify-content: space-between; 10 | } 11 | 12 | .statsList .item { 13 | box-sizing: border-box; 14 | width: 25%; 15 | padding: 8px; 16 | text-align: center; 17 | } 18 | .statsList .item .count { 19 | font-size: 1.6rem; 20 | } 21 | .statsList .item .desc { 22 | color: gray; 23 | } 24 | 25 | /* 简单角色卡 */ 26 | .characterList { 27 | display: flex; 28 | flex-flow: wrap; 29 | justify-content: space-between; 30 | gap: 2rem; 31 | padding: 2rem; 32 | } 33 | .characterList .characterCard .inner { 34 | position: relative; 35 | background-size: cover; 36 | background-repeat: no-repeat; 37 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.4); 38 | border-radius: 8px; 39 | color: white; 40 | } 41 | .characterList .characterCard .rarity { 42 | position: absolute; 43 | top: 130px; 44 | left: 50%; 45 | transform: translateX(-50%); 46 | z-index: 5; 47 | } 48 | .characterList .characterCard .rarity img { 49 | width: auto; 50 | height: 24px; 51 | } 52 | .characterList .characterCard img.avatar { 53 | height: 150px; 54 | width: auto; 55 | } 56 | .characterList .characterCard .characterName { 57 | font-size: 1.4rem; 58 | padding: 0.4rem; 59 | padding-top: 0; 60 | color: #000; 61 | text-align: center; 62 | position: relative; 63 | } 64 | .characterList .characterCard .characterName .text { 65 | position: relative; 66 | z-index: 1; 67 | } 68 | .characterList .characterCard .characterName img { 69 | position: absolute; 70 | left: 0; 71 | bottom: 0; 72 | width: 148px; 73 | height: auto; 74 | } 75 | .characterCard .element img { 76 | position: absolute; 77 | left: 0rem; 78 | top: 0rem; 79 | width: 2.4rem; 80 | height: 2.4rem; 81 | } 82 | .characterCard .constellation { 83 | position: absolute; 84 | right: -8px; 85 | top: -8px; 86 | border-radius: 50%; 87 | display: inline-block; 88 | width: 2rem; 89 | height: 2rem; 90 | text-align: center; 91 | font-size: 1.2rem; 92 | line-height: calc(2 / 1.2); 93 | color: #fff; 94 | } 95 | .characterCard.rarity-105 .constellation { 96 | background-color: #b54f56; 97 | box-shadow: 0 0 0 2px #fff inset, 0 0 0 2px #b54f56; 98 | } 99 | .characterCard.rarity-5 .constellation { 100 | background-color: #b2732b; 101 | box-shadow: 0 0 0 2px #fff inset, 0 0 0 2px #b2732b; 102 | } 103 | .characterCard.rarity-4 .constellation { 104 | background-color: #63598b; 105 | box-shadow: 0 0 0 2px #fff inset, 0 0 0 2px #63598b; 106 | } 107 | .characterList .characterCard .outer { 108 | margin-top: 0.4rem; 109 | font-size: 1.2rem; 110 | text-align: center; 111 | } 112 | 113 | /* 城市列表 */ 114 | .cityList { 115 | display: flex; 116 | flex-flow: wrap; 117 | } 118 | .cityCard { 119 | background-image: url(../images/City_background.png); 120 | background-position: top left; 121 | background-repeat: no-repeat; 122 | background-size: 100% 120px; 123 | box-sizing: border-box; 124 | width: calc(50% - 2rem); 125 | height: 120px; 126 | color: #fff; 127 | border-radius: 8px; 128 | padding: 1rem; 129 | margin: 1rem; 130 | } 131 | .cityCard img { 132 | width: 90px; 133 | float: left; 134 | } 135 | .cityCard .right { 136 | height: 100%; 137 | display: flex; 138 | flex-direction: column; 139 | justify-content: center; 140 | } 141 | .cityCard .cityName { 142 | font-size: 30px; 143 | } 144 | 145 | /* 家园列表 */ 146 | .homeList { 147 | display: flex; 148 | flex-flow: wrap; 149 | } 150 | .homeCard { 151 | background-position: top left; 152 | background-repeat: no-repeat; 153 | background-size: 100% 100%; 154 | box-sizing: border-box; 155 | width: calc(50% - 2rem); 156 | color: #fff; 157 | border-radius: 8px; 158 | margin: 1rem; 159 | } 160 | .homeCard .top { 161 | display: flex; 162 | padding: 1rem; 163 | } 164 | .homeCard .top .comfortInfo { 165 | flex: 1; 166 | display: flex; 167 | justify-items: center; 168 | align-items: center; 169 | font-size: 1.2rem; 170 | } 171 | .homeCard .top .comfortInfo img { 172 | width: 2rem; 173 | margin-right: 4px; 174 | } 175 | .homeCard .bottom { 176 | display: flex; 177 | margin: 1rem auto; 178 | background-color: rgba(0, 0, 0, 0.4); 179 | padding: 1rem 0.2rem; 180 | } 181 | .homeCard .bottom > div { 182 | flex: 1; 183 | text-align: center; 184 | } 185 | .homeCard .bottom > div .num { 186 | font-size: 1.5rem; 187 | } 188 | -------------------------------------------------------------------------------- /src/modules/database.js: -------------------------------------------------------------------------------- 1 | const { Session } = require('koishi-core') 2 | const { GenshinKit } = require('@genshin-kit/core') 3 | 4 | const colName = 'hoyolab-cookies' 5 | 6 | /** 7 | * @param {Session} session 8 | * @param {string} cookie 9 | */ 10 | async function insertCookie(session, cookie) { 11 | const { ltoken, ltuid } = getCookieObj(cookie) 12 | if (!ltoken || !ltuid) return '操作失败:提供的 cookie 不正确。' 13 | 14 | // check cookie, get roles 15 | let roles = [] 16 | try { 17 | roles = await getBindingRoles(`ltoken=${ltoken}; ltuid=${ltuid}`) 18 | } catch (e) { 19 | return '操作失败:用户信息验证失败。' 20 | } 21 | 22 | if (roles.length < 1) { 23 | return '操作失败:该账号未绑定原神角色。' 24 | } 25 | 26 | // 操作数据库 27 | try { 28 | // 是否已经保存过 29 | const already = await session.database.mongo.db 30 | .collection(colName) 31 | .find({ ltuid }) 32 | .limit(1) 33 | .toArray() 34 | if (already.length) { 35 | // 已保存过,刷新信息 36 | await session.database.mongo.db.collection(colName).updateOne( 37 | { ltuid }, 38 | { 39 | $set: { 40 | owner: `${session.platform}:${session.userId}`, 41 | ltoken, 42 | game_uid: roles.map(({ game_uid }) => game_uid), 43 | }, 44 | } 45 | ) 46 | } else { 47 | // 未保存过,新增一行 48 | await session.database.mongo.db.collection(colName).insertOne({ 49 | owner: `${session.platform}:${session.userId}`, 50 | ltuid, 51 | ltoken, 52 | game_uid: roles.map(({ game_uid }) => game_uid), 53 | last_disabled: '', 54 | }) 55 | } 56 | 57 | // 成功! 58 | return `${ 59 | already.length ? '成功刷新账号信息!' : '成功添加账号信息!' 60 | }已绑定原神游戏角色:\n${roles 61 | .map( 62 | ({ level, nickname, game_uid, region_name }) => 63 | `Lv.${level} ${nickname} (${region_name}-${game_uid})` 64 | ) 65 | .join('\n')}` 66 | } catch (e) { 67 | // 数据库错误 68 | session.logger('genshin').warn('保存 cookie 时发生数据库异常', e) 69 | return '保存失败:数据库异常,请联系 bot 管理员。' 70 | } 71 | } 72 | 73 | /** 74 | * @param {Session} session 75 | * @param {number} uid 76 | * @returns {GenshinKit} 77 | */ 78 | async function getGenshinApp(session, uid) { 79 | const [self, common] = await Promise.all([ 80 | session.database.mongo.db 81 | .collection(colName) 82 | .find({ game_uid: { $in: ['' + uid] } }) 83 | .limit(1) 84 | .toArray(), 85 | session.database.mongo.db 86 | .collection(colName) 87 | .find({ last_disabled: { $ne: getFormatedToday() } }) 88 | .limit(1) 89 | .toArray(), 90 | ]) 91 | 92 | let data 93 | if (self.length) { 94 | // 本人账号 95 | data = self[0] 96 | } else if (common.length) { 97 | // 公共账号 98 | data = common[0] 99 | } else { 100 | // cookie 库耗尽 101 | return false 102 | } 103 | const { ltoken, ltuid, game_uid } = data 104 | const app = new GenshinKit().setCookie(`ltoken=${ltoken}; ltuid=${ltuid}`) 105 | app.selfUid = game_uid 106 | return app 107 | } 108 | 109 | /** 110 | * @param {Session} session 111 | * @param {string} cookie 112 | */ 113 | async function disableCookie(session, cookie) { 114 | const { ltoken, ltuid } = getCookieObj(cookie) 115 | await session.database.mongo.db 116 | .collection('hoyolab-cookies') 117 | .updateOne( 118 | { ltuid, ltoken }, 119 | { $set: { last_disabled: getFormatedToday() } } 120 | ) 121 | return true 122 | } 123 | 124 | async function getBindingRoles(cookie) { 125 | const g = new GenshinKit() 126 | g.setCookie(cookie) 127 | const { data } = await g.request( 128 | 'get', 129 | 'https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie' 130 | ) 131 | return data?.list.filter((item) => 132 | ['hk4e_cn', 'hk4e_global'].includes(item.game_biz) 133 | ) 134 | } 135 | 136 | /** 137 | * 138 | * @param {string} str 139 | * @returns {Record} 140 | */ 141 | function getCookieObj(str) { 142 | const obj = {} 143 | str 144 | .split(';') 145 | .filter((i) => !!i) 146 | .forEach((item) => { 147 | const s = item.split('=') 148 | const key = s?.[0].trim() 149 | const val = s?.[1].trim() || '' 150 | if (!key) return 151 | obj[key] = val 152 | }) 153 | return obj 154 | } 155 | 156 | function getFormatedToday() { 157 | const now = new Date() 158 | const timezoneCN = 8 159 | now.setHours(now.getHours() + timezoneCN) 160 | return now.toISOString().split('T')[0] 161 | } 162 | 163 | module.exports = { 164 | getGenshinApp, 165 | insertCookie, 166 | disableCookie, 167 | } 168 | -------------------------------------------------------------------------------- /src/plugins/wish.js: -------------------------------------------------------------------------------- 1 | const { GenshinGachaKit, util } = require('genshin-gacha-kit') 2 | const { Logger } = require('koishi-core') 3 | const logger = new Logger('genshin') 4 | logger.log = logger.info 5 | 6 | const gachaTypeNameToId = { 7 | 角色: 301, 8 | 武器: 302, 9 | 常驻: 200, 10 | } 11 | const gachaAppTypeToTypeName = { 12 | character: '角色', 13 | weapon: '武器', 14 | permanent: '常驻', 15 | novice: '新手', 16 | } 17 | 18 | /** 19 | * @param {import('koishi-core').Context} ctx 20 | * @param {*} pOptions 21 | */ 22 | function apply(ctx, pOptions) { 23 | ctx 24 | .command('genshin.wish') 25 | .alias('原神抽卡') 26 | .option('number', '-n ', { fallback: 1 }) 27 | // .option('name','-n 选定抽卡时的卡池名称') 28 | .option('type', '-t 选定抽卡时的卡池类别(角色/武器/常驻)', { 29 | fallback: '角色', 30 | }) 31 | .option('list-all', '-L 查看全部可用卡池') 32 | .option('list', '-l 查看相关类型卡池的内容') 33 | // .option('add', '-a 为本群添加卡池', { authority: 2 }) 34 | // .option('remove', '-r 为本群移除卡池', { authority: 2 }) 35 | // .channelFields(['genshin_gacha_pool']) 36 | .userFields(['genshin_gacha']) 37 | .check(check) 38 | .action(action) 39 | 40 | async function check({ session, options }) { 41 | logger.info('wish', options) 42 | 43 | if (options['list-all']) { 44 | const index = await util.getGachaIndex() 45 | const poolIds = index.map((i) => i.gacha_id) 46 | 47 | const queue = [] 48 | poolIds.forEach((id) => queue.push(util.getGachaData(id))) 49 | let pools = await Promise.all(queue) 50 | pools = pools.map((i) => util.poolStructureConverter(i)) 51 | 52 | return [ 53 | `当前可用的卡池共有 ${pools.length} 个:`, 54 | pools 55 | .map((i) => { 56 | return `${i.name} (${i.upSSR.map((i) => i.name).join('、')} UP)` 57 | }) 58 | .join('\n'), 59 | ].join('\n') 60 | } 61 | 62 | if (options.list) { 63 | if (!gachaTypeNameToId[options.list]) 64 | return '没有这个类型的卡池:' + options.list 65 | let pool = await util.getOfficialGachaPool( 66 | gachaTypeNameToId[options.list] 67 | ) 68 | pool = util.poolStructureConverter(pool) 69 | return [ 70 | `${pool.name}`, 71 | `${gachaAppTypeToTypeName[pool.type]}池`, 72 | `5星 UP:${pool.upSSR.map((i) => i.name).join('、') || '无'}`, 73 | `4星 UP:${pool.upSR.map((i) => i.name).join('、') || '无'}`, 74 | ].join('\n') 75 | } 76 | } 77 | 78 | async function action({ session, options }) { 79 | const gacha = new GenshinGachaKit() 80 | let genshin_gacha = session.user.genshin_gacha 81 | console.log('1111', genshin_gacha) 82 | const { counter, result } = genshin_gacha 83 | console.log('2222', { counter, result }) 84 | 85 | if (counter?.total !== undefined && result?.r !== undefined) { 86 | gacha.setCounter(counter) 87 | gacha.setResult(result) 88 | } 89 | 90 | let number = options.number 91 | number = Math.min(90, number) 92 | number = Math.max(1, number) 93 | 94 | let pool = await util.getOfficialGachaPool(gachaTypeNameToId[options.type]) 95 | if (!pool) return `无法拉取 ${options.type} 的卡池信息。` 96 | pool = util.poolStructureConverter(pool) 97 | 98 | gacha.setGachaPool(pool) 99 | 100 | const items = gacha.multiWish(number) 101 | 102 | const savedData = { 103 | counter: gacha.getCounter(), 104 | result: gacha.getResult(), 105 | } 106 | console.log('保存数据', savedData) 107 | genshin_gacha = savedData 108 | await session.user._update() 109 | console.log('数据库中的数据', session.user.genshin_gacha) 110 | 111 | return `抽到了 ${items 112 | .map((i) => `${i.name}(${i.rarity}星)x${i.count}`) 113 | .join('、')}` 114 | } 115 | 116 | ctx 117 | .command('genshin.backpack') 118 | .option('reset', '-R') 119 | .userFields(['genshin_gacha']) 120 | .action(async ({ session, options }) => { 121 | let genshin_gacha = session.user.genshin_gacha 122 | if (!genshin_gacha) return '您还未抽过卡。' 123 | 124 | if (options.reset) { 125 | const gacha = new GenshinGachaKit() 126 | gacha.clearCounter().clearResult() 127 | genshin_gacha = { 128 | counter: gacha.getCounter(), 129 | result: gacha.getResult(), 130 | } 131 | await session.user._update() 132 | return '已重置背包。' 133 | } 134 | 135 | const { counter, result } = Object.assign({}, genshin_gacha) 136 | console.log(JSON.stringify({ counter, result })) 137 | return [ 138 | `您共抽了 ${counter.total} 次卡`, 139 | `五星角色:${result.ssr 140 | .filter((i) => i.type === 'character') 141 | .map((i) => i.name) 142 | .join('、') || '无'}`, 143 | `五星武器:${result.ssr 144 | .filter((i) => i.type === 'weapon') 145 | .map((i) => i.name) 146 | .join('、') || '无'}`, 147 | `距离上一次五星 ${counter.lastSSR} 抽,您现在${ 148 | counter.ensureSSR === 1 ? '有' : '没有' 149 | }大保底。`, 150 | ].join('\n') 151 | }) 152 | 153 | ctx 154 | .command('arr') 155 | .userFields(['arr_test']) 156 | .action(async ({ session }) => { 157 | const arr = session.user.arr_test || [] 158 | arr.push({ length: { foo: { bar: [arr.length] } } }) 159 | session.user.arr_test = arr 160 | await session.user._update() 161 | return JSON.stringify(arr) 162 | }) 163 | } 164 | 165 | module.exports = { 166 | name: 'genshin/wish', 167 | apply, 168 | } 169 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/helper-validator-identifier@^7.15.7": 6 | version "7.15.7" 7 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" 8 | integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== 9 | 10 | "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": 11 | version "7.16.4" 12 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" 13 | integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== 14 | 15 | "@babel/types@^7.6.1", "@babel/types@^7.9.6": 16 | version "7.16.0" 17 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" 18 | integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== 19 | dependencies: 20 | "@babel/helper-validator-identifier" "^7.15.7" 21 | to-fast-properties "^2.0.0" 22 | 23 | "@dragon-fish/bump@^0.0.15": 24 | version "0.0.15" 25 | resolved "https://registry.yarnpkg.com/@dragon-fish/bump/-/bump-0.0.15.tgz#b04e9e3e3be11b8166228fc14da427c18386dfb8" 26 | integrity sha512-ObYvwi0vNhKZ1eerSpOK6ThfIF4bruzLxuc74joC4ag9uc3VocKHzVqdzIlWKh43dTwmdEisawOOJ/iobI/70A== 27 | dependencies: 28 | axios "^0.21.1" 29 | commander "^7.1.0" 30 | fs-extra "^9.1.0" 31 | 32 | "@genshin-kit/core@^2.6.0": 33 | version "2.6.0" 34 | resolved "https://registry.yarnpkg.com/@genshin-kit/core/-/core-2.6.0.tgz#f76827d6739b3ae77b79845ea26898fba59b9526" 35 | integrity sha512-382F4DV6gAdJ8c/830Tg2Nhlw4lYX5mcoW7V/d6gP8F1NdmN2vnQ6kXDkK/rvp1q3GgED8rz0jTGqrrVxM2Gxg== 36 | dependencies: 37 | axios "^0.24.0" 38 | tslib "^2.3.1" 39 | 40 | "@koa/router@^10.1.1": 41 | version "10.1.1" 42 | resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78" 43 | integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw== 44 | dependencies: 45 | debug "^4.1.1" 46 | http-errors "^1.7.3" 47 | koa-compose "^4.1.0" 48 | methods "^1.1.2" 49 | path-to-regexp "^6.1.0" 50 | 51 | "@types/accepts@*": 52 | version "1.3.5" 53 | resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" 54 | integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== 55 | dependencies: 56 | "@types/node" "*" 57 | 58 | "@types/body-parser@*": 59 | version "1.19.2" 60 | resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" 61 | integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== 62 | dependencies: 63 | "@types/connect" "*" 64 | "@types/node" "*" 65 | 66 | "@types/connect@*": 67 | version "3.4.35" 68 | resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" 69 | integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== 70 | dependencies: 71 | "@types/node" "*" 72 | 73 | "@types/content-disposition@*": 74 | version "0.5.4" 75 | resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.4.tgz#de48cf01c79c9f1560bcfd8ae43217ab028657f8" 76 | integrity sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ== 77 | 78 | "@types/cookies@*": 79 | version "0.7.7" 80 | resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.7.tgz#7a92453d1d16389c05a5301eef566f34946cfd81" 81 | integrity sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA== 82 | dependencies: 83 | "@types/connect" "*" 84 | "@types/express" "*" 85 | "@types/keygrip" "*" 86 | "@types/node" "*" 87 | 88 | "@types/express-serve-static-core@^4.17.18": 89 | version "4.17.26" 90 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz#5d9a8eeecb9d5f9d7fc1d85f541512a84638ae88" 91 | integrity sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ== 92 | dependencies: 93 | "@types/node" "*" 94 | "@types/qs" "*" 95 | "@types/range-parser" "*" 96 | 97 | "@types/express@*": 98 | version "4.17.13" 99 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" 100 | integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== 101 | dependencies: 102 | "@types/body-parser" "*" 103 | "@types/express-serve-static-core" "^4.17.18" 104 | "@types/qs" "*" 105 | "@types/serve-static" "*" 106 | 107 | "@types/http-assert@*": 108 | version "1.5.3" 109 | resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.3.tgz#ef8e3d1a8d46c387f04ab0f2e8ab8cb0c5078661" 110 | integrity sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA== 111 | 112 | "@types/http-errors@*": 113 | version "1.8.1" 114 | resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67" 115 | integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q== 116 | 117 | "@types/keygrip@*": 118 | version "1.0.2" 119 | resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" 120 | integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== 121 | 122 | "@types/koa-compose@*": 123 | version "3.2.5" 124 | resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d" 125 | integrity sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ== 126 | dependencies: 127 | "@types/koa" "*" 128 | 129 | "@types/koa@*": 130 | version "2.13.4" 131 | resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b" 132 | integrity sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw== 133 | dependencies: 134 | "@types/accepts" "*" 135 | "@types/content-disposition" "*" 136 | "@types/cookies" "*" 137 | "@types/http-assert" "*" 138 | "@types/http-errors" "*" 139 | "@types/keygrip" "*" 140 | "@types/koa-compose" "*" 141 | "@types/node" "*" 142 | 143 | "@types/koa__router@^8.0.8": 144 | version "8.0.11" 145 | resolved "https://registry.yarnpkg.com/@types/koa__router/-/koa__router-8.0.11.tgz#d7b37e6db934fc072ea1baa2ab92bc8ac4564f3e" 146 | integrity sha512-WXgKWpBsbS14kzmzD9LeFapOIa678h7zvUHxDwXwSx4ETKXhXLVUAToX6jZ/U7EihM7qwyD9W/BZvB0MRu7MTQ== 147 | dependencies: 148 | "@types/koa" "*" 149 | 150 | "@types/lru-cache@^5.1.1": 151 | version "5.1.1" 152 | resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" 153 | integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== 154 | 155 | "@types/mime@^1": 156 | version "1.3.2" 157 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" 158 | integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== 159 | 160 | "@types/node@*": 161 | version "16.11.12" 162 | resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10" 163 | integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw== 164 | 165 | "@types/qs@*": 166 | version "6.9.7" 167 | resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" 168 | integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== 169 | 170 | "@types/range-parser@*": 171 | version "1.2.4" 172 | resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" 173 | integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 174 | 175 | "@types/serve-static@*": 176 | version "1.13.10" 177 | resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" 178 | integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== 179 | dependencies: 180 | "@types/mime" "^1" 181 | "@types/node" "*" 182 | 183 | "@types/ws@^7.4.7": 184 | version "7.4.7" 185 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" 186 | integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== 187 | dependencies: 188 | "@types/node" "*" 189 | 190 | accepts@^1.3.5: 191 | version "1.3.7" 192 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 193 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 194 | dependencies: 195 | mime-types "~2.1.24" 196 | negotiator "0.6.2" 197 | 198 | acorn@^7.1.1: 199 | version "7.4.1" 200 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" 201 | integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== 202 | 203 | asap@~2.0.3: 204 | version "2.0.6" 205 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" 206 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= 207 | 208 | assert-never@^1.2.1: 209 | version "1.2.1" 210 | resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" 211 | integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== 212 | 213 | at-least-node@^1.0.0: 214 | version "1.0.0" 215 | resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" 216 | integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== 217 | 218 | axios@^0.21.1, axios@^0.21.4: 219 | version "0.21.4" 220 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" 221 | integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== 222 | dependencies: 223 | follow-redirects "^1.14.0" 224 | 225 | axios@^0.24.0: 226 | version "0.24.0" 227 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" 228 | integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== 229 | dependencies: 230 | follow-redirects "^1.14.4" 231 | 232 | babel-walk@3.0.0-canary-5: 233 | version "3.0.0-canary-5" 234 | resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" 235 | integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw== 236 | dependencies: 237 | "@babel/types" "^7.9.6" 238 | 239 | bytes@3.1.1: 240 | version "3.1.1" 241 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" 242 | integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== 243 | 244 | cache-content-type@^1.0.0: 245 | version "1.0.1" 246 | resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" 247 | integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== 248 | dependencies: 249 | mime-types "^2.1.18" 250 | ylru "^1.2.0" 251 | 252 | call-bind@^1.0.0, call-bind@^1.0.2: 253 | version "1.0.2" 254 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 255 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 256 | dependencies: 257 | function-bind "^1.1.1" 258 | get-intrinsic "^1.0.2" 259 | 260 | character-parser@^2.2.0: 261 | version "2.2.0" 262 | resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" 263 | integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= 264 | dependencies: 265 | is-regex "^1.0.3" 266 | 267 | co-body@^6.0.0: 268 | version "6.1.0" 269 | resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.1.0.tgz#d87a8efc3564f9bfe3aced8ef5cd04c7a8766547" 270 | integrity sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ== 271 | dependencies: 272 | inflation "^2.0.0" 273 | qs "^6.5.2" 274 | raw-body "^2.3.3" 275 | type-is "^1.6.16" 276 | 277 | co@^4.6.0: 278 | version "4.6.0" 279 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 280 | integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= 281 | 282 | commander@^7.1.0: 283 | version "7.2.0" 284 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" 285 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== 286 | 287 | constantinople@^4.0.1: 288 | version "4.0.1" 289 | resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" 290 | integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw== 291 | dependencies: 292 | "@babel/parser" "^7.6.0" 293 | "@babel/types" "^7.6.1" 294 | 295 | content-disposition@~0.5.2: 296 | version "0.5.3" 297 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 298 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 299 | dependencies: 300 | safe-buffer "5.1.2" 301 | 302 | content-type@^1.0.4: 303 | version "1.0.4" 304 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 305 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 306 | 307 | cookies@~0.8.0: 308 | version "0.8.0" 309 | resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" 310 | integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow== 311 | dependencies: 312 | depd "~2.0.0" 313 | keygrip "~1.1.0" 314 | 315 | copy-to@^2.0.1: 316 | version "2.0.1" 317 | resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" 318 | integrity sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU= 319 | 320 | debug@^4.1.1, debug@^4.3.2: 321 | version "4.3.3" 322 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" 323 | integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== 324 | dependencies: 325 | ms "2.1.2" 326 | 327 | deep-equal@~1.0.1: 328 | version "1.0.1" 329 | resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" 330 | integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= 331 | 332 | delegates@^1.0.0: 333 | version "1.0.0" 334 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 335 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 336 | 337 | depd@^2.0.0, depd@~2.0.0: 338 | version "2.0.0" 339 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 340 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 341 | 342 | depd@~1.1.2: 343 | version "1.1.2" 344 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 345 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 346 | 347 | destroy@^1.0.4: 348 | version "1.0.4" 349 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 350 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 351 | 352 | doctypes@^1.1.0: 353 | version "1.1.0" 354 | resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" 355 | integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= 356 | 357 | ee-first@1.1.1: 358 | version "1.1.1" 359 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 360 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 361 | 362 | encodeurl@^1.0.2: 363 | version "1.0.2" 364 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 365 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 366 | 367 | escape-html@^1.0.3: 368 | version "1.0.3" 369 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 370 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 371 | 372 | fastest-levenshtein@^1.0.12: 373 | version "1.0.12" 374 | resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" 375 | integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== 376 | 377 | follow-redirects@^1.14.0, follow-redirects@^1.14.4: 378 | version "1.14.5" 379 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" 380 | integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA== 381 | 382 | fresh@~0.5.2: 383 | version "0.5.2" 384 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 385 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 386 | 387 | fs-extra@^9.1.0: 388 | version "9.1.0" 389 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" 390 | integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== 391 | dependencies: 392 | at-least-node "^1.0.0" 393 | graceful-fs "^4.2.0" 394 | jsonfile "^6.0.1" 395 | universalify "^2.0.0" 396 | 397 | function-bind@^1.1.1: 398 | version "1.1.1" 399 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 400 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 401 | 402 | genshin-gacha-kit@^1.1.0: 403 | version "1.1.0" 404 | resolved "https://registry.yarnpkg.com/genshin-gacha-kit/-/genshin-gacha-kit-1.1.0.tgz#dd1b73e69e7c04bd7b94e4e2113bd05b5229a93b" 405 | integrity sha512-xQ2tRLjSzcGD5FA2RTJZ35oDjenuvJr+eBvvet6TN9dkedLDydYqq73hVshRXvaYcVqUKbX543MvxYBAVEhD+A== 406 | dependencies: 407 | axios "^0.21.1" 408 | tslib "^2.2.0" 409 | 410 | get-intrinsic@^1.0.2: 411 | version "1.1.1" 412 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" 413 | integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== 414 | dependencies: 415 | function-bind "^1.1.1" 416 | has "^1.0.3" 417 | has-symbols "^1.0.1" 418 | 419 | graceful-fs@^4.1.6, graceful-fs@^4.2.0: 420 | version "4.2.8" 421 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" 422 | integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== 423 | 424 | has-flag@^4.0.0: 425 | version "4.0.0" 426 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 427 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 428 | 429 | has-symbols@^1.0.1, has-symbols@^1.0.2: 430 | version "1.0.2" 431 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" 432 | integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== 433 | 434 | has-tostringtag@^1.0.0: 435 | version "1.0.0" 436 | resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" 437 | integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== 438 | dependencies: 439 | has-symbols "^1.0.2" 440 | 441 | has@^1.0.3: 442 | version "1.0.3" 443 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 444 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 445 | dependencies: 446 | function-bind "^1.1.1" 447 | 448 | http-assert@^1.3.0: 449 | version "1.5.0" 450 | resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" 451 | integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w== 452 | dependencies: 453 | deep-equal "~1.0.1" 454 | http-errors "~1.8.0" 455 | 456 | http-errors@1.8.1, http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0: 457 | version "1.8.1" 458 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" 459 | integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== 460 | dependencies: 461 | depd "~1.1.2" 462 | inherits "2.0.4" 463 | setprototypeof "1.2.0" 464 | statuses ">= 1.5.0 < 2" 465 | toidentifier "1.0.1" 466 | 467 | iconv-lite@0.4.24: 468 | version "0.4.24" 469 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 470 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 471 | dependencies: 472 | safer-buffer ">= 2.1.2 < 3" 473 | 474 | inflation@^2.0.0: 475 | version "2.0.0" 476 | resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" 477 | integrity sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8= 478 | 479 | inherits@2.0.4: 480 | version "2.0.4" 481 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 482 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 483 | 484 | is-core-module@^2.2.0: 485 | version "2.8.0" 486 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" 487 | integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== 488 | dependencies: 489 | has "^1.0.3" 490 | 491 | is-expression@^4.0.0: 492 | version "4.0.0" 493 | resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" 494 | integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A== 495 | dependencies: 496 | acorn "^7.1.1" 497 | object-assign "^4.1.1" 498 | 499 | is-generator-function@^1.0.7: 500 | version "1.0.10" 501 | resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" 502 | integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== 503 | dependencies: 504 | has-tostringtag "^1.0.0" 505 | 506 | is-promise@^2.0.0: 507 | version "2.2.2" 508 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" 509 | integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== 510 | 511 | is-regex@^1.0.3: 512 | version "1.1.4" 513 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" 514 | integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== 515 | dependencies: 516 | call-bind "^1.0.2" 517 | has-tostringtag "^1.0.0" 518 | 519 | js-stringify@^1.0.2: 520 | version "1.0.2" 521 | resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" 522 | integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= 523 | 524 | jsonfile@^6.0.1: 525 | version "6.1.0" 526 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" 527 | integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== 528 | dependencies: 529 | universalify "^2.0.0" 530 | optionalDependencies: 531 | graceful-fs "^4.1.6" 532 | 533 | jstransformer@1.0.0: 534 | version "1.0.0" 535 | resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" 536 | integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= 537 | dependencies: 538 | is-promise "^2.0.0" 539 | promise "^7.0.1" 540 | 541 | keygrip@~1.1.0: 542 | version "1.1.0" 543 | resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" 544 | integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== 545 | dependencies: 546 | tsscmp "1.0.6" 547 | 548 | koa-bodyparser@^4.3.0: 549 | version "4.3.0" 550 | resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.3.0.tgz#274c778555ff48fa221ee7f36a9fbdbace22759a" 551 | integrity sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw== 552 | dependencies: 553 | co-body "^6.0.0" 554 | copy-to "^2.0.1" 555 | 556 | koa-compose@^4.1.0: 557 | version "4.1.0" 558 | resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" 559 | integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== 560 | 561 | koa-convert@^2.0.0: 562 | version "2.0.0" 563 | resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5" 564 | integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA== 565 | dependencies: 566 | co "^4.6.0" 567 | koa-compose "^4.1.0" 568 | 569 | koa@^2.13.1: 570 | version "2.13.4" 571 | resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e" 572 | integrity sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g== 573 | dependencies: 574 | accepts "^1.3.5" 575 | cache-content-type "^1.0.0" 576 | content-disposition "~0.5.2" 577 | content-type "^1.0.4" 578 | cookies "~0.8.0" 579 | debug "^4.3.2" 580 | delegates "^1.0.0" 581 | depd "^2.0.0" 582 | destroy "^1.0.4" 583 | encodeurl "^1.0.2" 584 | escape-html "^1.0.3" 585 | fresh "~0.5.2" 586 | http-assert "^1.3.0" 587 | http-errors "^1.6.3" 588 | is-generator-function "^1.0.7" 589 | koa-compose "^4.1.0" 590 | koa-convert "^2.0.0" 591 | on-finished "^2.3.0" 592 | only "~0.0.2" 593 | parseurl "^1.3.2" 594 | statuses "^1.5.0" 595 | type-is "^1.6.16" 596 | vary "^1.1.2" 597 | 598 | koishi-core@^3.13.1: 599 | version "3.14.2" 600 | resolved "https://registry.yarnpkg.com/koishi-core/-/koishi-core-3.14.2.tgz#036b11f592a9c7c0c6324ad7dc5a5c675d502ffb" 601 | integrity sha512-32Zh35DL+ok8DNeNri4amIpt6Njf2lQ+Zgt5wNH5nq5BdUvPSEc4jAQhtcwxnrGvdVrl8n5QIuCZfkdY5tMk6w== 602 | dependencies: 603 | "@koa/router" "^10.1.1" 604 | "@types/koa__router" "^8.0.8" 605 | "@types/lru-cache" "^5.1.1" 606 | "@types/ws" "^7.4.7" 607 | axios "^0.21.4" 608 | fastest-levenshtein "^1.0.12" 609 | koa "^2.13.1" 610 | koa-bodyparser "^4.3.0" 611 | koishi-utils "^4.3.0" 612 | lru-cache "^6.0.0" 613 | 614 | koishi-utils@^4.3.0: 615 | version "4.3.0" 616 | resolved "https://registry.yarnpkg.com/koishi-utils/-/koishi-utils-4.3.0.tgz#14bd29033516f6527f3f04f664c5ec1ee1244d82" 617 | integrity sha512-MV799odIPx2xWIcI4kIFFUmZotKUwejBo/ChYTZ3reQNZ0VGpvUghA4+oMm4m6qOgXlJsUiUc84kbSwOPrYWmw== 618 | dependencies: 619 | supports-color "^8.1.0" 620 | 621 | lru-cache@^6.0.0: 622 | version "6.0.0" 623 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 624 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 625 | dependencies: 626 | yallist "^4.0.0" 627 | 628 | media-typer@0.3.0: 629 | version "0.3.0" 630 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 631 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 632 | 633 | methods@^1.1.2: 634 | version "1.1.2" 635 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 636 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 637 | 638 | mime-db@1.51.0: 639 | version "1.51.0" 640 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" 641 | integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== 642 | 643 | mime-types@^2.1.18, mime-types@~2.1.24: 644 | version "2.1.34" 645 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" 646 | integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== 647 | dependencies: 648 | mime-db "1.51.0" 649 | 650 | ms@2.1.2: 651 | version "2.1.2" 652 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 653 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 654 | 655 | negotiator@0.6.2: 656 | version "0.6.2" 657 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 658 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 659 | 660 | object-assign@^4.1.1: 661 | version "4.1.1" 662 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 663 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 664 | 665 | object-inspect@^1.9.0: 666 | version "1.11.1" 667 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.1.tgz#d4bd7d7de54b9a75599f59a00bd698c1f1c6549b" 668 | integrity sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA== 669 | 670 | on-finished@^2.3.0: 671 | version "2.3.0" 672 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 673 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 674 | dependencies: 675 | ee-first "1.1.1" 676 | 677 | only@~0.0.2: 678 | version "0.0.2" 679 | resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" 680 | integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= 681 | 682 | parseurl@^1.3.2: 683 | version "1.3.3" 684 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 685 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 686 | 687 | path-parse@^1.0.6: 688 | version "1.0.7" 689 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 690 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 691 | 692 | path-to-regexp@^6.1.0: 693 | version "6.2.0" 694 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" 695 | integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== 696 | 697 | promise@^7.0.1: 698 | version "7.3.1" 699 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" 700 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== 701 | dependencies: 702 | asap "~2.0.3" 703 | 704 | pug-attrs@^3.0.0: 705 | version "3.0.0" 706 | resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" 707 | integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA== 708 | dependencies: 709 | constantinople "^4.0.1" 710 | js-stringify "^1.0.2" 711 | pug-runtime "^3.0.0" 712 | 713 | pug-code-gen@^3.0.2: 714 | version "3.0.2" 715 | resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce" 716 | integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg== 717 | dependencies: 718 | constantinople "^4.0.1" 719 | doctypes "^1.1.0" 720 | js-stringify "^1.0.2" 721 | pug-attrs "^3.0.0" 722 | pug-error "^2.0.0" 723 | pug-runtime "^3.0.0" 724 | void-elements "^3.1.0" 725 | with "^7.0.0" 726 | 727 | pug-error@^2.0.0: 728 | version "2.0.0" 729 | resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" 730 | integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== 731 | 732 | pug-filters@^4.0.0: 733 | version "4.0.0" 734 | resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" 735 | integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A== 736 | dependencies: 737 | constantinople "^4.0.1" 738 | jstransformer "1.0.0" 739 | pug-error "^2.0.0" 740 | pug-walk "^2.0.0" 741 | resolve "^1.15.1" 742 | 743 | pug-lexer@^5.0.1: 744 | version "5.0.1" 745 | resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" 746 | integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w== 747 | dependencies: 748 | character-parser "^2.2.0" 749 | is-expression "^4.0.0" 750 | pug-error "^2.0.0" 751 | 752 | pug-linker@^4.0.0: 753 | version "4.0.0" 754 | resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" 755 | integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw== 756 | dependencies: 757 | pug-error "^2.0.0" 758 | pug-walk "^2.0.0" 759 | 760 | pug-load@^3.0.0: 761 | version "3.0.0" 762 | resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" 763 | integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ== 764 | dependencies: 765 | object-assign "^4.1.1" 766 | pug-walk "^2.0.0" 767 | 768 | pug-parser@^6.0.0: 769 | version "6.0.0" 770 | resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" 771 | integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw== 772 | dependencies: 773 | pug-error "^2.0.0" 774 | token-stream "1.0.0" 775 | 776 | pug-runtime@^3.0.0, pug-runtime@^3.0.1: 777 | version "3.0.1" 778 | resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" 779 | integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg== 780 | 781 | pug-strip-comments@^2.0.0: 782 | version "2.0.0" 783 | resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" 784 | integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ== 785 | dependencies: 786 | pug-error "^2.0.0" 787 | 788 | pug-walk@^2.0.0: 789 | version "2.0.0" 790 | resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" 791 | integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== 792 | 793 | pug@^3.0.2: 794 | version "3.0.2" 795 | resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" 796 | integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw== 797 | dependencies: 798 | pug-code-gen "^3.0.2" 799 | pug-filters "^4.0.0" 800 | pug-lexer "^5.0.1" 801 | pug-linker "^4.0.0" 802 | pug-load "^3.0.0" 803 | pug-parser "^6.0.0" 804 | pug-runtime "^3.0.1" 805 | pug-strip-comments "^2.0.0" 806 | 807 | qs@^6.5.2: 808 | version "6.10.2" 809 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.2.tgz#c1431bea37fc5b24c5bdbafa20f16bdf2a4b9ffe" 810 | integrity sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw== 811 | dependencies: 812 | side-channel "^1.0.4" 813 | 814 | raw-body@^2.3.3: 815 | version "2.4.2" 816 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" 817 | integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== 818 | dependencies: 819 | bytes "3.1.1" 820 | http-errors "1.8.1" 821 | iconv-lite "0.4.24" 822 | unpipe "1.0.0" 823 | 824 | resolve@^1.15.1: 825 | version "1.20.0" 826 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 827 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 828 | dependencies: 829 | is-core-module "^2.2.0" 830 | path-parse "^1.0.6" 831 | 832 | safe-buffer@5.1.2: 833 | version "5.1.2" 834 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 835 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 836 | 837 | "safer-buffer@>= 2.1.2 < 3": 838 | version "2.1.2" 839 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 840 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 841 | 842 | setprototypeof@1.2.0: 843 | version "1.2.0" 844 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 845 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 846 | 847 | side-channel@^1.0.4: 848 | version "1.0.4" 849 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" 850 | integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 851 | dependencies: 852 | call-bind "^1.0.0" 853 | get-intrinsic "^1.0.2" 854 | object-inspect "^1.9.0" 855 | 856 | "statuses@>= 1.5.0 < 2", statuses@^1.5.0: 857 | version "1.5.0" 858 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 859 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 860 | 861 | supports-color@^8.1.0: 862 | version "8.1.1" 863 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 864 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 865 | dependencies: 866 | has-flag "^4.0.0" 867 | 868 | to-fast-properties@^2.0.0: 869 | version "2.0.0" 870 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 871 | integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= 872 | 873 | toidentifier@1.0.1: 874 | version "1.0.1" 875 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 876 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 877 | 878 | token-stream@1.0.0: 879 | version "1.0.0" 880 | resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" 881 | integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= 882 | 883 | tslib@^2.2.0, tslib@^2.3.1: 884 | version "2.3.1" 885 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" 886 | integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== 887 | 888 | tsscmp@1.0.6: 889 | version "1.0.6" 890 | resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" 891 | integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== 892 | 893 | type-is@^1.6.16: 894 | version "1.6.18" 895 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 896 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 897 | dependencies: 898 | media-typer "0.3.0" 899 | mime-types "~2.1.24" 900 | 901 | universalify@^2.0.0: 902 | version "2.0.0" 903 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" 904 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== 905 | 906 | unpipe@1.0.0: 907 | version "1.0.0" 908 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 909 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 910 | 911 | vary@^1.1.2: 912 | version "1.1.2" 913 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 914 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 915 | 916 | void-elements@^3.1.0: 917 | version "3.1.0" 918 | resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" 919 | integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= 920 | 921 | with@^7.0.0: 922 | version "7.0.2" 923 | resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" 924 | integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w== 925 | dependencies: 926 | "@babel/parser" "^7.9.6" 927 | "@babel/types" "^7.9.6" 928 | assert-never "^1.2.1" 929 | babel-walk "3.0.0-canary-5" 930 | 931 | yallist@^4.0.0: 932 | version "4.0.0" 933 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 934 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 935 | 936 | ylru@^1.2.0: 937 | version "1.2.1" 938 | resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" 939 | integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ== 940 | --------------------------------------------------------------------------------